@zevra/ui 0.44.0 → 0.45.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/DECISIONS.md +46 -0
- package/dist/actions.d.ts +9 -2
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +5 -5
- package/dist/actions.js.map +1 -1
- package/dist/catalogue.d.ts.map +1 -1
- package/dist/catalogue.js +18 -1
- package/dist/catalogue.js.map +1 -1
- package/dist/content.d.ts +17 -1
- package/dist/content.d.ts.map +1 -1
- package/dist/content.js +11 -3
- package/dist/content.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/cx.d.ts +9 -0
- package/dist/cx.d.ts.map +1 -1
- package/dist/cx.js +4 -0
- package/dist/cx.js.map +1 -1
- package/dist/feedback.d.ts +9 -2
- package/dist/feedback.d.ts.map +1 -1
- package/dist/feedback.js +5 -5
- package/dist/feedback.js.map +1 -1
- package/dist/forms.d.ts +13 -3
- package/dist/forms.d.ts.map +1 -1
- package/dist/forms.js +7 -7
- package/dist/forms.js.map +1 -1
- package/dist/grille.d.ts +3 -2
- package/dist/grille.d.ts.map +1 -1
- package/dist/grille.js +2 -2
- package/dist/grille.js.map +1 -1
- package/dist/icon.d.ts +5 -1
- package/dist/icon.d.ts.map +1 -1
- package/dist/icon.js +3 -3
- package/dist/icon.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/use-persisted-state.d.ts +3 -1
- package/dist/use-persisted-state.d.ts.map +1 -1
- package/dist/use-persisted-state.js +6 -3
- package/dist/use-persisted-state.js.map +1 -1
- package/package.json +5 -5
- package/react/actions.tsx +11 -1
- package/react/catalogue.tsx +37 -1
- package/react/content.tsx +22 -1
- package/react/css-inline.ts +1 -1
- package/react/cx.ts +13 -0
- package/react/feedback.tsx +11 -2
- package/react/forms.tsx +16 -7
- package/react/grille.tsx +5 -4
- package/react/icon.tsx +6 -2
- package/react/index.ts +1 -1
- package/react/use-persisted-state.ts +6 -4
- package/src/components.css +2 -2
- package/src/data.css +10 -3
- package/src/feedback.css +3 -2
- package/src/forms.css +7 -4
- package/src/navigation.css +3 -3
- package/src/tokens.css +28 -0
package/react/cx.ts
CHANGED
|
@@ -18,3 +18,16 @@ export function cx(...parts: (string | false | null | undefined)[]): string {
|
|
|
18
18
|
export function mod(base: string, variante?: string | null): string {
|
|
19
19
|
return variante ? `${base}--${variante}` : ''
|
|
20
20
|
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Les angles d'un composant (DECISIONS.md, « Les angles arrondis, en
|
|
24
|
+
* option ») : `vifs` est le défaut de la charte, `arrondis` l'option. Sans
|
|
25
|
+
* valeur, le composant suit son conteneur : c'est ce qui laisse une app
|
|
26
|
+
* entière s'arrondir d'une seule enveloppe `Angles`.
|
|
27
|
+
*/
|
|
28
|
+
export type ChoixAngles = 'vifs' | 'arrondis'
|
|
29
|
+
|
|
30
|
+
/** La classe qui redéfinit les tokens de rayon, ou rien pour suivre le conteneur. */
|
|
31
|
+
export function classeAngles(angles?: ChoixAngles | null): string {
|
|
32
|
+
return angles === 'arrondis' ? 'zv-arrondi' : angles === 'vifs' ? 'zv-vif' : ''
|
|
33
|
+
}
|
package/react/feedback.tsx
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// roue dit « attendez », cette phrase dit sur quoi.
|
|
10
10
|
|
|
11
11
|
import type { HTMLAttributes, ReactNode } from 'react'
|
|
12
|
-
import { cx } from './cx.js'
|
|
12
|
+
import { classeAngles, cx, type ChoixAngles } from './cx.js'
|
|
13
13
|
|
|
14
14
|
type Div = Omit<HTMLAttributes<HTMLDivElement>, 'className'>
|
|
15
15
|
type Span = Omit<HTMLAttributes<HTMLSpanElement>, 'className'>
|
|
@@ -25,10 +25,13 @@ export interface AlertProps extends Div {
|
|
|
25
25
|
/** `sm` resserre, `lg` amplifie : ce dernier pour le message qui REMPLACE
|
|
26
26
|
* un contenu attendu (incident, réponse impossible). */
|
|
27
27
|
taille?: 'sm' | 'normal' | 'lg'
|
|
28
|
+
/** `arrondis` (option) ou `vifs` (défaut de la charte). Sans valeur, le
|
|
29
|
+
* composant suit son conteneur : voir `Angles`. */
|
|
30
|
+
angles?: ChoixAngles
|
|
28
31
|
className?: string
|
|
29
32
|
}
|
|
30
33
|
|
|
31
|
-
export function Alert({ ton, taille = 'normal', className, ...reste }: AlertProps) {
|
|
34
|
+
export function Alert({ ton, taille = 'normal', angles, className, ...reste }: AlertProps) {
|
|
32
35
|
return (
|
|
33
36
|
<div
|
|
34
37
|
role="alert"
|
|
@@ -37,6 +40,7 @@ export function Alert({ ton, taille = 'normal', className, ...reste }: AlertProp
|
|
|
37
40
|
`zv-alert--${ton}`,
|
|
38
41
|
taille === 'sm' && 'zv-alert--sm',
|
|
39
42
|
taille === 'lg' && 'zv-alert--lg',
|
|
43
|
+
classeAngles(angles),
|
|
40
44
|
className,
|
|
41
45
|
)}
|
|
42
46
|
{...reste}
|
|
@@ -55,6 +59,9 @@ export interface BadgeProps extends Span {
|
|
|
55
59
|
gabarit?: 'micro' | 'state'
|
|
56
60
|
/** Pastille en tête, de la couleur du texte. */
|
|
57
61
|
pastille?: boolean
|
|
62
|
+
/** `arrondis` (option) ou `vifs` (défaut de la charte). Sans valeur, le
|
|
63
|
+
* composant suit son conteneur : voir `Angles`. */
|
|
64
|
+
angles?: ChoixAngles
|
|
58
65
|
className?: string
|
|
59
66
|
children?: ReactNode
|
|
60
67
|
}
|
|
@@ -65,6 +72,7 @@ export function Badge({
|
|
|
65
72
|
ton = 'neutre',
|
|
66
73
|
gabarit,
|
|
67
74
|
pastille,
|
|
75
|
+
angles,
|
|
68
76
|
className,
|
|
69
77
|
children,
|
|
70
78
|
...reste
|
|
@@ -77,6 +85,7 @@ export function Badge({
|
|
|
77
85
|
gabarit === 'micro' && 'zv-badge--micro',
|
|
78
86
|
gabarit === 'state' && 'zv-badge--state',
|
|
79
87
|
pastille && 'zv-badge--dot',
|
|
88
|
+
classeAngles(angles),
|
|
80
89
|
className,
|
|
81
90
|
)}
|
|
82
91
|
{...reste}
|
package/react/forms.tsx
CHANGED
|
@@ -20,7 +20,7 @@ import type {
|
|
|
20
20
|
SelectHTMLAttributes,
|
|
21
21
|
TextareaHTMLAttributes,
|
|
22
22
|
} from 'react'
|
|
23
|
-
import { cx } from './cx.js'
|
|
23
|
+
import { classeAngles, cx, type ChoixAngles } from './cx.js'
|
|
24
24
|
import { Icon } from './icon.js'
|
|
25
25
|
|
|
26
26
|
/* ─── Groupe de champ ──────────────────────────────────────────────── */
|
|
@@ -92,13 +92,16 @@ export interface InputProps
|
|
|
92
92
|
/** Pose `aria-invalid` : c'est lui qui rend l'erreur audible, et le CSS le
|
|
93
93
|
* suit autant que la classe. */
|
|
94
94
|
erreur?: boolean
|
|
95
|
+
/** `arrondis` (option) ou `vifs` (défaut de la charte). Sans valeur, le
|
|
96
|
+
* composant suit son conteneur : voir `Angles`. */
|
|
97
|
+
angles?: ChoixAngles
|
|
95
98
|
className?: string
|
|
96
99
|
}
|
|
97
100
|
|
|
98
|
-
export function Input({ mono, nu, erreur, className, ...reste }: InputProps) {
|
|
101
|
+
export function Input({ mono, nu, erreur, angles, className, ...reste }: InputProps) {
|
|
99
102
|
return (
|
|
100
103
|
<input
|
|
101
|
-
className={cx('zv-input', mono && 'zv-input--mono', nu && 'zv-input--bare', className)}
|
|
104
|
+
className={cx('zv-input', mono && 'zv-input--mono', nu && 'zv-input--bare', classeAngles(angles), className)}
|
|
102
105
|
aria-invalid={erreur || undefined}
|
|
103
106
|
{...reste}
|
|
104
107
|
/>
|
|
@@ -108,13 +111,16 @@ export function Input({ mono, nu, erreur, className, ...reste }: InputProps) {
|
|
|
108
111
|
export interface TextareaProps
|
|
109
112
|
extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'className'> {
|
|
110
113
|
erreur?: boolean
|
|
114
|
+
/** `arrondis` (option) ou `vifs` (défaut de la charte). Sans valeur, le
|
|
115
|
+
* composant suit son conteneur : voir `Angles`. */
|
|
116
|
+
angles?: ChoixAngles
|
|
111
117
|
className?: string
|
|
112
118
|
}
|
|
113
119
|
|
|
114
|
-
export function Textarea({ erreur, className, ...reste }: TextareaProps) {
|
|
120
|
+
export function Textarea({ erreur, angles, className, ...reste }: TextareaProps) {
|
|
115
121
|
return (
|
|
116
122
|
<textarea
|
|
117
|
-
className={cx('zv-textarea', className)}
|
|
123
|
+
className={cx('zv-textarea', classeAngles(angles), className)}
|
|
118
124
|
aria-invalid={erreur || undefined}
|
|
119
125
|
{...reste}
|
|
120
126
|
/>
|
|
@@ -135,15 +141,18 @@ export function Select({
|
|
|
135
141
|
|
|
136
142
|
export interface SearchProps
|
|
137
143
|
extends Omit<InputHTMLAttributes<HTMLInputElement>, 'className'> {
|
|
144
|
+
/** `arrondis` (option) ou `vifs` (défaut de la charte). Sans valeur, le
|
|
145
|
+
* composant suit son conteneur : voir `Angles`. */
|
|
146
|
+
angles?: ChoixAngles
|
|
138
147
|
/** Enveloppe : c'est elle qui porte le cadre et la largeur. */
|
|
139
148
|
className?: string
|
|
140
149
|
}
|
|
141
150
|
|
|
142
151
|
/** Cadre + loupe + champ nu. La loupe est dans le balisage (et non un fond
|
|
143
152
|
* CSS) pour suivre `currentColor` et rester nette en zoom. */
|
|
144
|
-
export function Search({ className, ...reste }: SearchProps) {
|
|
153
|
+
export function Search({ angles, className, ...reste }: SearchProps) {
|
|
145
154
|
return (
|
|
146
|
-
<div className={cx('zv-search', className)}>
|
|
155
|
+
<div className={cx('zv-search', classeAngles(angles), className)}>
|
|
147
156
|
<svg
|
|
148
157
|
className="zv-search__icon"
|
|
149
158
|
viewBox="0 0 13 13"
|
package/react/grille.tsx
CHANGED
|
@@ -247,8 +247,9 @@ export const TEXTES_GRILLE: TextesGrille = {
|
|
|
247
247
|
export interface DataGridProps<T> {
|
|
248
248
|
/** Identifiant STABLE du tableau : il nomme la vue enregistrée
|
|
249
249
|
* (`table:<tableId>:v1`). Deux tableaux qui le partagent partagent leur
|
|
250
|
-
* vue ; le changer fait oublier celle de tous les utilisateurs.
|
|
251
|
-
|
|
250
|
+
* vue ; le changer fait oublier celle de tous les utilisateurs. Sans
|
|
251
|
+
* lui, la vue vit le temps de la page et ne s'enregistre pas. */
|
|
252
|
+
tableId?: string
|
|
252
253
|
data: T[]
|
|
253
254
|
/** Colonnes TanStack. Chacune doit avoir un `id` ou un `accessorKey`
|
|
254
255
|
* textuel : c'est lui que la vue enregistre. `size` est la largeur
|
|
@@ -1357,7 +1358,7 @@ export function DataGrid<T>({
|
|
|
1357
1358
|
[cleIds],
|
|
1358
1359
|
)
|
|
1359
1360
|
const [vue, setVue, reinitialiserVue] = usePersistedState<VueGrille>(
|
|
1360
|
-
`table:${tableId}:v1
|
|
1361
|
+
tableId ? `table:${tableId}:v1` : null,
|
|
1361
1362
|
defaut,
|
|
1362
1363
|
reconcilier,
|
|
1363
1364
|
)
|
|
@@ -1722,7 +1723,7 @@ export function DataGrid<T>({
|
|
|
1722
1723
|
variante="fantome"
|
|
1723
1724
|
compact
|
|
1724
1725
|
icone="telecharger"
|
|
1725
|
-
onClick={() => telecharger(versCsv(table), typeof exportCsv === 'string' ? exportCsv : tableId)}
|
|
1726
|
+
onClick={() => telecharger(versCsv(table), typeof exportCsv === 'string' ? exportCsv : (tableId ?? 'export'))}
|
|
1726
1727
|
>
|
|
1727
1728
|
{t.exporter}
|
|
1728
1729
|
</Button>
|
package/react/icon.tsx
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// sur papier comme sur la bande manifeste sans déclinaison.
|
|
7
7
|
|
|
8
8
|
import type { ButtonHTMLAttributes, HTMLAttributes, ReactNode, SVGAttributes } from 'react'
|
|
9
|
-
import { cx } from './cx.js'
|
|
9
|
+
import { classeAngles, cx, type ChoixAngles } from './cx.js'
|
|
10
10
|
import { CORPS, NOMS, type IconId } from './icon-data.js'
|
|
11
11
|
|
|
12
12
|
export type { IconId }
|
|
@@ -58,6 +58,9 @@ export interface IconButtonProps
|
|
|
58
58
|
* (« Croix ») : c'est ce que le lecteur d'écran annonce. */
|
|
59
59
|
label: string
|
|
60
60
|
taille?: IconProps['taille']
|
|
61
|
+
/** `arrondis` (option) ou `vifs` (défaut de la charte). Sans valeur, le
|
|
62
|
+
* composant suit son conteneur : voir `Angles`. */
|
|
63
|
+
angles?: ChoixAngles
|
|
61
64
|
className?: string
|
|
62
65
|
children?: ReactNode
|
|
63
66
|
}
|
|
@@ -66,6 +69,7 @@ export function IconButton({
|
|
|
66
69
|
icone,
|
|
67
70
|
label,
|
|
68
71
|
taille = 'lg',
|
|
72
|
+
angles,
|
|
69
73
|
className,
|
|
70
74
|
children,
|
|
71
75
|
type = 'button',
|
|
@@ -75,7 +79,7 @@ export function IconButton({
|
|
|
75
79
|
<button
|
|
76
80
|
type={type}
|
|
77
81
|
aria-label={label}
|
|
78
|
-
className={cx('zv-icon-btn', className)}
|
|
82
|
+
className={cx('zv-icon-btn', classeAngles(angles), className)}
|
|
79
83
|
{...reste}
|
|
80
84
|
>
|
|
81
85
|
{icone ? <Icon nom={icone} taille={taille} /> : children}
|
package/react/index.ts
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
// lit : les avertissements ⚠️ signalent ce qui casse le système si on le
|
|
28
28
|
// contourne, pas de simples préférences.
|
|
29
29
|
|
|
30
|
-
export { cx, mod } from './cx.js'
|
|
30
|
+
export { cx, mod, type ChoixAngles } from './cx.js'
|
|
31
31
|
|
|
32
32
|
export * from './actions.js'
|
|
33
33
|
export * from './content.js'
|
|
@@ -27,9 +27,11 @@ import type { Dispatch, SetStateAction } from 'react'
|
|
|
27
27
|
*
|
|
28
28
|
* Rend `[valeur, setValeur, reinitialiser]` : `reinitialiser` vide la clé et
|
|
29
29
|
* revient à `initial`.
|
|
30
|
+
*
|
|
31
|
+
* Une clé `null` : un état ordinaire, qui ne lit ni n'écrit rien.
|
|
30
32
|
*/
|
|
31
33
|
export function usePersistedState<S>(
|
|
32
|
-
key: string,
|
|
34
|
+
key: string | null,
|
|
33
35
|
initial: S,
|
|
34
36
|
reconcilier?: (lu: unknown, initial: S) => S | undefined,
|
|
35
37
|
): [S, Dispatch<SetStateAction<S>>, () => void] {
|
|
@@ -53,7 +55,7 @@ export function usePersistedState<S>(
|
|
|
53
55
|
useEffect(() => {
|
|
54
56
|
let valeur: S | undefined
|
|
55
57
|
try {
|
|
56
|
-
const brut = window.localStorage.getItem(key)
|
|
58
|
+
const brut = key === null ? null : window.localStorage.getItem(key)
|
|
57
59
|
if (brut != null) {
|
|
58
60
|
const parse: unknown = JSON.parse(brut)
|
|
59
61
|
valeur = reconcilierRef.current
|
|
@@ -72,7 +74,7 @@ export function usePersistedState<S>(
|
|
|
72
74
|
useEffect(() => {
|
|
73
75
|
// Avant la lecture, l'état est `initial` : l'écrire écraserait la vue
|
|
74
76
|
// enregistrée par la vue par défaut, au premier rendu de chaque page.
|
|
75
|
-
if (!lu) return
|
|
77
|
+
if (!lu || key === null) return
|
|
76
78
|
const texte = serialiser(etat)
|
|
77
79
|
if (texte === null || texte === enregistre.current) return
|
|
78
80
|
try {
|
|
@@ -85,7 +87,7 @@ export function usePersistedState<S>(
|
|
|
85
87
|
|
|
86
88
|
const reinitialiser = useCallback(() => {
|
|
87
89
|
try {
|
|
88
|
-
window.localStorage.removeItem(key)
|
|
90
|
+
if (key !== null) window.localStorage.removeItem(key)
|
|
89
91
|
} catch {
|
|
90
92
|
// Rien à vider qu'on puisse atteindre : on revient quand même au défaut.
|
|
91
93
|
}
|
package/src/components.css
CHANGED
|
@@ -796,7 +796,7 @@
|
|
|
796
796
|
.zv-progress {
|
|
797
797
|
height: 3px;
|
|
798
798
|
background: var(--hairline);
|
|
799
|
-
border-radius:
|
|
799
|
+
border-radius: var(--r-pill);
|
|
800
800
|
overflow: hidden;
|
|
801
801
|
}
|
|
802
802
|
|
|
@@ -1129,7 +1129,7 @@
|
|
|
1129
1129
|
overflow: hidden;
|
|
1130
1130
|
background: var(--hairline);
|
|
1131
1131
|
/* Angle vif comme le reste ; aucune ombre, l'image est dans le flux. */
|
|
1132
|
-
border-radius:
|
|
1132
|
+
border-radius: var(--r-card);
|
|
1133
1133
|
}
|
|
1134
1134
|
|
|
1135
1135
|
/* Les quatre rapports du système. Un cinquième se demande, il ne s'invente
|
package/src/data.css
CHANGED
|
@@ -47,9 +47,10 @@
|
|
|
47
47
|
* Le tableau scrolle DANS son cadre : sans ce confinement, une colonne trop
|
|
48
48
|
* large fait scroller la page entière et le rail de navigation part avec.
|
|
49
49
|
* Angle vif et sans ombre : un tableau est une surface de travail, pas une
|
|
50
|
-
* carte éditoriale.
|
|
51
|
-
*
|
|
52
|
-
*
|
|
50
|
+
* carte éditoriale. Son rayon est celui d'un panneau (--r-panel, 0 par
|
|
51
|
+
* défaut) : il ne s'arrondit que sous .zv-arrondi, et le défilement interne
|
|
52
|
+
* se rogne au rayon. Ne pas le composer avec .zv-card : ce sont deux
|
|
53
|
+
* intentions différentes. */
|
|
53
54
|
|
|
54
55
|
.zv-table {
|
|
55
56
|
overflow-x: auto;
|
|
@@ -73,6 +74,7 @@
|
|
|
73
74
|
* Les colonnes souples sont en minmax(0|150px, …) : sans borne basse à 0 ou
|
|
74
75
|
* sans min-width sur la cellule, la troncature ne se déclenche jamais. */
|
|
75
76
|
--zv-cols: minmax(0, 1fr);
|
|
77
|
+
border-radius: var(--r-panel); /* 0 par défaut, arrondi sous .zv-arrondi */
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
.zv-table__head {
|
|
@@ -631,6 +633,7 @@
|
|
|
631
633
|
font-size: var(--mono);
|
|
632
634
|
font-weight: 600;
|
|
633
635
|
color: var(--ink-2);
|
|
636
|
+
border-radius: var(--r-pill); /* 0 par défaut, arrondi sous .zv-arrondi */
|
|
634
637
|
}
|
|
635
638
|
|
|
636
639
|
/* Valeur technique dans une étiquette (date normalisée, référence) : la mono
|
|
@@ -756,6 +759,7 @@
|
|
|
756
759
|
.zv-fold {
|
|
757
760
|
border: 1px solid var(--line);
|
|
758
761
|
background: var(--white);
|
|
762
|
+
border-radius: var(--r-panel); /* 0 par défaut, arrondi sous .zv-arrondi */
|
|
759
763
|
}
|
|
760
764
|
|
|
761
765
|
.zv-fold + .zv-fold {
|
|
@@ -830,6 +834,7 @@
|
|
|
830
834
|
font-weight: 600;
|
|
831
835
|
white-space: nowrap;
|
|
832
836
|
color: var(--ink-2);
|
|
837
|
+
border-radius: var(--r-pill); /* 0 par défaut, arrondi sous .zv-arrondi */
|
|
833
838
|
}
|
|
834
839
|
|
|
835
840
|
/* ─── Code ─────────────────────────────────────────────────────────────
|
|
@@ -851,6 +856,7 @@
|
|
|
851
856
|
font-size: 0.85em;
|
|
852
857
|
overflow-wrap: break-word;
|
|
853
858
|
color: var(--ink-2);
|
|
859
|
+
border-radius: var(--r-pill); /* 0 par défaut, arrondi sous .zv-arrondi */
|
|
854
860
|
}
|
|
855
861
|
|
|
856
862
|
/* En bloc. Le cadre défile en son sein, comme le tableau : une ligne longue
|
|
@@ -866,6 +872,7 @@
|
|
|
866
872
|
line-height: 1.7;
|
|
867
873
|
tab-size: 2;
|
|
868
874
|
color: var(--ink);
|
|
875
|
+
border-radius: var(--r-panel); /* 0 par défaut, arrondi sous .zv-arrondi */
|
|
869
876
|
}
|
|
870
877
|
|
|
871
878
|
/* Le <code> intérieur n'apporte que la sémantique : sans ce rappel, il
|
package/src/feedback.css
CHANGED
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
* les quatre tokens de rayon à 0. La contradiction longtemps signalée ici
|
|
76
76
|
* (un bouton arrondi au milieu de blocs vifs dans l'écran vide) est
|
|
77
77
|
* éteinte par cet arbitrage, pas par ce module. */
|
|
78
|
-
border-radius:
|
|
78
|
+
border-radius: var(--r-panel);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/* Information : le seul ton relevé en bandeau de bas de page (garanties,
|
|
@@ -206,7 +206,7 @@
|
|
|
206
206
|
/* Un état ne se coupe jamais en deux lignes : « EN CHARGE » sur deux
|
|
207
207
|
* lignes se lit comme deux états. */
|
|
208
208
|
white-space: nowrap;
|
|
209
|
-
border-radius:
|
|
209
|
+
border-radius: var(--r-pill); /* angle vif : relevé, et arbitré depuis (25/08/2026) */
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
/* Gabarit micro : niveau de log en tête de ligne, badge de la coque. À
|
|
@@ -641,6 +641,7 @@
|
|
|
641
641
|
transition:
|
|
642
642
|
opacity 140ms cubic-bezier(0.2, 0.7, 0.2, 1),
|
|
643
643
|
visibility 0s linear 140ms;
|
|
644
|
+
border-radius: var(--r-panel); /* 0 par défaut, arrondi sous .zv-arrondi */
|
|
644
645
|
}
|
|
645
646
|
|
|
646
647
|
.zv-tooltip-hit:hover > .zv-tooltip,
|
package/src/forms.css
CHANGED
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
border: 1px solid var(--line);
|
|
114
114
|
/* Angle vif : aucun rounded-* sur un seul champ des huit écrans. Posé
|
|
115
115
|
* explicitement, sinon Safari arrondit les champs de lui-même. */
|
|
116
|
-
border-radius:
|
|
116
|
+
border-radius: var(--r-btn);
|
|
117
117
|
background: var(--white);
|
|
118
118
|
padding: 9px 12px;
|
|
119
119
|
/* Un <input> n'hérite pas de la police du document : sans cette ligne, le
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
transition:
|
|
191
191
|
border-color 140ms cubic-bezier(0.2, 0.7, 0.2, 1),
|
|
192
192
|
box-shadow 140ms cubic-bezier(0.2, 0.7, 0.2, 1);
|
|
193
|
+
border-radius: var(--r-btn); /* 0 par défaut, arrondi sous .zv-arrondi */
|
|
193
194
|
}
|
|
194
195
|
|
|
195
196
|
.zv-search:hover {
|
|
@@ -331,7 +332,7 @@
|
|
|
331
332
|
min-width: 0;
|
|
332
333
|
min-height: 96px; /* sans source : voir ci-dessus */
|
|
333
334
|
border: 1px solid var(--line);
|
|
334
|
-
border-radius:
|
|
335
|
+
border-radius: var(--r-btn);
|
|
335
336
|
background: var(--white);
|
|
336
337
|
padding: 9px 12px;
|
|
337
338
|
font-family: var(--font-text);
|
|
@@ -369,6 +370,7 @@
|
|
|
369
370
|
position: relative;
|
|
370
371
|
display: inline-block;
|
|
371
372
|
max-width: 100%;
|
|
373
|
+
border-radius: var(--r-btn); /* 0 par défaut, arrondi sous .zv-arrondi */
|
|
372
374
|
}
|
|
373
375
|
|
|
374
376
|
/* Ancre pleine largeur : le cas d'un CHAMP de formulaire, où la liste doit
|
|
@@ -761,7 +763,7 @@
|
|
|
761
763
|
|
|
762
764
|
.zv-seg {
|
|
763
765
|
border: 1px solid var(--line);
|
|
764
|
-
border-radius:
|
|
766
|
+
border-radius: var(--r-btn);
|
|
765
767
|
background: var(--white);
|
|
766
768
|
padding: 4px 9px;
|
|
767
769
|
font-family: var(--font-text);
|
|
@@ -849,6 +851,7 @@
|
|
|
849
851
|
background: var(--white);
|
|
850
852
|
padding: 38px 24px;
|
|
851
853
|
cursor: pointer;
|
|
854
|
+
border-radius: var(--r-panel); /* 0 par défaut, arrondi sous .zv-arrondi */
|
|
852
855
|
}
|
|
853
856
|
|
|
854
857
|
/* Survol et survol de dépôt rendus à l'identique : la zone répond pareil que
|
|
@@ -1125,7 +1128,7 @@
|
|
|
1125
1128
|
margin-right: -6px;
|
|
1126
1129
|
padding: 0;
|
|
1127
1130
|
border: 0;
|
|
1128
|
-
border-radius:
|
|
1131
|
+
border-radius: var(--r-btn);
|
|
1129
1132
|
background: none;
|
|
1130
1133
|
color: var(--muted);
|
|
1131
1134
|
cursor: pointer;
|
package/src/navigation.css
CHANGED
|
@@ -290,7 +290,7 @@
|
|
|
290
290
|
align-items: center;
|
|
291
291
|
justify-content: center;
|
|
292
292
|
border: 1px solid var(--line);
|
|
293
|
-
border-radius:
|
|
293
|
+
border-radius: var(--r-btn);
|
|
294
294
|
background: var(--white);
|
|
295
295
|
/* base.css ne reset pas les boutons : sans police ni fond explicites, un
|
|
296
296
|
* <button> retombe sur ceux du navigateur et détonne. Même précaution que
|
|
@@ -419,7 +419,7 @@
|
|
|
419
419
|
flex-direction: column;
|
|
420
420
|
min-width: 230px;
|
|
421
421
|
border: 1px solid var(--line);
|
|
422
|
-
border-radius:
|
|
422
|
+
border-radius: var(--r-panel);
|
|
423
423
|
background: var(--white);
|
|
424
424
|
padding: 5px;
|
|
425
425
|
/* Seule ombre du chrome applicatif, et elle est justifiée : un menu flotte
|
|
@@ -614,7 +614,7 @@ a.zv-menu__item:hover {
|
|
|
614
614
|
min-width: 230px;
|
|
615
615
|
max-width: 320px;
|
|
616
616
|
border: 1px solid var(--line);
|
|
617
|
-
border-radius:
|
|
617
|
+
border-radius: var(--r-panel);
|
|
618
618
|
background: var(--white);
|
|
619
619
|
box-shadow: var(--shadow-menu);
|
|
620
620
|
padding: 14px 16px;
|
package/src/tokens.css
CHANGED
|
@@ -158,3 +158,31 @@
|
|
|
158
158
|
/* Signature */
|
|
159
159
|
--spec-filet: 56px; /* filet de spectre 56×2px devant chaque kicker */
|
|
160
160
|
}
|
|
161
|
+
|
|
162
|
+
/* ─── Les angles arrondis, en option (27/10/2026) ───────────────────
|
|
163
|
+
*
|
|
164
|
+
* HORS RELEVÉ (DECISIONS.md, « Les angles arrondis, en option ») : le
|
|
165
|
+
* défaut reste l'angle vif du 25/08. `zv-arrondi` redéfinit les quatre
|
|
166
|
+
* tokens, et une propriété personnalisée s'hérite : posée sur <html>, la
|
|
167
|
+
* classe arrondit l'app ; sur un conteneur, la zone ; sur un composant,
|
|
168
|
+
* lui seul. `zv-vif` remet un élément au carré dans une zone arrondie.
|
|
169
|
+
*
|
|
170
|
+
* Légèrement, et c'est voulu : à peu près la moitié du relevé d'avant le
|
|
171
|
+
* 25/08. Le rond de forme (pastille, radio, interrupteur) n'en dépend pas. */
|
|
172
|
+
.zv-arrondi {
|
|
173
|
+
--r-btn: 4px;
|
|
174
|
+
--r-pill: 3px;
|
|
175
|
+
--r-panel: 6px;
|
|
176
|
+
--r-card: 8px;
|
|
177
|
+
}
|
|
178
|
+
.zv-vif {
|
|
179
|
+
--r-btn: 0;
|
|
180
|
+
--r-pill: 0;
|
|
181
|
+
--r-panel: 0;
|
|
182
|
+
--r-card: 0;
|
|
183
|
+
}
|
|
184
|
+
/* L'enveloppe `Angles` : elle ne porte que les tokens, sans ajouter de
|
|
185
|
+
* boîte à la mise en page (l'héritage passe par l'arbre, pas par la boîte). */
|
|
186
|
+
.zv-angles {
|
|
187
|
+
display: contents;
|
|
188
|
+
}
|