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.
- package/dist/CHANGELOG.md +282 -0
- package/dist/_virtual/index7.js +5 -2
- package/dist/_virtual/index8.js +2 -5
- package/dist/agent-docs/adoption-report.json +164 -83
- package/dist/agent-docs/components/AppBottomNav.md +180 -49
- package/dist/agent-docs/components/AppCard.md +25 -21
- package/dist/agent-docs/components/AppDataGrid.md +2602 -0
- package/dist/agent-docs/components/AppEditor.md +18 -13
- package/dist/agent-docs/components/AppSelect.md +50 -0
- package/dist/agent-docs/components/AppSidebar.md +504 -11
- package/dist/agent-docs/components/DataTable.md +34 -3
- package/dist/agent-docs/components/DatePicker.md +7 -7
- package/dist/agent-docs/components/FileUploader.md +12 -12
- package/dist/agent-docs/components/GridFilterPanel.md +112 -0
- package/dist/agent-docs/components/Sidebar.md +72 -1
- package/dist/agent-docs/components/SidebarMenuBadge.md +87 -0
- package/dist/agent-docs/components-list.md +47 -2
- package/dist/agent-docs/manifest.json +310 -36
- package/dist/components/design-tokens.js +138 -66
- package/dist/components/nav-tokens.js +41 -0
- package/dist/components/ui/app-bottom-nav.js +125 -130
- package/dist/components/ui/app-data-grid/app-data-grid.js +874 -0
- package/dist/components/ui/app-data-grid/engine/use-grid-column-resize.js +110 -0
- package/dist/components/ui/app-data-grid/engine/use-grid-engine.js +598 -0
- package/dist/components/ui/app-data-grid/engine/use-grid-infinite-loader.js +50 -0
- package/dist/components/ui/app-data-grid/engine/use-grid-virtualizer.js +90 -0
- package/dist/components/ui/app-data-grid/grid-aggregate.js +5 -0
- package/dist/components/ui/app-data-grid/grid-column-registry.js +28 -0
- package/dist/components/ui/app-data-grid/grid-columns.js +204 -0
- package/dist/components/ui/app-data-grid/grid-filter-compile.js +33 -0
- package/dist/components/ui/app-data-grid/grid-filter-operators.js +139 -0
- package/dist/components/ui/app-data-grid/grid-grouping.js +104 -0
- package/dist/components/ui/app-data-grid/grid-header-matrix.js +112 -0
- package/dist/components/ui/app-data-grid/grid-i18n.js +207 -0
- package/dist/components/ui/app-data-grid/grid-mount-count.js +8 -0
- package/dist/components/ui/app-data-grid/grid-reducer.js +200 -0
- package/dist/components/ui/app-data-grid/grid-result-scope.js +35 -0
- package/dist/components/ui/app-data-grid/grid-tokens.js +169 -0
- package/dist/components/ui/app-data-grid/grid-view-preset.js +97 -0
- package/dist/components/ui/app-data-grid/parts/grid-actions-row.js +86 -0
- package/dist/components/ui/app-data-grid/parts/grid-cell-text.js +67 -0
- package/dist/components/ui/app-data-grid/parts/grid-column-registry-panel.js +320 -0
- package/dist/components/ui/app-data-grid/parts/grid-density-control.js +88 -0
- package/dist/components/ui/app-data-grid/parts/grid-filter-chips.js +224 -0
- package/dist/components/ui/app-data-grid/parts/grid-filter-editor.js +197 -0
- package/dist/components/ui/app-data-grid/parts/grid-filter-panel.js +386 -0
- package/dist/components/ui/app-data-grid/parts/grid-filter-row.js +273 -0
- package/dist/components/ui/app-data-grid/parts/grid-fullscreen-toggle.js +29 -0
- package/dist/components/ui/app-data-grid/parts/grid-group-row.js +135 -0
- package/dist/components/ui/app-data-grid/parts/grid-header.js +338 -0
- package/dist/components/ui/app-data-grid/parts/grid-pagination-control.js +218 -0
- package/dist/components/ui/app-data-grid/parts/grid-row.js +181 -0
- package/dist/components/ui/app-data-grid/parts/grid-scroll-area.js +186 -0
- package/dist/components/ui/app-data-grid/parts/grid-selection-bar.js +195 -0
- package/dist/components/ui/app-data-grid/parts/grid-status-surface.js +66 -0
- package/dist/components/ui/app-data-grid/parts/grid-table.js +482 -0
- package/dist/components/ui/app-data-grid/parts/grid-toolbar-slots.js +192 -0
- package/dist/components/ui/app-data-grid/use-grid-filters.js +173 -0
- package/dist/components/ui/app-select.js +332 -222
- package/dist/components/ui/app-sidebar-mobile.js +119 -104
- package/dist/components/ui/app-sidebar.js +516 -313
- package/dist/components/ui/button.js +2 -1
- package/dist/components/ui/gantt/components/Chart/Chart.js +1 -1
- package/dist/components/ui/nav-badge.js +66 -0
- package/dist/components/ui/sidebar.js +272 -207
- package/dist/components/ui/tables/data-cross-table/data-cross-table.js +6 -6
- package/dist/components/ui/tables/data-table/data-table-constants.js +36 -16
- package/dist/components/ui/tables/data-table/data-table-i18n.js +135 -1
- package/dist/css-for-template.css +27 -0
- package/dist/index.d.ts +5872 -144
- package/dist/index.js +473 -406
- package/dist/node_modules/eventemitter3/index2.js +1 -1
- package/dist/styles.css +2 -1
- package/dist/styles.v3.css +1 -1
- package/package.json +25 -7
- /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
|
|
12
|
-
| ------------------- |
|
|
13
|
-
| `extensions` | `AcceptItem[]`
|
|
14
|
-
| `multiple` | `boolean`
|
|
15
|
-
| `onUpload` | `(files: File[]) => void`
|
|
16
|
-
| `onRemove` | `(removed: File[], remaining: File[]) => void` | `undefined`
|
|
17
|
-
| `description` | `string`
|
|
18
|
-
| `formatDescription` | `string`
|
|
19
|
-
| `selectedLabel` | `string`
|
|
20
|
-
| `removeAllLabel` | `string`
|
|
21
|
-
| `maxTotalSize` | `number` (bytes)
|
|
22
|
-
| `maxFiles` | `number`
|
|
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
|
|