origam 2.18.4 → 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 +215 -0
- package/dist/src/assets/css/main.css +1 -1
- package/dist/src/assets/css/tokens/dark.css +10 -10
- package/dist/src/assets/css/tokens/light.css +5 -5
- package/dist/src/assets/css/tokens/origam-utilities.css +30 -12
- package/dist/src/assets/locales/en.json +9 -0
- package/dist/src/assets/locales/fr.json +9 -0
- package/dist/src/assets/scss/tokens/_dark.scss +10 -10
- package/dist/src/assets/scss/tokens/_light.scss +5 -5
- package/dist/src/assets/scss/tokens/_origam-utilities.scss +30 -12
- package/dist/src/components/Calendar/OrigamCalendar.vue +2 -2
- package/dist/src/components/Chart/OrigamChartMap.vue +1 -1
- package/dist/src/components/DataTable/OrigamDataTable.vue +18 -1
- package/dist/src/components/DataTable/OrigamDataTableGroupHeaderRow.vue +4 -0
- package/dist/src/components/DatePicker/OrigamDatePickerControls.vue +5 -0
- package/dist/src/components/Field/OrigamField.vue +47 -8
- package/dist/src/components/InfiniteScroll/OrigamInfiniteScroll.vue +17 -0
- package/dist/src/components/InlineEdit/OrigamInlineEdit.vue +2 -2
- package/dist/src/components/List/OrigamListGroup.vue +7 -0
- package/dist/src/components/RatingField/OrigamRatingField.vue +2 -2
- package/dist/src/components/Slide/OrigamSlideGroup.vue +5 -0
- package/package.json +1 -1
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é
|
|
@@ -89,6 +227,83 @@ les ruptures, elles, ne le sont pas — voir "Work priorities and versioning"
|
|
|
89
227
|
du `CLAUDE.md`. `origam` n'a aucun consommateur : les deux ruptures
|
|
90
228
|
ci-dessous partent en **mineure**, sans shim ni période de grâce.
|
|
91
229
|
|
|
230
|
+
### Fixed — `button-name` et `scrollable-region-focusable` (6 des 18 violations laissées de côté par le lot précédent)
|
|
231
|
+
|
|
232
|
+
Recompté sur `a11y-violations.baseline.json` avant de commencer (pas repris
|
|
233
|
+
d'un chiffre cité ailleurs) : **18 violations / 17 clés**, dont deux familles
|
|
234
|
+
explicitement laissées de côté par le lot ci-dessus.
|
|
235
|
+
|
|
236
|
+
**`button-name` (3, cause commune)** — `OrigamDataTableGroupHeaderRow`,
|
|
237
|
+
`OrigamDatePicker`, `OrigamDatePickerControls` rendaient chacun un
|
|
238
|
+
`<origam-btn icon="…">` sans `aria-label`/`aria-labelledby`/`title` : un
|
|
239
|
+
bouton icône réel, annoncé "button" et rien d'autre par un lecteur d'écran
|
|
240
|
+
(`OrigamBtn` avertit déjà de ce cas précis en dev depuis #653, mais ne
|
|
241
|
+
fabrique jamais de libellé — cf. son commentaire `isUnnamedIconOnly`, à
|
|
242
|
+
raison : un libellé deviné tairait axe sans rien dire à l'utilisateur).
|
|
243
|
+
Corrigé à la source de chaque bouton (pas dans `OrigamBtn`, qui n'a pas
|
|
244
|
+
l'information sémantique) :
|
|
245
|
+
- `OrigamDataTableGroupHeaderRow` — le bouton d'expand/collapse du groupe
|
|
246
|
+
reçoit `aria-expanded` + `aria-label` dynamique (`origam.data_table_group_header_row.{expand_group,collapse_group}`),
|
|
247
|
+
même motif que le correctif `data_table_row.{expand_row,collapse_row}`
|
|
248
|
+
déjà en place sur `OrigamDataTableRow`.
|
|
249
|
+
- `OrigamDatePickerControls` — les 3 boutons icône (bascule mois/année,
|
|
250
|
+
précédent, suivant) reçoivent chacun un `aria-label` via `useLocale()`
|
|
251
|
+
(`origam.date_picker_controls.{toggle_year,prev,next}`).
|
|
252
|
+
- `OrigamDatePicker::default` en héritait sans bouton icône propre — sa
|
|
253
|
+
Variant par défaut rend `OrigamDatePickerControls`, donc le correctif
|
|
254
|
+
ci-dessus l'assainit aussi ; son AUTRE violation (`color-contrast`,
|
|
255
|
+
hors périmètre) reste dans la baseline.
|
|
256
|
+
|
|
257
|
+
Nouvelles clés ajoutées à `en.json` ET `fr.json` dans le même commit,
|
|
258
|
+
`snake_case` minuscule, aucune chaîne en dur dans les templates.
|
|
259
|
+
|
|
260
|
+
**`scrollable-region-focusable` (3, cause commune)** — `OrigamInfiniteScroll`,
|
|
261
|
+
`OrigamInfiniteScrollIntersect` (dont la story monte elle-même un
|
|
262
|
+
`OrigamInfiniteScroll`) et `OrigamSlideGroup` rendent chacun un conteneur
|
|
263
|
+
`overflow: auto` sans jamais être atteignables au clavier quand leur contenu
|
|
264
|
+
n'a aucun descendant focusable — axe-core l'exige (technique WAI WCAG
|
|
265
|
+
SCR29).
|
|
266
|
+
|
|
267
|
+
⚠️ `tabindex="0"` inconditionnel a été essayé et écarté : `OrigamSlideGroup`
|
|
268
|
+
a un seul consommateur réel (`OrigamChipGroup`), qui slotte toujours des
|
|
269
|
+
puces focusables — y poser `tabindex` sans condition aurait inséré un arrêt
|
|
270
|
+
de tabulation redondant AVANT les items, dégradant le parcours clavier réel
|
|
271
|
+
pour corriger un cas de story synthétique. Le correctif retenu conditionne
|
|
272
|
+
donc le `tabindex` sur l'ABSENCE de descendant focusable (`focusableChildren()`,
|
|
273
|
+
déjà utilisé ailleurs dans le DS) :
|
|
274
|
+
- `OrigamInfiniteScroll` — `hasFocusableDescendant` (recalculé par
|
|
275
|
+
`MutationObserver` sur la racine, le contenu s'accumulant en continu via
|
|
276
|
+
`@load`) pilote un `:tabindex` conditionnel sur la racine.
|
|
277
|
+
- `OrigamSlideGroup` — `hasFocusableContent` (recalculé dans le même
|
|
278
|
+
`requestAnimationFrame` qui mesure déjà `isOverflowing`) pilote un
|
|
279
|
+
`:tabindex` conditionnel sur `.origam-slide-group__container`, l'élément
|
|
280
|
+
RÉELLEMENT scrollable — distinct de la racine, qui porte déjà son propre
|
|
281
|
+
`tabindex` conditionnel pour un mécanisme sans rapport (proxy de focus
|
|
282
|
+
vers le premier item, cf. `handleFocus`) qu'axe ne peut pas lire ici
|
|
283
|
+
puisque `__container` n'est pas un ancêtre de la racine.
|
|
284
|
+
- `OrigamInfiniteScrollIntersect::default` en héritait sans conteneur
|
|
285
|
+
scrollable propre — sa Variant par défaut monte un `OrigamInfiniteScroll`,
|
|
286
|
+
donc le correctif ci-dessus l'assainit aussi.
|
|
287
|
+
|
|
288
|
+
**Bilan mesuré** : baseline **18 clés/17 violations → 12 clés/12 violations**
|
|
289
|
+
(6 clés retirées : `OrigamDataTableGroupHeaderRow`, `OrigamDatePickerControls`,
|
|
290
|
+
`OrigamInfiniteScroll`, `OrigamInfiniteScrollIntersect`, `OrigamSlideGroup`,
|
|
291
|
+
et `button-name` retiré de l'entrée `OrigamDatePicker` qui garde son
|
|
292
|
+
`color-contrast`). Suite `pnpm -F @origam/tests test:a11y` complète (226
|
|
293
|
+
tests, catalogue 218/218) : **226 passed**, aucune régression sur les 36
|
|
294
|
+
composants à baseline vide. Contrôle positif exécuté sur
|
|
295
|
+
`OrigamDataTableGroupHeaderRow` : retirer `aria-expanded`/`aria-label` fait
|
|
296
|
+
échouer la porte avec `1 violation(s) a11y NOUVELLE(S) non baselinée(s) —
|
|
297
|
+
button-name` (`REAL_EXIT=1`) ; le correctif remis, la suite ciblée repasse
|
|
298
|
+
au vert. `pnpm -F origam guards` (28/28), `guards:self` (15/15),
|
|
299
|
+
`pnpm -F @origam/tests test:e2e:audit` (3/3) et `pnpm run lint`
|
|
300
|
+
(`--max-warnings 0`) verts sur le dernier commit.
|
|
301
|
+
|
|
302
|
+
**Laissé de côté, délibérément** (12 clés / 12 violations restent dans
|
|
303
|
+
`a11y-violations.baseline.json`) : `color-contrast` (8 instances, périmètre
|
|
304
|
+
d'autres agents), `aria-required-parent`/`aria-required-children`/`listitem`/
|
|
305
|
+
`aria-prohibited-attr` (un défaut chacun, cause non partagée avec ce lot).
|
|
306
|
+
|
|
92
307
|
### ⚠️ BREAKING — `click:prepend` / `click:append` retirés d'`IBtnEmits` (#443, #577)
|
|
93
308
|
|
|
94
309
|
`<OrigamBtn>` n'émet plus `click:prepend` ni `click:append` — ni au niveau du
|