@zevra/ui 0.6.0 → 0.8.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/dist/catalogue.d.ts.map +1 -1
- package/dist/catalogue.js +24 -1
- package/dist/catalogue.js.map +1 -1
- package/dist/css-inline.d.ts.map +1 -1
- package/dist/css-inline.js +1 -1
- package/dist/css-inline.js.map +1 -1
- package/dist/data-table.d.ts +30 -0
- package/dist/data-table.d.ts.map +1 -0
- package/dist/data-table.js +35 -0
- package/dist/data-table.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/select-menu.d.ts +25 -0
- package/dist/select-menu.d.ts.map +1 -0
- package/dist/select-menu.js +157 -0
- package/dist/select-menu.js.map +1 -0
- package/package.json +18 -3
- package/react/catalogue.tsx +37 -1
- package/react/css-inline.ts +1 -1
- package/react/data-table.tsx +153 -0
- package/react/index.ts +1 -0
- package/react/select-menu.tsx +250 -0
- package/src/base.css +3 -1
- package/src/components.css +54 -3
- package/src/data.css +45 -0
- package/src/forms.css +137 -12
- package/src/navigation.css +9 -0
- package/src/tokens.css +21 -5
- package/tokens/index.js +10 -4
package/src/forms.css
CHANGED
|
@@ -183,6 +183,15 @@
|
|
|
183
183
|
border: 1px solid var(--line);
|
|
184
184
|
background: var(--white);
|
|
185
185
|
padding-inline: 13px;
|
|
186
|
+
/* La prise de focus s'ANIME (25/08) : sans transition, le cadre sautait
|
|
187
|
+
* d'un état à l'autre et le retour se lisait comme un défaut de rendu. */
|
|
188
|
+
transition:
|
|
189
|
+
border-color 140ms cubic-bezier(0.2, 0.7, 0.2, 1),
|
|
190
|
+
box-shadow 140ms cubic-bezier(0.2, 0.7, 0.2, 1);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.zv-search:hover {
|
|
194
|
+
border-color: var(--accent-line);
|
|
186
195
|
}
|
|
187
196
|
|
|
188
197
|
/* DÉRIVÉ : la bordure de focus relevée sur .zv-input, portée par le cadre.
|
|
@@ -196,16 +205,42 @@
|
|
|
196
205
|
* · supprimer ce filet priverait la souris de tout retour, alors que le
|
|
197
206
|
* relevé lui en donne un sur les champs bordés.
|
|
198
207
|
* La redondance coûte moins cher que l'une ou l'autre perte. */
|
|
208
|
+
/* ⚠️ REPRIS le 25/08/2026 — la DA jugeait la prise de focus « boff ». Elle
|
|
209
|
+
* l'était : le cadre passait à --accent-line, un filet si pâle qu'à côté de
|
|
210
|
+
* l'anneau du champ intérieur il ne se voyait pas. Trois corrections :
|
|
211
|
+
* · le filet passe à --accent PLEIN, pas à sa version diluée ;
|
|
212
|
+
* · un halo --accent-soft de 3px double le trait — c'est lui qui rend le
|
|
213
|
+
* retour visible du coin de l'œil, sans déplacer un pixel de la mise en
|
|
214
|
+
* page (box-shadow ne prend pas de place) ;
|
|
215
|
+
* · la loupe s'allume avec le cadre : elle cesse d'être une invite grise
|
|
216
|
+
* pour devenir la marque du champ actif.
|
|
217
|
+
*
|
|
218
|
+
* L'anneau :focus-visible du champ INTÉRIEUR est neutralisé ici, et
|
|
219
|
+
* seulement ici : le cadre le remplace, et il le remplace pour la souris
|
|
220
|
+
* comme pour le clavier. C'est ce qui lève la double marque assumée jusque-là
|
|
221
|
+
* — un seul objet à l'écran, un seul retour. Le champ nu reste parfaitement
|
|
222
|
+
* repérable au clavier, puisque c'est le cadre entier qui s'allume. */
|
|
199
223
|
.zv-search:focus-within {
|
|
200
|
-
border-color: var(--accent
|
|
224
|
+
border-color: var(--accent);
|
|
225
|
+
box-shadow: 0 0 0 3px var(--accent-soft);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.zv-search:focus-within .zv-search__icon {
|
|
229
|
+
stroke: var(--accent);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.zv-search__input:focus-visible {
|
|
233
|
+
outline: none;
|
|
201
234
|
}
|
|
202
235
|
|
|
203
236
|
.zv-search__icon {
|
|
204
237
|
flex: none;
|
|
205
238
|
width: 13px;
|
|
206
239
|
height: 13px;
|
|
207
|
-
/* Même gris que le placeholder : la loupe est une invite, pas une donnée.
|
|
240
|
+
/* Même gris que le placeholder : la loupe est une invite, pas une donnée.
|
|
241
|
+
* Elle s'allume avec le cadre — voir :focus-within plus bas. */
|
|
208
242
|
stroke: var(--label);
|
|
243
|
+
transition: stroke 140ms cubic-bezier(0.2, 0.7, 0.2, 1);
|
|
209
244
|
}
|
|
210
245
|
|
|
211
246
|
.zv-search__input {
|
|
@@ -279,6 +314,63 @@
|
|
|
279
314
|
max-width: 100%;
|
|
280
315
|
}
|
|
281
316
|
|
|
317
|
+
/* Ancre pleine largeur : le cas d'un CHAMP de formulaire, où la liste doit
|
|
318
|
+
* tomber exactement sous le contrôle et faire la même largeur que lui. La
|
|
319
|
+
* variante en ligne ci-dessus reste celle des filtres, où le déclencheur se
|
|
320
|
+
* dimensionne sur son libellé. */
|
|
321
|
+
.zv-select-anchor--block {
|
|
322
|
+
display: block;
|
|
323
|
+
width: 100%;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.zv-select-anchor--block .zv-menu {
|
|
327
|
+
width: 100%;
|
|
328
|
+
min-width: 0;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/* ─── Déclencheur de sélection DESSINÉE ─────────────────────────────────
|
|
332
|
+
* ⚠️ AJOUTÉ le 25/08/2026 : « le select, faut le designer jusque dans
|
|
333
|
+
* l'affichage de la liste » (DA, sur pièces).
|
|
334
|
+
*
|
|
335
|
+
* Le <select> natif (.zv-input--select) reste dans le paquet et garde son
|
|
336
|
+
* usage — mais il ne peut PAS être habillé : la liste déroulée est peinte
|
|
337
|
+
* par le système, pas par la page. Sur un macOS en mode sombre, elle sort
|
|
338
|
+
* en menu noir au milieu d'une interface claire. Aucun CSS ne corrige cela,
|
|
339
|
+
* c'est une limite du contrôle.
|
|
340
|
+
*
|
|
341
|
+
* D'où ce déclencheur, qui a l'apparence exacte d'un champ et ouvre le
|
|
342
|
+
* .zv-menu du paquet. Ce qu'il COÛTE, et qu'il faut assumer en le
|
|
343
|
+
* choisissant : le clavier, l'annonce et la liste native sont à réimplémenter
|
|
344
|
+
* — c'est fait dans le composant React (SelectMenu), pas dans ce fichier.
|
|
345
|
+
* Un gabarit qui pose ces classes à la main sans ce travail livre un select
|
|
346
|
+
* inutilisable au clavier. Dans ce cas, prendre le natif. */
|
|
347
|
+
.zv-input--trigger {
|
|
348
|
+
display: flex;
|
|
349
|
+
align-items: center;
|
|
350
|
+
justify-content: space-between;
|
|
351
|
+
gap: 10px;
|
|
352
|
+
text-align: left;
|
|
353
|
+
line-height: 1.4;
|
|
354
|
+
cursor: pointer;
|
|
355
|
+
transition: border-color 140ms cubic-bezier(0.2, 0.7, 0.2, 1);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.zv-input--trigger:hover {
|
|
359
|
+
border-color: var(--accent-line);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/* Ouvert, le déclencheur reste marqué : sans cela, la liste flotte au-dessus
|
|
363
|
+
* d'un champ qui a l'air au repos, et on ne sait plus lequel elle sert. */
|
|
364
|
+
.zv-input--trigger[aria-expanded='true'] {
|
|
365
|
+
border-color: var(--accent);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/* Le placeholder d'un déclencheur est du texte, pas un ::placeholder : il
|
|
369
|
+
* lui faut donc sa propre teinte, celle du champ vide. */
|
|
370
|
+
.zv-input--trigger[data-vide='oui'] {
|
|
371
|
+
color: var(--label);
|
|
372
|
+
}
|
|
373
|
+
|
|
282
374
|
.zv-select {
|
|
283
375
|
display: inline-flex;
|
|
284
376
|
align-items: center;
|
|
@@ -384,37 +476,70 @@
|
|
|
384
476
|
* elle est portée par l'aplat plein et par le libellé accolé, pas par cette
|
|
385
477
|
* nuance-là. */
|
|
386
478
|
|
|
479
|
+
/* ⚠️ REDESSINÉ le 25/08/2026 — la DA a tranché « switch horrible » sur
|
|
480
|
+
* pièces, et elle avait raison sur trois points :
|
|
481
|
+
* · 28×16 avec un bouton rond de 12, c'est un jouet posé au milieu de
|
|
482
|
+
* contrôles carrés de 16px de haut ; la ligne de réglage n'avait aucune
|
|
483
|
+
* unité ;
|
|
484
|
+
* · la piste éteinte était --accent-line, un indigo très pâle : éteint et
|
|
485
|
+
* allumé se distinguaient par la SATURATION d'une même teinte, ce qui
|
|
486
|
+
* tombe au premier écran mal calibré et disparaît en daltonisme ;
|
|
487
|
+
* · le bouton rond contredisait l'arbitrage « carré » du même jour.
|
|
488
|
+
* La piste passe donc à 36×20, à angle vif, avec un filet qui la pose comme
|
|
489
|
+
* les champs voisins ; éteint elle est BLANCHE au filet gris, allumée elle
|
|
490
|
+
* est un aplat indigo plein. L'écart n'est plus une nuance, c'est un
|
|
491
|
+
* contraste. */
|
|
387
492
|
.zv-switch {
|
|
388
493
|
position: relative;
|
|
389
494
|
display: inline-block;
|
|
390
|
-
width:
|
|
391
|
-
height:
|
|
495
|
+
width: 36px;
|
|
496
|
+
height: 20px;
|
|
392
497
|
flex: none;
|
|
393
|
-
|
|
498
|
+
border: 1px solid var(--line);
|
|
499
|
+
background: var(--white);
|
|
394
500
|
/* La courbe est celle du paquet (motion.css, `--zv-easing`), recopiée en
|
|
395
501
|
* clair : forms.css ne dépend pas de motion.css et n'a pas à en dépendre
|
|
396
502
|
* pour une transition de couleur. Ce n'est PAS `ease` — le défaut d'un
|
|
397
503
|
* framework tiers n'a rien à faire dans le système. */
|
|
398
|
-
transition:
|
|
504
|
+
transition:
|
|
505
|
+
background-color 150ms cubic-bezier(0.2, 0.7, 0.2, 1),
|
|
506
|
+
border-color 150ms cubic-bezier(0.2, 0.7, 0.2, 1);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.zv-switch-hit:hover .zv-switch {
|
|
510
|
+
border-color: var(--accent-line);
|
|
399
511
|
}
|
|
400
512
|
|
|
401
513
|
.zv-switch--on {
|
|
514
|
+
border-color: var(--accent);
|
|
402
515
|
background: var(--accent);
|
|
403
516
|
}
|
|
404
517
|
|
|
518
|
+
.zv-switch-hit:hover .zv-switch--on {
|
|
519
|
+
border-color: var(--accent-deep);
|
|
520
|
+
background: var(--accent-deep);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/* Bouton CARRÉ : le rond ici n'est pas une forme porteuse de sens (ce que
|
|
524
|
+
* sont la pastille d'état ou le radio), c'était un style — il tombe avec les
|
|
525
|
+
* autres rayons. Éteint il est gris comme un contrôle inactif, allumé il
|
|
526
|
+
* passe en blanc sur l'aplat indigo. */
|
|
405
527
|
.zv-switch__knob {
|
|
406
528
|
position: absolute;
|
|
407
529
|
inset-block-start: 2px;
|
|
408
530
|
inset-inline-start: 2px;
|
|
409
|
-
width:
|
|
410
|
-
height:
|
|
411
|
-
border-radius:
|
|
412
|
-
background: var(--
|
|
413
|
-
transition:
|
|
531
|
+
width: 14px;
|
|
532
|
+
height: 14px;
|
|
533
|
+
border-radius: 0;
|
|
534
|
+
background: var(--label);
|
|
535
|
+
transition:
|
|
536
|
+
inset-inline-start 150ms cubic-bezier(0.2, 0.7, 0.2, 1),
|
|
537
|
+
background-color 150ms cubic-bezier(0.2, 0.7, 0.2, 1);
|
|
414
538
|
}
|
|
415
539
|
|
|
416
540
|
.zv-switch--on .zv-switch__knob {
|
|
417
|
-
inset-inline-start:
|
|
541
|
+
inset-inline-start: 18px;
|
|
542
|
+
background: var(--white);
|
|
418
543
|
}
|
|
419
544
|
|
|
420
545
|
/* Cible tactile portée par une enveloppe : agrandir la piste elle-même
|
package/src/navigation.css
CHANGED
|
@@ -429,6 +429,15 @@
|
|
|
429
429
|
background: var(--hairline);
|
|
430
430
|
}
|
|
431
431
|
|
|
432
|
+
/* ⚠️ Option SURVOLÉE AU CLAVIER — ajoutée le 25/08/2026 avec la sélection
|
|
433
|
+
* dessinée. Ce n'est ni :hover (la souris n'est pas dessus) ni :focus (le
|
|
434
|
+
* focus reste sur le déclencheur, c'est aria-activedescendant qui porte
|
|
435
|
+
* l'annonce). Sans cette classe, parcourir la liste aux flèches ne se voit
|
|
436
|
+
* pas : le lecteur d'écran suit, l'œil non. */
|
|
437
|
+
.zv-menu__item--survol {
|
|
438
|
+
background: var(--hairline);
|
|
439
|
+
}
|
|
440
|
+
|
|
432
441
|
.zv-menu__item:focus-visible {
|
|
433
442
|
outline-offset: -2px;
|
|
434
443
|
}
|
package/src/tokens.css
CHANGED
|
@@ -74,11 +74,27 @@
|
|
|
74
74
|
--lead: 18px;
|
|
75
75
|
--body: 15px;
|
|
76
76
|
|
|
77
|
-
/* Rayons
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
/* Rayons — ARBITRÉS À ZÉRO le 25/08/2026.
|
|
78
|
+
*
|
|
79
|
+
* La DA a tranché sur pièces : « très carré, ça fait pro et inspire
|
|
80
|
+
* confiance » ; le rond disait « flexible, jovial », qui n'est pas ce que
|
|
81
|
+
* vend Zevra. Le relevé donnait 5/3/10/16px, hérités d'un état antérieur
|
|
82
|
+
* de la charte — et déjà contredits sur place, puisque les champs de
|
|
83
|
+
* saisie, les étiquettes et les pastilles d'initiales étaient à angle vif
|
|
84
|
+
* depuis le premier jour. Les quatre tokens s'alignent sur eux.
|
|
85
|
+
*
|
|
86
|
+
* ⚠️ Les tokens RESTENT, à zéro : ils nomment quatre intentions
|
|
87
|
+
* distinctes (action, pastille, panneau flottant, carte). Le jour où la DA
|
|
88
|
+
* veut rendre de la rondeur à l'une d'elles, c'est une ligne ici — pas une
|
|
89
|
+
* chasse aux `border-radius` dans douze fichiers.
|
|
90
|
+
*
|
|
91
|
+
* ⚠️ Ce qui n'est PAS concerné : le rond de forme, qui porte du sens et
|
|
92
|
+
* non du style — pastille d'état, bouton d'interrupteur, radio, halo. Ils
|
|
93
|
+
* écrivent leur `border-radius` en clair, sans passer par un token. */
|
|
94
|
+
--r-btn: 0;
|
|
95
|
+
--r-pill: 0;
|
|
96
|
+
--r-panel: 0;
|
|
97
|
+
--r-card: 0;
|
|
82
98
|
|
|
83
99
|
/* Ombres */
|
|
84
100
|
--shadow-card: 0 2px 10px rgba(11, 16, 32, 0.05);
|
package/tokens/index.js
CHANGED
|
@@ -99,11 +99,17 @@ export const mesures = {
|
|
|
99
99
|
specFilet: '56px',
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
/** Rayons — À ZÉRO depuis l'arbitrage DA du 25/08/2026 (« très carré, ça
|
|
103
|
+
* fait pro et inspire confiance »). Les quatre clés restent : elles nomment
|
|
104
|
+
* quatre intentions distinctes, et rendre de la rondeur à l'une d'elles
|
|
105
|
+
* doit rester une ligne à changer, pas une chasse dans douze fichiers.
|
|
106
|
+
* Le rond de FORME — pastille d'état, bouton d'interrupteur, radio, halo —
|
|
107
|
+
* ne passe pas par ici : il porte du sens, pas du style. */
|
|
102
108
|
export const rayons = {
|
|
103
|
-
btn: '
|
|
104
|
-
pill: '
|
|
105
|
-
panel: '
|
|
106
|
-
card: '
|
|
109
|
+
btn: '0',
|
|
110
|
+
pill: '0',
|
|
111
|
+
panel: '0',
|
|
112
|
+
card: '0',
|
|
107
113
|
}
|
|
108
114
|
|
|
109
115
|
export const ombres = {
|