laif-ds 1.0.0 → 1.0.2-app-data-grid.76

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.
Files changed (76) hide show
  1. package/dist/CHANGELOG.md +282 -0
  2. package/dist/_virtual/index7.js +5 -2
  3. package/dist/_virtual/index8.js +2 -5
  4. package/dist/agent-docs/adoption-report.json +164 -83
  5. package/dist/agent-docs/components/AppBottomNav.md +180 -49
  6. package/dist/agent-docs/components/AppCard.md +25 -21
  7. package/dist/agent-docs/components/AppDataGrid.md +2602 -0
  8. package/dist/agent-docs/components/AppEditor.md +18 -13
  9. package/dist/agent-docs/components/AppSelect.md +50 -0
  10. package/dist/agent-docs/components/AppSidebar.md +504 -11
  11. package/dist/agent-docs/components/DataTable.md +34 -3
  12. package/dist/agent-docs/components/DatePicker.md +7 -7
  13. package/dist/agent-docs/components/FileUploader.md +12 -12
  14. package/dist/agent-docs/components/GridFilterPanel.md +112 -0
  15. package/dist/agent-docs/components/Sidebar.md +72 -1
  16. package/dist/agent-docs/components/SidebarMenuBadge.md +87 -0
  17. package/dist/agent-docs/components-list.md +47 -2
  18. package/dist/agent-docs/manifest.json +310 -36
  19. package/dist/components/design-tokens.js +138 -66
  20. package/dist/components/nav-tokens.js +41 -0
  21. package/dist/components/ui/app-bottom-nav.js +125 -130
  22. package/dist/components/ui/app-data-grid/app-data-grid.js +874 -0
  23. package/dist/components/ui/app-data-grid/engine/use-grid-column-resize.js +110 -0
  24. package/dist/components/ui/app-data-grid/engine/use-grid-engine.js +598 -0
  25. package/dist/components/ui/app-data-grid/engine/use-grid-infinite-loader.js +50 -0
  26. package/dist/components/ui/app-data-grid/engine/use-grid-virtualizer.js +90 -0
  27. package/dist/components/ui/app-data-grid/grid-aggregate.js +5 -0
  28. package/dist/components/ui/app-data-grid/grid-column-registry.js +28 -0
  29. package/dist/components/ui/app-data-grid/grid-columns.js +204 -0
  30. package/dist/components/ui/app-data-grid/grid-filter-compile.js +33 -0
  31. package/dist/components/ui/app-data-grid/grid-filter-operators.js +139 -0
  32. package/dist/components/ui/app-data-grid/grid-grouping.js +104 -0
  33. package/dist/components/ui/app-data-grid/grid-header-matrix.js +112 -0
  34. package/dist/components/ui/app-data-grid/grid-i18n.js +207 -0
  35. package/dist/components/ui/app-data-grid/grid-mount-count.js +8 -0
  36. package/dist/components/ui/app-data-grid/grid-reducer.js +200 -0
  37. package/dist/components/ui/app-data-grid/grid-result-scope.js +35 -0
  38. package/dist/components/ui/app-data-grid/grid-tokens.js +169 -0
  39. package/dist/components/ui/app-data-grid/grid-view-preset.js +97 -0
  40. package/dist/components/ui/app-data-grid/parts/grid-actions-row.js +86 -0
  41. package/dist/components/ui/app-data-grid/parts/grid-cell-text.js +67 -0
  42. package/dist/components/ui/app-data-grid/parts/grid-column-registry-panel.js +320 -0
  43. package/dist/components/ui/app-data-grid/parts/grid-density-control.js +88 -0
  44. package/dist/components/ui/app-data-grid/parts/grid-filter-chips.js +224 -0
  45. package/dist/components/ui/app-data-grid/parts/grid-filter-editor.js +197 -0
  46. package/dist/components/ui/app-data-grid/parts/grid-filter-panel.js +386 -0
  47. package/dist/components/ui/app-data-grid/parts/grid-filter-row.js +273 -0
  48. package/dist/components/ui/app-data-grid/parts/grid-fullscreen-toggle.js +29 -0
  49. package/dist/components/ui/app-data-grid/parts/grid-group-row.js +135 -0
  50. package/dist/components/ui/app-data-grid/parts/grid-header.js +338 -0
  51. package/dist/components/ui/app-data-grid/parts/grid-pagination-control.js +218 -0
  52. package/dist/components/ui/app-data-grid/parts/grid-row.js +181 -0
  53. package/dist/components/ui/app-data-grid/parts/grid-scroll-area.js +186 -0
  54. package/dist/components/ui/app-data-grid/parts/grid-selection-bar.js +195 -0
  55. package/dist/components/ui/app-data-grid/parts/grid-status-surface.js +66 -0
  56. package/dist/components/ui/app-data-grid/parts/grid-table.js +482 -0
  57. package/dist/components/ui/app-data-grid/parts/grid-toolbar-slots.js +192 -0
  58. package/dist/components/ui/app-data-grid/use-grid-filters.js +173 -0
  59. package/dist/components/ui/app-select.js +332 -222
  60. package/dist/components/ui/app-sidebar-mobile.js +119 -104
  61. package/dist/components/ui/app-sidebar.js +516 -313
  62. package/dist/components/ui/button.js +2 -1
  63. package/dist/components/ui/gantt/components/Chart/Chart.js +1 -1
  64. package/dist/components/ui/nav-badge.js +66 -0
  65. package/dist/components/ui/sidebar.js +272 -207
  66. package/dist/components/ui/tables/data-cross-table/data-cross-table.js +6 -6
  67. package/dist/components/ui/tables/data-table/data-table-constants.js +36 -16
  68. package/dist/components/ui/tables/data-table/data-table-i18n.js +135 -1
  69. package/dist/css-for-template.css +27 -0
  70. package/dist/index.d.ts +5872 -144
  71. package/dist/index.js +473 -406
  72. package/dist/node_modules/eventemitter3/index2.js +1 -1
  73. package/dist/styles.css +2 -1
  74. package/dist/styles.v3.css +1 -1
  75. package/package.json +25 -7
  76. /package/dist/agent-docs/components/{truncated-cell.md → TruncatedCell.md} +0 -0
@@ -43,13 +43,13 @@ Date picker component that supports both **single date** and **date range** sele
43
43
 
44
44
  ### Single Mode Props (mode="single" or undefined)
45
45
 
46
- | Prop | Type | Default | Description |
47
- | ------------- | ----------------------------------- | ----------- | ------------------------------------------------------------- |
48
- | `value` | `Date` | `undefined` | Controlled selected date. |
49
- | `onChange` | `(date: Date \| undefined) => void` | `undefined` | Called when the date changes. |
50
- | `showTime` | `boolean` | `false` | Show time picker columns (HH, MM) alongside the calendar. |
51
- | `withSeconds` | `boolean` | `false` | Show seconds column in the time picker (requires `showTime`). |
52
- | `minuteStep` | `number` | `1` | Step interval for minute options (`1`-`59`, requires `showTime`). |
46
+ | Prop | Type | Default | Description |
47
+ | ------------- | ----------------------------------- | ----------- | ----------------------------------------------------------------------- |
48
+ | `value` | `Date` | `undefined` | Controlled selected date. |
49
+ | `onChange` | `(date: Date \| undefined) => void` | `undefined` | Called when the date changes. |
50
+ | `showTime` | `boolean` | `false` | Show time picker columns (HH, MM) alongside the calendar. |
51
+ | `withSeconds` | `boolean` | `false` | Show seconds column in the time picker (requires `showTime`). |
52
+ | `minuteStep` | `number` | `1` | Step interval for minute options (`1`-`59`, requires `showTime`). |
53
53
  | `secondStep` | `number` | `1` | Step interval for second options (`1`-`59`, useful with `withSeconds`). |
54
54
 
55
55
  ### Range Mode Props (mode="range")
@@ -8,18 +8,18 @@ Drag-and-drop uploader with keyboard activation, file type filtering, limits (co
8
8
 
9
9
  ## Props
10
10
 
11
- | Prop | Type | Default | Description |
12
- | ------------------- | ------------------------- | -------------------------------------------------- | --------------------------------------------------------- |
13
- | `extensions` | `AcceptItem[]` | `["pdf","image","video","audio"]` | Allowed extensions/categories (maps to accept attribute). |
14
- | `multiple` | `boolean` | `false` | Enables multiple file selection. |
15
- | `onUpload` | `(files: File[]) => void` | `undefined` | Called when files are **added**, with the resulting list. |
16
- | `onRemove` | `(removed: File[], remaining: File[]) => void` | `undefined` | Called when files are **removed** (single or remove-all), with the removed files and the list that remains. |
17
- | `description` | `string` | `"Trascina un file o clicca per selezionare"` | Dropzone hint. |
18
- | `formatDescription` | `string` | `"Formato accettato: PDF, Immagini, Video, Audio"` | Accepted formats hint. |
19
- | `selectedLabel` | `string` | `"File selezionati"` | Title shown above selected files list. |
20
- | `removeAllLabel` | `string` | `"rimuovi tutto"` | Label for the "remove all" button. |
21
- | `maxTotalSize` | `number` (bytes) | `undefined` | Maximum total size of selected files. |
22
- | `maxFiles` | `number` | `undefined` | Maximum number of files (when `multiple` is true). |
11
+ | Prop | Type | Default | Description |
12
+ | ------------------- | ---------------------------------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
13
+ | `extensions` | `AcceptItem[]` | `["pdf","image","video","audio"]` | Allowed extensions/categories (maps to accept attribute). |
14
+ | `multiple` | `boolean` | `false` | Enables multiple file selection. |
15
+ | `onUpload` | `(files: File[]) => void` | `undefined` | Called when files are **added**, with the resulting list. |
16
+ | `onRemove` | `(removed: File[], remaining: File[]) => void` | `undefined` | Called when files are **removed** (single or remove-all), with the removed files and the list that remains. |
17
+ | `description` | `string` | `"Trascina un file o clicca per selezionare"` | Dropzone hint. |
18
+ | `formatDescription` | `string` | `"Formato accettato: PDF, Immagini, Video, Audio"` | Accepted formats hint. |
19
+ | `selectedLabel` | `string` | `"File selezionati"` | Title shown above selected files list. |
20
+ | `removeAllLabel` | `string` | `"rimuovi tutto"` | Label for the "remove all" button. |
21
+ | `maxTotalSize` | `number` (bytes) | `undefined` | Maximum total size of selected files. |
22
+ | `maxFiles` | `number` | `undefined` | Maximum number of files (when `multiple` is true). |
23
23
 
24
24
  `AcceptItem` includes: `pdf | doc | docx | xls | xlsx | ppt | pptx | txt | csv | jpg | jpeg | png | gif | image | video | audio | zip | rar | 7z | tar | gz | tgz`.
25
25
 
@@ -0,0 +1,112 @@
1
+ # GridFilterPanel
2
+
3
+ ## Overview
4
+
5
+ The overlay filter inventory of `AppDataGrid`: a toggle button that opens a panel listing one entry per
6
+ filterable column, plus the badges currently applied. It is a **controlled** surface — it owns no filter
7
+ state, it renders the `badges` it is handed and reports every change through `onAdd` / `onUpdate` /
8
+ `onRemove`.
9
+
10
+ ⚠️ **Deprecated, not removed.** New work should use the Riga Zero filter row instead — `AppDataGrid` with
11
+ `filterMode="row"` puts one filter cell per column inside the grid itself, opened in place. `GridFilterPanel`
12
+ is still exported as a value and as a type from both barrels (`organisms/index.ts` and
13
+ `ui/app-data-grid/index.ts`), and every existing call-site keeps compiling. There is no `@deprecated` JSDoc
14
+ tag on the source, deliberately: it would trip the consumer lint rules that ban deprecated APIs.
15
+
16
+ ⚠️ **It ships without rendered coverage, and that is the reason the deprecation entry exists** — a
17
+ measurement, not a style preference. Since `adg-r25` (2026-09-04) no story mounts this component, so its
18
+ rendered behaviour has no executable coverage at all. The docblock of
19
+ `app-data-grid-atomo-filtro.stories.tsx :: BersagliDellaRigaDeiChip` lists **eight known falsifications of
20
+ the overlay inventory that would pass green today**: body opening upwards, absolute positioning removed,
21
+ narrow width, `elementFromPoint` missing the panel, flipped anchor, `focus()` removed, and the primary
22
+ action placed inside the scrolling container. A consumer who mounts it is mounting a surface this repository
23
+ no longer measures.
24
+
25
+ What still guards it is narrow and worth knowing: `scripts/check-filter-panel-selectors.mjs` binds the two
26
+ selectors the stories assert **only in the negative** (`data-grid-filter-panel` and
27
+ `data-grid-filter-panel-toggle`) to the source that emits them, so a **rename** goes red instead of leaving
28
+ those assertions green forever. That gate catches a rename, not a behavioural break — the eight above stay
29
+ uncovered.
30
+
31
+ Recorded in `docs/analysis/datatable-v2/PIANO-COMPLETAMENTO.md` §«`GridFilterPanel` è spedito senza
32
+ copertura resa».
33
+
34
+ ---
35
+
36
+ ## Props
37
+
38
+ ### GridFilterPanelProps
39
+
40
+ | Prop | Type | Default | Description |
41
+ | ------------------ | ------------------------------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
42
+ | `columns` | `readonly GridFilterColumn[]` | — | **Required.** The filterable columns offered in the panel's dropdown. |
43
+ | `badges` | `readonly GridBadgeFilter[]` | — | **Required.** The applied filters, rendered as badges. Built with the one badge constructor, so the panel and the Riga Zero produce the same state. |
44
+ | `open` | `boolean` | — | **Required.** Whether the panel is open. Controlled — the component never holds this itself. |
45
+ | `onOpenChange` | `(open: boolean) => void` | — | **Required.** Fired when the toggle opens or closes the panel. |
46
+ | `onAdd` | `(badge: GridBadgeFilter) => void` | — | **Required.** Fired when a new filter badge is created. |
47
+ | `onUpdate` | `(id: string, patch: Partial<GridBadgeFilter>) => void` | — | **Required.** Fired with a partial patch when an existing badge changes. |
48
+ | `onRemove` | `(id: string) => void` | — | **Required.** Fired when a badge is removed. |
49
+ | `onBuildCondition` | `() => void` | — | The panel's primary action, «Costruisci una condizione». ⚠️ The panel composes nothing itself — the composer is its own surface (the filter atom) and this is only where it opens from. **Omitted ⇒ the button renders `disabled` rather than hidden**, because the criterion «the primary action does not scroll away» needs the node to exist either way, and a button that accepts a click and discards it is worse than one that declares it cannot act. |
50
+ | `registry` | `React.ReactNode` | — | The column registry (R9), rendered inside the panel when present. |
51
+ | `columnVisibility` | `Readonly<Record<string, boolean>>` | all visible | Column visibility, so a hidden column is not offered in the dropdown. Absent means every column is visible. |
52
+ | `i18n` | `GridI18n` | `defaultGridI18n` | Label overrides, same object shape the grid takes. |
53
+ | `className` | `string` | — | Extra classes on the panel root. |
54
+
55
+ ---
56
+
57
+ ## Behavior
58
+
59
+ - **Fully controlled.** `open` and `badges` both come from the call-site; the panel renders and reports,
60
+ it never stores.
61
+ - **Two stable selectors**, and they are contractual: `data-grid-filter-panel` on the panel and
62
+ `data-grid-filter-panel-toggle` on the trigger. `scripts/check-filter-panel-selectors.mjs` fails the
63
+ build if either is renamed in the source without the assertions following.
64
+ - **The primary action is always present**, `disabled` when `onBuildCondition` is omitted — see the prop
65
+ note above.
66
+ - **Hidden columns are not offered**: a column whose `columnVisibility` entry is `false` is dropped from
67
+ the dropdown rather than shown and rejected.
68
+
69
+ ---
70
+
71
+ ## Examples
72
+
73
+ ### Preferred: the Riga Zero instead
74
+
75
+ New work should not mount this component. The same filters live inside the grid:
76
+
77
+ ```tsx
78
+ import { AppDataGrid } from "laif-ds";
79
+
80
+ export function Commesse({ rows, columns }) {
81
+ return <AppDataGrid data={rows} columns={columns} filterMode="row" />;
82
+ }
83
+ ```
84
+
85
+ ### Existing call-sites: the controlled panel
86
+
87
+ ```tsx
88
+ import { GridFilterPanel } from "laif-ds";
89
+ import { useState } from "react";
90
+
91
+ export function InventarioFiltri({ columns }) {
92
+ const [open, setOpen] = useState(false);
93
+ const [badges, setBadges] = useState([]);
94
+
95
+ return (
96
+ <GridFilterPanel
97
+ columns={columns}
98
+ badges={badges}
99
+ open={open}
100
+ onOpenChange={setOpen}
101
+ onAdd={(badge) => setBadges((prev) => [...prev, badge])}
102
+ onUpdate={(id, patch) =>
103
+ setBadges((prev) =>
104
+ prev.map((badge) => (badge.id === id ? { ...badge, ...patch } : badge)),
105
+ )
106
+ }
107
+ onRemove={(id) => setBadges((prev) => prev.filter((badge) => badge.id !== id))}
108
+ onBuildCondition={() => setOpen(false)}
109
+ />
110
+ );
111
+ }
112
+ ```
@@ -16,7 +16,7 @@ Low-level primitives to build responsive sidebars with desktop/offcanvas modes,
16
16
  - **SidebarHeader / SidebarFooter**: Top/bottom containers.
17
17
  - **SidebarContent**: Scrollable body.
18
18
  - **SidebarGroup / SidebarGroupLabel / SidebarGroupAction / SidebarGroupContent**: Labeled groups with optional action.
19
- - **SidebarMenu / SidebarMenuItem / SidebarMenuButton / SidebarMenuAction / SidebarMenuBadge**: Menu building blocks.
19
+ - **SidebarMenu / SidebarMenuItem / SidebarMenuButton / SidebarMenuAction / SidebarMenuBadge**: Menu building blocks. `SidebarMenuBadge` is **deprecated** — see below.
20
20
  - **SidebarMenuSub / SidebarMenuSubItem / SidebarMenuSubButton**: Nested menus.
21
21
 
22
22
  ---
@@ -30,8 +30,78 @@ Low-level primitives to build responsive sidebars with desktop/offcanvas modes,
30
30
  toggle an `openMobile` no sheet is listening to, leaving the navigation
31
31
  unreachable. So on mobile `collapsible` has no effect at all.
32
32
  - **Collapsible**: `icon` mode shows only icons and tooltips; `offcanvas` moves panel off-screen.
33
+ - **Icon-mode geometry** (`SidebarMenuButton` in the 3rem rail): a 32px pill
34
+ (`!size-8`, `mx-auto`) with **6px** of padding (`!p-1.5`) around a **20px**
35
+ glyph (`[&>svg]:size-5`) — 16px in expanded rows, where the button's own
36
+ `[&>svg]:size-4` applies. The three numbers come from
37
+ `navTokens.rail.button` (`src/components/nav-tokens.ts`) and are one decision: `32 - 2*6 = 20` makes the
38
+ content box **exactly** the glyph, which is what keeps every glyph on the
39
+ panel's centre line. The label stays mounted as a `flex-1` sibling (it is the
40
+ row's accessible name), so any slack in that box is claimed by the label and
41
+ pushes the glyph off-centre by half of it. Give the glyph a different size and
42
+ the padding has to follow.
33
43
  - **Keyboard**: Toggle with ⌘/Ctrl + B.
34
44
  - **Tooltips**: Menu buttons show tooltips only when collapsed on desktop.
45
+ - **Peek (overlay expansion)**: see below.
46
+
47
+ ---
48
+
49
+ ## `SidebarMenuBadge` is deprecated
50
+
51
+ Use `AppSidebar` with **`NavItem.badge` / `NavItem.badgeLabel`** instead (see
52
+ `AppSidebar.md` → "Badges"). The primitive still works and is still exported,
53
+ unchanged, for a consumer hand-building a `Sidebar` out of these parts — but it
54
+ is the wrong tool for a navigation row:
55
+
56
+ - it is `group-data-[collapsible=icon]:hidden`, so whatever it carries simply
57
+ **disappears** in the 3rem rail, where `NavItem.badge` degrades to a dot and
58
+ moves the value into the tooltip;
59
+ - it has **no spoken form** — `NavItem.badgeLabel` rides an `sr-only` span
60
+ inside the row while the visual mark is `aria-hidden`;
61
+ - it is positioned absolutely over the row rather than laid out in it, so it
62
+ cannot share the row with a chevron or an action;
63
+ - it renders on one surface, where `NavItem.badge` renders on all four a
64
+ `NavItem` feeds, the mobile panel and `AppBottomNav` included.
65
+
66
+ Removing it would be a breaking change on a published package, so it stays until
67
+ a major.
68
+
69
+ ---
70
+
71
+ ## Peek — `useSidebar().peek` / `setPeek`
72
+
73
+ A second, temporary way for the sidebar to be expanded, used by `AppSidebar`'s
74
+ `expandOnHover`. The primitive provides the mechanism only: the hover, focus and
75
+ pin logic lives in `AppSidebar`, which calls `setPeek` and nothing else.
76
+
77
+ ```ts
78
+ const { state, open, setOpen, peek, setPeek } = useSidebar();
79
+ ```
80
+
81
+ - `peek: boolean` — temporary expansion driven by hover or focus.
82
+ - `setPeek(peek: boolean)` — the only thing the owner of the logic writes.
83
+
84
+ Three things follow from it, and each exists for a reason:
85
+
86
+ - **`state` is `open || peek ? "expanded" : "collapsed"`.** Widening the panel
87
+ alone would not work: the children read `state` and the
88
+ `group-data-[collapsible=icon]:*` rules, not the panel's width, so labels,
89
+ inline submenus and the tooltip suppression on `SidebarMenuButton` all hang off
90
+ this. Note that `data-collapsible` empties as soon as `state` is `"expanded"`,
91
+ peek included.
92
+ - **`peek` never goes through `setOpen`,** so it never writes the
93
+ `sidebar_state` cookie. Otherwise every pass of the mouse would overwrite the
94
+ consumer's persisted preference with noise.
95
+ - **The wrapper gets `data-peek="true"`,** and that is what keeps the peek an
96
+ _overlay_ rather than a push: the gap element and `SidebarInset` cancel the
97
+ effect of `data-state` on `data-peek="true"` and stay at icon width (per
98
+ variant — `floating` / `inset` keep their
99
+ `calc(var(--sidebar-width-icon) + 1rem)`), while the `fixed` panel takes the
100
+ raised z-index and the shadow. Any consumer styling that keys off
101
+ `data-state="collapsed"` for layout has to be re-anchored the same way.
102
+
103
+ `peek` is forced to `false` below 768px, where the panel is a Sheet and there is
104
+ no hover to speak of.
35
105
 
36
106
  ---
37
107
 
@@ -66,6 +136,7 @@ export function Shell() {
66
136
  <SidebarMenuButton isActive>
67
137
  <span>Dashboard</span>
68
138
  </SidebarMenuButton>
139
+ {/* Deprecated — prefer `AppSidebar` + `NavItem.badge`. */}
69
140
  <SidebarMenuBadge>3</SidebarMenuBadge>
70
141
  </SidebarMenuItem>
71
142
  </SidebarMenu>
@@ -0,0 +1,87 @@
1
+ # SidebarMenuBadge
2
+
3
+ ## Overview
4
+
5
+ ⚠️ **Deprecated — use `AppSidebar` with `NavItem.badge` / `NavItem.badgeLabel` instead.**
6
+ The primitive still works and is still exported, unchanged: removing it would be a
7
+ breaking change on a published package, so it stays until a major.
8
+
9
+ A small count or mark pinned to the right edge of a `SidebarMenuButton` row, for a
10
+ consumer hand-building a `Sidebar` out of the primitives. It renders a `<div>` carrying
11
+ `data-sidebar="menu-badge"`, positioned **absolutely** over the row and
12
+ `pointer-events-none`, with its vertical offset following the sibling button's size
13
+ (`sm` / `default` / `lg`).
14
+
15
+ The full rationale for the deprecation — four reasons, each measurable — lives in
16
+ `Sidebar.md` § «`SidebarMenuBadge` is deprecated», and the replacement is documented in
17
+ `AppSidebar.md` § «Badges». The short version, because it is what decides whether you
18
+ may use it:
19
+
20
+ - it is `group-data-[collapsible=icon]:hidden`, so whatever it carries **disappears** in
21
+ the 3rem rail, where `NavItem.badge` degrades to a dot and moves the value into the
22
+ tooltip;
23
+ - it has **no spoken form**, while `NavItem.badgeLabel` rides an `sr-only` span inside
24
+ the row with the visual mark `aria-hidden`;
25
+ - being absolutely positioned rather than laid out in the row, it cannot share that row
26
+ with a chevron or an action;
27
+ - it renders on one surface, where `NavItem.badge` renders on all four a `NavItem` feeds
28
+ — the mobile panel and `AppBottomNav` included.
29
+
30
+ ---
31
+
32
+ ## Props
33
+
34
+ No own props. Extends `React.ComponentProps<"div">` — `className` is merged through
35
+ `cn()`, everything else is spread onto the `<div>`.
36
+
37
+ ---
38
+
39
+ ## Behavior
40
+
41
+ - **Hidden in icon mode.** `group-data-[collapsible=icon]:hidden`: in the collapsed rail
42
+ the badge is not rendered to the user at all. This is the reason it must not carry
43
+ information that exists nowhere else.
44
+ - **Not interactive.** `pointer-events-none`, so clicks fall through to the menu button
45
+ underneath; it cannot host a control.
46
+ - **Follows the button's size**, not its own prop: `top-1` next to a `sm` button,
47
+ `top-1.5` next to `default`, `top-2.5` next to `lg`, driven by the sibling's
48
+ `data-size` through the `peer/menu-button` group.
49
+ - **Colour follows the row's state**, again through the peer: it takes the accent
50
+ foreground when the menu button is hovered or `data-active=true`.
51
+ - **Numerals are tabular** (`tabular-nums`) so a changing count does not shift width.
52
+
53
+ ---
54
+
55
+ ## Example
56
+
57
+ ```tsx
58
+ import {
59
+ Sidebar,
60
+ SidebarContent,
61
+ SidebarMenu,
62
+ SidebarMenuItem,
63
+ SidebarMenuButton,
64
+ SidebarMenuBadge,
65
+ } from "laif-ds";
66
+
67
+ export function Example() {
68
+ return (
69
+ <Sidebar>
70
+ <SidebarContent>
71
+ <SidebarMenu>
72
+ <SidebarMenuItem>
73
+ <SidebarMenuButton>Inbox</SidebarMenuButton>
74
+ <SidebarMenuBadge>3</SidebarMenuBadge>
75
+ </SidebarMenuItem>
76
+ </SidebarMenu>
77
+ </SidebarContent>
78
+ </Sidebar>
79
+ );
80
+ }
81
+ ```
82
+
83
+ For new work, the same row in `AppSidebar`:
84
+
85
+ ```tsx
86
+ <AppSidebar navigation={[{ items: [{ label: "Inbox", badge: 3, badgeLabel: "3 non lette" }] }]} />
87
+ ```
@@ -46,9 +46,9 @@ This document provides a complete mapping of all components available in the lai
46
46
  ### Layout & Structure Components
47
47
 
48
48
  - **Accordion** - Collapsible content panels for organizing information hierarchically
49
- - **AppBottomNav** - Mobile bottom navigation bar (`md:hidden`, in the normal flow as the last child of `SidebarInset`): six equal cells — up to 5 primary destinations plus a Menu cell that opens `AppSidebar`'s mobile panel, optionally already drilled into a level, or up to 6 destinations with `showMenu={false}` when the app opens that panel from its own header
49
+ - **AppBottomNav** - Mobile bottom navigation bar (`md:hidden`, in the normal flow as the last child of `SidebarInset`): six equal cells — up to 5 primary destinations plus a Menu cell that opens `AppSidebar`'s mobile panel, optionally already drilled into a level, or up to 6 destinations with `showMenu={false}` when the app opens that panel from its own header, with an optional badge per cell (`badge`: a count as a superscript on the glyph, `99+` past 99, short text degrading to a dot) and `menuBadge` for a dot on the Menu cell, OR-ed with the badged items dropped past the cell budget
50
50
  - **AppCard** - Enhanced card component with variant styles, semantic states, size control, and loading skeleton support
51
- - **AppSidebar** - Application sidebar navigation component, with groups rendered as a stacked list or as a tab bar (`navigationDisplay="tab"`, one group at a time, only the selected tab labelled and animated open to fit it, `navigationFooter` always visible), optional icon-only collapse (`collapsible="icon"`: tooltips on top-level items, dropdown for sub-items) and, below 768px, a Settings-style mobile menu (grouped cards, 44px rows, drill-down on sub-items)
51
+ - **AppSidebar** - Application sidebar navigation component, with groups rendered as a stacked list or as a tab bar (`navigationDisplay="tab"`, one group at a time, only the selected tab labelled and animated open to fit it, `navigationFooter` always visible), optional icon-only collapse (`collapsible="icon"`: tooltips on top-level items, dropdown for sub-items), optional hover expansion over that (`expandOnHover`: the pointer or the focus expands the panel as an overlay that does not move the page, a Pin in the header makes it permanent, `pinned`/`defaultPinned`/`onPinnedChange` alias the primitive's `open`) and, below 768px, a Settings-style mobile menu (grouped cards, 44px rows, drill-down on sub-items), plus an optional badge on every row and group (`badge`: `number | string | true` with `badgeLabel` for the spoken form, degrading per surface — pill when expanded, dot in the icon rail with the value in the tooltip, superscript in `AppBottomNav` — and never aggregating counts)
52
52
  - **AppStepper** - Step-by-step progress indicator for multi-step processes
53
53
  - **AspectRatio** - Container that maintains a specific aspect ratio for responsive layouts
54
54
  - **Breadcrumb** - Breadcrumb navigation component for hierarchical navigation
@@ -73,6 +73,7 @@ This document provides a complete mapping of all components available in the lai
73
73
  - **Drawer** - Slide-out panel for secondary content
74
74
  - **DropdownMenu** - Dropdown menu component with keyboard navigation
75
75
  - **HoverCard** - Popover card displayed on hover
76
+ - **InterruptPrompt** - Animated prompt to interrupt an action (e.g. hitting Enter twice)
76
77
  - **Menubar** - Application menu bar component
77
78
  - **Popover** - Floating content container triggered by user interaction
78
79
  - **Sheet** - Side sheet component for secondary content
@@ -81,6 +82,7 @@ This document provides a complete mapping of all components available in the lai
81
82
  ### Data Display Components
82
83
 
83
84
  - **Avatar** - User profile image display with fallback initials
85
+ - **AppDataGrid** - Data grid that replaces the deprecated `DataTable`: a single emitter (a column resize no longer refetches), opt-in virtualization keeping native `<table>` semantics, column widths/resize/left-pinning, multi-level headers with a real `id`/`headers` chain, lifted filter panel and chips, density and full screen, an infinite source with skeleton rows, client-side row grouping and saved views. Independent of `DataTable` — it imports nothing from it and the two can live on the same page
84
86
  - **Badge** - Small status indicator or label for highlighting information
85
87
  - **DataCrossTable** - Cross-tabulation data display component
86
88
  - **DataTable** - Advanced table component with sorting, filtering, and pagination
@@ -152,6 +154,49 @@ The following components are marked as deprecated and should not be used in new
152
154
  - **MultipleSelector** - ~~Use `AppSelect` instead~~
153
155
  - **AppMultipleSelectDropdown** - ~~Use `AppSelect` instead~~
154
156
  - **ResizePrompt** - ~~Use alternative resize handling methods~~
157
+ - **DataTable** - ~~Use `AppDataGrid` instead~~
158
+
159
+ - **GridFilterPanel** - ~~Use the Riga Zero filter row instead (`filterMode="row"`)~~
160
+
161
+ ⚠️ **Deprecated, not removed** — same distinction as `DataTable` above. `GridFilterPanel` is still
162
+ exported as a value and as a type from both barrels (`organisms/index.ts` and
163
+ `ui/app-data-grid/index.ts`), and every existing call-site keeps compiling. What changed is that
164
+ `AppDataGrid` now offers the filters **in the grid itself**, on the Riga Zero — one filter cell per
165
+ column, opened in place — and that is where new work should go.
166
+
167
+ ⚠️ **AND THE REASON THIS ENTRY EXISTS IS A COVERAGE FACT, not a style preference.** Since
168
+ `adg-r25` (2026-09-04, decision of Lorenzo) **no story mounts this component**, so its rendered
169
+ behaviour has **no executable coverage at all**: the docblock of
170
+ `app-data-grid-atomo-filtro.stories.tsx :: BersagliDellaRigaDeiChip` lists **eight known
171
+ falsifications of its overlay inventory that would pass green today** — body opening upwards,
172
+ absolute positioning removed, narrow width, `elementFromPoint` missing the panel, flipped anchor,
173
+ `focus()` removed, primary action inside the scrolling container. A consumer who mounts it is
174
+ mounting a surface this repository no longer measures.
175
+
176
+ What still guards it is narrow and worth knowing: `scripts/check-filter-panel-selectors.mjs` binds
177
+ the two selectors that the stories assert **only in the negative** (`data-grid-filter-panel` and
178
+ `data-grid-filter-panel-toggle`) to the source that emits them, so a rename goes red instead of
179
+ leaving four assertions green forever. That gate catches a **rename**, not a behavioural break: the
180
+ eight above stay uncovered.
181
+
182
+ Recorded in `docs/analysis/datatable-v2/PIANO-COMPLETAMENTO.md` §«`GridFilterPanel` è spedito senza
183
+ copertura resa».
184
+
185
+ ⚠️ **Deprecated, not removed, and the difference matters.** `DataTable` still works and is still
186
+ exported; every existing call-site keeps compiling. What changed is that new work should reach for
187
+ `AppDataGrid`, which is the same table rewritten to satisfy the fifteen requirements the old one
188
+ could not — a single emitter (a column resize no longer refetches), virtualization that keeps
189
+ native `<table>` semantics, multi-level headers with a real `id`/`headers` chain, an infinite
190
+ source, and client-side row grouping.
191
+
192
+ **The two can live on the same page.** `AppDataGrid` imports nothing from `DataTable` and shares no
193
+ state with it, which is what makes a call-site-by-call-site migration possible instead of a
194
+ flag day.
195
+
196
+ **Migrating is mostly a rename.** `scripts/codemod/rename-map.json` records, name by name, which
197
+ old export maps to which new one and which parts of the new surface have no old equivalent.
198
+
199
+ - **SidebarMenuBadge** - ~~Use `NavItem.badge` instead~~ (on `AppSidebar`, with `badgeLabel` for the spoken form; the primitive stays exported and functional, but it is hidden in icon mode and has no spoken form — see `Sidebar.md`)
155
200
 
156
201
  ---
157
202