prime-ui-kit 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/chunks/{chunk-OAXJWF3L.js → chunk-3PY52JP3.js} +1764 -1764
- package/dist/chunks/{chunk-X3JT5CLR.js → chunk-4KONMO7Z.js} +1 -1
- package/dist/chunks/{chunk-MB4CXSLL.js → chunk-W6EGTNG6.js} +3772 -2888
- package/dist/color-picker.js +2 -2
- package/dist/components/data-table/ColumnsMenu.d.ts +39 -17
- package/dist/components/data-table/DataTable.d.ts +41 -12
- package/dist/components/data-table/DataTableColumnsMenu.d.ts +45 -0
- package/dist/components/data-table/Head.d.ts +18 -5
- package/dist/components/data-table/Row.d.ts +10 -4
- package/dist/components/data-table/StateRows.d.ts +5 -3
- package/dist/components/data-table/columnOrder.d.ts +14 -0
- package/dist/components/data-table/reorder.d.ts +15 -5
- package/dist/components/data-table/types.d.ts +5 -0
- package/dist/components/data-table/useFrozenColumns.d.ts +6 -2
- package/dist/components/datepicker/DatepickerPanel.d.ts +1 -1
- package/dist/components/dnd/Dnd.d.ts +9 -5
- package/dist/components/dnd/inPlaceRow.d.ts +7 -0
- package/dist/components/dnd/useDragSource.d.ts +2 -0
- package/dist/components/dnd/useSortableList.d.ts +5 -0
- package/dist/components/field-list/FieldList.d.ts +37 -15
- package/dist/components/gantt/Gantt.d.ts +1 -1
- package/dist/components/index.d.ts +3 -1
- package/dist/components/kanban/Kanban.d.ts +4 -0
- package/dist/components/list/List.d.ts +9 -4
- package/dist/components/scroll-container/ScrollContainer.d.ts +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +4 -2
- package/dist/internal/ToolRow.d.ts +23 -0
- package/dist/internal/leaveGuard.d.ts +6 -0
- package/dist/internal/overlay/DialogGuard.d.ts +3 -2
- package/dist/internal/overlay/DialogParts.d.ts +14 -5
- package/dist/layout/index.d.ts +1 -1
- package/dist/layout/page/Page.d.ts +8 -14
- package/dist/skill/anti-slop.md +55 -1
- package/dist/skill/api-contract.md +2 -2
- package/dist/skill/cheatsheet.md +12 -4
- package/dist/skill/checklist.md +7 -0
- package/dist/skill/choosing.md +1 -0
- package/dist/skill/components.md +1 -1
- package/dist/skill/composition.md +196 -21
- package/dist/skill/layouts.md +1 -1
- package/dist/skill/reference/components/confirm-dialog/COMPONENT.md +1 -1
- package/dist/skill/reference/components/data-table/COMPONENT.md +110 -49
- package/dist/skill/reference/components/data-table/examples/actions-column.tsx +154 -0
- package/dist/skill/reference/components/data-table/examples/column-order.tsx +152 -0
- package/dist/skill/reference/components/data-table/examples/columns-visibility.tsx +18 -18
- package/dist/skill/reference/components/data-table/examples/controlled.tsx +32 -17
- package/dist/skill/reference/components/data-table/examples/examples.module.css +14 -36
- package/dist/skill/reference/components/data-table/examples/narrow.tsx +25 -19
- package/dist/skill/reference/components/data-table/examples/reorder.tsx +24 -2
- package/dist/skill/reference/components/data-table/examples/row-link.tsx +18 -22
- package/dist/skill/reference/components/data-table/examples/screen.tsx +12 -1
- package/dist/skill/reference/components/data-table/examples/selection.tsx +13 -18
- package/dist/skill/reference/components/data-table/examples/server.tsx +45 -31
- package/dist/skill/reference/components/data-table/examples/toolbar.tsx +22 -35
- package/dist/skill/reference/components/datepicker/COMPONENT.md +2 -2
- package/dist/skill/reference/components/dnd/COMPONENT.md +13 -7
- package/dist/skill/reference/components/dnd/examples/examples.module.css +4 -3
- package/dist/skill/reference/components/dnd/examples/handle.tsx +5 -5
- package/dist/skill/reference/components/dnd/examples/locked.tsx +1 -1
- package/dist/skill/reference/components/dnd/examples/table-columns.tsx +75 -0
- package/dist/skill/reference/components/dnd/examples/table.tsx +6 -6
- package/dist/skill/reference/components/drawer/COMPONENT.md +26 -10
- package/dist/skill/reference/components/drawer/examples/header-actions.tsx +1 -1
- package/dist/skill/reference/components/drawer/examples/loading.tsx +58 -0
- package/dist/skill/reference/components/field-list/COMPONENT.md +78 -47
- package/dist/skill/reference/components/field-list/examples/base-row.tsx +2 -1
- package/dist/skill/reference/components/field-list/examples/locked.tsx +11 -11
- package/dist/skill/reference/components/field-list/examples/narrow.tsx +108 -33
- package/dist/skill/reference/components/field-list/examples/reorder.tsx +1 -1
- package/dist/skill/reference/components/field-list/examples/row-menu.tsx +71 -0
- package/dist/skill/reference/components/field-list/examples/screen.module.css +1 -1
- package/dist/skill/reference/components/field-list/examples/screen.tsx +169 -162
- package/dist/skill/reference/components/field-list/examples/totals.tsx +9 -8
- package/dist/skill/reference/components/field-list/examples/variants.tsx +51 -0
- package/dist/skill/reference/components/gantt/COMPONENT.md +4 -4
- package/dist/skill/reference/components/kanban/COMPONENT.md +6 -2
- package/dist/skill/reference/components/kanban/examples/states.tsx +7 -5
- package/dist/skill/reference/components/list/COMPONENT.md +21 -11
- package/dist/skill/reference/components/list/examples/reorder.tsx +42 -7
- package/dist/skill/reference/components/modal/COMPONENT.md +23 -10
- package/dist/skill/reference/components/scroll-container/COMPONENT.md +1 -1
- package/dist/skill/reference/components/segmented-control/COMPONENT.md +3 -2
- package/dist/skill/reference/components/sheet/COMPONENT.md +18 -7
- package/dist/skill/reference/components/smart-filter/COMPONENT.md +2 -2
- package/dist/skill/reference/layout/page/COMPONENT.md +13 -17
- package/dist/skill/reference/layout/page/examples/screen.module.css +1 -1
- package/dist/skill/reference/layout/page/examples/screen.tsx +93 -104
- package/dist/skill/reference/layout/page/examples/sections.tsx +2 -15
- package/dist/skill/responsive.md +14 -10
- package/dist/tokens/semantic.d.ts +2 -2
- package/dist/tokens/themes/dark.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/confirm-dialog/COMPONENT.md +1 -1
- package/src/components/data-table/COMPONENT.md +110 -49
- package/src/components/data-table/examples/actions-column.tsx +154 -0
- package/src/components/data-table/examples/column-order.tsx +152 -0
- package/src/components/data-table/examples/columns-visibility.tsx +18 -18
- package/src/components/data-table/examples/controlled.tsx +32 -17
- package/src/components/data-table/examples/examples.module.css +14 -36
- package/src/components/data-table/examples/narrow.tsx +25 -19
- package/src/components/data-table/examples/reorder.tsx +24 -2
- package/src/components/data-table/examples/row-link.tsx +18 -22
- package/src/components/data-table/examples/screen.tsx +12 -1
- package/src/components/data-table/examples/selection.tsx +13 -18
- package/src/components/data-table/examples/server.tsx +45 -31
- package/src/components/data-table/examples/toolbar.tsx +22 -35
- package/src/components/datepicker/COMPONENT.md +2 -2
- package/src/components/dnd/COMPONENT.md +13 -7
- package/src/components/dnd/examples/examples.module.css +4 -3
- package/src/components/dnd/examples/handle.tsx +5 -5
- package/src/components/dnd/examples/locked.tsx +1 -1
- package/src/components/dnd/examples/table-columns.tsx +75 -0
- package/src/components/dnd/examples/table.tsx +6 -6
- package/src/components/drawer/COMPONENT.md +26 -10
- package/src/components/drawer/examples/header-actions.tsx +1 -1
- package/src/components/drawer/examples/loading.tsx +58 -0
- package/src/components/field-list/COMPONENT.md +78 -47
- package/src/components/field-list/examples/base-row.tsx +2 -1
- package/src/components/field-list/examples/locked.tsx +11 -11
- package/src/components/field-list/examples/narrow.tsx +108 -33
- package/src/components/field-list/examples/reorder.tsx +1 -1
- package/src/components/field-list/examples/row-menu.tsx +71 -0
- package/src/components/field-list/examples/screen.module.css +1 -1
- package/src/components/field-list/examples/screen.tsx +169 -162
- package/src/components/field-list/examples/totals.tsx +9 -8
- package/src/components/field-list/examples/variants.tsx +51 -0
- package/src/components/gantt/COMPONENT.md +4 -4
- package/src/components/kanban/COMPONENT.md +6 -2
- package/src/components/kanban/examples/states.tsx +7 -5
- package/src/components/list/COMPONENT.md +21 -11
- package/src/components/list/examples/reorder.tsx +42 -7
- package/src/components/modal/COMPONENT.md +23 -10
- package/src/components/scroll-container/COMPONENT.md +1 -1
- package/src/components/segmented-control/COMPONENT.md +3 -2
- package/src/components/sheet/COMPONENT.md +18 -7
- package/src/components/smart-filter/COMPONENT.md +2 -2
- package/src/layout/page/COMPONENT.md +13 -17
- package/src/layout/page/examples/screen.module.css +1 -1
- package/src/layout/page/examples/screen.tsx +93 -104
- package/src/layout/page/examples/sections.tsx +2 -15
- package/src/styles/theme-dark.css +1 -1
- package/src/styles/theme-light.css +1 -1
- package/dist/components/data-table/context.d.ts +0 -14
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Loading draws skeleton cards in the card geometry; an empty column keeps its drop area and a closed order stays in place while the rest move; a read-only board drags nothing — `loading`, `disabled`. */
|
|
1
|
+
/** Loading draws skeleton cards in the card geometry, and placeholder columns before the columns arrive; an empty column keeps its drop area and a closed order stays in place while the rest move; a read-only board drags nothing — `loading`, `loadingColumns`, `disabled`. */
|
|
2
2
|
import { Badge, Kanban, Typography } from "prime-ui-kit";
|
|
3
3
|
|
|
4
4
|
type Order = { id: string; title: string; total: string; closed?: boolean };
|
|
@@ -24,9 +24,10 @@ const PLACEMENT = {
|
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
const STATES = [
|
|
27
|
-
{ caption: "loading", loading: true, disabled: false },
|
|
28
|
-
{ caption: "
|
|
29
|
-
{ caption: "disabled", loading: false, disabled:
|
|
27
|
+
{ caption: "loading · columns=[]", columns: [], loading: true, disabled: false },
|
|
28
|
+
{ caption: "loading", columns: COLUMNS, loading: true, disabled: false },
|
|
29
|
+
{ caption: "Kanban.Item disabled", columns: COLUMNS, loading: false, disabled: false },
|
|
30
|
+
{ caption: "disabled", columns: COLUMNS, loading: false, disabled: true },
|
|
30
31
|
];
|
|
31
32
|
|
|
32
33
|
export default function KanbanStatesExample() {
|
|
@@ -35,7 +36,8 @@ export default function KanbanStatesExample() {
|
|
|
35
36
|
<div>
|
|
36
37
|
<Kanban.Root
|
|
37
38
|
aria-label={`Заказы склада: ${state.caption}`}
|
|
38
|
-
columns={
|
|
39
|
+
columns={state.columns}
|
|
40
|
+
loadingColumns={COLUMNS.length}
|
|
39
41
|
items={ORDERS}
|
|
40
42
|
getId={(order) => order.id}
|
|
41
43
|
getLabel={(order) => order.id}
|
|
@@ -28,13 +28,14 @@ import { List } from "prime-ui-kit";
|
|
|
28
28
|
```
|
|
29
29
|
List.Root <ul aria-label>; size (else the host tier) → row tier; onReorder → Dnd.Sortable <ul>
|
|
30
30
|
└─ List.Item <li> with a full-width <button> | <a href> | asChild element; current, disabled
|
|
31
|
-
│ value; with onReorder: Dnd.Handle (busy while saving)
|
|
31
|
+
│ value; with onReorder: Dnd.Handle (busy while saving) at the row's end, after its actions
|
|
32
32
|
├─ List.ItemIcon leading Avatar.Root / Icon / Badge.Dot (aria-hidden); after the text — a trailing glyph
|
|
33
33
|
├─ List.ItemText primary line, truncates
|
|
34
34
|
├─ List.ItemDescription second line, muted, truncates
|
|
35
35
|
├─ List.ItemMeta trailing small text (time, date, amount)
|
|
36
36
|
├─ List.ItemCount trailing Badge, one tier down
|
|
37
|
-
└─ List.ItemActions the row's own controls (Switch, Dropdown): beside the row element, one tier down
|
|
37
|
+
└─ List.ItemActions the row's own controls (Switch, Dropdown): beside the row element, one tier down;
|
|
38
|
+
side="end" after it, side="start" before it (a reorderable row's toggle)
|
|
38
39
|
```
|
|
39
40
|
|
|
40
41
|
## API
|
|
@@ -47,7 +48,7 @@ List.Root <ul aria-label>; size (else the host tier) → row t
|
|
|
47
48
|
| Prop | Type | Default | Description |
|
|
48
49
|
|---|---|---|---|
|
|
49
50
|
| `size` | `"xs" \| "s" \| "m" \| "l" \| "xl"` | host tier, else `"m"` | Row tier: height, text, icon and avatar size; counts take one tier down. Without it the tier of its host, else `m`. |
|
|
50
|
-
| `onReorder` | `(id: string, beforeId: string \| null) => void \| Promise<void>` | — | Rows reorder by
|
|
51
|
+
| `onReorder` | `(id: string, beforeId: string \| null) => void \| Promise<void>` | — | Rows reorder by an end handle (drag, touch hold, Alt + ↑ / ↓): item `value` `id` goes before `beforeId` (`null` = last). Apply with `moveBefore`; a returned promise keeps the row busy, a rejection moves it back. |
|
|
51
52
|
| `labels` | `Partial<ListLabels>` | — | Built-in strings, see Labels. |
|
|
52
53
|
| `aria-label` | `string` | — | Name of the list for screen readers («Обращения»), when no visible heading names it. |
|
|
53
54
|
| `children` | `ReactNode` | — | `List.Item`s. |
|
|
@@ -108,10 +109,11 @@ List.Root <ul aria-label>; size (else the host tier) → row t
|
|
|
108
109
|
| `…rest` | `Omit<HTMLAttributes<HTMLSpanElement>, "children" \| "color">` | — | `className` and the other `span` attributes. |
|
|
109
110
|
|
|
110
111
|
### List.ItemActions
|
|
111
|
-
`ref` → `HTMLDivElement`. The row's own controls (a `Switch`, a `Dropdown` with its icon `Button`) at its end, beside the row element and never inside it, one tier below the row.
|
|
112
|
+
`ref` → `HTMLDivElement`. The row's own controls (a `Switch`, a `Dropdown` with its icon `Button`) at its end or its start, beside the row element and never inside it, one tier below the row.
|
|
112
113
|
|
|
113
114
|
| Prop | Type | Default | Description |
|
|
114
115
|
|---|---|---|---|
|
|
116
|
+
| `side` | `"start" \| "end"` | `"end"` | `"end"` after the row element: a plain settings row, label first. `"start"` before it, in the DOM too: the on / off of a reorderable row reads first and the grip keeps the end. |
|
|
115
117
|
| `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children` (the controls, each named on its own), `className` and the other `div` attributes. |
|
|
116
118
|
|
|
117
119
|
## Variants
|
|
@@ -137,6 +139,12 @@ A second line or an avatar makes a row taller than the one-line height; the vert
|
|
|
137
139
|
### List.ItemCount color
|
|
138
140
|
`gray` (default) for a plain number; a hue for what needs attention (`blue` for unread). Any palette hue.
|
|
139
141
|
|
|
142
|
+
### List.ItemActions side
|
|
143
|
+
| Value | Looks like | Use when | Default |
|
|
144
|
+
|---|---|---|---|
|
|
145
|
+
| `end` | the controls after the row's text and trail | a plain row: the label first, the toggle or ⋯ menu at the end | yes |
|
|
146
|
+
| `start` | the controls before the row's icon and text, first in the DOM and the Tab order | a reorderable row's on / off: the state reads first, the grip keeps the end edge | |
|
|
147
|
+
|
|
140
148
|
## States
|
|
141
149
|
| State | Driven by | DOM |
|
|
142
150
|
|---|---|---|
|
|
@@ -146,9 +154,9 @@ A second line or an avatar makes a row taller than the one-line height; the vert
|
|
|
146
154
|
| current | `current` | `aria-current="true"` (button) or `"page"` (link); `fill-muted-hover` fill, primary text |
|
|
147
155
|
| focus-visible | keyboard | the focus ring inside the row edge |
|
|
148
156
|
| disabled | `disabled` | `disabled` on a button; `aria-disabled="true"`, no `href` on a link, `tabindex="-1"` on an `asChild` element; `data-disabled="true"`; disabled text; in a reorderable list the handle is disabled and the row holds its place |
|
|
149
|
-
| reorderable | `onReorder` | `data-reorderable="true"` on the root (a `Dnd.Sortable` `<ul>`); each `<li>` is a sortable item (`data-dnd-item` = `value`) with a
|
|
157
|
+
| reorderable | `onReorder` | `data-reorderable="true"` on the root (a `Dnd.Sortable` `<ul>`); each `<li>` is a sortable item (`data-dnd-item` = `value`) with a `Dnd.Handle` at its end; drag by the handle (a touch hold on touch), Alt + ↑ / ↓ from the handle or the row; a lifted row leaves a dashed gap in the row's radius, its neighbours glide, the copy (handle and row, in the row's padding and radius) follows the pointer and sets down in its new place without a jump |
|
|
150
158
|
| saving a move | `onReorder` returned a pending promise | the row stays in its new place, `aria-busy="true"`, the handle is busy (Dnd: a spinner in the disabled grip), the row content dims to 0.6 (`--prime-motion-fade-fast` both ways); a rejection glides the row back |
|
|
151
|
-
| own controls | `List.ItemActions` in the item | the row element and the controls stand in one frame that takes the hover, press and current fills for both; the element itself stays clear |
|
|
159
|
+
| own controls | `List.ItemActions` in the item | the row element and the controls stand in one frame that takes the hover, press and current fills for both; the element itself stays clear; `side="start"` controls come before the element in the frame, `data-side` on the actions |
|
|
152
160
|
| rows come and go | the data adds or takes out a `List.Item` (`value`, else its key) | a new row rises in once (`enterMotion`), a removed one closes up in place (`listPresence`); the first render stays still |
|
|
153
161
|
|
|
154
162
|
Root attributes: `data-size`, `role="list"` (the list style reset would drop the list semantics in WebKit). The fill changes on `background-color` with `--prime-motion-fade-xfast` both ways (a fade: reduced motion keeps it).
|
|
@@ -159,8 +167,9 @@ Root attributes: `data-size`, `role="list"` (the list style reset would drop the
|
|
|
159
167
|
- Row: leading icon · body (text over description) · trail. Beside two lines the trail stacks — meta on top, count below; beside one line they sit in a row.
|
|
160
168
|
- Text and description truncate with an ellipsis; give a long `List.ItemText` a `title` with the full text.
|
|
161
169
|
- On a coarse pointer a row is at least the touch target (44px).
|
|
162
|
-
- Reorderable (`onReorder`): an `xs` handle box
|
|
163
|
-
- `List.ItemActions`: the controls one tier below the row, 4px apart, as far from the row's
|
|
170
|
+
- Reorderable (`onReorder`): an `xs` handle box ends each row, 4px after the row element and its `List.ItemActions` (inline-end: on the left in RTL); the row keeps its own padding and fill, so every row's handle stands on one line.
|
|
171
|
+
- `List.ItemActions`: the controls one tier below the row, 4px apart, as far from the row's edge as from its top and bottom — the end edge, or the start edge with `side="start"`, where the row's own padding then parts the controls from its icon or text.
|
|
172
|
+
- One toggle place per row: a plain row ends with its toggle (label first); a reorderable row leads with it (`side="start"`) and ends with the grip — never a toggle between the label and the grip.
|
|
164
173
|
- A colour dot in `List.ItemIcon` is the large `Badge.Dot` (8px) centred in an icon-wide box, so the text lines up with the rows that carry icons.
|
|
165
174
|
|
|
166
175
|
## Accessibility
|
|
@@ -181,8 +190,8 @@ Root attributes: `data-size`, `role="list"` (the list style reset would drop the
|
|
|
181
190
|
- The open record: `aria-current="true"` on a button (a selection inside the screen), `aria-current="page"` on a link (`href`, `asChild`) — the link points at the current URL. A router link may set it itself.
|
|
182
191
|
- The row's name is its text, description, meta and count, in that order; the leading icon or avatar is `aria-hidden` — the text names the row.
|
|
183
192
|
- Arrow keys do not move between rows: rows are ordinary Tab stops, as in the Sidebar.
|
|
184
|
-
- `List.ItemActions` stand beside the row element, never inside it: the row's name stays its text
|
|
185
|
-
- With `onReorder` each row gets a handle named «Переместить {label}» (`labels.reorderItem`, `{label}` is the row's text line) and `aria-keyshortcuts
|
|
193
|
+
- `List.ItemActions` stand beside the row element, never inside it: the row's name stays its text. Tab follows the row as it reads: the `side="start"` controls, the row, the `side="end"` controls.
|
|
194
|
+
- With `onReorder` each row gets a handle named «Переместить {label}» (`labels.reorderItem`, `{label}` is the row's text line) and `aria-keyshortcuts`, last in the row: Tab reaches the row with its `List.ItemActions`, then the handle; the new place is announced politely («Новый лид: позиция 2 из 5»), a row being saved is `aria-busy`.
|
|
186
195
|
|
|
187
196
|
### Labels
|
|
188
197
|
<!-- Generated from api.ts by `bun run docs:build`. Edit api.ts, not this section. -->
|
|
@@ -200,7 +209,7 @@ Root attributes: `data-size`, `role="list"` (the list style reset would drop the
|
|
|
200
209
|
| [with-icon.tsx](examples/with-icon.tsx) | Leading avatars of clients, icons of queues and colour dots of projects; an avatar takes the row tier, a dot stands in an icon-wide box — `List.ItemIcon`, `Badge.Dot`. |
|
|
201
210
|
| [overflow.tsx](examples/overflow.tsx) | A long inbox in a pane of a fixed height: the list scrolls in a ScrollContainer and long names and previews truncate — `List.ItemText`, `List.ItemDescription`. |
|
|
202
211
|
| [as-link.tsx](examples/as-link.tsx) | Rows as links to the invoice pages: a plain link, or your router link through the slot — `href`, `asChild`. |
|
|
203
|
-
| [reorder.tsx](examples/reorder.tsx) | Funnel stages in the team's order: a stage moves by its handle or Alt+arrows and is saved on the server — `onReorder`, `value`. |
|
|
212
|
+
| [reorder.tsx](examples/reorder.tsx) | Funnel stages in the team's order: a stage moves by its handle or Alt+arrows and is saved on the server; its switch leads the row, the grip ends it — `onReorder`, `value`, `side`. |
|
|
204
213
|
| [row-controls.tsx](examples/row-controls.tsx) | Funnel stages with their own controls: a colour dot names the stage's hue, a switch shows it on the board and a menu edits it, all beside the row that opens the stage — `List.ItemActions`, `Badge.Dot`. |
|
|
205
214
|
|
|
206
215
|
## Mistakes
|
|
@@ -212,6 +221,7 @@ Root attributes: `data-size`, `role="list"` (the list style reset would drop the
|
|
|
212
221
|
- Up / down buttons on rows or a hand-made `Dnd.Sortable` of rows to order them → `List.Root onReorder` with a `value` on every item.
|
|
213
222
|
- `onReorder` that rolls the order back itself on an error → return the promise; a rejection moves the row back.
|
|
214
223
|
- A Switch or a menu button put inside a row, or a row rebuilt as a `div` to hold one → `List.ItemActions` beside the row element.
|
|
224
|
+
- A Switch at the end of a reorderable row, between its label and the grip → `List.ItemActions side="start"`; the grip keeps the end.
|
|
215
225
|
- A hollow `Icon` circle or a hand-drawn dot as a stage colour → `Badge.Dot color` in `List.ItemIcon`.
|
|
216
226
|
|
|
217
227
|
## Related
|
|
@@ -1,15 +1,39 @@
|
|
|
1
|
-
/** Funnel stages in the team's order: a stage moves by its handle or Alt+arrows and is saved on the server — `onReorder`, `value`. */
|
|
2
|
-
import { Card, List, moveBefore } from "prime-ui-kit";
|
|
1
|
+
/** Funnel stages in the team's order: a stage moves by its handle or Alt+arrows and is saved on the server; its switch leads the row, the grip ends it — `onReorder`, `value`, `side`. */
|
|
2
|
+
import { Card, List, moveBefore, Switch } from "prime-ui-kit";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
|
|
5
5
|
import styles from "./examples.module.css";
|
|
6
6
|
|
|
7
7
|
const STAGES = [
|
|
8
|
-
{
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
{
|
|
9
|
+
id: "lead",
|
|
10
|
+
name: "Новый лид",
|
|
11
|
+
description: "Заявка с сайта или от партнёра",
|
|
12
|
+
deals: 42,
|
|
13
|
+
shown: true,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "qualified",
|
|
17
|
+
name: "Квалификация",
|
|
18
|
+
description: "Бюджет и сроки подтверждены",
|
|
19
|
+
deals: 18,
|
|
20
|
+
shown: true,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "proposal",
|
|
24
|
+
name: "Коммерческое предложение",
|
|
25
|
+
description: "КП отправлено",
|
|
26
|
+
deals: 11,
|
|
27
|
+
shown: true,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: "contract",
|
|
31
|
+
name: "Договор",
|
|
32
|
+
description: "Согласование с юристами",
|
|
33
|
+
deals: 6,
|
|
34
|
+
shown: true,
|
|
35
|
+
},
|
|
36
|
+
{ id: "won", name: "Оплата", description: "Счёт выставлен", deals: 3, shown: false },
|
|
13
37
|
];
|
|
14
38
|
|
|
15
39
|
const SAVE_DELAY_MS = 600;
|
|
@@ -36,6 +60,17 @@ export default function ListReorderExample() {
|
|
|
36
60
|
>
|
|
37
61
|
{stages.map((stage) => (
|
|
38
62
|
<List.Item key={stage.id} value={stage.id}>
|
|
63
|
+
<List.ItemActions side="start">
|
|
64
|
+
<Switch.Root
|
|
65
|
+
aria-label={`Показывать «${stage.name}» на доске`}
|
|
66
|
+
checked={stage.shown}
|
|
67
|
+
onCheckedChange={(shown) =>
|
|
68
|
+
setStages((current) =>
|
|
69
|
+
current.map((item) => (item.id === stage.id ? { ...item, shown } : item)),
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
/>
|
|
73
|
+
</List.ItemActions>
|
|
39
74
|
<List.ItemText>{stage.name}</List.ItemText>
|
|
40
75
|
<List.ItemDescription>{stage.description}</List.ItemDescription>
|
|
41
76
|
<List.ItemCount>{stage.deals}</List.ItemCount>
|
|
@@ -84,7 +84,7 @@ No DOM, no ref. State and dismiss policy.
|
|
|
84
84
|
| `…rest` | `HTMLAttributes<HTMLElement>` | — | `className` and the other attributes of the `<header>`. |
|
|
85
85
|
|
|
86
86
|
### Modal.Actions
|
|
87
|
-
`ref` → `HTMLDivElement`. A row of controls at the end of the header, before the close button: a status Badge, a ⋯ Dropdown
|
|
87
|
+
`ref` → `HTMLDivElement`. A row of controls at the end of the header, before the close button: a status Badge, a ⋯ Dropdown; under the title when it would get less than 12rem; or at the end of a `Modal.Section` heading. Controls inside take tier `s`.
|
|
88
88
|
|
|
89
89
|
| Prop | Type | Default | Description |
|
|
90
90
|
|---|---|---|---|
|
|
@@ -99,12 +99,20 @@ No DOM, no ref. State and dismiss policy.
|
|
|
99
99
|
| `children` | `ReactNode` | — (required) | An `Icon` (sized to the m icon), or the record's picture: an `Avatar.Root` (sized to the tile) or a `Thumbnail.Root`. |
|
|
100
100
|
| `…rest` | `Omit<HTMLAttributes<HTMLSpanElement>, "children">` | — | `className` and the other attributes of the tile. |
|
|
101
101
|
|
|
102
|
-
### Modal.Title
|
|
103
|
-
`ref` → `HTMLHeadingElement
|
|
102
|
+
### Modal.Title
|
|
103
|
+
`ref` → `HTMLHeadingElement`. `<h2>` (title-m); its id names the dialog.
|
|
104
104
|
|
|
105
105
|
| Prop | Type | Default | Description |
|
|
106
106
|
|---|---|---|---|
|
|
107
|
-
| `…rest` | `Omit<HTMLAttributes<HTMLHeadingElement
|
|
107
|
+
| `…rest` | `Omit<HTMLAttributes<HTMLHeadingElement>, "id">` | — | `className`, `children` and the other attributes except `id` (the dialog owns it). |
|
|
108
|
+
|
|
109
|
+
### Modal.Description
|
|
110
|
+
`ref` → `HTMLParagraphElement`. `<p>` (body-s, muted) under the title; its id describes the dialog.
|
|
111
|
+
|
|
112
|
+
| Prop | Type | Default | Description |
|
|
113
|
+
|---|---|---|---|
|
|
114
|
+
| `loading` | `boolean` | `false` | Its data loads: a `Skeleton` holds the line's place and `aria-busy` is set, so the header never moves; the data fades in. |
|
|
115
|
+
| `…rest` | `Omit<HTMLAttributes<HTMLParagraphElement>, "id">` | — | `className`, `children` and the other attributes except `id` (the dialog owns it). |
|
|
108
116
|
|
|
109
117
|
### Modal.Body
|
|
110
118
|
`ref` → `HTMLDivElement`. The only scrolling zone (a ScrollContainer), 16 gap between blocks.
|
|
@@ -114,7 +122,7 @@ No DOM, no ref. State and dismiss policy.
|
|
|
114
122
|
| `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `className`, `children` and the other attributes of the zone. |
|
|
115
123
|
|
|
116
124
|
### Modal.Section
|
|
117
|
-
`ref` → `HTMLElement`. A titled `<section>` of the body: an `<h3>` (title-s, under the `<h2>` title), an optional description, a `Modal.Actions` at the end of the heading row; the content 16 below, sections 32 apart. Fields group in a `Fieldset`.
|
|
125
|
+
`ref` → `HTMLElement`. A titled `<section>` of the body: an `<h3>` (title-s, under the `<h2>` title), an optional description, a `Modal.Actions` at the end of the heading row; the content 16 below, sections 32 apart, in any wrapper. Fields group in a `Fieldset`.
|
|
118
126
|
|
|
119
127
|
| Prop | Type | Default | Description |
|
|
120
128
|
|---|---|---|---|
|
|
@@ -127,7 +135,7 @@ No DOM, no ref. State and dismiss policy.
|
|
|
127
135
|
|
|
128
136
|
| Prop | Type | Default | Description |
|
|
129
137
|
|---|---|---|---|
|
|
130
|
-
| `layout` | `"fill" \| "end"` | `"fill"` for `xs` `s` `m`, `"end"` for `l` `xl` | `fill`: equal-width buttons in one row; `end`: auto width, at the end. Stacked on phones (viewport below 640 px) and in a dialog narrower than 360 px. |
|
|
138
|
+
| `layout` | `"fill" \| "end"` | `"fill"` for `xs` `s` `m`, `"end"` for `l` `xl` | `fill`: equal-width buttons in one row, wrapping rather than cutting a label; `end`: auto width, at the end. Stacked on phones (viewport below 640 px) and in a dialog narrower than 360 px. |
|
|
131
139
|
| `…rest` | `HTMLAttributes<HTMLElement>` | — | `className`, `children` and the other attributes of the `<footer>`. |
|
|
132
140
|
|
|
133
141
|
### Modal.Meta
|
|
@@ -138,7 +146,7 @@ No DOM, no ref. State and dismiss policy.
|
|
|
138
146
|
| `…rest` | `HTMLAttributes<HTMLParagraphElement>` | — | `className`, `children` and the other attributes of the `<p>`. |
|
|
139
147
|
|
|
140
148
|
### Modal.Guard
|
|
141
|
-
No DOM, no ref. Holds the dialog from anywhere inside Content, where the form state lives; renders only the built-in «discard changes?» confirm. Closing from code is never held.
|
|
149
|
+
No DOM, no ref. Holds the dialog from anywhere inside Content, where the form state lives; renders only the built-in «discard changes?» confirm. While `busy` or `dirty` the browser also asks before the tab closes or reloads. Closing from code is never held.
|
|
142
150
|
|
|
143
151
|
| Prop | Type | Default | Description |
|
|
144
152
|
|---|---|---|---|
|
|
@@ -175,7 +183,7 @@ Below 640px of viewport a centred dialog of every size becomes a full-width bott
|
|
|
175
183
|
### layout (Footer)
|
|
176
184
|
| Value | Looks like | Use when | Default |
|
|
177
185
|
|---|---|---|---|
|
|
178
|
-
| `fill` | Equal-width buttons in one row, gap 12 | Narrow dialogs with two actions | for `xs`, `s`, `m` |
|
|
186
|
+
| `fill` | Equal-width buttons in one row, gap 12; never narrower than their labels — when they do not fit, the last ones wrap to a row of their own | Narrow dialogs with two actions | for `xs`, `s`, `m` |
|
|
179
187
|
| `end` | Auto-width buttons at the end, gap 8 | Wide dialogs | for `l`, `xl` |
|
|
180
188
|
|
|
181
189
|
With a `Modal.Meta` the footer is a row in any layout: the status takes the free room at the start, the buttons keep their width at the end and stay one row — when the footer runs short the status goes above them first. On phones (viewport below 640px, where the dialog is a bottom sheet) and in a dialog narrower than 360px, actions stack full width in DOM order (primary last), the status above them.
|
|
@@ -218,6 +226,9 @@ Around the record's picture — an `Avatar.Root` or a `Thumbnail.Root` (found by
|
|
|
218
226
|
| closing | `open` turns false | the dialog keeps showing the children it had open while the exit motion plays |
|
|
219
227
|
| busy | `Modal.Guard busy` | Escape, the scrim, a swipe, the close button and `Modal.Close` do nothing; the close button and the `Close` child are `disabled` in place |
|
|
220
228
|
| dirty | `Modal.Guard dirty` | a dismiss opens the «Не сохранять изменения?» ConfirmDialog (`labels.discard*`); its confirm closes the dialog; a swipe past the threshold glides back and asks the same |
|
|
229
|
+
| leaving the tab | `Modal.Guard busy` or `dirty` | the browser asks before the tab closes or reloads (`beforeunload`), as with `Page.Guard` |
|
|
230
|
+
| description loading | `Modal.Description loading` | a `Skeleton` holds the line, `aria-busy` on the `<p>`; the data fades in under the same element |
|
|
231
|
+
| actions below | the title would get less than 12rem beside `Modal.Actions` | `data-actions-below` on the header: the actions move under the title and the description |
|
|
221
232
|
| sheet | a centred dialog on a phone viewport | `data-sheet` on the dialog: the bottom-sheet surface, the grab handle while it swipes |
|
|
222
233
|
| swiping | as a phone sheet, a drag down from the handle or the header (with `closeOnOutsideClick`; without it there is no handle and no swipe) | `data-swiping` and `--swipe-offset` on the dialog while the pointer drags it; past 30% of its height or on a flick it closes, otherwise it glides back; a busy `Modal.Guard` sets `data-swipe-disabled` and the handle takes no drag |
|
|
223
234
|
| placement | `placement` on Content | `data-placement` on the dialog |
|
|
@@ -231,7 +242,7 @@ Motion (`overlayMotion`): the scrim fades in and out over `base`; the dialog fad
|
|
|
231
242
|
- Max height = viewport minus `--prime-modal-viewport-padding` on both sides; only the body scrolls.
|
|
232
243
|
- Tabs in the header: a `Tabs.List` inside `Modal.Header` (with `Tabs.Root` around the header and the body) spans the header's last row. The header becomes the tab strip, edge to edge and without the hairline; the active tab is the body rising into it, the panels sit in the body.
|
|
233
244
|
- Fields inside take the floating layer's fill; a card inside is the next layer (`floating-1`), a flat tile. Group fields with a 20 gap.
|
|
234
|
-
- Titled groups of a long body: `Modal.Section label` — an `<h3>` under the dialog's `<h2>` title, an optional `description`, a `Modal.Actions` at the end of its heading row; content 16 below, sections 32 apart. A group of fields is a `Fieldset`.
|
|
245
|
+
- Titled groups of a long body: `Modal.Section label` — an `<h3>` under the dialog's `<h2>` title, an optional `description`, a `Modal.Actions` at the end of its heading row; content 16 below, sections 32 apart — directly in the body, in a `Tabs.Panel` or in a form, with no spacing wrapper of your own. A group of fields is a `Fieldset`.
|
|
235
246
|
- Narrow viewport (< 640px), `placement="center"`: the shared bottom-sheet surface (`src/internal/sheet.module.css`) — full width, rounded top, a grab handle strip on top while it swipes, up to the sheet top gap high, the bottom safe-area inset below the content.
|
|
236
247
|
- `placement="top"`: the dialog hangs from a line 12% of the viewport down (between `--prime-modal-viewport-padding` and `--prime-space-24`) and grows downward.
|
|
237
248
|
|
|
@@ -285,6 +296,8 @@ Motion (`overlayMotion`): the scrim fades in and out over `base`; the dialog fad
|
|
|
285
296
|
- A destructive confirm built as a Modal → use ConfirmDialog. A destructive step that needs input (type the name to delete) stays a Modal with `closeOnOutsideClick={false}`.
|
|
286
297
|
- Primary action not in `Modal.Confirm` → Enter does nothing; wrap it. In a form, the `type="submit"` button is the primary and stays outside `Modal.Confirm`: Enter in a field submits the form.
|
|
287
298
|
- Primary action first in the footer → put it last (DOM order is the visual order).
|
|
299
|
+
- «Удалить» as a third footer button of an edit dialog → the footer is the dialog's answer (Cancel + the primary); deleting the record goes to the last `tone="danger"` item of a ⋯ `Dropdown` in `Modal.Actions`, confirmed by a ConfirmDialog.
|
|
300
|
+
- A wrapper with its own gap around `Modal.Section`s inside a `Tabs.Panel` or a form → not needed: sections keep 32 between them in any wrapper.
|
|
288
301
|
- A hand-made heading row (`Typography as="h3"` + buttons) over a group in the body → `Modal.Section label` with `Modal.Actions`.
|
|
289
302
|
- Busy or unsaved state lifted out of the form into Root props → put `Modal.Guard` next to the form, inside Content.
|
|
290
303
|
- `key` or a conditional around `Modal.Root` to reset a form → the dialog unmounts at once, without its exit; keep the Root mounted and drive `open`.
|
|
@@ -292,5 +305,5 @@ Motion (`overlayMotion`): the scrim fades in and out over `base`; the dialog fad
|
|
|
292
305
|
- Long multi-section forms in a modal → use Drawer.
|
|
293
306
|
|
|
294
307
|
## Related
|
|
295
|
-
- **Built from:** the dialog shared with Drawer and Sheet (`internal/overlay/DialogParts`, `internal/overlay/ModalDialog`), [Button](../button/COMPONENT.md) (header close button), [ScrollContainer](../scroll-container/COMPONENT.md) (`Modal.Body`), [Avatar](../avatar/COMPONENT.md) and [Thumbnail](../thumbnail/COMPONENT.md) (a record's picture in `Modal.Icon`), [ConfirmDialog](../confirm-dialog/COMPONENT.md) (the `Modal.Guard` discard confirm), `Icon` (the close glyph)
|
|
308
|
+
- **Built from:** the dialog shared with Drawer and Sheet (`internal/overlay/DialogParts`, `internal/overlay/ModalDialog`), [Button](../button/COMPONENT.md) (header close button), [ScrollContainer](../scroll-container/COMPONENT.md) (`Modal.Body`), [Avatar](../avatar/COMPONENT.md) and [Thumbnail](../thumbnail/COMPONENT.md) (a record's picture in `Modal.Icon`), [Skeleton](../skeleton/COMPONENT.md) (`Modal.Description loading`), [ConfirmDialog](../confirm-dialog/COMPONENT.md) (the `Modal.Guard` discard confirm), `Icon` (the close glyph)
|
|
296
309
|
- **See also:** [ConfirmDialog](../confirm-dialog/COMPONENT.md) (a destructive confirm built on Modal `s`), [Drawer](../drawer/COMPONENT.md) (the same header, body, footer and `Guard` at the edge), [Popover](../popover/COMPONENT.md), [CommandMenu](../command-menu/COMPONENT.md)
|
|
@@ -48,7 +48,7 @@ ScrollContainer <div> (or the `as` tag); thin scrollbar, soft hidden edges
|
|
|
48
48
|
| `anchor` | `"start" \| "end"` | `"start"` | `end` — a chat or a log: opens at the end and follows new content while the person is at the end; scrolled away, the view holds still. |
|
|
49
49
|
| `onReachStart` | `() => void \| Promise<void>` | — | Fires within 120 px of the start, once per approach: load older content. A returned promise blocks repeats and sets `aria-busy`; content added above keeps the view. |
|
|
50
50
|
| `onReachEnd` | `() => void \| Promise<void>` | — | The scroll position came within 120 px of the end: load the next page. Same once-per-approach and promise rules as `onReachStart`. |
|
|
51
|
-
| `overscrollBehavior` | `"auto" \| "contain" \| "none"` | `"contain"` | CSS `overscroll-behavior
|
|
51
|
+
| `overscrollBehavior` | `"auto" \| "contain" \| "none"` | `"contain"` | CSS `overscroll-behavior` along the region's own axes; `contain` stops scroll chaining into the page, a scroll across them still reaches the region around. |
|
|
52
52
|
| `as` | `"div" \| "main" \| "aside" \| "section" \| "nav" \| "article" \| "pre"` | `"div"` | Root element; a landmark tag when the region is one, `pre` for preformatted text (CodeBlock). |
|
|
53
53
|
| `…rest` | `HTMLAttributes<HTMLElement>` | — | `children`, `className` (height, padding), `aria-label`, `tabIndex`, `role`, event handlers and the other attributes. |
|
|
54
54
|
|
|
@@ -158,14 +158,15 @@ Colour all items or none; do not give an item and its Count the same hue; prefer
|
|
|
158
158
|
| optional | `optional` | a muted `labels.optional` marker after the label |
|
|
159
159
|
| support row reserved | `reserveSupportRow` | the support row stays rendered while empty, so an error arriving shifts nothing |
|
|
160
160
|
| focus-visible | keyboard | focus ring inside the segment |
|
|
161
|
-
|
|
|
161
|
+
| compact | row wider than the container at the tier's padding | row `data-collapse="compact"`: single-line segments tighten their padding by one step, so a row a few pixels too wide keeps its last segment and count whole; if it still does not fit (and not every segment has an icon) it scrolls |
|
|
162
|
+
| collapsed | even the compact row does not fit and every segment has an icon | row `data-collapse="icon"`: titles, counts and descriptions leave the row, segments turn square; a `VisuallyHidden` copy of the title names each segment and a `Tooltip` shows it |
|
|
162
163
|
| overflow | row still wider than the container | root `data-overflow-start` / `data-overflow-end`: edge fades in the track color |
|
|
163
164
|
|
|
164
165
|
Item DOM: `data-state`, `data-disabled`, `data-icon-only`, `data-two-line`, `data-value`, `data-color`. The thumb (the shared selection indicator) glides (`emphasized` + `base`, `data-animate`) only into a user's choice (click, arrows); a value set from outside and layout changes snap it; it stays still under `prefers-reduced-motion`. It sits inside the segment track, which clips it, so moving the selection never changes the row's scroll area. When the row scrolls, the selected segment is kept in view on mount and on every value change: only the row scrolls, never the page, and the scroll glides only after a user's choice.
|
|
165
166
|
|
|
166
167
|
## Layout & spacing
|
|
167
168
|
- In a form it is a field: label → track `label-gap`, track → support row `hint-gap`, field → field `--prime-space-5` like every field.
|
|
168
|
-
- Width is content-based by default; the row is a switcher (foundation §9): segments never wrap or truncate. In a narrow container segments with icons drop their titles
|
|
169
|
+
- Width is content-based by default; the row is a switcher (foundation §9): segments never wrap or truncate. In a narrow container the segments first tighten their padding, then segments with icons drop their titles, then the row scrolls horizontally with fading edges.
|
|
169
170
|
- Without `size` the control takes the tier of its host (a toolbar, a form), else `m`.
|
|
170
171
|
- On a coarse pointer each segment's hit area grows to the 44 px touch target in height; the track keeps its tier height.
|
|
171
172
|
- In a toolbar: gap `--prime-space-3` between controls; keep every control at one size.
|
|
@@ -77,7 +77,7 @@ No DOM, no ref. State and dismiss policy.
|
|
|
77
77
|
| `…rest` | `HTMLAttributes<HTMLElement>` | — | `className` and the other attributes of the `<header>`. |
|
|
78
78
|
|
|
79
79
|
### Sheet.Actions
|
|
80
|
-
`ref` → `HTMLDivElement`. A row of controls at the end of the header, before the close button: a status Badge, a ⋯ Dropdown
|
|
80
|
+
`ref` → `HTMLDivElement`. A row of controls at the end of the header, before the close button: a status Badge, a ⋯ Dropdown; under the title when it would get less than 12rem. Controls inside take tier `s`.
|
|
81
81
|
|
|
82
82
|
| Prop | Type | Default | Description |
|
|
83
83
|
|---|---|---|---|
|
|
@@ -92,12 +92,20 @@ No DOM, no ref. State and dismiss policy.
|
|
|
92
92
|
| `children` | `ReactNode` | — (required) | An `Icon` (sized to the m icon), or the record's picture: an `Avatar.Root` (sized to the tile) or a `Thumbnail.Root`. |
|
|
93
93
|
| `…rest` | `Omit<HTMLAttributes<HTMLSpanElement>, "children">` | — | `className` and the other attributes of the tile. |
|
|
94
94
|
|
|
95
|
-
### Sheet.Title
|
|
96
|
-
`ref` → `HTMLHeadingElement
|
|
95
|
+
### Sheet.Title
|
|
96
|
+
`ref` → `HTMLHeadingElement`. `<h2>` (title-m); its id names the dialog.
|
|
97
97
|
|
|
98
98
|
| Prop | Type | Default | Description |
|
|
99
99
|
|---|---|---|---|
|
|
100
|
-
| `…rest` | `Omit<HTMLAttributes<HTMLHeadingElement
|
|
100
|
+
| `…rest` | `Omit<HTMLAttributes<HTMLHeadingElement>, "id">` | — | `className`, `children` and the other attributes except `id` (the dialog owns it). |
|
|
101
|
+
|
|
102
|
+
### Sheet.Description
|
|
103
|
+
`ref` → `HTMLParagraphElement`. `<p>` (body-s, muted) under the title; its id describes the dialog.
|
|
104
|
+
|
|
105
|
+
| Prop | Type | Default | Description |
|
|
106
|
+
|---|---|---|---|
|
|
107
|
+
| `loading` | `boolean` | `false` | Its data loads: a `Skeleton` holds the line's place and `aria-busy` is set, so the header never moves; the data fades in. |
|
|
108
|
+
| `…rest` | `Omit<HTMLAttributes<HTMLParagraphElement>, "id">` | — | `className`, `children` and the other attributes except `id` (the dialog owns it). |
|
|
101
109
|
|
|
102
110
|
### Sheet.Body
|
|
103
111
|
`ref` → `HTMLDivElement`. The only scrolling zone (a ScrollContainer), 16 gap between blocks.
|
|
@@ -111,7 +119,7 @@ No DOM, no ref. State and dismiss policy.
|
|
|
111
119
|
|
|
112
120
|
| Prop | Type | Default | Description |
|
|
113
121
|
|---|---|---|---|
|
|
114
|
-
| `layout` | `"fill" \| "end"` | `"end"` | `fill`: equal-width buttons in one row; `end`: auto width, at the end. Stacked on phones (viewport below 640 px) and in a dialog narrower than 360 px. |
|
|
122
|
+
| `layout` | `"fill" \| "end"` | `"end"` | `fill`: equal-width buttons in one row, wrapping rather than cutting a label; `end`: auto width, at the end. Stacked on phones (viewport below 640 px) and in a dialog narrower than 360 px. |
|
|
115
123
|
| `…rest` | `HTMLAttributes<HTMLElement>` | — | `className`, `children` and the other attributes of the `<footer>`. |
|
|
116
124
|
|
|
117
125
|
### Sheet.Meta
|
|
@@ -122,7 +130,7 @@ No DOM, no ref. State and dismiss policy.
|
|
|
122
130
|
| `…rest` | `HTMLAttributes<HTMLParagraphElement>` | — | `className`, `children` and the other attributes of the `<p>`. |
|
|
123
131
|
|
|
124
132
|
### Sheet.Guard
|
|
125
|
-
No DOM, no ref. Holds the dialog from anywhere inside Content, where the form state lives; renders only the built-in «discard changes?» confirm. Closing from code is never held.
|
|
133
|
+
No DOM, no ref. Holds the dialog from anywhere inside Content, where the form state lives; renders only the built-in «discard changes?» confirm. While `busy` or `dirty` the browser also asks before the tab closes or reloads. Closing from code is never held.
|
|
126
134
|
|
|
127
135
|
| Prop | Type | Default | Description |
|
|
128
136
|
|---|---|---|---|
|
|
@@ -165,6 +173,9 @@ Sheet has no `variant`, `side` or `size`: it always rises from the bottom edge,
|
|
|
165
173
|
| closing | `open` turns false | the panel keeps showing the children it had open while it slides down |
|
|
166
174
|
| busy | `Sheet.Guard busy` | Escape, the scrim, a swipe, the close button and `Sheet.Close` do nothing; the close button and the `Close` child are `disabled` in place; the handle stays, `data-swipe-disabled` on the panel (no grab cursor) |
|
|
167
175
|
| dirty | `Sheet.Guard dirty` | a dismiss opens the «Не сохранять изменения?» ConfirmDialog (`labels.discard*`); a swipe past the threshold glides back and asks the same |
|
|
176
|
+
| leaving the tab | `Sheet.Guard busy` or `dirty` | the browser asks before the tab closes or reloads (`beforeunload`), as with `Page.Guard` |
|
|
177
|
+
| description loading | `Sheet.Description loading` | a `Skeleton` holds the line, `aria-busy` on the `<p>`; the data fades in under the same element |
|
|
178
|
+
| actions below | the title would get less than 12rem beside `Sheet.Actions` | `data-actions-below` on the header: the actions move under the title and the description |
|
|
168
179
|
|
|
169
180
|
Motion: the scrim fades, the sheet slides up over `slow` and down over `base` (`overlayMotion`); under `prefers-reduced-motion` it unmounts at once. A swipe down moves the sheet with the pointer; on release it closes past 30% of its height or on a quick flick and glides the rest of the way out, otherwise it glides back — both over `base` on the `emphasized` (iOS sheet) curve. A pull upward meets growing resistance and stops at 24; the sheet's fill continues that far below the screen edge. The scrim thins as the sheet goes down. The drag starts from the handle or the header, never from the body, so its content scrolls and its controls work as usual.
|
|
170
181
|
|
|
@@ -237,5 +248,5 @@ Motion: the scrim fades, the sheet slides up over `slow` and down over `base` (`
|
|
|
237
248
|
- `closeOnOutsideClick={false}` and `closeOnEscape={false}` with no header × and no `Sheet.Close` → nothing closes it; keep a button that answers.
|
|
238
249
|
|
|
239
250
|
## Related
|
|
240
|
-
- **Built from:** the dialog shared with Modal and Drawer (`internal/overlay/DialogParts`), [Button](../button/COMPONENT.md) (close button), [ScrollContainer](../scroll-container/COMPONENT.md) (`Sheet.Body`), [Avatar](../avatar/COMPONENT.md) and [Thumbnail](../thumbnail/COMPONENT.md) (a record's picture in `Sheet.Icon`), [ConfirmDialog](../confirm-dialog/COMPONENT.md) (the `Sheet.Guard` discard confirm), `Icon` (the close glyph)
|
|
251
|
+
- **Built from:** the dialog shared with Modal and Drawer (`internal/overlay/DialogParts`), [Button](../button/COMPONENT.md) (close button), [ScrollContainer](../scroll-container/COMPONENT.md) (`Sheet.Body`), [Avatar](../avatar/COMPONENT.md) and [Thumbnail](../thumbnail/COMPONENT.md) (a record's picture in `Sheet.Icon`), [Skeleton](../skeleton/COMPONENT.md) (`Sheet.Description loading`), [ConfirmDialog](../confirm-dialog/COMPONENT.md) (the `Sheet.Guard` discard confirm), `Icon` (the close glyph)
|
|
241
252
|
- **See also:** [Drawer](../drawer/COMPONENT.md) (the same parts as a side panel), [Modal](../modal/COMPONENT.md) (the same parts in the centre), [Datepicker](../datepicker/COMPONENT.md) (`Datepicker.Panel` in a sheet), [Dropdown](../dropdown/COMPONENT.md)
|
|
@@ -173,7 +173,7 @@ same height and type.
|
|
|
173
173
|
- Values and chips wrap with `--prime-space-2` gaps; «Сбросить все» is pushed to the end. The chips row rises in with the first filter and closes up in place with the last (`partPresence`).
|
|
174
174
|
- Option groups stack `--prime-space-3` apart, a caption `--prime-space-1` above each group's values. A range row holds two equal Inputs with a dash between them, centred on the field label.
|
|
175
175
|
- While typing a search a range row stays only when its field name matches.
|
|
176
|
-
- The root draws nothing: its host places Toolbar and Chips.
|
|
176
|
+
- The root draws nothing: its host places Toolbar and Chips, next to what they filter. A table among other blocks (KPI cards, a chart) takes them in its own tools row — the DataTable `toolbar` (the Toolbar) and `toolbarChips` (the Chips), with `SmartFilter.Root` around the DataTable. A page that is one list takes them in its bar — the Toolbar in `Page.Tools`, the Chips in `Page.Chips`, with `SmartFilter.Root` around `Page.Root`. Elsewhere a host stacks them (a `Card.Body`, a form column).
|
|
177
177
|
|
|
178
178
|
## Accessibility
|
|
179
179
|
|
|
@@ -252,4 +252,4 @@ same height and type.
|
|
|
252
252
|
|
|
253
253
|
## Related
|
|
254
254
|
- **Built from:** [Button](../button/COMPONENT.md), [Badge](../badge/COMPONENT.md), [Input](../input/COMPONENT.md), [Datepicker](../datepicker/COMPONENT.md), [Popover](../popover/COMPONENT.md), [Divider](../divider/COMPONENT.md), [Kbd](../kbd/COMPONENT.md), [EmptyPage](../empty-page/COMPONENT.md), [LinkButton](../link-button/COMPONENT.md), [Typography](../typography/COMPONENT.md), Icon (`action.search`, `action.filter`, `action.add`, `nav.chevronDown`), [VisuallyHidden](../visually-hidden/COMPONENT.md)
|
|
255
|
-
- **See also:** [Page](../../layout/page/COMPONENT.md) (`Page.Tools`, `Page.Chips`), [TagSelect](../tag-select/COMPONENT.md), [DataTable](../data-table/COMPONENT.md)
|
|
255
|
+
- **See also:** [Page](../../layout/page/COMPONENT.md) (`Page.Tools`, `Page.Chips`), [TagSelect](../tag-select/COMPONENT.md), [DataTable](../data-table/COMPONENT.md) (`toolbar`, `toolbarChips`)
|
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
## When to use
|
|
9
9
|
- Every route rendered inside `AppShell.Main`: the app is navigation and the page, and the page carries its own top (`Page.TopBar`), title (`Page.Title`, the `<h1>`) and body.
|
|
10
10
|
- A work screen (a list, a board, a chat, a schedule): `Page.TopBar` with the title (`Page.Heading`), the page's tools (`Page.Tools`: sections, search and filter, view), all its buttons (`Page.Actions`) and the active filters (`Page.Chips`).
|
|
11
|
+
- A filter stands next to what it filters. `Page.Tools` holds what acts on the whole page: sections, the view, a period that drives several blocks (the KPI cards and the table). The search, filter, chips and column chooser of a page that is one list stay there too — the list is the page. On a page that holds more than its table (KPI cards, a chart), they belong to the table's own tools row (DataTable `toolbar` + `toolbarChips`), not the bar.
|
|
11
12
|
- A document page (settings, a long form, help) or an overview (a dashboard): `Page.Header` in the flow — the large title and its buttons — and `Page.TopBar collapse`, which repeats the title once it scrolls away and keeps the path and the buttons in reach.
|
|
12
13
|
- A nested record: a `Breadcrumb` path in `Page.Heading`; in the bar the title reads as its last level.
|
|
13
14
|
- A text page held to a reading measure (`maxWidth="readable"`), a wide dashboard capped at the content width (`maxWidth="wide"`).
|
|
14
15
|
- The tiles of a dashboard — KPI cards, charts, panels — as one board (`Page.Grid` + `Page.Cell`).
|
|
15
|
-
- A new topic of the page with its own heading and a link or button beside it (`Page.Section
|
|
16
|
+
- A new topic of the page with its own heading and a link or button beside it (`Page.Section`, the heading over its content).
|
|
16
17
|
- A page whose body takes the rest of the panel's height — a log table, a board, a chat (`fill`).
|
|
17
18
|
- Mail, a messenger, a ticket queue: a list and the chosen record side by side, one at a time on a narrow panel (`Page.Split`).
|
|
18
19
|
- A form that is the whole page (a record's editor, settings with one save): `Page.Guard dirty busy` holds leaving it through the navigation, the path and the browser.
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
## When not to use
|
|
21
22
|
- The app frame (navigation rail, scrolling main, phone footer) → use [AppShell](../app-shell/COMPONENT.md); there is no global app header — a bar belongs to its page.
|
|
22
23
|
- A search across the whole app → a page of its own or a [CommandMenu](../../components/command-menu/COMPONENT.md); the top bar carries only what its page needs.
|
|
23
|
-
- A bounded block inside the page → use [Card](../../components/card/COMPONENT.md).
|
|
24
|
+
- A bounded block inside the page, a titled panel of a settings page included → use [Card](../../components/card/COMPONENT.md) with its own `Card.Header`.
|
|
24
25
|
- An empty / error / not-found page → use [EmptyPage](../../components/empty-page/COMPONENT.md).
|
|
25
26
|
- A heading inside a card → `Card.Title`; text headings inside prose → use [Typography](../../components/typography/COMPONENT.md).
|
|
26
27
|
- A grid inside one block (thumbnails, fields, bars in a panel) → the block's own CSS grid; `Page.Grid` places the page's tiles.
|
|
@@ -42,7 +43,7 @@ Page.Root the page column (<div>); maxWidth, fill, labe
|
|
|
42
43
|
│ │ ├─ Breadcrumb.Root the path; the heading draws one chevron after it
|
|
43
44
|
│ │ ├─ Page.Title <h1>, title-m, the path's last level, truncates
|
|
44
45
|
│ │ └─ Page.Description <p>, muted caption under the whole line, truncates
|
|
45
|
-
│ ├─ Page.Tools the page
|
|
46
|
+
│ ├─ Page.Tools what acts on the whole page, in the order written: the one tool row (as the DataTable toolbar)
|
|
46
47
|
│ │ ├─ SegmentedControl.Root sections, view (fullWidth unless set)
|
|
47
48
|
│ │ ├─ SmartFilter.Toolbar search and filter: grows first on a line of its own
|
|
48
49
|
│ │ ├─ Datepicker.Root a period (fullWidth unless set)
|
|
@@ -121,7 +122,7 @@ Page.Root the page column (<div>); maxWidth, fill, labe
|
|
|
121
122
|
| `…rest` | `HTMLAttributes<HTMLParagraphElement>` | — | `children`, `className` and the other paragraph attributes. |
|
|
122
123
|
|
|
123
124
|
### Page.Tools
|
|
124
|
-
`ref` → `HTMLDivElement`.
|
|
125
|
+
`ref` → `HTMLDivElement`. What acts on the whole page: sections, a shared period, view; the search of a one-list page. The tool row of the DataTable `toolbar`: a search takes the free room, the rest keep their width at the end. Named, a `group`.
|
|
125
126
|
|
|
126
127
|
| Prop | Type | Default | Description |
|
|
127
128
|
|---|---|---|---|
|
|
@@ -155,7 +156,6 @@ Page.Root the page column (<div>); maxWidth, fill, labe
|
|
|
155
156
|
|---|---|---|---|
|
|
156
157
|
| `label` | `ReactNode` | — (required) | The visible heading (`h2`); it also names the section. |
|
|
157
158
|
| `description` | `ReactNode` | — | One line of context under the heading, in secondary body-s. |
|
|
158
|
-
| `layout` | `"stack" \| "aside"` | `"stack"` | `stack` — the heading over the content; `aside` — a ~16rem heading column beside it (a settings page), above it once the content would get narrower than 30rem. |
|
|
159
159
|
| `…rest` | `Omit<HTMLAttributes<HTMLElement>, "title">` | — | `children` (the content; `Page.Actions` goes to the heading row), `className` and the other section attributes. |
|
|
160
160
|
|
|
161
161
|
### Page.Grid
|
|
@@ -239,19 +239,13 @@ The size follows the place; the consumer passes nothing, and there are no title
|
|
|
239
239
|
| `dirty` (Guard) | nothing until a person leaves: a press on the navigation or the path asks «leave without saving?» | a form that is the page has unsaved changes | `false` |
|
|
240
240
|
| `busy` (Guard) | nothing until a person leaves: a press on the navigation or the path does nothing | the page's save request runs | `false` |
|
|
241
241
|
|
|
242
|
-
### layout (Section)
|
|
243
|
-
| Value | Looks like | Use when | Default |
|
|
244
|
-
|---|---|---|---|
|
|
245
|
-
| `stack` | the heading row over the content, 16 apart | a topic of a dashboard, a list or a detail page | ✓ |
|
|
246
|
-
| `aside` | a ~16rem heading column beside the content, above it once the content would get < 30rem | a settings page: a heading column beside each panel | |
|
|
247
|
-
|
|
248
242
|
### Top bar plan
|
|
249
243
|
One plan, chosen from the natural widths of the groups (`data-plan` on the bar's row). The bar takes the first step whose first line fits:
|
|
250
244
|
|
|
251
245
|
| Step | Looks like | Use when | Default |
|
|
252
246
|
|---|---|---|---|
|
|
253
247
|
| `one` | `[Heading 1fr][Tools][Actions]` on one line | everything fits | yes |
|
|
254
|
-
| `below` | the tools on a line of their own under the heading and the actions,
|
|
248
|
+
| `below` | the tools on a line of their own under the heading and the actions — the one tool row, as the DataTable `toolbar`: a search (`SmartFilter.Toolbar`, `Input.Root`) takes the free room, switchers, pickers and buttons keep their width at the end; under 36rem the search takes a line of its own and a `SegmentedControl.Root` / `Datepicker.Root` / Select fills the line it stands on | heading + tools + actions do not fit | |
|
|
255
249
|
| `icons-secondary` | as `below`; secondary Buttons with a `Button.Icon` show only the icon, the label is their name and their tooltip | heading + actions still do not fit | |
|
|
256
250
|
| `icons` | the primary Button gives way to its icon too | still too wide | |
|
|
257
251
|
| `fold` | the secondary Buttons fold into «⋯» (`labels.more`); the primary stays | still too wide, and «⋯» is narrower than their icons (a single secondary keeps its icon); past it a Breadcrumb path folds into «…»; if the path and the title still do not share the line, the heading stacks: the path on its own line over the title, the title and the description wrapping (`data-heading="stack"`); a heading without a path truncates | |
|
|
@@ -288,7 +282,6 @@ A wide cell (`span` 7–11) written next to a narrow one (`span` 4–5) is a pai
|
|
|
288
282
|
| folded buttons | plan `fold` | the secondary Buttons' wrappers `hidden`; a «⋯» Dropdown in their place, their `menuitem`s inside |
|
|
289
283
|
| heading place | inside TopBar or in the flow | `data-place="bar" \| "flow"` on Heading |
|
|
290
284
|
| with actions | `Page.Actions` child | `data-has-actions="true"` on Header / the section heading row |
|
|
291
|
-
| section heading column | `layout="aside"` on Section | `data-layout="aside"` on Section (absent for `stack`) |
|
|
292
285
|
| tile span | `span` / `rows` on Cell | `data-span="1"…"12"` (always), `data-rows="2"…"4"` (absent for 1) |
|
|
293
286
|
| tile pair | a `span` 7–11 Cell next to a `span` 4–5 Cell in the Grid | `data-pair="wide" \| "narrow"` on both Cells (set by the Grid) |
|
|
294
287
|
| held | `Page.Guard` `busy` or `dirty` | a press on a `Sidebar.Item`, `Sidebar.Brand`, `BottomNav.Item` or `Breadcrumb.Item` link is stopped (capture phase, before the item's and the router link's handlers); `dirty` opens the `ConfirmDialog` and its confirm repeats the press once the dialog has closed (its texts are the `leave*` keys of `labels` on `Page.Root`); a `beforeunload` listener while either is on. A press that opens a new tab (a modifier key, a middle click, `target="_blank"`) and navigation from code are never held |
|
|
@@ -298,6 +291,7 @@ A wide cell (`span` 7–11) written next to a narrow one (`span` 4–5) is a pai
|
|
|
298
291
|
## Layout & spacing
|
|
299
292
|
- The edge air comes from the host: `AppShell.Main` sets `--page-gutter` (the page gutter, 16 → 24 → 32) and `--page-top` (24 → 32 from 1024px); `Page.Root` pads itself with them. Outside a host the page brings no air. The page resets both for what it holds, so a page nested in it starts clean.
|
|
300
293
|
- `Page.TopBar` steps out of the gutter to the panel's edges and keeps the gutter inside; padding 12 above (or the top safe-area inset) and below; what follows starts 24 under its controls (header → body; the bar's own 12 counts in). The first line is as high as the Sidebar brand row (control m + 8), so the two read as one line. Groups 16 apart on a line, lines 12 apart; tools 8 apart; buttons 8 apart.
|
|
294
|
+
- `Page.Tools` and `Page.Chips` are the kit's one tool row and chips line (`ToolRow`), the same as the DataTable `toolbar` and `toolbarChips`: the bar only places them. On the first line every tool keeps its natural width; on a line of their own they take the line and lay out from its width (container `prime-tool-row`), never from the window.
|
|
301
295
|
- In the bar only the heading's column gives (`minmax(0, 1fr)`): the tools and the actions keep their width. The heading keeps its natural width until every button step is taken; then a heading with a path stacks (the path over the title, the title and the description wrapping), so no level is cut to a fragment; a heading without a path truncates its title.
|
|
302
296
|
- The plan is measured, never chosen by breakpoints: the bar lays itself out from its own width.
|
|
303
297
|
- Header (flow) → Body 24; blocks inside Body 24; a `Page.Section` 40 from its neighbours (the body's 24 + 16); tile → tile in a Grid 16 on both axes; section heading → content 16, heading → description 4; flow Title → Description 8; heading → Actions 24 side by side, 16 once they wrap below.
|
|
@@ -349,12 +343,12 @@ A wide cell (`span` 7–11) written next to a narrow one (`span` 4–5) is a pai
|
|
|
349
343
|
| [collapse.tsx](examples/collapse.tsx) | An overview whose large title scrolls away under the top bar: the bar repeats it with its line of data and keeps the period and the page's buttons in reach — `collapse`. |
|
|
350
344
|
| [tools.tsx](examples/tools.tsx) | The orders page's tools in its top bar: sections with counts, search and filter, the period, in the order written; the active filters on a line under everything — `Page.Tools`, `Page.Chips`. |
|
|
351
345
|
| [actions-collapse.tsx](examples/actions-collapse.tsx) | The buttons of an invoices page on a tablet-wide column: the line runs short, so the secondary buttons show only their icons with the label as the name and the tooltip, the primary keeps its label — `Page.Actions`, `Button.Icon`. |
|
|
352
|
-
| [sections.tsx](examples/sections.tsx) | A page with titled sections: tiles of one screen close together, a new topic set off by air, a link at the end of the heading
|
|
346
|
+
| [sections.tsx](examples/sections.tsx) | A page with titled sections: tiles of one screen close together, a new topic set off by air, a link at the end of the heading — `Page.Section`, `label`, `description`, `Page.Actions`. |
|
|
353
347
|
| [grid.tsx](examples/grid.tsx) | A dashboard board: four KPI tiles, a chart two rows high beside two panels, one gap on both axes — `Page.Grid`, `Page.Cell`, `span`, `rows`. |
|
|
354
348
|
| [list-detail.tsx](examples/list-detail.tsx) | A ticket queue as list + detail on a full-height page: side by side on a wide panel, one pane at a time with a back button on a narrow one; the chosen ticket cross-fades in — `Page.Split`, `Page.List`, `Page.Detail`, `Page.BackButton`, `fill`. |
|
|
355
349
|
| [guard.tsx](examples/guard.tsx) | A client's card edited on its own page: after an edit a press on the navigation or the path asks before the changes are lost, and while it saves nothing leaves — `Page.Guard`, `dirty`, `busy`. |
|
|
356
350
|
| [narrow.tsx](examples/narrow.tsx) | On a phone the top bar leads with the menu button that opens the navigation by itself, the primary button gives way to its icon and the secondary ones fold into «⋯» — `offCanvas`, `Page.Actions`. |
|
|
357
|
-
| [screen.tsx](examples/screen.tsx) | A settings page as a document: the path in the top bar that repeats the title once it scrolls away, the large title in the flow,
|
|
351
|
+
| [screen.tsx](examples/screen.tsx) | A settings page as a document: the path in the top bar that repeats the title once it scrolls away, the large title in the flow, each section a card with its own heading, a form saved by its own button, switches that apply at once and a danger zone with a confirm — `collapse`, `maxWidth`, `Card.Header`. |
|
|
358
352
|
|
|
359
353
|
## Mistakes
|
|
360
354
|
- `{ready ? <Page.Description>…</Page.Description> : null}` → the line appears after the load and the title jumps; keep it mounted with `loading` until the data comes.
|
|
@@ -366,11 +360,13 @@ A wide cell (`span` 7–11) written next to a narrow one (`span` 4–5) is a pai
|
|
|
366
360
|
- Buttons without an icon in a crowded bar → they cannot give way to an icon; give each `Button.Root` a `Button.Icon` beside its label.
|
|
367
361
|
- Two places for buttons (some beside the title, the primary among the tools) → every button of the page goes into the one `Page.Actions`, the primary last.
|
|
368
362
|
- `SmartFilter.Root` inside the bar, around `Page.Tools` → it holds no DOM; wrap it around `Page.Root` so its Toolbar (in `Page.Tools`) and its Chips (in `Page.Chips`) share it.
|
|
363
|
+
- A table's search, filter, chips or «Колонки» in `Page.Tools` / `Page.Chips` above KPI cards or a chart they do not filter → they read as filters of the whole page; move them into the table's `toolbar` / `toolbarChips`. The bar keeps the title, a period that drives every block, sections and the primary action.
|
|
369
364
|
- `Page.Header` inside `Page.TopBar` → the bar takes `Page.Heading` and `Page.Actions` directly; `Page.Header` is the flow's document header.
|
|
370
365
|
- A hand-made menu button for the phone Sidebar → the bar draws it while the Sidebar is off-canvas.
|
|
371
366
|
- Hiding buttons with media queries on a phone → `Page.Actions` in the bar collapses and folds them by measured width.
|
|
372
367
|
- Wrapping a group of the bar or `Page.Title` in your own component → the bar and the heading find their parts among their direct children.
|
|
373
368
|
- A hand-made `<section>` + `Typography as="h2"` + own gap CSS → `Page.Section label`.
|
|
369
|
+
- A heading column beside a panel (the section's title and description on the left, its card on the right) → it wastes the width and breaks the reading line; a titled block is a `Card.Root` with its own `Card.Header` (`Card.Title as="h2"`, `Card.Description`) stacked in the flow.
|
|
374
370
|
- Each row of cards in its own grid → put every tile of the screen in one `Page.Grid`.
|
|
375
371
|
- Computing a height from `100vh` minus the bar for a full-height table or chat → `Page.Root fill` and a filling child.
|
|
376
372
|
- A list + detail built with window media queries → `Page.Split` follows its own width.
|
|
@@ -378,5 +374,5 @@ A wide cell (`span` 7–11) written next to a narrow one (`span` 4–5) is a pai
|
|
|
378
374
|
- Tiles of a row cut to 6 + 6 so a mid-width grid keeps no hole → write the 8 and the 4 next to each other; the grid pairs them as 2/3 + 1/3.
|
|
379
375
|
|
|
380
376
|
## Related
|
|
381
|
-
- **Built from:** [AppShell](../app-shell/COMPONENT.md) (the navigation the menu button opens), [Breadcrumb](../../components/breadcrumb/COMPONENT.md) (the path the heading places), [Button](../../components/button/COMPONENT.md) (the menu button, «⋯», `Page.BackButton`; the icon-only label hook), [Dropdown](../../components/dropdown/COMPONENT.md) (folded buttons), [Tooltip](../../components/tooltip/COMPONENT.md) (the label of an icon-only button), [
|
|
382
|
-
- **See also:** [Sidebar](../sidebar/COMPONENT.md), [BottomNav](../bottom-nav/COMPONENT.md), [Select](../../components/select/COMPONENT.md), [Card](../../components/card/COMPONENT.md), [ChartFrame](../../components/chart-frame/COMPONENT.md), [List](../../components/list/COMPONENT.md), [EmptyPage](../../components/empty-page/COMPONENT.md), [Drawer](../../components/drawer/COMPONENT.md), [VisuallyHidden](../../components/visually-hidden/COMPONENT.md)
|
|
377
|
+
- **Built from:** [AppShell](../app-shell/COMPONENT.md) (the navigation the menu button opens), [Breadcrumb](../../components/breadcrumb/COMPONENT.md) (the path the heading places), [Button](../../components/button/COMPONENT.md) (the menu button, «⋯», `Page.BackButton`; the icon-only label hook), [Dropdown](../../components/dropdown/COMPONENT.md) (folded buttons), [Tooltip](../../components/tooltip/COMPONENT.md) (the label of an icon-only button), `ToolRow` (`Page.Tools` and `Page.Chips`: the kit's one tool row and chips line) with [SmartFilter](../../components/smart-filter/COMPONENT.md), [Input](../../components/input/COMPONENT.md) and [Typography](../../components/typography/COMPONENT.md) (what grows in the tool row), [SegmentedControl](../../components/segmented-control/COMPONENT.md), [Datepicker](../../components/datepicker/COMPONENT.md) and [Select](../../components/select/COMPONENT.md) (what fills a short line; the first two get `fullWidth`), [Crossfade](../../components/crossfade/COMPONENT.md) (a `Page.Cell` child gets `fill`), [Skeleton](../../components/skeleton/COMPONENT.md) (the line of data while it loads), [ConfirmDialog](../../components/confirm-dialog/COMPONENT.md) (the confirm of `Page.Guard`), Icon (`nav.menu`, `nav.chevronRight`, `action.more`, `nav.chevronLeft`)
|
|
378
|
+
- **See also:** [DataTable](../../components/data-table/COMPONENT.md) (`toolbar`, `toolbarChips`), [Sidebar](../sidebar/COMPONENT.md), [BottomNav](../bottom-nav/COMPONENT.md), [Select](../../components/select/COMPONENT.md), [Card](../../components/card/COMPONENT.md), [ChartFrame](../../components/chart-frame/COMPONENT.md), [List](../../components/list/COMPONENT.md), [EmptyPage](../../components/empty-page/COMPONENT.md), [Drawer](../../components/drawer/COMPONENT.md), [VisuallyHidden](../../components/visually-hidden/COMPONENT.md)
|