Recréer le bouton-poussoir Arduino à l'aide de SVG et de <lit-element>

Publié: 2022-03-10
Résumé rapide ↬ HTML est livré avec un tas de contrôles d'entrée, et il existe des tonnes de bibliothèques de composants qui incluent de nombreux contrôles standard tels que des cases à cocher et des boutons radio. Mais que se passe-t-il lorsque vous avez besoin de quelque chose d'inhabituel ?

Dans cet article, vous apprendrez à créer des composants HTML personnalisés qui imitent des objets physiques, tels que le bouton-poussoir Arduino. Nous allons dessiner le composant dans Inkscape à partir de zéro, optimiser le code SVG généré pour le Web et l'envelopper en tant que composant Web autonome à l'aide de la bibliothèque légère lit-element , en accordant une attention particulière aux considérations d'accessibilité et d'utilisabilité mobile.

Aujourd'hui, je vais vous guider dans la création d'un composant HTML qui imite un composant de bouton-poussoir momentané couramment utilisé avec Arduino et dans les projets électroniques. Nous utiliserons des technologies telles que SVG, les composants Web et lit-element , et apprendrons à rendre le bouton accessible grâce à une supercherie JavaScript-CSS.

Commençons!

D'Arduino à HTML : le besoin d'un composant de bouton-poussoir

Avant de nous lancer dans l'aventure, explorons ce que nous allons créer et, plus important encore, pourquoi. Je crée un simulateur Arduino open-source en JavaScript appelé avr8js. Ce simulateur est capable d'exécuter du code Arduino et je l'utiliserai dans une série de tutoriels et de cours qui enseignent aux fabricants comment programmer pour Arduino.

Le simulateur lui-même ne s'occupe que de l'exécution du programme - il exécute le code instruction par instruction et met à jour son état interne et une mémoire tampon en fonction de la logique du programme. Afin d'interagir avec le programme Arduino, vous devez créer des composants électroniques virtuels qui peuvent envoyer des entrées au simulateur ou réagir à ses sorties.

L'exécution du simulateur seul ressemble beaucoup à l'exécution de JavaScript de manière isolée. Vous ne pouvez pas vraiment interagir avec l'utilisateur à moins de créer également des éléments HTML et de les rattacher au code JavaScript via le DOM.

Ainsi, en plus du simulateur du processeur, je travaille également sur une bibliothèque de composants HTML qui imitent le matériel physique, en commençant par les deux premiers composants que vous trouverez dans presque tous les projets électroniques : une LED et un bouton poussoir.

Les éléments LED et Pushbutton en action
Les éléments LED et Pushbutton en action

La LED est relativement simple, car elle n'a que deux états de sortie : allumée et éteinte. Dans les coulisses, il utilise un filtre SVG pour créer l'effet d'éclairage.

Le bouton poussoir est plus intéressant. Il a également deux états, mais il doit réagir aux entrées de l'utilisateur et mettre à jour son état en conséquence, et c'est de là que vient le défi, comme nous le verrons bientôt. Mais d'abord, définissons les exigences de notre composant que nous allons créer.

Plus après saut! Continuez à lire ci-dessous ↓

Définition des exigences pour le bouton-poussoir

Notre composant ressemblera à un bouton poussoir de 12 mm. Ces boutons sont très courants dans les kits de démarrage électroniques et sont livrés avec des capuchons de plusieurs couleurs, comme vous pouvez le voir sur la photo ci-dessous :

Jeu Simon avec boutons poussoirs jaune, rouge, bleu et vert
Jeu Simon avec boutons-poussoirs jaunes, rouges, bleus et verts ( Grand aperçu )

En termes de comportement, le bouton-poussoir doit avoir deux états : enfoncé et relâché. Ceux-ci sont similaires aux événements HTML mousedown/mouseup, mais nous devons nous assurer que les boutons-poussoirs peuvent également être utilisés à partir d'appareils mobiles et sont accessibles aux utilisateurs sans souris.

Comme nous utiliserons l'état du bouton-poussoir comme entrée pour Arduino, il n'est pas nécessaire de prendre en charge les événements "clic" ou "double-clic". C'est au programme Arduino exécuté dans la simulation de décider comment agir sur l'état du bouton, et les boutons physiques ne génèrent pas d'événements de clic.

Si vous souhaitez en savoir plus, consultez une conférence que j'ai eue avec Benjamin Gruenbaum à la SmashingConf Freiburg en 2019 : « Anatomy of a Click ».

Pour résumer nos exigences, notre bouton-poussoir doit :

  1. ressemble au bouton-poussoir physique de 12 mm ;
  2. avoir deux états distincts : pressé et relâché, et ils doivent être discernables visuellement ;
  3. prendre en charge l'interaction de la souris, les appareils mobiles et être accessible aux utilisateurs de clavier ;
  4. prendre en charge différentes couleurs de capuchon (au moins rouge, vert, bleu, jaune, blanc et noir).

Maintenant que nous avons défini les exigences, nous pouvons commencer à travailler sur la mise en œuvre.

SVG pour la victoire

La plupart des composants Web sont implémentés à l'aide d'une combinaison de CSS et de HTML. Lorsque nous avons besoin de graphiques plus complexes, nous utilisons généralement des images raster, au format JPG ou PNG (ou GIF si vous vous sentez nostalgique).

Dans notre cas, cependant, nous utiliserons une autre approche : les graphiques SVG. SVG se prête beaucoup plus facilement aux graphiques complexes que CSS (oui, je sais, vous pouvez créer des choses fascinantes avec CSS, mais cela ne veut pas dire qu'il le devrait). Mais ne vous inquiétez pas, nous n'abandonnons pas complètement CSS. Cela nous aidera à styliser les boutons-poussoirs, et éventuellement même à les rendre accessibles.

SVG a un autre grand avantage par rapport aux images graphiques raster : il est très facile à manipuler à partir de JavaScript et peut être stylisé via CSS. Cela signifie que nous pouvons fournir une seule image pour le bouton et utiliser JavaScript pour personnaliser le capuchon de couleur et les styles CSS pour indiquer l'état du bouton. Sympa, n'est-ce pas ?

Enfin, SVG n'est qu'un document XML, qui peut être modifié avec des éditeurs de texte et intégré directement dans HTML, ce qui en fait une solution parfaite pour créer des composants HTML réutilisables. Êtes-vous prêt à dessiner notre bouton poussoir ?

Dessiner le bouton-poussoir avec Inkscape

Inkscape est mon outil préféré pour créer des graphiques vectoriels SVG. Il est gratuit et regorge de fonctionnalités puissantes, telles qu'une grande collection de préréglages de filtres intégrés, de traçage de bitmap et d'opérations binaires de chemin. J'ai commencé à utiliser Inkscape pour créer de l'art PCB, mais au cours des deux dernières années, j'ai commencé à l'utiliser pour la plupart de mes tâches d'édition graphique.

Dessiner le bouton-poussoir dans Inkscape est assez simple. Nous allons dessiner une vue de dessus du bouton et de ses quatre fils métalliques qui le relient aux autres parties, comme suit :

  1. Rectangle gris foncé de 12 × 12 mm pour le boîtier en plastique, avec des coins légèrement arrondis pour le rendre plus doux.
  2. Rectangle gris clair plus petit de 10,5 × 10,5 pour le couvercle en métal.
  3. Quatre cercles plus foncés, un dans chaque coin pour les broches qui maintiennent le bouton ensemble.
  4. Un grand cercle au milieu, c'est le contour du capuchon du bouton.
  5. Un cercle plus petit au milieu pour le haut du capuchon du bouton.
  6. Quatre rectangles gris clair en forme de « T » pour les fils métalliques du bouton.

Et le résultat, légèrement agrandi :

Notre croquis de bouton-poussoir dessiné à la main
Notre croquis de bouton-poussoir dessiné à la main ( Grand aperçu )

Comme touche finale, nous ajouterons un peu de magie de dégradé SVG au contour du bouton, pour lui donner une sensation 3D :

Ajout d'un remplissage dégradé pour créer une sensation 3D
Ajout d'un remplissage dégradé pour créer une sensation 3D ( Grand aperçu )

On y va ! Nous avons les visuels, nous devons maintenant les mettre sur le Web.

D'Inkscape au Web SVG

Comme je l'ai mentionné ci-dessus, les SVG sont assez simples à intégrer dans HTML - vous pouvez simplement coller le contenu du fichier SVG dans votre document HTML, l'ouvrir dans un navigateur et il sera rendu sur votre écran. Vous pouvez le voir en action dans l'exemple CodePen suivant :

Voir le bouton-poussoir Pen SVG en HTML par @Uri Shaked

Voir le bouton-poussoir Pen SVG en HTML par @Uri Shaked

Cependant, les fichiers SVG enregistrés à partir d'Inkscape contiennent beaucoup de bagages inutiles tels que la version d'Inkscape et la position de la fenêtre lorsque vous avez enregistré le fichier pour la dernière fois. Dans de nombreux cas, il existe également des éléments vides, des dégradés et des filtres inutilisés, et ils gonflent tous la taille du fichier et rendent plus difficile son utilisation dans HTML.

Heureusement, Inkscape peut nettoyer la plupart des dégâts pour nous. Voici comment procéder :

  1. Allez dans le menu Fichier et cliquez sur Nettoyer le document . (Cela supprimera les définitions inutilisées de votre document.)
  2. Allez à nouveau dans Fichier et cliquez sur Enregistrer sous… . Lors de l'enregistrement, sélectionnez SVG optimisé ( *.svg ) dans la liste déroulante Type de fichier.
  3. Vous verrez une boîte de dialogue "Sortie SVG optimisée" avec trois onglets. Cochez toutes les options, à l'exception de « Conserver les données de l'éditeur », « Conserver les définitions non référencées » et « Conserver les ID créés manuellement… ».
( Grand aperçu )

La suppression de toutes ces choses créera un fichier SVG plus petit avec lequel il sera plus facile de travailler. Dans mon cas, le fichier est passé de 4593 octets à seulement 2080 octets, soit moins de la moitié de sa taille. Pour les fichiers SVG plus complexes, cela peut représenter une énorme économie de bande passante et peut faire une différence notable dans le temps de chargement de votre page Web.

Le SVG optimisé est également beaucoup plus facile à lire et à comprendre. Dans l'extrait suivant, vous devriez pouvoir repérer facilement les deux rectangles qui composent le corps du bouton poussoir :

 <rect width="12" height="12" rx=".44" ry=".44" fill="#464646" stroke-width="1.0003"/> <rect x=".75" y=".75" width="10.5" height="10.5" rx=".211" ry=".211" fill="#eaeaea"/> <g fill="#1b1b1b"> <circle cx="1.767" cy="1.7916" r=".37"/> <circle cx="10.161" cy="1.7916" r=".37"/> <circle cx="10.161" cy="10.197" r=".37"/> <circle cx="1.767" cy="10.197" r=".37"/> </g> <circle cx="6" cy="6" r="3.822" fill="url(#a)"/> <circle cx="6" cy="6" r="2.9" fill="#ff2a2a" stroke="#2f2f2f" stroke-opacity=".47" stroke-width=".08"/>

Vous pouvez même raccourcir davantage le code, par exemple en modifiant la largeur du trait du premier rectangle de 1.0003 à 1 . Cela ne fait pas de différence significative dans la taille du fichier, mais cela rend le code plus facile à lire.

En général, un passage manuel sur le fichier SVG généré est toujours utile. Dans de nombreux cas, vous pouvez supprimer des groupes vides ou appliquer des transformations matricielles, ainsi que simplifier les coordonnées du dégradé en les mappant de "l'espace utilisateur lors de l'utilisation" (coordonnées globales) à la "boîte de délimitation de l'objet" (par rapport à l'objet). Ces optimisations sont facultatives, mais vous obtenez un code plus facile à comprendre et à gérer.

À partir de ce moment, nous allons mettre Inkscape de côté et travailler avec la représentation textuelle de l'image SVG.

Création d'un composant Web réutilisable

Jusqu'à présent, nous avons obtenu les graphiques de notre bouton-poussoir, prêts à être insérés dans notre simulateur. Nous pouvons facilement personnaliser la couleur du bouton en modifiant l'attribut de fill du plus petit cercle et la couleur de départ du dégradé du plus grand cercle.

Notre prochain objectif est de transformer notre bouton-poussoir en un composant Web réutilisable qui peut être personnalisé en passant un attribut de color et réagit à l'interaction de l'utilisateur (événements de presse/publication). Nous utiliserons lit-element , une petite bibliothèque qui simplifie la création de composants Web.

lit-element excelle dans la création de petites bibliothèques de composants autonomes. Il est construit au-dessus de la norme Web Components, qui permet à ces composants d'être consommés par n'importe quelle application Web, quel que soit le framework utilisé : Angular, React, Vue ou Vanilla JS pourraient tous utiliser notre composant.

La création de composants dans lit-element se fait à l'aide d'une syntaxe basée sur les classes, avec une méthode render() qui renvoie le code HTML de l'élément. Un peu similaire à React, si vous le connaissez. Cependant, contrairement à react, lit-element utilise des littéraux de modèle balisés Javascript standard pour définir le contenu du composant.

Voici comment créer un composant hello-world simple :

 import { customElement, html, LitElement } from 'lit-element'; @customElement('hello-world') export class HelloWorldElement extends LitElement { render() { return html` <h1> Hello, World! </h1> `; } }

Ce composant peut ensuite être utilisé n'importe où dans votre code HTML simplement en écrivant <hello-world></hello-world> .

Note : En fait, notre bouton-poussoir nécessite juste un peu plus de code : nous devons déclarer une propriété d'entrée pour la couleur, en utilisant le @property() (et avec une valeur par défaut de rouge), et coller le code SVG dans notre render() , en remplaçant la couleur du capuchon du bouton par la valeur de la propriété color (voir exemple). Les bits importants sont à la ligne 5, où nous définissons la propriété color : @property() color = 'red'; De plus, à la ligne 35 (où nous utilisons cette propriété pour définir la couleur de remplissage du cercle qui forme le capuchon du bouton), en utilisant la syntaxe littérale du modèle JavaScript, écrite sous la forme ${color} :

 <circle cx="6" cy="6" r="2.9" fill="${color}" stroke="#2f2f2f" stroke-opacity=".47" stroke-width=".08" />

Le rendre interactif

La dernière pièce du puzzle serait de rendre le bouton interactif. Il y a deux aspects que nous devons considérer : la réponse visuelle à l'interaction ainsi que la réponse programmatique à l'interaction.

Pour la partie visuelle, nous pouvons simplement inverser le remplissage dégradé du contour du bouton, ce qui créera l'illusion que le bouton a été pressé :

Inverser le dégradé de contour du bouton
Inverser le dégradé de contour du bouton ( Grand aperçu )

Le dégradé du contour du bouton est défini par le code SVG suivant, où ${color} est remplacé par la couleur du bouton par lit-element , comme expliqué ci-dessus :

 <linearGradient x1="0" x2="1" y1="0" y2="1"> <stop stop-color="#ffffff" offset="0" /> <stop stop-color="${color}" offset="0.3" /> <stop stop-color="${color}" offset="0.5" /> <stop offset="1" /> </linearGradient>

Une approche pour l'aspect du bouton enfoncé consisterait à définir un deuxième dégradé, à inverser l'ordre des couleurs et à l'utiliser comme remplissage du cercle chaque fois que le bouton est enfoncé. Cependant, il existe une astuce sympa qui nous permet de réutiliser le même dégradé : nous pouvons faire pivoter l'élément svg de 180 degrés à l'aide d'une transformation SVG :

 <circle cx="6" cy="6" r="3.822" fill="url(#a)" transform="rotate(180 6 6)" />

L'attribut transform indique à SVG que nous voulons faire pivoter le cercle de 180 degrés et que la rotation doit se produire autour du point (6, 6) qui est le centre du cercle (défini par cx et cy ). Les transformations SVG affectent également le remplissage de la forme, et donc notre dégradé sera également tourné.

Nous voulons uniquement inverser le dégradé lorsque le bouton est enfoncé, donc au lieu d'ajouter l'attribut transform directement sur l'élément <circle> , comme nous l'avons fait ci-dessus, nous allons en fait définir une classe CSS pour cet élément, puis en profiter du fait que les attributs SVG peuvent être définis via CSS, bien qu'en utilisant une syntaxe légèrement différente :

 transform: rotate(180deg); transform-origin: 6px 6px;

Ces deux règles CSS font exactement la même chose que la transform que nous avions ci-dessus - faites pivoter le cercle de 180 degrés autour de son centre à (6, 6). Nous voulons que ces règles soient appliquées uniquement lorsque le bouton est pressé, nous allons donc ajouter un nom de classe CSS à notre cercle :

 <circle class="button-contour" cx="6" cy="6" r="3.822" fill="url(#a)" />

Et maintenant, nous pouvons utiliser la pseudo-classe CSS :active pour appliquer une transformation au button-contour chaque fois que l'élément SVG est cliqué :

 svg:active .button-contour { transform: rotate(180deg); transform-origin: 6px 6px; }

lit-element nous permet d'attacher une feuille de style à notre composant en la déclarant dans un getter statique à l'intérieur de notre classe de composant, en utilisant un littéral de modèle balisé :

 static get styles() { return css` svg:active .button-contour { transform: rotate(180deg); transform-origin: 6px 6px; } `; }

Tout comme le modèle HTML, cette syntaxe nous permet d'injecter des valeurs personnalisées dans notre code CSS, même si nous n'en avons pas besoin ici. lit-element s'occupe également de créer Shadow DOM pour notre composant, de sorte que le CSS n'affecte que les éléments de notre composant et ne se répande pas dans d'autres parties de l'application.

Maintenant, qu'en est-il du comportement programmatique du bouton lorsqu'il est pressé ? Nous voulons déclencher un événement afin que les utilisateurs de notre composant puissent comprendre chaque fois que l'état du bouton change. Une façon de faire est d'écouter les événements mousedown et mouseup sur l'élément SVG, et de déclencher les événements « button-press »/« button-release » en conséquence. Voici à quoi cela ressemble avec la syntaxe lit-element :

 render() { const { color } = this; return html` <svg @mousedown=${() => this.dispatchEvent(new Event('button-press'))} @mouseup=${() => this.dispatchEvent(new Event('button-release'))} ... </svg> `; }

Cependant, ce n'est pas la meilleure solution, comme nous le verrons bientôt. Mais d'abord, jetez un coup d'œil au code que nous avons obtenu jusqu'à présent :

 import { customElement, css, html, LitElement, property } from 'lit-element'; @customElement('wokwi-pushbutton') export class PushbuttonElement extends LitElement { @property() color = 'red'; static get styles() { return css` svg:active .button-contour { transform: rotate(180deg); transform-origin: 6px 6px; } `; } render() { const { color } = this; return html` <svg @mousedown=${() => this.dispatchEvent(new Event('button-press'))} @mouseup=${() => this.dispatchEvent(new Event('button-release'))} width="18mm" height="12mm" version="1.1" viewBox="-3 0 18 12" xmlns="https://www.w3.org/2000/svg" > <defs> <linearGradient x1="0" x2="1" y1="0" y2="1"> <stop stop-color="#ffffff" offset="0" /> <stop stop-color="${color}" offset="0.3" /> <stop stop-color="${color}" offset="0.5" /> <stop offset="1" /> </linearGradient> </defs> <rect x="0" y="0" width="12" height="12" rx=".44" ry=".44" fill="#464646" /> <rect x=".75" y=".75" width="10.5" height="10.5" rx=".211" ry=".211" fill="#eaeaea" /> <g fill="#1b1b1"> <circle cx="1.767" cy="1.7916" r=".37" /> <circle cx="10.161" cy="1.7916" r=".37" /> <circle cx="10.161" cy="10.197" r=".37" /> <circle cx="1.767" cy="10.197" r=".37" /> </g> <g fill="#eaeaea"> <path d="m-0.3538 1.4672c-0.058299 0-0.10523 0.0469-0.10523 0.10522v0.38698h-2.1504c-0.1166 0-0.21045 0.0938-0.21045 0.21045v0.50721c0 0.1166 0.093855 0.21045 0.21045 0.21045h2.1504v0.40101c0 0.0583 0.046928 0.10528 0.10523 0.10528h0.35723v-1.9266z" /> <path d="m-0.35376 8.6067c-0.058299 0-0.10523 0.0469-0.10523 0.10523v0.38697h-2.1504c-0.1166 0-0.21045 0.0939-0.21045 0.21045v0.50721c0 0.1166 0.093855 0.21046 0.21045 0.21046h2.1504v0.401c0 0.0583 0.046928 0.10528 0.10523 0.10528h0.35723v-1.9266z" /> <path d="m12.354 1.4672c0.0583 0 0.10522 0.0469 0.10523 0.10522v0.38698h2.1504c0.1166 0 0.21045 0.0938 0.21045 0.21045v0.50721c0 0.1166-0.09385 0.21045-0.21045 0.21045h-2.1504v0.40101c0 0.0583-0.04693 0.10528-0.10523 0.10528h-0.35723v-1.9266z" /> <path d="m12.354 8.6067c0.0583 0 0.10523 0.0469 0.10523 0.10522v0.38698h2.1504c0.1166 0 0.21045 0.0938 0.21045 0.21045v0.50721c0 0.1166-0.09386 0.21045-0.21045 0.21045h-2.1504v0.40101c0 0.0583-0.04693 0.10528-0.10523 0.10528h-0.35723v-1.9266z" /> </g> <g> <circle class="button-contour" cx="6" cy="6" r="3.822" fill="url(#a)" /> <circle cx="6" cy="6" r="2.9" fill="${color}" stroke="#2f2f2f" stroke-opacity=".47" stroke-width=".08" /> </g> </svg> `; } }
  • Voir la démo →

Vous pouvez cliquer sur chacun des boutons et voir comment ils réagissent. Le rouge a même des écouteurs d'événements (définis dans index.html ), donc lorsque vous cliquez dessus, vous devriez voir des messages écrits sur la console. Mais attendez, et si vous vouliez utiliser le clavier à la place ?

Rendre le composant accessible et adapté aux mobiles

Hourra ! Nous avons créé un composant de bouton poussoir réutilisable avec SVG et lit-element !

Avant d'approuver notre travail, il y a quelques questions que nous devrions examiner. Premièrement, le bouton n'est pas accessible aux personnes qui utilisent le clavier. De plus, le comportement sur mobile est incohérent : les boutons apparaissent enfoncés lorsque vous maintenez votre doigt dessus, mais les événements JavaScript ne sont pas déclenchés si vous maintenez votre doigt enfoncé pendant plus d'une seconde.

Commençons par régler le problème du clavier. Nous pourrions rendre le bouton accessible au clavier en ajoutant un attribut tabindex à l'élément svg, le rendant focusable. Une meilleure alternative, à mon avis, consiste simplement à envelopper le bouton avec un élément <button> standard. En utilisant l'élément standard, nous le rendons également compatible avec les lecteurs d'écran et d'autres technologies d'assistance.

Cette approche présente un inconvénient, comme vous pouvez le voir ci-dessous :

Notre joli composant enfermé dans un élément bouton
Notre joli composant encagé dans un élément <button> . ( Grand aperçu )

L'élément <button> est livré avec un style intégré. Cela pourrait facilement être résolu en appliquant du CSS pour supprimer ces styles :

 button { border: none; background: none; padding: 0; margin: 0; text-decoration: none; -webkit-appearance: none; -moz-appearance: none; } button:active .button-contour { transform: rotate(180deg); transform-origin: 6px 6px; }

Notez que nous avons également remplacé le sélecteur qui inverse la grille du contour des boutons, en utilisant button:active à la place de svg:active . Cela garantit que le style de bouton enfoncé s'applique chaque fois que l'élément <button> réel est enfoncé, quel que soit le périphérique d'entrée utilisé.

Nous pouvons même rendre notre composant plus convivial pour les lecteurs d'écran en ajoutant un attribut aria-label qui inclut la couleur du bouton :

 <button aria-label="${color} pushbutton">

Il reste encore une chose à régler : les événements "appuyer sur un bouton" et "relâcher un bouton". Idéalement, nous voulons les déclencher en fonction de la pseudo-classe CSS :active du bouton, comme nous l'avons fait dans le CSS ci-dessus. En d'autres termes, nous aimerions déclencher l'événement « button-press » chaque fois que le bouton devient :active , et l'événement « button-release » se déclencher chaque fois qu'il est :not(:active) .

Mais comment écouter une pseudo-classe CSS de Javascript ?

Il s'avère que ce n'est pas si simple. J'ai posé cette question à la communauté JavaScript Israel, et j'ai finalement trouvé une idée qui a fonctionné à partir du fil sans fin : utilisez le sélecteur :active pour déclencher une animation CSS super courte, puis je peux l'écouter depuis JavaScript en utilisant le animationstart un événement.

Une expérience CodePen rapide a prouvé que cela fonctionne réellement de manière fiable. Même si j'aimais la sophistication de cette idée, j'ai décidé d'opter pour une solution différente et plus simple. L'événement animationstart n'est pas disponible sur Edge et iOS Safari, et déclencher une animation CSS juste pour détecter le changement d'état du bouton ne semble pas être la bonne façon de faire les choses.

Au lieu de cela, nous allons ajouter trois paires d'écouteurs d'événements à l'élément <button> : mousedown/mouseup pour la souris, touchstart/touchend pour les appareils mobiles et keyup/keydown pour le clavier. Pas la solution la plus élégante, à mon avis, mais elle fait l'affaire et fonctionne sur tous les navigateurs.

 <button aria-label="${color} pushbutton" @mousedown=${this.down} @mouseup=${this.up} @touchstart=${this.down} @touchend=${this.up} @keydown=${(e: KeyboardEvent) => e.keyCode === SPACE_KEY && this.down()} @keyup=${(e: KeyboardEvent) => e.keyCode === SPACE_KEY && this.up()} >

SPACE_KEY est une constante égale à 32, et up / down sont deux méthodes de classe qui distribuent les événements d'appui sur le button-press et button-release :

 @property() pressed = false; private down() { if (!this.pressed) { this.pressed = true; this.dispatchEvent(new Event('button-press')); } } private up() { if (this.pressed) { this.pressed = false; this.dispatchEvent(new Event('button-release')); } }
  • Vous pouvez trouver le code source complet ici.

Nous l'avons fait!

Ce fut un assez long voyage qui a commencé par décrire les exigences et dessiner l'illustration du bouton dans Inkscape, passer par la conversion de notre fichier SVG en un composant Web réutilisable à l'aide lit-element , et après nous être assurés qu'il est accessible et adapté aux mobiles, nous s'est retrouvé avec près de 100 lignes de code d'un délicieux composant de bouton-poussoir virtuel.

Ce bouton n'est qu'un composant unique dans une bibliothèque open-source de composants électroniques virtuels que je construis. Vous êtes invité à jeter un coup d'œil au code source ou à consulter le Storybook en ligne où vous pouvez voir et interagir avec tous les composants disponibles.

Et enfin, si vous êtes intéressé par Arduino, jetez un œil au cours de programmation Simon pour Arduino que je suis en train de construire, où vous pouvez également voir le bouton-poussoir en action.

A la prochaine, alors !