DEV Community

Cover image for Composant Snackbar avec RiotJS
Steeve
Steeve

Posted on

Composant Snackbar avec RiotJS

Cet article traite de la création d'un composant Snackbar avec Riot, en utilisant le CSS Material Design BeerCSS, et de l'exécution d'une action lors des événements d'entrée et de sélection.

Avant de commencer, assurez-vous d'avoir une application de base Riot, ou consultez mes articles précédents.

Les Snackbars communiquent des messages en bas de l'écran, qui sont minimalement interruptifs et ne nécessitent pas d'action de l'utilisateur. Ils peuvent contenir une seule action, telle que "Annuler", "Ouvrir", ou "En savoir plus".

Example of snackbar showing on a mobile app

Base du Composant Snackbar

L'objectif est de créer une application Riot avec une Snackbar apparaissant lorsqu'un bouton est cliqué, et de la faire disparaître automatiquement lorsque l'action est cliquée.

Gif of a Snackbar made with RiotJS displayed when a button is click

Tout d'abord, créez un nouveau fichier nommé c-snackbar.riot dans le dossier des composants. Le préfixe c- signifie "composant", une convention de nommage utile et une bonne pratique.

Écrivez le code suivant dans ./components/c-snackbar.riot. Le HTML provient de la documentation BeerCSS et j'ai ajouté la syntaxe RiotJS pour la logique :

<c-snackbar>
    <div class="
            snackbar
            { props?.active ? 'active ' : null }
            { props?.top ? 'top ' : null }
            { props?.bottom ? 'bottom ' : null }
            { props?.error ? 'error ' : null }
            { props?.primary ? 'primary ' : null }
            { props?.secondary ? 'secondary ' : null }
            { props?.tertiary ? 'tertiary ' : null }
        ">
        <i if={ props?.icon }>{props.icon}</i>
        <span class="max"><slot></slot></span>
        <a if={ props?.action } onclick={ clicked } class="inverse-link">{ props?.action }</a>
    </div>
    <script>
        export default {
            clicked (e) {
                e.preventDefault();
                e.stopPropagation();
                this.root.dispatchEvent(new Event("action"));
            }
        }
    </script>
</c-snackbar>
Enter fullscreen mode Exit fullscreen mode

Source Code: https://github.com/steevepay/riot-beercss/blob/main/components/c-snackbar.riot

Expliquons le code :

  1. Les balises <c-snackbar> et </c-snackbar> définissent une balise racine personnalisée, portant le même nom que le fichier. Vous devez l'écrire ; sinon, cela pourrait créer des résultats inattendus. Utiliser la balise <div></div> comme balise racine ou redéfinir des balises HTML natives est une mauvaise pratique, donc commencer par c- est une bonne convention.
  2. Le message est passé en tant que balise Slot <slot></slot>, une fonctionnalité centrale de Riot.js permettant d'injecter des modèles HTML personnalisés dans un composant enfant depuis son parent. Dans notre cas, seule une chaîne est injectée, sans HTML.
  3. Les Snackbars peuvent afficher un bouton permettant aux utilisateurs d'agir (Call to action) sur un processus effectué par l'application : Si l'attribut props.action existe, le message est affiché à l'intérieur du bouton d'action.
  4. Lorsque le bouton d'action est cliqué : L'événement click est capturé et exécute la fonction clicked pour émettre un événement personnalisé nommé action.
  5. Pour afficher la Snackbar, elle doit contenir la classe active : lorsque l'attribut props.active existe, il ajoute la classe active grâce à l'expression : { props?.active ? 'active ' : null }.
  6. Différents styles sont disponibles pour le composant, par exemple, primary est appliqué si props?.primary existe et est vrai.

Enfin, chargez et instanciez le composant c-snackbar.riot dans une page principale nommée index.riot:

<index-riot>
    <div style="width:600px;padding:20px;">
        <c-button onclick={ () => openSnack("default") } inverse={ true }>Default</c-button>
        <c-button onclick={ () => openSnack("error") } error={ true }>Error</c-button>
        <c-button onclick={ () => openSnack("primary") } primary={ true }>Primary</c-button>

        <c-snackbar 
            active={ state.active }
            onaction={ close }
            error={ state.error } 
            icon={ state.icon } 
            action={ state.action }
            primary={ state.primary }
        >
            { state.message }
        </c-snackbar>
    </div>
    <script>
        import cButton from "../components/c-button.riot"
        import cSnackbar from "../components/c-snackbar.riot"

        export default {
            components: {
                cSnackbar,
                cButton
            },
            state: {
                active: false,
                icon: null,
                message: null,
                error: null,
                timeout: null
            },
            openSnack(type) {
                if (this.state.active === true) {
                    return;
                }
                this.update({ 
                    active: true,
                    message: type === 'error' ? "Something went wrong." : "Email Archived.",
                    action: type === 'error' ? "Contact Support" : "Undo",
                    icon: type === 'error' ? 'error' : 'check',
                    error: type === 'error',
                    primary: type === 'primary'
                })
                clearTimeout(this.state.timeout)
                this.state.timeout = setTimeout(() => {
                    this.update({ active: false })
                }, 3000)
                this.update();
            },
            close () {
                this.update({ active: false })
            }
        }
    </script>
</index-riot>
Enter fullscreen mode Exit fullscreen mode

Source Code: https://github.com/steevepay/riot-beercss/blob/main/examples/index.snackbar.riot

Détails du code :

  1. Le composant est importé avec import cSnackbar from "./components/c-snackbar.riot"; puis chargé dans l'objet Riot components:{}. Un composant Button est également chargé dans la page : lorsqu'un clic se produit, il affiche le toaster avec un message personnalisé !
  2. Le composant snackbar est instancié avec <c-snackbar /> dans le HTML.
  3. L'état du composant, tel que active, est stocké dans l'objet Riot state:{} sous la propriété booléenne state.active. La propriété est passée en tant qu'attribut, comme : <c-snackbar active={ state.active } />. Pour rendre le toaster complètement interactif, d'autres états sont stockés : le message, l'icône et le libellé de l'action.
  4. Lorsqu'un bouton est cliqué, la fonction openSnack est exécutée grâce à onclick={ () => openSnack("default") }. Un type est passé en premier argument pour sélectionner le type de Snackbar, le message, l'icône et l'action. À la fin, le toaster est affiché en mettant à jour state.active sur vrai.
  5. Pour faire disparaître automatiquement le toaster, un timeout est créé pour masquer le Snackbar en mettant à jour state.active sur false après 2 secondes.
  6. L'événement personnalisé action est surveillé avec onaction : si un clic déclenche l'action du Snackbar, la fonction close met à jour state.active pour la faire disparaître.

Tests du Composant Snackbar

Il existe deux méthodes pour tester le composant Snackbar, et elles sont couvertes dans deux articles différents :

Conclusion

Voilà 🎉 Nous avons créé un composant Snackbar Riot en utilisant des éléments Material Design avec BeerCSS. Le code source est disponible sur Github : https://github.com/steevepay/riot-beercss/blob/main/components/c-snackbar.riot

Bonne journée ! Santé 🍻

Top comments (0)