@legba-core/ui

@legba-core/ui

Ce que ça fait

Base Lit et système de thème par variables CSS pour les Web Components @legba-core/ui, plus les composants atomiques média (LGB-031), texte (LGB-032) et composés (LGB-033). Média : deux boutons bascule contrôlés (micro/caméra), une piste vidéo, un mètre de niveau audio, un avatar et un nom. Texte : <legba-message>/<legba-message-input>/<legba-transcript-line> pour un fil de discussion et une transcription live. Composés : <legba-call> (grille d’appel connectée à @legba-core/realtime/client), <legba-call-button> (déclencheur), <legba-chat> (discussion réutilisant la connexion d’un <legba-call>). Un seul jeu de jetons --legba-*, un système de thème clair/sombre/marque à 3 états, et une isolation Shadow DOM héritée directement de Lit.

Symboles publics

SymboleRôle
CONTRAST_THRESHOLDSLes trois seuils de contraste WCAG niveau AA
LEGBA_NAME_FALLBACKTexte de repli affiché par <legba-name> quand value est vide/blanc
LegbaAudioLevel<legba-audio-level> — mètre visuel de niveau audio
LegbaAvatar<legba-avatar> — avatar avec repli initiales/icône générique
LegbaCall<legba-call> — grille d’appel composée, connectée à @legba-core/realtime/client
LegbaCallButton<legba-call-button for="id"> — déclenche connect() sur un <legba-call> référencé
LegbaCameraButton<legba-camera-button> — bouton bascule contrôlé pour la caméra
LegbaChat<legba-chat for="id"> — discussion réutilisant la connexion d’un <legba-call> référencé
LegbaElementClasse de base de tout Web Component @legba-core/ui
LegbaMessage<legba-message> — un message de discussion
LegbaMessageInput<legba-message-input> — composeur de message
LegbaMicButton<legba-mic-button> — bouton bascule contrôlé pour le microphone
LegbaName<legba-name> — affiche un nom avec repli documenté si vide
LegbaTranscriptLine<legba-transcript-line> — une ligne de transcription live
LegbaVideoTrack<legba-video-track> — rendu d’une MediaStreamTrack vidéo
LegbaAudioTrack<legba-audio-track> — lecture d’une MediaStreamTrack audio distante
THEME_TOKENSFeuille de styles Lit posant les jetons --legba-*-default
contrastRatioRapport de contraste WCAG 2.x entre deux couleurs
meetsContrastAADit si un rapport atteint le seuil WCAG AA d’une nature de contenu

Installation

pnpm add @legba-core/ui lit

Depuis LGB-033, @legba-core/ui dépend de @legba-core/realtime (les composants composés <legba-call>/<legba-chat> importent createLegbaRoom depuis @legba-core/realtime/client) — installé automatiquement, aucune étape supplémentaire pour un consommateur npm.

Pièges

  • Un jeton public (--legba-color-primary, etc.) n’est jamais déclaré directement par LegbaElement/THEME_TOKENS — une déclaration directe sur :host gagnerait toujours contre une valeur posée par un ancêtre en light DOM (une propriété posée directement sur un élément prime sur l’héritage). Chaque composant doit consommer un jeton avec un repli explicite vers sa variable -default : var(--legba-color-primary, var(--legba-color-primary-default)), jamais var(--legba-color-primary) seul.
  • La technique « auto-référence pour hériter ou retomber sur un défaut » (--x: var(--x, défaut);) ne fonctionne PAS dans les navigateurs actuels — c’est toujours invalide, vérifié directement, quel que soit ce qu’un ancêtre pose. Ne jamais l’utiliser dans ce paquet ni dans les composants qui en dérivent.
  • Un jeton CSS explicitement vide (--legba-radius: ;) n’est pas équivalent à « non posé » : c’est une déclaration valide mais vide, qui ne déclenche jamais le repli -default — c’est la propriété CSS qui le consomme qui devient invalide et retombe sur sa propre valeur initiale.
  • src/internal/ reste réservé aux composants de démonstration jamais exportés (utilisés uniquement par les tests de composant de LGB-030) — les composants atomiques de LGB-031/032 vivent, eux, sous src/atoms/ et sont bien exportés.
  • Les boutons bascule (LegbaMicButton/LegbaCameraButton) sont entièrement contrôlés : un clic ne mute jamais active lui-même, seulement legba-toggle (l’appelant doit rappeler active = ...) — voir leurs pièges respectifs.
  • <legba-message> masque tout le composant quand text est vide ; <legba-transcript-line> fait l’inverse (indicateur explicite « … ») — choix délibérément différents, documentés sur chaque symbole, pas une incohérence.
  • Accessibilité (LGB-035). Trois faits qu’un intégrateur doit connaître avant de thématiser. (1) --legba-color-primary du thème clair vaut #8a4e12 depuis LGB-035, et non plus #b3661a : l’ancienne valeur ne donnait que 3,88:1 sur le fond clair, sous le seuil AA de 4,5:1. Redéfinir ce jeton, c’est reprendre à sa charge la conformité du couple ainsi créé — contrastRatio et meetsContrastAA sont exportés pour permettre de le vérifier. (2) --legba-target-min (2,75rem) donne leur taille minimale à toutes les cibles : le remplacer par une valeur en px figerait les cibles et les empêcherait de suivre le réglage « taille de police » du navigateur. (3) --legba-color-focus pilote l’anneau de focus, indicateur non textuel dont le seuil est 3:1 — c’est un jeton distinct de primary précisément pour qu’une marque puisse changer son accent sans dégrader la visibilité du focus.
  • "sideEffects": false (package.json) et les imports d’enregistrement de tag. Vérifié en construisant LGB-033 : un import « nu » (import "../atoms/legba-avatar.js";, sans liaison, utilisé pour garantir qu’un tag custom element est enregistré) posé DANS un composant composé (ex. legba-call.ts) est éliminé par tsup/esbuild lors de la construction de ce paquet, à cause de sideEffects: false — un avertissement de build le signale. Sans conséquence ici : src/index.ts ré-exporte déjà CHAQUE atome par son nom (export { LegbaAvatar } from "./atoms/legba-avatar.js"), ce qui force son inclusion dans dist/index.js indépendamment de cet import nu — vérifié en grepant le bundle publié. Risque réel pour un futur composant composé : s’il consomme un atome qui n’est PAS (ou plus) ré-exporté individuellement par src/index.ts, son enregistrement de tag pourrait être silencieusement absent du bundle publié. Règle à respecter : tout atome consommé par un composant composé doit rester exporté par son nom dans src/index.ts.