@cyrilld/zestds 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1156 -48
- package/dist/cursors.cjs +2 -1
- package/dist/cursors.cjs.map +1 -1
- package/dist/cursors.d.cts +0 -1
- package/dist/cursors.d.ts +0 -1
- package/dist/cursors.js +2 -1
- package/dist/cursors.js.map +1 -1
- package/dist/flags.cjs +2 -1
- package/dist/flags.cjs.map +1 -1
- package/dist/flags.d.cts +1 -2
- package/dist/flags.d.ts +1 -2
- package/dist/flags.js +2 -1
- package/dist/flags.js.map +1 -1
- package/dist/index.cjs +704 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1498 -5
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +665 -6
- package/dist/index.d.ts +665 -6
- package/dist/index.js +684 -7
- package/dist/index.js.map +1 -1
- package/package.json +12 -4
package/README.md
CHANGED
|
@@ -10,18 +10,20 @@ import "@cyrilld/zestds/dist/index.css";
|
|
|
10
10
|
<Home01 width={20} height={20} />
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Today the package publishes **the tokens
|
|
14
|
-
|
|
13
|
+
Today the package publishes **the tokens, the icon families, the logo and the button family**.
|
|
14
|
+
Phase 2 started on 2026-09-09 with `Button`, `CloseButton`, `UtilityButton` and `Spinner` — see
|
|
15
|
+
"Ce qui reste à faire" for what follows.
|
|
15
16
|
|
|
16
17
|
**Both imports matter.** The code and the styles travel separately — `dist/index.js` on one
|
|
17
18
|
side, `dist/index.css` on the other. Importing the first without the second gives components
|
|
18
19
|
that render, structurally, with no background, no spacing and no radius. Nothing fails and
|
|
19
20
|
nothing warns.
|
|
20
21
|
|
|
21
|
-
Its Storybook is the design system's documentation, written in French.
|
|
22
|
-
are written — colors, typography, spacing, radius, shadows, the focus ring, icons
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
Its Storybook is the design system's documentation, written in French. Twelve Foundations pages
|
|
23
|
+
are written — colors, typography, spacing, radius, shadows, the focus ring, icons, file icons,
|
|
24
|
+
flag icons, cursors, avatars, logo — plus the first Base components page, Boutons. The rest of the
|
|
25
|
+
plan sits alongside them as **announced but empty pages**: two remaining foundations, then the
|
|
26
|
+
other Base components and the Application components.
|
|
25
27
|
|
|
26
28
|
That isn't decoration. A sidebar that only shows what exists gives the illusion of a complete
|
|
27
29
|
system: someone looking for "Badges" and not finding it can't tell whether it doesn't exist, is
|
|
@@ -38,7 +40,8 @@ src/
|
|
|
38
40
|
styles/ theme.css (the tokens), fonts.css, typography.css, base.css
|
|
39
41
|
fonts/ the six Averta .woff2 files — commercial license, see fonts/README.md
|
|
40
42
|
components/
|
|
41
|
-
base/
|
|
43
|
+
base/ Button/ CloseButton/ UtilityButton/ Spinner/ Badge/ Avatar/ Tooltip/
|
|
44
|
+
Checkbox/ Toggle/ — phase 2, since 2026-09-09
|
|
42
45
|
foundations/ the icons: catalogue.ts generated from Figma, index.tsx built on it
|
|
43
46
|
docs/ the Storybook documentation — MDX pages and their boards. NOT shipped.
|
|
44
47
|
Introduction.mdx the Storybook landing page
|
|
@@ -69,7 +72,7 @@ Colors are layered, and a component only ever cites the last two:
|
|
|
69
72
|
| Ramps | `--zds-color-brand-600` | Never |
|
|
70
73
|
| Utility palettes | `--zds-color-utility-lime-500` | To categorize |
|
|
71
74
|
| Roles | `--zds-color-text-primary` | Yes |
|
|
72
|
-
| Component | `--zds-color-toggle-
|
|
75
|
+
| Component | `--zds-color-toggle-bg-pressed` | Last resort |
|
|
73
76
|
|
|
74
77
|
Beyond colors: the type scale (thirteen sizes, each with its line height), the named spacing
|
|
75
78
|
scale, thirteen widths, eleven radii, seven shadows plus the relief, the focus ring, and the
|
|
@@ -79,14 +82,14 @@ eight brand gradients in three angles each.
|
|
|
79
82
|
|
|
80
83
|
| Import | What | Weight |
|
|
81
84
|
| --- | --- | --- |
|
|
82
|
-
| `@cyrilld/zestds` | tokens,
|
|
83
|
-
| `@cyrilld/zestds/flags` | 234 country flags |
|
|
85
|
+
| `@cyrilld/zestds` | tokens, 135 icons, 27 file icons, the logo, the nine base components | 249 KB (+ 70 KB CSS) |
|
|
86
|
+
| `@cyrilld/zestds/flags` | 234 country flags | 329 KB |
|
|
84
87
|
| `@cyrilld/zestds/cursors` | 50 cursors | 94 KB |
|
|
85
88
|
|
|
86
89
|
⚠️ **The two catalogues are deliberately NOT re-exported from the root.** A catalogue is a data
|
|
87
90
|
object queried by key at runtime — that is the whole point of `<FlagIcon code={country} />` — so
|
|
88
91
|
no bundler can prove an entry is unused and nothing gets tree-shaken away. A single `export *`
|
|
89
|
-
added to `src/index.ts` for convenience would take the root from
|
|
92
|
+
added to `src/index.ts` for convenience would take the root from 249 KB to over 670 KB without
|
|
90
93
|
breaking anything visible: typecheck passes, build passes, the package silently triples.
|
|
91
94
|
|
|
92
95
|
Flags need no CSS at all — their colours are national facts, not tokens. Cursors need
|
|
@@ -159,8 +162,16 @@ To try local changes in another project before publishing a new version:
|
|
|
159
162
|
| `yarn typecheck` | Type-check the package |
|
|
160
163
|
| `yarn lint` | Lint the package |
|
|
161
164
|
| `yarn build` | Build to `dist/` (ESM, CJS, types, CSS) |
|
|
165
|
+
| `yarn verify:interrupteur` | Les QUATRE géométries, le déplacement PEINT du bouton, la bordure déclarée ET peinte, le survol dans les deux sens, et cinq contrastes épinglés |
|
|
162
166
|
| `yarn verify:render` | Drive Edge over the pages: fonts, boards, red flags, console errors |
|
|
163
167
|
| `yarn verify:labels` | Contraste des étiquettes d'icône de fichier, sans navigateur |
|
|
168
|
+
| `yarn verify:tokens` | Les composants ne citent que les couleurs de Zest, et aucun jeton de composant ne redouble un rôle |
|
|
169
|
+
| `yarn verify:foundations` | Le thème se lit en entier, aucune valeur brute qu'un jeton nomme déjà, aucune mention du fournisseur tiers |
|
|
170
|
+
| `yarn verify:buttons` | Géométrie, spinner, contrastes et anneau de focus des boutons — mesurés sur la peinture |
|
|
171
|
+
| `yarn verify:badges` | Les 207 badges contre le modèle relevé sur les 477 symboles du Figma, plus 26 contrastes |
|
|
172
|
+
| `yarn verify:avatars` | Les six boîtes, les deux géométries du point de statut, les chevauchements, trois contrastes |
|
|
173
|
+
| `yarn verify:info-bulles` | Les deux anatomies, le débord PEINT de la flèche sur les quatre côtés, les six placements, et que la flèche pointe sur le centre du déclencheur |
|
|
174
|
+
| `yarn verify:checkboxes` | Les DEUX pages en une passe : les tailles et les sept valeurs qui changent avec elles, l'épaisseur PEINTE de la marque, et cinq contrastes épinglés |
|
|
164
175
|
|
|
165
176
|
`verify:render` needs a dev server running and `storybook-static/index.json` present (it reads
|
|
166
177
|
the story ids from there rather than guessing them). Point it elsewhere with
|
|
@@ -187,10 +198,18 @@ git tag automatically (e.g. `v0.2.0`) — `--follow-tags` pushes both the commit
|
|
|
187
198
|
|
|
188
199
|
## Testing
|
|
189
200
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
201
|
+
**127 tests across nine component suites** (counted 2026-09-11): 27 on the avatars, 23 on the
|
|
202
|
+
tooltip, 18 on the checkbox and its radio, 17 on the badge, 15 on the toggle, and 27 over the
|
|
203
|
+
button family — `Button` 15, `CloseButton` 5, `UtilityButton` 4, `Spinner` 3. `--passWithNoTests` was dropped on
|
|
204
|
+
2026-09-09, as planned: the suite is no longer empty, so a red `yarn test` means something again.
|
|
205
|
+
|
|
206
|
+
The tests check **behaviour, not paint**. They do not assert a padding or a colour: those live in
|
|
207
|
+
the component's CSS sheet, and jsdom does not apply imported sheets — a test claiming
|
|
208
|
+
`padding: 10px` here would lie the day the CSS moved, without ever failing. The browser boards on
|
|
209
|
+
the Boutons page measure those, for real. What the tests do pin down is the three places the
|
|
210
|
+
button departs from reflex: loading blocks activation WITHOUT leaving the tab order, "icon only"
|
|
211
|
+
is derived from the absence of a label rather than declared, and an unnamed icon-only button
|
|
212
|
+
warns.
|
|
194
213
|
|
|
195
214
|
When components arrive, they are tested with [Vitest](https://vitest.dev) and
|
|
196
215
|
[React Testing Library](https://testing-library.com/react), driving them the way a user would
|
|
@@ -231,15 +250,17 @@ both `tsc` and `storybook build`, and only a real browser found them:
|
|
|
231
250
|
- [x] **Icônes** — 121 publiées, les neuf catégories de la page « Icônes » du Figma.
|
|
232
251
|
Navigateur et règles d'usage. Les conflits de nom et les styles à revoir sont sortis de
|
|
233
252
|
la page le 2026-09-08 : voir « Les décisions ouvertes sur les icônes » plus bas.
|
|
234
|
-
- [x] **
|
|
253
|
+
- [x] **Icônes de fichier** — 27 types × 3 habillages, page en ligne. Les dessins viennent
|
|
235
254
|
**du Figma** (`3847:2911`), re-teintés sur les jetons : dix substitutions,
|
|
236
|
-
l'écart mesuré en Lab. ⚠️ Le cadre Figma `3847:2911` est
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
(Default / Gray / Solid) sont une **proposition** : ni la
|
|
240
|
-
|
|
241
|
-
- [x] **
|
|
242
|
-
|
|
255
|
+
l'écart mesuré en Lab. ⚠️ Le cadre Figma `3847:2911` est une bibliothèque **tierce** collée
|
|
256
|
+
telle quelle — variables d'origine, collection en anglais, et en retard sur le paquet. Il
|
|
257
|
+
ne décide que la LISTE des 27 types. ⚠️ Les trois règles d'usage des habillages
|
|
258
|
+
(Default / Gray / Solid) sont une **proposition** : ni la source d'origine ni le Figma
|
|
259
|
+
n'en donnent, elles attendent un arbitrage.
|
|
260
|
+
- [x] **Drapeaux** — 234 drapeaux, page en ligne. ⚠️ **Cette page a changé de nom deux
|
|
261
|
+
fois** : « Flag icons » à la demande de Micka, puis « Drapeaux » de nouveau le
|
|
262
|
+
2026-09-11, quand les titres de pages sont repassés en français — voir « Décidé ».
|
|
263
|
+
Générés depuis le Figma (`3853:17761`), pastille ronde, une seule forme. Les
|
|
243
264
|
couleurs ne sont **pas** portées sur les jetons : celles d'un drapeau sont des faits
|
|
244
265
|
nationaux. Les noms français viennent d'`Intl.DisplayNames`, pas d'une liste recopiée.
|
|
245
266
|
⚠️ Cinq codes du Figma sont faux et corrigés dans le catalogue — voir « En attente ».
|
|
@@ -263,14 +284,110 @@ both `tsc` and `storybook build`, and only a real browser found them:
|
|
|
263
284
|
COPIE du catalogue : Storybook réclame un fichier, pas un composant. Si le logo change,
|
|
264
285
|
régénérer le catalogue **et** recopier le favicon.
|
|
265
286
|
- [ ] **Phase 2** — base components : boutons, badges, champs, sélecteurs, info-bulles
|
|
266
|
-
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
287
|
+
- [x] **Boutons** — page en ligne, quatre composants livrés le 2026-09-09. `Button`
|
|
288
|
+
(11 hiérarchies × 5 tailles × 5 états × icône seule), `CloseButton` (3 tailles + fond
|
|
289
|
+
sombre), `UtilityButton` (28 et 32 px) et `Spinner`. Relevés sur cinq cadres du Figma.
|
|
290
|
+
Le `Button` retiré le 2026-09-08 est celui-ci, recodé : l'ancien peignait son primaire en
|
|
291
|
+
`#4f46e5` — un indigo qui n'est pas le bleu de Zest — dimensionnait son `sm` à 13 px,
|
|
292
|
+
taille absente de l'échelle, et ne citait aucun jeton. Récupérable par
|
|
293
|
+
`git checkout 69a30fa -- src/Button` si on veut le relire.
|
|
294
|
+
⚠️ **Un écart au Figma, arbitré** — voir « Décidé ».
|
|
295
|
+
⚠️ **Trois questions restent ouvertes** — voir « En attente » : les bordures sous les 3:1,
|
|
296
|
+
le tracé du spinner, et le soulignement des liens.
|
|
297
|
+
✅ Retire `.zds-doc-bouton` du provisoire de `docs.css`.
|
|
298
|
+
- [x] **Badges** — page en ligne, un composant livré le 2026-09-10. `Badge` : 3 habillages
|
|
299
|
+
(`pill`, `badge`, `modern`) × 3 tailles × **13 couleurs**, plus quatre emplacements — le
|
|
300
|
+
point, la croix de retrait, une icône de tête, une icône de fin. Relevé sur trois cadres :
|
|
301
|
+
`Badge` (3869:2612, **477 symboles**), `_Dot` (3874:1192) et `_Badge close X` (3869:4461).
|
|
302
|
+
⚠️ **ILS N'ÉTAIENT PAS BLOQUÉS**, et cette ligne a longtemps dit le contraire. Les trois
|
|
303
|
+
habillages sont deux fonds DOUX et un fond blanc : le Figma ne dessine aucun badge en
|
|
304
|
+
aplat, donc `success-solid` et `warning-solid` n'y sont employés par personne. L'arbitrage
|
|
305
|
+
de ces deux jetons reste ouvert — il concerne le premier bouton plein, pas le badge.
|
|
306
|
+
✅ **Les treize couleurs tiennent leurs deux seuils de contraste** depuis l'arbitrage du
|
|
307
|
+
2026-09-10 : turquoise, tilleul et jaune, les trois teintes claires, descendent de deux
|
|
308
|
+
crans là où les dix autres gardent les leurs. Voir « Décidé ».
|
|
309
|
+
⚠️ **Une anomalie du Figma est reproduite** en taille `sm`, et **deux neutres presque
|
|
310
|
+
identiques** sont livrés faute d'arbitrage. Voir « En attente ».
|
|
311
|
+
✅ Ajoute `verify:badges` : géométrie rendue contre le modèle des 477 symboles, 26
|
|
312
|
+
contrastes, anneau de focus de la croix.
|
|
313
|
+
- [x] **Avatars** — page en ligne, trois composants livrés le 2026-09-10. `Avatar`
|
|
314
|
+
(6 tailles × 4 contenus, bordure et statut optionnels), `AvatarGroup` et
|
|
315
|
+
`AvatarLabelGroup`. Relevé sur CINQ cadres : `Avatar` (3881:5036, 48 symboles),
|
|
316
|
+
`Status icon` (3881:5020), `Avatar group` (3881:4989), `_Avatar add button` (3881:4946) et
|
|
317
|
+
`Avatar label group` (3881:4930).
|
|
318
|
+
⚠️ **CE DÉPÔT AFFIRMAIT QU'IL N'Y AVAIT PAS DE COMPOSANT AVATAR.** C'était faux : le relevé
|
|
319
|
+
s'était arrêté sur le cadre de la banque de photos. Voir « Décidé ».
|
|
320
|
+
✅ Les **initiales** entrent dans le système, à leur place dans un ordre de priorité —
|
|
321
|
+
photo > initiales > picto. La règle « jamais d'initiales » de la page Foundations est
|
|
322
|
+
abrogée, et l'échelle de tailles qu'elle proposait était fausse.
|
|
323
|
+
✅ Ajoute deux icônes au catalogue (133 → **135**) et `verify:avatars`.
|
|
324
|
+
⚠️ Le statut est **absent par défaut** : la production ne le gère pas encore.
|
|
325
|
+
- [x] **Info-bulles** — page en ligne, trois composants livrés le 2026-09-10. `Tooltip`
|
|
326
|
+
(6 positions × flèche optionnelle × ligne de support optionnelle), `HelpTooltip` — l'icône
|
|
327
|
+
d'aide de 16 px qui porte sa propre bulle — et `TooltipArrow`, le dessin de la flèche.
|
|
328
|
+
Relevés sur deux cadres : `Tooltip` (3266:935, 14 symboles) et `Help icon` (3266:1096,
|
|
329
|
+
28 symboles).
|
|
330
|
+
⚠️ **Le développeur choisit la position, et rien ne se retourne tout seul.** Arbitrage du
|
|
331
|
+
lead front : le paquet reste à zéro dépendance d'exécution, donc les six placements sont
|
|
332
|
+
du CSS. La conséquence est à connaître avant de s'en servir — une bulle posée près du bord
|
|
333
|
+
de l'écran en sort, et rien ne la retournera. Voir « Décidé ».
|
|
334
|
+
⚠️ **Une décision prise le matin même a été renversée** : un premier jet passait par
|
|
335
|
+
`react-aria-components`, approuvé en dépendance paire puis retiré. Ce qui survit du détour,
|
|
336
|
+
ce sont ses MESURES, relevées dans un vrai navigateur et reprises à l'identique. Voir
|
|
337
|
+
« Décidé ».
|
|
338
|
+
⚠️ `--zds-color-tooltip-supporting-text` existait déjà, porté du thème de référence, et
|
|
339
|
+
portait une valeur fausse. Ses trois voisins de bloc sont dans le même cas — des ports que
|
|
340
|
+
rien n'a confrontés au Figma, et qu'aucun contrôle ne regarde tant que rien ne les cite.
|
|
341
|
+
✅ Retire `.zds-doc-bulle` du provisoire de `docs.css` — et ce retrait a découvert que la
|
|
342
|
+
bulle de la page Icônes n'avait **jamais** peint la bonne couleur. Retire aussi le `title`
|
|
343
|
+
natif du bouton d'ajout des groupes d'avatars, qui porte désormais une vraie info-bulle.
|
|
344
|
+
✅ Ajoute `verify:info-bulles`.
|
|
345
|
+
- [x] **Cases à cocher et boutons radio** — deux pages en ligne, deux composants livrés le
|
|
346
|
+
2026-09-10. `Checkbox` (2 tailles × cochée/indéterminée × 4 états, libellé et indication
|
|
347
|
+
optionnels) et `Radio`, le même atome en rond, dont le `name` est OBLIGATOIRE. Relevés sur
|
|
348
|
+
deux cadres : `_Checkbox base` (3891:11902, 40 symboles) et `Checkbox` (3891:11629,
|
|
349
|
+
74 symboles).
|
|
350
|
+
⚠️ **Deux pages, une seule feuille de style.** « Cases à cocher » et « Boutons radio » sont
|
|
351
|
+
rangés séparément — demande produit, alignée sur la bibliothèque de référence — mais les
|
|
352
|
+
deux composants restent UN atome : `Checkbox.css` habille les deux et `verify:checkboxes`
|
|
353
|
+
visite les DEUX pages en une passe. Voir « Décidé ».
|
|
354
|
+
⚠️ **Sept valeurs changent avec la taille, et trois avaient été uniformisées** — dont
|
|
355
|
+
l'épaisseur PEINTE de la marque, qui sortait à 1 px au lieu de 1,6666 et se lisait pâle.
|
|
356
|
+
C'est l'œil de Micka qui l'a signalé, pas les contrôles. Voir « Décidé ».
|
|
357
|
+
⚠️ **Deux écarts au Figma, arbitrés, à remonter dans le Figma** : la bordure de la case
|
|
358
|
+
décochée est foncée à navy-70, le cadre la peignant à 1,44 de contraste — le plus bas
|
|
359
|
+
mesuré sur ce design system, et ici la boîte EST le contrôle ; et l'état de survol, que le
|
|
360
|
+
Figma dessine identique au repos sur ses quarante symboles, est dessiné. Voir « Décidé ».
|
|
361
|
+
⚠️ **L'indication sous le libellé reste sous le seuil AA**, et ce n'est pas la faute du
|
|
362
|
+
composant : le Figma la peint `text-secondary`, un rôle qui est sous le seuil partout où il
|
|
363
|
+
porte du texte. Épinglée à l'envers dans le vérificateur — voir « En attente ».
|
|
364
|
+
✅ L'anneau de focus se montre enfin sur une planche, par le crochet `data-zds-demo="focus"`
|
|
365
|
+
que la page Boutons avait déjà et qui n'avait pas été repris.
|
|
366
|
+
✅ Ajoute `verify:checkboxes`.
|
|
367
|
+
- [x] **Interrupteur** — page en ligne, un composant livré le 2026-09-11. `Toggle` :
|
|
368
|
+
2 tailles × 2 types (`default`, `slim`) × 4 états, libellé et aide optionnels. Relevé sur
|
|
369
|
+
deux cadres : `_Toggle base` (3896:1480, 32 symboles) et `Toggle` (3896:1553, 64 symboles).
|
|
370
|
+
L'ORGANISATION de la page est celle de la page « Toggles » de la bibliothèque de référence,
|
|
371
|
+
à la demande de Micka : intro, un exemple de tête, Installation, puis les variantes dans son
|
|
372
|
+
ordre — nu, libellé, libellé + aide, désactivé, tailles, slim, slim + libellé et aide.
|
|
373
|
+
⚠️ **Ce n'est pas une case à cocher, et ça ne se remplace pas** : l'interrupteur applique son
|
|
374
|
+
effet tout de suite. D'où `role="switch"` sur l'input, pour qu'un lecteur d'écran annonce
|
|
375
|
+
« activé » au lieu de « coché ».
|
|
376
|
+
⚠️ **`slim` n'est pas `default` en plus petit** : en `md`, 40 × 20 contre 44 × 24, pour le
|
|
377
|
+
même bouton de 20. Ce qui change est le retrait, donc la piste du `slim` fait exactement la
|
|
378
|
+
hauteur de son bouton, et c'est sa bordure qui le détache au lieu de son ombre.
|
|
379
|
+
✅ **Les trois jetons `toggle-*` du thème étaient faux, tous les trois**, et le relevé l'a dit
|
|
380
|
+
d'un coup — dont un dans la rampe grise que le design system n'emploie pas. Voir « Décidé ».
|
|
381
|
+
✅ **La collection d'ombres de Zest est lue pour la première fois** : elle est teintée
|
|
382
|
+
#0a0d12, et pas #101828 comme la phase 1b le supposait. Voir « Décidé ».
|
|
383
|
+
✅ **Deux écarts au Figma, arbitrés le jour même** : la bordure de la piste éteinte est
|
|
384
|
+
foncée à navy-70 comme celle de la case à cocher, et l'état éteint gagne un survol que le
|
|
385
|
+
Figma ne dessine pas. **Les deux sont à remonter dans le Figma.** Voir « Décidé ».
|
|
386
|
+
⚠️ **Une question reste ouverte, et elle vaut aussi pour la case à cocher** : le bouton
|
|
387
|
+
blanc tient 1,11 contre sa piste. Voir « En attente ».
|
|
388
|
+
✅ Ajoute `verify:interrupteur`.
|
|
389
|
+
- [ ] Champs et liste déroulante — ce qui reste de la phase 2. Les deux pages sont annoncées
|
|
390
|
+
et vides sous `src/docs/a-venir/` : `Champs.mdx` et `Selecteurs.mdx`.
|
|
274
391
|
- Chaque composant livré retire un morceau du provisoire de `docs.css` — le tableau est
|
|
275
392
|
dans le `CLAUDE.md`.
|
|
276
393
|
- [ ] **Phase 3** — application components : navigation, tableaux, modales
|
|
@@ -278,8 +395,149 @@ both `tsc` and `storybook build`, and only a real browser found them:
|
|
|
278
395
|
|
|
279
396
|
## En attente
|
|
280
397
|
|
|
398
|
+
- ⚠️ **LES TABLEAUX MARKDOWN NE SE RENDENT PAS DANS LA DOCUMENTATION, ET 15 S'AFFICHENT EN MUR DE
|
|
399
|
+
BARRES VERTICALES** (constaté le 2026-09-11 en relisant une capture de la page « Interrupteur »).
|
|
400
|
+
Un `| … | … |` écrit dans un `.mdx` ressort tel quel, en une seule ligne de texte : l'extension
|
|
401
|
+
GFM de remark n'est branchée nulle part dans la configuration de Storybook, et `remark-gfm` n'est
|
|
402
|
+
même pas installé.
|
|
403
|
+
|
|
404
|
+
Le compte, relevé page par page dans le navigateur : « Info-bulles » 5, « Cases à cocher » 3,
|
|
405
|
+
« Boutons radio » 3, « Introduction » 2, « Logo » 2. Ce sont pour l'essentiel les tableaux de
|
|
406
|
+
CHOIX (« quel contrôle pour quelle question ») et les tableaux d'API — c'est-à-dire les deux
|
|
407
|
+
endroits où un développeur va chercher sa réponse.
|
|
408
|
+
|
|
409
|
+
⚠️ **Les tableaux qui se rendent bien sont ceux qui sont des COMPOSANTS.** `<Tableau>` construit
|
|
410
|
+
un vrai `<table>` en React, donc il ne dépend pas du Markdown : c'est pour ça que les tableaux de
|
|
411
|
+
tailles et d'états ont toujours eu l'air corrects, et que le défaut est resté invisible. La page
|
|
412
|
+
« Interrupteur » est passée sur `<Tableau>` pour ses deux tableaux, donc elle n'en porte plus.
|
|
413
|
+
|
|
414
|
+
**Deux réparations possibles, et c'est un arbitrage :** brancher `remark-gfm` dans
|
|
415
|
+
`.storybook/main.ts`, ce qui répare les 15 d'un coup mais ajoute une dépendance de développement
|
|
416
|
+
et change le rendu de cinq pages ; ou convertir les 15 en `<Tableau>`, sans dépendance, mais à la
|
|
417
|
+
main.
|
|
418
|
+
|
|
419
|
+
*Repère : le défaut ne se voit pas en écrivant la page — il se voit en la REGARDANT rendue. Aucun
|
|
420
|
+
contrôle du dépôt ne lit le texte d'une page pour y chercher du Markdown non interprété.*
|
|
421
|
+
|
|
422
|
+
- ⚠️ **LE BOUTON BLANC DE L'INTERRUPTEUR ÉTEINT TIENT 1,11 CONTRE SA PISTE, ET RIEN NE LE RATTRAPE**
|
|
423
|
+
(mesuré le 2026-09-11, en tranchant les deux questions ci-dessus). Une fois la bordure de la piste
|
|
424
|
+
montée à navy-70, la limite du contrôle passe son seuil — mais la POSITION du bouton, qui est ce
|
|
425
|
+
qui porte l'état, reste portée par un disque blanc sur un fond navy-20. En type `default` il n'a
|
|
426
|
+
même pas de bordure : c'est son ombre seule qui le détache, et une ombre ne compte pas dans un
|
|
427
|
+
calcul de contraste.
|
|
428
|
+
|
|
429
|
+
La WCAG 1.4.11 demande 3:1 pour « les parties d'un objet graphique nécessaires à la
|
|
430
|
+
compréhension ». La position du bouton en est une.
|
|
431
|
+
|
|
432
|
+
**Ce n'est pas arbitré, et je ne l'ai pas arbitré tout seul**, pour deux raisons : réparer
|
|
433
|
+
demanderait de changer le dessin du bouton — une bordure sur le type `default`, ou un fond qui
|
|
434
|
+
n'est plus blanc — c'est-à-dire de s'écarter du Figma sur la pièce la plus visible du composant ;
|
|
435
|
+
et c'est un dessin que toutes les bibliothèques du marché livrent tel quel. **La même question se
|
|
436
|
+
pose à l'identique sur la case à cocher décochée**, dont la boîte blanche tient 1,11 contre la
|
|
437
|
+
page. À trancher pour les deux, ou pour aucun.
|
|
438
|
+
|
|
439
|
+
- ⚠️ **`text-secondary` EST SOUS LE SEUIL AA, PARTOUT OÙ IL PORTE DU TEXTE** (relevé le
|
|
440
|
+
2026-09-10). Le rôle vaut navy-70 (#7e8694), qui tient **3,67** sur du blanc pour un seuil de 4,50
|
|
441
|
+
sur du petit texte. Ce n'est pas le problème d'un composant : c'est le rôle.
|
|
442
|
+
|
|
443
|
+
Découvert en codant la case à cocher, dont le Figma peint le texte d'aide avec ce rôle. Le foncer
|
|
444
|
+
dans ce composant seulement rendrait cette aide différente de toutes les autres du design system,
|
|
445
|
+
donc il est resté tel quel et **épinglé** dans `verify:checkboxes` — le jour où le rôle sera
|
|
446
|
+
foncé, ce contrôle rougira, et ce sera le rappel qu'il faut retirer l'exception.
|
|
447
|
+
|
|
448
|
+
Les paliers : navy-80 (#4d5971) tient 7,04, navy-70 tient 3,67. Il n'y a **rien entre les deux**
|
|
449
|
+
dans la rampe — c'est la même pénurie de paliers sombres que l'échelle de texte documente déjà
|
|
450
|
+
(quatre paliers foncés pour huit rangs). Foncer `text-secondary` sur navy-80 le rendrait égal à
|
|
451
|
+
`text-tertiary`, donc la question n'est pas seulement « quel palier » mais « combien de rangs de
|
|
452
|
+
texte gris nous faut-il vraiment ». **À arbitrer par l'équipe produit, pas par un composant.**
|
|
453
|
+
|
|
454
|
+
|
|
281
455
|
Des décisions qui appartiennent à Micka ou à l'équipe produit, pas au code.
|
|
282
456
|
|
|
457
|
+
- ⚠️ **LA COLLECTION SÉMANTIQUE DU FIGMA NE COUVRE PAS LES FONDS.** C'est la question de fond
|
|
458
|
+
soulevée le 2026-09-09, et elle est plus large qu'un jeton mal choisi.
|
|
459
|
+
|
|
460
|
+
Relevé sur la page « Couleurs » (`4:8067`) : la collection « 1. Usage des couleurs » nomme
|
|
461
|
+
`Couleurs/Texte/`, `Couleurs/Bordure/` et `Couleurs/Effets/Ombres/`. **Il n'y a pas de
|
|
462
|
+
`Couleurs/Fond/`.** Conséquence directe et vérifiable : le Figma peint lui-même l'aplat du
|
|
463
|
+
`Secondary gray` avec `Couleurs/Bleu marine/20`, une RAMPE BRUTE, parce qu'aucun jeton sémantique
|
|
464
|
+
ne nomme cette surface.
|
|
465
|
+
|
|
466
|
+
Côté thème, la couture est la même vue d'un autre angle : `text-*` et `border-*` sont passés sur
|
|
467
|
+
le navy de Zest le 2026-09-07, `bg-*` et `fg-*` sont restés sur la rampe gris NEUTRE, celle que
|
|
468
|
+
Zest n'emploie pas pour son interface. `--zds-color-bg-secondary` vaut `gray-50` (`#FAFAFA`) quand le Figma peint
|
|
469
|
+
`navy-20` (`#F1F3F5`) — deux familles différentes, donc aucun rôle existant ne peut nommer ces
|
|
470
|
+
aplats sans mentir.
|
|
471
|
+
|
|
472
|
+
Les quatre aplats du bouton sont donc écrits en jetons de COMPOSANT
|
|
473
|
+
(`--zds-color-button-secondary-bg` & co) plutôt qu'en repointant `bg-secondary`, ce qui aurait
|
|
474
|
+
déplacé toutes les surfaces du paquet. **Deux décisions à prendre, dans cet ordre :**
|
|
475
|
+
|
|
476
|
+
1. **ajouter un groupe `Couleurs/Fond/` à la collection sémantique du Figma** — c'est lui qui
|
|
477
|
+
manque, et tant qu'il manque chaque composant réinventera ses noms d'aplat ;
|
|
478
|
+
2. **repointer `bg-*` et `fg-*` sur le navy** une fois ce groupe écrit.
|
|
479
|
+
|
|
480
|
+
Le bouton est le premier composant à s'asseoir sur cette couture ; le deuxième la retrouvera.
|
|
481
|
+
`yarn verify:tokens` garde la trace : il échoue si un jeton de composant redouble un rôle
|
|
482
|
+
existant de la MÊME catégorie, et laisse passer les fonds — l'exception est explicite dans le
|
|
483
|
+
script, pas oubliée.
|
|
484
|
+
- ⚠️ **LE CORPS DE TEXTE DE LA DOCUMENTATION N'EST PAS SUR L'ÉCHELLE DU DESIGN SYSTEM.** Mesuré
|
|
485
|
+
dans le navigateur le 2026-09-09 : les paragraphes des pages Storybook rendent à **14 px** en
|
|
486
|
+
`#2E3438` — ni le `body-md` de 16 px de l'échelle, ni aucune couleur de Zest (`text-tertiary`
|
|
487
|
+
vaut `#4D5971`). La POLICE avait été corrigée en septembre via `fontBase` dans `preview.ts` ; la
|
|
488
|
+
taille et la couleur ne l'ont pas été.
|
|
489
|
+
|
|
490
|
+
⚠️ **Et `.prose` ne peut pas servir à ça**, ce qui a été vérifié empiriquement plutôt que
|
|
491
|
+
supposé : posée sur `.sbdocs-content`, elle ne change QUE la couleur héritée du conteneur. Les
|
|
492
|
+
paragraphes restent à 14 px, les titres à 24, la largeur à 1000. C'est par construction — son
|
|
493
|
+
en-tête dit que « chaque sélecteur est enveloppé dans `:where()`, donc à spécificité nulle :
|
|
494
|
+
cette feuille propose une mise en page, elle ne l'impose pas ». Les règles de Storybook la
|
|
495
|
+
battent partout. Deux autres raisons l'excluent de toute façon : elle plafonne à **720 px**, ce
|
|
496
|
+
qui écraserait les aperçus et les planches pleine largeur, et la page « Typographie » la
|
|
497
|
+
DÉMONTRE — un spécimen posé dans un conteneur identique à lui ne démontre plus rien.
|
|
498
|
+
|
|
499
|
+
**La voie praticable** est celle que `preview.ts` a déjà prise pour la police : des règles dans
|
|
500
|
+
`docs.css`, avec la spécificité nécessaire pour battre Storybook. Ça touche l'aspect des douze
|
|
501
|
+
pages, d'où l'arbitrage. **Faut-il aligner le corps de texte de la doc sur l'échelle ?**
|
|
502
|
+
- **Les deux bornes du biseau skéuomorphique** (2026-09-09). Le MCP Figma rapporte le contour des
|
|
503
|
+
aplats comme plat, sur deux lectures ; le dégradé est donc implémenté d'après la recette standard
|
|
504
|
+
(`rgba(255,255,255,0.12)` en haut, extinction complète en bas) et non d'après un relevé. **À
|
|
505
|
+
confirmer dans le Figma**, ou à corriger sur les deux jetons `--zds-color-button-bevel-*`.
|
|
506
|
+
- **Le tracé du spinner est une construction, pas un relevé** (2026-09-09). Le cadre
|
|
507
|
+
`Buttons/Button loading icon` (3861:2509) existe et donne deux tailles, 20 et 24 px, mais son
|
|
508
|
+
export SVG passe par une URL que la machine de relevé n'a pas le droit d'appeler. Ce qui est
|
|
509
|
+
livré est un anneau conventionnel — piste à 30 % du `currentColor`, tête d'un quart de tour —
|
|
510
|
+
qui a l'avantage de suivre la couleur du texte, donc de servir en blanc sur un Primary comme en
|
|
511
|
+
rouge sur un destructif. **À remplacer par le vrai tracé**, ou à valider tel quel. Et de toute
|
|
512
|
+
façon un cadre statique ne décrit ni durée, ni sens, ni courbe d'accélération.
|
|
513
|
+
- **Le soulignement des liens au survol** (2026-09-09). Le Figma le peint plus CLAIR que le
|
|
514
|
+
libellé — texte au palier 700, trait au 500 — et il fait pareil sur le lien destructif. Mais
|
|
515
|
+
`link-gray` ne suit pas : son trait suit son texte. Reproduit tel quel, pas harmonisé. **Motif
|
|
516
|
+
ou oubli ?**
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
- ⚠️ **LE BADGE OFFRE DEUX NEUTRES, ET ILS SE RESSEMBLENT** (2026-09-10). `navy`, le neutre de
|
|
520
|
+
Zest, et `gray`, celui de la livraison de référence. Trois indices font penser à une migration
|
|
521
|
+
inachevée plutôt qu'à un choix : le fond du badge `navy` est encore peint dans le Figma par
|
|
522
|
+
`Component colors/Utility/Slate/utility-slate-50` (#f8fafc), une variable d'une **collection
|
|
523
|
+
tierce** étrangère à celle de Zest ; le `gray` porte son libellé sur la rampe grise, que Zest
|
|
524
|
+
n'emploie pas pour ses textes ; et rien ne dit lequel employer quand.
|
|
525
|
+
|
|
526
|
+
Les deux sont livrés, parce que les deux sont dessinés. `verify:tokens` porte une exception
|
|
527
|
+
**énumérée** — cinq citations nommées dans `GRIS_ADMIS` — et il échoue aussi si l'une d'elles
|
|
528
|
+
cesse d'être citée : le jour où `gray` disparaît, la dispense part avec lui. **À trancher.**
|
|
529
|
+
|
|
530
|
+
- **Quatre fonds de badge s'écartent du Figma, et c'est mesuré** (2026-09-10). Le Figma peint le
|
|
531
|
+
fond de `brand`, `success`, `horizon` et `fuschia` avec le palier `Zest/10`, celui que notre
|
|
532
|
+
échelle 50 → 950 laisse dehors. Les quatre prennent le `-50` : ΔE 5,46 · 5,79 · 4,45 · 8,79.
|
|
533
|
+
Les quatre restent au-dessus de l'AA sous leur libellé — l'écart coûte une nuance, pas une
|
|
534
|
+
lisibilité. Récupérer `Zest/10` demanderait un palier `25` sur les rampes, ce qui est la
|
|
535
|
+
décision de design system déjà listée dans le `CLAUDE.md`.
|
|
536
|
+
|
|
537
|
+
Le badge `navy` est dans le même cas, l'écart en moins : `utility-slate-50` #f8fafc contre notre
|
|
538
|
+
`navy-10` #f9fafb, **ΔE 0,61** — invisible à l'œil et mesurable. Substitué sans hésitation, mais
|
|
539
|
+
le Figma reste à repointer.
|
|
540
|
+
|
|
283
541
|
- ⚠️ **Les deux aplats de statut ne tiennent pas l'AA — et ils ont maintenant des victimes.**
|
|
284
542
|
`yarn verify:labels` sort en échec sur **dix étiquettes d'icône de fichier** : CSV, XLS et XLSX
|
|
285
543
|
portent du blanc sur `success-600` (3,59:1), PPT et PPTX sur `warning-600` (3,49:1), en Default
|
|
@@ -287,10 +545,36 @@ Des décisions qui appartiennent à Micka ou à l'équipe produit, pas au code.
|
|
|
287
545
|
contrôle échoue exprès pour qu'elle ne s'oublie pas. `bg-warning-solid` (`#DC6803`) tient
|
|
288
546
|
**3,49:1** et `bg-success-solid` (`#119B57`) **3,59:1** sous du texte blanc, pour un seuil AA
|
|
289
547
|
de 4,5:1. `bg-error-solid` (4,83) et `bg-brand-solid` (4,54) passent, de justesse pour le
|
|
290
|
-
second. Les fonds **doux** vont bien
|
|
291
|
-
|
|
292
|
-
**
|
|
293
|
-
|
|
548
|
+
second. Les fonds **doux** vont bien : le défaut ne touche que les aplats.
|
|
549
|
+
|
|
550
|
+
⚠️ **CETTE ENTRÉE A LONGTEMPS DIT DEUX CHOSES FAUSSES**, corrigées le 2026-09-10.
|
|
551
|
+
|
|
552
|
+
**Un.** Elle annonçait que ces deux jetons bloquaient « le premier badge ». C'est faux : le
|
|
553
|
+
cadre `Badge` ne dessine aucun aplat, ses trois habillages sont deux fonds doux et un fond
|
|
554
|
+
blanc. Aucun des deux jetons n'y est cité. Seul le premier bouton PLEIN de statut les attend.
|
|
555
|
+
|
|
556
|
+
**Deux.** Elle présentait les dix étiquettes d'icône de fichier comme des « victimes » de cette
|
|
557
|
+
décision. Elles n'en sont pas, et ça a été vérifié plutôt que déduit : en basculant les deux
|
|
558
|
+
jetons sur le 700, `verify:labels` sort **les dix mêmes échecs, aux mêmes 3,59 et 3,49**. Les
|
|
559
|
+
SVG citent `--zds-color-success-600` et `--zds-color-warning-600` DIRECTEMENT, pas le jeton
|
|
560
|
+
d'aplat. C'est un problème indépendant, dont l'en-tête du catalogue nomme déjà la cause : « le
|
|
561
|
+
design system n'a ni orange, ni vert, ni rouge utilitaires », donc CSV et PPT empruntent les
|
|
562
|
+
rampes sémantiques faute de teinte de catégorisation. À trancher à part, et `verify:labels`
|
|
563
|
+
devrait cesser d'accuser `bg-*-solid`.
|
|
564
|
+
|
|
565
|
+
**Ce qui reste, et ce que la mesure ajoute.** Descendre les deux aplats sur le **700** (5,08 et
|
|
566
|
+
5,43) répare le statut et rien de plus : mesuré sur les 13 couleurs de la palette, un aplat
|
|
567
|
+
saturé sous du texte blanc échoue pour **7 couleurs sur 13** au palier 600 et encore **3 sur 13**
|
|
568
|
+
au palier 700 — lime, jaune et turquoise, qu'il faudrait descendre au 800 ou au 900, où le lime
|
|
569
|
+
n'est plus du lime. Autrement dit : **il n'existe aucun palier qui fasse marcher un BOUTON PLEIN
|
|
570
|
+
sur toute la palette.**
|
|
571
|
+
|
|
572
|
+
⚠️ **Ne pas lire cette dernière phrase comme un verdict sur le badge.** Le badge, lui, a été
|
|
573
|
+
réglé le 2026-09-10 en descendant ces trois teintes de deux crans — voir « Décidé » — et ça
|
|
574
|
+
marche parce que son FOND reste au palier 50 : c'est le fond pâle qui porte l'identité de la
|
|
575
|
+
teinte, et seuls le texte et la pièce foncent. Sur un aplat saturé c'est l'inverse : le fond EST
|
|
576
|
+
la teinte, et le foncer la détruit. La même couleur, deux conclusions opposées, parce que ce
|
|
577
|
+
n'est pas la même surface qui porte l'information.
|
|
294
578
|
- **La ligne de `.prose` fait 103 caractères**, mesurés ici (Averta 16 px sur 720 px, médiane sur
|
|
295
579
|
les lignes pleines de l'article d'exemple). Le confort de lecture se situe entre 45 et 75, et
|
|
296
580
|
85 est la limite haute usuelle. Les 720 px viennent pourtant du Figma (`paragraph-max-width`)
|
|
@@ -309,19 +593,53 @@ Des décisions qui appartiennent à Micka ou à l'équipe produit, pas au code.
|
|
|
309
593
|
du **texte** mesuré, pas du réglage : les deux articles d'exemple n'ont ni les mêmes mots ni la
|
|
310
594
|
même densité d'élisions. C'est une raison de plus de ne pas recopier un chiffre d'un dépôt à
|
|
311
595
|
l'autre. À arbitrer, parce que ça touche un jeton du Figma.
|
|
312
|
-
- ⚠️ **
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
596
|
+
- ⚠️ **DEUX ICÔNES ET UN STATUT À FINIR DE CADRER, côté Figma** (2026-09-10). Le composant Avatar
|
|
597
|
+
est livré, mais trois choses lui restent dues :
|
|
598
|
+
|
|
599
|
+
`message-alert-square-01` et `-02` ont été **ajoutées au catalogue à la main** depuis le cadre
|
|
600
|
+
`31:9082`. Le catalogue se dit « généré » : il n'existe en réalité aucun générateur dans le
|
|
601
|
+
dépôt, et les 135 entrées ont toutes été relevées de la même façon. Ce n'est pas un défaut, mais
|
|
602
|
+
l'en-tête du catalogue promet une régénération qui n'est pas outillée. **À écrire, ou à
|
|
603
|
+
reformuler.**
|
|
604
|
+
|
|
605
|
+
Le statut « Com. sensible » porte une **étiquette abrégée** dans le Figma, et rien dans les
|
|
606
|
+
projets Zest ne la définissait — il a fallu demander. L'API l'appelle `sensitive-comment` et la
|
|
607
|
+
page écrit « commentaire sensible ». **À renommer dans le Figma** pour que le prochain relevé
|
|
608
|
+
n'ait pas à demander.
|
|
609
|
+
|
|
610
|
+
Enfin ses trois cadres portent des variables d'une **collection tierce** :
|
|
611
|
+
`utility-neutral-300` peint le statut hors ligne, `Colors/Background/bg-primary` l'anneau du
|
|
612
|
+
groupe, et `Bleu marine/100` existe en double — une fois dans `Couleurs/`, une fois hors
|
|
613
|
+
collection. Substitués par mesure, **le Figma reste à repointer**.
|
|
614
|
+
|
|
615
|
+
- ⚠️ **LE RAYON DE L'INFO-BULLE EST ÉCRIT AVEC UN JETON D'ESPACEMENT DANS LE FIGMA** (relevé le
|
|
616
|
+
2026-09-10 sur le spécimen `Size=md, State=Hover` du cadre `_Avatar add button`, 3881:4984) —
|
|
617
|
+
`rounded-[var(--spacing-md)]`, et non un jeton de rayon. Les 8 px tombent juste par
|
|
618
|
+
coïncidence : c'est aussi la valeur du `radius-sm` du Figma. **À repointer** avant que quelqu'un
|
|
619
|
+
ne change l'échelle d'espacement.
|
|
620
|
+
|
|
621
|
+
✅ **Le reste de cette entrée est clos depuis le 2026-09-10.** Elle disait que l'info-bulle du
|
|
622
|
+
bouton d'ajout d'un groupe d'avatars attendait le composant `Tooltip`, et que le bouton portait
|
|
623
|
+
un `title` de navigateur en attendant. `Tooltip` est livré, le bouton le porte, et le `title` a
|
|
624
|
+
été retiré — voir « Décidé ». Le relevé du spécimen reste ici, puisque c'est lui qui porte la
|
|
625
|
+
question du rayon ouverte ci-dessus, et qu'il dit à quoi la bulle du bouton d'ajout doit
|
|
626
|
+
ressembler :
|
|
627
|
+
|
|
628
|
+
| Ce que c'est | Ce que le Figma peint |
|
|
629
|
+
|---|---|
|
|
630
|
+
| Fond | `Couleurs/Bleu marine/100` (#21304e) |
|
|
631
|
+
| Libellé | `caption-md` 12/18 semibold, blanc, centré, sans retour |
|
|
632
|
+
| Padding | `spacing-lg` 12 px à l'horizontale, `spacing-md` 8 px à la verticale |
|
|
633
|
+
| Rayon | 8 px |
|
|
634
|
+
| Flèche | 16 × 6, sous la bulle, centrée |
|
|
635
|
+
| Ombre | `0 12px 8px rgb(16 24 40 / 0.08)`, `0 4px 3px rgb(16 24 40 / 0.03)` |
|
|
636
|
+
| Position | au-dessus du bouton, centrée, base à 43 px de son centre |
|
|
637
|
+
|
|
638
|
+
- ⚠️ **LA PLANCHE DU REPLI DE LA PAGE FOUNDATIONS DESSINE SES RONDS À LA MAIN** (2026-09-10). Elle
|
|
639
|
+
a été faite quand aucun composant n'existait. La basculer sur `<Avatar>` changerait le dessin de
|
|
640
|
+
cette page — un arbitrage de design et non un rangement — donc c'est signalé et non appliqué,
|
|
641
|
+
comme `.zds-doc-copie` l'est pour les boutons. Même remarque pour la planche des tailles, dont
|
|
642
|
+
l'échelle est désormais fausse : la page le dit en rouge au lieu de la refaire.
|
|
325
643
|
- **L'aire de protection et la taille plancher du logo** sont une **proposition** elles aussi :
|
|
326
644
|
une demi-hauteur d'isotype, et 24 px sous lesquels on passe à l'isotype seul. Le Figma ne dit
|
|
327
645
|
rien des deux. Dessinées dans la page pour être discutées.
|
|
@@ -360,6 +678,796 @@ Des décisions qui appartiennent à Micka ou à l'équipe produit, pas au code.
|
|
|
360
678
|
Le journal des arbitrages. Plusieurs de ces choix paraissent arbitraires et sont le résultat
|
|
361
679
|
d'une mesure ou d'une décision produit — ne pas les « harmoniser » sans lire l'entrée.
|
|
362
680
|
|
|
681
|
+
- ⚠️ **LES TITRES DE PAGES SONT PASSÉS EN FRANÇAIS LE 2026-09-11** (demande de Micka). Quatre
|
|
682
|
+
restaient en anglais : « Checkboxes » devient **Cases à cocher**, « Radio buttons » **Boutons
|
|
683
|
+
radio**, « File icons » **Icônes de fichier** et « Flag icons » **Drapeaux**.
|
|
684
|
+
|
|
685
|
+
Les trois SECTIONS restent en anglais — « Foundations », « Base components », « Application
|
|
686
|
+
components ». Ce n'est pas un oubli : le préfixe du titre est ce sur quoi `verify:foundations`
|
|
687
|
+
partage les pages de composant des pages de fondations, et le renommer changerait l'identifiant
|
|
688
|
+
de toutes les pages du dépôt d'un coup.
|
|
689
|
+
|
|
690
|
+
⚠️ **« Drapeaux » ANNULE UNE DÉCISION DE MICKA LUI-MÊME.** Cette page avait été renommée
|
|
691
|
+
« Flag icons » — en anglais — à sa demande ; la règle du jour la ramène au français. Les deux
|
|
692
|
+
fois, c'est bien lui qui a tranché. C'est écrit ici pour que personne ne « répare » le nom en
|
|
693
|
+
tombant sur l'ancienne entrée.
|
|
694
|
+
|
|
695
|
+
**Un titre n'est pas une étiquette, c'est l'identifiant de la page.** Storybook le dérive du
|
|
696
|
+
`<Meta title>` : « Cases à cocher » donne `base-components-cases-à-cocher--docs`, accents
|
|
697
|
+
compris, à encoder en URL comme `Foundations/Icônes` l'était déjà. Ont dû suivre le renommage :
|
|
698
|
+
l'ordre de la barre latérale dans `.storybook/preview.ts`, les deux pages et leurs identifiants
|
|
699
|
+
de repli dans `verify:checkboxes`, les renvois d'une page à l'autre, et les commentaires des
|
|
700
|
+
planches. Et `verify:render` lit les identifiants dans `storybook-static/index.json` : sans un
|
|
701
|
+
`yarn build-storybook` rejoué, il visite les anciens.
|
|
702
|
+
|
|
703
|
+
- ⚠️ **LA BORDURE DE L'INTERRUPTEUR ÉTEINT EST FONCÉE À navy-70, COMME CELLE DE LA CASE À COCHER**
|
|
704
|
+
(2026-09-11, arbitrage délégué après mesure). Le Figma peint la limite du contrôle
|
|
705
|
+
`border-primary` (navy-40), qui tient **1,44** sur du blanc pour un seuil de 3:1, sur un fond
|
|
706
|
+
navy-20 qui tient 1,11.
|
|
707
|
+
|
|
708
|
+
**Ce dépôt tranche ce cas sur une seule question, et elle est mesurable :** y a-t-il autre chose,
|
|
709
|
+
DANS le contrôle, qui le rende identifiable à 3:1 ? Le bouton garde son libellé à 11,82, donc sa
|
|
710
|
+
bordure est restée au Figma à 2,17. La case à cocher n'a rien, donc elle est montée à navy-70.
|
|
711
|
+
L'interrupteur éteint, mesuré : son bouton blanc tient **1,11** contre sa piste, et en `slim` la
|
|
712
|
+
bordure de ce bouton tient **1,30**. Rien n'atteint 3 — il est dans le cas de la case, pas dans
|
|
713
|
+
celui du bouton. navy-70 tient 3,67.
|
|
714
|
+
|
|
715
|
+
⚠️ **ET LA BORDURE DU BOUTON DU TYPE `slim` SUIT, pas seulement la piste.** En `slim` le bouton
|
|
716
|
+
remplit la piste : sa bordure est la SEULE chose qui l'en sépare, et la position du bouton EST
|
|
717
|
+
l'état. La foncer d'un côté seulement donnerait un anneau extérieur net autour d'un bouton
|
|
718
|
+
invisible — 3,30 contre la piste au lieu de 1,30.
|
|
719
|
+
|
|
720
|
+
⚠️ **TROISIÈME FOIS QUE CET ARBITRAGE EST RENDU À PARTIR DE navy-40** — la case à cocher, le point
|
|
721
|
+
« hors ligne » de l'avatar, l'interrupteur. **Ce n'est plus une exception, c'est la règle du
|
|
722
|
+
dépôt**, et elle s'énonce en une phrase : *une limite de contrôle qui n'est rattrapée par rien
|
|
723
|
+
d'autre monte à navy-70.* À remonter dans le Figma, pour les trois.
|
|
724
|
+
|
|
725
|
+
⚠️ **Le jeton retrouve son NOM d'origine.** `--zds-color-toggle-border` était le jeton porté du
|
|
726
|
+
thème de référence, supprimé le matin même parce qu'il valait `gray-300` et qu'un rôle suffisait.
|
|
727
|
+
Il revient le soir, à navy-70 : **son nom était juste, sa valeur était fausse, et le rôle ne
|
|
728
|
+
suffisait plus une fois l'arbitrage rendu.**
|
|
729
|
+
|
|
730
|
+
- ⚠️ **L'INTERRUPTEUR ÉTEINT GAGNE UN SURVOL, QUE LE FIGMA NE DESSINE PAS** (2026-09-11, arbitrage
|
|
731
|
+
délégué). Les seize symboles `Pressed=False, State=Hover` sont identiques, propriété par
|
|
732
|
+
propriété, à leurs `State=Default`. Même constat que sur la case à cocher le 2026-09-10, et même
|
|
733
|
+
décision : un contrôle qui applique son effet AU CLIC et qui ne répond pas au survol paraît inerte.
|
|
734
|
+
|
|
735
|
+
**Une seule règle couvre les deux états** — « au survol, la piste descend d'un cran de sa rampe » :
|
|
736
|
+
navy-20 → navy-30 éteinte, brand-500 → brand-700 allumée. Micka doit pouvoir la réexpliquer de
|
|
737
|
+
mémoire, et une exception greffée sur l'éteint l'en empêcherait.
|
|
738
|
+
|
|
739
|
+
⚠️ **LE CRAN EST DISCRET, ET C'EST MESURÉ AVANT D'ÊTRE ASSUMÉ : 1,12** contre la piste au repos.
|
|
740
|
+
Le palier suivant, navy-40, tiendrait 1,30 — et ce ne serait plus un cran. Un survol n'est pas un
|
|
741
|
+
état qu'on lit, c'est une confirmation que le contrôle est vivant ; le rendre spectaculaire le
|
|
742
|
+
ferait concurrencer l'état allumé, qui lui porte l'information. À remonter dans le Figma.
|
|
743
|
+
|
|
744
|
+
✅ **`verify:interrupteur` vérifie les deux sens.** Le survol doit exister sur l'éteint ET sur
|
|
745
|
+
l'allumé : un ajout au Figma que rien ne garde disparaît sans laisser de trace — la piste
|
|
746
|
+
resterait plausible, et ni un test ni une capture ne le diraient.
|
|
747
|
+
|
|
748
|
+
- ⚠️ **ET LE CONTRASTE ÉPINGLÉ A ATTRAPÉ UN DÉFAUT DE LA SONDE, PAS DU COMPOSANT** (2026-09-11).
|
|
749
|
+
En ajoutant le survol de l'éteint, `verify:interrupteur` s'est mis à mesurer la piste au repos à
|
|
750
|
+
**1,24 au lieu de 1,11** : le test de survol laisse la souris posée sur un interrupteur, et la
|
|
751
|
+
mesure des contrastes, qui vient après, lisait donc une piste SURVOLÉE.
|
|
752
|
+
|
|
753
|
+
La sonde éloigne maintenant la souris et attend la transition de 0,15 s. **Sans l'épingle, elle
|
|
754
|
+
aurait rapporté une valeur plausible et fausse** — 1,24 ne ressemble pas à une erreur.
|
|
755
|
+
|
|
756
|
+
*Repère : une sonde qui simule une interaction laisse le navigateur dans l'état où elle l'a mis.
|
|
757
|
+
Ce qu'elle mesure ensuite n'est pas l'état au repos.*
|
|
758
|
+
|
|
759
|
+
- ⚠️ **LES TROIS JETONS `toggle-*` PORTÉS DANS LE THÈME ÉTAIENT FAUX, TOUS LES TROIS** (2026-09-11).
|
|
760
|
+
`--zds-color-toggle-border` valait `gray-300` — la rampe que ce design system n'emploie pas —
|
|
761
|
+
quand le Figma peint la piste éteinte avec `border-primary`, un RÔLE qui existait déjà : le jeton
|
|
762
|
+
de composant n'avait même pas lieu d'être, et il a été supprimé plutôt que corrigé. Les deux
|
|
763
|
+
autres peignaient la bordure du bouton fin en brand-600 et son survol en brand-700, quand le Figma
|
|
764
|
+
dit brand-500 et brand-700.
|
|
765
|
+
|
|
766
|
+
C'est exactement ce qui était arrivé à `--zds-color-tooltip-supporting-text` la veille, et pour la
|
|
767
|
+
même raison : **rien ne les citait, donc aucun contrôle ne les lisait.** La prédiction écrite ici
|
|
768
|
+
le 2026-09-10 — « des ports, pas des relevés, à vérifier au moment où l'interrupteur sera codé » —
|
|
769
|
+
s'est vérifiée à 3 sur 3.
|
|
770
|
+
|
|
771
|
+
*Repère : un jeton porté d'un autre thème est une hypothèse, pas une valeur. Tant que rien ne le
|
|
772
|
+
cite, il est invérifiable ; le jour où on le cite, il faut le relire au Figma AVANT de s'en
|
|
773
|
+
servir.*
|
|
774
|
+
|
|
775
|
+
⚠️ **ET LE SUPPRIMER A LAISSÉ DEUX ÉCHOS.** `--zds-color-toggle-border` servait d'EXEMPLE de
|
|
776
|
+
jeton de composant à deux endroits — la page « Couleurs » et l'exemple de prose de la page
|
|
777
|
+
« Typographie » — qui ont donc cité un jeton mort le temps d'un commit. Les deux pointent
|
|
778
|
+
désormais sur `--zds-color-toggle-bg-pressed`, qui existe et qui illustre mieux la règle : aucun
|
|
779
|
+
rôle de FOND ne porte brand-500. Aucun contrôle ne l'a vu, parce qu'un nom de jeton écrit dans
|
|
780
|
+
une page est du texte, pas une citation.
|
|
781
|
+
|
|
782
|
+
- ⚠️ **LA COLLECTION D'OMBRES DE ZEST EST TEINTÉE #0a0d12, ET NON #101828** (relevé le 2026-09-11,
|
|
783
|
+
premier accès à `Couleurs/Effets/Ombres`). Le relevé donne `shadow-xs` à 5 %, `shadow-md_01` à
|
|
784
|
+
10 % et `shadow-md_02` à 6 %, tous sur #0a0d12 — c'est-à-dire le `gray-950` de la livraison de
|
|
785
|
+
référence, pas la teinte que l'entrée ouverte de la phase 1b annonçait.
|
|
786
|
+
|
|
787
|
+
La teinte est **substituée** au noir de notre rampe sur l'ombre du bouton de l'interrupteur, comme
|
|
788
|
+
elle l'avait été sur l'info-bulle : à 10 % sur du blanc, l'écart ne fait pas trois niveaux sur
|
|
789
|
+
255, et la cohérence du thème vaut plus. **La question des sept ombres reste ouverte** — ce n'est
|
|
790
|
+
pas depuis un composant qu'on la tranche — mais elle a maintenant sa vraie valeur de départ.
|
|
791
|
+
|
|
792
|
+
⚠️ **Et la géométrie, elle, diverge.** L'`ombre-md` du Figma est `0 4px 6px 0` puis
|
|
793
|
+
`0 2px 4px -2px`, là où `--zds-shadow-md` écrit `0 4px 6px -1px` sur sa première couche. Une
|
|
794
|
+
couche sur deux : le jeton ne se réemploie pas, d'où `--zds-shadow-toggle-knob`. L'entrée de la
|
|
795
|
+
phase 1b disait « la géométrie est la même de part et d'autre, la teinte changera » : **les deux
|
|
796
|
+
moitiés de cette phrase sont fausses.**
|
|
797
|
+
|
|
798
|
+
- ⚠️ **0,5 px ET 1 px SONT LE MÊME PIXEL SUR UN ÉCRAN À 1×** (2026-09-11). Le Figma donne deux
|
|
799
|
+
épaisseurs de bordure à la piste éteinte selon le type — 0,5 sur le `default`, 1 sur le `slim` —
|
|
800
|
+
et Chromium arrondit une bordure sous-pixel à un pixel d'écran. Les deux rendent donc 1 px, et la
|
|
801
|
+
distinction n'apparaît qu'à partir de 2×.
|
|
802
|
+
|
|
803
|
+
`verify:interrupteur` mesure les DEUX : l'épaisseur que la feuille déclare, où la distinction
|
|
804
|
+
vit, et celle que le navigateur peint, comparée à ce que la densité de l'écran permet. Le premier
|
|
805
|
+
jet ne mesurait que la peinte, et reprochait au composant un arrondi du navigateur.
|
|
806
|
+
|
|
807
|
+
*Repère : une mesure prise dans un navigateur est prise sur UNE densité d'écran. Ce qui s'y voit
|
|
808
|
+
n'est pas toujours ce que la feuille demande.*
|
|
809
|
+
|
|
810
|
+
- ⚠️ **L'HABITUDE D'AVANT-COMMIT COMPTE QUATRE CONTRÔLES DEPUIS LE 2026-09-10**, et le quatrième est
|
|
811
|
+
celui qui manquait : **aucun récit de fabrication dans une page de composant**. Micka l'a demandé
|
|
812
|
+
deux fois ; à la seconde, il est devenu un script.
|
|
813
|
+
|
|
814
|
+
`verify:foundations` relit donc les pages dont le `<Meta>` commence par « Base components/ » et
|
|
815
|
+
refuse huit tournures — « relevé », « mesuré », « un premier jet », « arbitré », « le Figma
|
|
816
|
+
dessine… », « à remonter dans le Figma », un numéro de nœud, « symbole ». Les pages Foundations sont
|
|
817
|
+
écartées : elles MESURENT par conception, le mot y est le sujet. Le partage se fait sur le TITRE,
|
|
818
|
+
pas sur un nom de fichier — c'est le titre qui décide du rangement.
|
|
819
|
+
|
|
820
|
+
⚠️ **UNE EXCEPTION ÉNUMÉRÉE, et elle est instructive.** La page « Badges » écrit « le choix entre
|
|
821
|
+
eux n'est pas arbitré » : le mot est le même, l'usage est l'inverse — cette phrase DIT au
|
|
822
|
+
développeur que le choix lui revient. Le contrôle échoue aussi si l'exception cesse d'être
|
|
823
|
+
employée, comme `GRIS_ADMIS`.
|
|
824
|
+
|
|
825
|
+
Le contrôle a trouvé quatre passages sur trois pages écrites plus tôt : les notes de clôture de
|
|
826
|
+
« Badges » et « Avatars » qui décrivaient notre outillage de vérification, une phrase de « Boutons »
|
|
827
|
+
sur le même sujet, et une note de l'avatar **périmée en plus d'être narrative** — elle annonçait
|
|
828
|
+
encore une info-bulle provisoire alors que `Tooltip` était arrivé et que le bouton d'ajout
|
|
829
|
+
l'employait.
|
|
830
|
+
|
|
831
|
+
*Repère : une règle qu'on s'écrit ne tient pas. Le réflexe d'écrire ce qu'on vient de comprendre là
|
|
832
|
+
où on vient de le comprendre est plus fort qu'une consigne — il faut un contrôle.*
|
|
833
|
+
|
|
834
|
+
- ⚠️ **`git checkout -- <fichier>` A EFFACÉ DU TRAVAIL NON COMMITÉ, POUR LA DEUXIÈME FOIS**
|
|
835
|
+
(2026-09-10). Employé pour défaire une mutation de test, il a ramené trois pages à HEAD — et
|
|
836
|
+
emporté avec la mutation **trois corrections de documentation venant d'être écrites**.
|
|
837
|
+
|
|
838
|
+
La première fois, c'étaient quatre correctifs de `verifier-jetons.mjs`, et la leçon était déjà dans
|
|
839
|
+
ce README. Elle n'a pas tenu, parce qu'au moment du nettoyage on pense « annuler la mutation », pas
|
|
840
|
+
« ce fichier contient aussi autre chose ». La commande est la même ; git ne connaît pas l'intention.
|
|
841
|
+
|
|
842
|
+
Et l'effacement est **silencieux** : la commande réussit, le fichier existe, les tests passent —
|
|
843
|
+
ils portaient sur autre chose. Ce qui l'a révélé, c'est un `grep -c` sur les phrases censées avoir
|
|
844
|
+
disparu.
|
|
845
|
+
|
|
846
|
+
**La règle : restaurer une mutation depuis une COPIE prise juste avant (`cp`), jamais depuis git**,
|
|
847
|
+
et vérifier la restauration par son CONTENU, pas par l'absence d'erreur.
|
|
848
|
+
|
|
849
|
+
- ⚠️ **UN ÉTAT QU'AUCUNE PLANCHE NE MONTRE EST UN ÉTAT QUE PERSONNE NE RELIT** (2026-09-10, question
|
|
850
|
+
de Micka : « pourquoi il n'y a pas le focus ring pour le state focus ? »). L'anneau de la case à
|
|
851
|
+
cocher était juste, le vérificateur le mesurait, et **aucune planche ne l'affichait** : le tableau
|
|
852
|
+
des états en annonçait quatre pour trois visibles.
|
|
853
|
+
|
|
854
|
+
Deux raisons se cumulaient, et les deux sont normales : `:focus-visible` ne se déclenche qu'à la
|
|
855
|
+
navigation clavier — un clic ne montre rien, mesuré à `box-shadow: none` — et un seul élément du
|
|
856
|
+
document tient le focus à la fois, donc une planche ne peut pas le montrer sur trois spécimens.
|
|
857
|
+
|
|
858
|
+
La page Boutons avait déjà résolu ça avec `data-zds-demo="focus"`, un crochet qui **partage une
|
|
859
|
+
seule déclaration** avec `:focus-visible` pour que la démonstration ne puisse pas dériver. **Il n'a
|
|
860
|
+
simplement pas été repris.** Il l'est, sur les deux pages, et `verify:checkboxes` referme la porte
|
|
861
|
+
comme `verify:buttons` : un vrai focus clavier contre un forcé, comparés octet pour octet, avec un
|
|
862
|
+
refus de conclure si l'un des deux ressort vide — deux absences se comparent égales.
|
|
863
|
+
|
|
864
|
+
*Repère : quand un composant a un état que le Figma dessine, vérifier que la PAGE peut le montrer,
|
|
865
|
+
pas seulement que le CSS le déclare. Les deux questions sont différentes, et la seconde ne répond
|
|
866
|
+
pas à la première.*
|
|
867
|
+
|
|
868
|
+
⚠️ **Et la sonde marque son témoin par un ATTRIBUT, pas par son identifiant.** Le `useId` de React
|
|
869
|
+
fabrique des identifiants à deux-points (« :r0: ») : valides en HTML, corrects pour un `for`, et
|
|
870
|
+
invalides dans un sélecteur CSS. Une sonde bâtie dessus échoue sur son propre sélecteur, pas sur un
|
|
871
|
+
défaut du composant.
|
|
872
|
+
|
|
873
|
+
- ⚠️ **UNE PAGE DE COMPOSANT EST UNE CONSIGNE, PAS UN CARNET DE BORD** (2026-09-10, demande de
|
|
874
|
+
Micka). Les pages « Cases à cocher » et « Info-bulles » avaient dérivé vers le récit de leur
|
|
875
|
+
FABRICATION : ce que le Figma dessine, ce qui a été mesuré, ce qu'un premier jet rendait, qui a
|
|
876
|
+
arbitré quoi, quel nœud est cité. Rien de tout ça n'aide un développeur à choisir une taille ou à
|
|
877
|
+
écrire un libellé.
|
|
878
|
+
|
|
879
|
+
Une page sous « Base components » répond à trois questions et pas une de plus : **quand l'employer**,
|
|
880
|
+
**quelle variante**, **ce que l'API prend**. Le reste — les relevés, les écarts à la maquette, les
|
|
881
|
+
défauts trouvés et comment — vit dans ce README et dans le CLAUDE.md, où il était déjà. Les pages
|
|
882
|
+
Foundations sont l'exception et continuent de mesurer : mesurer EST leur sujet.
|
|
883
|
+
|
|
884
|
+
Les tournures à chercher avant de livrer une page : « relevé », « mesuré », « un premier jet »,
|
|
885
|
+
« arbitré », « le Figma dessine », « à remonter dans le Figma », un numéro de nœud, « symbole ».
|
|
886
|
+
|
|
887
|
+
*Repère : j'avais déjà cette règle en note et je l'ai quand même enfreinte deux fois. Le réflexe
|
|
888
|
+
d'écrire ce qu'on vient de comprendre là où on vient de le comprendre est fort — la relecture de la
|
|
889
|
+
page doit se faire en se demandant « qu'est-ce qu'un dev fait de cette phrase ? ».*
|
|
890
|
+
|
|
891
|
+
- ⚠️ **SEPT VALEURS CHANGENT AVEC LA TAILLE DE LA CASE, ET TROIS AVAIENT ÉTÉ UNIFORMISÉES**
|
|
892
|
+
(2026-09-10). La boîte, le rayon, l'écart au texte, l'écart entre les deux textes, le palier
|
|
893
|
+
typographique, **la part de la marque** et **son épaisseur de trait**.
|
|
894
|
+
|
|
895
|
+
taille boîte marque part trait peint point radio
|
|
896
|
+
sm 16 12 75 % 1,6666 37,5 %
|
|
897
|
+
md 20 14 70 % 2 40 %
|
|
898
|
+
|
|
899
|
+
Les trois dernières colonnes avaient une seule valeur, et **ça se voyait** : la coche sortait à 1 px
|
|
900
|
+
au lieu de 1,6666, donc pâle. **C'est l'œil de Micka qui l'a signalé, pas les contrôles** — qui
|
|
901
|
+
mesuraient la part de la marque à une seule valeur et ne regardaient pas le trait du tout.
|
|
902
|
+
|
|
903
|
+
⚠️ **Et le trait ne suit pas l'échelle du dessin.** Les coordonnées du tracé la suivent
|
|
904
|
+
exactement — celles du Figma sont celles de notre catalogue multipliées par 12/24 puis 14/24, au
|
|
905
|
+
chiffre près. Le TRAIT, lui, reste épais : une réduction proportionnelle donnerait 1 px en `sm`.
|
|
906
|
+
C'est un choix de dessin — une coche fine dans une petite boîte disparaît. `stroke-width`
|
|
907
|
+
s'exprimant dans les unités du `viewBox` (24 pour nos icônes), peindre une épaisseur E sur une
|
|
908
|
+
marque de M pixels demande `E × 24 / M`. `verify:checkboxes` mesure l'épaisseur PEINTE, jamais
|
|
909
|
+
l'attribut.
|
|
910
|
+
|
|
911
|
+
*Repère : quand une taille change, lister ce qui change AVEC elle avant de coder. Une proportion
|
|
912
|
+
qui vaut pour une taille est une hypothèse, pas un relevé.*
|
|
913
|
+
|
|
914
|
+
- ⚠️ **« CASES À COCHER » ET « BOUTONS RADIO » SONT DEUX PAGES, ET UNE SEULE FEUILLE DE STYLE**
|
|
915
|
+
(2026-09-10, demande produit, alignée sur la façon dont la bibliothèque de référence les range).
|
|
916
|
+
Les deux composants restent UN atome : `Checkbox.css` habille les deux, et `verify:checkboxes`
|
|
917
|
+
visite les DEUX pages en une passe.
|
|
918
|
+
|
|
919
|
+
Ne lire que la première laisserait le radio non vérifié, et un correctif fait pour l'un peut casser
|
|
920
|
+
l'autre sans qu'aucune page ne le dise. Le radio doit apparaître dans ses DEUX tailles : son point
|
|
921
|
+
fait 37,5 % en `sm` et 40 % en `md`, donc une page qui n'en montrerait qu'une laisserait la
|
|
922
|
+
seconde sans mesure.
|
|
923
|
+
|
|
924
|
+
- ⚠️ **LA BORDURE DE LA CASE DÉCOCHÉE A ÉTÉ FONCÉE, ET C'EST UN ÉCART ARBITRÉ AU FIGMA**
|
|
925
|
+
(2026-09-10, décision produit). Le cadre la peint `border-primary` (navy-40), qui tient **1,44**
|
|
926
|
+
sur du blanc pour un seuil de 3:1 — **le plus bas mesuré sur ce design system**.
|
|
927
|
+
|
|
928
|
+
Et c'est plus grave que sur le bouton, où le même compromis a été accepté à 2,17 : un bouton garde
|
|
929
|
+
son libellé à 11,82, donc il reste identifiable, tandis qu'ici **la boîte EST le contrôle**. Une
|
|
930
|
+
case décochée à 1,44 est presque invisible. `navy-70` tient 3,67 : le palier le plus CLAIR de nos
|
|
931
|
+
neutres qui passe le seuil, donc le plus proche de l'intention du dessin. Exactement l'arbitrage
|
|
932
|
+
rendu pour le point de statut « hors ligne » de l'avatar, qui partait lui aussi de navy-40.
|
|
933
|
+
|
|
934
|
+
⚠️ **Et aucun rôle de bordure ne porte navy-70.** Les rôles de bordure vont de navy-40 à navy-20,
|
|
935
|
+
plus les teintes de marque et d'erreur. navy-70 est porté par `text-secondary`, un rôle de TEXTE :
|
|
936
|
+
s'en servir pour peindre une BORDURE serait la confusion que la seconde vérification de
|
|
937
|
+
`verify:tokens` existe pour empêcher. D'où un jeton de composant. À remonter dans le Figma.
|
|
938
|
+
|
|
939
|
+
- ⚠️ **LE FOND COCHÉ RESTE SUR brand-500, LÀ OÙ LE BOUTON EST DESCENDU À brand-600** (2026-09-10).
|
|
940
|
+
Ce n'est pas une incohérence : le bouton a bougé parce que du TEXTE blanc sur brand-500 tient 3,60
|
|
941
|
+
pour un seuil AA de 4,50. Ici la marque blanche n'est pas du texte, c'est un objet graphique, et la
|
|
942
|
+
WCAG 1.4.11 en demande 3:1 — les 3,60 passent. Descendre d'un cran « par cohérence » foncerait un
|
|
943
|
+
contrôle qui n'en a pas besoin.
|
|
944
|
+
|
|
945
|
+
- ⚠️ **L'ÉTAT « HOVER » DU FIGMA NE DESSINE RIEN, ET LE NÔTRE EST UN AJOUT** (2026-09-10, décision
|
|
946
|
+
produit). Les quarante symboles portent bien une variante `Hover`, et elle est **identique au
|
|
947
|
+
PIXEL** à l'état `Default` — établi en échantillonnant la capture du cadre aux coordonnées que
|
|
948
|
+
`get_metadata` donne, sur les décochés, les cochés, les indéterminés et les radios.
|
|
949
|
+
|
|
950
|
+
La variante existe, donc l'intention y était ; elle dessine juste la même chose. Un contrôle sans
|
|
951
|
+
retour au survol paraît inerte, donc on en dessine un : décoché il prend un fond navy-20, coché il
|
|
952
|
+
descend d'un cran. Ce cran ne demande aucun jeton — `bg-brand-solid` EST brand-600, c'est un rôle,
|
|
953
|
+
et de la bonne catégorie. À remonter dans le Figma.
|
|
954
|
+
|
|
955
|
+
*Repère : une variante qui existe et ne dessine rien n'est pas un choix, c'est un oubli de
|
|
956
|
+
maquette — et elle ne se voit qu'en comparant deux symboles au pixel.*
|
|
957
|
+
|
|
958
|
+
- ⚠️ **LE DÉSACTIVÉ EST DEUX CHANGEMENTS À LA FOIS, ET CE SONT LES PIXELS QUI L'ONT TRANCHÉ**
|
|
959
|
+
(2026-09-10). On pouvait croire à une simple opacité posée sur l'état par défaut : un blanc à 50 %
|
|
960
|
+
sur du blanc reste blanc, et la bordure aurait donné #e9ebef, alors que la case désactivée mesure
|
|
961
|
+
**#f8f9fa** — soit exactement navy-20 à 50 %. Le symbole confirme : fond navy-20, bordure
|
|
962
|
+
conservée, `opacity: 0.5`.
|
|
963
|
+
|
|
964
|
+
L'opacité est le même mécanisme que le bouton désactivé, et c'est elle qui explique la marque :
|
|
965
|
+
elle reste blanche parce que l'opacité s'applique au GROUPE, pas à chaque couche. **Elle est posée
|
|
966
|
+
sur la LIGNE, pas sur la case** — sur la case seule, le libellé resterait à pleine intensité à côté
|
|
967
|
+
d'un contrôle éteint.
|
|
968
|
+
|
|
969
|
+
- ⚠️ **L'ANNEAU DE FOCUS EST UN RELEVÉ, POUR UNE FOIS, PAS UN AJOUT** (2026-09-10). Le Figma l'écrit
|
|
970
|
+
`0 0 0 2px bg-primary, 0 0 0 4px Bleu/100` — soit exactement la recette que le bouton avait posée
|
|
971
|
+
et que la croix de fermeture, la croix du badge et l'icône d'aide de l'info-bulle réemploient.
|
|
972
|
+
Quatre pièces l'avaient ajoutée de leur côté, faute de la trouver dans les cadres ; celle-ci
|
|
973
|
+
confirme qu'elle était juste.
|
|
974
|
+
|
|
975
|
+
- ⚠️ **L'ÉLÉMENT EST UN VRAI `<input>`, ET C'EST CE QUI REND `:indeterminate` POSSIBLE** (2026-09-10).
|
|
976
|
+
Il porte `appearance: none` et se laisse habiller, mais il garde ce qu'un `div` n'a pas : le
|
|
977
|
+
clavier, la participation au formulaire, le groupement des radios par `name`, et les
|
|
978
|
+
pseudo-classes natives `:checked`, `:disabled`, `:focus-visible` et `:indeterminate`.
|
|
979
|
+
|
|
980
|
+
`verify:checkboxes` vérifie explicitement `appearance: none` : sans lui, le navigateur peint SA
|
|
981
|
+
case par-dessus la nôtre. Le résultat n'est pas vide — c'est une case native, à la bonne place, qui
|
|
982
|
+
ignore tous nos jetons.
|
|
983
|
+
|
|
984
|
+
⚠️ **`indeterminate` est une propriété du NŒUD, pas un attribut, et elle se réécrit à chaque
|
|
985
|
+
rendu.** Aucun attribut HTML ne la déclare, donc React ne la synchronise jamais : sans l'écriture
|
|
986
|
+
répétée, une case rendue indéterminée le RESTERAIT après être repassée à `false`, et l'écart entre
|
|
987
|
+
l'état demandé et le DOM n'apparaît ni dans le balisage, ni dans un diff, ni sur une capture.
|
|
988
|
+
|
|
989
|
+
⚠️ **Et elle est indépendante de `checked`, contre le Figma.** Le cadre ne la dessine qu'avec
|
|
990
|
+
`Checked=True`, mais obliger à cocher une case pour la rendre indéterminée serait l'inverse de son
|
|
991
|
+
sens. HTML gagne.
|
|
992
|
+
|
|
993
|
+
- ⚠️ **LE LIBELLÉ EST RELIÉ PAR `htmlFor`, IL N'ENVELOPPE PAS** (2026-09-10). Un `<label>` qui
|
|
994
|
+
envelopperait le contrôle ET le texte d'aide ferait de l'aide une partie du NOM accessible : un
|
|
995
|
+
lecteur d'écran annoncerait les deux d'un bloc, à chaque rencontre du contrôle. Le libellé est le
|
|
996
|
+
nom, l'aide est une DESCRIPTION via `aria-describedby`.
|
|
997
|
+
|
|
998
|
+
Conséquence assumée : cliquer le libellé bascule la case, cliquer l'aide ne fait rien. **Et la
|
|
999
|
+
mutation mord** — envelopper dans un `<label>` fait échouer le test de nom/description de la case
|
|
1000
|
+
ET celui du radio. C'est précisément l'implémentation « évidente », celle qui rend toute la ligne
|
|
1001
|
+
cliquable, qui casse la sémantique.
|
|
1002
|
+
|
|
1003
|
+
- ⚠️ **LE TEXTE D'AIDE RESTE SOUS L'AA, ET CE N'EST PAS UN PROBLÈME DE CE COMPOSANT** (2026-09-10).
|
|
1004
|
+
Il tient 3,67 pour un seuil de 4,50 — mais le Figma le peint `text-secondary`, et ce RÔLE est
|
|
1005
|
+
navy-70 : il est sous le seuil **partout où il porte du texte**. Le foncer ici seulement rendrait
|
|
1006
|
+
cette aide différente de toutes les autres du design system.
|
|
1007
|
+
|
|
1008
|
+
Épinglé dans `verify:checkboxes` **dans l'autre sens** : le jour où le rôle sera foncé, ce contrôle
|
|
1009
|
+
rougira, et ce sera le rappel qu'il faut retirer l'exception. **C'est une décision de fondation, et
|
|
1010
|
+
elle est ouverte** — voir « En attente ».
|
|
1011
|
+
|
|
1012
|
+
- ⚠️ **LE PLACEMENT DE L'INFO-BULLE EST CHOISI PAR LE DÉVELOPPEUR, ET LE PAQUET N'A TOUJOURS AUCUNE
|
|
1013
|
+
DÉPENDANCE D'EXÉCUTION** (2026-09-10, arbitrage du lead dev front). Les six placements de la
|
|
1014
|
+
maquette sont en CSS, et l'appelant en choisit un.
|
|
1015
|
+
|
|
1016
|
+
**La conséquence est à connaître avant de s'en servir : rien ne retourne la bulle si elle ne tient
|
|
1017
|
+
pas.** Une info-bulle placée près du bord de l'écran en sortira. C'est le prix de zéro dépendance,
|
|
1018
|
+
et la page de documentation énonce les trois cas où il faut changer de placement.
|
|
1019
|
+
|
|
1020
|
+
⚠️ **CETTE DÉCISION EN A ANNULÉ UNE PRISE LE MÊME JOUR, ET LE DÉTOUR A SERVI.** Une première
|
|
1021
|
+
version passait par `react-aria-components`, déjà en production sur `liste-evaluations` et
|
|
1022
|
+
`export-rapport-entretien` ; l'équipe produit l'avait validée en `peerDependency`, en connaissance
|
|
1023
|
+
du coût. Le lead dev front a tranché l'autre branche — celle que la recommandation d'origine
|
|
1024
|
+
proposait — et le paquet est revenu à **zéro dépendance d'exécution**.
|
|
1025
|
+
|
|
1026
|
+
Ce qui SURVIT du détour, ce sont ses MESURES : le recouvrement de la flèche, son retrait de 12 px
|
|
1027
|
+
sur les placements décalés et l'écart de 4 px au déclencheur ont tous été relevés dans un vrai
|
|
1028
|
+
navigateur pendant ce passage, et sont reproduits à l'identique. Trois problèmes sont partis avec
|
|
1029
|
+
la bibliothèque :
|
|
1030
|
+
|
|
1031
|
+
· son `transform` en style EN LIGNE sur l'enveloppe de la flèche écrasait notre rotation sans
|
|
1032
|
+
bruit ;
|
|
1033
|
+
· les bulles forcées ouvertes étaient mal placées dans une page MDX longue — un relevé donnait
|
|
1034
|
+
4 px d'écart, le suivant 118 px sur le MÊME code — ce qui avait obligé à rendre deux planches
|
|
1035
|
+
« en statique » ;
|
|
1036
|
+
· une bulle « froide » était intestable sous jsdom, donc le fichier de test devait réchauffer la
|
|
1037
|
+
bibliothèque avant CHAQUE cas, ce qui masquait justement la question.
|
|
1038
|
+
|
|
1039
|
+
Et une chose est devenue MEILLEURE que la bibliothèque : elle ancrait la flèche au CENTRE du
|
|
1040
|
+
déclencheur, donc les 12 px du Figma ne tombaient juste que sur une icône de 16 px et dérivaient à
|
|
1041
|
+
70,64 px sur un bouton `sm`. En CSS, les placements décalés s'ancrent sur la FLÈCHE : le retrait
|
|
1042
|
+
vaut 12 px quelle que soit la largeur du déclencheur, et `verify:info-bulles` le mesure sur trois
|
|
1043
|
+
largeurs différentes.
|
|
1044
|
+
|
|
1045
|
+
*Repère : une décision produit peut être renversée par une décision technique le jour même, et
|
|
1046
|
+
c'est normal. Ce qu'il faut sauver du travail annulé, ce sont ses MESURES — pas son architecture.*
|
|
1047
|
+
|
|
1048
|
+
- ⚠️ **LE COMPOSANT N'AJOUTE QU'UN SEUL NŒUD : UNE ANCRE** (2026-09-10). Un `span` qui sert de repère
|
|
1049
|
+
de position à la bulle et qui ne prend pas de `tabIndex`. Envelopper le déclencheur dans un bouton
|
|
1050
|
+
est ce que fait l'implémentation en production, et ça y a créé **six arrêts de tabulation morts** —
|
|
1051
|
+
six boutons focusables sans action. Un test vérifie qu'un seul bouton est rendu, et qu'une seconde
|
|
1052
|
+
tabulation SORT de l'ensemble.
|
|
1053
|
+
|
|
1054
|
+
⚠️ **UN DÉCLENCHEUR NON FOCUSABLE EN DEVIENT UN, ET C'EST VOULU** — une aide qu'on ne peut pas
|
|
1055
|
+
atteindre au clavier n'aide qu'une partie des gens. Un `span` reçoit un `tabIndex` ; un élément
|
|
1056
|
+
déjà focusable (bouton, lien, champ) n'est pas touché, et un `tabIndex` donné par l'appelant est
|
|
1057
|
+
respecté. Trois tests couvrent les trois cas, parce que la règle est invisible dans le balisage.
|
|
1058
|
+
|
|
1059
|
+
⚠️ **LES GESTIONNAIRES SONT COMPOSÉS, PAS REMPLACÉS.** `cloneElement` écrase les props qu'il
|
|
1060
|
+
reçoit : poser `onMouseEnter` sur un déclencheur qui en avait déjà un le ferait disparaître en
|
|
1061
|
+
silence — la bulle s'ouvrirait, et l'action attendue par l'appelant ne se ferait plus, sans aucune
|
|
1062
|
+
erreur. Celui de l'appelant passe en premier.
|
|
1063
|
+
|
|
1064
|
+
- ⚠️ **ÉCHAP FERME LA BULLE, ET C'EST UN AJOUT** (2026-09-10). Le Figma ne dessine que « ouverte » et
|
|
1065
|
+
« fermée ». Sans Échap, une bulle ouverte au clavier recouvre ce qui l'entoure jusqu'au prochain
|
|
1066
|
+
changement de focus — et une bulle à texte de soutien fait 320 px de large. L'écoute est posée sur
|
|
1067
|
+
le DOCUMENT, pas sur le déclencheur : la touche doit fonctionner même si le focus a bougé.
|
|
1068
|
+
|
|
1069
|
+
- ⚠️ **LE RECOUVREMENT DE LA FLÈCHE EST DEUX NOMBRES DIFFÉRENTS, et c'est de la géométrie**
|
|
1070
|
+
(2026-09-10). À la verticale la flèche s'enfonce de 8,51471 − 6 = 2,5147 px. Tournée d'un quart de
|
|
1071
|
+
tour, elle pivote autour de son CENTRE alors que sa boîte garde la largeur NON tournée (16) : son
|
|
1072
|
+
centre est à 8 px du bord, plus une demi-hauteur de 4,2574 — elle dépasserait de 12,2574 et doit
|
|
1073
|
+
s'enfoncer de 6,2574. Un seul nombre pour les quatre côtés mesurait 9,74 px sur les côtés contre
|
|
1074
|
+
5,99 en haut, et paraissait cohérent.
|
|
1075
|
+
|
|
1076
|
+
- ⚠️ **`box-sizing: border-box` PORTE LA LARGEUR DE 320 PX** (2026-09-10). Le Figma cale la bulle à
|
|
1077
|
+
texte de soutien sur 320 px TOTAL. En `content-box` — le défaut de CSS, et ce dépôt n'a aucune
|
|
1078
|
+
remise à zéro globale — les 12 px de padding s'ajoutent de chaque côté : mesurée, la bulle sortait
|
|
1079
|
+
à **344 px**. Et 344 ressemble à 320. Le contrôle vérifie les DEUX, la largeur et le modèle de
|
|
1080
|
+
boîte, parce que « corriger » la largeur à 296 ferait disparaître le symptôme sans la cause.
|
|
1081
|
+
|
|
1082
|
+
- ⚠️ **L'OMBRE DE L'INFO-BULLE EST UN `filter`, ET C'EST LA FLÈCHE QUI L'IMPOSE** (2026-09-10,
|
|
1083
|
+
demande produit). Un `box-shadow` ombre la BOÎTE : il dessinerait un rectangle autour de la bulle
|
|
1084
|
+
ET de sa flèche, en laissant la flèche plate. `drop-shadow()` suit la silhouette PEINTE.
|
|
1085
|
+
|
|
1086
|
+
Le prix : aucun de nos jetons `--zds-shadow-*` n'est réutilisable, ils portent un étalement négatif
|
|
1087
|
+
que `drop-shadow()` ne sait pas exprimer — d'où `--zds-shadow-tooltip-filter`. Sa teinte est aussi
|
|
1088
|
+
une SUBSTITUTION délibérée : le Figma la pose en `rgba(16, 24, 40, …)`, une couleur d'une
|
|
1089
|
+
collection TIERCE, là où toute notre rampe d'ombres est en noir. À 8 % d'opacité sur du blanc,
|
|
1090
|
+
l'écart mesure 2,3 niveaux sur 255.
|
|
1091
|
+
|
|
1092
|
+
- ⚠️ **LE HELP ICON EST L'UN DES CINQ DESSINS QUE LE CATALOGUE ÉCARTE** (2026-09-10). Deux
|
|
1093
|
+
générations de `help-circle-01` cohabitent dans le Figma sous le même nom : le catalogue publie la
|
|
1094
|
+
silhouette REMPLIE, et le cadre de l'info-bulle cite le nœud `3167:12028`, le tracé au CONTOUR
|
|
1095
|
+
rangé dans `ZEST_ICONS_EN_CONFLIT`. Un `<HelpCircle01 />` rendrait donc l'autre dessin.
|
|
1096
|
+
|
|
1097
|
+
Le composite va le chercher PAR SON NUMÉRO DE NŒUD — aucun troisième exemplaire du tracé — avec un
|
|
1098
|
+
repli si l'arbitrage le fait un jour monter dans le catalogue publié. `HelpCircle01` n'est employé
|
|
1099
|
+
nulle part aujourd'hui, donc cet arbitrage ne coûte rien en code.
|
|
1100
|
+
|
|
1101
|
+
⚠️ **ET L'EN-TÊTE DU CATALOGUE AFFIRME QUELQUE CHOSE DE FAUX** : il dit que « la page Icônes les
|
|
1102
|
+
montre à côté de ceux qui gagnent, pour qu'on tranche en regardant ». Elle ne les montre pas.
|
|
1103
|
+
`ZEST_ICONS_EN_CONFLIT` est exporté de `src/index.ts` et rendu par aucune page. **À faire, ou à
|
|
1104
|
+
cesser de promettre.**
|
|
1105
|
+
|
|
1106
|
+
- ⚠️ **`verify:info-bulles` ÉTAIT AVEUGLE À UNE INVERSION DE PLACEMENT, ET C'EST UNE MUTATION QUI L'A
|
|
1107
|
+
DIT** (2026-09-10). Échanger `left: 50%` contre `right: 50%` sur `top-right` envoie la bulle du
|
|
1108
|
+
côté opposé, et le contrôle restait vert : le retrait de 12 px est mesuré depuis le bord de la
|
|
1109
|
+
BULLE, donc il vaut 12 où que la bulle se trouve.
|
|
1110
|
+
|
|
1111
|
+
L'invariant qui manquait est le SÉMANTIQUE — **la flèche doit pointer sur le centre du
|
|
1112
|
+
déclencheur** — et il est désormais mesuré sur chaque placement. Les deux sont gardés : le retrait
|
|
1113
|
+
décrit la bulle, le centrage décrit sa RELATION au déclencheur.
|
|
1114
|
+
|
|
1115
|
+
⚠️ **ET UNE AUTRE MUTATION A EU L'AIR DE NE PAS MORDRE ALORS QU'ELLE N'AVAIT PAS ÉTÉ CHARGÉE.**
|
|
1116
|
+
Deux mutations CSS ressortaient vertes à 10 s d'attente et rouges à 14 : le rechargement à chaud de
|
|
1117
|
+
Vite ne les avait pas appliquées. *Avant de conclure qu'un contrôle est aveugle, lire la règle
|
|
1118
|
+
SERVIE dans le DOM.* Sur ces deux mutations, une seule l'était réellement.
|
|
1119
|
+
|
|
1120
|
+
- ⚠️ **UN JETON DÉCLARÉ ET JAMAIS CITÉ ÉCHAPPE À TOUS LES CONTRÔLES** (2026-09-10).
|
|
1121
|
+
`--zds-color-tooltip-supporting-text` existait déjà, porté du thème de référence, et valait
|
|
1122
|
+
`gray-300` — là où le Figma de Zest donne `navy-20`. Le redéclarer a créé un DOUBLON silencieux :
|
|
1123
|
+
deux déclarations d'une même propriété, la première morte.
|
|
1124
|
+
|
|
1125
|
+
Personne n'avait vu la mauvaise valeur parce que rien ne la CITAIT : `verify:tokens` résout les
|
|
1126
|
+
jetons qu'un composant emploie. Ses quatre voisins du même bloc étaient dans le même cas — **des
|
|
1127
|
+
ports, pas des relevés**. Les trois `toggle-*` ont été relus le 2026-09-11 : **les trois étaient
|
|
1128
|
+
faux**. Seul `slider-handle-*` reste invérifié, et il attend le curseur.
|
|
1129
|
+
|
|
1130
|
+
- ⚠️ **LE PROVISOIRE `.zds-doc-bulle` PEIGNAIT LA MAUVAISE COULEUR DEPUIS LE JOUR OÙ IL A ÉTÉ ÉCRIT**
|
|
1131
|
+
(2026-09-10). Son fond citait `bg-primary-solid`, qui aboutit sur `gray-950` (#0a0d12) ; la
|
|
1132
|
+
maquette peint la bulle en `Bleu marine/100` (#21304e). Deux noirs différents, et le mauvais.
|
|
1133
|
+
`docs.css` n'étant pas une feuille de composant, `verify:tokens` ne l'a jamais lu.
|
|
1134
|
+
|
|
1135
|
+
La leçon vaut plus que le correctif : **un dessin fait à côté d'un composant absent ne se contente
|
|
1136
|
+
pas de vieillir, il peut être faux dès le premier jour, et rien ne le surveille.** Le même soupçon
|
|
1137
|
+
porte sur les trois provisoires qui restent dans ce bloc.
|
|
1138
|
+
|
|
1139
|
+
- ⚠️ **RETIRER LE `title` DU BOUTON D'AJOUT ÉTAIT INVISIBLE AUX 25 TESTS DE L'AVATAR** (2026-09-10).
|
|
1140
|
+
Tous sont restés verts : aucun ne gardait le provisoire. Le remplacement n'apparaissait que dans le
|
|
1141
|
+
diff — exactement la régression par remplacement que rien ne voit. Deux tests ont été ajoutés
|
|
1142
|
+
après coup, et ils affirment les DEUX sens : la bulle native a disparu, et l'`aria-label` est
|
|
1143
|
+
resté. Sans le second, retirer le libellé « puisque la bulle le dit » passerait sans bruit, et le
|
|
1144
|
+
bouton s'annoncerait « bouton » — une info-bulle n'existe qu'au survol.
|
|
1145
|
+
|
|
1146
|
+
- ⚠️ **UN DÉLIMITEUR DE COMMENTAIRE EN TROP DANS `theme.css` SUPPRIME LA DÉCLARATION QUI LE SUIT**
|
|
1147
|
+
(2026-09-10). Un `*` suivi d'un `/` surnuméraire refermait le commentaire du bloc AVATAR en son
|
|
1148
|
+
milieu : le paragraphe d'après devenait du CSS invalide, et la récupération d'erreur du navigateur
|
|
1149
|
+
**saute jusqu'au prochain `;`**. Ce qui a disparu n'est donc pas le paragraphe, mais
|
|
1150
|
+
`--zds-color-avatar-bg`, la déclaration d'après. Un `var()` sur un jeton inexistant ne peint rien,
|
|
1151
|
+
sans erreur ni avertissement : les trois avatars en pastille — picto, initiales, masque — sont
|
|
1152
|
+
sortis **transparents**.
|
|
1153
|
+
|
|
1154
|
+
`tsc`, les 69 tests, `verify:tokens` et `verify:avatars` étaient tous verts. C'est Micka qui l'a vu
|
|
1155
|
+
à l'œil, et c'est le genre de défaut qui donne un résultat plausible : un rond blanc bordé
|
|
1156
|
+
ressemble à un choix.
|
|
1157
|
+
|
|
1158
|
+
Trois choses à en garder :
|
|
1159
|
+
|
|
1160
|
+
· **chercher AU-DESSUS du jeton manquant, pas à son endroit.** Le fichier se lit parfaitement à la
|
|
1161
|
+
ligne de la déclaration disparue ; le dégât est en amont d'elle ;
|
|
1162
|
+
· **compter les ouvertures contre les fermetures ne suffit pas**, même si ça a suffi ici (60 contre
|
|
1163
|
+
61). Le comptage est aveugle au cas « un commentaire, du texte, un second commentaire » : ça
|
|
1164
|
+
s'équilibre et il reste pourtant du texte dehors. `verify:foundations` retire donc les
|
|
1165
|
+
commentaires comme le fait un navigateur, puis exige que tout ce qui reste dans `:root` soit une
|
|
1166
|
+
déclaration. Les deux cas sont éprouvés par mutation, avec un troisième — un commentaire jamais
|
|
1167
|
+
refermé — où le contrôle **refuse de conclure** au lieu de passer ;
|
|
1168
|
+
· **une sonde géométrique ne voit pas une couleur absente.** `verify:avatars` était vert parce que
|
|
1169
|
+
rien n'avait bougé. Il mesure désormais le fond de la pastille ET exige que celui d'une photo
|
|
1170
|
+
reste transparent : sans cette seconde moitié, le contrôle passerait sur une page où plus rien
|
|
1171
|
+
n'est peint — deux fois du vide comparé à lui-même.
|
|
1172
|
+
|
|
1173
|
+
Effet de bord mesuré : `dist/index.css` est passé de 58,39 à 58,02 Ko en réparant, parce que le
|
|
1174
|
+
texte orphelin était **embarqué tel quel dans le CSS publié**.
|
|
1175
|
+
|
|
1176
|
+
- ⚠️ **TROIS VÉRIFICATIONS AVANT CHAQUE COMMIT, ET C'EST UNE HABITUDE, PAS UN RÉFLEXE AU CAS PAR
|
|
1177
|
+
CAS** (2026-09-10, demande produit). Les jetons sémantiques (`verify:tokens`), l'application des
|
|
1178
|
+
FOUNDATIONS et l'absence du nom du fournisseur tiers (`verify:foundations`, écrit ce jour-là).
|
|
1179
|
+
|
|
1180
|
+
**La raison est que les deux défauts qui ont motivé la règle étaient invisibles là où ils
|
|
1181
|
+
étaient écrits.** Les 13 sauts de couche du premier badge rendaient juste, passaient `tsc`, les
|
|
1182
|
+
44 tests et les deux contrôles de jetons existants — l'audit qui les a trouvés était manuel, et
|
|
1183
|
+
personne ne l'aurait lancé sur un changement qui « ne touche pas aux couleurs ». Le nom du
|
|
1184
|
+
fournisseur, lui, est revenu deux fois dans les notes pendant qu'on le retirait des pages. Un
|
|
1185
|
+
contrôle qu'on ne lance que quand on le soupçonne ne trouve que ce qu'on soupçonne.
|
|
1186
|
+
|
|
1187
|
+
Ce que `verify:foundations` cherche et ce qu'il laisse passer :
|
|
1188
|
+
|
|
1189
|
+
· il ne signale que les valeurs brutes **qu'un jeton nomme déjà**, et **par famille de
|
|
1190
|
+
propriété** — l'échelle d'espacement pour `padding` / `margin` / `gap`, celle des rayons pour
|
|
1191
|
+
`border-radius`, celle du texte pour `font-size` et `line-height`. Comparer un padding à tous
|
|
1192
|
+
les jetons confondus reprocherait un `padding: 10px` au nom d'un jeton de RAYON, ce qui ne veut
|
|
1193
|
+
rien dire : deux jetons qui partagent une valeur ne partagent pas un sens — c'est déjà le
|
|
1194
|
+
raisonnement de la CATÉGORIE dans `verify:tokens` ;
|
|
1195
|
+
· une valeur **hors échelle** passe en silence, et c'est voulu : les 10 px de padding du badge,
|
|
1196
|
+
ses 3 px de rayon de croix, les filets sous-pixel de l'avatar sont des relevés du Figma, il n'y
|
|
1197
|
+
a rien à citer à leur place. Le contrôle attrape l'oubli, pas l'exception ;
|
|
1198
|
+
· **une exception énumérée**, comme `GRIS_ADMIS` dans `verify:tokens` : le `padding: 2px` du
|
|
1199
|
+
biseau des boutons pleins est une ÉPAISSEUR de trait, pas un espacement, et citer
|
|
1200
|
+
`--zds-space-xxs` là serait exactement la confusion que le contrôle existe pour empêcher. Il
|
|
1201
|
+
**échoue aussi si l'exception cesse d'être employée** — une dispense ne survit pas à son
|
|
1202
|
+
bénéficiaire ;
|
|
1203
|
+
· le motif du nom du fournisseur est **reconstitué à l'exécution**. Un contrôle qui écrirait la
|
|
1204
|
+
chaîne qu'il interdit se trouverait lui-même et rougirait à chaque passage. Les binaires sont
|
|
1205
|
+
écartés : les octets d'un WebP peuvent épeler n'importe quoi, et les 282 avatars produiraient
|
|
1206
|
+
un faux positif par lot.
|
|
1207
|
+
|
|
1208
|
+
Les quatre mutations qui prouvent qu'il mord ont été jouées : un `margin: 8px` dans le badge,
|
|
1209
|
+
un `border-radius` / `font-size` / `line-height` bruts, le biseau du bouton passé à 1 px, et le
|
|
1210
|
+
nom du fournisseur remis dans une page. Chacune fait sortir 1.
|
|
1211
|
+
|
|
1212
|
+
- ⚠️ **UNE ANOMALIE DU FIGMA EST REPRODUITE DANS LE BADGE, EN TAILLE `sm`** (2026-09-10). Un
|
|
1213
|
+
`Badge color` ou un `Badge modern` de taille `sm` portant une icône gagne 2 px du côté OPPOSÉ à
|
|
1214
|
+
l'icône — 8 au lieu de 6 — et tombe alors à la largeur exacte du `Pill color`, alors que ces
|
|
1215
|
+
deux habillages ne se distinguent QUE par leur padding. Les autres tailles ne le font pas.
|
|
1216
|
+
Vraisemblablement des variantes recopiées depuis le pill sans réajuster le padding.
|
|
1217
|
+
|
|
1218
|
+
Reproduite plutôt que corrigée : les maquettes font foi, et une correction silencieuse aurait
|
|
1219
|
+
fait diverger le code et le Figma sans laisser de trace. Elle est **épinglée** dans
|
|
1220
|
+
`verify:badges`, donc **la corriger dans le Figma fera échouer le contrôle** — c'est le rappel
|
|
1221
|
+
qu'il faudra retirer les deux règles CSS et la section de la page avec elle.
|
|
1222
|
+
|
|
1223
|
+
- **La géométrie du badge est une TABLE, et la table a été prouvée** (2026-09-10). Quatre règles —
|
|
1224
|
+
hauteur = interligne + 2 × padding ; le côté du LIBELLÉ porte le padding de base du type ; le
|
|
1225
|
+
côté d'une PIÈCE le perd de 2 px sur le pill et le garde sur les deux autres, sauf l'icône qui
|
|
1226
|
+
le perd sur les deux ; la croix ne suit pas l'échelle (3, 4, 6). Un script a recalculé les
|
|
1227
|
+
largeurs ET les hauteurs des **477 symboles** du cadre depuis ces règles : les 477 tombent
|
|
1228
|
+
juste, au pixel. C'est ce modèle que `verify:badges` vérifie dans le navigateur.
|
|
1229
|
+
|
|
1230
|
+
- ⚠️ **LE COMPOSANT AVATAR EXISTAIT, ET CE DÉPÔT AFFIRMAIT LE CONTRAIRE** (2026-09-10). Le
|
|
1231
|
+
`CLAUDE.md`, le README et la page Foundations écrivaient tous les trois qu'il n'y avait pas de
|
|
1232
|
+
composant `Avatar` dans le V2.0 et que c'était « délibéré ». Le relevé s'était arrêté sur le
|
|
1233
|
+
cadre `3857:23794` — la banque de 282 photos — et n'avait pas cherché plus loin. Le composant
|
|
1234
|
+
vit dans **cinq cadres**, il a six tailles, quatre contenus, une bordure, trois statuts, un
|
|
1235
|
+
groupe et un avatar-libellé.
|
|
1236
|
+
|
|
1237
|
+
⚠️ **Un cadre qui répond à une question ne prouve pas qu'aucun autre n'y répond mieux.** C'est la
|
|
1238
|
+
leçon, et elle vaut pour les prochains relevés : la banque de photos était une réponse plausible
|
|
1239
|
+
à « où sont les avatars », donc personne n'a cherché la suivante.
|
|
1240
|
+
|
|
1241
|
+
- ⚠️ **LES INITIALES ENTRENT DANS LE SYSTÈME, ET UNE RÈGLE EN GRAS EST ABROGÉE** (2026-09-10). La
|
|
1242
|
+
page Foundations écrivait « chez Zest, un avatar est une photo ou un picto — jamais des
|
|
1243
|
+
initiales », avec une planche marquée en rouge et un paragraphe d'arguments. Le V2.0 les dessine
|
|
1244
|
+
dans les six tailles ; l'équipe produit a tranché.
|
|
1245
|
+
|
|
1246
|
+
Ce qui remplace l'interdiction est un **ordre** : photo > initiales > picto. Le raisonnement
|
|
1247
|
+
d'origine n'était pas faux — deux lettres désignent mal — il était trop absolu : elles désignent
|
|
1248
|
+
mieux qu'un pictogramme quand on connaît le nom. Le composant dérive donc son contenu de ce
|
|
1249
|
+
qu'on lui donne au lieu d'exiger trois interrupteurs.
|
|
1250
|
+
|
|
1251
|
+
⚠️ **L'ANONYME PASSE DEVANT TOUT, y compris une photo présente**, et il interdit le point de
|
|
1252
|
+
statut. Ce n'est pas une préférence : il sert les réponses anonymisées d'une campagne de
|
|
1253
|
+
feedback, et si une photo pouvait le battre, une photo suffirait à lever l'anonymat de quelqu'un
|
|
1254
|
+
qui l'a demandé.
|
|
1255
|
+
|
|
1256
|
+
L'échelle de tailles proposée par la page — 24, 32, 40, 48, 64, 96 — était **fausse**. Le Figma
|
|
1257
|
+
donne 24, 32, 40, 48, **56**, 64.
|
|
1258
|
+
|
|
1259
|
+
- **Le statut de l'avatar est ABSENT par défaut** (2026-09-10), sur décision produit : la
|
|
1260
|
+
production ne gère pas encore cet affichage, c'est une anticipation. Le composant n'en dessine
|
|
1261
|
+
aucun sans qu'on passe `status`, et la page ne le montre que dans sa propre section.
|
|
1262
|
+
`verify:avatars` vérifie qu'il reste absent de la majorité des avatars de la page — sans quoi
|
|
1263
|
+
elle laisserait croire à un défaut par défaut.
|
|
1264
|
+
|
|
1265
|
+
⚠️ **LES TROIS POINTS TIENNENT LES 3:1, ET DEUX ONT ÉTÉ FONCÉS POUR ÇA.** Sur décision produit du
|
|
1266
|
+
2026-09-10, le seuil de la WCAG 1.4.11 est exigé et non plus toléré : le disque d'un point de
|
|
1267
|
+
statut porte une information, donc sa couleur doit se distinguer du fond.
|
|
1268
|
+
|
|
1269
|
+
| | avant | après | sur blanc |
|
|
1270
|
+
|---|---|---|---|
|
|
1271
|
+
| En ligne | `success-600` | inchangé | 3,59 |
|
|
1272
|
+
| Hors ligne | `navy-40` — 1,44 | **`navy-70`** | 3,67 |
|
|
1273
|
+
| Commentaire sensible | `error-200` — 1,42 | **`error-500`** | 3,76 |
|
|
1274
|
+
|
|
1275
|
+
⚠️ **UNE OBJECTION QUE J'AVAIS FAITE ÉTAIT TROP LARGE.** J'avais écrit que foncer le gris ferait
|
|
1276
|
+
lire « hors ligne » comme un état ACTIF, et Micka l'avait acceptée. C'est vrai d'un `navy-80` ou
|
|
1277
|
+
d'un `navy-100` ; ce n'est pas vrai de `navy-70`, un gris moyen qui se lit toujours comme une
|
|
1278
|
+
absence de couleur à côté du vert. L'objection valait pour l'ampleur du geste, pas pour le geste
|
|
1279
|
+
— et elle a coûté un aller-retour.
|
|
1280
|
+
|
|
1281
|
+
⚠️ **LE DISQUE SENSIBLE ET SON PICTO NE POUVAIENT PAS TENIR ENSEMBLE.** Le Figma peint un picto
|
|
1282
|
+
`Rouge/200` sur un disque `Rouge/40` : le picto tient bien 3,40 sur son disque, mais le disque ne
|
|
1283
|
+
tient que 1,42 sur du blanc. Et un disque assez foncé pour tenir 3:1 ne laisse plus passer aucun
|
|
1284
|
+
rouge — au palier 500, un `error-600` tombe à 1,29. **Les deux exigences s'excluent sur la même
|
|
1285
|
+
teinte.** Le disque monte donc au 500 et le picto devient BLANC, à 3,76 : c'est la forme
|
|
1286
|
+
conventionnelle d'une alerte, et elle aligne ce point sur les deux autres. À répercuter dans le
|
|
1287
|
+
Figma, qui vient justement de repeindre ce picto en rouge.
|
|
1288
|
+
|
|
1289
|
+
- **Le gris du statut hors ligne est une substitution mesurée** (2026-09-10). Le Figma le peint
|
|
1290
|
+
`utility-neutral-300` (#d4d4d4), d'une collection tierce. Le plus proche chez Zest était
|
|
1291
|
+
`gray-300` (ΔE 1,99), écarté parce qu'il est dans la rampe grise que le contrôle interdit, et
|
|
1292
|
+
`navy-40` (ΔE 4,03) a servi un temps — avant d'être abandonné faute de contraste. `navy-70` est
|
|
1293
|
+
le palier le plus CLAIR des neutres de Zest qui tienne 3:1, donc le plus proche de l'intention.
|
|
1294
|
+
|
|
1295
|
+
- ⚠️ **LE DÉPÔT ANNONÇAIT « 121 ICÔNES » EN NEUF ENDROITS ALORS QU'IL Y EN AVAIT 133**
|
|
1296
|
+
(2026-09-10). La dérive est antérieure à l'ajout des deux icônes du statut : douze icônes avaient
|
|
1297
|
+
été ajoutées sans que la prose suive. Les neuf mentions sont passées à **135**. Le nombre est
|
|
1298
|
+
recopié à la main dans six fichiers — c'est exactement le piège que ce dépôt documente pour les
|
|
1299
|
+
pages qui recopient une valeur au lieu de la lire.
|
|
1300
|
+
|
|
1301
|
+
- ⚠️ **LES TROIS TEINTES CLAIRES DU BADGE DESCENDENT DE DEUX CRANS** (2026-09-10). Telles que le
|
|
1302
|
+
Figma les peignait, turquoise, tilleul et jaune ne tenaient aucun de leurs deux seuils : libellé
|
|
1303
|
+
3,77 / 4,05 / 4,35 pour 4,50, et **pièce** 2,55 / 2,34 / 2,69 pour 3,00. Le Figma les avait déjà
|
|
1304
|
+
foncées d'un cran pour deux d'entre elles ; ça ne suffisait pas.
|
|
1305
|
+
|
|
1306
|
+
Un cran de plus sur la pièce ET sur le texte fait passer les six mesures :
|
|
1307
|
+
|
|
1308
|
+
| Couleur | Pièce | Libellé |
|
|
1309
|
+
|---|---|---|
|
|
1310
|
+
| turquoise | 600 → **700** (2,55 → 3,77) | 700 → **800** (3,77 → 5,69) |
|
|
1311
|
+
| tilleul | 700 → **800** (2,34 → 4,05) | 800 → **900** (4,05 → 7,00) |
|
|
1312
|
+
| jaune | 700 → **800** (2,69 → 4,35) | 800 → **900** (4,35 → 7,59) |
|
|
1313
|
+
|
|
1314
|
+
⚠️ **LE RAPPORT PIÈCE/LIBELLÉ EST PRÉSERVÉ**, et c'est ce qui rend l'arbitrage propre : la
|
|
1315
|
+
nouvelle valeur de pièce est l'ANCIENNE valeur de libellé. Les treize couleurs partagent donc la
|
|
1316
|
+
même règle — la pièce est un cran plus claire que le libellé — et ces trois-là sont simplement
|
|
1317
|
+
assises deux crans plus bas. Ce ne sont plus des exceptions, et `verify:badges` ne porte plus
|
|
1318
|
+
aucun contraste épinglé : les seuils eux-mêmes les gardent.
|
|
1319
|
+
|
|
1320
|
+
⚠️ **ON N'A TOUCHÉ QUE CE QUI BLOQUAIT.** Les dix autres couleurs tiennent leurs deux seuils
|
|
1321
|
+
(libellé 4,69 à 12,58 ; pièce 3,31 à 6,84) et gardent leurs paliers. Les aligner « par
|
|
1322
|
+
cohérence » aurait assombri dix couleurs justes pour rien. Le FOND ne bouge pas non plus : il
|
|
1323
|
+
reste au palier 50, donc ces badges restent aussi pâles que les autres — et l'objection écrite
|
|
1324
|
+
la veille, « un tilleul au 900 n'est plus du tilleul », portait sur un APLAT saturé sous du texte
|
|
1325
|
+
blanc, où c'est le fond qui porte l'identité de la teinte. La bordure ne bouge pas : elle est
|
|
1326
|
+
décorative, un badge n'étant pas une commande.
|
|
1327
|
+
|
|
1328
|
+
- ⚠️ **LA RÈGLE DES CALQUES ÉTAIT ÉCRITE MAIS VÉRIFIÉE PAR RIEN** (2026-09-10). Un composant ne
|
|
1329
|
+
cite que le calque des rôles (3) ou celui des jetons de composant (4) — jamais une rampe brute
|
|
1330
|
+
(1), jamais une palette utilitaire (2). Un audit des cinq feuilles de composant a trouvé
|
|
1331
|
+
**13 citations en faute**, toutes dans le premier badge : le fond du survol de sa croix, écrit
|
|
1332
|
+
en `var(--zds-color-brand-100)`, `var(--zds-color-navy-30)` et huit `var(--zds-color-utility-*-100)`.
|
|
1333
|
+
Des valeurs justes, un rendu juste, et un défaut que rien ne voyait — ni le typage, ni les 44
|
|
1334
|
+
tests, ni les deux vérifications de `verify:tokens`, qui ne regardaient que la rampe grise et les
|
|
1335
|
+
doublons de rôle.
|
|
1336
|
+
|
|
1337
|
+
La réparation est la partie instructive : **quatre des treize n'ont demandé aucun jeton neuf**,
|
|
1338
|
+
`bg-brand-secondary` et ses trois voisins portant déjà exactement le palier 100 de leur rampe. Le
|
|
1339
|
+
navy était un piège — le seul rôle qui porte `navy-30` est `border-secondary`, un rôle de
|
|
1340
|
+
BORDURE, et l'employer pour peindre un aplat aurait été la confusion même que la seconde
|
|
1341
|
+
vérification existe pour empêcher. Les neuf autres ont pris un jeton de composant.
|
|
1342
|
+
|
|
1343
|
+
`verify:tokens` porte désormais un **troisième contrôle**, avec son témoin : il échoue si un
|
|
1344
|
+
composant cite un calque 1 ou 2.
|
|
1345
|
+
|
|
1346
|
+
- **La liste de navigation à droite des pages de doc** (2026-09-10), par `parameters.docs.toc`.
|
|
1347
|
+
⚠️ Son `headingSelector` n'est pas un détail : Storybook ne liste que les `h3` par défaut, et sur
|
|
1348
|
+
une page dont les chapitres sont en `h1` et les sections en `h2`, la liste s'affichait avec UNE
|
|
1349
|
+
entrée — elle avait l'air de marcher. ⚠️ Elle est **globale**, et pas par choix : le conteneur de
|
|
1350
|
+
doc de Storybook 8.6 ne lit `toc` que dans les paramètres du PROJET, un `<Meta parameters>` par
|
|
1351
|
+
page n'activant rien — vérifié dans le navigateur sur trois pages. Demandée pour les badges et
|
|
1352
|
+
les boutons, elle est donc posée sur les quinze pages.
|
|
1353
|
+
|
|
1354
|
+
- ⚠️ **LES QUATRE PIÈCES DU BADGE NE FONT QU'UNE COULEUR — le palier 600 — et seul le LIBELLÉ est
|
|
1355
|
+
au 700** (2026-09-10). Relevé sur quatre symboles de trois habillages : chacun ne cite que deux
|
|
1356
|
+
valeurs de couleur, `Zest/200` pour sa pièce et `Zest/300` pour son libellé.
|
|
1357
|
+
|
|
1358
|
+
Un premier jet peignait les pièces en `currentColor`, donc à la couleur du libellé : un cran trop
|
|
1359
|
+
sombre partout, et sur un `modern` carrément navy — **treize badges identiques là où la maquette
|
|
1360
|
+
en dessine treize colorés**. Le typage, les 44 tests et la sonde de géométrie passaient tous : le
|
|
1361
|
+
badge se rendait parfaitement. C'est la planche des treize couleurs, dessinée en restructurant la
|
|
1362
|
+
page, qui l'a montré. `verify:badges` compare désormais chaque icône et chaque croix à la teinte
|
|
1363
|
+
MESURÉE du point de sa couleur — 126 comparaisons — pour que ça ne revienne pas.
|
|
1364
|
+
|
|
1365
|
+
C'est aussi ce qui a corrigé une lecture fausse des 108 symboles absents du cadre. Ils sont tous
|
|
1366
|
+
des `Badge modern` dans les douze couleurs autres que Gray, mais **seuls 36 sont légitimes** —
|
|
1367
|
+
ceux sans aucune pièce, qui n'ont rien à colorer. Les 72 autres, `X close` et `Icon trailing`,
|
|
1368
|
+
sont un TROU de la maquette : leur unique spécimen Gray peint bien sa pièce en `Couleurs/Gris/200`.
|
|
1369
|
+
**À dessiner dans le Figma.**
|
|
1370
|
+
|
|
1371
|
+
- **Le badge nomme ses couleurs avec les mots du THÈME, pas ceux du Figma** (2026-09-10).
|
|
1372
|
+
`horizon`, `lime`, `yellow` et non `Bleu horizon`, `Vert tilleul`, `Jaune` : le thème les
|
|
1373
|
+
déclare ainsi depuis le portage, et traduire à chaque aller-retour entre une classe CSS et un
|
|
1374
|
+
jeton coûterait plus que ça ne rapporte. La page « Badges » affiche les deux vocabulaires côte à
|
|
1375
|
+
côte, et c'est le seul endroit où la correspondance a besoin d'être visible.
|
|
1376
|
+
|
|
1377
|
+
- **Les quatre emplacements du badge sont des propriétés INDÉPENDANTES**, là où le Figma les range
|
|
1378
|
+
sur un axe unique et donc exclusif (2026-09-10). C'est l'inverse du choix fait sur `Button`,
|
|
1379
|
+
dont les onze hiérarchies sont une liste plate, et la différence est réelle : un jeu de
|
|
1380
|
+
variantes Figma ne sait pas exprimer « deux emplacements optionnels » sans multiplier les
|
|
1381
|
+
variantes par quatre. L'exclusivité est une contrainte de l'OUTIL, pas une règle du produit — et
|
|
1382
|
+
un badge qui porte à la fois un point d'état et une croix de retrait est une pièce courante.
|
|
1383
|
+
Rien n'est inventé au passage : chaque emplacement porte sa géométrie relevée.
|
|
1384
|
+
|
|
1385
|
+
⚠️ Deux cas que le Figma ne dessine pas ont dû être tranchés ici : quand un point ET une icône
|
|
1386
|
+
de tête sont présents, le padding suit le POINT, qui est la pièce la plus au bord ; quand une
|
|
1387
|
+
icône de fin ET une croix sont présentes, il suit la CROIX. Ce sont des choix, et deux tests les
|
|
1388
|
+
fixent.
|
|
1389
|
+
|
|
1390
|
+
- **L'anneau de focus de la croix du badge est un AJOUT** (2026-09-10). Le cadre `_Badge close X`
|
|
1391
|
+
ne dessine que `Default` et `Hover`. Une commande qu'on ne voit pas quand on l'atteint au
|
|
1392
|
+
clavier ne s'emploie pas sans souris : l'anneau reprend la recette du `CloseButton`, à l'octet.
|
|
1393
|
+
À répercuter dans le Figma.
|
|
1394
|
+
|
|
1395
|
+
- ⚠️ **Un symbole du `_Badge close X` est MAL ÉTIQUETÉ** (2026-09-10). La variante `Color=Orange`
|
|
1396
|
+
peint `Couleurs/Rose/200` (#dd2590) : c'est du ROSE. Aucun symbole n'y porte l'étiquette `Rose`,
|
|
1397
|
+
et `Color=Warning` peint bien l'orange. C'est l'étiquette qui est fausse, pas le dessin — le
|
|
1398
|
+
même piège que les cinq codes de drapeau. Le code nomme cette couleur `rose`. **Le Figma reste à
|
|
1399
|
+
corriger.**
|
|
1400
|
+
|
|
1401
|
+
- **Cinq fonds de badge citent un RÔLE et non un jeton de composant** (2026-09-10), et c'est
|
|
1402
|
+
`verify:tokens` qui l'a établi plutôt qu'une relecture : `bg-brand-primary`, `bg-error-primary`,
|
|
1403
|
+
`bg-warning-primary`, `bg-success-primary` et `bg-primary` portent exactement les valeurs que le
|
|
1404
|
+
premier jet allait redéclarer. Les rôles `bg-*-primary` sont les paliers 50 des rampes, donc
|
|
1405
|
+
exactement le fond doux que le badge peint. Le message du contrôle laisse entendre que les fonds
|
|
1406
|
+
sont dispensés : la dispense ne vaut que là où AUCUN rôle ne nomme la valeur, ce qui est le cas
|
|
1407
|
+
des huit couleurs utilitaires.
|
|
1408
|
+
|
|
1409
|
+
- ⚠️ **Les bordures des boutons restent celles du Figma, sous les 3:1, et c'est un compromis
|
|
1410
|
+
ASSUMÉ** (2026-09-09). `border-primary` (navy-40, `#D3D7DE`) pour les neutres,
|
|
1411
|
+
`border-error-subtle` (error-300) pour le destructif. Mesuré en navigateur, le trait PEINT — donc
|
|
1412
|
+
composé sous le contour de 18 % du relief — tient **2,17:1** et **2,87:1** sur du blanc, contre
|
|
1413
|
+
les 3:1 que la WCAG 1.4.11 demande à ce qui délimite une commande. Et l'aplat ne rattrape rien :
|
|
1414
|
+
navy-20 sur blanc fait 1,11:1.
|
|
1415
|
+
|
|
1416
|
+
Un premier jet avait remonté ces bordures à `navy-70` (3,67:1) et `border-error` (3,76:1), qui
|
|
1417
|
+
tiennent le seuil ; l'équipe produit a préféré la **fidélité au Figma**, le dessin s'alourdissant
|
|
1418
|
+
visiblement. Le libellé tient 11,82:1 : le bouton reste identifiable, c'est sa LIMITE qui ne
|
|
1419
|
+
l'est pas.
|
|
1420
|
+
|
|
1421
|
+
⚠️ La page « Boutons » continue de mesurer et d'afficher ces trois valeurs **en rouge**. Un
|
|
1422
|
+
compromis assumé se documente, il ne se cache pas — et si on revient dessus un jour, les deux
|
|
1423
|
+
paliers qui tiennent le seuil sont écrits ci-dessus.
|
|
1424
|
+
- **Le relief skéuomorphique est COMPLET sur toutes les pièces** (2026-09-09), contour de 1 px
|
|
1425
|
+
compris, et il est peint PAR-DESSUS la bordure — l'ordre du Figma, qui pose son style d'effet sur
|
|
1426
|
+
un calque au-dessus du cadre. Conséquence à connaître : sur une pièce encadrée, la bordure peinte
|
|
1427
|
+
n'est pas la bordure déclarée. navy-40 sous 18 % de noir donne `#ADB0B6`. C'est pour ça que la
|
|
1428
|
+
planche de contraste lit le `box-shadow` CALCULÉ et compose ses couches, au lieu de lire le
|
|
1429
|
+
jeton.
|
|
1430
|
+
- **Le biseau des aplats est un DÉGRADÉ, pas un liseré plat** (2026-09-09). Le liseré clair d'un
|
|
1431
|
+
bouton plein s'allume en haut et s'éteint en bas : il simule une lumière venant du dessus. Il est
|
|
1432
|
+
posé en pseudo-élément masqué — un `border` CSS ne porte pas de dégradé, et une vraie bordure de
|
|
1433
|
+
2 px ferait passer un `md` de 40 à 44 px.
|
|
1434
|
+
|
|
1435
|
+
⚠️ **Les deux bornes du dégradé sont À CONFIRMER.** Le MCP Figma rapporte ce contour comme PLAT
|
|
1436
|
+
(`rgba(255,255,255,0.12)`) sur deux lectures, `forceCode` compris, et `get_metadata` ne montre
|
|
1437
|
+
aucun calque de dégradé : l'outil l'aplatit, ou il l'est. La borne haute vient de cette valeur
|
|
1438
|
+
relevée ; l'extinction complète en bas est la recette standard, pas un relevé. Les jetons
|
|
1439
|
+
`--zds-color-button-bevel-from` et `-to` isolent les deux valeurs à corriger.
|
|
1440
|
+
- **Les composants ne citent que les couleurs de Zest, et c'est contrôlé** (2026-09-09).
|
|
1441
|
+
`yarn verify:tokens` résout chaque jeton cité par une feuille de composant jusqu'à sa valeur et
|
|
1442
|
+
échoue si l'un aboutit dans la rampe `gray-*` que Zest laisse de côté. Il porte un témoin —
|
|
1443
|
+
`bg-secondary`, qui doit être détecté — et refuse de conclure si le témoin ne mord pas. Vert sur
|
|
1444
|
+
les quatre composants, 90 citations résolues.
|
|
1445
|
+
- ⚠️ **Le Primary descend d'un palier par rapport au Figma** (2026-09-09). Le Figma peint le
|
|
1446
|
+
Primary AU REPOS en `Bleu/100` — notre `brand-500`, `#4481FF`. Mesuré, du blanc dessus tient
|
|
1447
|
+
**3,60:1**, sous le seuil AA de 4,5, et son propre survol tient 4,54 : le bouton était donc plus
|
|
1448
|
+
lisible au survol qu'au repos. Chaque état descend d'un palier — repos sur `bg-brand-solid`
|
|
1449
|
+
(600, 4,54:1), survol sur `bg-brand-solid-hover` (700, 6,08:1). Ce n'est pas seulement une
|
|
1450
|
+
correction d'accessibilité : **le destructif était DÉJÀ sur le palier 600 au repos**, donc le
|
|
1451
|
+
Figma se contredisait entre ses deux familles et le décalage les aligne. ⚠️ **À répercuter dans
|
|
1452
|
+
le Figma.**
|
|
1453
|
+
- **« Destructif » est une liste plate de onze valeurs, pas un drapeau** (2026-09-09). La famille
|
|
1454
|
+
destructive du Figma ne reprend que quatre des sept hiérarchies : il n'existe ni
|
|
1455
|
+
`secondary-white` destructif, ni `tertiary-gray` destructif. Un booléen `destructive` rendrait
|
|
1456
|
+
exprimables quatre combinaisons que personne n'a dessinées, et le composant devrait inventer
|
|
1457
|
+
quoi peindre. Une union plate laisse le typage refuser.
|
|
1458
|
+
- **Le chargement n'est pas un `disabled`** (2026-09-09). Un `disabled` sort le bouton de l'ordre
|
|
1459
|
+
de tabulation : le focus est perdu à l'instant où l'on presse « Envoyer » et retombe sur le
|
|
1460
|
+
`body`, en haut du document. Le composant pose `aria-disabled`, qui annonce l'indisponibilité
|
|
1461
|
+
sans retirer la pièce, et bloque l'activation en avalant le clic — Entrée et Espace passent par
|
|
1462
|
+
le même garde, puisque les deux déclenchent un clic.
|
|
1463
|
+
- **La bordure du `UtilityButton` cite le jeton de Zest, pas celui du Figma** (2026-09-09). Le
|
|
1464
|
+
Figma la peint `#D4D4D4`, en dur dans l'état par défaut et liée à `Colors/Border/` — la
|
|
1465
|
+
collection anglaise résiduelle, antérieure au calque sémantique de Zest — au survol. Zest, c'est
|
|
1466
|
+
`Couleurs/Bordure/border-primary`, `#D3D7DE`, et c'est bien ce que le `Button` principal
|
|
1467
|
+
emploie. Mesuré, l'écart est de 1,48:1 contre 1,44:1 : l'œil ne le voit pas, c'est le
|
|
1468
|
+
vocabulaire qui est en jeu. Même piège que les icônes de fichier. ⚠️ **À corriger dans le
|
|
1469
|
+
Figma.**
|
|
1470
|
+
|
|
363
1471
|
- **Le logo porte ses couleurs EN DUR, et il est à la racine** (2026-09-08). Elles correspondent
|
|
364
1472
|
pourtant exactement à deux jetons — mesuré, `#00D85D` = `--zds-color-mark` et `#21304E` =
|
|
365
1473
|
`--zds-color-navy-100`, ΔE 0,0 tous les deux. Les écrire en `var(--zds-…)` serait une faute :
|