origam 2.18.7 → 2.18.9
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/CHANGELOG.md +540 -364
- package/dist/src/assets/css/main.css +1 -1
- package/dist/src/assets/css/tokens/dark.css +7 -2
- package/dist/src/assets/css/tokens/light.css +6 -1
- package/dist/src/assets/scss/tokens/_dark.scss +7 -2
- package/dist/src/assets/scss/tokens/_light.scss +6 -1
- package/dist/src/components/Btn/OrigamBtn.vue +2 -5
- package/dist/src/components/Chart/OrigamChartMap.vue +4 -4
- package/dist/src/components/Code/OrigamCode.vue +2 -2
- package/dist/src/components/Overlay/OrigamOverlay.vue +1 -0
- package/dist/src/consts/Code/code.const.cjs +2 -2
- package/dist/src/consts/Code/code.const.d.ts +22 -5
- package/dist/src/consts/Code/code.const.js +2 -2
- package/dist/src/interfaces/Chart/chart-map.interface.d.ts +16 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -18,6 +18,170 @@ This project follows [Semantic Versioning](https://semver.org).
|
|
|
18
18
|
|
|
19
19
|
## [Unreleased]
|
|
20
20
|
|
|
21
|
+
## [2.18.8] - 2026-09-23
|
|
22
|
+
|
|
23
|
+
### Fixed — #901 `OrigamBtn` — `calc(auto + 0px)` ramenait `min-width` à `0` sur tous les boutons
|
|
24
|
+
|
|
25
|
+
`OrigamBtn.vue`, second bloc `<style scoped>`, déclarait sans condition sur
|
|
26
|
+
`.origam-btn` `--origam-btn---min-width: calc(var(--origam-btn---width, 36px)
|
|
27
|
+
+ var(--origam-btn---density, 0px))`. La feuille (`light.css`/`dark.css`)
|
|
28
|
+
déclare `--origam-btn---width: auto`, donc le repli `36px` n'était jamais
|
|
29
|
+
atteint et la valeur devenait `calc(auto + 0px)` — invalide au moment de la
|
|
30
|
+
substitution dans `min-width` (ligne 563), pas au parse : la propriété
|
|
31
|
+
retombait sur sa valeur initiale (`auto` → `0` hors flex), jamais sur le
|
|
32
|
+
repli `64px`. Même spécificité `(0,2,0)` que les modificateurs `&--size-*`,
|
|
33
|
+
mais déclaré APRÈS eux : les 5 échelons de `size` et `&--icon` étaient donc
|
|
34
|
+
tous écrasés — famille de la garde 29 `unitless-zero-in-calc` / #607.
|
|
35
|
+
|
|
36
|
+
Mesuré en navigateur réel (Playwright + Histoire statique, chromium) :
|
|
37
|
+
|
|
38
|
+
| | avant | après |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `size=x-small` | `0px` | `36px` |
|
|
41
|
+
| `size=small` | `0px` | `50px` |
|
|
42
|
+
| `size=default` | `0px` | `64px` |
|
|
43
|
+
| `size=large` | `0px` | `78px` |
|
|
44
|
+
| `size=x-large` | `0px` | `92px` |
|
|
45
|
+
| `density=comfortable` (size=default) | `0px` | `72px` |
|
|
46
|
+
| `icon=true` | `28px` (dépendait de `--origam-btn---height` résolue, pas de 0 voulu) | `0px` |
|
|
47
|
+
|
|
48
|
+
Correctif : `min-width` (l.563) lit désormais directement
|
|
49
|
+
`--origam-btn---min-width` (repli `64px`) plutôt que `--origam-btn---width`,
|
|
50
|
+
et le second bloc `<style scoped>` ne réécrit plus ce canal (ni
|
|
51
|
+
`--origam-btn---min-height`, strictement identique au repli déjà présent
|
|
52
|
+
l.566 et jamais déclaré par aucune feuille — retrait vérifié sans effet).
|
|
53
|
+
|
|
54
|
+
⛔ **Corollaire découvert en réparant** : le nouveau `calc(var(--origam-
|
|
55
|
+
btn---min-width, 64px) + var(--origam-btn---density, 0px))` fait
|
|
56
|
+
maintenant participer `--origam-btn---min-width` à une addition — et
|
|
57
|
+
`&--icon` le posait à `0` NU (`<number>`, pas `<length>`), le même défaut
|
|
58
|
+
que celui réparé ici. `OrigamCode.vue` déclarait le même canal en `0` nu
|
|
59
|
+
pour son bouton de copie compact (`.origam-code__copy`,
|
|
60
|
+
`.origam-code__copy--compact`). Les trois déclarations passent à `0px` —
|
|
61
|
+
changement sémantiquement neutre (`0` == `0px` en CSS), guard
|
|
62
|
+
`unitless-zero-in-calc` self-testé vert. `token-var-channels` gagne 1 entrée
|
|
63
|
+
« canal mort connu » pour `--origam-btn---min-height` (jamais alimenté par
|
|
64
|
+
le pipeline de tokens, extension locale volontaire — baseline mise à jour).
|
|
65
|
+
|
|
66
|
+
**VRT** : mesuré (pas supposé) via `pnpm -F @origam/tests test:vrt:docker`
|
|
67
|
+
(image `mcr.microsoft.com/playwright:v1.59.1-jammy` pinnée, seule verdict
|
|
68
|
+
valable — cf. `vrt/VRT.md`) — `vrt/btn-variant.spec.ts`, 7/7 verts, **aucune
|
|
69
|
+
capture ne bouge**. Les 7 libellés de la matrice (`Text` … `Outlined`, 4 à
|
|
70
|
+
8 caractères) dépassent déjà le plancher `size=small` (`50px`) une fois le
|
|
71
|
+
padding `12px`×2 ajouté, donc le nouveau plancher ne change la largeur
|
|
72
|
+
d'aucun bouton de ce pilote. Aucune baseline à régénérer dans cette PR.
|
|
73
|
+
|
|
74
|
+
### Fixed — #411 : `OrigamChartMap` faisait **disparaître** contours et pays sous un thème de marque
|
|
75
|
+
|
|
76
|
+
Ce n'est pas « la couleur ne suit pas le thème ». `borderColor` **était** une
|
|
77
|
+
prop déclarée, donc le résolveur d'ADR-005 l'atteignait déjà : un thème
|
|
78
|
+
nommant `components['origam-chart-map'].borderColor` posait bien sa valeur.
|
|
79
|
+
Le défaut est en aval — la valeur partait **verbatim dans le `stroke` inline
|
|
80
|
+
du SVG, sans passer par `resolveColor()`**, contrairement à sa voisine
|
|
81
|
+
`lineColor` qui y passait déjà.
|
|
82
|
+
|
|
83
|
+
Or un intent comme `'success'` **n'est pas du CSS valide pour `stroke`** : le
|
|
84
|
+
navigateur ne repeint pas en gris, il **jette la déclaration entière**. Une
|
|
85
|
+
marque nommant cette prop ne recevait donc pas un contour mal thémé — elle
|
|
86
|
+
n'avait **plus de contours de pays du tout**.
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
- :style="{ fill: country.fill, stroke: borderColor }"
|
|
90
|
+
+ :style="{ fill: country.fill, stroke: resolveColor(borderColor) }"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Le jumeau, trouvé en réparant et livré dans la même PR** :
|
|
94
|
+
`defaultCountryFill` portait le défaut identique une ligne plus bas
|
|
95
|
+
(`fill = props.defaultCountryFill` sans `resolveColor()`, typé `string` nu
|
|
96
|
+
face au `TIntent | string` de `lineColor`) — donc les pays **absents du jeu
|
|
97
|
+
de données** disparaissaient de la même façon. Vérifié dans le code avant de
|
|
98
|
+
le traiter, pas déduit par symétrie.
|
|
99
|
+
|
|
100
|
+
Les deux props sont retypées `TIntent | string` et passent par
|
|
101
|
+
`resolveColor()`, qui laisse traverser les littéraux CSS.
|
|
102
|
+
|
|
103
|
+
⚠️ **Le défaut de `defaultCountryFill` reste le littéral
|
|
104
|
+
`rgba(0,0,0,0.08)`, délibérément.** `resolveColor()` ne rend qu'une couleur
|
|
105
|
+
**opaque fixe**, là où ce littéral est un **voile semi-transparent composité
|
|
106
|
+
sur le `bgColor` que le graphique peint lui-même** : il s'adapte donc au
|
|
107
|
+
clair, au sombre et à un `bgColor` personnalisé. Aucun intent ne reproduit
|
|
108
|
+
ça — le retyper « pour la symétrie » aurait échangé un comportement
|
|
109
|
+
adaptatif contre un comportement figé. Consigné dans le JSDoc de
|
|
110
|
+
`IChartMapProps` et dans la table de la doc. Le défaut de `borderColor`,
|
|
111
|
+
lui, passe de `rgba(0,0,0,0.2)` à l'intent `'neutral'`.
|
|
112
|
+
|
|
113
|
+
⚠️ **Le ticket était périmé aux deux tiers**, revérifié avant d'écrire une
|
|
114
|
+
ligne : des trois composants qu'il nomme, `OrigamSelect` était déjà réparé
|
|
115
|
+
par `331d9b62` (#456) et `OrigamDatePickerField` par `374858be5` — lequel
|
|
116
|
+
citait déjà #411 sans le fermer. Son périmètre à 3 était en revanche exact :
|
|
117
|
+
grep des littéraux cités, aucune 4ᵉ occurrence dans le DS.
|
|
118
|
+
|
|
119
|
+
A/B contre le commit parent, en Vitest (chaîne `style` littérale) **et** en
|
|
120
|
+
Chromium réel (`getComputedStyle`) : `borderColor` stable **10/10** ;
|
|
121
|
+
`defaultCountryFill` **2/4 rouge avant, 4/4 vert après** en unitaire, rouge
|
|
122
|
+
puis vert en navigateur, stable 10/10 sous `--repeat-each=5`. Story, doc,
|
|
123
|
+
2 specs TU et 2 specs e2e (ajoutées à `GREEN_SPECS`).
|
|
124
|
+
|
|
125
|
+
### Fixed — #535 : le contraste syntaxique de `OrigamCode` était sous AA, deux fois plus bas que le ticket ne le disait
|
|
126
|
+
|
|
127
|
+
⚠️ **Le `4,27:1` du ticket ne se reproduit plus** — `HomeHero` a migré vers
|
|
128
|
+
un extrait `bash` qui ne touche que 2 des 8 catégories shiki, toutes deux
|
|
129
|
+
déjà conformes. Le défaut sous-jacent, lui, est réel et bien plus large.
|
|
130
|
+
|
|
131
|
+
Remesuré sur **8 catégories shiki** (mots-clés, ponctuation, chaînes,
|
|
132
|
+
commentaires, nombres/variables, fonctions, paramètres, balises) × **8 fonds**
|
|
133
|
+
(DS par défaut + 7 thèmes de marque) × **2 modes**, depuis les valeurs hex
|
|
134
|
+
littérales réelles (shiki 4.3.1, `*.theme.ts`) :
|
|
135
|
+
|
|
136
|
+
| | avant | thème shiki seul | **livré** |
|
|
137
|
+
|---|---|---|---|
|
|
138
|
+
| clair, pire cas | **2,93:1** *(paramètre, `geek`)* | 4,23:1 | **4,77:1** *(commentaire, `glass`)* |
|
|
139
|
+
| sombre, pire cas | **2,55:1** *(commentaire, `material`)* | 5,79:1 | **6,77:1** *(mot-clé, `material`)* |
|
|
140
|
+
|
|
141
|
+
**Le pire cas réel était à 2,55:1 : le ticket sous-estimait son propre défaut
|
|
142
|
+
d'un facteur deux.**
|
|
143
|
+
|
|
144
|
+
**D'où vient la couleur, établi et non supposé.** Shiki peint chaque token via
|
|
145
|
+
`--shiki-light` / `--shiki-dark` **inline sur chaque `<span>`**, depuis deux
|
|
146
|
+
thèmes figés déclarés dans `consts/Code/code.const.ts`. **Aucun token
|
|
147
|
+
`--origam-code---syntax-*` par catégorie n'existe** — déjà établi par #399 /
|
|
148
|
+
#661, reconfirmé en relisant le code. La fausse piste signalée dans le ticket
|
|
149
|
+
tient toujours : `--origam-color__feedback--success---fgSubtle` (touché par
|
|
150
|
+
#524) alimente bien `--origam-code__syntax---string`, mais **ce n'est pas ce
|
|
151
|
+
que shiki peint**.
|
|
152
|
+
|
|
153
|
+
**Aucun token créé, et l'arbitrage a été évité plutôt que contourné.** La
|
|
154
|
+
question « faut-il des tokens de syntaxe par catégorie ? » était posée comme
|
|
155
|
+
point d'arrêt ; le calcul a montré qu'aucune décision d'architecture n'était
|
|
156
|
+
nécessaire :
|
|
157
|
+
|
|
158
|
+
1. `CODE_LIGHT_THEME` / `CODE_DARK_THEME` → `github-light-high-contrast` /
|
|
159
|
+
`github-dark-high-contrast` — **mêmes paquets shiki, coût de bundle
|
|
160
|
+
inchangé**.
|
|
161
|
+
2. `--origam-code---background-color` : `surface---sunken` →
|
|
162
|
+
`surface---raised`, **un token sémantique qui existe déjà par thème**.
|
|
163
|
+
|
|
164
|
+
Le thème shiki seul ne suffisait pas (4,23:1 en clair) : **il fallait les
|
|
165
|
+
deux**.
|
|
166
|
+
|
|
167
|
+
Nouveau `describe` `Syntax contrast (#535)` dans `code.spec.ts`,
|
|
168
|
+
`getComputedStyle` réel sur chaque couleur shiki distincte, clair + sombre —
|
|
169
|
+
**3/3 vert**.
|
|
170
|
+
|
|
171
|
+
**Non vérifié** : les 7 thèmes de marque **via Playwright contre le site
|
|
172
|
+
marketing lui-même** — calcul déterministe sur les valeurs source à la place,
|
|
173
|
+
le mécanisme CSS étant, lui, vérifié en navigateur réel. VitePress a son
|
|
174
|
+
propre pipeline shiki indépendant, hors périmètre. Le seed marketing
|
|
175
|
+
(`server/db/seed/const.json`) garde une copie figée des anciens noms de
|
|
176
|
+
thème : signalé, **non resynchronisé**, ça demande un re-sync de base séparé.
|
|
177
|
+
|
|
178
|
+
**Trouvaille annexe** : le `#29` cité dans les commentaires « bugs DS
|
|
179
|
+
connus » de `code.spec.ts` ne correspond à aucun ticket — `gh issue view 29`
|
|
180
|
+
est une PR dependabot sans rapport. Corrigé dans le commentaire. Même motif
|
|
181
|
+
que le `#46` qui a circulé des mois dans la doc de ce dépôt.
|
|
182
|
+
|
|
183
|
+
## [2.18.7] - 2026-09-23
|
|
184
|
+
|
|
21
185
|
### Fixed — #607 / #569 : 19 canaux de thème confisqués par le bloc du composant
|
|
22
186
|
|
|
23
187
|
Un composant qui redéclare un token que les feuilles déclarent déjà rend ce
|
|
@@ -156,6 +320,8 @@ sont **compositées** sur le `default` de leur propre thème, avec l'opération
|
|
|
156
320
|
décimales (composite 0.9757 contre pixel rendu 0.9754). Vérifiée ROUGE sur les
|
|
157
321
|
valeurs du commit parent, une fois par marque : `geek/light` puis `glass/light`.
|
|
158
322
|
|
|
323
|
+
## [2.18.6] - 2026-09-23
|
|
324
|
+
|
|
159
325
|
### Fixed — #818 baseline shrink : les 8 `color-contrast` du DS (8 → 0)
|
|
160
326
|
|
|
161
327
|
⚠️ **Ce lot porte sur le DS lui-même, pas sur une palette marketing** : il
|
|
@@ -294,76 +460,7 @@ d'intention) rejouée après le lot : **226 passed, 0 failed**. Suite unitaire
|
|
|
294
460
|
complète : **7149 passed**. `pnpm -F origam guards` 28/28, `guards:self`
|
|
295
461
|
15/15, `type-check` et `pnpm audit` propres.
|
|
296
462
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
Recompté sur `a11y-violations.baseline.json` (pas repris d'un chiffre cité
|
|
300
|
-
ailleurs) : la baseline #818 portait **25 clés / 33 violations** sur 24
|
|
301
|
-
composants, dont **12 `aria-allowed-attr`** concentrées sur la famille
|
|
302
|
-
`OrigamDataTable*`. Cause commune, pas 12 défauts distincts :
|
|
303
|
-
`OrigamTextField` ne posait pas `inheritAttrs: false` alors qu'il
|
|
304
|
-
redistribue déjà explicitement chaque attr de fall-through
|
|
305
|
-
(`filterInputAttrs` → `rootAttrs` sur `<origam-input>`, `inputAttrs` sur le
|
|
306
|
-
vrai `<input>`). Sans ce flag, Vue appliquait EN PLUS le `$attrs` brut sur
|
|
307
|
-
la racine `<origam-input>`, qui ne s'y soustrayait pas non plus — doublant
|
|
308
|
-
`aria-haspopup`/`aria-expanded`/`aria-controls`/`aria-valuenow`/… sur le
|
|
309
|
-
`<div>` wrapper, qui ne porte aucun rôle les autorisant. `role` (prop
|
|
310
|
-
déclarée sur `OrigamTextField`) n'atteignait par ailleurs que
|
|
311
|
-
`<origam-field>`, jamais le vrai `<input>` — c'est ce défaut exact que le
|
|
312
|
-
commentaire `KNOWN_FAILURES` documentait déjà pour `OrigamSelect` (test
|
|
313
|
-
`fixme`).
|
|
314
|
-
|
|
315
|
-
**Correctif à la source** (`packages/ds/src/components/TextField/OrigamTextField.vue`) :
|
|
316
|
-
`defineOptions({ inheritAttrs: false })` + `role` désormais aussi lié sur le
|
|
317
|
-
`<input>` réel. Élimine, mesuré axe-core en navigateur réel (Playwright +
|
|
318
|
-
Histoire statique) :
|
|
319
|
-
- `OrigamSelect` — sort de `KNOWN_FAILURES` (`components.spec.ts`), test
|
|
320
|
-
`fixme` → vert.
|
|
321
|
-
- `OrigamDataTable`, `OrigamDataTableFooter`, `OrigamDataTableHeaderCell`,
|
|
322
|
-
`OrigamDataTableHeaders`, `OrigamDataTableHeadersCell`,
|
|
323
|
-
`OrigamDataTableRow` — `aria-allowed-attr` disparaît, entrée de baseline
|
|
324
|
-
retirée entièrement.
|
|
325
|
-
- `OrigamDataTableGroupHeaderRow`, `OrigamDataTableRows`, `OrigamNumberField`
|
|
326
|
-
— `aria-allowed-attr` disparaît, l'entrée reste pour leur AUTRE violation
|
|
327
|
-
(`button-name` / `color-contrast`), non touchée par ce lot.
|
|
328
|
-
- `OrigamDataTableHeadersCellMobile` — `aria-allowed-attr` ET
|
|
329
|
-
`aria-prohibited-attr` disparaissent (même fuite, deux règles axe
|
|
330
|
-
différentes), entrée retirée entièrement.
|
|
331
|
-
|
|
332
|
-
**Deuxième cause, distincte, deux composants** —
|
|
333
|
-
`packages/ds/src/components/ColorPickerField/OrigamColorPickerField.vue` et
|
|
334
|
-
`.../DatePickerField/OrigamDatePickerField.vue` posaient un
|
|
335
|
-
`aria-haspopup` avec une valeur inventée (`'colorpickerbox'` /
|
|
336
|
-
`'datepickerbox'`, jamais un token ARIA valide) sur l'élément
|
|
337
|
-
`.origam-field` (via `activator="parent"` d'`OrigamMenu`), sans `role` le
|
|
338
|
-
justifiant. Remplacé par `aria-haspopup: 'dialog'` (motif WAI-ARIA « Date
|
|
339
|
-
Picker Dialog ») + `role: 'combobox'` sur le même élément — même principe
|
|
340
|
-
que `comboboxAriaAttrs` d'`OrigamSelect`. `aria-allowed-attr` ET
|
|
341
|
-
`aria-valid-attr-value` disparaissent pour les deux ; `OrigamColorPickerField`
|
|
342
|
-
est intégralement retiré de la baseline, `OrigamDatePickerField` y reste
|
|
343
|
-
pour son `color-contrast` (non touché).
|
|
344
|
-
|
|
345
|
-
**Bilan mesuré** : baseline #818 25 clés/33 violations → **17 clés/18
|
|
346
|
-
violations**. Suite `pnpm -F @origam/tests test:a11y` complète (226 tests,
|
|
347
|
-
catalogue 218/218) : **226 passed**, aucune régression sur les 36
|
|
348
|
-
composants à baseline vide. Contrôle positif exécuté : réintroduire l'ancien
|
|
349
|
-
comportement fait échouer `a11y — OrigamSelect Default Variant` avec
|
|
350
|
-
`aria-allowed-attr`/`aria-prohibited-attr` NON baselinés — la porte capte
|
|
351
|
-
la régression, pas seulement l'édition du JSON.
|
|
352
|
-
|
|
353
|
-
**Laissé de côté, délibérément** (17 clés / 18 violations restent dans
|
|
354
|
-
`a11y-violations.baseline.json`, cf. #818) : `color-contrast` (8 instances —
|
|
355
|
-
plusieurs agents dédiés au contraste travaillent déjà sur ce périmètre),
|
|
356
|
-
`button-name` (3, boutons icône sans libellé — famille distincte),
|
|
357
|
-
`scrollable-region-focusable` (3), `aria-required-parent`/`aria-required-children`/
|
|
358
|
-
`listitem`/`aria-prohibited-attr` (`OrigamChartMap`, sans lien avec ce
|
|
359
|
-
correctif) — un défaut chacun, cause non partagée avec ce lot, non
|
|
360
|
-
instruit ici.
|
|
361
|
-
|
|
362
|
-
Récolte de deux dépréciations posées "pour la prochaine majeure" avant que le
|
|
363
|
-
`CLAUDE.md` n'acte que `3.0.0` est réservé à la séparation en modules et que
|
|
364
|
-
les ruptures, elles, ne le sont pas — voir "Work priorities and versioning"
|
|
365
|
-
du `CLAUDE.md`. `origam` n'a aucun consommateur : les deux ruptures
|
|
366
|
-
ci-dessous partent en **mineure**, sans shim ni période de grâce.
|
|
463
|
+
## [2.18.5] - 2026-09-23
|
|
367
464
|
|
|
368
465
|
### Fixed — `button-name` et `scrollable-region-focusable` (6 des 18 violations laissées de côté par le lot précédent)
|
|
369
466
|
|
|
@@ -442,172 +539,109 @@ au vert. `pnpm -F origam guards` (28/28), `guards:self` (15/15),
|
|
|
442
539
|
d'autres agents), `aria-required-parent`/`aria-required-children`/`listitem`/
|
|
443
540
|
`aria-prohibited-attr` (un défaut chacun, cause non partagée avec ce lot).
|
|
444
541
|
|
|
445
|
-
|
|
542
|
+
## [2.18.4] - 2026-09-23
|
|
446
543
|
|
|
447
|
-
|
|
448
|
-
type, ni au niveau de l'exécution. `IBtnEmits` n'`extends` plus
|
|
449
|
-
`IAdjacentEmits`, et les `<span>` `origam-btn__prepend` / `__append` ne
|
|
450
|
-
portent plus de `@click` du tout : un clic souris dessus ne déclenche plus
|
|
451
|
-
rien.
|
|
544
|
+
### Fixed — #818 baseline shrink : `aria-allowed-attr`/`aria-prohibited-attr`/`aria-valid-attr-value` (12 des 25 entrées)
|
|
452
545
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
`<
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
546
|
+
Recompté sur `a11y-violations.baseline.json` (pas repris d'un chiffre cité
|
|
547
|
+
ailleurs) : la baseline #818 portait **25 clés / 33 violations** sur 24
|
|
548
|
+
composants, dont **12 `aria-allowed-attr`** concentrées sur la famille
|
|
549
|
+
`OrigamDataTable*`. Cause commune, pas 12 défauts distincts :
|
|
550
|
+
`OrigamTextField` ne posait pas `inheritAttrs: false` alors qu'il
|
|
551
|
+
redistribue déjà explicitement chaque attr de fall-through
|
|
552
|
+
(`filterInputAttrs` → `rootAttrs` sur `<origam-input>`, `inputAttrs` sur le
|
|
553
|
+
vrai `<input>`). Sans ce flag, Vue appliquait EN PLUS le `$attrs` brut sur
|
|
554
|
+
la racine `<origam-input>`, qui ne s'y soustrayait pas non plus — doublant
|
|
555
|
+
`aria-haspopup`/`aria-expanded`/`aria-controls`/`aria-valuenow`/… sur le
|
|
556
|
+
`<div>` wrapper, qui ne porte aucun rôle les autorisant. `role` (prop
|
|
557
|
+
déclarée sur `OrigamTextField`) n'atteignait par ailleurs que
|
|
558
|
+
`<origam-field>`, jamais le vrai `<input>` — c'est ce défaut exact que le
|
|
559
|
+
commentaire `KNOWN_FAILURES` documentait déjà pour `OrigamSelect` (test
|
|
560
|
+
`fixme`).
|
|
466
561
|
|
|
467
|
-
**
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
562
|
+
**Correctif à la source** (`packages/ds/src/components/TextField/OrigamTextField.vue`) :
|
|
563
|
+
`defineOptions({ inheritAttrs: false })` + `role` désormais aussi lié sur le
|
|
564
|
+
`<input>` réel. Élimine, mesuré axe-core en navigateur réel (Playwright +
|
|
565
|
+
Histoire statique) :
|
|
566
|
+
- `OrigamSelect` — sort de `KNOWN_FAILURES` (`components.spec.ts`), test
|
|
567
|
+
`fixme` → vert.
|
|
568
|
+
- `OrigamDataTable`, `OrigamDataTableFooter`, `OrigamDataTableHeaderCell`,
|
|
569
|
+
`OrigamDataTableHeaders`, `OrigamDataTableHeadersCell`,
|
|
570
|
+
`OrigamDataTableRow` — `aria-allowed-attr` disparaît, entrée de baseline
|
|
571
|
+
retirée entièrement.
|
|
572
|
+
- `OrigamDataTableGroupHeaderRow`, `OrigamDataTableRows`, `OrigamNumberField`
|
|
573
|
+
— `aria-allowed-attr` disparaît, l'entrée reste pour leur AUTRE violation
|
|
574
|
+
(`button-name` / `color-contrast`), non touchée par ce lot.
|
|
575
|
+
- `OrigamDataTableHeadersCellMobile` — `aria-allowed-attr` ET
|
|
576
|
+
`aria-prohibited-attr` disparaissent (même fuite, deux règles axe
|
|
577
|
+
différentes), entrée retirée entièrement.
|
|
472
578
|
|
|
473
|
-
**
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
579
|
+
**Deuxième cause, distincte, deux composants** —
|
|
580
|
+
`packages/ds/src/components/ColorPickerField/OrigamColorPickerField.vue` et
|
|
581
|
+
`.../DatePickerField/OrigamDatePickerField.vue` posaient un
|
|
582
|
+
`aria-haspopup` avec une valeur inventée (`'colorpickerbox'` /
|
|
583
|
+
`'datepickerbox'`, jamais un token ARIA valide) sur l'élément
|
|
584
|
+
`.origam-field` (via `activator="parent"` d'`OrigamMenu`), sans `role` le
|
|
585
|
+
justifiant. Remplacé par `aria-haspopup: 'dialog'` (motif WAI-ARIA « Date
|
|
586
|
+
Picker Dialog ») + `role: 'combobox'` sur le même élément — même principe
|
|
587
|
+
que `comboboxAriaAttrs` d'`OrigamSelect`. `aria-allowed-attr` ET
|
|
588
|
+
`aria-valid-attr-value` disparaissent pour les deux ; `OrigamColorPickerField`
|
|
589
|
+
est intégralement retiré de la baseline, `OrigamDatePickerField` y reste
|
|
590
|
+
pour son `color-contrast` (non touché).
|
|
481
591
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
592
|
+
**Bilan mesuré** : baseline #818 25 clés/33 violations → **17 clés/18
|
|
593
|
+
violations**. Suite `pnpm -F @origam/tests test:a11y` complète (226 tests,
|
|
594
|
+
catalogue 218/218) : **226 passed**, aucune régression sur les 36
|
|
595
|
+
composants à baseline vide. Contrôle positif exécuté : réintroduire l'ancien
|
|
596
|
+
comportement fait échouer `a11y — OrigamSelect Default Variant` avec
|
|
597
|
+
`aria-allowed-attr`/`aria-prohibited-attr` NON baselinés — la porte capte
|
|
598
|
+
la régression, pas seulement l'édition du JSON.
|
|
486
599
|
|
|
487
|
-
**
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
600
|
+
**Laissé de côté, délibérément** (17 clés / 18 violations restent dans
|
|
601
|
+
`a11y-violations.baseline.json`, cf. #818) : `color-contrast` (8 instances —
|
|
602
|
+
plusieurs agents dédiés au contraste travaillent déjà sur ce périmètre),
|
|
603
|
+
`button-name` (3, boutons icône sans libellé — famille distincte),
|
|
604
|
+
`scrollable-region-focusable` (3), `aria-required-parent`/`aria-required-children`/
|
|
605
|
+
`listitem`/`aria-prohibited-attr` (`OrigamChartMap`, sans lien avec ce
|
|
606
|
+
correctif) — un défaut chacun, cause non partagée avec ce lot, non
|
|
607
|
+
instruit ici.
|
|
492
608
|
|
|
493
|
-
###
|
|
609
|
+
### Fixed
|
|
494
610
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
retiré : `createOrigam()` installe désormais exactement ce qu'on lui passe,
|
|
502
|
-
rien de plus.
|
|
611
|
+
- **#871 (clôture) — les 7 dernières violations AA étaient UN défaut de
|
|
612
|
+
palette répété, pas sept défauts de composant.** Mesuré avec
|
|
613
|
+
`packages/tests/audit/dark-contrast.audit.mjs` : **7 / 1 664 → 0 / 1 664**,
|
|
614
|
+
les 8 identités × 2 modes × 2 portées, quatre contrôles verts des deux
|
|
615
|
+
côtés. Exactement **7 lignes changent, aucune ne se dégrade**, et le ratio
|
|
616
|
+
minimum de toute la surface passe de 3.65 à **4.70**.
|
|
503
617
|
|
|
504
|
-
|
|
505
|
-
`
|
|
506
|
-
|
|
507
|
-
résoudre — chaque composant retombe uniquement sur ses propres valeurs
|
|
508
|
-
`withDefaults()`. Concrètement : un `<origam-avatar>` sans prop `rounded`
|
|
509
|
-
explicite n'est plus automatiquement circulaire (`rounded="full"` venait du
|
|
510
|
-
thème, pas du composant).
|
|
618
|
+
Les 7 se répartissaient en deux causes, toutes deux dans
|
|
619
|
+
`packages/marketing/src/themes` — **aucune dans le DS**, qui était déjà à
|
|
620
|
+
zéro :
|
|
511
621
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
622
|
+
| cause | marque · mode | couple | avant | après |
|
|
623
|
+
|---|---|---|---|---|
|
|
624
|
+
| encre héritée du mode clair | `apple` sombre | `#ffffff` → `#000000` sur `#0a84ff` | 3.65 | **5.76** |
|
|
625
|
+
| encre héritée du mode clair | `ecom` sombre | `#ffffff` → `#1a0f0a` sur `#f43f5e` | 3.67 | **5.12** |
|
|
626
|
+
| jeton de rôle inversé | `ecom` clair | `action.primary.bg` → `.fgSubtle` sur la crème | 4.43 | **5.93** |
|
|
515
627
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
628
|
+
**La cause commune.** Le mode sombre ÉCLAIRCIT l'accent de marque — c'est
|
|
629
|
+
la bonne pratique pour une grande surface (`#0071e3` → `#0a84ff` chez
|
|
630
|
+
`apple`, rose-600 → rose-500 chez `ecom`) — mais les deux palettes gardaient
|
|
631
|
+
l'encre `#ffffff` de leur jumeau clair. Or chacune applique **déjà** la règle
|
|
632
|
+
inverse à ses intentions `feedback` : les 4 d'`ecom` et 3 des 4 d'`apple`
|
|
633
|
+
encrent leur accent éclairci avec le `text.inverse` de la palette.
|
|
634
|
+
`action.primary` était la dernière exception. Le badge n'était pas en cause :
|
|
635
|
+
`--origam-badge__badge---{background-color,color}` lit exactement ce couple —
|
|
636
|
+
tout comme `--origam-btn--primary---*`, qui n'est pas dans la sonde et était
|
|
637
|
+
donc en défaut sans être mesuré.
|
|
520
638
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
**Rayon de souffle mesuré, corrigé dans le même lot** — quatre consommateurs
|
|
528
|
-
directs de `createOrigam()` nu trouvés par balayage exhaustif (DS, marketing,
|
|
529
|
-
stories, docs, tests) :
|
|
530
|
-
- `packages/ds/src/nuxt/module.ts` — le module Nuxt officiel. **Non cassé** :
|
|
531
|
-
son propre `DEFAULT_THEMES` (utilisé quand l'option `origam.themes` du
|
|
532
|
-
consommateur est omise) passe désormais `origamTheme` explicitement à
|
|
533
|
-
`createOrigam()`, préservant à l'identique le comportement de tout
|
|
534
|
-
consommateur Nuxt existant (marketing compris) qui ne configurait rien.
|
|
535
|
-
Seul un `createOrigam()` direct, hors module Nuxt, doit s'adapter.
|
|
536
|
-
- `packages/marketing/nuxt.config.ts` — configure `origam.themes`
|
|
537
|
-
explicitement (7 thèmes de marque + un thème `origam` renommé pour le
|
|
538
|
-
playground `/theming`), ce qui **contourne** le fallback du module. Le vrai
|
|
539
|
-
thème neutre non-nommé (celui que `activeDefaultsFor` fusionne toujours en
|
|
540
|
-
premier, avant la marque active) était fourni jusqu'ici par le préfixage
|
|
541
|
-
implicite de `createOrigam()` — invisible dans la config marketing. Il est
|
|
542
|
-
désormais listé explicitement, en premier, dans le tableau `themes`.
|
|
543
|
-
- `packages/stories/histoire.setup.ts` — Histoire (utilisé par les ~208
|
|
544
|
-
stories de composants) appelait `createOrigam()` nu ; sans correction,
|
|
545
|
-
chaque story aurait silencieusement perdu les props par défaut du thème
|
|
546
|
-
(avatars carrés au lieu de circulaires, etc.). Passe désormais
|
|
547
|
-
`{ themes: origamTheme }`.
|
|
548
|
-
- `packages/docs/.vitepress/theme/index.ts` — les démos de composants live de
|
|
549
|
-
la doc VitePress appelaient `createOrigam()` nu ; même correction.
|
|
550
|
-
|
|
551
|
-
Les échantillons de code montrés au consommateur (`installation.const.ts` /
|
|
552
|
-
`installation.vue` sur le marketing, `guide/usage.md` côté docs) sont mis à
|
|
553
|
-
jour pour montrer la forme correcte — un utilisateur copiant l'ancien
|
|
554
|
-
exemple aurait obtenu des composants non stylés selon le thème.
|
|
555
|
-
|
|
556
|
-
**Tests adaptés** (comptés avant correction, comme demandé) — 3 fichiers /
|
|
557
|
-
5 assertions reposaient sur l'enregistrement implicite et ont été corrigés
|
|
558
|
-
pour installer `origamTheme` explicitement là où le test vérifie précisément
|
|
559
|
-
une valeur par défaut issue du thème, ou réécrits pour pinner le NOUVEAU
|
|
560
|
-
contrat plutôt que l'ancien :
|
|
561
|
-
- `theme-props-resolver.spec.ts` (2 assertions — `origam-radio`/`origam-text-field`
|
|
562
|
-
vs `origam-input` density) ;
|
|
563
|
-
- `installed-themes.composable.spec.ts` (describe block entier renommé
|
|
564
|
-
`origam baseline — explicit opt-in only (#360)`, 2 assertions corrigées et
|
|
565
|
-
2 nouvelles ajoutées pour couvrir explicitement le nouveau contrat) ;
|
|
566
|
-
- `OrigamChip.spec.ts` (1 assertion — `components['origam-chip'].size`).
|
|
567
|
-
|
|
568
|
-
**Preuve fonctionnelle** (pas seulement structurelle) —
|
|
569
|
-
`packages/tests/TU/origam/createOrigam-bare-no-theme-360.spec.ts` monte un
|
|
570
|
-
vrai `<OrigamAvatar>` : sans thème, la classe `origam--rounded-full` est
|
|
571
|
-
absente ; avec `origamTheme` passé explicitement, elle est présente — la
|
|
572
|
-
même monteuse prouve donc que le harnais peut actionner la prop avant de
|
|
573
|
-
conclure qu'elle ne l'est plus par défaut.
|
|
574
|
-
|
|
575
|
-
### Fixed
|
|
576
|
-
|
|
577
|
-
- **#871 (clôture) — les 7 dernières violations AA étaient UN défaut de
|
|
578
|
-
palette répété, pas sept défauts de composant.** Mesuré avec
|
|
579
|
-
`packages/tests/audit/dark-contrast.audit.mjs` : **7 / 1 664 → 0 / 1 664**,
|
|
580
|
-
les 8 identités × 2 modes × 2 portées, quatre contrôles verts des deux
|
|
581
|
-
côtés. Exactement **7 lignes changent, aucune ne se dégrade**, et le ratio
|
|
582
|
-
minimum de toute la surface passe de 3.65 à **4.70**.
|
|
583
|
-
|
|
584
|
-
Les 7 se répartissaient en deux causes, toutes deux dans
|
|
585
|
-
`packages/marketing/src/themes` — **aucune dans le DS**, qui était déjà à
|
|
586
|
-
zéro :
|
|
587
|
-
|
|
588
|
-
| cause | marque · mode | couple | avant | après |
|
|
589
|
-
|---|---|---|---|---|
|
|
590
|
-
| encre héritée du mode clair | `apple` sombre | `#ffffff` → `#000000` sur `#0a84ff` | 3.65 | **5.76** |
|
|
591
|
-
| encre héritée du mode clair | `ecom` sombre | `#ffffff` → `#1a0f0a` sur `#f43f5e` | 3.67 | **5.12** |
|
|
592
|
-
| jeton de rôle inversé | `ecom` clair | `action.primary.bg` → `.fgSubtle` sur la crème | 4.43 | **5.93** |
|
|
593
|
-
|
|
594
|
-
**La cause commune.** Le mode sombre ÉCLAIRCIT l'accent de marque — c'est
|
|
595
|
-
la bonne pratique pour une grande surface (`#0071e3` → `#0a84ff` chez
|
|
596
|
-
`apple`, rose-600 → rose-500 chez `ecom`) — mais les deux palettes gardaient
|
|
597
|
-
l'encre `#ffffff` de leur jumeau clair. Or chacune applique **déjà** la règle
|
|
598
|
-
inverse à ses intentions `feedback` : les 4 d'`ecom` et 3 des 4 d'`apple`
|
|
599
|
-
encrent leur accent éclairci avec le `text.inverse` de la palette.
|
|
600
|
-
`action.primary` était la dernière exception. Le badge n'était pas en cause :
|
|
601
|
-
`--origam-badge__badge---{background-color,color}` lit exactement ce couple —
|
|
602
|
-
tout comme `--origam-btn--primary---*`, qui n'est pas dans la sonde et était
|
|
603
|
-
donc en défaut sans être mesuré.
|
|
604
|
-
|
|
605
|
-
⚠️ **On n'a PAS foncé l'accent**, bien que ce soit l'autre levier : chez
|
|
606
|
-
`apple`, `action.primary.bg` sert aussi d'ENCRE (le bloc `components` passe
|
|
607
|
-
ce `var()` en `color` sur `origam-breadcrumb-item`). Le ramener à `#0071e3`
|
|
608
|
-
donnait 4.70 sous du blanc mais faisait tomber le fil d'Ariane à **4.47** sur
|
|
609
|
-
le fond noir — un défaut échangé contre un autre. Vérifié par calcul avant
|
|
610
|
-
d'écrire la moindre ligne.
|
|
639
|
+
⚠️ **On n'a PAS foncé l'accent**, bien que ce soit l'autre levier : chez
|
|
640
|
+
`apple`, `action.primary.bg` sert aussi d'ENCRE (le bloc `components` passe
|
|
641
|
+
ce `var()` en `color` sur `origam-breadcrumb-item`). Le ramener à `#0071e3`
|
|
642
|
+
donnait 4.70 sous du blanc mais faisait tomber le fil d'Ariane à **4.47** sur
|
|
643
|
+
le fond noir — un défaut échangé contre un autre. Vérifié par calcul avant
|
|
644
|
+
d'écrire la moindre ligne.
|
|
611
645
|
|
|
612
646
|
La 3ᵉ cause est une erreur de RÔLE : `bg` est un jeton de surface, `fgSubtle`
|
|
613
647
|
la teinte prévue pour être LUE sur une surface neutre. `ecomDarkTheme` posait
|
|
@@ -673,40 +707,89 @@ conclure qu'elle ne l'est plus par défaut.
|
|
|
673
707
|
du filtre. **Vérifiée ROUGE sur `origin/develop`** : 3 échecs / 14 succès.
|
|
674
708
|
C'est elle qui a trouvé la 8ᵉ violation ci-dessus.
|
|
675
709
|
|
|
676
|
-
|
|
677
|
-
Les feuilles de tokens portent ~1 761 déclarations **dérivées**
|
|
678
|
-
(`--origam-title---color: var(--origam-color__text---primary)`). Une custom
|
|
679
|
-
property est substituée **sur l'élément qui la déclare** ; ce qu'un
|
|
680
|
-
descendant hérite est la valeur DÉJÀ substituée. Le bloc sombre étant ancré
|
|
681
|
-
à la racine (`:root:not([data-theme])[data-mode="dark"]`), un sous-arbre
|
|
682
|
-
`<OrigamThemeProvider mode="dark">` basculait bien les ~60 tokens
|
|
683
|
-
sémantiques — le bloc runtime, lui, émet `[data-mode="dark"]` — mais laissait
|
|
684
|
-
les 1 761 dérivés **gelés** sur les valeurs claires de la racine. Motif
|
|
685
|
-
dominant mesuré : `rgb(10,10,10)` sur `rgb(10,10,10)`, texte et fond
|
|
686
|
-
identiques.
|
|
710
|
+
## [2.18.3] - 2026-09-23
|
|
687
711
|
|
|
688
|
-
|
|
712
|
+
#### `v-contrast` était silencieusement inerte sur fond opaque (#869)
|
|
689
713
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
714
|
+
La directive `v-contrast`, câblée sur 30 composants, n'émettait **jamais**
|
|
715
|
+
rien — ni classe, ni `color: !important`, ni `console.warn` — dès que fond
|
|
716
|
+
**et** texte étaient tous deux OPAQUES, c'est-à-dire la configuration par
|
|
717
|
+
défaut du DS. Deux ruptures indépendantes dans le code partagé, corrigeant
|
|
718
|
+
l'une ne suffisait pas sans l'autre :
|
|
694
719
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
720
|
+
1. **`toRgb()`** faisait **toujours** passer la couleur par un aller-retour
|
|
721
|
+
`canvas.fillStyle`, même quand `getComputedStyle` avait déjà rendu une
|
|
722
|
+
chaîne `rgb()/rgba()` exploitable. Le getter `fillStyle` de Chromium
|
|
723
|
+
sérialise toute couleur OPAQUE en hexadécimal `#rrggbb` (seul l'alpha < 1
|
|
724
|
+
ressort en `rgba(…)`), ce qui transformait une valeur déjà utilisable en
|
|
725
|
+
une valeur morte pour `rgbaParts`/`channelsOf`.
|
|
726
|
+
2. **`channelsOf()`** extrayait les canaux via `match(/[\d.]+/g)`, taillé
|
|
727
|
+
pour `rgb(r, g, b)` — une suite de chiffres hexadécimaux SANS séparateur
|
|
728
|
+
(ex. `#777777`, six chiffres) s'agrège en UN seul grand nombre au lieu de
|
|
729
|
+
trois, donc `channelsOf` rend `null` sur exactement la forme hex que la
|
|
730
|
+
rupture 1 pouvait encore produire (couleur nommée, `hsl()`, …
|
|
731
|
+
nécessitant légitimement le détour par le canvas).
|
|
701
732
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
733
|
+
**Correctif** : `toRgb()` court-circuite désormais le canvas quand l'entrée
|
|
734
|
+
est déjà `rgb()/rgba()` (le cas de la quasi-totalité des appels, puisqu'ils
|
|
735
|
+
lisent `getComputedStyle`), et le chemin canvas restant convertit son
|
|
736
|
+
résultat hexadécimal en `rgb()/rgba()` via un nouveau `hexToRgb()` avant de
|
|
737
|
+
le rendre — `toRgb()` ne rend plus jamais de hex. La mécanique de correction
|
|
738
|
+
elle-même (forcer noir/blanc, poser `data-origam-contrast-fixed`, journaliser
|
|
739
|
+
le ratio) n'est pas modifiée : elle fonctionnait déjà, elle n'était
|
|
740
|
+
simplement jamais atteinte.
|
|
741
|
+
|
|
742
|
+
**Preuve** — `packages/tests/e2e/contrast-directive.spec.ts` (Playwright,
|
|
743
|
+
Chromium réel — jsdom n'a pas de `canvas.getContext('2d')` fonctionnel dans
|
|
744
|
+
ce dépôt, donc ne peut ni reproduire ni vérifier ce bug) : contrôle positif
|
|
745
|
+
(`#777777` sur blanc, 4.48:1, opaque des deux côtés) déclenche désormais la
|
|
746
|
+
correction + le `console.warn` ; contrôle négatif (noir sur blanc, 21:1) ne
|
|
747
|
+
déclenche rien ; non-régression du chemin translucide (fond composé via
|
|
748
|
+
`resolvePaintedBackground`) inchangée. **A/B contre le commit parent** : 4
|
|
749
|
+
des 5 tests rougissent sur le code d'avant (le contrôle négatif reste vert
|
|
750
|
+
des deux côtés, comme attendu).
|
|
751
|
+
|
|
752
|
+
⚠️ **Rayon mesuré séparément, pas hérité de #871 — et le chiffre publié par
|
|
753
|
+
#871 contenait un artefact, corrigé depuis par #883.** Le chiffrage initial
|
|
754
|
+
du ticket (346 violations en mode sombre) datait d'avant #876. #876 avait
|
|
755
|
+
d'abord publié **189 → 11** ; en rejouant `audit/dark-contrast.audit.mjs`
|
|
756
|
+
avec la VRAIE directive (redirect du stub désactivé) au lieu de sa
|
|
757
|
+
reformulation mathématique, seuls **7 `console.warn` réels** se
|
|
758
|
+
déclenchaient sur les 32 configurations (30 composants × 8 identités × 2
|
|
759
|
+
modes, portées racine + sous-arbre) — écart signalé à l'auteur de #876, qui
|
|
760
|
+
l'a reproduit, creusé et corrigé sous #883 : **les bornes AVANT et APRÈS
|
|
761
|
+
étaient toutes les deux fausses (185 → 7, pas 189 → 11)**, la même erreur de
|
|
762
|
+
mesure existant déjà dans le comptage "avant". Le delta réel (178) n'a
|
|
763
|
+
jamais changé.
|
|
764
|
+
|
|
765
|
+
L'écart venait d'`origam-tooltip__content` (identité `apple`, root + subtree,
|
|
766
|
+
light + dark) et, découvert par #883, également d'`origam-bottom-nav` sur la
|
|
767
|
+
même identité. Fond réel : `color(srgb 0.898039 0.898039 0.905882 / 0.94)`
|
|
768
|
+
(translucide) ; `toRgb()` le résout correctement en `rgb(215, 215, 217)` une
|
|
769
|
+
fois composé sur son ancêtre opaque, contre du texte noir : **ratio 14.61:1,
|
|
770
|
+
conforme** — vérifié en appelant directement `toRgb()`/
|
|
771
|
+
`resolvePaintedBackground()` de la vraie directive sur cette page. La
|
|
772
|
+
fonction `parse()` de `dark-contrast.audit.mjs` (une réimplémentation
|
|
773
|
+
distincte, pas la directive) ne reconnaissait que `rgba?\(…\)` — elle
|
|
774
|
+
ignorait silencieusement cette couche `color(srgb …)`, sautait jusqu'à
|
|
775
|
+
l'ancêtre opaque suivant et rapportait à tort un faux "noir sur noir"
|
|
776
|
+
(ratio 1.00). **Ce n'était pas un défaut du DS ni de `v-contrast`** — la
|
|
777
|
+
même classe de lacune que ce ticket corrige, mais dans un autre fichier. Les
|
|
778
|
+
7 restantes (4 `origam-badge__badge`, 3 `origam-breadcrumb-item`) sont
|
|
779
|
+
confirmées identiques entre les deux mesures, et `sous 2:1` passe à **0** une
|
|
780
|
+
fois l'artefact retiré : plus rien de ce qui reste n'est proche d'invisible.
|
|
781
|
+
|
|
782
|
+
Non corrigé ici : `dark-contrast.audit.mjs` appartenait à #871/#876, pas à ce
|
|
783
|
+
ticket — signalé, reproduit et corrigé séparément sous #883 (ne pas citer
|
|
784
|
+
189 → 11, c'était faux des deux côtés).
|
|
785
|
+
|
|
786
|
+
**Rupture d'API** : aucune — `toRgb`/`channelsOf`/`hexToRgb` restent des
|
|
787
|
+
fonctions privées du module, non exportées ; la surface publique
|
|
788
|
+
(`setContrastConfig`, `v-contrast` par défaut) est inchangée.
|
|
789
|
+
|
|
790
|
+
## [2.18.2] - 2026-09-23
|
|
791
|
+
|
|
792
|
+
### Fixed
|
|
710
793
|
|
|
711
794
|
- **#871 — le harnais de contraste ne savait pas lire `color(srgb …)`, et
|
|
712
795
|
FABRIQUAIT donc des violations.** Son `parse()` ne reconnaissait que
|
|
@@ -741,46 +824,6 @@ conclure qu'elle ne l'est plus par défaut.
|
|
|
741
824
|
propre n'a été ouvert : le défaut est dans l'instrumentation de #871, donc
|
|
742
825
|
il se règle sous #871.
|
|
743
826
|
|
|
744
|
-
- **#871 — `system-bar` et `tooltip` illisibles en sombre.** Les deux peignent
|
|
745
|
-
une surface sombre dans les DEUX modes (`neutral---700` / `neutral---800`)
|
|
746
|
-
et lisaient `text---inverse`, qui vaut blanc en clair et **encre** en
|
|
747
|
-
sombre : 1.91:1 et 1.31:1. `dark.css` lit maintenant `text---primary` ;
|
|
748
|
-
`light.css` est inchangé.
|
|
749
|
-
|
|
750
|
-
- **#871 — `bottom-nav` peignait une dalle claire dans une UI sombre.** Son
|
|
751
|
-
fond était épinglé à la primitive `neutral---200` (#e6e6e6) dans les deux
|
|
752
|
-
modes, sous un `text---primary` presque blanc (1.03:1). En sombre il passe
|
|
753
|
-
au token sémantique `surface---overlay`. Le clair est inchangé.
|
|
754
|
-
|
|
755
|
-
### Changed — ⛔ RUPTURE (documentée, assumée)
|
|
756
|
-
|
|
757
|
-
- **Les feuilles de tokens ne sont plus ancrées à `:root`.** Un consommateur
|
|
758
|
-
qui avait contourné le gel ci-dessus en re-déclarant lui-même des variables
|
|
759
|
-
de composant dans un sous-arbre `[data-mode]` voit désormais la feuille les
|
|
760
|
-
déclarer aussi, en (0,1,0) côté clair et (0,2,0) côté sombre. Son bloc de
|
|
761
|
-
contournement doit donc être au moins aussi spécifique, ou être retiré.
|
|
762
|
-
|
|
763
|
-
Concrètement dans ce dépôt : `packages/marketing` embarque
|
|
764
|
-
`ORIGAM_COMPONENT_RESET_LIGHT/DARK` (`themes/origam-reset.generated.ts`),
|
|
765
|
-
une re-déclaration GÉNÉRÉE de ~2 700 variables de composant, écrite
|
|
766
|
-
exactement pour ce défaut. Elle est maintenant redondante — **elle n'a pas
|
|
767
|
-
été retirée ici**, faute de mesure sur le rendu du site.
|
|
768
|
-
|
|
769
|
-
Ce qui NE change pas : `data-theme="light" data-mode="dark"` reste clair
|
|
770
|
-
(l'axe marque gouverne quand les deux se contredisent, règle #807),
|
|
771
|
-
`data-mode="light"` sous un OS sombre reste clair (#794), et une marque
|
|
772
|
-
claire continue de gagner sur la feuille par l'ordre source.
|
|
773
|
-
|
|
774
|
-
### Documentation
|
|
775
|
-
|
|
776
|
-
- `CLAUDE.md`, section *Multi-theme* : la note qui affirmait que le bloc
|
|
777
|
-
auto-mode ne porte que **11** déclarations est **fausse** — recompté en
|
|
778
|
-
parsant la feuille le 2026-09-22, les deux blocs en portent **2 731**
|
|
779
|
-
chacun. L'affirmation décrivait un état antérieur à #794 que plus rien ne
|
|
780
|
-
remesurait.
|
|
781
|
-
|
|
782
|
-
### Fixed
|
|
783
|
-
|
|
784
827
|
- **#371 (point 3) — le sélecteur « Items per page » du footer
|
|
785
828
|
DataTable n'avait aucun nom accessible**, déjà corrigé par `3f063d727`
|
|
786
829
|
(2026-09-10) — ce commit **citait #371 sans le fermer**, sixième
|
|
@@ -816,85 +859,218 @@ conclure qu'elle ne l'est plus par défaut.
|
|
|
816
859
|
`OrigamDataTableRow.story.vue`) et d'une section « Responsive » +
|
|
817
860
|
ligne de table dans `OrigamDataTable.md`.
|
|
818
861
|
|
|
819
|
-
|
|
862
|
+
## [2.18.1] - 2026-09-22
|
|
820
863
|
|
|
821
|
-
|
|
864
|
+
Récolte de deux dépréciations posées "pour la prochaine majeure" avant que le
|
|
865
|
+
`CLAUDE.md` n'acte que `3.0.0` est réservé à la séparation en modules et que
|
|
866
|
+
les ruptures, elles, ne le sont pas — voir "Work priorities and versioning"
|
|
867
|
+
du `CLAUDE.md`. `origam` n'a aucun consommateur : les deux ruptures
|
|
868
|
+
ci-dessous partent en **mineure**, sans shim ni période de grâce.
|
|
822
869
|
|
|
823
|
-
|
|
824
|
-
rien — ni classe, ni `color: !important`, ni `console.warn` — dès que fond
|
|
825
|
-
**et** texte étaient tous deux OPAQUES, c'est-à-dire la configuration par
|
|
826
|
-
défaut du DS. Deux ruptures indépendantes dans le code partagé, corrigeant
|
|
827
|
-
l'une ne suffisait pas sans l'autre :
|
|
870
|
+
### ⚠️ BREAKING — `click:prepend` / `click:append` retirés d'`IBtnEmits` (#443, #577)
|
|
828
871
|
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
une valeur morte pour `rgbaParts`/`channelsOf`.
|
|
835
|
-
2. **`channelsOf()`** extrayait les canaux via `match(/[\d.]+/g)`, taillé
|
|
836
|
-
pour `rgb(r, g, b)` — une suite de chiffres hexadécimaux SANS séparateur
|
|
837
|
-
(ex. `#777777`, six chiffres) s'agrège en UN seul grand nombre au lieu de
|
|
838
|
-
trois, donc `channelsOf` rend `null` sur exactement la forme hex que la
|
|
839
|
-
rupture 1 pouvait encore produire (couleur nommée, `hsl()`, …
|
|
840
|
-
nécessitant légitimement le détour par le canvas).
|
|
872
|
+
`<OrigamBtn>` n'émet plus `click:prepend` ni `click:append` — ni au niveau du
|
|
873
|
+
type, ni au niveau de l'exécution. `IBtnEmits` n'`extends` plus
|
|
874
|
+
`IAdjacentEmits`, et les `<span>` `origam-btn__prepend` / `__append` ne
|
|
875
|
+
portent plus de `@click` du tout : un clic souris dessus ne déclenche plus
|
|
876
|
+
rien.
|
|
841
877
|
|
|
842
|
-
**
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
878
|
+
**Pourquoi cette paire précisément, et pourquoi une suppression plutôt qu'un
|
|
879
|
+
correctif.** Les deux émissions n'ont jamais été atteignables au clavier :
|
|
880
|
+
l'événement partait d'un `<span>` descendant, alors qu'une activation clavier
|
|
881
|
+
synthétise son clic sur la RACINE du composant — l'écouteur posé sur le
|
|
882
|
+
descendant ne le voit jamais. Le correctif générique appliqué aux dix autres
|
|
883
|
+
consommateurs d'`useAdjacent` (promouvoir la zone en `role="button"` + arrêt
|
|
884
|
+
de tabulation) est **illégal** ici : `<OrigamBtn>` rend un `<button>` ou un
|
|
885
|
+
`<a>`, et le modèle de contenu HTML interdit à tous deux un descendant de
|
|
886
|
+
contenu interactif *et* tout descendant portant `tabindex`. Un
|
|
887
|
+
`<button type="button">` imbriqué y est tout aussi invalide. La forme était
|
|
888
|
+
fausse, pas seulement le balisage : un contrôle qui possède déjà une action
|
|
889
|
+
ne peut pas en héberger une seconde — deux actions sont deux boutons,
|
|
890
|
+
composés via `<origam-btn-group>`.
|
|
850
891
|
|
|
851
|
-
**
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
déclenche rien ; non-régression du chemin translucide (fond composé via
|
|
857
|
-
`resolvePaintedBackground`) inchangée. **A/B contre le commit parent** : 4
|
|
858
|
-
des 5 tests rougissent sur le code d'avant (le contrôle négatif reste vert
|
|
859
|
-
des deux côtés, comme attendu).
|
|
892
|
+
**Ce qui NE bouge PAS** : les slots `prepend` / `append` (`IBtnSlots extends
|
|
893
|
+
IAdjacentSlots`) restent intacts, ainsi que les props `prependIcon` /
|
|
894
|
+
`appendIcon` / `prependAvatar` / `appendAvatar` — un contenu décoratif ou
|
|
895
|
+
informationnel en prepend/append reste parfaitement légitime, seule
|
|
896
|
+
l'émission d'un clic disparaît.
|
|
860
897
|
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
l'a reproduit, creusé et corrigé sous #883 : **les bornes AVANT et APRÈS
|
|
870
|
-
étaient toutes les deux fausses (185 → 7, pas 189 → 11)**, la même erreur de
|
|
871
|
-
mesure existant déjà dans le comptage "avant". Le delta réel (178) n'a
|
|
872
|
-
jamais changé.
|
|
898
|
+
**Preuve du comportement retiré** — A/B contre le commit parent, fonctionnel
|
|
899
|
+
et pas seulement typé : `packages/tests/TU/components/Btn/OrigamBtn.adjacent-emit-removed.spec.ts`
|
|
900
|
+
monte `<OrigamBtn>` avec un écouteur `onClick:prepend` / `onClick:append` et
|
|
901
|
+
déclenche un vrai `click` DOM sur la zone. Sur le commit parent, ce même test
|
|
902
|
+
appellerait l'écouteur (l'émission déclarée par `IAdjacentEmits` partait
|
|
903
|
+
encore) ; sur ce commit, l'écouteur n'est jamais invoqué — vérifié en
|
|
904
|
+
rejouant le fichier de spec avant/après le changement, pas seulement en le
|
|
905
|
+
lisant une fois vert.
|
|
873
906
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
fois composé sur son ancêtre opaque, contre du texte noir : **ratio 14.61:1,
|
|
879
|
-
conforme** — vérifié en appelant directement `toRgb()`/
|
|
880
|
-
`resolvePaintedBackground()` de la vraie directive sur cette page. La
|
|
881
|
-
fonction `parse()` de `dark-contrast.audit.mjs` (une réimplémentation
|
|
882
|
-
distincte, pas la directive) ne reconnaissait que `rgba?\(…\)` — elle
|
|
883
|
-
ignorait silencieusement cette couche `color(srgb …)`, sautait jusqu'à
|
|
884
|
-
l'ancêtre opaque suivant et rapportait à tort un faux "noir sur noir"
|
|
885
|
-
(ratio 1.00). **Ce n'était pas un défaut du DS ni de `v-contrast`** — la
|
|
886
|
-
même classe de lacune que ce ticket corrige, mais dans un autre fichier. Les
|
|
887
|
-
7 restantes (4 `origam-badge__badge`, 3 `origam-breadcrumb-item`) sont
|
|
888
|
-
confirmées identiques entre les deux mesures, et `sous 2:1` passe à **0** une
|
|
889
|
-
fois l'artefact retiré : plus rien de ce qui reste n'est proche d'invisible.
|
|
907
|
+
Nettoyage induit : le helper `warnDeprecatedEmit` (`color.util.ts`) et la
|
|
908
|
+
constante `ADJACENT_EMIT_REPLACEMENT` (`consts/Btn/btn.const.ts`) sont
|
|
909
|
+
retirés — `<OrigamBtn>` était leur seul appelant, et le fichier `btn.const.ts`
|
|
910
|
+
devenu vide est supprimé.
|
|
890
911
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
912
|
+
**Migration.** Aucun consommateur interne (DS, marketing, stories, docs,
|
|
913
|
+
tests) n'utilisait `click:prepend` / `click:append` sur `<OrigamBtn>` —
|
|
914
|
+
balayage exhaustif, zéro résultat. Un consommateur externe qui les écoutait
|
|
915
|
+
doit remplacer l'action posée sur la zone prepend/append par un second
|
|
916
|
+
`<origam-btn>` dans un `<origam-btn-group>`.
|
|
894
917
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
(`
|
|
918
|
+
### ⚠️ BREAKING — `createOrigam()` nu n'installe plus le thème par défaut (#360)
|
|
919
|
+
|
|
920
|
+
`createOrigam()` préfixait inconditionnellement chaque install avec le thème
|
|
921
|
+
neutre interne `origamTheme` (`[...origamTheme, ...suppliedThemes]`) : même un
|
|
922
|
+
appel nu, ou un `themes: []` explicite, recevait quand même les variables CSS
|
|
923
|
+
et — surtout — les **props par défaut par composant** (ADR-005,
|
|
924
|
+
`components: { 'origam-avatar': { rounded: 'full' }, … }`) de ce thème. Une
|
|
925
|
+
application qui n'en voulait pas ne pouvait pas s'en défaire. Ce préfixage est
|
|
926
|
+
retiré : `createOrigam()` installe désormais exactement ce qu'on lui passe,
|
|
927
|
+
rien de plus.
|
|
928
|
+
|
|
929
|
+
**Ce qui change concrètement.** Sans `themes`/`theme` explicite,
|
|
930
|
+
`createOrigam()` n'injecte plus aucune variable `--origam-*` et le résolveur
|
|
931
|
+
de props par défaut (`installThemePropsResolver`, ADR-005) n'a plus rien à
|
|
932
|
+
résoudre — chaque composant retombe uniquement sur ses propres valeurs
|
|
933
|
+
`withDefaults()`. Concrètement : un `<origam-avatar>` sans prop `rounded`
|
|
934
|
+
explicite n'est plus automatiquement circulaire (`rounded="full"` venait du
|
|
935
|
+
thème, pas du composant).
|
|
936
|
+
|
|
937
|
+
**Le thème par défaut reste disponible, à la demande** — `origamTheme`,
|
|
938
|
+
exporté par `origam/themes` (déjà public avant cette rupture, aucun nouvel
|
|
939
|
+
export nécessaire) :
|
|
940
|
+
|
|
941
|
+
```ts
|
|
942
|
+
// AVANT (2.x) — enregistrait implicitement le thème origam par défaut
|
|
943
|
+
import { createOrigam } from 'origam'
|
|
944
|
+
app.use(createOrigam())
|
|
945
|
+
|
|
946
|
+
// APRÈS — le thème par défaut est un choix explicite
|
|
947
|
+
import { createOrigam } from 'origam'
|
|
948
|
+
import { origamTheme } from 'origam/themes'
|
|
949
|
+
app.use(createOrigam({ themes: origamTheme }))
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
**Rayon de souffle mesuré, corrigé dans le même lot** — quatre consommateurs
|
|
953
|
+
directs de `createOrigam()` nu trouvés par balayage exhaustif (DS, marketing,
|
|
954
|
+
stories, docs, tests) :
|
|
955
|
+
- `packages/ds/src/nuxt/module.ts` — le module Nuxt officiel. **Non cassé** :
|
|
956
|
+
son propre `DEFAULT_THEMES` (utilisé quand l'option `origam.themes` du
|
|
957
|
+
consommateur est omise) passe désormais `origamTheme` explicitement à
|
|
958
|
+
`createOrigam()`, préservant à l'identique le comportement de tout
|
|
959
|
+
consommateur Nuxt existant (marketing compris) qui ne configurait rien.
|
|
960
|
+
Seul un `createOrigam()` direct, hors module Nuxt, doit s'adapter.
|
|
961
|
+
- `packages/marketing/nuxt.config.ts` — configure `origam.themes`
|
|
962
|
+
explicitement (7 thèmes de marque + un thème `origam` renommé pour le
|
|
963
|
+
playground `/theming`), ce qui **contourne** le fallback du module. Le vrai
|
|
964
|
+
thème neutre non-nommé (celui que `activeDefaultsFor` fusionne toujours en
|
|
965
|
+
premier, avant la marque active) était fourni jusqu'ici par le préfixage
|
|
966
|
+
implicite de `createOrigam()` — invisible dans la config marketing. Il est
|
|
967
|
+
désormais listé explicitement, en premier, dans le tableau `themes`.
|
|
968
|
+
- `packages/stories/histoire.setup.ts` — Histoire (utilisé par les ~208
|
|
969
|
+
stories de composants) appelait `createOrigam()` nu ; sans correction,
|
|
970
|
+
chaque story aurait silencieusement perdu les props par défaut du thème
|
|
971
|
+
(avatars carrés au lieu de circulaires, etc.). Passe désormais
|
|
972
|
+
`{ themes: origamTheme }`.
|
|
973
|
+
- `packages/docs/.vitepress/theme/index.ts` — les démos de composants live de
|
|
974
|
+
la doc VitePress appelaient `createOrigam()` nu ; même correction.
|
|
975
|
+
|
|
976
|
+
Les échantillons de code montrés au consommateur (`installation.const.ts` /
|
|
977
|
+
`installation.vue` sur le marketing, `guide/usage.md` côté docs) sont mis à
|
|
978
|
+
jour pour montrer la forme correcte — un utilisateur copiant l'ancien
|
|
979
|
+
exemple aurait obtenu des composants non stylés selon le thème.
|
|
980
|
+
|
|
981
|
+
**Tests adaptés** (comptés avant correction, comme demandé) — 3 fichiers /
|
|
982
|
+
5 assertions reposaient sur l'enregistrement implicite et ont été corrigés
|
|
983
|
+
pour installer `origamTheme` explicitement là où le test vérifie précisément
|
|
984
|
+
une valeur par défaut issue du thème, ou réécrits pour pinner le NOUVEAU
|
|
985
|
+
contrat plutôt que l'ancien :
|
|
986
|
+
- `theme-props-resolver.spec.ts` (2 assertions — `origam-radio`/`origam-text-field`
|
|
987
|
+
vs `origam-input` density) ;
|
|
988
|
+
- `installed-themes.composable.spec.ts` (describe block entier renommé
|
|
989
|
+
`origam baseline — explicit opt-in only (#360)`, 2 assertions corrigées et
|
|
990
|
+
2 nouvelles ajoutées pour couvrir explicitement le nouveau contrat) ;
|
|
991
|
+
- `OrigamChip.spec.ts` (1 assertion — `components['origam-chip'].size`).
|
|
992
|
+
|
|
993
|
+
**Preuve fonctionnelle** (pas seulement structurelle) —
|
|
994
|
+
`packages/tests/TU/origam/createOrigam-bare-no-theme-360.spec.ts` monte un
|
|
995
|
+
vrai `<OrigamAvatar>` : sans thème, la classe `origam--rounded-full` est
|
|
996
|
+
absente ; avec `origamTheme` passé explicitement, elle est présente — la
|
|
997
|
+
même monteuse prouve donc que le harnais peut actionner la prop avant de
|
|
998
|
+
conclure qu'elle ne l'est plus par défaut.
|
|
999
|
+
|
|
1000
|
+
### Fixed
|
|
1001
|
+
|
|
1002
|
+
- **#871 — le mode sombre ne peignait qu'à moitié dans un sous-arbre thémé.**
|
|
1003
|
+
Les feuilles de tokens portent ~1 761 déclarations **dérivées**
|
|
1004
|
+
(`--origam-title---color: var(--origam-color__text---primary)`). Une custom
|
|
1005
|
+
property est substituée **sur l'élément qui la déclare** ; ce qu'un
|
|
1006
|
+
descendant hérite est la valeur DÉJÀ substituée. Le bloc sombre étant ancré
|
|
1007
|
+
à la racine (`:root:not([data-theme])[data-mode="dark"]`), un sous-arbre
|
|
1008
|
+
`<OrigamThemeProvider mode="dark">` basculait bien les ~60 tokens
|
|
1009
|
+
sémantiques — le bloc runtime, lui, émet `[data-mode="dark"]` — mais laissait
|
|
1010
|
+
les 1 761 dérivés **gelés** sur les valeurs claires de la racine. Motif
|
|
1011
|
+
dominant mesuré : `rgb(10,10,10)` sur `rgb(10,10,10)`, texte et fond
|
|
1012
|
+
identiques.
|
|
1013
|
+
|
|
1014
|
+
Les deux feuilles s'accrochent désormais aussi à l'axe `data-mode` :
|
|
1015
|
+
|
|
1016
|
+
```css
|
|
1017
|
+
:root, [data-theme="light"], [data-mode="light"] { /* clair */ }
|
|
1018
|
+
[data-theme="dark"], [data-mode="dark"]:not([data-theme="light"]) { /* sombre */ }
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
Rejoué sur 30 composants × 8 identités × 2 modes × 2 portées (racine ET
|
|
1022
|
+
sous-arbre), soit **1 664 instances**, Chromium, contrôles positif et négatif
|
|
1023
|
+
verts : **185 → 7 violations AA**, dont sombre **182 → 4** et clair
|
|
1024
|
+
**3 → 3** (aucune régression). Les 7 restantes appartiennent toutes aux
|
|
1025
|
+
palettes de marque de `packages/marketing`, aucune au DS, et aucune ne
|
|
1026
|
+
descend sous 2:1. Harnais : `pnpm -F @origam/tests audit:dark-contrast`.
|
|
1027
|
+
|
|
1028
|
+
⚠️ **Ces bornes ont d'abord été publiées à `189 → 11`, et les deux étaient
|
|
1029
|
+
fausses de 4.** Le parseur de couleurs du harnais ne connaissait pas
|
|
1030
|
+
`color(srgb …)`, que la palette `apple` émet : le fond translucide du
|
|
1031
|
+
tooltip était pris pour « pas de fond », la remontée d'ancêtres sautait
|
|
1032
|
+
jusqu'à la surface opaque et rapportait du noir sur noir à 1.00 — quatre
|
|
1033
|
+
violations **fabriquées**, présentes des DEUX côtés de la mesure. Le
|
|
1034
|
+
**delta de 178 n'a jamais été faux** ; seules les bornes l'étaient. Détail
|
|
1035
|
+
et garde de non-récidive plus bas.
|
|
1036
|
+
|
|
1037
|
+
- **#871 — `system-bar` et `tooltip` illisibles en sombre.** Les deux peignent
|
|
1038
|
+
une surface sombre dans les DEUX modes (`neutral---700` / `neutral---800`)
|
|
1039
|
+
et lisaient `text---inverse`, qui vaut blanc en clair et **encre** en
|
|
1040
|
+
sombre : 1.91:1 et 1.31:1. `dark.css` lit maintenant `text---primary` ;
|
|
1041
|
+
`light.css` est inchangé.
|
|
1042
|
+
|
|
1043
|
+
- **#871 — `bottom-nav` peignait une dalle claire dans une UI sombre.** Son
|
|
1044
|
+
fond était épinglé à la primitive `neutral---200` (#e6e6e6) dans les deux
|
|
1045
|
+
modes, sous un `text---primary` presque blanc (1.03:1). En sombre il passe
|
|
1046
|
+
au token sémantique `surface---overlay`. Le clair est inchangé.
|
|
1047
|
+
|
|
1048
|
+
### Changed — ⛔ RUPTURE (documentée, assumée)
|
|
1049
|
+
|
|
1050
|
+
- **Les feuilles de tokens ne sont plus ancrées à `:root`.** Un consommateur
|
|
1051
|
+
qui avait contourné le gel ci-dessus en re-déclarant lui-même des variables
|
|
1052
|
+
de composant dans un sous-arbre `[data-mode]` voit désormais la feuille les
|
|
1053
|
+
déclarer aussi, en (0,1,0) côté clair et (0,2,0) côté sombre. Son bloc de
|
|
1054
|
+
contournement doit donc être au moins aussi spécifique, ou être retiré.
|
|
1055
|
+
|
|
1056
|
+
Concrètement dans ce dépôt : `packages/marketing` embarque
|
|
1057
|
+
`ORIGAM_COMPONENT_RESET_LIGHT/DARK` (`themes/origam-reset.generated.ts`),
|
|
1058
|
+
une re-déclaration GÉNÉRÉE de ~2 700 variables de composant, écrite
|
|
1059
|
+
exactement pour ce défaut. Elle est maintenant redondante — **elle n'a pas
|
|
1060
|
+
été retirée ici**, faute de mesure sur le rendu du site.
|
|
1061
|
+
|
|
1062
|
+
Ce qui NE change pas : `data-theme="light" data-mode="dark"` reste clair
|
|
1063
|
+
(l'axe marque gouverne quand les deux se contredisent, règle #807),
|
|
1064
|
+
`data-mode="light"` sous un OS sombre reste clair (#794), et une marque
|
|
1065
|
+
claire continue de gagner sur la feuille par l'ordre source.
|
|
1066
|
+
|
|
1067
|
+
### Documentation
|
|
1068
|
+
|
|
1069
|
+
- `CLAUDE.md`, section *Multi-theme* : la note qui affirmait que le bloc
|
|
1070
|
+
auto-mode ne porte que **11** déclarations est **fausse** — recompté en
|
|
1071
|
+
parsant la feuille le 2026-09-22, les deux blocs en portent **2 731**
|
|
1072
|
+
chacun. L'affirmation décrivait un état antérieur à #794 que plus rien ne
|
|
1073
|
+
remesurait.
|
|
898
1074
|
|
|
899
1075
|
## [2.18.0] - 2026-09-19
|
|
900
1076
|
|