laif-ds 1.0.2-app-data-grid.81 → 1.0.2-app-data-grid.87
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/CHANGELOG.md +7 -0
- package/dist/agent-docs/adoption-report.json +3 -3
- package/dist/agent-docs/components/AppDataGrid.md +10 -9
- package/dist/agent-docs/components/DatePicker.md +1 -0
- package/dist/agent-docs/components/DropdownMenu.md +2 -0
- package/dist/agent-docs/manifest.json +6 -6
- package/dist/components/ui/app-data-grid/app-data-grid.js +229 -229
- package/dist/components/ui/app-data-grid/parts/grid-filter-chips.js +57 -47
- package/dist/components/ui/app-data-grid/parts/grid-filter-editor.js +48 -44
- package/dist/components/ui/app-data-grid/parts/grid-filter-row.js +134 -130
- package/dist/components/ui/app-data-grid/parts/grid-portal-container.js +14 -0
- package/dist/components/ui/date-picker.js +36 -34
- package/dist/components/ui/dropdown-menu.js +3 -3
- package/dist/index.d.ts +46 -5
- package/package.json +1 -1
package/dist/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### 🐛 Fixed — overlay di AppDataGrid a schermo intero e toggle della riga (2026-09-23)
|
|
11
|
+
|
|
12
|
+
- **AppDataGrid**: **A schermo intero il pannello di una cella della Riga Zero si apriva SOTTO la griglia.** La radice è `fixed` a `gridZ.fullscreen` (110), e il pannello — con l'elenco degli operatori, gli `AppSelect` e il calendario del `DatePicker` dell'editor — si portalava nel `<body>` a `z-[60]`: invisibile e irraggiungibile. Ora pannello, elenco degli operatori, elenchi e calendario di `GridFilterValueEditor`, compositore «da … a …» (`GridFilterRangeComposer`) e menu delle pill (`GridFilterChips`) si montano **dentro `[data-app-data-grid]`**, risolta dal DOM (`parts/grid-portal-container.ts`), come già il pannello delle colonne. Fuori da una griglia — le parti sono export pubblici — il portale resta il `<body>`. `Escape` chiude un livello alla volta e non esce dallo schermo intero finché un overlay è aperto. Prova: `AppDataGrid/Overlay a schermo intero e toggle della riga` (hit test con `elementFromPoint` al centro di ogni overlay). ⚠️ Chi cercava `[data-grid-filter-cell-panel]` con `closest("[data-app-data-grid]") === null` deve aggiornare l'asserzione.
|
|
13
|
+
- **AppDataGrid**: ⚠️ **`toolbar.filterRowToggle.render` riceve `{ open, toggle }`** (`GridFilterRowToggleRenderProps`, nuovo slot `GridToolbarFilterRowToggleSlot`, entrambi esportati). Prima `render` non riceveva niente, e il TSDoc prometteva di governare `filterRowOpen` da fuori — prop che non esiste: lo stato della riga è locale. `open` dice se la riga è montata, `toggle` è lo stesso gesto del bottone della griglia (annuncia una volta a `onFilterRowOpenChange`). Un `render` senza parametri resta valido; `() => null` resta un errore del compilatore.
|
|
14
|
+
- **DatePicker**: nuova prop opzionale **`portalContainer?: HTMLElement | null`** — l'elemento in cui si monta il calendario (difetto: il `<body>`, come prima).
|
|
15
|
+
- **DropdownMenu**: `DropdownMenuContent` accetta **`container?: HTMLElement | null`** — l'elemento in cui si monta il menu (difetto: il `<body>`, come prima).
|
|
16
|
+
|
|
10
17
|
### 🔧 Changed — paginatore di AppDataGrid (2026-09-23)
|
|
11
18
|
|
|
12
19
|
- **AppDataGrid**: ⚠️ **Breaking-ish — il difetto di `pageSize` passa da `10` a `25`.** Chi montava la griglia paginata senza dichiarare la taglia ora vede 25 righe per pagina (e 25 scheletri durante il caricamento). La taglia resta dichiarabile dall'esterno con la prop `pageSize`, con `pagination.pageSize` o con `initialState.pagination.pageSize` (precedenza invariata: `initialState` > slot > prop). `GRID_PAGE_SIZE_OPTIONS` resta `[10, 25, 50, 100]`. Decisione esplicita del proprietario.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "1.0.0",
|
|
3
|
-
"generatedAt": "2026-09-
|
|
3
|
+
"generatedAt": "2026-09-23T10:15:22.232Z",
|
|
4
4
|
"package": {
|
|
5
5
|
"name": "laif-ds",
|
|
6
|
-
"version": "1.0.2-app-data-grid.
|
|
6
|
+
"version": "1.0.2-app-data-grid.87"
|
|
7
7
|
},
|
|
8
8
|
"summary": {
|
|
9
|
-
"scannedFiles":
|
|
9
|
+
"scannedFiles": 491,
|
|
10
10
|
"deprecatedComponentsCount": 4,
|
|
11
11
|
"deprecatedComponentsUsedCount": 2,
|
|
12
12
|
"componentsWithoutExamplesCount": 5,
|
|
@@ -62,7 +62,7 @@ Three contracts are **copied from `DataTable`, never imported**, so that migrati
|
|
|
62
62
|
| `onRowSelectionChange` | `(selection) => void` | `undefined` | Fires on every selection change. |
|
|
63
63
|
| `onCheckedRowsChange` | `(rows: TData[]) => void` | `undefined` | The selected rows, already resolved to data. |
|
|
64
64
|
| `rowClassName` | `string \| ((row: GridRow<TData>) => string)` | `undefined` | Per-row classes. The callback form is resolved internally. |
|
|
65
|
-
| `toolbar` | `GridToolbarSlots` | `undefined` | **Fase 3, live.** The shell, per slot: `search`, `fullscreen`, `filterRowToggle`, `filters`, `resetFilters`, `columns`, `actions`. ⚠️ **2026-09-23 — «visible but optional»**: `fullscreen`, `columns` and `filterRowToggle` are rendered BY DEFAULT (key omitted = the grid's own ghost button; `columns` only when the visibility map is writable, `filterRowToggle` only in `filterMode="row"`) and **`false` switches them off**; `{ render }` replaces the node. `true` and strings are compiler errors (probes in `type-probes/shell-slots.probe.tsx`). Only `search` stays always rendered. ⚠️ **`density` is NOT in that list from `adg-c12`** — the key was deleted, not moved to the opt-in family, and `toolbar={{ density: {} }}` is a `TS2353`. The "always rendered" family is therefore **two** keys, not three. Each key is a **configuration object** whose PRESENCE turns the slot on and whose optional `render` replaces the node the grid would draw. `search` is rendered **always** — declaring it only lets you substitute the node. `fullscreen`/`columns`/`filterRowToggle` are rendered by default and `false` switches them off (`columns` still needs a writable visibility map, see `onColumnVisibilityChange`). `filters`/`resetFilters`/`actions` are **absent by default**, with **different** conditions: `filters` needs the key to carry `render` or `onOpen`; `resetFilters` needs the key to carry `render` or `onReset`, because **the grid cannot tell whether the command has any effect** — page defaults never reach it (`initialState` is a seed read once, `preset` carries the user's restored view), so «differs from the defaults» is the consumer's answer and the presence of `onReset` IS that answer; `actions` renders only its `render`, with no default node. ⚠️ **`resetFilters` restores FILTERS AND SEARCH ONLY** — sorting, page size, column widths/order/visibility must survive, and since `query/preset` and `view/preset` replace wholesale, whoever implements `onReset` has to build a preset carrying the **defaults** for `filters`/`search` and the **current** values for everything else; `pageIndex` returning to 0 is inevitable and correct. It renders **after the search and before the `filters` trigger**, and it does **not** replace «Restore default view» in the actions menu: that one is the total way out of an unreadable saved view. ⚠️ **Not to be confused with the top-level `actions` PROP**, which from `adg-m3` lands in the SAME `.ml-auto` group, immediately BEFORE this slot (both now AFTER the full-screen toggle, 2026-09-23): that one is the compat rename of `DataTableProps.actions` and the grid dresses its buttons itself; this one is the consumer's own node and the grid draws nothing for it. A slot is deliberately not a `ReactNode`: `ReactNode` admits `boolean` and `string`, so `toolbar={{ search: false }}` would compile and switch search off. `search: false`, `search: "si"` and `search: { render: () => null }` are all compiler errors, proven by the **three** probes in `type-probes/shell-slots.probe.tsx` rather than by this sentence — the first two guard the **property type**, the third the **return type** (`search`/`density`/`fullscreen` use `GridToolbarAlwaysSlot`, whose `render` returns `ReactElement`, not `ReactElement | null`). ⚠️ **The type closes the form, not the intention, and that is a declared limit:** `() => null`does not compile, but`() => <></>` does and paints nothing, so a substitute node that renders nothing stays writable — excluding it would mean inspecting what a function returns, which a type does not do. |
|
|
65
|
+
| `toolbar` | `GridToolbarSlots` | `undefined` | **Fase 3, live.** The shell, per slot: `search`, `fullscreen`, `filterRowToggle`, `filters`, `resetFilters`, `columns`, `actions`. ⚠️ **2026-09-23 — «visible but optional»**: `fullscreen`, `columns` and `filterRowToggle` are rendered BY DEFAULT (key omitted = the grid's own ghost button; `columns` only when the visibility map is writable, `filterRowToggle` only in `filterMode="row"`) and **`false` switches them off**; `{ render }` replaces the node — for `filterRowToggle` `render` receives `{ open, toggle }` (`GridFilterRowToggleRenderProps`), the only way to read and change the zero row's local state from outside. `true` and strings are compiler errors (probes in `type-probes/shell-slots.probe.tsx`). Only `search` stays always rendered. ⚠️ **`density` is NOT in that list from `adg-c12`** — the key was deleted, not moved to the opt-in family, and `toolbar={{ density: {} }}` is a `TS2353`. The "always rendered" family is therefore **two** keys, not three. Each key is a **configuration object** whose PRESENCE turns the slot on and whose optional `render` replaces the node the grid would draw. `search` is rendered **always** — declaring it only lets you substitute the node. `fullscreen`/`columns`/`filterRowToggle` are rendered by default and `false` switches them off (`columns` still needs a writable visibility map, see `onColumnVisibilityChange`). `filters`/`resetFilters`/`actions` are **absent by default**, with **different** conditions: `filters` needs the key to carry `render` or `onOpen`; `resetFilters` needs the key to carry `render` or `onReset`, because **the grid cannot tell whether the command has any effect** — page defaults never reach it (`initialState` is a seed read once, `preset` carries the user's restored view), so «differs from the defaults» is the consumer's answer and the presence of `onReset` IS that answer; `actions` renders only its `render`, with no default node. ⚠️ **`resetFilters` restores FILTERS AND SEARCH ONLY** — sorting, page size, column widths/order/visibility must survive, and since `query/preset` and `view/preset` replace wholesale, whoever implements `onReset` has to build a preset carrying the **defaults** for `filters`/`search` and the **current** values for everything else; `pageIndex` returning to 0 is inevitable and correct. It renders **after the search and before the `filters` trigger**, and it does **not** replace «Restore default view» in the actions menu: that one is the total way out of an unreadable saved view. ⚠️ **Not to be confused with the top-level `actions` PROP**, which from `adg-m3` lands in the SAME `.ml-auto` group, immediately BEFORE this slot (both now AFTER the full-screen toggle, 2026-09-23): that one is the compat rename of `DataTableProps.actions` and the grid dresses its buttons itself; this one is the consumer's own node and the grid draws nothing for it. A slot is deliberately not a `ReactNode`: `ReactNode` admits `boolean` and `string`, so `toolbar={{ search: false }}` would compile and switch search off. `search: false`, `search: "si"` and `search: { render: () => null }` are all compiler errors, proven by the **three** probes in `type-probes/shell-slots.probe.tsx` rather than by this sentence — the first two guard the **property type**, the third the **return type** (`search`/`density`/`fullscreen` use `GridToolbarAlwaysSlot`, whose `render` returns `ReactElement`, not `ReactElement | null`). ⚠️ **The type closes the form, not the intention, and that is a declared limit:** `() => null`does not compile, but`() => <></>` does and paints nothing, so a substitute node that renders nothing stays writable — excluding it would mean inspecting what a function returns, which a type does not do. |
|
|
66
66
|
| `selection` | `GridSelectionSlots` | `undefined` | **Live from Fase 6.** Configures the **page-selection bar** — the band that appears **above** the scroll area (right after the filter band, the mockup's order) as soon as at least one row is ticked, and that does not exist at all while none is. ⚠️ **It used to appear UNDER it; it moved on 2026-09-03**, and the move retires a named promise — see "Page selection" below. `mode` is the one-member union `"page"` because selection is page-only (no promotion to the whole result set), which makes that decision a compile error instead of a note. `actions` is `readonly GridSelectionAction[]` — the bulk actions rendered inside the bar (`label` **without** a number, optional `icon`, `destructive?: boolean` mapped to the shared `Button`'s `destructive` variant, and `onSelect(rowIds)` receiving the **page** ids). `summary` replaces the bar's **totals band** — not the bar, and not the count: the count is the bar's accessible name via `aria-labelledby`, so a slot that replaced it would leave the group unnamed. **`summary` still passes no arguments, and that is now a decision rather than an open question**: the two things it could pass — the selected rows and their aggregates — the consumer already has from `onCheckedRowsChange` (or the `rowSelection` it controls) and from its own `aggregate` functions, so passing them here would open a second channel for the same two numbers. |
|
|
67
67
|
| `pagination` | `GridPaginationSlots` | `undefined` | **LIVE from Fase 4.** `pagination.pageSize` turns the paginator ON **and** seeds the live page size. **The precedence is decided** and resolved in ONE place (at the `useGridEngine` call): `initialState.pagination.pageSize` > `pagination.pageSize` > the top-level `pageSize` prop. **On the CLIENT branch the paginator is a read-out, not a control**: `paginated` is `never` there and the types carry no page channel, so it prints the range and the rows clause from the declared `resultTotal` and renders NO page numbers, NO first/prev/next/last and NO size select — those commands could change nothing but the wording. **It does not coexist with `groupBy`**: the render path excludes it, because grouping × pagination is the pair declared unrepresentable by `paginated?: never` (line 982) on the branch that admits `groupBy`. |
|
|
68
68
|
| `initialFullscreen` | `boolean` | `false` | **Fase 3, live.** Seeds the fullscreen state at the **first** render, so a call site that mounts with it finds `role="dialog"` immediately rather than after an effect. It is an `initial*`, not a controlled `fullscreen`: it seeds and then stops governing, so no consumer has to resynchronise a state it does not own. |
|
|
@@ -385,8 +385,8 @@ Stable hooks, independent of the i18n language:
|
|
|
385
385
|
| `[data-grid-filter-cell="<id>"]` | A cell of the zero row — one per leaf column plus `"__select"` when `checkable`, in the order of the columns, **never** with `colSpan`. Carries `data-grid-filter-cell-label` (the column's name) and `data-grid-filter-cell-applied="true"\|"false"`. Until `adg-r14` these were also the nodes the «N filters out of view» count was measured on; that indicator has been REMOVED from the toolbar and nothing reads their rects any more |
|
|
386
386
|
| `[data-grid-filter-cell-tick="<id>"]` | The zero row's **column mark**: a 1px-wide, `h-3` (12px) span pinned to the cell's LEFT edge and vertically CENTRED, `aria-hidden` and `pointer-events-none`. Present on every filter cell except the first and except a right-pinned block's edge cell. ⚠️ **It is a node and not a `box-shadow`:** an `inset` shadow covers the box's whole side, so the mark came out as tall as the cell and welded the zero row to the headers. Its height is asserted, not just its presence, because a full-height mark would satisfy a probe that only counts nodes |
|
|
387
387
|
| `[data-grid-filter-cell-trigger="<id>"]` | The one target of a filter cell: a real `<button>`, the cell's only tab stop, opening the Fase 7 filter atom in a popover. Carries `data-filter-truncated="true"\|"false"` — **always present**, so asserting its PRESENCE is green on a cell that truncates nothing — plus `title` and an `sr-only` node with the whole text **only when truncated**. **No glyph marks the cut at any width** — the ellipsis is the CSS one, drawn by `truncate` on the text span. Its `aria-label` names the operator IN FULL in both branches, even when the visible text takes the short form |
|
|
388
|
-
| `[data-grid-filter-cell-panel="<id>"]` | The popover of a filter cell.
|
|
389
|
-
| `[data-grid-toolbar-filter-row-toggle]` | The «Show / Hide filter row» button, rendered in the toolbar with `filterMode="row"` — **the DEFAULT since 2026-09-22, so it is in the toolbar of an ordinary grid**, not only of one that opted in. `aria-expanded` says whether the ZERO ROW is MOUNTED — since R13 closing it removes the `<tr>` entirely, and this button is the only way back, so it is rendered in both states. **From 2026-09-23** a DS `Button` `variant="ghost"`, and `toolbar.filterRowToggle: false` removes it
|
|
388
|
+
| `[data-grid-filter-cell-panel="<id>"]` | The popover of a filter cell. Portaled **inside `[data-app-data-grid]`** (since 2026-09-23; it was `document.body`), together with the operator list and every list / calendar of the editor inside it: at full screen a body-level panel at `z-[60]` opened BEHIND the `fixed` root at z 110. Look for it in the `document`, not under the cell. Inside: `[data-grid-filter-cell-operator="<id>"]` (the operator `<select>`, also carrying `data-grid-filter-cell-type`) and the atom's editor, named `filter-row-<id>` |
|
|
389
|
+
| `[data-grid-toolbar-filter-row-toggle]` | The «Show / Hide filter row» button, rendered in the toolbar with `filterMode="row"` — **the DEFAULT since 2026-09-22, so it is in the toolbar of an ordinary grid**, not only of one that opted in. `aria-expanded` says whether the ZERO ROW is MOUNTED — since R13 closing it removes the `<tr>` entirely, and this button is the only way back, so it is rendered in both states. **From 2026-09-23** a DS `Button` `variant="ghost"`, and `toolbar.filterRowToggle: false` removes it — and with it the ONLY way back, since the row's open state is local to the grid (there is no `filterRowOpen` prop; `onFilterRowOpenChange` only announces). To put your own command there, pass `toolbar.filterRowToggle: { render: ({ open, toggle }) => … }`: `open` is whether the row is mounted, `toggle` is the grid's own gesture (it flips the state and fires `onFilterRowOpenChange` once) |
|
|
390
390
|
| `[data-grid-toolbar]` | The toolbar row (Fase 3 **named** it; the row itself predates the phase and P6 renders it always, so it is present even at a minimal call site). `flex flex-wrap items-center gap-2` — `items-center` and no longer `items-end`, because from `adg-m3` the search cell is one line tall like the others. **From `adg-m3` it has TWO groups**: the direct children up to the filter-row indicator (what NARROWS the data), then one `.ml-auto` wrapper holding «columns», the `actions` prop's own buttons (`[data-grid-actions-row]`, from `adg-m3`), the `toolbar.actions` slot and the full-screen toggle, in that order (what changes the VIEW or takes the data out). ⚠️ **`ml-auto` only does work because the search lost `flex-1`**, and the measured four-way table is in the `play` of `AppDataGrid/Confronto`: with the field growing, `ml-auto` present or absent gives the identical layout. So a probe on the group's RIGHT edge alone is vacuous — the group ends flush right in three of the four combinations. Measure the GAP before the group instead: `gap-2` is 8px, and an auto margin that works makes it more |
|
|
391
391
|
| `[data-grid-toolbar-columns]` | The «columns» trigger — a DS `Button` `variant="ghost"`. **Visible by default from 2026-09-23, even with the key omitted**, and rendered ONLY when the visibility map can actually be written: always without the `columnVisibility` prop (the reducer writes), or with `columnVisibility` + `onColumnVisibilityChange`. `toolbar.columns: false` removes it; `render` replaces it and wins over the writability check |
|
|
392
392
|
| `[data-grid-toolbar-columns-panel]` | The popover content holding `GridColumnRegistryPanel`, owned by the grid. Portaled **inside `[data-app-data-grid]`**, not to `<body>` — at full screen a body-level panel sits outside the sentinel cycle and outside `aria-modal`, so its checkboxes are neither tab-reachable nor announced |
|
|
@@ -450,10 +450,10 @@ Stable hooks, independent of the i18n language:
|
|
|
450
450
|
| `[data-grid-filter-editor-placeholder]` | **P7.** The empty `<option>` of a select editor. Enumerate a column's choices as `select.querySelectorAll("option:not([data-grid-filter-editor-placeholder])")` |
|
|
451
451
|
| `[data-grid-filter-editor-unknown]` | **AUDIT 2026-09-09.** The synthetic `<option>` a list editor renders when the badge's value is NOT among the options the column declares. Without it the `<select>` fell back to the placeholder while the filter was active, so an applied filter looked empty. Enumerating a column's DECLARED choices therefore excludes it too: `select.querySelectorAll("option:not([data-grid-filter-editor-placeholder]):not([data-grid-filter-editor-unknown])")` |
|
|
452
452
|
| `[data-grid-filter-editor-empty]` | **P7.** A list editor whose column declares ZERO options. It is an INCOMPLETE DECLARATION and is marked as such — never a reason to fall back to a free text field, which would put back the very defect the phase repairs |
|
|
453
|
-
| `[data-grid-filter-composer="<columnId>"]` | **P7.** The «from … to …» composer (a `PopoverContent`, portaled — look for it in the `document`, not
|
|
453
|
+
| `[data-grid-filter-composer="<columnId>"]` | **P7.** The «from … to …» composer (a `PopoverContent`, portaled into the grid root that contains its anchor, or `<body>` outside a grid — look for it in the `document`, not under the anchor). Its draft is LOCAL: `Escape`, «Cancel» and a click outside throw it away without touching the state or the emission counter; `[data-grid-filter-composer-apply="<columnId>"]` is the only gesture that promotes it. Also carries `[data-grid-filter-composer-title]`, `[data-grid-filter-composer-side="from\|to"]` (whose editors are named `<columnId>-from` / `-to`) and `[data-grid-filter-composer-cancel="<columnId>"]` |
|
|
454
454
|
| `[data-grid-filter-chip-trigger="<columnId>"]` | **P7 — the chip is now ONE target.** The pill's `<button>`; accessible name «Condition on <column>: <operator> <value>», short side ≥ 44px. It also carries `data-grid-filter-chip-operator="<operator>"`, the operator id declared in the DOM. ⚠️ Inside `[data-grid-filter-chip]` there is **exactly one** focusable node — count them, do not query the accessible name: with the old `✕` still there the name query stays green because the `✕` is called something else |
|
|
455
|
-
| `[data-grid-filter-chip-edit="<columnId>"]` | **P7.** The «Edit value…» menu item; opens the composer through `onEditValue`, `disabled` without it. ⚠️ **Portaled
|
|
456
|
-
| `[data-grid-filter-chip-remove="<columnId>"]` | **P7 — same name, different node.** No longer the `✕` in the canvas: it is the «Remove» menu item, `data-variant="destructive"`, separated from «Edit value…» by a `[role="separator"]`. ⚠️ **Portaled**
|
|
455
|
+
| `[data-grid-filter-chip-edit="<columnId>"]` | **P7.** The «Edit value…» menu item; opens the composer through `onEditValue`, `disabled` without it. ⚠️ **Portaled** — into the grid root when the chips sit inside a grid (since 2026-09-23), otherwise `<body>`: look for it in the `document` |
|
|
456
|
+
| `[data-grid-filter-chip-remove="<columnId>"]` | **P7 — same name, different node.** No longer the `✕` in the canvas: it is the «Remove» menu item, `data-variant="destructive"`, separated from «Edit value…» by a `[role="separator"]`. ⚠️ **Portaled** (same rule as the item above). Both items are ≥ 44px on the short side |
|
|
457
457
|
| `[data-grid-header-filtered="<columnId>"]` | **P7.** The glyph on the header of a CONSTRAINED column — a funnel `role="img"` whose accessible name is `filters.columnFiltered`. **Shape plus name FIRST, colour added** (WCAG 1.4.1): the discriminator is still the funnel outline no other header carries, plus the accessible name; the accent tint (`text-d-primary`) is added to those, not put in their place, so a reader who does not distinguish the hue still reads the shape. A probe must key on `[data-grid-header-filtered]`, never on the colour — the token is consumer-overridable. ⚠️ **Measured price:** in the light theme `--d-primary` resolves `#64c2d1` on `#fafafa` = 1.86:1, under the 3:1 WCAG 1.4.11 asks of a graphical object, and paler than the `#7a7a7a` (3.94:1) the glyph had by inheritance. It holds only because colour carries no state here; a theme wanting 3:1 on the glyph moves `--d-primary` one step darker (measured: `#3e8b97` = 3.54:1). It is not a button: the filter is removed and edited from its own pill. It is driven by the SAME list the filter count reads, so «filtered» in the header and the chip that names it cannot diverge |
|
|
458
458
|
| `[data-grid-selection-bar]` | **Fase 6.** The page-selection bar — `role="group"` + `aria-labelledby` pointing at the visible count, **never `role="status"`** (the mockup's `CompleteSelectionBar` carries `role="status" aria-live="polite"`; the component does NOT, because the invariant is ONE live region per grid — `UnaSolaRegioneLive` counts them). **In flow ABOVE the scroll area since 2026-09-03**, between the filter band and the table band; its wire is therefore `gridStickyHeaderShadow` (downward, `0 1px`) and no longer the footer's upward one. ⚠️ **The node does not exist while nothing is selected** — not "exists with height 0": the frame is a `flex flex-col gap-2`, so an always-rendered wrapper would still cost 8px of gap, i.e. one data row for ever. Its height comes from `gridRowHeightClass[density]`, the same map the `selectionBar` addend of `gridFrameHeight` reads. **See: "Declared limit — in fullscreen the band is paid by the viewport"** below — the no-lost-row promise holds for a bounded frame, and in fullscreen it costs one row by decision |
|
|
459
459
|
| `[data-grid-selection-count]` | **Fase 6.** The visible count — «2 rows selected». Carries the `id` the bar's `aria-labelledby` points at, and the number as its attribute value. The figure is `engine.selectedPageRowIds.length`, i.e. the ticked ids the **current row model** still knows — never `Object.keys(rowSelection).length`, which survives paging and filtering. ⚠️ **From M4 it holds the count ALONE** — «2 rows selected» — because the scope moved into the sibling `[data-grid-selection-scope]`; it is also where the bar's typography starts, `text-sm font-medium` (14px / 500) as in the mockup |
|
|
@@ -1131,9 +1131,10 @@ centre: the grid was on top. The menu now takes an inline z from that token whil
|
|
|
1131
1131
|
|
|
1132
1132
|
The z-index that decides is the one on **Radix's popper wrapper**, not on the menu content: the wrapper is the
|
|
1133
1133
|
stacking context. Radix copies the content's computed z-index onto the wrapper at mount, which is why an
|
|
1134
|
-
inline z on the content reaches it — and why raising the content's z _after_ mount does nothing.
|
|
1135
|
-
|
|
1136
|
-
|
|
1134
|
+
inline z on the content reaches it — and why raising the content's z _after_ mount does nothing. The row menu keeps
|
|
1135
|
+
that inline z. Since 2026-09-23 `DropdownMenuContent` takes an additive `container` (default `<body>`), and the
|
|
1136
|
+
filter chips' menus use it to mount inside the grid root instead — the same way as the filter cell panel, the
|
|
1137
|
+
columns panel and the actions panel.
|
|
1137
1138
|
|
|
1138
1139
|
⚠️ **The density buttons' pressed state inverts fill and text**, rather than using `bg-d-muted`. In the shipped
|
|
1139
1140
|
theme `--d-muted` and `--d-background` resolve to the **same** colour, so the pressed fill measured **1.00:1**
|
|
@@ -22,6 +22,7 @@ Date picker component that supports both **single date** and **date range** sele
|
|
|
22
22
|
| `disabled` | `boolean` | `false` | Disables interactions and the popover. |
|
|
23
23
|
| `size` | `"sm" \| "default" \| "lg"` | `"default"` | Trigger size affecting height and icon size. |
|
|
24
24
|
| `clearable` | `boolean` | `false` | Show a clear (X) button to reset the selection. |
|
|
25
|
+
| `portalContainer` | `HTMLElement \| null` | `undefined` (`<body>`) | Element the calendar popover portals into. Use it when the picker lives inside a container with its own stacking context (e.g. a fixed full-screen grid), where a `<body>` portal would open behind it. |
|
|
25
26
|
| `onClear` | `() => void` | `undefined` | Callback fired when the value is cleared via the clear button. |
|
|
26
27
|
| `minDate` | `Date` | `undefined` | Minimum selectable date. Dates before this are disabled. |
|
|
27
28
|
| `maxDate` | `Date` | `undefined` | Maximum selectable date. Dates after this are disabled. |
|
|
@@ -17,6 +17,8 @@ Contextual menu built on Radix Dropdown Menu with support for submenus, checkbox
|
|
|
17
17
|
|
|
18
18
|
All components extend Radix props.
|
|
19
19
|
|
|
20
|
+
`DropdownMenuContent` also takes `container?: HTMLElement | null` — the element the menu portals into (default: `<body>`). Use it when the menu lives inside a container with its own stacking context (e.g. a fixed full-screen grid), where a `<body>` portal would open behind it.
|
|
21
|
+
|
|
20
22
|
---
|
|
21
23
|
|
|
22
24
|
## Example
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "1.1.0",
|
|
3
|
-
"generatedAt": "2026-09-
|
|
3
|
+
"generatedAt": "2026-09-23T10:15:21.679Z",
|
|
4
4
|
"package": {
|
|
5
5
|
"name": "laif-ds",
|
|
6
|
-
"version": "1.0.2-app-data-grid.
|
|
6
|
+
"version": "1.0.2-app-data-grid.87"
|
|
7
7
|
},
|
|
8
8
|
"stats": {
|
|
9
9
|
"documentedComponentCount": 97,
|
|
@@ -3025,10 +3025,10 @@
|
|
|
3025
3025
|
},
|
|
3026
3026
|
"metadata": {
|
|
3027
3027
|
"props": {
|
|
3028
|
-
"totalProps":
|
|
3028
|
+
"totalProps": 32,
|
|
3029
3029
|
"requiredPropsCount": 0,
|
|
3030
|
-
"typedPropsCount":
|
|
3031
|
-
"describedPropsCount":
|
|
3030
|
+
"typedPropsCount": 32,
|
|
3031
|
+
"describedPropsCount": 32
|
|
3032
3032
|
},
|
|
3033
3033
|
"accessibility": {
|
|
3034
3034
|
"hasCoverage": true
|
|
@@ -6549,5 +6549,5 @@
|
|
|
6549
6549
|
]
|
|
6550
6550
|
}
|
|
6551
6551
|
],
|
|
6552
|
-
"checksum": "
|
|
6552
|
+
"checksum": "dd17ac2062d7ac17ed7e5fcfa71461eb29c6d3d5fdeff193dcaac9c34da35e94"
|
|
6553
6553
|
}
|