prime-ui-kit 0.13.0 → 0.14.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 +7 -6
- package/dist/chunks/{chunk-ZSJMNA46.js → chunk-P6ZO37JM.js} +1 -1
- package/dist/chunks/{chunk-Z3WKKAS6.js → chunk-SYEX7OVT.js} +3572 -2865
- package/dist/chunks/{chunk-E6SQBSDF.js → chunk-WXKRUVSE.js} +199 -162
- package/dist/color-picker.js +2 -2
- package/dist/components/banner/Banner.d.ts +5 -2
- package/dist/components/chart-frame/ChartFrame.d.ts +19 -6
- package/dist/components/chat/Chat.d.ts +2 -2
- package/dist/components/chat/ChatPinned.d.ts +2 -2
- package/dist/components/chat/MessageList.d.ts +1 -1
- package/dist/components/chat/chatContext.d.ts +1 -1
- package/dist/components/field-list/FieldList.d.ts +90 -0
- package/dist/components/index.d.ts +3 -1
- package/dist/components/input/Input.d.ts +2 -2
- package/dist/components/kanban/Kanban.d.ts +6 -3
- package/dist/components/page-content/PageContent.d.ts +55 -4
- package/dist/components/sparkline/Sparkline.d.ts +64 -15
- package/dist/components/sparkline/geometry.d.ts +26 -0
- package/dist/components/tooltip/Tooltip.d.ts +5 -2
- package/dist/hooks/usePosition.d.ts +15 -4
- package/dist/index.css +1 -1
- package/dist/index.js +4 -2
- package/dist/internal/ChartTooltip.d.ts +26 -0
- package/dist/internal/FieldAction.d.ts +6 -7
- package/dist/internal/fieldCell.d.ts +21 -0
- package/dist/internal/messageList.d.ts +2 -2
- package/dist/internal/palette.d.ts +7 -0
- package/dist/skill/SKILL.md +24 -14
- package/dist/skill/anti-slop.md +77 -4
- package/dist/skill/cheatsheet.md +24 -5
- package/dist/skill/checklist.md +19 -1
- package/dist/skill/choosing.md +10 -5
- package/dist/skill/components.md +4 -3
- package/dist/skill/composition.md +28 -15
- package/dist/skill/foundations.md +8 -6
- package/dist/skill/layouts.md +6 -6
- package/dist/skill/patterns/app-shell.module.css +1 -8
- package/dist/skill/patterns/app-shell.tsx +11 -9
- package/dist/skill/patterns/chat.tsx +23 -5
- package/dist/skill/patterns/dashboard.module.css +1 -31
- package/dist/skill/patterns/dashboard.tsx +150 -136
- package/dist/skill/patterns/detail-page.module.css +0 -3
- package/dist/skill/patterns/detail-page.tsx +4 -7
- package/dist/skill/patterns/form-drawer.tsx +2 -2
- package/dist/skill/patterns/kanban-board.tsx +4 -2
- package/dist/skill/patterns/list-page.tsx +2 -2
- package/dist/skill/patterns/media-library.module.css +0 -22
- package/dist/skill/patterns/media-library.tsx +17 -18
- package/dist/skill/patterns/record-editor.module.css +18 -0
- package/dist/skill/patterns/record-editor.tsx +356 -0
- package/dist/skill/patterns/screen-states.module.css +3 -17
- package/dist/skill/patterns/screen-states.tsx +70 -69
- package/dist/skill/patterns/settings-page.module.css +1 -21
- package/dist/skill/patterns/settings-page.tsx +58 -79
- package/dist/skill/reference/components/avatar/COMPONENT.md +4 -4
- package/dist/skill/reference/components/avatar/examples/presence.tsx +1 -1
- package/dist/skill/reference/components/avatar/examples/states.tsx +1 -1
- package/dist/skill/reference/components/banner/COMPONENT.md +6 -6
- package/dist/skill/reference/components/banner/examples/dismissible.tsx +22 -11
- package/dist/skill/reference/components/banner/examples/examples.module.css +3 -3
- package/dist/skill/reference/components/banner/examples/narrow.tsx +1 -1
- package/dist/skill/reference/components/breadcrumb/COMPONENT.md +1 -1
- package/dist/skill/reference/components/breadcrumb/examples/overflow.tsx +1 -1
- package/dist/skill/reference/components/card/COMPONENT.md +5 -4
- package/dist/skill/reference/components/card/examples/examples.module.css +0 -28
- package/dist/skill/reference/components/card/examples/kpi-media.tsx +13 -11
- package/dist/skill/reference/components/card/examples/narrow.tsx +1 -1
- package/dist/skill/reference/components/card/examples/panel-chart.tsx +45 -22
- package/dist/skill/reference/components/chart-frame/COMPONENT.md +10 -7
- package/dist/skill/reference/components/chart-frame/examples/tooltip.tsx +20 -24
- package/dist/skill/reference/components/chat/COMPONENT.md +3 -3
- package/dist/skill/reference/components/chat/examples/search.tsx +1 -1
- package/dist/skill/reference/components/chat-list/COMPONENT.md +1 -1
- package/dist/skill/reference/components/checkbox/examples/indicator.tsx +24 -2
- package/dist/skill/reference/components/color-picker/COMPONENT.md +2 -2
- package/dist/skill/reference/components/color-swatches/COMPONENT.md +1 -0
- package/dist/skill/reference/components/datepicker/COMPONENT.md +1 -0
- package/dist/skill/reference/components/dnd/COMPONENT.md +3 -3
- package/dist/skill/reference/components/field-list/COMPONENT.md +164 -0
- package/dist/skill/reference/components/field-list/examples/base-row.tsx +76 -0
- package/dist/skill/reference/components/field-list/examples/controlled.tsx +72 -0
- package/dist/skill/reference/components/field-list/examples/errors.tsx +85 -0
- package/dist/skill/reference/components/field-list/examples/examples.module.css +34 -0
- package/dist/skill/reference/components/field-list/examples/limits.tsx +55 -0
- package/dist/skill/reference/components/field-list/examples/locked.tsx +139 -0
- package/dist/skill/reference/components/field-list/examples/narrow.tsx +68 -0
- package/dist/skill/reference/components/field-list/examples/overview.tsx +66 -0
- package/dist/skill/reference/components/field-list/examples/reorder.tsx +42 -0
- package/dist/skill/reference/components/field-list/examples/sizes.tsx +42 -0
- package/dist/skill/reference/components/field-list/examples/states.tsx +51 -0
- package/dist/skill/reference/components/input/examples/examples.module.css +2 -7
- package/dist/skill/reference/components/kanban/COMPONENT.md +13 -9
- package/dist/skill/reference/components/kanban/examples/limits.tsx +2 -1
- package/dist/skill/reference/components/kanban/examples/variants.tsx +16 -8
- package/dist/skill/reference/components/list/COMPONENT.md +1 -1
- package/dist/skill/reference/components/media-viewer/COMPONENT.md +2 -2
- package/dist/skill/reference/components/message/COMPONENT.md +2 -2
- package/dist/skill/reference/components/notification/COMPONENT.md +1 -0
- package/dist/skill/reference/components/page-content/COMPONENT.md +70 -14
- package/dist/skill/reference/components/page-content/examples/grid.tsx +107 -0
- package/dist/skill/reference/components/page-content/examples/overview.tsx +2 -2
- package/dist/skill/reference/components/page-content/examples/sections.tsx +81 -0
- package/dist/skill/reference/components/page-toolbar/COMPONENT.md +1 -1
- package/dist/skill/reference/components/segmented-control/COMPONENT.md +1 -0
- package/dist/skill/reference/components/select/COMPONENT.md +4 -2
- package/dist/skill/reference/components/select/examples/icon-only.tsx +38 -0
- package/dist/skill/reference/components/sparkline/COMPONENT.md +83 -30
- package/dist/skill/reference/components/sparkline/examples/compact.tsx +1 -1
- package/dist/skill/reference/components/sparkline/examples/curve.tsx +28 -0
- package/dist/skill/reference/components/sparkline/examples/gaps.tsx +33 -0
- package/dist/skill/reference/components/sparkline/examples/overview.tsx +11 -2
- package/dist/skill/reference/components/sparkline/examples/period.tsx +7 -2
- package/dist/skill/reference/components/sparkline/examples/reference.tsx +37 -0
- package/dist/skill/reference/components/sparkline/examples/variants.tsx +2 -2
- package/dist/skill/reference/components/tabs/examples/examples.module.css +0 -6
- package/dist/skill/reference/components/tabs/examples/in-drawer.tsx +11 -13
- package/dist/skill/reference/components/timeline/examples/examples.module.css +0 -8
- package/dist/skill/reference/components/timeline/examples/narrow.tsx +2 -2
- package/dist/skill/reference/components/timeline/examples/sizes.tsx +3 -3
- package/dist/skill/reference/components/timeline/examples/variants.tsx +4 -4
- package/dist/skill/reference/components/tooltip/COMPONENT.md +6 -4
- package/dist/skill/reference/components/tooltip/examples/placement.tsx +2 -1
- package/dist/skill/reference/components/video-note/COMPONENT.md +1 -1
- package/dist/skill/reference/components/voice-player/COMPONENT.md +1 -1
- package/dist/skill/reference/layout/app-header/examples/in-app-shell.tsx +2 -2
- package/dist/skill/reference/layout/app-shell/COMPONENT.md +1 -1
- package/dist/skill/reference/layout/app-shell/examples/footer.tsx +2 -2
- package/dist/skill/reference/layout/app-shell/examples/overview.tsx +2 -2
- package/dist/skill/reference/layout/app-shell/examples/template.tsx +2 -2
- package/dist/skill/reference/layout/bottom-nav/examples/floating-action.tsx +2 -2
- package/dist/skill/reference/layout/bottom-nav/examples/floating.tsx +2 -2
- package/dist/skill/reference/layout/bottom-nav/examples/in-app-shell.tsx +2 -2
- package/dist/skill/responsive.md +5 -3
- package/dist/skill/ux.md +145 -0
- package/dist/tokens/semantic.d.ts +2 -0
- package/package.json +1 -1
- package/src/components/avatar/COMPONENT.md +4 -4
- package/src/components/avatar/examples/presence.tsx +1 -1
- package/src/components/avatar/examples/states.tsx +1 -1
- package/src/components/banner/COMPONENT.md +6 -6
- package/src/components/banner/examples/dismissible.tsx +22 -11
- package/src/components/banner/examples/examples.module.css +3 -3
- package/src/components/banner/examples/narrow.tsx +1 -1
- package/src/components/breadcrumb/COMPONENT.md +1 -1
- package/src/components/breadcrumb/examples/overflow.tsx +1 -1
- package/src/components/card/COMPONENT.md +5 -4
- package/src/components/card/examples/examples.module.css +0 -28
- package/src/components/card/examples/kpi-media.tsx +13 -11
- package/src/components/card/examples/narrow.tsx +1 -1
- package/src/components/card/examples/panel-chart.tsx +45 -22
- package/src/components/chart-frame/COMPONENT.md +10 -7
- package/src/components/chart-frame/examples/tooltip.tsx +20 -24
- package/src/components/chat/COMPONENT.md +3 -3
- package/src/components/chat/examples/search.tsx +1 -1
- package/src/components/chat-list/COMPONENT.md +1 -1
- package/src/components/checkbox/examples/indicator.tsx +24 -2
- package/src/components/color-picker/COMPONENT.md +2 -2
- package/src/components/color-swatches/COMPONENT.md +1 -0
- package/src/components/datepicker/COMPONENT.md +1 -0
- package/src/components/dnd/COMPONENT.md +3 -3
- package/src/components/field-list/COMPONENT.md +164 -0
- package/src/components/field-list/examples/base-row.tsx +76 -0
- package/src/components/field-list/examples/controlled.tsx +72 -0
- package/src/components/field-list/examples/errors.tsx +85 -0
- package/src/components/field-list/examples/examples.module.css +34 -0
- package/src/components/field-list/examples/limits.tsx +55 -0
- package/src/components/field-list/examples/locked.tsx +139 -0
- package/src/components/field-list/examples/narrow.tsx +68 -0
- package/src/components/field-list/examples/overview.tsx +66 -0
- package/src/components/field-list/examples/reorder.tsx +42 -0
- package/src/components/field-list/examples/sizes.tsx +42 -0
- package/src/components/field-list/examples/states.tsx +51 -0
- package/src/components/input/examples/examples.module.css +2 -7
- package/src/components/kanban/COMPONENT.md +13 -9
- package/src/components/kanban/examples/limits.tsx +2 -1
- package/src/components/kanban/examples/variants.tsx +16 -8
- package/src/components/list/COMPONENT.md +1 -1
- package/src/components/media-viewer/COMPONENT.md +2 -2
- package/src/components/message/COMPONENT.md +2 -2
- package/src/components/notification/COMPONENT.md +1 -0
- package/src/components/page-content/COMPONENT.md +70 -14
- package/src/components/page-content/examples/grid.tsx +107 -0
- package/src/components/page-content/examples/overview.tsx +2 -2
- package/src/components/page-content/examples/sections.tsx +81 -0
- package/src/components/page-toolbar/COMPONENT.md +1 -1
- package/src/components/segmented-control/COMPONENT.md +1 -0
- package/src/components/select/COMPONENT.md +4 -2
- package/src/components/select/examples/icon-only.tsx +38 -0
- package/src/components/sparkline/COMPONENT.md +83 -30
- package/src/components/sparkline/examples/compact.tsx +1 -1
- package/src/components/sparkline/examples/curve.tsx +28 -0
- package/src/components/sparkline/examples/gaps.tsx +33 -0
- package/src/components/sparkline/examples/overview.tsx +11 -2
- package/src/components/sparkline/examples/period.tsx +7 -2
- package/src/components/sparkline/examples/reference.tsx +37 -0
- package/src/components/sparkline/examples/variants.tsx +2 -2
- package/src/components/tabs/examples/examples.module.css +0 -6
- package/src/components/tabs/examples/in-drawer.tsx +11 -13
- package/src/components/timeline/examples/examples.module.css +0 -8
- package/src/components/timeline/examples/narrow.tsx +2 -2
- package/src/components/timeline/examples/sizes.tsx +3 -3
- package/src/components/timeline/examples/variants.tsx +4 -4
- package/src/components/tooltip/COMPONENT.md +6 -4
- package/src/components/tooltip/examples/placement.tsx +2 -1
- package/src/components/video-note/COMPONENT.md +1 -1
- package/src/components/voice-player/COMPONENT.md +1 -1
- package/src/layout/app-header/examples/in-app-shell.tsx +2 -2
- package/src/layout/app-shell/COMPONENT.md +1 -1
- package/src/layout/app-shell/examples/footer.tsx +2 -2
- package/src/layout/app-shell/examples/overview.tsx +2 -2
- package/src/layout/app-shell/examples/template.tsx +2 -2
- package/src/layout/bottom-nav/examples/floating-action.tsx +2 -2
- package/src/layout/bottom-nav/examples/floating.tsx +2 -2
- package/src/layout/bottom-nav/examples/in-app-shell.tsx +2 -2
- package/src/styles/theme-light.css +1 -0
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
**Category:** page
|
|
4
4
|
**Kind:** layout
|
|
5
5
|
|
|
6
|
-
> Page structure inside the main column: title,
|
|
6
|
+
> Page structure inside the main column: title, page actions and content blocks, titled sections and the tile grid of a dashboard; a page as high as the panel and the list + detail layout.
|
|
7
7
|
|
|
8
8
|
## When to use
|
|
9
9
|
- Every route rendered inside `AppShell.Main`: a page heading (`<h1>`), an intro line, page-level actions and the page body.
|
|
10
10
|
- A text page held to a reading measure (`PageContent.Root maxWidth="readable"`).
|
|
11
11
|
- A wide dashboard page capped at the content width (`maxWidth="wide"`).
|
|
12
|
+
- The tiles of a dashboard — KPI cards, charts, panels — as one board (`PageContent.Grid` + `PageContent.Cell`).
|
|
13
|
+
- A new topic of the page with its own heading and a link or button beside it (`PageContent.Section`); a settings page with a heading column beside each panel (`layout="aside"`).
|
|
12
14
|
- A page whose body takes the rest of the panel's height — a log table, a board, a chat (`fill`).
|
|
13
15
|
- Mail, a messenger, a ticket queue: a list and the chosen record side by side, one at a time on a narrow panel (`PageContent.Split`).
|
|
14
16
|
|
|
@@ -16,7 +18,8 @@
|
|
|
16
18
|
- The app frame (navigation rail, header, scrolling main column) → use [AppShell](../../layout/app-shell/COMPONENT.md).
|
|
17
19
|
- A bounded block inside the page → use [Card](../card/COMPONENT.md).
|
|
18
20
|
- An empty / error / not-found page → use [EmptyPage](../empty-page/COMPONENT.md).
|
|
19
|
-
-
|
|
21
|
+
- A heading inside a card → `Card.Title`; text headings inside prose → use [Typography](../typography/COMPONENT.md).
|
|
22
|
+
- A grid inside one block (thumbnails, fields, bars in a panel) → the block's own CSS grid; `PageContent.Grid` places the page's tiles.
|
|
20
23
|
- Details that open over the list and close again (a record from a table) → use [Drawer](../drawer/COMPONENT.md); `Split` is for a list people work through record by record.
|
|
21
24
|
|
|
22
25
|
## Import
|
|
@@ -26,12 +29,16 @@ import { PageContent } from "prime-ui-kit";
|
|
|
26
29
|
|
|
27
30
|
## Anatomy
|
|
28
31
|
```
|
|
29
|
-
PageContent.Root | PageContent.
|
|
32
|
+
PageContent.Root | PageContent.Page column; Root adds maxWidth and fill, Page renders <section>
|
|
30
33
|
├─ PageContent.Header heading column + actions in one wrapping row
|
|
31
34
|
│ ├─ PageContent.Title <h1>, heading-m
|
|
32
35
|
│ ├─ PageContent.Description <p>, secondary body-m
|
|
33
36
|
│ └─ PageContent.Actions page buttons (moved to the end of the header row)
|
|
34
|
-
└─ PageContent.Body page content, blocks
|
|
37
|
+
└─ PageContent.Body page content, blocks 24 apart
|
|
38
|
+
├─ PageContent.Grid 12-column tile grid, 16 on both axes; a container (prime-grid)
|
|
39
|
+
│ └─ PageContent.Cell one tile place: span, rows; its child fills it
|
|
40
|
+
├─ PageContent.Section <section> + <h2> label, 40 from its neighbours
|
|
41
|
+
│ └─ PageContent.Actions a link or button at the end of the section heading
|
|
35
42
|
└─ PageContent.Split list + detail; a container (prime-split)
|
|
36
43
|
├─ PageContent.List list pane: 16–20rem column, or the whole split while closed
|
|
37
44
|
└─ PageContent.Detail detail pane: the rest, or the whole split while open
|
|
@@ -43,7 +50,7 @@ PageContent.Root | PageContent.Section column; Root adds maxWidth and fill,
|
|
|
43
50
|
<!-- Generated from api.ts by `bun run docs:build`. Edit api.ts, not this section. -->
|
|
44
51
|
|
|
45
52
|
### PageContent.Root
|
|
46
|
-
`ref` → `HTMLDivElement`. The page column inside `main`: header → body
|
|
53
|
+
`ref` → `HTMLDivElement`. The page column inside `main`: header → body 24 apart, centred under its cap.
|
|
47
54
|
|
|
48
55
|
| Prop | Type | Default | Description |
|
|
49
56
|
|---|---|---|---|
|
|
@@ -51,8 +58,8 @@ PageContent.Root | PageContent.Section column; Root adds maxWidth and fill,
|
|
|
51
58
|
| `fill` | `boolean` | `false` | The page takes the height of main (`AppShell.Root fillViewport`) and the body takes what the header leaves: for a full-height table, board, chat or `PageContent.Split`. |
|
|
52
59
|
| `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children` (Header, Body), `className` and the other div attributes. |
|
|
53
60
|
|
|
54
|
-
### PageContent.
|
|
55
|
-
`ref` → `HTMLElement`. The
|
|
61
|
+
### PageContent.Page
|
|
62
|
+
`ref` → `HTMLElement`. The whole app page as a `<section>` (the same column, the full panel width); name it with `aria-labelledby` → the Title `id`.
|
|
56
63
|
|
|
57
64
|
| Prop | Type | Default | Description |
|
|
58
65
|
|---|---|---|---|
|
|
@@ -88,12 +95,38 @@ PageContent.Root | PageContent.Section column; Root adds maxWidth and fill,
|
|
|
88
95
|
| `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children` (Buttons), `className` and the other div attributes. |
|
|
89
96
|
|
|
90
97
|
### PageContent.Body
|
|
91
|
-
`ref` → `HTMLDivElement`. The page content
|
|
98
|
+
`ref` → `HTMLDivElement`. The page content: blocks of one screen 24 apart, a `PageContent.Section` 40 from its neighbours.
|
|
92
99
|
|
|
93
100
|
| Prop | Type | Default | Description |
|
|
94
101
|
|---|---|---|---|
|
|
95
102
|
| `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children`, `className` and the other div attributes. |
|
|
96
103
|
|
|
104
|
+
### PageContent.Section
|
|
105
|
+
`ref` → `HTMLElement`. A titled section of the page — a `<section>` named by its `h2` (title-m): the heading with an optional description and `PageContent.Actions` at its end, then the content 16 below. Stands 40 from its neighbours in Body.
|
|
106
|
+
|
|
107
|
+
| Prop | Type | Default | Description |
|
|
108
|
+
|---|---|---|---|
|
|
109
|
+
| `label` | `ReactNode` | — (required) | The visible heading (`h2`); it also names the section. |
|
|
110
|
+
| `description` | `ReactNode` | — | One line of context under the heading, in secondary body-s. |
|
|
111
|
+
| `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. |
|
|
112
|
+
| `…rest` | `Omit<HTMLAttributes<HTMLElement>, "title">` | — | `children` (the content; `PageContent.Actions` goes to the heading row), `className` and the other section attributes. |
|
|
113
|
+
|
|
114
|
+
### PageContent.Grid
|
|
115
|
+
`ref` → `HTMLDivElement`. The grid of the page's tiles (KPI cards, charts, panels): 12 columns, 16 apart on both axes, so its rows read as one board. A size container: cells fold by its own width (see Grid columns).
|
|
116
|
+
|
|
117
|
+
| Prop | Type | Default | Description |
|
|
118
|
+
|---|---|---|---|
|
|
119
|
+
| `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children` (`PageContent.Cell`), `className` and the other div attributes. |
|
|
120
|
+
|
|
121
|
+
### PageContent.Cell
|
|
122
|
+
`ref` → `HTMLDivElement`. One tile place in `PageContent.Grid`; its child (a Card, a ChartFrame) stretches to it, so the tiles of a row share one height.
|
|
123
|
+
|
|
124
|
+
| Prop | Type | Default | Description |
|
|
125
|
+
|---|---|---|---|
|
|
126
|
+
| `span` | `1 \| 2 \| … \| 12` | `12` | Columns of 12 on a wide grid (64rem+). Narrower grids round it: see Grid columns in COMPONENT.md. |
|
|
127
|
+
| `rows` | `1 \| 2 \| 3 \| 4` | `1` | Rows the cell spans from 40rem: a chart beside two stacked tiles (`ChartFrame.Plot height="fill"` fills the height). |
|
|
128
|
+
| `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children` (one tile), `className` and the other div attributes. |
|
|
129
|
+
|
|
97
130
|
### PageContent.Split
|
|
98
131
|
`ref` → `HTMLDivElement`. List + detail (mail, a messenger, a ticket queue): side by side from 48rem of its own width, one pane at a time below it, focus following the pane that comes into view.
|
|
99
132
|
|
|
@@ -141,13 +174,27 @@ PageContent.Root | PageContent.Section column; Root adds maxWidth and fill,
|
|
|
141
174
|
| `readable` | Intro line wraps at the reading width | Default, most pages | yes |
|
|
142
175
|
| `full` | Intro uses the full header width | The column is already narrow | |
|
|
143
176
|
|
|
144
|
-
One `PageContent.Title` (`<h1>`) per page;
|
|
177
|
+
One `PageContent.Title` (`<h1>`) per page; a topic inside Body is a `PageContent.Section` (its `h2`). One primary button in Actions, the rest `soft` / `ghost` neutral.
|
|
145
178
|
|
|
146
179
|
### Flags
|
|
147
180
|
| Flag | Looks like when on | Use when | Default |
|
|
148
181
|
|---|---|---|---|
|
|
149
182
|
| `fill` (Root) | the page is as high as main; the body takes what the header leaves; main keeps gutter-high air under it | a full-height table, board, chat or `PageContent.Split` in an `AppShell.Root fillViewport` | `false` |
|
|
150
183
|
|
|
184
|
+
### layout (Section)
|
|
185
|
+
| Value | Looks like | Use when | Default |
|
|
186
|
+
|---|---|---|---|
|
|
187
|
+
| `stack` | the heading row over the content, 16 apart | a topic of a dashboard, a list or a detail page | ✓ |
|
|
188
|
+
| `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 | |
|
|
189
|
+
|
|
190
|
+
### Grid columns
|
|
191
|
+
| Grid width | Cell `span` 1–3 | `span` 4 | `span` 5–6 | `span` 7–12 | `rows` |
|
|
192
|
+
|---|---|---|---|---|---|
|
|
193
|
+
| < 30rem | the row | the row | the row | the row | — |
|
|
194
|
+
| 30–40rem | half | the row | the row | the row | — |
|
|
195
|
+
| 40–64rem | half | a third | half | the row | spans |
|
|
196
|
+
| ≥ 64rem | its span | its span | its span | its span | spans |
|
|
197
|
+
|
|
151
198
|
### Split layout
|
|
152
199
|
| Value | Looks like | Use when | Default |
|
|
153
200
|
|---|---|---|---|
|
|
@@ -161,14 +208,18 @@ One `PageContent.Title` (`<h1>`) per page; sub-sections inside Body use `title-s
|
|
|
161
208
|
| filling | `fill` | `data-fill="true"` on Root; `AppShell.Main` drops its long bottom air for it |
|
|
162
209
|
| full-width intro | `measure="full"` | `data-measure="full"` on Description |
|
|
163
210
|
| with actions | `PageContent.Actions` child | `data-has-actions="true"` on Header |
|
|
211
|
+
| section heading column | `layout="aside"` on Section | `data-layout="aside"` on Section (absent for `stack`) |
|
|
212
|
+
| section with actions | `PageContent.Actions` child of Section | `data-has-actions="true"` on the section heading row |
|
|
213
|
+
| tile span | `span` / `rows` on Cell | `data-span="1"…"12"` (always), `data-rows="2"…"4"` (absent for 1) |
|
|
164
214
|
| detail open | `open` / `defaultOpen` on Split | `data-open="true"` on Split; narrow: the list is `display: none`, else the detail is |
|
|
165
215
|
| pane swap | `open` changes on a narrow split | the pane that comes into view enters once (`enterMotion.enterBase`: base, opacity + a 4 px rise); focus moves into the detail, or back to the list control; a wide split moves nothing |
|
|
166
216
|
|
|
167
217
|
## Layout & spacing
|
|
168
218
|
- No outer padding: edge gutters come from `AppShell.Main`.
|
|
169
|
-
- Header → Body `--prime-space-
|
|
219
|
+
- Header → Body `--prime-space-6` (24); blocks inside Body `--prime-space-6` (24); a `PageContent.Section` 40 from its neighbours (the body's 24 + `--prime-space-4`); tile → tile in a Grid `--prime-space-4` (16) on both axes; section heading → content `--prime-space-4` (16), heading → description `--prime-space-1` (4); Title → Description `--prime-space-2` (8); buttons in Actions `--prime-space-2`; heading → Actions `--prime-space-6` (24) side by side, `--prime-space-4` (16) once they wrap below.
|
|
170
220
|
- Header is a wrapping row: actions stay to the right of the title while the heading keeps half a reading measure, otherwise they wrap below it — no breakpoint needed, works from 320px.
|
|
171
221
|
- Title and Description wrap long words (`overflow-wrap: anywhere`).
|
|
222
|
+
- Grid lays itself out from its own width (container `prime-grid`), never from the window, so a board beside an open Sidebar folds on its own. A Cell stretches its child: the tiles of a row share one height; a chart in a `rows={2}` cell fills it with `ChartFrame.Plot height="fill"`. `dense` flow lets a small tile fill a hole left by a wide one.
|
|
172
223
|
- `fill` needs a main with a height: `AppShell.Root fillViewport` (main scrolls inside the panel). The body passes its free height on to a filling child — DataTable `scrollHeight="fill"`, Crossfade `fill`, `PageContent.Split`.
|
|
173
224
|
- Split takes the free height of a filling page and lays itself out from its own width (container `prime-split`), never from the window: a split beside an open Sidebar may be narrow on a wide screen. Each pane is a column whose last child takes the free height — put a Card with its own `ScrollContainer` there, so the list and the thread scroll separately. The records of the list pane are a [List](../list/COMPONENT.md).
|
|
174
225
|
- The detail pane is on screen all the time on a wide split: while nothing is chosen it shows a short hint («Выберите диалог»), never an empty card.
|
|
@@ -182,7 +233,8 @@ One `PageContent.Title` (`<h1>`) per page; sub-sections inside Body use `title-s
|
|
|
182
233
|
|
|
183
234
|
### ARIA
|
|
184
235
|
- Title is an `<h1>`; use one per page.
|
|
185
|
-
- Give `PageContent.
|
|
236
|
+
- Give `PageContent.Page` an `aria-labelledby` that points at the Title `id` to name the region.
|
|
237
|
+
- `PageContent.Section` is a `<section>` named by its own `<h2>` (`label`) through `aria-labelledby`, so it is a region landmark with the heading's name; the heading levels go h1 (page) → h2 (section) → h3 (a card title inside it).
|
|
186
238
|
- Name `PageContent.List` and `PageContent.Detail` with `aria-label`. On a narrow split opening the detail moves focus into it and going back returns focus to the list control; the hidden pane is `display: none`, out of Tab and the accessibility tree. The panes take focus from code only (`tabindex="-1"`, no ring).
|
|
187
239
|
- `PageContent.BackButton` is named by `labels.back` and is shown only while the split shows one pane.
|
|
188
240
|
|
|
@@ -198,18 +250,22 @@ One `PageContent.Title` (`<h1>`) per page; sub-sections inside Body use `title-s
|
|
|
198
250
|
|---|---|
|
|
199
251
|
| [overview.tsx](examples/overview.tsx) | A page in the main column: title, description and page actions, then the body blocks — `PageContent.Actions`. |
|
|
200
252
|
| [variants.tsx](examples/variants.tsx) | The same page column at three caps: the whole main, a wide dashboard column, a reading column — `maxWidth`. |
|
|
253
|
+
| [grid.tsx](examples/grid.tsx) | A dashboard board: four KPI tiles, a chart two rows high beside two panels, one gap on both axes — `PageContent.Grid`, `PageContent.Cell`, `span`, `rows`. |
|
|
254
|
+
| [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, a heading column beside a panel — `PageContent.Section`, `label`, `description`, `PageContent.Actions`, `layout`. |
|
|
201
255
|
| [list-detail.tsx](examples/list-detail.tsx) | A support inbox 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 — `PageContent.Split`, `PageContent.BackButton`, `fill`. |
|
|
202
256
|
| [narrow.tsx](examples/narrow.tsx) | In a phone-width column the page actions wrap under the heading instead of squeezing it. |
|
|
203
257
|
|
|
204
258
|
## Mistakes
|
|
205
259
|
- Padding on `PageContent.Root` to imitate gutters → gutters come from `AppShell.Main`.
|
|
206
260
|
- Actions placed outside Header → put `PageContent.Actions` inside `PageContent.Header` so it aligns with the title and wraps.
|
|
207
|
-
- Several `PageContent.Title` on one page → one `<h1
|
|
208
|
-
-
|
|
261
|
+
- Several `PageContent.Title` on one page → one `<h1>`; a topic of the page is a `PageContent.Section` with its `<h2>`.
|
|
262
|
+
- A hand-made `<section>` + `Typography as="h2"` + own gap CSS → `PageContent.Section label`.
|
|
263
|
+
- Each row of cards in its own auto-fit grid → the rows stand 24 apart instead of 16; put every tile of the screen in one `PageContent.Grid`.
|
|
264
|
+
- Margins between blocks in Body → Body already sets the 24 gap and the 40 around a Section.
|
|
209
265
|
- Computing a height from `100vh` minus the header for a full-height table or chat → `PageContent.Root fill` and a filling child.
|
|
210
266
|
- A list + detail built with window media queries → `PageContent.Split` follows its own width.
|
|
211
267
|
- Unmounting the detail content the moment the narrow split goes back → keep the last record until another is chosen (the pane leaves with it on screen).
|
|
212
268
|
|
|
213
269
|
## Related
|
|
214
270
|
- **Built from:** [Button](../button/COMPONENT.md) (`PageContent.BackButton`), Icon (`nav.chevronLeft`)
|
|
215
|
-
- **See also:** [AppShell](../../layout/app-shell/COMPONENT.md), [Sidebar](../../layout/sidebar/COMPONENT.md), [Card](../card/COMPONENT.md), [List](../list/COMPONENT.md), [EmptyPage](../empty-page/COMPONENT.md), [ScrollContainer](../scroll-container/COMPONENT.md), [Drawer](../drawer/COMPONENT.md)
|
|
271
|
+
- **See also:** [AppShell](../../layout/app-shell/COMPONENT.md), [Sidebar](../../layout/sidebar/COMPONENT.md), [Card](../card/COMPONENT.md), [ChartFrame](../chart-frame/COMPONENT.md), [List](../list/COMPONENT.md), [EmptyPage](../empty-page/COMPONENT.md), [ScrollContainer](../scroll-container/COMPONENT.md), [Drawer](../drawer/COMPONENT.md)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/** A dashboard board: four KPI tiles, a chart two rows high beside two panels, one gap on both axes — `PageContent.Grid`, `PageContent.Cell`, `span`, `rows`. */
|
|
2
|
+
import { Card, ChartFrame, type ChartFrameSeries, chartColors, PageContent } from "prime-ui-kit";
|
|
3
|
+
|
|
4
|
+
import styles from "./examples.module.css";
|
|
5
|
+
|
|
6
|
+
const KPIS = [
|
|
7
|
+
{ label: "Выручка", value: "4,8 млн ₽", delta: "+12% к сентябрю", tone: "success" },
|
|
8
|
+
{ label: "Заказы", value: "1 284", delta: "+6% к сентябрю", tone: "success" },
|
|
9
|
+
{ label: "Средний чек", value: "3 740 ₽", delta: "−2% к сентябрю", tone: "danger" },
|
|
10
|
+
{ label: "Возвраты", value: "1,8%", delta: "без изменений", tone: "neutral" },
|
|
11
|
+
] as const;
|
|
12
|
+
|
|
13
|
+
const SERIES: ChartFrameSeries[] = [{ id: "orders", label: "Заказы" }];
|
|
14
|
+
|
|
15
|
+
const WEEKS = [
|
|
16
|
+
{ week: "1 нед", orders: 268 },
|
|
17
|
+
{ week: "2 нед", orders: 301 },
|
|
18
|
+
{ week: "3 нед", orders: 287 },
|
|
19
|
+
{ week: "4 нед", orders: 334 },
|
|
20
|
+
{ week: "5 нед", orders: 352 },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const MARGIN = { top: 8, right: 8, bottom: 24, left: 8 };
|
|
24
|
+
|
|
25
|
+
const formatOrders = (value: number) => `${value.toLocaleString("ru-RU")} заказов`;
|
|
26
|
+
|
|
27
|
+
export default function PageContentGridExample() {
|
|
28
|
+
return (
|
|
29
|
+
<div className={styles.main}>
|
|
30
|
+
<PageContent.Body>
|
|
31
|
+
<PageContent.Grid>
|
|
32
|
+
{KPIS.map((kpi) => (
|
|
33
|
+
<PageContent.Cell key={kpi.label} span={3}>
|
|
34
|
+
<Card.Root variant="stat-trend">
|
|
35
|
+
<Card.Label>{kpi.label}</Card.Label>
|
|
36
|
+
<Card.Value>{kpi.value}</Card.Value>
|
|
37
|
+
<Card.Delta tone={kpi.tone}>{kpi.delta}</Card.Delta>
|
|
38
|
+
</Card.Root>
|
|
39
|
+
</PageContent.Cell>
|
|
40
|
+
))}
|
|
41
|
+
<PageContent.Cell span={8} rows={2}>
|
|
42
|
+
<ChartFrame.Root series={SERIES} formatValue={formatOrders}>
|
|
43
|
+
<ChartFrame.Header>
|
|
44
|
+
<ChartFrame.Title>Заказы по неделям</ChartFrame.Title>
|
|
45
|
+
<ChartFrame.Description>Октябрь</ChartFrame.Description>
|
|
46
|
+
</ChartFrame.Header>
|
|
47
|
+
<ChartFrame.Plot
|
|
48
|
+
height="fill"
|
|
49
|
+
renderPlot={({ width, height, series }) => {
|
|
50
|
+
const max = Math.max(...WEEKS.map((w) => w.orders));
|
|
51
|
+
const innerW = width - MARGIN.left - MARGIN.right;
|
|
52
|
+
const innerH = height - MARGIN.top - MARGIN.bottom;
|
|
53
|
+
const slot = innerW / WEEKS.length;
|
|
54
|
+
const bar = slot * 0.56;
|
|
55
|
+
return (
|
|
56
|
+
<svg width={width} height={height} aria-hidden="true">
|
|
57
|
+
<line
|
|
58
|
+
x1={MARGIN.left}
|
|
59
|
+
x2={width - MARGIN.right}
|
|
60
|
+
y1={MARGIN.top + innerH}
|
|
61
|
+
y2={MARGIN.top + innerH}
|
|
62
|
+
stroke={chartColors.axis}
|
|
63
|
+
/>
|
|
64
|
+
{WEEKS.map((w, i) => {
|
|
65
|
+
const h = (innerH * w.orders) / max;
|
|
66
|
+
const x = MARGIN.left + slot * i + (slot - bar) / 2;
|
|
67
|
+
return (
|
|
68
|
+
<g key={w.week} data-hidden={series[0].hidden}>
|
|
69
|
+
<rect
|
|
70
|
+
x={x}
|
|
71
|
+
y={MARGIN.top + innerH - h}
|
|
72
|
+
width={bar}
|
|
73
|
+
height={h}
|
|
74
|
+
rx={4}
|
|
75
|
+
fill={series[0].color}
|
|
76
|
+
/>
|
|
77
|
+
<text x={x + bar / 2} y={height - 4} textAnchor="middle">
|
|
78
|
+
{w.week}
|
|
79
|
+
</text>
|
|
80
|
+
</g>
|
|
81
|
+
);
|
|
82
|
+
})}
|
|
83
|
+
</svg>
|
|
84
|
+
);
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
</ChartFrame.Root>
|
|
88
|
+
</PageContent.Cell>
|
|
89
|
+
<PageContent.Cell span={4}>
|
|
90
|
+
<Card.Root variant="stat-trend">
|
|
91
|
+
<Card.Label>Новые клиенты</Card.Label>
|
|
92
|
+
<Card.Value>86</Card.Value>
|
|
93
|
+
<Card.Delta tone="success">+14 к сентябрю</Card.Delta>
|
|
94
|
+
</Card.Root>
|
|
95
|
+
</PageContent.Cell>
|
|
96
|
+
<PageContent.Cell span={4}>
|
|
97
|
+
<Card.Root variant="stat-trend">
|
|
98
|
+
<Card.Label>Ждут оплаты</Card.Label>
|
|
99
|
+
<Card.Value>312 400 ₽</Card.Value>
|
|
100
|
+
<Card.Delta tone="warning">7 счетов</Card.Delta>
|
|
101
|
+
</Card.Root>
|
|
102
|
+
</PageContent.Cell>
|
|
103
|
+
</PageContent.Grid>
|
|
104
|
+
</PageContent.Body>
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
@@ -6,7 +6,7 @@ import styles from "./examples.module.css";
|
|
|
6
6
|
export default function PageContentOverviewExample() {
|
|
7
7
|
return (
|
|
8
8
|
<div className={styles.main}>
|
|
9
|
-
<PageContent.
|
|
9
|
+
<PageContent.Page aria-labelledby="settings-heading">
|
|
10
10
|
<PageContent.Header>
|
|
11
11
|
<PageContent.Title id="settings-heading">Настройки</PageContent.Title>
|
|
12
12
|
<PageContent.Description>
|
|
@@ -35,7 +35,7 @@ export default function PageContentOverviewExample() {
|
|
|
35
35
|
</Card.Body>
|
|
36
36
|
</Card.Root>
|
|
37
37
|
</PageContent.Body>
|
|
38
|
-
</PageContent.
|
|
38
|
+
</PageContent.Page>
|
|
39
39
|
</div>
|
|
40
40
|
);
|
|
41
41
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** 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, a heading column beside a panel — `PageContent.Section`, `label`, `description`, `PageContent.Actions`, `layout`. */
|
|
2
|
+
import {
|
|
3
|
+
Card,
|
|
4
|
+
DataTable,
|
|
5
|
+
type DataTableColumn,
|
|
6
|
+
LinkButton,
|
|
7
|
+
PageContent,
|
|
8
|
+
Typography,
|
|
9
|
+
} from "prime-ui-kit";
|
|
10
|
+
|
|
11
|
+
import styles from "./examples.module.css";
|
|
12
|
+
|
|
13
|
+
type Invoice = { id: string; client: string; amount: number };
|
|
14
|
+
|
|
15
|
+
const INVOICES: Invoice[] = [
|
|
16
|
+
{ id: "СЧ-1042", client: "ООО «Север»", amount: 184_000 },
|
|
17
|
+
{ id: "СЧ-1041", client: "ИП Лаптева", amount: 42_500 },
|
|
18
|
+
{ id: "СЧ-1039", client: "АО «Техносфера»", amount: 610_000 },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const MONEY = new Intl.NumberFormat("ru-RU", {
|
|
22
|
+
style: "currency",
|
|
23
|
+
currency: "RUB",
|
|
24
|
+
maximumFractionDigits: 0,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const COLUMNS: DataTableColumn<Invoice>[] = [
|
|
28
|
+
{ id: "id", header: "Счёт", cell: (row) => row.id },
|
|
29
|
+
{ id: "client", header: "Клиент", cell: (row) => row.client },
|
|
30
|
+
{
|
|
31
|
+
id: "amount",
|
|
32
|
+
header: "Сумма",
|
|
33
|
+
numeric: true,
|
|
34
|
+
headerAlign: "end",
|
|
35
|
+
cell: (row) => MONEY.format(row.amount),
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
export default function PageContentSectionsExample() {
|
|
40
|
+
return (
|
|
41
|
+
<div className={styles.main}>
|
|
42
|
+
<PageContent.Body>
|
|
43
|
+
<PageContent.Grid>
|
|
44
|
+
<PageContent.Cell span={6}>
|
|
45
|
+
<Card.Root variant="stat-trend">
|
|
46
|
+
<Card.Label>Выставлено</Card.Label>
|
|
47
|
+
<Card.Value>2,4 млн ₽</Card.Value>
|
|
48
|
+
<Card.Delta tone="success">+9% к сентябрю</Card.Delta>
|
|
49
|
+
</Card.Root>
|
|
50
|
+
</PageContent.Cell>
|
|
51
|
+
<PageContent.Cell span={6}>
|
|
52
|
+
<Card.Root variant="stat-trend">
|
|
53
|
+
<Card.Label>Оплачено</Card.Label>
|
|
54
|
+
<Card.Value>1,9 млн ₽</Card.Value>
|
|
55
|
+
<Card.Delta tone="neutral">79% выставленного</Card.Delta>
|
|
56
|
+
</Card.Root>
|
|
57
|
+
</PageContent.Cell>
|
|
58
|
+
</PageContent.Grid>
|
|
59
|
+
<PageContent.Section label="Последние счета" description="Три последних за октябрь">
|
|
60
|
+
<PageContent.Actions>
|
|
61
|
+
<LinkButton href="#invoices">Все счета</LinkButton>
|
|
62
|
+
</PageContent.Actions>
|
|
63
|
+
<DataTable columns={COLUMNS} rows={INVOICES} getRowKey={(row) => row.id} paging="none" />
|
|
64
|
+
</PageContent.Section>
|
|
65
|
+
<PageContent.Section
|
|
66
|
+
layout="aside"
|
|
67
|
+
label="Реквизиты в счетах"
|
|
68
|
+
description="Попадают в каждый новый счёт."
|
|
69
|
+
>
|
|
70
|
+
<Card.Root variant="panel">
|
|
71
|
+
<Card.Body>
|
|
72
|
+
<Typography variant="body-m" tone="secondary">
|
|
73
|
+
ООО «Прайм Софт», ИНН 7701234567, р/с в Т-Банке.
|
|
74
|
+
</Typography>
|
|
75
|
+
</Card.Body>
|
|
76
|
+
</Card.Root>
|
|
77
|
+
</PageContent.Section>
|
|
78
|
+
</PageContent.Body>
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
@@ -111,7 +111,7 @@ PageToolbar has no variants: the layout follows the toolbar's width.
|
|
|
111
111
|
No keyboard interaction.
|
|
112
112
|
|
|
113
113
|
### ARIA
|
|
114
|
-
- A plain `<div>`:
|
|
114
|
+
- A plain `<div>`: when a page has more than one panel, give each `role="group"` and an `aria-label` (a name on a `<div>` without a role is ignored by assistive tech).
|
|
115
115
|
- Slots move only visually (`order`); the Tab order is the JSX order. Write the slots in the reading order of the wide layout — Tools, Sections, View, Actions, Chips. In the narrow layout the action is shown beside the tools but reached after the view.
|
|
116
116
|
- An icon-only primary action on a narrow page carries `aria-label`.
|
|
117
117
|
|
|
@@ -158,6 +158,7 @@ Item DOM: `data-state`, `data-disabled`, `data-icon-only`, `data-two-line`, `dat
|
|
|
158
158
|
## Layout & spacing
|
|
159
159
|
- In a form it is a field: label → track `label-gap`, track → support row `hint-gap`, field → field `--prime-space-5` like every field.
|
|
160
160
|
- Width is content-based by default; segments never wrap. In a narrow container the row scrolls horizontally with fading edges.
|
|
161
|
+
- On a coarse pointer each segment's hit area grows to the 44 px touch target in height; the track keeps its tier height.
|
|
161
162
|
- In a toolbar: gap `--prime-space-3` between controls; keep every control at one size.
|
|
162
163
|
- Caption under a group: gap `--prime-space-2`.
|
|
163
164
|
- `fullWidth` inside modals and mobile sheets. Single-line segments are `flex: 1 1 0` with `min-width: max-content`: short labels share the spare width equally, a long label keeps its own width, nothing truncates; when the labels do not fit, the row scrolls.
|
|
@@ -30,7 +30,7 @@ import { Select } from "prime-ui-kit";
|
|
|
30
30
|
```
|
|
31
31
|
Select.Root field frame: label · control · hint/error; value, open, search
|
|
32
32
|
├── Select.Trigger <button role="combobox">: [icon] [value] [clear] [chevron]
|
|
33
|
-
│ ├── Select.TriggerIcon optional leading glyph
|
|
33
|
+
│ ├── Select.TriggerIcon optional leading glyph; alone (no Select.Value) — an icon-only trigger
|
|
34
34
|
│ └── Select.Value picked label or placeholder (renderValue for a rich trigger)
|
|
35
35
|
└── Select.Content portaled panel while open; closed, the items render hidden in place so the trigger knows their labels
|
|
36
36
|
├── search row with `searchable`
|
|
@@ -103,7 +103,7 @@ an icon) goes inside `Select.ItemMeta`.
|
|
|
103
103
|
|
|
104
104
|
| Prop | Type | Default | Description |
|
|
105
105
|
|---|---|---|---|
|
|
106
|
-
| `children` | `ReactNode` | — | `Select.TriggerIcon`, `Select.Value`, optionally a Badge after it. |
|
|
106
|
+
| `children` | `ReactNode` | — | `Select.TriggerIcon`, `Select.Value`, optionally a Badge after it. A `Select.TriggerIcon` alone makes an icon-only trigger (the value read, not shown). |
|
|
107
107
|
|
|
108
108
|
### Select.Value
|
|
109
109
|
`ref` → `HTMLSpanElement`. The picked label (labels joined with `multiple`) with an ellipsis, or the placeholder.
|
|
@@ -212,6 +212,7 @@ No `variant` or `tone`. The trigger is the field look (fill, inset control borde
|
|
|
212
212
|
- Label → field: tier `label-gap`; field → hint: tier `hint-gap`; field → field in a form: `--prime-space-5`.
|
|
213
213
|
- Panel: at least the trigger width and `--prime-panel-min-width`, at most twice that; max height `--prime-panel-max-height` (scrolls); flips near the viewport edge.
|
|
214
214
|
- Long values truncate with an ellipsis in the trigger.
|
|
215
|
+
- The clear segment's hit area grows to the 44 px touch target in height on a coarse pointer, like the clear segment of an Input.
|
|
215
216
|
- A rich row and its trigger use the same parts in the same order: leading media (`Avatar.Root`,
|
|
216
217
|
`Thumbnail.Root`) → `Select.ItemText` (+ `Select.ItemDescription`) → trailing `Badge.Root` /
|
|
217
218
|
`Select.ItemMeta`. In a row the trailing part sits before the check; in the trigger, at the end
|
|
@@ -306,6 +307,7 @@ No `variant` or `tone`. The trigger is the field look (fill, inset control borde
|
|
|
306
307
|
| [saving.tsx](examples/saving.tsx) | A choice that saves on the server at once: the picked value shows with a spinner on the trigger, and a refused save rolls it back and says why — `onValueChange`, `error`. |
|
|
307
308
|
| [rich-options.tsx](examples/rich-options.tsx) | Options with a picture, a second line and a price; the trigger draws the picked option with the same parts — `renderValue`, `Select.ItemText`, `Select.ItemDescription`, `Select.ItemMeta`. |
|
|
308
309
|
| [people.tsx](examples/people.tsx) | People in the rows and the trigger: an avatar sized to the tier before the name, a role badge after it — `Avatar.Root`, `Badge.Root`, `renderValue`. |
|
|
310
|
+
| [icon-only.tsx](examples/icon-only.tsx) | An icon picker as wide as its glyph: the trigger holds only the picked icon and the chevron, the value is still read aloud — `Select.TriggerIcon`. |
|
|
309
311
|
| [controlled.tsx](examples/controlled.tsx) | The parent owns the value: the plan drives the price under the field and a button resets it — `value`, `onValueChange`. |
|
|
310
312
|
| [controlled-open.tsx](examples/controlled-open.tsx) | The parent owns the list: a button opens it from code, a pick or Escape closes it — `open`, `onOpenChange`. |
|
|
311
313
|
| [in-form.tsx](examples/in-form.tsx) | Regional settings form: the required country is checked on submit, the error shakes the field and leaves once a country is picked, a calm note confirms the save — `required`, `error`, `hint`. |
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** An icon picker as wide as its glyph: the trigger holds only the picked icon and the chevron, the value is still read aloud — `Select.TriggerIcon`. */
|
|
2
|
+
import { Icon, type IconName, Select } from "prime-ui-kit";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
|
|
5
|
+
const ICONS: { value: IconName; label: string }[] = [
|
|
6
|
+
{ value: "object.package", label: "Склад" },
|
|
7
|
+
{ value: "object.truck", label: "Доставка" },
|
|
8
|
+
{ value: "object.receipt", label: "Счета" },
|
|
9
|
+
{ value: "object.users", label: "Клиенты" },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
export default function SelectIconOnlyExample() {
|
|
13
|
+
const [icon, setIcon] = React.useState<IconName>("object.truck");
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Select.Root
|
|
17
|
+
label="Иконка раздела"
|
|
18
|
+
value={icon}
|
|
19
|
+
onValueChange={(next) => setIcon(next as IconName)}
|
|
20
|
+
>
|
|
21
|
+
<Select.Trigger>
|
|
22
|
+
<Select.TriggerIcon>
|
|
23
|
+
<Icon name={icon} />
|
|
24
|
+
</Select.TriggerIcon>
|
|
25
|
+
</Select.Trigger>
|
|
26
|
+
<Select.Content>
|
|
27
|
+
{ICONS.map((option) => (
|
|
28
|
+
<Select.Item key={option.value} value={option.value}>
|
|
29
|
+
<Select.ItemIcon>
|
|
30
|
+
<Icon name={option.value} />
|
|
31
|
+
</Select.ItemIcon>
|
|
32
|
+
{option.label}
|
|
33
|
+
</Select.Item>
|
|
34
|
+
))}
|
|
35
|
+
</Select.Content>
|
|
36
|
+
</Select.Root>
|
|
37
|
+
);
|
|
38
|
+
}
|