@zevra/ui 0.43.1 → 0.44.1
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 +32 -0
- 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 +29 -3
- package/dist/data-table.d.ts.map +1 -1
- package/dist/data-table.js +58 -40
- package/dist/data-table.js.map +1 -1
- package/dist/grille.d.ts +94 -10
- package/dist/grille.d.ts.map +1 -1
- package/dist/grille.js +189 -79
- package/dist/grille.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 +1 -1
- package/react/css-inline.ts +1 -1
- package/react/data-table.tsx +76 -5
- package/react/grille.tsx +458 -167
- package/react/use-persisted-state.ts +6 -4
- package/src/data.css +71 -3
package/react/data-table.tsx
CHANGED
|
@@ -15,11 +15,12 @@
|
|
|
15
15
|
// variables. Aucune classe nouvelle n'entre par cette porte : ce sont les
|
|
16
16
|
// mêmes .zv-table / .zv-row / .zv-cell que le tableau écrit à la main.
|
|
17
17
|
|
|
18
|
-
import { Fragment, type CSSProperties, type ReactNode } from 'react'
|
|
18
|
+
import { Fragment, type CSSProperties, type DragEvent, type ReactNode } from 'react'
|
|
19
19
|
import {
|
|
20
20
|
flexRender,
|
|
21
21
|
type Column,
|
|
22
22
|
type Header,
|
|
23
|
+
type Row,
|
|
23
24
|
type RowData,
|
|
24
25
|
type Table as TableTanstack,
|
|
25
26
|
} from '@tanstack/react-table'
|
|
@@ -85,6 +86,32 @@ export interface DataTableProps<T> {
|
|
|
85
86
|
* liste). Elle porte un filet d'accent à gauche, distinct de la ligne
|
|
86
87
|
* COCHÉE, qui est une sélection pour agir. */
|
|
87
88
|
ligneActive?: (ligne: T) => boolean
|
|
89
|
+
/** Clic droit sur une ligne : l'appelant ouvre son menu contextuel aux
|
|
90
|
+
* coordonnées données. Le menu du navigateur est alors retenu. */
|
|
91
|
+
onRowContextMenu?: (ligne: T, x: number, y: number) => void
|
|
92
|
+
/** Double clic : « ouvrir pour de bon », quand le simple clic ne fait que
|
|
93
|
+
* montrer. La sélection de texte qu'il provoque est effacée. */
|
|
94
|
+
onRowDoubleClick?: (ligne: T) => void
|
|
95
|
+
/** La ligne se saisit (glisser-déposer NATIF) : l'appelant remplit le
|
|
96
|
+
* `dataTransfer`, pour ranger une pièce dans un dossier par exemple. */
|
|
97
|
+
onRowDragStart?: (ligne: T, e: DragEvent<HTMLDivElement>) => void
|
|
98
|
+
/** Les lignes à rendre, dans leur ordre, à la place du modèle de TanStack :
|
|
99
|
+
* pour un ordre que le tri ne sait pas dire (des lignes épinglées en tête
|
|
100
|
+
* quel que soit le tri). */
|
|
101
|
+
lignes?: Row<T>[]
|
|
102
|
+
/** Rangée posée en tête du corps, avant les lignes : une ligne de SAISIE. */
|
|
103
|
+
avantLignes?: ReactNode
|
|
104
|
+
/** Rangée intercalée AVANT une ligne : l'intitulé d'un groupe (une année,
|
|
105
|
+
* un mois) quand la clé change. Rien pour ne rien intercaler. */
|
|
106
|
+
intercalaire?: (ligne: Row<T>, precedente: Row<T> | undefined) => ReactNode
|
|
107
|
+
/** Sous les lignes : un pied de totaux, le déclencheur d'une liste infinie. */
|
|
108
|
+
apresLignes?: ReactNode
|
|
109
|
+
/** Rangées resserrées, pour un tableau secondaire posé dans une fiche. */
|
|
110
|
+
dense?: boolean
|
|
111
|
+
/** Le tableau REMPLIT la hauteur de son parent (une colonne flex bornée) :
|
|
112
|
+
* seules les lignes défilent, les intitulés et les filtres restent en
|
|
113
|
+
* haut. */
|
|
114
|
+
remplir?: boolean
|
|
88
115
|
className?: string
|
|
89
116
|
}
|
|
90
117
|
|
|
@@ -144,6 +171,15 @@ export function DataTable<T>({
|
|
|
144
171
|
celluleEntete,
|
|
145
172
|
sousEntete,
|
|
146
173
|
ligneActive,
|
|
174
|
+
onRowContextMenu,
|
|
175
|
+
onRowDoubleClick,
|
|
176
|
+
onRowDragStart,
|
|
177
|
+
lignes: lignesImposees,
|
|
178
|
+
avantLignes,
|
|
179
|
+
intercalaire,
|
|
180
|
+
apresLignes,
|
|
181
|
+
dense,
|
|
182
|
+
remplir,
|
|
147
183
|
className,
|
|
148
184
|
}: DataTableProps<T>) {
|
|
149
185
|
const grille = table.options.enableColumnResizing === true
|
|
@@ -154,7 +190,7 @@ export function DataTable<T>({
|
|
|
154
190
|
grille ? piste(c, reglages[c.id] != null) : (c.columnDef.meta?.largeur ?? 'minmax(0, 1fr)'),
|
|
155
191
|
)
|
|
156
192
|
.join(' ')
|
|
157
|
-
const lignes = table.getRowModel().rows
|
|
193
|
+
const lignes = lignesImposees ?? table.getRowModel().rows
|
|
158
194
|
const style: Record<string, string> = { '--zv-cols': gabarit }
|
|
159
195
|
if (grille) {
|
|
160
196
|
style['--zv-cols-somme'] = `${colonnes.reduce((s, c) => s + c.getSize(), 0)}px`
|
|
@@ -163,9 +199,10 @@ export function DataTable<T>({
|
|
|
163
199
|
|
|
164
200
|
return (
|
|
165
201
|
<div
|
|
166
|
-
className={cx('zv-table', className)}
|
|
202
|
+
className={cx('zv-table', dense && 'zv-table--dense', remplir && 'zv-table--remplir', className)}
|
|
167
203
|
style={style as CSSProperties}
|
|
168
204
|
>
|
|
205
|
+
<Haut actif={remplir}>
|
|
169
206
|
{table.getHeaderGroups().map((groupe) => (
|
|
170
207
|
<div className="zv-table__head" key={groupe.id}>
|
|
171
208
|
{groupe.headers.map((entete) => {
|
|
@@ -218,12 +255,16 @@ export function DataTable<T>({
|
|
|
218
255
|
))}
|
|
219
256
|
|
|
220
257
|
{sousEntete}
|
|
258
|
+
</Haut>
|
|
259
|
+
|
|
260
|
+
{avantLignes}
|
|
221
261
|
|
|
222
262
|
{lignes.length === 0
|
|
223
263
|
? vide
|
|
224
|
-
: lignes.map((ligne) => (
|
|
264
|
+
: lignes.map((ligne, i) => (
|
|
265
|
+
<Fragment key={ligne.id}>
|
|
266
|
+
{intercalaire?.(ligne, lignes[i - 1])}
|
|
225
267
|
<div
|
|
226
|
-
key={ligne.id}
|
|
227
268
|
className={cx(
|
|
228
269
|
'zv-row',
|
|
229
270
|
ligne.getIsSelected() && 'zv-row--selected',
|
|
@@ -236,6 +277,25 @@ export function DataTable<T>({
|
|
|
236
277
|
tabIndex={onRowClick ? 0 : undefined}
|
|
237
278
|
style={onRowClick ? undefined : { cursor: 'default' }}
|
|
238
279
|
onClick={onRowClick ? () => onRowClick(ligne.original) : undefined}
|
|
280
|
+
onContextMenu={
|
|
281
|
+
onRowContextMenu
|
|
282
|
+
? (e) => {
|
|
283
|
+
e.preventDefault()
|
|
284
|
+
onRowContextMenu(ligne.original, e.clientX, e.clientY)
|
|
285
|
+
}
|
|
286
|
+
: undefined
|
|
287
|
+
}
|
|
288
|
+
onDoubleClick={
|
|
289
|
+
onRowDoubleClick
|
|
290
|
+
? (e) => {
|
|
291
|
+
e.preventDefault()
|
|
292
|
+
e.currentTarget.ownerDocument.defaultView?.getSelection()?.removeAllRanges()
|
|
293
|
+
onRowDoubleClick(ligne.original)
|
|
294
|
+
}
|
|
295
|
+
: undefined
|
|
296
|
+
}
|
|
297
|
+
draggable={onRowDragStart ? true : undefined}
|
|
298
|
+
onDragStart={onRowDragStart ? (e) => onRowDragStart(ligne.original, e) : undefined}
|
|
239
299
|
onKeyDown={
|
|
240
300
|
onRowClick
|
|
241
301
|
? (e) => {
|
|
@@ -269,7 +329,18 @@ export function DataTable<T>({
|
|
|
269
329
|
)
|
|
270
330
|
})}
|
|
271
331
|
</div>
|
|
332
|
+
</Fragment>
|
|
272
333
|
))}
|
|
334
|
+
|
|
335
|
+
{apresLignes}
|
|
273
336
|
</div>
|
|
274
337
|
)
|
|
275
338
|
}
|
|
339
|
+
|
|
340
|
+
/** L'en-tête et les filtres, groupés dans un bloc COLLANT quand le tableau
|
|
341
|
+
* remplit son parent : sans ce bloc, chaque rangée collerait au même
|
|
342
|
+
* endroit et la seconde recouvrirait la première. Sinon, rien n'enveloppe :
|
|
343
|
+
* le balisage reste celui d'avant. */
|
|
344
|
+
function Haut({ actif, children }: { actif?: boolean; children: ReactNode }) {
|
|
345
|
+
return actif ? <div className="zv-table__haut">{children}</div> : <>{children}</>
|
|
346
|
+
}
|