BRI-1406 — Conventions de nommage requises pour le matching Figma ↔ code¶
Livrable design du projet Design system — notif publish Figma & conventions de nommage (design). But : poser les règles qui permettent au moteur de comparaison (côté dev, BRI-1404) d'apparier un token/composant Figma avec son équivalent code sans faux positifs. Sources : extraction Uimmo du 2026-06-11 (table tokens BRI-304) + artefacts réels du V0 Design QA sur le composant Helper (
projects/design-qa-figma-vs-app/).
0. Principe directeur (à lire avant tout le reste)¶
On matche sur la valeur résolue, jamais sur le nom seul. Le nom sert à apparier deux entités ; la valeur résolue sert à décider s'il y a drift. Trois raisons, toutes vérifiées sur le DS :
- Collisions de noms entre collections.
lg,sm,xl… existent simultanément dans Spaces (gap/padding), Radius (coins) et Sizes (icônes/largeurs), avec des valeurs différentes :lg= 12 en Spaces, 16 en Radius, 24 en Sizes. Un match par nom seul apparie des choses sans rapport. → toujours qualifier par collection + comparer la valeur. - Le nom est instable, la
keyne l'est pas. Chaque variable Figma a unekeyimmuable ; le nom peut être renommé — c'est justement un type de drift qu'on veut détecter. Le matching interne à Figma (versions, dédup) se fait parkey. Mais le code n'a pas ces clés → le pont Figma↔code repose forcément sur une convention de nommage partagée, d'où ce document. - Le nom court ment.
get_variable_defsaffiche le nom court (defaultHeading) alors que la variable réelle est groupée (Typography/defaultHeading). Ne jamais matcher sur le nom court seul.
1. Le « pont » réel : la CSS custom property¶
Quand Figma génère du code (get_design_context), il émet la valeur sous forme de variable CSS : var(--lg, 16px), background: var(--info-state/infobackground50). Côté code, le thème Tailwind/Uniwind résout ses classes vers ces mêmes customs properties. Le dénominateur commun exploitable est donc le nom de la CSS var (secondairement la valeur résolue).
Transformation observée : nom de variable Figma → nom CSS¶
| Variable Figma (nom complet) | CSS var émise par Figma | Règle |
|---|---|---|
Bricks specific/brandText |
--bricks-specific/brandtext |
groupe kebab-case + / + token tout en minuscules |
Bricks specific/brandBackground50 |
--bricks-specific/brandbackground50 |
idem (le B de Background disparaît) |
Info state/infoBackground50 |
--info-state/infobackground50 |
espace → -, minusculisé |
Success state/successText |
--success-state/successtext |
idem |
Backgrounds/neutralBackground50 |
--backgrounds/neutralbackground50 |
idem |
Typography/defaultHeading |
--defaultHeading ⚠️ |
groupe Typography/ DROPPÉ + casse conservée |
Typography/defaultText |
--defaultText ⚠️ |
idem |
⚠️ Incohérence majeure à gérer : la plupart des groupes sont conservés en préfixe kebab minuscule, sauf
Typography/qui est supprimé et garde le camelCase. Le moteur ne peut donc pas appliquer une transformation uniforme — il lui faut une fonction de normalisation (cf. §6) avec ces cas particuliers codés en dur, OU matcher sur la valeur résolue en repli quand la normalisation du nom échoue.
✅ Côté code (confirmé lead dev front, 2026-06-30)¶
Les noms côté code sont les MÊMES qu'en Figma, mais en vrai kebab-case : infoBackground50 → info-background-50, Info state → info-state. Là où Figma émet une bouillie minuscule sans séparateurs (infobackground50), le code sépare proprement les mots et les chiffres.
→ La clé de matching canonique est donc le kebab-case. Le moteur normalise les deux côtés en kebab-case (couper le camelCase + insérer un - avant les groupes de chiffres) puis compare. Le code étant déjà en kebab-case, c'est surtout le nom Figma qu'il faut transformer. La seule exception reste Typography/ (groupe droppé) → canonique default-heading, default-text.
Fichiers à parser côté code : common/front/theme/* (couleurs, spacing, radius, typo).
2. Règles par catégorie¶
2.1 Couleurs¶
- Côté Figma : collection
Colors(~85 variables), noms groupésGroupe/tokenCamelCase. Groupes :Bricks specific,Typography,Core,Borders,Backgrounds,Success state,Alert state,Info state,Pending state,Disabled state,Shiny,Transparency. - Rampes d'état : chaque état sémantique (success/alert/info/pending) suit le schéma
xxxText·xxxBorder·xxxBackgroundNNNavecNNN ∈ {50,100,200,…,950}. - Règle de matching : normaliser le nom Figma → CSS var (cf. §1), apparier, puis comparer la valeur hex/rgb résolue avec tolérance (égalité hex stricte, ou ΔE faible). Les valeurs code sont souvent en
rgb()→ convertir en hex avant comparaison. - Pièges confirmés :
Info statea deux bordures numérotées (infoBorder600,infoBorder950) alors que les autres états ont un seulxxxBordernon numéroté (choix design assumé, pas un drift). Le moteur doit tolérer des schémas par état différents.Core/whiteexiste dansColorset dansPrimitives: c'est un alias légitime (la version Colors pointe vers la primitive), pas un drift.
2.2 Typographie¶
- Côté Figma : styles de texte (pas des variables) — familles
Heading/*(Inter Semi Bold) etText/*(Inter Medium). Paliers :Heading/{3xs,2xs,xs,sm,md,lg,xl,2xl,3xl},Text/{xs,sm,md,lg}. - Le style porte police / taille / interligne / letter-spacing ; la couleur est séparée (token Colors). Le matching typo et le matching couleur sont donc deux comparaisons distinctes sur le même nœud.
- Piège résolution :
letter-spacingest stocké en % dans Figma (-2%) et doit être résolu en px selon la font-size avant comparaison : 16px→-0.32px, 14px→-0.28px, 12px→-0.24px. Comparer des%à despx= faux positif garanti. - font-weight : Figma attend 600 (Semi Bold) sur titres ET messages du Helper. ⚠️ (le code rendait 400 — drift réel détecté en V0.)
- ✅ Côté code (confirmé) : chaque style de texte = une className dédiée qui applique tout d'un coup (police + taille + poids + interligne + letter-spacing). 1 style Figma (
Heading/sm) ↔ 1 className. Le matching typo se fait donc style ↔ className (1:1), puis vérification des valeurs résolues que la classe applique. (Lister les classNames exactes en parsantcommon/front/theme/*côté extracteur code.)
2.3 Espacements, rayons, tailles¶
- Trois collections distinctes, échelles partiellement homonymes :
Spaces(gap/padding) :3xs=2 · 2xs=4 · xs=6 · sm=8 · md=10 · lg=12 · xl=16 · 2xl=20 · 3xl=24 · 4xl=32 · 5xl=40 · 6xl=48 · 7xl=56 · 8xl=64Radius(coins) :3xs=2 · 2xs=4 · xs=6 · sm=8 · md=12 · lg=16 · xl=24 · 2xl=32 · full=9999Sizes(icônes, largeurs) :2xs=8 · xs=12 · sm=16 · md=20 · lg=24 … container-{sm..2xl}=400..1200- Règle de matching impérative : ne jamais apparier
lg↔lgsans connaître la collection (= le rôle CSS :gap/padding→ Spaces,border-radius→ Radius,width/height/icône → Sizes).search_design_systemrenvoievariableCollectionName→ filtrer dessus. Côté code, déduire la collection de la propriété CSS ciblée. - Pièges confirmés (Helper) : padding
lgrendu asymétrique côté code (16px haut/bas, 12px gauche/droite) alors que Figma attend 12px partout → comparer les 4 côtés séparément, pas une valeur unique.
2.4 Composants & variantes¶
- Côté Figma : nom de composant en PascalCase, variantes via props régulières
State=… , Style=… , Size=…. Les valeurs de variantes peuvent être en français + PascalCase (Alerte,Pending,Neutral). - Côté code (Storybook) : args en anglais minuscule (
alert,pending,neutral). Les valeurs de taille sont identiques des deux côtés (md,lg). - Règle : apparier (composant, variante) via une table de normalisation props-à-props, casse insensible, FR→EN. Table de référence (Helper, étendue au DS) :
| Valeur Figma | Valeur code (args) |
|---|---|
Alerte |
alert |
Pending |
pending |
Info |
info |
Success |
success |
Neutral |
neutral |
→ toute nouvelle valeur de variante doit être ajoutée ici. C'est le cœur du matching composant : si la normalisation est fausse, on compare des variantes qui ne se correspondent pas.
2.5 Icônes¶
- Côté Figma : set type Iconsax, noms en kebab-case par famille (
wallet-*,empty-wallet-*,card-*,money-*,arrow-*,chart-*…). - ✅ Côté code (confirmé) : la lib code EST Iconsax (iconsax.io) — même source que Figma. → mapping 1:1 par nom Iconsax (kebab-case), pas de table de traduction nécessaire. Vérifier surtout la présence/absence d'une icône d'un côté et la variante (linear/bold/etc.).
3. Cas de renommage & alias¶
| Cas | Traitement |
|---|---|
| Renommage d'un token (nom change, valeur identique) | C'est un drift de nom légitime à signaler. Détecté en comparant la key (stable) à l'historique côté Figma ; côté code, repérable par « même valeur, nom normalisé différent ». |
Alias (Colors/Core/white → primitive white) |
Non-drift. Maintenir une liste d'alias connus pour ne pas remonter de faux écart. |
Casse incohérente (brandborder500 vs brandBorder300/400) |
Normaliser en comparaison insensible à la casse. (Ce cas précis a été corrigé dans Figma → brandBorder500.) |
Tokens multi-rôles (disabledBackground = border ET background) |
Un token → plusieurs propriétés CSS. Matching 1:1 impossible ; documenter le multi-usage et ne pas trancher automatiquement. |
4. Hors scope du matching (à exclure explicitement)¶
- Lib 🖥️ WebApp (legacy) : plus utilisée, pur legacy. Expose des homonymes (
colors/white,Text/md/md - Medium,gray-secondary…). L'extracteur Figma DOIT filtrer sur lelibraryKeyUimmo sinon faux drifts massifs. Candidate à l'archivage/dépublication. - Kits publics (Material 3, iOS…) : jamais comparés.
- Doublons inter-bibliothèques Uimmo ↔ WebApp : ignorer la version WebApp.
- Collection
Primitives: couche brute sous les tokens sémantiquesColors. La source de vérité pour la comparaison au code est la couche sémantique (Colors), pas les primitives. Transparency/ghost*etShiny/*: rampes spéciales/incomplètes — à comparer seulement si un équivalent code existe, sinon hors scope (ne pas générer de drift « absent en code » par défaut).
5. Pièges de résolution avant comparaison (récap)¶
À normaliser des deux côtés avant tout diff, sinon faux positifs :
- Couleur : tout convertir en hex minuscule (
rgb(236,82,35)→#ec5223). - letter-spacing : résoudre le
%Figma en px selon la font-size. - padding : comparer les 4 côtés séparément (asymétries réelles).
- Nom de token : passer par la fonction de normalisation (§6), pas une égalité brute.
- font-weight : entier (
600) des deux côtés.
6. Spéc de la fonction de normalisation (pour le moteur, BRI-1404)¶
Contrat attendu pour apparier un token Figma à un token code :
Clé canonique = kebab-case (le code est déjà en kebab-case ; on y ramène le nom Figma).
toKebab(name) -> clé canonique
// "Info state/infoBackground50" -> "info-state/info-background-50"
// 1) split sur "/" -> [groupe, token]
// 2) groupe: espaces -> "-", minuscules ("Info state" -> "info-state")
// 3) token: couper le camelCase + insérer "-" avant les groupes de chiffres, minuscules
// ("infoBackground50" -> "info-background-50")
// 4) CAS PARTICULIER: groupe == "Typography" -> drop groupe
// ("Typography/defaultHeading" -> "default-heading")
// 5) recoller "groupe/token" (ou "token" pour Typography)
matchToken(figmaVar, codeVar):
// a) apparier par clé canonique kebab-case (les deux côtés normalisés)
// b) TOUJOURS qualifier par collection/rôle CSS (Spaces|Radius|Sizes|Colors)
// c) décider du drift sur la VALEUR RÉSOLUE, pas sur le nom
// d) si nom non résolu mais valeur unique identique -> apparier + signaler "nom divergent"
Règle d'or : nom pour apparier, valeur pour juger. En cas d'ambiguïté de nom, ne jamais conclure au drift sur le seul nom.
7. Réponses lead dev front (2026-06-30) — questions clôturées¶
- Noms côté code ✅ : mêmes noms qu'en Figma, en kebab-case (pas de mapping type
bg-info-50). → clé de matching = kebab-case (cf. §1 et §6). - Typographie ✅ : variants dédiés en className — une className applique tout le style. Matching style Figma ↔ className (1:1).
- Icônes ✅ : lib code = Iconsax (iconsax.io), même source que Figma → mapping 1:1 par nom.
mddans Radius ✅ : 12.- Fichiers tokens code ✅ :
common/front/theme/*(à parser par l'extracteur code, BRI-1403).
Reste à produire côté dev (pas un bloquant de cette issue) : remplir la colonne « code » de la table BRI-304 en parsant
common/front/theme/*, et en déduire le score de sync V0. La convention de nommage, elle, est figée.