@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/dist/css-inline.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"css-inline.js","sourceRoot":"","sources":["../react/css-inline.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,0EAA0E;AAE1E;;;iEAGiE;AACjE,MAAM,CAAC,MAAM,WAAW,GAAW,
|
|
1
|
+
{"version":3,"file":"css-inline.js","sourceRoot":"","sources":["../react/css-inline.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,0EAA0E;AAE1E;;;iEAGiE;AACjE,MAAM,CAAC,MAAM,WAAW,GAAW,mp8LAAmp8L,CAAA;AAEtr8L;;;yBAGyB;AACzB,MAAM,CAAC,MAAM,WAAW,GAAW,03BAA03B,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { type RowData, type Table as TableTanstack } from '@tanstack/react-table';
|
|
3
|
+
declare module '@tanstack/react-table' {
|
|
4
|
+
interface ColumnMeta<TData extends RowData, TValue> {
|
|
5
|
+
/** `nom` : colonne d'identité, la seule en encre pleine.
|
|
6
|
+
* `num` : chiffres alignés à droite, en chasse tabulaire. */
|
|
7
|
+
registre?: 'nom' | 'num';
|
|
8
|
+
/** Intitulé qui REMPLACE l'en-tête sous le point de rupture, où les
|
|
9
|
+
* colonnes s'empilent et où l'en-tête disparaît. */
|
|
10
|
+
label?: string;
|
|
11
|
+
/** Unité accolée au nombre, en plus petit. */
|
|
12
|
+
unite?: ReactNode;
|
|
13
|
+
/** Largeur de la colonne dans la grille (syntaxe grid-template-columns).
|
|
14
|
+
* Par défaut : `minmax(0, 1fr)`. */
|
|
15
|
+
largeur?: string;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export interface DataTableProps<T> {
|
|
19
|
+
table: TableTanstack<T>;
|
|
20
|
+
/** Rendu à la place des lignes quand le modèle est vide. ⚠️ C'est la LIGNE
|
|
21
|
+
* d'absence qu'on attend ici (filtre trop étroit), pas l'écran d'absence :
|
|
22
|
+
* l'en-tête doit rester visible pour qu'on puisse élargir le filtre. */
|
|
23
|
+
vide?: ReactNode;
|
|
24
|
+
/** Appelé au clic sur une ligne. Sans lui, la ligne n'est pas cliquable —
|
|
25
|
+
* et elle ne doit pas en avoir l'air. */
|
|
26
|
+
onRowClick?: (ligne: T) => void;
|
|
27
|
+
className?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function DataTable<T>({ table, vide, onRowClick, className }: DataTableProps<T>): import("react").JSX.Element;
|
|
30
|
+
//# sourceMappingURL=data-table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../react/data-table.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAEL,KAAK,OAAO,EACZ,KAAK,KAAK,IAAI,aAAa,EAC5B,MAAM,uBAAuB,CAAA;AAM9B,OAAO,QAAQ,uBAAuB,CAAC;IAErC,UAAU,UAAU,CAAC,KAAK,SAAS,OAAO,EAAE,MAAM;QAChD;sEAC8D;QAC9D,QAAQ,CAAC,EAAE,KAAK,GAAG,KAAK,CAAA;QACxB;6DACqD;QACrD,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,8CAA8C;QAC9C,KAAK,CAAC,EAAE,SAAS,CAAA;QACjB;6CACqC;QACrC,OAAO,CAAC,EAAE,MAAM,CAAA;KACjB;CACF;AAED,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;IACvB;;6EAEyE;IACzE,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;8CAC0C;IAC1C,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAA;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC,+BA+FrF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { flexRender, } from '@tanstack/react-table';
|
|
3
|
+
import { cx } from './cx.js';
|
|
4
|
+
export function DataTable({ table, vide, onRowClick, className }) {
|
|
5
|
+
const colonnes = table.getVisibleLeafColumns();
|
|
6
|
+
const gabarit = colonnes
|
|
7
|
+
.map((c) => c.columnDef.meta?.largeur ?? 'minmax(0, 1fr)')
|
|
8
|
+
.join(' ');
|
|
9
|
+
const lignes = table.getRowModel().rows;
|
|
10
|
+
return (_jsxs("div", { className: cx('zv-table', className), style: { ['--zv-cols']: gabarit }, children: [table.getHeaderGroups().map((groupe) => (_jsx("div", { className: "zv-table__head", children: groupe.headers.map((entete) => {
|
|
11
|
+
const triable = entete.column.getCanSort();
|
|
12
|
+
const sens = entete.column.getIsSorted();
|
|
13
|
+
const registre = entete.column.columnDef.meta?.registre;
|
|
14
|
+
const contenu = entete.isPlaceholder
|
|
15
|
+
? null
|
|
16
|
+
: flexRender(entete.column.columnDef.header, entete.getContext());
|
|
17
|
+
return (_jsx("div", { className: cx('zv-cell', registre === 'num' && 'zv-cell--num'), "aria-sort": sens === 'asc' ? 'ascending' : sens === 'desc' ? 'descending' : undefined, children: triable ? (_jsxs("button", { type: "button", className: "zv-sort", onClick: entete.column.getToggleSortingHandler(), children: [contenu, _jsx("span", { className: "zv-sort__mark", "aria-hidden": "true", children: sens === 'asc' ? '↑' : sens === 'desc' ? '↓' : '↕' })] })) : (contenu) }, entete.id));
|
|
18
|
+
}) }, groupe.id))), lignes.length === 0
|
|
19
|
+
? vide
|
|
20
|
+
: lignes.map((ligne) => (_jsx("div", { className: "zv-row",
|
|
21
|
+
// Le clavier suit le clic : une ligne cliquable qui n'est pas
|
|
22
|
+
// atteignable au clavier est une action inaccessible.
|
|
23
|
+
role: onRowClick ? 'button' : undefined, tabIndex: onRowClick ? 0 : undefined, style: onRowClick ? undefined : { cursor: 'default' }, onClick: onRowClick ? () => onRowClick(ligne.original) : undefined, onKeyDown: onRowClick
|
|
24
|
+
? (e) => {
|
|
25
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
26
|
+
e.preventDefault();
|
|
27
|
+
onRowClick(ligne.original);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
: undefined, children: ligne.getVisibleCells().map((cellule) => {
|
|
31
|
+
const meta = cellule.column.columnDef.meta;
|
|
32
|
+
return (_jsxs("div", { className: cx('zv-cell', meta?.registre === 'nom' && 'zv-cell--name', meta?.registre === 'num' && 'zv-cell--num'), children: [meta?.label && _jsx("span", { className: "zv-cell__label", children: meta.label }), flexRender(cellule.column.columnDef.cell, cellule.getContext()), meta?.unite && _jsx("span", { className: "zv-cell__unit", children: meta.unite })] }, cellule.id));
|
|
33
|
+
}) }, ligne.id)))] }));
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=data-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-table.js","sourceRoot":"","sources":["../react/data-table.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export * from './icon.js';
|
|
|
8
8
|
export * from './layout.js';
|
|
9
9
|
export * from './navigation.js';
|
|
10
10
|
export * from './overlays.js';
|
|
11
|
+
export * from './select-menu.js';
|
|
11
12
|
export * from './surfaces.js';
|
|
12
13
|
export * from './typography.js';
|
|
13
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../react/index.ts"],"names":[],"mappings":"AA6BA,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,SAAS,CAAA;AAEjC,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../react/index.ts"],"names":[],"mappings":"AA6BA,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,SAAS,CAAA;AAEjC,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -36,6 +36,7 @@ export * from './icon.js';
|
|
|
36
36
|
export * from './layout.js';
|
|
37
37
|
export * from './navigation.js';
|
|
38
38
|
export * from './overlays.js';
|
|
39
|
+
export * from './select-menu.js';
|
|
39
40
|
export * from './surfaces.js';
|
|
40
41
|
export * from './typography.js';
|
|
41
42
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../react/index.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,8EAA8E;AAC9E,8EAA8E;AAC9E,+EAA+E;AAC/E,EAAE;AACF,6EAA6E;AAC7E,4DAA4D;AAC5D,EAAE;AACF,gDAAgD;AAChD,6EAA6E;AAC7E,gDAAgD;AAChD,uEAAuE;AACvE,oDAAoD;AACpD,EAAE;AACF,0EAA0E;AAC1E,4EAA4E;AAC5E,uEAAuE;AACvE,wEAAwE;AACxE,yEAAyE;AACzE,sBAAsB;AACtB,EAAE;AACF,4EAA4E;AAC5E,4EAA4E;AAC5E,yEAAyE;AACzE,yCAAyC;AAEzC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,SAAS,CAAA;AAEjC,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../react/index.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,8EAA8E;AAC9E,8EAA8E;AAC9E,+EAA+E;AAC/E,EAAE;AACF,6EAA6E;AAC7E,4DAA4D;AAC5D,EAAE;AACF,gDAAgD;AAChD,6EAA6E;AAC7E,gDAAgD;AAChD,uEAAuE;AACvE,oDAAoD;AACpD,EAAE;AACF,0EAA0E;AAC1E,4EAA4E;AAC5E,uEAAuE;AACvE,wEAAwE;AACxE,yEAAyE;AACzE,sBAAsB;AACtB,EAAE;AACF,4EAA4E;AAC5E,4EAA4E;AAC5E,yEAAyE;AACzE,yCAAyC;AAEzC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,SAAS,CAAA;AAEjC,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface OptionSelect<T extends string = string> {
|
|
3
|
+
valeur: T;
|
|
4
|
+
label: ReactNode;
|
|
5
|
+
/** Texte employé pour la recherche au clavier et l'affichage du
|
|
6
|
+
* déclencheur quand `label` n'est pas une chaîne. */
|
|
7
|
+
texte?: string;
|
|
8
|
+
desactive?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface SelectMenuProps<T extends string = string> {
|
|
11
|
+
options: readonly OptionSelect<T>[];
|
|
12
|
+
valeur: T | null;
|
|
13
|
+
onChange: (valeur: T) => void;
|
|
14
|
+
/** Affiché quand rien n'est choisi. */
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
/** Identifiant du déclencheur — à faire correspondre au `htmlFor` du champ. */
|
|
17
|
+
id?: string;
|
|
18
|
+
/** Nom du contrôle, quand aucun intitulé visible ne le désigne. */
|
|
19
|
+
label?: string;
|
|
20
|
+
desactive?: boolean;
|
|
21
|
+
erreur?: boolean;
|
|
22
|
+
className?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function SelectMenu<T extends string = string>({ options, valeur, onChange, placeholder, id, label, desactive, erreur, className, }: SelectMenuProps<T>): import("react").JSX.Element;
|
|
25
|
+
//# sourceMappingURL=select-menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-menu.d.ts","sourceRoot":"","sources":["../react/select-menu.tsx"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACrD,MAAM,EAAE,CAAC,CAAA;IACT,KAAK,EAAE,SAAS,CAAA;IAChB;0DACsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACxD,OAAO,EAAE,SAAS,YAAY,CAAC,CAAC,CAAC,EAAE,CAAA;IACnC,MAAM,EAAE,CAAC,GAAG,IAAI,CAAA;IAChB,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,CAAA;IAC7B,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,+EAA+E;IAC/E,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAOD,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,EACpD,OAAO,EACP,MAAM,EACN,QAAQ,EACR,WAAwB,EACxB,EAAE,EACF,KAAK,EACL,SAAS,EACT,MAAM,EACN,SAAS,GACV,EAAE,eAAe,CAAC,CAAC,CAAC,+BAwLpB"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
// Sélection DESSINÉE — le déclencheur a l'apparence d'un champ, et la liste
|
|
4
|
+
// est peinte par le paquet.
|
|
5
|
+
//
|
|
6
|
+
// ⚠️ POURQUOI CE COMPOSANT EXISTE, ALORS QUE `Select` (natif) EST LÀ.
|
|
7
|
+
// Un <select> natif ne peut pas être habillé : sa liste déroulée est peinte
|
|
8
|
+
// par le SYSTÈME, pas par la page. Sur un macOS en mode sombre elle sort en
|
|
9
|
+
// menu noir au milieu d'une interface claire — aucun CSS ne corrige cela.
|
|
10
|
+
//
|
|
11
|
+
// ⚠️ CE QUE ÇA COÛTE, ET QUI EST PAYÉ ICI. En remplaçant le contrôle natif,
|
|
12
|
+
// on perd le clavier, l'annonce au lecteur d'écran et la liste système. Tout
|
|
13
|
+
// est réimplémenté dans ce fichier : rôles ARIA de combobox/listbox,
|
|
14
|
+
// navigation aux flèches, Origine/Fin, Échap, recherche au clavier, fermeture
|
|
15
|
+
// au clic extérieur et restitution du focus. C'est la raison pour laquelle il
|
|
16
|
+
// n'existe PAS de version « CSS seule » de ce composant : les classes posées
|
|
17
|
+
// à la main sans ce travail livrent un select inutilisable au clavier.
|
|
18
|
+
//
|
|
19
|
+
// Quand préférer `Select` (natif) : un formulaire long sur mobile, où la
|
|
20
|
+
// liste système est plus rapide à manipuler que n'importe quelle liste
|
|
21
|
+
// maison, et où le clavier logiciel s'adapte tout seul.
|
|
22
|
+
import { useCallback, useEffect, useId, useRef, useState } from 'react';
|
|
23
|
+
import { cx } from './cx.js';
|
|
24
|
+
function texteDe(o) {
|
|
25
|
+
if (!o)
|
|
26
|
+
return '';
|
|
27
|
+
return o.texte ?? (typeof o.label === 'string' ? o.label : String(o.valeur));
|
|
28
|
+
}
|
|
29
|
+
export function SelectMenu({ options, valeur, onChange, placeholder = 'Choisir…', id, label, desactive, erreur, className, }) {
|
|
30
|
+
const auto = useId();
|
|
31
|
+
const idListe = `${id ?? auto}-liste`;
|
|
32
|
+
const [ouvert, setOuvert] = useState(false);
|
|
33
|
+
// L'option SURVOLÉE au clavier, distincte de l'option CHOISIE : c'est elle
|
|
34
|
+
// que `aria-activedescendant` désigne, et elle ne devient un choix qu'à
|
|
35
|
+
// Entrée. Les confondre ferait valider au premier coup de flèche.
|
|
36
|
+
const [actif, setActif] = useState(0);
|
|
37
|
+
const ancre = useRef(null);
|
|
38
|
+
const declencheur = useRef(null);
|
|
39
|
+
const liste = useRef(null);
|
|
40
|
+
// La saisie au clavier (« ré » → Rédacteur) s'accumule et retombe après
|
|
41
|
+
// une seconde : c'est le comportement d'un <select> natif, et le perdre
|
|
42
|
+
// se remarque tout de suite sur une liste longue.
|
|
43
|
+
const frappe = useRef({ texte: '', quand: 0 });
|
|
44
|
+
const indexChoisi = options.findIndex((o) => o.valeur === valeur);
|
|
45
|
+
const choisi = indexChoisi >= 0 ? options[indexChoisi] : undefined;
|
|
46
|
+
const ouvrir = useCallback(() => {
|
|
47
|
+
if (desactive)
|
|
48
|
+
return;
|
|
49
|
+
// On s'ouvre SUR l'option courante, pas sur la première : dans une liste
|
|
50
|
+
// de vingt entrées, repartir du haut oblige à retrouver sa place.
|
|
51
|
+
setActif(indexChoisi >= 0 ? indexChoisi : 0);
|
|
52
|
+
setOuvert(true);
|
|
53
|
+
}, [desactive, indexChoisi]);
|
|
54
|
+
const fermer = useCallback((rendreLeFocus = true) => {
|
|
55
|
+
setOuvert(false);
|
|
56
|
+
if (rendreLeFocus)
|
|
57
|
+
declencheur.current?.focus();
|
|
58
|
+
}, []);
|
|
59
|
+
const choisir = useCallback((i) => {
|
|
60
|
+
const o = options[i];
|
|
61
|
+
if (!o || o.desactive)
|
|
62
|
+
return;
|
|
63
|
+
onChange(o.valeur);
|
|
64
|
+
fermer();
|
|
65
|
+
}, [options, onChange, fermer]);
|
|
66
|
+
// Clic extérieur. `pointerdown` et non `click` : un clic qui commence
|
|
67
|
+
// dehors et finit dedans ne doit pas rouvrir ce qu'il vient de fermer.
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (!ouvert)
|
|
70
|
+
return;
|
|
71
|
+
const doc = ancre.current?.ownerDocument ?? document;
|
|
72
|
+
function dehors(e) {
|
|
73
|
+
if (!ancre.current?.contains(e.target))
|
|
74
|
+
setOuvert(false);
|
|
75
|
+
}
|
|
76
|
+
doc.addEventListener('pointerdown', dehors);
|
|
77
|
+
return () => doc.removeEventListener('pointerdown', dehors);
|
|
78
|
+
}, [ouvert]);
|
|
79
|
+
// L'option active reste visible quand on parcourt une liste plus haute que
|
|
80
|
+
// son cadre.
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (!ouvert)
|
|
83
|
+
return;
|
|
84
|
+
const el = liste.current?.children[actif];
|
|
85
|
+
el?.scrollIntoView({ block: 'nearest' });
|
|
86
|
+
}, [ouvert, actif]);
|
|
87
|
+
function suivant(depuis, pas) {
|
|
88
|
+
const n = options.length;
|
|
89
|
+
for (let k = 1; k <= n; k++) {
|
|
90
|
+
const i = (depuis + pas * k + n * n) % n;
|
|
91
|
+
if (!options[i]?.desactive)
|
|
92
|
+
return i;
|
|
93
|
+
}
|
|
94
|
+
return depuis;
|
|
95
|
+
}
|
|
96
|
+
function onKeyDown(e) {
|
|
97
|
+
if (desactive)
|
|
98
|
+
return;
|
|
99
|
+
if (!ouvert) {
|
|
100
|
+
if (['Enter', ' ', 'ArrowDown', 'ArrowUp'].includes(e.key)) {
|
|
101
|
+
e.preventDefault();
|
|
102
|
+
ouvrir();
|
|
103
|
+
}
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
switch (e.key) {
|
|
107
|
+
case 'Escape':
|
|
108
|
+
e.preventDefault();
|
|
109
|
+
e.stopPropagation();
|
|
110
|
+
fermer();
|
|
111
|
+
return;
|
|
112
|
+
case 'Enter':
|
|
113
|
+
case ' ':
|
|
114
|
+
e.preventDefault();
|
|
115
|
+
choisir(actif);
|
|
116
|
+
return;
|
|
117
|
+
case 'ArrowDown':
|
|
118
|
+
e.preventDefault();
|
|
119
|
+
setActif((i) => suivant(i, 1));
|
|
120
|
+
return;
|
|
121
|
+
case 'ArrowUp':
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
setActif((i) => suivant(i, -1));
|
|
124
|
+
return;
|
|
125
|
+
case 'Home':
|
|
126
|
+
e.preventDefault();
|
|
127
|
+
setActif(suivant(-1, 1));
|
|
128
|
+
return;
|
|
129
|
+
case 'End':
|
|
130
|
+
e.preventDefault();
|
|
131
|
+
setActif(suivant(options.length, -1));
|
|
132
|
+
return;
|
|
133
|
+
case 'Tab':
|
|
134
|
+
// Tab valide et sort : c'est ce que fait un select natif, et sortir
|
|
135
|
+
// sans rien retenir surprend.
|
|
136
|
+
choisir(actif);
|
|
137
|
+
return;
|
|
138
|
+
default:
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
if (e.key.length === 1) {
|
|
142
|
+
const maintenant = Date.now();
|
|
143
|
+
const texte = (maintenant - frappe.current.quand < 1000 ? frappe.current.texte : '') +
|
|
144
|
+
e.key.toLowerCase();
|
|
145
|
+
frappe.current = { texte, quand: maintenant };
|
|
146
|
+
const i = options.findIndex((o) => !o.desactive && texteDe(o).toLowerCase().startsWith(texte));
|
|
147
|
+
if (i >= 0)
|
|
148
|
+
setActif(i);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return (_jsxs("div", { ref: ancre, className: cx('zv-select-anchor', 'zv-select-anchor--block', className), children: [_jsxs("button", { ref: declencheur, id: id, type: "button", role: "combobox", "aria-expanded": ouvert, "aria-controls": idListe, "aria-haspopup": "listbox", "aria-label": label, "aria-invalid": erreur || undefined, "aria-activedescendant": ouvert ? `${idListe}-${actif}` : undefined, disabled: desactive, "data-vide": choisi ? undefined : 'oui', className: "zv-input zv-input--trigger", onClick: () => (ouvert ? fermer() : ouvrir()), onKeyDown: onKeyDown, children: [_jsx("span", { className: "zv-trunc", children: choisi ? choisi.label : placeholder }), _jsx("span", { className: "zv-select__chevron", "aria-hidden": "true", children: "\u25BE" })] }), ouvert && (_jsx("div", { ref: liste, id: idListe, role: "listbox", className: "zv-menu", children: options.map((o, i) => (_jsx("button", { id: `${idListe}-${i}`, type: "button", role: "option", "aria-selected": o.valeur === valeur, "aria-disabled": o.desactive || undefined,
|
|
152
|
+
// ⚠️ tabIndex -1 : le focus ne quitte JAMAIS le déclencheur.
|
|
153
|
+
// C'est ce qui permet à aria-activedescendant de porter
|
|
154
|
+
// l'annonce, et à la frappe de continuer d'arriver au clavier.
|
|
155
|
+
tabIndex: -1, className: cx('zv-menu__item', i === actif && !o.desactive && 'zv-menu__item--survol'), onPointerEnter: () => !o.desactive && setActif(i), onClick: () => choisir(i), children: o.label }, o.valeur))) }))] }));
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=select-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-menu.js","sourceRoot":"","sources":["../react/select-menu.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zevra/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Design system Zevra « Encre & Papier » — tokens, CSS des composants et logos officiels.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
"types": "./dist/css-inline.d.ts",
|
|
35
35
|
"default": "./dist/css-inline.js"
|
|
36
36
|
},
|
|
37
|
+
"./react/table": {
|
|
38
|
+
"types": "./dist/data-table.d.ts",
|
|
39
|
+
"default": "./dist/data-table.js"
|
|
40
|
+
},
|
|
37
41
|
"./css": "./src/index.css",
|
|
38
42
|
"./tokens.css": "./src/tokens.css",
|
|
39
43
|
"./fonts.css": "./src/fonts.css",
|
|
@@ -66,14 +70,21 @@
|
|
|
66
70
|
"scripts": {
|
|
67
71
|
"build": "node scripts/build-icon-react.mjs && node scripts/build-css-bundle.mjs && tsc -p tsconfig.json",
|
|
68
72
|
"test": "npm run build && vitest run",
|
|
69
|
-
"prepublishOnly": "npm run build"
|
|
73
|
+
"prepublishOnly": "npm run build",
|
|
74
|
+
"storybook": "npm run build && node scripts/build-stories.mjs && storybook dev -p 6006 --no-open",
|
|
75
|
+
"build:storybook": "npm run build && node scripts/build-stories.mjs && storybook build -o storybook-static"
|
|
70
76
|
},
|
|
71
77
|
"devDependencies": {
|
|
78
|
+
"@storybook/addon-docs": "^10.5.10",
|
|
79
|
+
"@storybook/react-vite": "^10.5.10",
|
|
80
|
+
"@tanstack/react-table": "^8.21.3",
|
|
72
81
|
"@types/react": "^19.2.18",
|
|
73
82
|
"@types/react-dom": "^19.2.5",
|
|
74
83
|
"react": "^19.2.8",
|
|
75
84
|
"react-dom": "^19.2.8",
|
|
85
|
+
"storybook": "^10.5.10",
|
|
76
86
|
"typescript": "^7.0.2",
|
|
87
|
+
"vite": "^7.3.6",
|
|
77
88
|
"vitest": "^3.2.4"
|
|
78
89
|
},
|
|
79
90
|
"keywords": [
|
|
@@ -84,11 +95,15 @@
|
|
|
84
95
|
"components"
|
|
85
96
|
],
|
|
86
97
|
"peerDependencies": {
|
|
87
|
-
"react": ">=18"
|
|
98
|
+
"react": ">=18",
|
|
99
|
+
"@tanstack/react-table": ">=8"
|
|
88
100
|
},
|
|
89
101
|
"peerDependenciesMeta": {
|
|
90
102
|
"react": {
|
|
91
103
|
"optional": true
|
|
104
|
+
},
|
|
105
|
+
"@tanstack/react-table": {
|
|
106
|
+
"optional": true
|
|
92
107
|
}
|
|
93
108
|
}
|
|
94
109
|
}
|
package/react/catalogue.tsx
CHANGED
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
SidebarHead, Tabs, Topbar, TopbarTitle,
|
|
46
46
|
} from './navigation.js'
|
|
47
47
|
import { Drawer, Modal, Toast, Toasts } from './overlays.js'
|
|
48
|
+
import { SelectMenu } from './select-menu.js'
|
|
48
49
|
import { Band, Fade, Glyph, GridFloor, Halo, PanelNavy, TextOnDark, anim } from './surfaces.js'
|
|
49
50
|
import {
|
|
50
51
|
Body, CardTitle, Display, Em, H1, H2, H3, Heading, Kicker, Lead, Link, Mono, Note,
|
|
@@ -119,6 +120,27 @@ function DemoTabs() {
|
|
|
119
120
|
)
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
function DemoSelectMenu() {
|
|
124
|
+
const [role, setRole] = useState<'admin' | 'redacteur' | 'lecture'>('redacteur')
|
|
125
|
+
return (
|
|
126
|
+
<div style={{ maxWidth: 280 }}>
|
|
127
|
+
<Field label="RÔLE" htmlFor="ex-role-menu">
|
|
128
|
+
<SelectMenu
|
|
129
|
+
id="ex-role-menu"
|
|
130
|
+
valeur={role}
|
|
131
|
+
onChange={setRole}
|
|
132
|
+
options={[
|
|
133
|
+
{ valeur: 'admin', label: 'Administrateur' },
|
|
134
|
+
{ valeur: 'redacteur', label: 'Rédacteur' },
|
|
135
|
+
{ valeur: 'lecture', label: 'Lecture seule' },
|
|
136
|
+
{ valeur: 'facturation' as never, label: 'Facturation', desactive: true },
|
|
137
|
+
]}
|
|
138
|
+
/>
|
|
139
|
+
</Field>
|
|
140
|
+
</div>
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
|
|
122
144
|
function DemoMenu() {
|
|
123
145
|
const [ouvert, setOuvert] = useState(false)
|
|
124
146
|
const [valeur, setValeur] = useState('Toute la base')
|
|
@@ -454,7 +476,21 @@ export const CATALOGUE: GroupeCatalogue[] = [
|
|
|
454
476
|
id: 'select',
|
|
455
477
|
nom: 'Sélection',
|
|
456
478
|
resume:
|
|
457
|
-
'<select>
|
|
479
|
+
'Liste DESSINÉE jusqu’au bout — c’est le motif par défaut depuis le 25/08. Le <select> natif ne peut pas être habillé : sa liste est peinte par le système, et sort en menu noir sur un macOS en mode sombre. Clavier, annonce et recherche à la frappe sont réimplémentés ici.',
|
|
480
|
+
code: `<Field label="RÔLE" htmlFor="role">
|
|
481
|
+
<SelectMenu id="role" valeur={role} onChange={setRole} options={[
|
|
482
|
+
{ valeur: 'admin', label: 'Administrateur' },
|
|
483
|
+
{ valeur: 'redacteur', label: 'Rédacteur' },
|
|
484
|
+
{ valeur: 'facturation', label: 'Facturation', desactive: true },
|
|
485
|
+
]} />
|
|
486
|
+
</Field>`,
|
|
487
|
+
rendu: <DemoSelectMenu />,
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
id: 'select-natif',
|
|
491
|
+
nom: 'Sélection native',
|
|
492
|
+
resume:
|
|
493
|
+
'⚠️ À RÉSERVER aux formulaires longs sur mobile, où la liste système est plus rapide que n’importe quelle liste maison et où le clavier logiciel s’adapte seul. Partout ailleurs, préférer « Sélection » : celle-ci ne peut pas être habillée.',
|
|
458
494
|
code: `<Field label="RÔLE" htmlFor="role">
|
|
459
495
|
<Select id="role"><option>Administrateur</option>…</Select>
|
|
460
496
|
</Field>`,
|