prime-ui-kit 0.18.0 → 0.19.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/dist/chunks/{chunk-OAXJWF3L.js → chunk-RZNGLELR.js} +120 -114
- package/dist/chunks/{chunk-MB4CXSLL.js → chunk-WYCTXD63.js} +832 -619
- package/dist/chunks/{chunk-X3JT5CLR.js → chunk-ZTZ2ML2B.js} +1 -1
- package/dist/color-picker.js +2 -2
- package/dist/components/data-table/ColumnsMenu.d.ts +16 -20
- package/dist/components/data-table/DataTable.d.ts +14 -11
- package/dist/components/data-table/Head.d.ts +8 -1
- package/dist/components/data-table/Row.d.ts +7 -1
- package/dist/components/data-table/StateRows.d.ts +3 -1
- package/dist/components/field-list/FieldList.d.ts +8 -8
- package/dist/components/index.d.ts +1 -1
- package/dist/components/kanban/Kanban.d.ts +4 -0
- package/dist/components/list/List.d.ts +9 -4
- package/dist/index.css +1 -1
- package/dist/index.js +2 -2
- package/dist/internal/fieldCell.d.ts +6 -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 +1 -7
- package/dist/skill/anti-slop.md +23 -0
- package/dist/skill/api-contract.md +1 -1
- package/dist/skill/cheatsheet.md +7 -3
- package/dist/skill/checklist.md +4 -0
- package/dist/skill/composition.md +70 -12
- 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 +40 -40
- package/dist/skill/reference/components/data-table/examples/actions-column.tsx +154 -0
- package/dist/skill/reference/components/data-table/examples/columns-visibility.tsx +3 -12
- package/dist/skill/reference/components/data-table/examples/controlled.tsx +1 -1
- package/dist/skill/reference/components/data-table/examples/narrow.tsx +4 -11
- 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/toolbar.tsx +26 -32
- package/dist/skill/reference/components/dnd/COMPONENT.md +4 -3
- 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.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 +29 -25
- 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/reorder.tsx +1 -1
- package/dist/skill/reference/components/field-list/examples/screen.module.css +1 -1
- package/dist/skill/reference/components/field-list/examples/screen.tsx +168 -162
- package/dist/skill/reference/components/field-list/examples/totals.tsx +9 -8
- 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/segmented-control/COMPONENT.md +3 -2
- package/dist/skill/reference/components/sheet/COMPONENT.md +18 -7
- package/dist/skill/reference/layout/page/COMPONENT.md +5 -12
- 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 +7 -5
- package/dist/tokens/semantic.d.ts +1 -1
- 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 +40 -40
- package/src/components/data-table/examples/actions-column.tsx +154 -0
- package/src/components/data-table/examples/columns-visibility.tsx +3 -12
- package/src/components/data-table/examples/controlled.tsx +1 -1
- package/src/components/data-table/examples/narrow.tsx +4 -11
- 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/toolbar.tsx +26 -32
- package/src/components/dnd/COMPONENT.md +4 -3
- 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.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 +29 -25
- 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/reorder.tsx +1 -1
- package/src/components/field-list/examples/screen.module.css +1 -1
- package/src/components/field-list/examples/screen.tsx +168 -162
- package/src/components/field-list/examples/totals.tsx +9 -8
- 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/segmented-control/COMPONENT.md +3 -2
- package/src/components/sheet/COMPONENT.md +18 -7
- package/src/layout/page/COMPONENT.md +5 -12
- 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,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)
|
|
@@ -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)
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
- A nested record: a `Breadcrumb` path in `Page.Heading`; in the bar the title reads as its last level.
|
|
13
13
|
- A text page held to a reading measure (`maxWidth="readable"`), a wide dashboard capped at the content width (`maxWidth="wide"`).
|
|
14
14
|
- 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
|
|
15
|
+
- 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
16
|
- A page whose body takes the rest of the panel's height — a log table, a board, a chat (`fill`).
|
|
17
17
|
- 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
18
|
- 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 +20,7 @@
|
|
|
20
20
|
## When not to use
|
|
21
21
|
- 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
22
|
- 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).
|
|
23
|
+
- 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
24
|
- An empty / error / not-found page → use [EmptyPage](../../components/empty-page/COMPONENT.md).
|
|
25
25
|
- A heading inside a card → `Card.Title`; text headings inside prose → use [Typography](../../components/typography/COMPONENT.md).
|
|
26
26
|
- A grid inside one block (thumbnails, fields, bars in a panel) → the block's own CSS grid; `Page.Grid` places the page's tiles.
|
|
@@ -155,7 +155,6 @@ Page.Root the page column (<div>); maxWidth, fill, labe
|
|
|
155
155
|
|---|---|---|---|
|
|
156
156
|
| `label` | `ReactNode` | — (required) | The visible heading (`h2`); it also names the section. |
|
|
157
157
|
| `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
158
|
| `…rest` | `Omit<HTMLAttributes<HTMLElement>, "title">` | — | `children` (the content; `Page.Actions` goes to the heading row), `className` and the other section attributes. |
|
|
160
159
|
|
|
161
160
|
### Page.Grid
|
|
@@ -239,12 +238,6 @@ The size follows the place; the consumer passes nothing, and there are no title
|
|
|
239
238
|
| `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
239
|
| `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
240
|
|
|
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
241
|
### Top bar plan
|
|
249
242
|
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
243
|
|
|
@@ -288,7 +281,6 @@ A wide cell (`span` 7–11) written next to a narrow one (`span` 4–5) is a pai
|
|
|
288
281
|
| folded buttons | plan `fold` | the secondary Buttons' wrappers `hidden`; a «⋯» Dropdown in their place, their `menuitem`s inside |
|
|
289
282
|
| heading place | inside TopBar or in the flow | `data-place="bar" \| "flow"` on Heading |
|
|
290
283
|
| 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
284
|
| tile span | `span` / `rows` on Cell | `data-span="1"…"12"` (always), `data-rows="2"…"4"` (absent for 1) |
|
|
293
285
|
| 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
286
|
| 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 |
|
|
@@ -349,12 +341,12 @@ A wide cell (`span` 7–11) written next to a narrow one (`span` 4–5) is a pai
|
|
|
349
341
|
| [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
342
|
| [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
343
|
| [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
|
|
344
|
+
| [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
345
|
| [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
346
|
| [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
347
|
| [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
348
|
| [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,
|
|
349
|
+
| [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
350
|
|
|
359
351
|
## Mistakes
|
|
360
352
|
- `{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.
|
|
@@ -371,6 +363,7 @@ A wide cell (`span` 7–11) written next to a narrow one (`span` 4–5) is a pai
|
|
|
371
363
|
- Hiding buttons with media queries on a phone → `Page.Actions` in the bar collapses and folds them by measured width.
|
|
372
364
|
- 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
365
|
- A hand-made `<section>` + `Typography as="h2"` + own gap CSS → `Page.Section label`.
|
|
366
|
+
- 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
367
|
- Each row of cards in its own grid → put every tile of the screen in one `Page.Grid`.
|
|
375
368
|
- Computing a height from `100vh` minus the bar for a full-height table or chat → `Page.Root fill` and a filling child.
|
|
376
369
|
- A list + detail built with window media queries → `Page.Split` follows its own width.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** 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,
|
|
1
|
+
/** 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`. */
|
|
2
2
|
import {
|
|
3
3
|
Breadcrumb,
|
|
4
4
|
Button,
|
|
@@ -88,118 +88,107 @@ export default function PageScreenExample() {
|
|
|
88
88
|
</Page.Heading>
|
|
89
89
|
</Page.Header>
|
|
90
90
|
<Page.Body>
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
<Card.
|
|
98
|
-
<
|
|
99
|
-
<
|
|
100
|
-
<Input.
|
|
91
|
+
<form noValidate onSubmit={save} onReset={() => setInnError(undefined)}>
|
|
92
|
+
<Card.Root variant="panel">
|
|
93
|
+
<Card.Header>
|
|
94
|
+
<Card.Title as="h2">Компания</Card.Title>
|
|
95
|
+
<Card.Description>Попадают в счета, акты и письма клиентам.</Card.Description>
|
|
96
|
+
</Card.Header>
|
|
97
|
+
<Card.Body>
|
|
98
|
+
<Fieldset disabled={saving}>
|
|
99
|
+
<Input.Root label="Название">
|
|
100
|
+
<Input.Wrapper>
|
|
101
|
+
<Input.Field name="name" defaultValue="ООО «Прайм Софт»" />
|
|
102
|
+
</Input.Wrapper>
|
|
103
|
+
</Input.Root>
|
|
104
|
+
<div className={styles.pair}>
|
|
105
|
+
<Input.Root label="ИНН" error={innError} hint="10 или 12 цифр" reserveSupportRow>
|
|
101
106
|
<Input.Wrapper>
|
|
102
|
-
<Input.Field name="
|
|
107
|
+
<Input.Field name="inn" inputMode="numeric" defaultValue="7704512908" />
|
|
103
108
|
</Input.Wrapper>
|
|
104
109
|
</Input.Root>
|
|
105
|
-
<
|
|
106
|
-
<
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
</
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
))}
|
|
126
|
-
</Select.Content>
|
|
127
|
-
</Select.Root>
|
|
128
|
-
</div>
|
|
129
|
-
<Textarea.Root
|
|
130
|
-
name="address"
|
|
131
|
-
label="Юридический адрес"
|
|
132
|
-
optional
|
|
133
|
-
rows={2}
|
|
134
|
-
defaultValue="125009, Москва, ул. Тверская, д. 7, офис 412"
|
|
135
|
-
/>
|
|
136
|
-
</Fieldset>
|
|
137
|
-
</Card.Body>
|
|
138
|
-
<Card.Footer>
|
|
139
|
-
<Button.Root type="reset" variant="ghost" tone="neutral" disabled={saving}>
|
|
140
|
-
Отменить изменения
|
|
141
|
-
</Button.Root>
|
|
142
|
-
<Button.Root type="submit" loading={saving}>
|
|
143
|
-
{saved ? "Сохранено" : "Сохранить"}
|
|
144
|
-
</Button.Root>
|
|
145
|
-
</Card.Footer>
|
|
146
|
-
</Card.Root>
|
|
147
|
-
</form>
|
|
148
|
-
</Page.Section>
|
|
149
|
-
|
|
150
|
-
<Page.Section
|
|
151
|
-
layout="aside"
|
|
152
|
-
label="Уведомления"
|
|
153
|
-
description="Включаются сразу, без сохранения."
|
|
154
|
-
>
|
|
155
|
-
<Card.Root variant="panel">
|
|
156
|
-
<Card.Body>
|
|
157
|
-
<Fieldset aria-label="Уведомления">
|
|
158
|
-
{ALERTS.map((alert) => (
|
|
159
|
-
<Switch.Root
|
|
160
|
-
key={alert.name}
|
|
161
|
-
name={alert.name}
|
|
162
|
-
defaultChecked={alert.defaultChecked}
|
|
163
|
-
hint={alert.hint}
|
|
164
|
-
>
|
|
165
|
-
<Switch.Label>{alert.label}</Switch.Label>
|
|
166
|
-
</Switch.Root>
|
|
167
|
-
))}
|
|
110
|
+
<Select.Root label="Часовой пояс" defaultValue="Europe/Moscow">
|
|
111
|
+
<Select.Trigger>
|
|
112
|
+
<Select.Value />
|
|
113
|
+
</Select.Trigger>
|
|
114
|
+
<Select.Content searchable>
|
|
115
|
+
{TIMEZONES.map((zone) => (
|
|
116
|
+
<Select.Item key={zone.value} value={zone.value}>
|
|
117
|
+
{zone.label}
|
|
118
|
+
</Select.Item>
|
|
119
|
+
))}
|
|
120
|
+
</Select.Content>
|
|
121
|
+
</Select.Root>
|
|
122
|
+
</div>
|
|
123
|
+
<Textarea.Root
|
|
124
|
+
name="address"
|
|
125
|
+
label="Юридический адрес"
|
|
126
|
+
optional
|
|
127
|
+
rows={2}
|
|
128
|
+
defaultValue="125009, Москва, ул. Тверская, д. 7, офис 412"
|
|
129
|
+
/>
|
|
168
130
|
</Fieldset>
|
|
169
131
|
</Card.Body>
|
|
132
|
+
<Card.Footer>
|
|
133
|
+
<Button.Root type="reset" variant="ghost" tone="neutral" disabled={saving}>
|
|
134
|
+
Отменить изменения
|
|
135
|
+
</Button.Root>
|
|
136
|
+
<Button.Root type="submit" loading={saving}>
|
|
137
|
+
{saved ? "Сохранено" : "Сохранить"}
|
|
138
|
+
</Button.Root>
|
|
139
|
+
</Card.Footer>
|
|
170
140
|
</Card.Root>
|
|
171
|
-
</
|
|
141
|
+
</form>
|
|
172
142
|
|
|
173
|
-
<
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
<Card.
|
|
179
|
-
<
|
|
180
|
-
|
|
181
|
-
<
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
</div>
|
|
187
|
-
<ConfirmDialog.Root
|
|
188
|
-
title="Удалить «Прайм Софт»?"
|
|
189
|
-
description="312 счетов, 48 клиентов и вся история удалятся без возможности восстановления."
|
|
190
|
-
confirmLabel="Удалить пространство"
|
|
191
|
-
onConfirm={removeWorkspace}
|
|
143
|
+
<Card.Root variant="panel">
|
|
144
|
+
<Card.Header>
|
|
145
|
+
<Card.Title as="h2">Уведомления</Card.Title>
|
|
146
|
+
<Card.Description>Включаются сразу, без сохранения.</Card.Description>
|
|
147
|
+
</Card.Header>
|
|
148
|
+
<Card.Body>
|
|
149
|
+
<Fieldset aria-label="Уведомления">
|
|
150
|
+
{ALERTS.map((alert) => (
|
|
151
|
+
<Switch.Root
|
|
152
|
+
key={alert.name}
|
|
153
|
+
name={alert.name}
|
|
154
|
+
defaultChecked={alert.defaultChecked}
|
|
155
|
+
hint={alert.hint}
|
|
192
156
|
>
|
|
193
|
-
<
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
157
|
+
<Switch.Label>{alert.label}</Switch.Label>
|
|
158
|
+
</Switch.Root>
|
|
159
|
+
))}
|
|
160
|
+
</Fieldset>
|
|
161
|
+
</Card.Body>
|
|
162
|
+
</Card.Root>
|
|
163
|
+
|
|
164
|
+
<Card.Root variant="panel">
|
|
165
|
+
<Card.Header>
|
|
166
|
+
<Card.Title as="h2">Рабочее пространство</Card.Title>
|
|
167
|
+
<Card.Description>Действия, которые нельзя отменить.</Card.Description>
|
|
168
|
+
</Card.Header>
|
|
169
|
+
<Card.Body>
|
|
170
|
+
<div className={styles.danger}>
|
|
171
|
+
<div className={styles.dangerText}>
|
|
172
|
+
<Typography variant="title-s">Удалить пространство</Typography>
|
|
173
|
+
<Typography variant="body-s" tone="secondary">
|
|
174
|
+
Счета, клиенты и история будут удалены для всех участников.
|
|
175
|
+
</Typography>
|
|
199
176
|
</div>
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
177
|
+
<ConfirmDialog.Root
|
|
178
|
+
title="Удалить «Прайм Софт»?"
|
|
179
|
+
description="312 счетов, 48 клиентов и вся история удалятся без возможности восстановления."
|
|
180
|
+
confirmLabel="Удалить пространство"
|
|
181
|
+
onConfirm={removeWorkspace}
|
|
182
|
+
>
|
|
183
|
+
<ConfirmDialog.Trigger>
|
|
184
|
+
<Button.Root variant="outline" tone="danger">
|
|
185
|
+
Удалить
|
|
186
|
+
</Button.Root>
|
|
187
|
+
</ConfirmDialog.Trigger>
|
|
188
|
+
</ConfirmDialog.Root>
|
|
189
|
+
</div>
|
|
190
|
+
</Card.Body>
|
|
191
|
+
</Card.Root>
|
|
203
192
|
</Page.Body>
|
|
204
193
|
</Page.Root>
|
|
205
194
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
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
|
|
2
|
-
import { Card, DataTable, type DataTableColumn, LinkButton, Page
|
|
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 — `Page.Section`, `label`, `description`, `Page.Actions`. */
|
|
2
|
+
import { Card, DataTable, type DataTableColumn, LinkButton, Page } from "prime-ui-kit";
|
|
3
3
|
|
|
4
4
|
import styles from "./examples.module.css";
|
|
5
5
|
|
|
@@ -55,19 +55,6 @@ export default function PageSectionsExample() {
|
|
|
55
55
|
</Page.Actions>
|
|
56
56
|
<DataTable columns={COLUMNS} rows={INVOICES} getRowKey={(row) => row.id} paging="none" />
|
|
57
57
|
</Page.Section>
|
|
58
|
-
<Page.Section
|
|
59
|
-
layout="aside"
|
|
60
|
-
label="Реквизиты в счетах"
|
|
61
|
-
description="Попадают в каждый новый счёт."
|
|
62
|
-
>
|
|
63
|
-
<Card.Root variant="panel">
|
|
64
|
-
<Card.Body>
|
|
65
|
-
<Typography variant="body-m" tone="secondary">
|
|
66
|
-
ООО «Прайм Софт», ИНН 7701234567, р/с в Т-Банке.
|
|
67
|
-
</Typography>
|
|
68
|
-
</Card.Body>
|
|
69
|
-
</Card.Root>
|
|
70
|
-
</Page.Section>
|
|
71
58
|
</Page.Body>
|
|
72
59
|
</div>
|
|
73
60
|
);
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
--prime-color-accent-soft: var(--prime-ref-color-cobalt-950);
|
|
7
7
|
--prime-color-accent-soft-hover: color-mix(in srgb, var(--prime-ref-color-cobalt-500) 28%, transparent);
|
|
8
8
|
--prime-color-accent-text: var(--prime-ref-color-cobalt-400);
|
|
9
|
-
--prime-color-bg-edge-shadow: color-mix(in srgb, var(--prime-ref-color-black)
|
|
9
|
+
--prime-color-bg-edge-shadow: color-mix(in srgb, var(--prime-ref-color-black) 28%, transparent);
|
|
10
10
|
--prime-color-bg-glass: color-mix(in srgb, var(--prime-ref-color-gray-875) 76%, transparent);
|
|
11
11
|
--prime-color-bg-glass-edge: color-mix(in srgb, var(--prime-ref-color-white) 28%, transparent);
|
|
12
12
|
--prime-color-bg-inverse: var(--prime-ref-color-gray-100);
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
--prime-color-accent-soft: var(--prime-ref-color-cobalt-100);
|
|
70
70
|
--prime-color-accent-soft-hover: var(--prime-ref-color-cobalt-200);
|
|
71
71
|
--prime-color-accent-text: var(--prime-ref-color-cobalt-700);
|
|
72
|
-
--prime-color-bg-edge-shadow: color-mix(in srgb, var(--prime-ref-color-gray-925)
|
|
72
|
+
--prime-color-bg-edge-shadow: color-mix(in srgb, var(--prime-ref-color-gray-925) 8%, transparent);
|
|
73
73
|
--prime-color-bg-glass: color-mix(in srgb, var(--prime-ref-color-white) 72%, transparent);
|
|
74
74
|
--prime-color-bg-glass-edge: color-mix(in srgb, var(--prime-ref-color-white) 85%, transparent);
|
|
75
75
|
--prime-color-bg-glass-solid: var(--prime-color-layer-floating-bg);
|