origam 2.18.5 → 2.18.6

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 CHANGED
@@ -18,6 +18,144 @@ This project follows [Semantic Versioning](https://semver.org).
18
18
 
19
19
  ## [Unreleased]
20
20
 
21
+ ### Fixed — #818 baseline shrink : les 8 `color-contrast` du DS (8 → 0)
22
+
23
+ ⚠️ **Ce lot porte sur le DS lui-même, pas sur une palette marketing** : il
24
+ part dans le paquet npm publié, un consommateur le reçoit.
25
+
26
+ Recompté sur `a11y-violations.baseline.json` (aucun chiffre repris
27
+ d'ailleurs) : **18 violations / 17 clés**, dont **8 `color-contrast`**.
28
+ Mesurées par axe-core en navigateur réel (Playwright + Histoire statique,
29
+ thème `origamTheme` — celui que `histoire.setup.ts` installe via
30
+ `createOrigam()`), elles valaient **15 nœuds** en défaut. Ce ne sont pas 8
31
+ défauts : ce sont **3 causes**.
32
+
33
+ **Cause 1 — une `opacity` décorative délave le TEXTE qu'elle contient**
34
+ (3 entrées : `OrigamNumberField`, `OrigamDatePickerField`,
35
+ `OrigamDataTableRows`). `opacity` crée un groupe de composition qui
36
+ s'applique à tout le sous-arbre, pas au seul trait qu'on visait.
37
+ - `OrigamField` : le label flottant est monté DANS
38
+ `.origam-field__outline--notch`, dont l'`opacity: .38` ne visait que la
39
+ bordure. Mesuré : `#6d28d9` à .38 sur blanc → `#c8adf1`, soit **1.96:1**.
40
+ L'alpha passe sur `border-color` (`color-mix`) — trait identique, label à
41
+ pleine opacité : **7.10:1**. Appliqué aux trois variantes (`outlined`,
42
+ `underlined`, `filled`).
43
+ - `OrigamDataTable` : `.origam-data-table--loading .origam-data-table-cell`
44
+ voilait aussi les en-têtes. Mesuré : `#6d28d9` à .5 → `#b694ec`,
45
+ **2.38:1**. Remonter l'opacité ne sauve pas la règle (il faudrait ≥ .82,
46
+ ce n'est plus un voile) : le voile épargne désormais les en-têtes, qui
47
+ sont la structure du tableau et non la donnée rafraîchie → **6.52:1**.
48
+
49
+ **Cause 2 — un premier plan choisi sans regarder la surface réellement
50
+ peinte** (4 entrées : `OrigamPicker`, `OrigamDatePicker`,
51
+ `OrigamUtilities` ×2). Même famille que #777 (Card) et #514.
52
+ - `--origam-picker-title---color` épinglait `text---secondary` (`#525252`)
53
+ quel que soit le fond ; sur un en-tête `bgColor="primary"` (`#7c3aed`)
54
+ cela donnait **1.37:1**. Le token vaut désormais `currentColor` : le
55
+ titre suit le premier plan de sa surface → **5.70:1** sur primary, et il
56
+ s'aligne visuellement sur le reste de l'en-tête.
57
+ - `.origam--color-{intent}` lisait `---fg`, le premier plan *sur* la
58
+ couleur (blanc) — donc `.origam--color-primary` peignait blanc sur
59
+ `#fafafa`, **1.04:1** : 5 des 7 pastilles étaient littéralement
60
+ invisibles. Ces classes miroitent désormais `tokenForegroundForIntent()`
61
+ (`---fgSubtle`), c'est-à-dire **la valeur que la déclaration inline du
62
+ même prop `color="{intent}"` applique déjà et qui l'emporte sur la
63
+ classe** : la correction fait converger les deux canaux (cf. #514, « 7
64
+ intents sur 8 rendaient une couleur différente »). 4.81:1 à 6.81:1 selon
65
+ l'intention.
66
+ - `.origam--bg-{intent}` porte désormais son premier plan apparié
67
+ (`---fg`), l'appariement que `useColor()` effectue déjà sur le canal
68
+ inline pour `bgColor`. Sans lui, du markup nu héritait de l'encre de la
69
+ page. Les 7 paires sont ≥ 4.5:1 (4.83 → 19.80).
70
+
71
+ **Cause 3 — un couple en dur réellement insuffisant** (1 entrée :
72
+ `OrigamChartRangeSelector`). Le bouton actif peignait blanc sur `#3b82f6`,
73
+ **3.68:1**. `#3b82f6` n'appartient à **aucune échelle du DS** (bleu
74
+ Tailwind) : c'était une valeur isolée, et c'est elle qui produisait la
75
+ violation. Corriger le contraste en gardant une valeur hors échelle aurait
76
+ réglé le symptôme en laissant la cause — l'état actif rejoint donc la
77
+ convention que `chip--selected`, `pagination__item---active` et `stepper`
78
+ appliquent déjà, **la paire complète** :
79
+ `--origam-color__action--primary---bg` + `---fg` (**5.70:1**), survol
80
+ `---bgHover` + `---fg` (**7.10:1**). Le premier plan passe du token brut
81
+ `--origam-color---white` au sémantique `---fg` : l'état sélectionné
82
+ devient **atteignable par le theming**, ce qu'un `#3b82f6` en dur ne serait
83
+ jamais. Mesuré rendu : `rgb(124, 58, 237)` sur `rgb(255, 255, 255)`.
84
+
85
+ Baseline : **18 → 10 violations, 17 → 10 clés, zéro `color-contrast`**.
86
+ Aucune autre entrée touchée. Formule de contraste reprise telle quelle de
87
+ `packages/tests/e2e/token-intent-contrast.spec.ts` (témoins rejoués :
88
+ noir/blanc **21.00**, `#767676` **4.54**, `#777777` **4.48**).
89
+
90
+ ⚠️ **Rupture visuelle assumée** (les ruptures sont gratuites sur ce dépôt,
91
+ mais celles-ci se voient) : `.origam--color-{intent}` passe du blanc à la
92
+ couleur de l'intention ; `.origam--bg-{intent}` impose son premier plan ;
93
+ le titre de Picker suit sa surface (sur un Picker neutre il passe du gris
94
+ `#525252` à l'encre héritée) ; le bouton actif de `OrigamChartRangeSelector`
95
+ passe du bleu au violet de l'identité (`action--primary`), comme tout autre
96
+ état sélectionné du DS.
97
+
98
+ ### Fixed — #818 baseline shrink : structure ARIA — `aria-required-parent`/`aria-required-children`/`listitem`/`aria-prohibited-attr` (4 entrées)
99
+
100
+ Recompté sur `a11y-violations.baseline.json` **après rebase sur `develop`**
101
+ (le lot `button-name`/`scrollable-region-focusable` ci-dessous, #892, est
102
+ passé pendant ce travail et a déjà fait bouger le compteur : 18/17 → 12/12
103
+ avant ce commit) : **12 violations / 12 clés → 8 violations / 8 clés** avec
104
+ ce lot. Les quatre entrées traitées ici sont la même famille de défaut vue
105
+ sous quatre angles : un rôle ARIA exigeant un parent ou des enfants d'un
106
+ rôle précis, et l'arbre rendu ne les fournissait pas.
107
+
108
+ - **`OrigamCalendar` — `aria-required-parent`** (`role="row"` sans parent
109
+ `grid`/`rowgroup`/`table`/`treegrid`). La ligne d'en-tête des jours
110
+ (`.origam-calendar__weekdays`, `role="row"`) était un SIBLING de
111
+ `.origam-calendar__month-grid` (qui seul portait `role="grid"`), jamais un
112
+ descendant. `role="grid"` + l'`aria-label` du mois sont montés d'un cran,
113
+ sur `.origam-calendar__body--month` (qui enveloppe déjà les deux) ; la
114
+ grille interne redevient un simple conteneur de mise en page. Les lignes du
115
+ mois (`role="row"`, déjà correctement rattachées) ne changent pas de statut.
116
+ - **`OrigamListGroup` — `aria-required-children`** (`<origam-list>` /
117
+ `role="list"` ou `"listbox"` sans AUCUN `listitem`/`option` descendant
118
+ lorsque le groupe est fermé — l'activateur porte délibérément aucun rôle,
119
+ ce n'est pas une ligne de la liste). Le groupe entier (activateur + sous-
120
+ liste) est désormais lui-même compté comme UNE ligne de la liste ambiante,
121
+ via un nouveau `groupRole` calculé sur `list.itemRole` : `listitem` en mode
122
+ `list` (seul rôle que `list` autorise comme enfant — vérifié empiriquement
123
+ contre `axe-core@4.13`, `role="group"` y est refusé), `group` en mode
124
+ `listbox` (rôle explicitement autorisé là). Sans liste ambiante (composant
125
+ autonome), aucun rôle n'est posé — un `listitem` hors de tout `list`
126
+ aurait simplement déplacé la violation vers `aria-required-parent`.
127
+ `OrigamListGroupActivator.story.vue` plaçait ses lignes hors du slot
128
+ `#items` (bug de story pré-existant, invisible tant que le wrapper ne
129
+ portait aucun rôle) ; corrigé dans le même commit — sans quoi le nouveau
130
+ rôle aurait cassé la ligne réelle imbriquée (`aria-required-parent` par
131
+ ricochet, capturé en re-testant la suite complète après le fix).
132
+ - **`OrigamFileFieldListItem` — `listitem`** (un `<li>` isolé sans `<ul>`
133
+ parent). Le composant réel est toujours monté par `OrigamFileField` dans
134
+ un vrai `<ul>` — la violation venait uniquement de la story qui démontre
135
+ le sous-composant seul, enveloppé dans un `<div>`. Les six Variants de
136
+ `OrigamFileFieldListItem.story.vue` enveloppent désormais le `<li>` dans un
137
+ `<ul role="list">` (le `role="list"` explicite est une marge de sécurité
138
+ contre le bug WebKit qui retire la sémantique de liste implicite quand
139
+ `list-style: none` est appliqué — présent aussi sur le vrai
140
+ `OrigamFileField.vue`, non corrigé ici, aucun outil de la suite ne le
141
+ détecte).
142
+ - **`OrigamChartMap` — `aria-prohibited-attr`** (`aria-label` sur un
143
+ `<path>` SVG sans rôle). `:role="country.hasData ? 'button' : undefined"`
144
+ gérait déjà le cas « pays sans donnée », mais `:aria-label` restait posé
145
+ sans condition — un `<path>` sans rôle a un rôle implicite `generic`, qui
146
+ interdit `aria-label`. `aria-label` suit désormais la même condition que
147
+ `role`.
148
+
149
+ **Preuve** : porte a11y ciblée (`OrigamCalendar`/`OrigamListGroup`/
150
+ `OrigamFileFieldListItem`/`OrigamChartMap`/`OrigamListGroupActivator`
151
+ Default Variant) verte, `axe-core` réel via Playwright + Histoire statique
152
+ (`E2E_STATIC=1`). Contrôle positif exécuté sur `OrigamListGroup` : rôle
153
+ retiré → `aria-required-children` NOUVELLE (non baselinée) → `exit 1` réel ;
154
+ rôle restauré → vert. Suite a11y complète (218 stories + 8 Variants
155
+ d'intention) rejouée après le lot : **226 passed, 0 failed**. Suite unitaire
156
+ complète : **7149 passed**. `pnpm -F origam guards` 28/28, `guards:self`
157
+ 15/15, `type-check` et `pnpm audit` propres.
158
+
21
159
  ### Fixed — #818 baseline shrink : `aria-allowed-attr`/`aria-prohibited-attr`/`aria-valid-attr-value` (12 des 25 entrées)
22
160
 
23
161
  Recompté sur `a11y-violations.baseline.json` (pas repris d'un chiffre cité