fold-ng 0.12.0 → 0.13.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/CHANGELOG.md +236 -1
- package/README.md +8 -5
- package/fesm2022/fold-ng.mjs +629 -186
- package/fesm2022/fold-ng.mjs.map +1 -1
- package/package.json +1 -1
- package/tmp-esm2022/tsconfig.lib.tsbuildinfo +1 -1
- package/tokens/primitives.css +34 -10
- package/tokens/scales.css +91 -17
- package/tokens/semantic.css +213 -86
- package/types/fold-ng.d.ts +213 -32
- package/types/fold-ng.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,239 @@ All notable changes to **fold-ng** are documented here. The format follows
|
|
|
8
8
|
|
|
9
9
|
_Nothing yet._
|
|
10
10
|
|
|
11
|
+
## [0.13.0] - 2026-08-23
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **BREAKING — `brand` / `on-brand` entrent au catalogue (48 rôles).** La
|
|
16
|
+
marque IDENTIFIE, donc contrairement à `primary` elle ne doit pas basculer de
|
|
17
|
+
polarité : une marque teal sur la page et bleu pâle sur le rail a cessé
|
|
18
|
+
d'être la marque. `primary` faisait deux métiers contradictoires — porter la
|
|
19
|
+
marque ET les affordances de premier plan, dont la seconde doit s'éclaircir
|
|
20
|
+
sur un chrome sombre. Un sous-bloc scopé ne peut **jamais** les redéclarer, et
|
|
21
|
+
un test le vérifie.
|
|
22
|
+
|
|
23
|
+
- **BREAKING — `fold-data-table` : `narrowLayout` / `cardsAt` /
|
|
24
|
+
`rowCardChrome`, et `mobileLayout` déprécié** (retiré avant la 1.0). La
|
|
25
|
+
bascule se décide sur la largeur du **conteneur** (600px par défaut), pas sur
|
|
26
|
+
la fenêtre : une table dans un panneau de 480px sur un écran de 1920 restait
|
|
27
|
+
une table illisible. `custom` était une redondance — projeter un
|
|
28
|
+
`foldRowCard` disait déjà tout.
|
|
29
|
+
|
|
30
|
+
- **BREAKING — `surface-band` entre au catalogue (46 rôles).** Une bande ne
|
|
31
|
+
monte pas, elle **s'écarte**, et la direction dépend de la polarité du thème.
|
|
32
|
+
`fold-card` la codait en dur (`surface-hover`, et `surface-card` en sunken) —
|
|
33
|
+
une hypothèse de polarité posée dans un composant. Sur navi la bande valait
|
|
34
|
+
la couleur de la page sur une carte blanche (1,09:1) ; sur le chrome navi
|
|
35
|
+
elle valait **exactement** le corps de la carte (1,00:1). Les quatre thèmes
|
|
36
|
+
non modifiés reprennent la valeur qu'ils avaient déjà : le rendu ne bouge
|
|
37
|
+
pas, seul le rôle devient explicite. Un thème maison doit le déclarer.
|
|
38
|
+
|
|
39
|
+
- **Les bordures de navi descendent d'un cran** (`paper-300` / `paper-200`).
|
|
40
|
+
Sur un fond clair la profondeur vient du **contour**, pas du remplissage : il
|
|
41
|
+
reste moins de 10% de luminance entre le blanc et une page claire, et trois
|
|
42
|
+
niveaux n'y tiennent pas. `surface-sunken` ne bouge pas.
|
|
43
|
+
|
|
44
|
+
- **BREAKING — `justify` sépare la répartition de la densité.** `size` se
|
|
45
|
+
documentait « pure padding/typography » et décidait en douce du modèle de
|
|
46
|
+
répartition : `compact` justifiait les onglets, `comfortable` les calait à
|
|
47
|
+
gauche. Une barre `compact` épouse maintenant son contenu ;
|
|
48
|
+
`justify="stretch"` restaure l'ancien comportement.
|
|
49
|
+
|
|
50
|
+
- **BREAKING — `FoldNavLayoutContext` gagne `barCollapsed`.** Le contexte ne
|
|
51
|
+
parlait que dans un sens : la barre savait tout du layout, le layout rien de
|
|
52
|
+
la barre. `collapsed` appartient à la barre et la largeur de piste au layout,
|
|
53
|
+
et le JSDoc disait d'aller poser `--fold-nav-layout-rail-width` à la main, à
|
|
54
|
+
chaque usage. Une implémentation maison du token doit exposer `barCollapsed`.
|
|
55
|
+
|
|
56
|
+
- **BREAKING — quatre rôles s'ajoutent au catalogue de couleurs** :
|
|
57
|
+
`on-info` · `on-warning` · `on-alert` · `on-success` (41 → 45). Un thème
|
|
58
|
+
maison doit les déclarer, sinon le test de parité échoue.
|
|
59
|
+
|
|
60
|
+
Ils ferment un **P0** indépendant de navi : `emphasis="solid"` +
|
|
61
|
+
`intent="warning"` peignait `on-primary` — du blanc — sur de l'ambre, à
|
|
62
|
+
**2,4:1 sur umbra et 3,3:1 sur les quatre autres**. Même défaut sur la bulle
|
|
63
|
+
compteur de `fold-nav-tile`. La combinaison est exprimable depuis que
|
|
64
|
+
emphasis et intent sont deux axes indépendants ; rien ne la testait, parce
|
|
65
|
+
que le catalogue n'avait pas d'encre pour un remplissage de statut.
|
|
66
|
+
|
|
67
|
+
- **BREAKING — les primitives `--fold-ref-navy-*` (9) et `--fold-ref-ivory-50`
|
|
68
|
+
sont supprimées**, remplacées par les familles `graphite` / `paper` /
|
|
69
|
+
`signal` / `navyink`. Une app qui référençait une primitive navi directement
|
|
70
|
+
doit migrer.
|
|
71
|
+
|
|
72
|
+
- **BREAKING — `--fold-shadow-*` peut être redéclarée par un thème.**
|
|
73
|
+
L'invariant disait « seul le rayon varie » et rangeait l'ombre avec les
|
|
74
|
+
mesures. La vraie ligne : un thème peut changer ce à quoi une surface
|
|
75
|
+
**ressemble**, jamais où elle **se trouve**. Une ombre ne déplace pas une
|
|
76
|
+
boîte. Un thème maison qui héritait des ombres de base les garde.
|
|
77
|
+
|
|
78
|
+
- **navi 2 — « Graphite & Signal ».** navi avait deux polarités et un seul jeu
|
|
79
|
+
de rôles : son sous-bloc chrome en déclarait **17 sur 45** et héritait les 28
|
|
80
|
+
autres de la page. Le givre blanc de la page posé sur le rail sombre rendait
|
|
81
|
+
une infobulle à **1,9:1**. Huit échecs WCAG mesurés sont fermés ; `card`,
|
|
82
|
+
`sunken` et `page` valaient blanc, blanc et ivoire — une table imbriquée dans
|
|
83
|
+
une carte n'avait aucun bord — et font maintenant trois marches distinctes.
|
|
84
|
+
Le rayon passe de 1/2/3/4px à 2/4/6/8px : à 1px un coin est un artefact de
|
|
85
|
+
rendu, pas une intention.
|
|
86
|
+
|
|
87
|
+
- **BREAKING — `--fold-text-md` vaut 13px ; le corps de texte s'appelle
|
|
88
|
+
`--fold-text-base`.** Un consommateur non migré rétrécit d'un cran **en
|
|
89
|
+
silence** : c'est un rechercher/remplacer, `--fold-text-md` →
|
|
90
|
+
`--fold-text-base`, à faire avant de monter de version.
|
|
91
|
+
|
|
92
|
+
- **Le bouton `lg` cesse d'être un `md` déguisé.** Les deux préréglages
|
|
93
|
+
nommaient littéralement la même taille — l'échelle n'avait aucune marche
|
|
94
|
+
entre le corps et 20px à saisir. `lg` rend maintenant en `--fold-text-lg`.
|
|
95
|
+
|
|
96
|
+
### Added
|
|
97
|
+
|
|
98
|
+
- **Un système typographique, au contrat.** La typo était la moitié manquante
|
|
99
|
+
du design system : cinq tailles, et graisse, interligne, interlettrage et
|
|
100
|
+
famille écrits en dur composant par composant — 74, 25, 22 déclarations,
|
|
101
|
+
pour 4, 9 et 11 valeurs distinctes. Personne n'avait décidé qu'il y aurait
|
|
102
|
+
onze interlettrages ; ils se sont accumulés.
|
|
103
|
+
|
|
104
|
+
Quatre échelles nouvelles, toutes dans le test de contrat au même titre que
|
|
105
|
+
la couleur, donc une marche ne peut plus naître ou disparaître sans que le
|
|
106
|
+
catalogue le dise :
|
|
107
|
+
|
|
108
|
+
- `--fold-font-sans` · `--fold-font-mono` — deux fontes, pas de `display` :
|
|
109
|
+
rien n'en rend une. Elles restent **hors de l'axe de thème** : changer de
|
|
110
|
+
fonte re-flow une page, et seul le radius peut varier par thème.
|
|
111
|
+
- `--fold-text-2xs … 2xl` — l'échelle s'étend vers le bas et vers
|
|
112
|
+
l'intérieur (10 · 11 · 12 · 13 · 14 · 16 · 20 · 24), là où le code avait
|
|
113
|
+
des littéraux. Elle s'arrête à 24px parce que rien, ni dans la librairie
|
|
114
|
+
ni dans la galerie, ne rend plus gros.
|
|
115
|
+
- `--fold-weight-regular|medium|semibold|bold|extrabold`
|
|
116
|
+
- `--fold-leading-none|tight|snug|normal|relaxed`
|
|
117
|
+
- `--fold-tracking-tightest|tighter|tight|normal|wide|caps`
|
|
118
|
+
|
|
119
|
+
`extrabold` et `tightest` viennent de la galerie : c'est elle, pas la
|
|
120
|
+
librairie, qui rend des titres hero — 800 sur treize sites, -0.04em sur
|
|
121
|
+
cinq, toujours ensemble avec une taille fluide. Un registre d'affichage
|
|
122
|
+
cohérent que personne n'avait nommé.
|
|
123
|
+
|
|
124
|
+
- **Un rôle sémantique que rien ne peint est un rôle mort.** Le contrat
|
|
125
|
+
vérifiait l'orphelinat dans un seul sens — une primitive que rien ne pointe
|
|
126
|
+
échoue depuis longtemps, mais un rôle que les cinq thèmes déclarent et
|
|
127
|
+
qu'aucun composant ne peint ne regardait personne. Sur 45 rôles, il y en
|
|
128
|
+
avait exactement un.
|
|
129
|
+
|
|
130
|
+
- **`depth-contrast.spec.ts`** — 4,5:1 entre deux **surfaces** ne veut rien
|
|
131
|
+
dire : personne ne lit un contour. Deux planchers, par le travail que fait la
|
|
132
|
+
séparation — **structure** (contour de carte, cadre de panneau) ≥ 1,25:1 et
|
|
133
|
+
**subdivision** (bande, séparateur) ≥ 1,15:1. `lumen` est exempté avec sa
|
|
134
|
+
raison, et sa valeur épinglée plutôt que passée sous silence.
|
|
135
|
+
|
|
136
|
+
- **`chrome-contrast.spec.ts`** — douze paires de contraste, chacune un échec
|
|
137
|
+
mesuré avant la refonte, plus deux invariants structurels. Les alphas sont
|
|
138
|
+
compositées sur le fond qu'elles rencontrent vraiment : mesurer un
|
|
139
|
+
`color-mix(…, transparent)` contre rien, c'est comment une surface
|
|
140
|
+
translucide passe un test qu'elle devrait échouer. Rejoué sur l'ancien
|
|
141
|
+
navi : 10 échecs sur 14.
|
|
142
|
+
|
|
143
|
+
- **`status-ink-contrast.spec.ts`** — chaque encre de statut sur son propre
|
|
144
|
+
fond, à 4,5:1, sur les cinq thèmes. Mesurer plutôt que décréter a payé :
|
|
145
|
+
`bubbly` type `info` en azure et non en violet, donc le blanc y tombe à
|
|
146
|
+
2,8:1 et il prend l'encre sombre là où les quatre autres prennent le blanc.
|
|
147
|
+
|
|
148
|
+
- **Un sous-bloc de thème scopé doit être CLOS.** Le test de parité
|
|
149
|
+
dédupliquait les sélecteurs `[data-theme]` et ne gardait que le bloc de
|
|
150
|
+
tête — le sous-bloc chrome de navi n'était vérifié par rien, et son
|
|
151
|
+
commentaire l'assumait. Une famille se redéclare désormais entière : prendre
|
|
152
|
+
`primary` sans `on-primary`, c'est poser sur le nouveau remplissage l'encre
|
|
153
|
+
prévue pour l'autre polarité.
|
|
154
|
+
|
|
155
|
+
- **`pnpm run lint:typography`** — jumeau de `lint:spacing`, branché en
|
|
156
|
+
pre-push et dans les deux workflows. Aucun `font-size`, `font-weight`,
|
|
157
|
+
`line-height` ou `letter-spacing` littéral sous `src/components`. Porte dure
|
|
158
|
+
d'emblée : le solde est à zéro, **galerie comprise** — elle en portait 276
|
|
159
|
+
à elle seule, plus que la librairie entière — et le garde-fou lit aussi les
|
|
160
|
+
styles inline des templates.
|
|
161
|
+
|
|
162
|
+
Trois exceptions, chacune pour une raison : les huit tailles qui restent des
|
|
163
|
+
littéraux sont de la **géométrie de composant**, pas du texte (les initiales
|
|
164
|
+
d'un avatar suivent son diamètre) ; `clamp()` est du **texte fluide**, une
|
|
165
|
+
expression qui balaie l'échelle plutôt qu'une marche dessus ; et un
|
|
166
|
+
commentaire n'est pas du code.
|
|
167
|
+
|
|
168
|
+
Les indirections Sass sont **suivies, pas crues** : `_field-box.scss` route
|
|
169
|
+
ses tailles par une map, donc `font-size: map.get($s, font)` ne porte aucun
|
|
170
|
+
littéral — il vit à l'entrée de map, qu'aucun motif `font-size:` n'aurait
|
|
171
|
+
jamais vue. Chaque `map.get(…, clé)` et chaque `$variable` est résolu contre
|
|
172
|
+
les liaisons du fichier et vérifié là-bas, et une indirection qui ne résout
|
|
173
|
+
nulle part est elle-même un signalement : une valeur qu'on ne peut pas
|
|
174
|
+
suivre, c'est exactement le trou.
|
|
175
|
+
|
|
176
|
+
### Fixed
|
|
177
|
+
|
|
178
|
+
- **Un clic hors tuile ferme le `fold-nav-launcher`.** Le scrim portait bien
|
|
179
|
+
`(click)="close()"` et ne pouvait jamais se déclencher : `.nl-dialog` est
|
|
180
|
+
`position: fixed; inset: 0` par-dessus lui. Le test qui le couvrait cliquait
|
|
181
|
+
le scrim directement et passait au vert depuis toujours — jsdom n'a pas de
|
|
182
|
+
mise en page, il n'a jamais vu le recouvrement.
|
|
183
|
+
|
|
184
|
+
- **Le mode cartes de `fold-data-table` rend une vraie liste.** `auto-cards`
|
|
185
|
+
était une réécriture CSS du tableau (`display: block` sur le `<tr>`, `flex`
|
|
186
|
+
sur les cellules) — ce qui **retire le rôle implicite** des éléments de
|
|
187
|
+
tableau : la table cessait d'être une table sans devenir une liste, et le
|
|
188
|
+
`<thead>` restait en en-têtes orphelins. Une `<ul>/<li>` maintenant, avec une
|
|
189
|
+
coquille commune (contour, ton, sélection) et un gabarit par défaut en `<dl>`.
|
|
190
|
+
|
|
191
|
+
- **Le zébrage se voit sur navi** — 1,07 → 1,15:1. Et les diviseurs de ligne
|
|
192
|
+
disparaissent dès que le zébrage est actif : la rayure porte déjà la
|
|
193
|
+
séparation.
|
|
194
|
+
|
|
195
|
+
- **Une barre d'onglets repliée défile, et son libellé actif n'est plus rogné.**
|
|
196
|
+
Le repli et le défilement s'excluaient : passé une douzaine d'items, le
|
|
197
|
+
premier écrasé était l'item actif, le seul qui garde son libellé. L'infobulle
|
|
198
|
+
d'un item icône passe dans le **top layer** (`popover`), donc elle échappe au
|
|
199
|
+
débordement du scroller sans qu'il faille lui réserver de la place.
|
|
200
|
+
|
|
201
|
+
- **La typographie de la barre répond à `size` seul.** L'orientation pilotait
|
|
202
|
+
taille ET graisse, donc franchir `foldAt` avec `direction="auto"` recomposait
|
|
203
|
+
les libellés au lieu de déplacer la barre.
|
|
204
|
+
|
|
205
|
+
- **`background="surface"` + `activeStyle="fill"` : la pilule active n'est plus
|
|
206
|
+
rognée** contre l'arête basse du bandeau.
|
|
207
|
+
|
|
208
|
+
- **Le gap d'un `fold-nav-layout` suit sa propre largeur, pas la fenêtre.** Il
|
|
209
|
+
tenait sur `@media (max-width: 640px)` pendant que le pli tenait sur la
|
|
210
|
+
largeur du conteneur : un layout étroit sur grand écran gardait 16px alors
|
|
211
|
+
qu'il était replié.
|
|
212
|
+
|
|
213
|
+
- **Le header et les rails du `fold-app-shell` peignent enfin leur fond.**
|
|
214
|
+
`--fold-color-bg-header` était déclaré par les cinq thèmes et consommé par
|
|
215
|
+
**zéro composant** : le header rendait transparent sur le `:host` du shell,
|
|
216
|
+
qui peint `bg-page` — résolu **hors** de la région chrome. Sous navi, du
|
|
217
|
+
texte clair de chrome sur un fond paper ; idem pour toute bande de rail que
|
|
218
|
+
le `fold-menu` ne recouvre pas. Antérieur à navi 2 — invisible tant que la
|
|
219
|
+
page et le chrome partageaient la même polarité.
|
|
220
|
+
|
|
221
|
+
- **`--fold-font-mono` existe.** Neuf déclarations de la galerie le lisaient,
|
|
222
|
+
aucune ne le déclarait : il ne rendait que par son fallback. Quatorze autres
|
|
223
|
+
recopiaient la pile à la main.
|
|
224
|
+
|
|
225
|
+
## [0.12.1] - 2026-08-22
|
|
226
|
+
|
|
227
|
+
### Fixed
|
|
228
|
+
|
|
229
|
+
- **A panel body no longer crushes a child that clips its own overflow.**
|
|
230
|
+
`fold-panel-body` laid its children out as a flex column, where every child
|
|
231
|
+
may shrink and a child whose `overflow` is not `visible` has an automatic
|
|
232
|
+
minimum size of **zero**. `fold-danger-zone` clips its overflow to keep its
|
|
233
|
+
dividers flush with its rounded corners, so in a full panel it was measured
|
|
234
|
+
at **2px** — its two borders — with the destructive action, its heading and
|
|
235
|
+
its explanation all erased. The box reported barely any overflow, so there
|
|
236
|
+
was nothing to scroll to either: the panel looked finished and was not.
|
|
237
|
+
|
|
238
|
+
The body is now a single-column grid with `grid-auto-rows: max-content`:
|
|
239
|
+
rows are sized by their content and the box overflows, which is what a
|
|
240
|
+
scrolling column is for. Every child is protected, not only the ones we
|
|
241
|
+
thought of. `fold-danger-zone` also asks for its content-based minimum back
|
|
242
|
+
explicitly, so it survives a hand-rolled flex column too.
|
|
243
|
+
|
|
11
244
|
## [0.12.0] - 2026-08-22
|
|
12
245
|
|
|
13
246
|
### Added
|
|
@@ -1616,7 +1849,9 @@ design-token stylesheet.
|
|
|
1616
1849
|
`currentColor`; `prefers-reduced-motion` + `forced-colors` are respected;
|
|
1617
1850
|
strings localise via inputs / providers (`provideFoldPanelLabels`).
|
|
1618
1851
|
|
|
1619
|
-
[unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.
|
|
1852
|
+
[unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.13.0...HEAD
|
|
1853
|
+
[0.13.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.13.0
|
|
1854
|
+
[0.12.1]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.12.1
|
|
1620
1855
|
[0.12.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.12.0
|
|
1621
1856
|
[0.11.1]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.11.1
|
|
1622
1857
|
[0.11.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.11.0
|
package/README.md
CHANGED
|
@@ -99,11 +99,14 @@ is the umbra or lumen block with its primitive families re-pointed. Adding a
|
|
|
99
99
|
sixth is a new `[data-theme]` block in `semantic.css` plus the primitives it
|
|
100
100
|
names.
|
|
101
101
|
|
|
102
|
-
`bubbly` and `navi` also change their corners
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
sits
|
|
106
|
-
|
|
102
|
+
`bubbly` and `navi` also change their corners, and `navi` its depth — **radius
|
|
103
|
+
and elevation are the two scales a theme may re-declare**. The line is not that
|
|
104
|
+
one scale is special: a theme may change what a surface **looks like**, never
|
|
105
|
+
where it **sits**. Corner softness is a brand axis (friendly vs institutional);
|
|
106
|
+
depth is calibrated against a ground, and a shadow tuned for near-black ink is
|
|
107
|
+
a grey smear on a light page. Neither moves a box by one pixel. Type, space and
|
|
108
|
+
motion stay theme-invariant — those re-flow or re-time a page. The contract
|
|
109
|
+
test enforces that split.
|
|
107
110
|
|
|
108
111
|
`navi` is the interesting one: mixing chrome and page means one theme needs the
|
|
109
112
|
`text`/`border`/`surface` roles to differ **per region**, which a single set of
|