टोस्ट कॉम्पोनेंट बनाना

ज़रूरत के हिसाब से और आसानी से इस्तेमाल होने वाला टोस्ट कॉम्पोनेंट बनाने के तरीके के बारे में बुनियादी खास जानकारी.

इस पोस्ट में, मुझे टोस्ट कॉम्पोनेंट बनाने का तरीका बताना है. डेमो आज़माएं.

डेमो

अगर आप वीडियो पसंद करते हैं, तो यहां इस पोस्ट का YouTube वर्शन दिया गया है:

खास जानकारी

टोस्ट, उपयोगकर्ताओं के लिए नॉन-इंटरैक्टिव, पैसिव, और एसिंक्रोनस छोटे मैसेज होते हैं. आम तौर पर, इनका इस्तेमाल उपयोगकर्ता को किसी कार्रवाई के नतीजों के बारे में बताने के लिए, इंटरफ़ेस सुझाव पैटर्न के तौर पर किया जाता है.

इंटरैक्शन

टोस्ट सूचनाओं, सूचनाएं, और निर्देशों से अलग होते हैं, क्योंकि ये इंटरैक्टिव नहीं होते हैं. इन्हें खारिज करने या बने रहने के मकसद से नहीं बनाया जाता. सूचनाएं ज़्यादा अहम जानकारी के लिए होती हैं. सिंक्रोनस मैसेज सेवा, जिसके लिए इंटरैक्शन की ज़रूरत होती है या सिस्टम लेवल के मैसेज (पेज लेवल की तुलना में) के लिए होते हैं. सूचना की अन्य रणनीतियों की तुलना में, टोस्ट ज़्यादा कारगर होते हैं.

मार्कअप

टोस्ट के लिए <output> एलिमेंट अच्छा विकल्प होता है, क्योंकि इसे स्क्रीन रीडर के लिए बोला जाता है. सही एचटीएमएल, JavaScript और सीएसएस को बेहतर बनाने के लिए हमें एक सुरक्षित आधार उपलब्ध कराता है. साथ ही, इसमें बहुत सारी JavaScript मौजूद होती हैं.

टोस्ट

<output class="gui-toast">Item added to cart</output>

role="status" को जोड़कर, इसमें ज़्यादा जानकारी शामिल की जा सकती है. अगर ब्राउज़र, खास जानकारी के हिसाब से <output> एलिमेंट को इन्प्लिसिट रोल नहीं देता है, तो इससे फ़ॉलबैक मिलता है.

<output role="status" class="gui-toast">Item added to cart</output>

टोस्ट कंटेनर

एक बार में एक से ज़्यादा टोस्ट दिखाए जा सकते हैं. कई टोस्ट को व्यवस्थित करने के लिए एक कंटेनर का इस्तेमाल किया जाता है. यह कंटेनर, स्क्रीन पर टोस्ट की पोज़ीशन को भी हैंडल करता है.

<section class="gui-toast-group">
  <output role="status">Wizard Rose added to cart</output>
  <output role="status">Self Watering Pot added to cart</output>
</section>

लेआउट

मैंने व्यूपोर्ट के inset-block-end में टोस्ट पिन करना चुना और अगर और टोस्ट जोड़े जाते हैं, तो वे स्क्रीन के किनारे से स्टैक हो जाते हैं.

जीयूआई कंटेनर

टोस्ट कंटेनर टोस्ट पेश करने के लिए पूरे लेआउट का काम करता है. व्यूपोर्ट के लिए fixed है और यह तय करने के लिए लॉजिकल प्रॉपर्टी inset का इस्तेमाल करता है कि किन किनारों पर पिन करना है. साथ ही, उसी block-end किनारे से थोड़ा padding का हिस्सा तय करें.

.gui-toast-group {
  position: fixed;
  z-index: 1;
  inset-block-end: 0;
  inset-inline: 0;
  padding-block-end: 5vh;
}

DevTools बॉक्स का साइज़ और पैडिंग (जगह) वाला स्क्रीनशॉट, जो .गिल-टोस्ट-कंटेनर एलिमेंट पर ओवरले किया गया है.

व्यूपोर्ट के अंदर खुद को सही जगह पर रखते हुए, टोस्ट कंटेनर एक ग्रिड कंटेनर होता है, जो टोस्ट को अलाइन और डिस्ट्रिब्यूट कर सकता है. आइटम को justify-content के साथ ग्रुप के तौर पर और justify-items के बीच में अलग-अलग रखा जाता है. gap को थोड़ा सा फेंकें, ताकि टोस्ट न छुएं.

.gui-toast-group {
  display: grid;
  justify-items: center;
  justify-content: center;
  gap: 1vh;
}

टोस्ट समूह पर सीएसएस ग्रिड ओवरले के साथ स्क्रीनशॉट, इस बार यह दिखाता है कि
टोस्ट चाइल्ड एलिमेंट के बीच स्पेस और खाली जगह है या नहीं.

जीयूआई टोस्ट

किसी एक टोस्ट में कुछ padding, border-radius वाले कुछ नर्म कोने, और मोबाइल और डेस्कटॉप का साइज़ बदलने के लिए, min() फ़ंक्शन होते हैं. यहां दिए गए सीएसएस में रिस्पॉन्सिव साइज़ की वजह से, व्यूपोर्ट या 25ch के 90% से ज़्यादा टोस्ट की पहुंच नहीं बढ़ती है.

.gui-toast {
  max-inline-size: min(25ch, 90vw);
  padding-block: .5ch;
  padding-inline: 1ch;
  border-radius: 3px;
  font-size: 1rem;
}

एक .gu-toast एलिमेंट का स्क्रीनशॉट, जिसमें पैडिंग और बॉर्डर
दायरा दिखाया गया है.

स्टाइल

लेआउट और पोज़िशनिंग सेट के ज़रिए, ऐसी सीएसएस जोड़ें जो उपयोगकर्ता सेटिंग और इंटरैक्शन के मुताबिक काम करने में मदद करती है.

टोस्ट कंटेनर

टोस्ट इंटरैक्टिव नहीं हैं, इसलिए उन पर टैप या स्वाइप करने से कुछ नहीं होता है, लेकिन फ़िलहाल, वे पॉइंटर इवेंट का इस्तेमाल करते हैं. इस सीएसएस की मदद से टोस्ट को क्लिक चुराने से रोकें.

.gui-toast-group {
  pointer-events: none;
}

जीयूआई टोस्ट

टोस्ट को कस्टम प्रॉपर्टी, एचएसएल, और एक प्राथमिकता मीडिया क्वेरी के साथ हल्की या गहरे रंग वाली अडैप्टिव थीम दें.

.gui-toast {
  --_bg-lightness: 90%;

  color: black;
  background: hsl(0 0% var(--_bg-lightness) / 90%);
}

@media (prefers-color-scheme: dark) {
  .gui-toast {
    color: white;
    --_bg-lightness: 20%;
  }
}

Animation

स्क्रीन पर आते ही नया टोस्ट खुद को ऐनिमेशन के साथ पेश करना चाहिए. कम की गई मोशन को अडजस्ट करने के लिए, translate की वैल्यू को डिफ़ॉल्ट रूप से 0 पर सेट करें. हालांकि, मोशन प्राथमिकता मीडिया क्वेरी में मोशन वैल्यू को लंबाई में अपडेट करें . सभी को थोड़ा-बहुत ऐनिमेशन मिलता है, लेकिन सिर्फ़ कुछ ही लोगों को टोस्ट की दूरी मिलती है.

यहां टोस्ट ऐनिमेशन के लिए इस्तेमाल किए गए मुख्य-फ़्रेम दिए गए हैं. सीएसएस, एंट्रेंस, इंतज़ार, और टोस्ट से बाहर निकलने की प्रोसेस को एक ही ऐनिमेशन में कंट्रोल करेगी.

@keyframes fade-in {
  from { opacity: 0 }
}

@keyframes fade-out {
  to { opacity: 0 }
}

@keyframes slide-in {
  from { transform: translateY(var(--_travel-distance, 10px)) }
}

इसके बाद टोस्ट एलिमेंट, वैरिएबल सेट अप करता है और मुख्य-फ़्रेम को ऑर्केस्ट्रेट करता है.

.gui-toast {
  --_duration: 3s;
  --_travel-distance: 0;

  will-change: transform;
  animation: 
    fade-in .3s ease,
    slide-in .3s ease,
    fade-out .3s ease var(--_duration);
}

@media (prefers-reduced-motion: no-preference) {
  .gui-toast {
    --_travel-distance: 5vh;
  }
}

JavaScript

स्टाइल और स्क्रीन रीडर ऐक्सेस करने लायक एचटीएमएल के तैयार होने पर, उपयोगकर्ता इवेंट के आधार पर टोस्ट बनाने, जोड़ने, और उन्हें नष्ट करने के लिए JavaScript की ज़रूरत होती है. टोस्ट कॉम्पोनेंट का डेवलपर अनुभव कम से कम और शुरू करने में आसान होना चाहिए, जैसे कि:

import Toast from './toast.js'

Toast('My first toast')

टोस्ट ग्रुप और टोस्ट बनाए जा रहे हैं

जब टोस्ट मॉड्यूल JavaScript से लोड होता है, तो इसे टोस्ट कंटेनर बनाना और पेज में जोड़ना चाहिए. मैंने body से पहले एलिमेंट को जोड़ना चुना है. इससे z-index स्टैकिंग की समस्याएं नहीं होंगी, क्योंकि कंटेनर सभी बॉडी एलिमेंट के कंटेनर से ऊपर है.

const init = () => {
  const node = document.createElement('section')
  node.classList.add('gui-toast-group')

  document.firstElementChild.insertBefore(node, document.body)
  return node
}

हेड और बॉडी टैग के बीच टोस्ट ग्रुप का स्क्रीनशॉट.

init() फ़ंक्शन को अंदरूनी तौर पर मॉड्यूल में कॉल किया जाता है. इसमें एलिमेंट को Toaster के तौर पर छिपाया जाता है:

const Toaster = init()

टोस्ट एचटीएमएल एलिमेंट, createToast() फ़ंक्शन की मदद से बनाया जाता है. फ़ंक्शन में टोस्ट के लिए कुछ टेक्स्ट की ज़रूरत होती है, एक <output> एलिमेंट बनाया जाता है, इसे कुछ क्लास और एट्रिब्यूट से सजाया जाता है, टेक्स्ट सेट किया जाता है, और नोड दिखाया जाता है.

const createToast = text => {
  const node = document.createElement('output')
  
  node.innerText = text
  node.classList.add('gui-toast')
  node.setAttribute('role', 'status')

  return node
}

एक या एक से ज़्यादा टोस्ट मैनेज करना

JavaScript अब दस्तावेज़ में एक कंटेनर जोड़ देता है, जिसमें टोस्ट शामिल किए जाते हैं. साथ ही, अब वह बनाए गए टोस्ट जोड़ने के लिए तैयार है. addToast() फ़ंक्शन एक या कई टोस्ट को हैंडल करता है. सबसे पहले यह जांच करना कि टोस्ट की संख्या कितनी है और फिर उसे हिलाना-डुलाना सही है या नहीं. फिर इस जानकारी का इस्तेमाल करके या तो टोस्ट जोड़ें या कोई खास ऐनिमेशन करें, ताकि दूसरे टोस्ट नए टोस्ट के लिए "जगह" लगे.

const addToast = toast => {
  const { matches:motionOK } = window.matchMedia(
    '(prefers-reduced-motion: no-preference)'
  )

  Toaster.children.length && motionOK
    ? flipToast(toast)
    : Toaster.appendChild(toast)
}

पहला टोस्ट जोड़ते समय, Toaster.appendChild(toast) सीएसएस ऐनिमेशन को ट्रिगर करने वाले पेज पर एक टोस्ट जोड़ता है: ऐनिमेट करें, 3s इंतज़ार करें, ऐनिमेट करें. जब टोस्ट पहले से मौजूद होते हैं, तो flipToast() को कहा जाता है. इसमें पॉल लुइस ने फ़्लिप नाम की तकनीक का इस्तेमाल किया है. इस कोशिश का मकसद, नया टोस्ट जोड़ने से पहले और बाद में, कंटेनर की पोज़िशन के बीच के अंतर का हिसाब लगाना है. यह इस तरह से समझाना है जैसे यह पता लगाना कि टोस्टर अब कहां है, वह कहां है, और फिर वह कहां है, जहां यह है, इसका ऐनिमेशन.

const flipToast = toast => {
  // FIRST
  const first = Toaster.offsetHeight

  // add new child to change container size
  Toaster.appendChild(toast)

  // LAST
  const last = Toaster.offsetHeight

  // INVERT
  const invert = last - first

  // PLAY
  const animation = Toaster.animate([
    { transform: `translateY(${invert}px)` },
    { transform: 'translateY(0)' }
  ], {
    duration: 150,
    easing: 'ease-out',
  })
}

सीएसएस ग्रिड, लेआउट को लिफ़्ट करने का काम करता है. जब एक नया टोस्ट जोड़ा जाता है, तो ग्रिड उसे शुरुआत में और दूसरे टोस्ट के बीच में रखता है. इस बीच, कंटेनर को पुरानी पोज़िशन से ऐनिमेट करने के लिए वेब ऐनिमेशन का इस्तेमाल किया जाता है.

सभी JavaScript को एक साथ रखना

जब Toast('my first toast') को कॉल किया जाता है, तो एक टोस्ट बनाया जाता है और पेज में जोड़ा जाता है (हो सकता है कि नए टोस्ट को दिखाने के लिए कंटेनर को भी ऐनिमेट किया गया हो), एक प्रॉमिस दिखाया जाता है और टोस्ट को देखा जाता है, ताकि सीएसएस ऐनिमेशन पूरा होने के बाद (तीन मुख्य-फ़्रेम वाले ऐनिमेशन) प्रॉमिस रिज़ॉल्यूशन के लिए सही तरीके से काम कर सकें.

const Toast = text => {
  let toast = createToast(text)
  addToast(toast)

  return new Promise(async (resolve, reject) => {
    await Promise.allSettled(
      toast.getAnimations().map(animation => 
        animation.finished
      )
    )
    Toaster.removeChild(toast)
    resolve() 
  })
}

मुझे लगा कि इस कोड का भ्रम की स्थिति वाला हिस्सा, Promise.allSettled() फ़ंक्शन और toast.getAnimations() मैपिंग में है. मैंने टोस्ट के लिए कई मुख्य-फ़्रेम ऐनिमेशन इस्तेमाल किए, ताकि मुझे पता चल सके कि सभी ने काम पूरा कर लिया है. इसलिए, हर एक के लिए JavaScript से अनुरोध करना चाहिए. साथ ही, उसके finished प्रॉमिस को पूरा करने का वादा किया गया है. allSettled अपने सभी वादों को पूरा करने के बाद, यह प्रोसेस अपने-आप पूरी हो जाती है. await Promise.allSettled() का इस्तेमाल करने का मतलब है कि कोड की अगली लाइन, एलिमेंट को आसानी से हटा सकती है और यह मान सकती है कि टोस्ट की लाइफ़साइकल पूरी हो गई है. आखिर में, resolve() को कॉल करने से हाई लेवल टोस्ट का वादा पूरा हो जाता है, ताकि टोस्ट दिखाई देने के बाद डेवलपर साफ़ कर सकें या कोई दूसरा काम कर सकें.

export default Toast

आखिर में, Toast फ़ंक्शन को मॉड्यूल से एक्सपोर्ट किया जाता है, ताकि दूसरी स्क्रिप्ट को इंपोर्ट और इस्तेमाल किया जा सके.

टोस्ट कॉम्पोनेंट का इस्तेमाल करना

टोस्ट या टोस्ट के डेवलपर अनुभव का इस्तेमाल करने के लिए, Toast फ़ंक्शन को इंपोर्ट किया जाता है और उसे मैसेज स्ट्रिंग के साथ कॉल किया जाता है.

import Toast from './toast.js'

Toast('Wizard Rose added to cart')

अगर डेवलपर टोस्ट दिखाए जाने के बाद काम या कुछ भी साफ़ करना चाहता है, तो वह एक साथ काम नहीं करने वाली प्रोसेस और await का इस्तेमाल कर सकता है.

import Toast from './toast.js'

async function example() {
  await Toast('Wizard Rose added to cart')
  console.log('toast finished')
}

नतीजा

अब आपको पता चल गया है कि मैंने इसे कैसे किया, तो आप कैसी होंगी‽ 🙂

चलिए, इसे अलग-अलग तरीके से समझें और वेब पर सभी के काम करने के तरीके सीखें. एक डेमो तैयार करें, मुझे ट्वीट करें वाले लिंक, और मैं उसे नीचे दिए गए कम्यूनिटी रीमिक्स सेक्शन में जोड़ दूंगी!

कम्यूनिटी रीमिक्स