prime-ui-kit 0.21.2 → 0.21.4
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 +2 -2
- package/THIRD_PARTY_NOTICES +13 -0
- package/dist/chunks/{chunk-T7IEJSTH.js → chunk-HMLQCKRL.js} +36 -0
- package/dist/chunks/{chunk-7JYPFRZ3.js → chunk-PFASPQSJ.js} +393 -354
- package/dist/chunks/{chunk-SQGPQOUO.js → chunk-SUGCIPD7.js} +1 -1
- package/dist/chunks/{chunk-ME4VEAQ5.js → chunk-UNNQITFE.js} +2132 -1619
- package/dist/chunks/{chunk-VQ3UCVDV.js → chunk-WGXXPJDR.js} +5 -2
- package/dist/color-picker.js +3 -3
- package/dist/components/chat-list/ChatList.d.ts +4 -3
- package/dist/components/command-menu/CommandMenu.d.ts +1 -4
- package/dist/components/composer/Composer.d.ts +1 -1
- package/dist/components/data-table/DataTable.d.ts +9 -7
- package/dist/components/data-table/Footer.d.ts +7 -3
- package/dist/components/datepicker/DatepickerPanel.d.ts +2 -2
- package/dist/components/dnd/labels.d.ts +2 -0
- package/dist/components/field-list/FieldList.d.ts +2 -4
- package/dist/components/file-upload/FileUpload.d.ts +1 -9
- package/dist/components/index.d.ts +2 -2
- package/dist/components/input/Input.d.ts +1 -1
- package/dist/components/kanban/Kanban.d.ts +0 -2
- package/dist/components/list/List.d.ts +7 -1
- package/dist/components/login-form/LoginForm.d.ts +5 -1
- package/dist/components/message/Message.d.ts +5 -1
- package/dist/components/message/MessageParts.d.ts +7 -2
- package/dist/components/rich-text/RichText.d.ts +12 -4
- package/dist/components/select/selectContext.d.ts +0 -2
- package/dist/components/smart-filter/SmartFilter.d.ts +1 -5
- package/dist/components/sparkline/Sparkline.d.ts +50 -8
- package/dist/components/tag-select/TagSelect.d.ts +0 -2
- package/dist/components/textarea/Textarea.d.ts +2 -2
- package/dist/icon-set.d.ts +5 -1
- package/dist/icon-set.js +8 -2
- package/dist/icons/glyph.d.ts +12 -1
- package/dist/icons/glyphs/telegram.d.ts +2 -0
- package/dist/icons/glyphs/vk.d.ts +2 -0
- package/dist/icons/glyphs/whatsapp.d.ts +2 -0
- package/dist/icons/registry.d.ts +8 -1
- package/dist/index.css +1 -1
- package/dist/index.js +7 -3
- package/dist/internal/ToolRow.d.ts +3 -1
- package/dist/internal/autofill.d.ts +30 -0
- package/dist/internal/barPlan.d.ts +7 -1
- package/dist/internal/blockStack.d.ts +7 -0
- package/dist/internal/overlay/DialogParts.d.ts +8 -6
- package/dist/internal/richText.d.ts +32 -1
- package/dist/internal/textFormatting.d.ts +2 -2
- package/dist/layout/page/Page.d.ts +2 -1
- package/dist/skill/SKILL.md +3 -2
- package/dist/skill/api-contract.md +2 -1
- package/dist/skill/cheatsheet.md +1 -1
- package/dist/skill/checklist.md +8 -1
- package/dist/skill/choosing.md +76 -5
- package/dist/skill/components.md +2 -2
- package/dist/skill/composition.md +108 -20
- package/dist/skill/foundations.md +1 -1
- package/dist/skill/layouts.md +4 -4
- package/dist/skill/reference/components/button/examples/in-form.tsx +0 -1
- package/dist/skill/reference/components/card/COMPONENT.md +1 -1
- package/dist/skill/reference/components/card/examples/screen.tsx +9 -11
- package/dist/skill/reference/components/chat-list/COMPONENT.md +6 -5
- package/dist/skill/reference/components/chat-list/examples/structure.tsx +4 -4
- package/dist/skill/reference/components/command-menu/COMPONENT.md +1 -2
- package/dist/skill/reference/components/command-menu/examples/states.tsx +1 -1
- package/dist/skill/reference/components/composer/COMPONENT.md +5 -4
- package/dist/skill/reference/components/composer/examples/formatting.tsx +1 -1
- package/dist/skill/reference/components/data-table/COMPONENT.md +17 -16
- package/dist/skill/reference/components/data-table/examples/server.tsx +2 -1
- package/dist/skill/reference/components/datepicker/COMPONENT.md +2 -2
- package/dist/skill/reference/components/dnd/COMPONENT.md +2 -1
- package/dist/skill/reference/components/drawer/COMPONENT.md +9 -6
- package/dist/skill/reference/components/drawer/examples/screen.tsx +1 -5
- package/dist/skill/reference/components/drawer/examples/tab-switcher.tsx +158 -0
- package/dist/skill/reference/components/field-list/COMPONENT.md +7 -7
- package/dist/skill/reference/components/field-list/examples/limits.tsx +2 -2
- package/dist/skill/reference/components/file-upload/COMPONENT.md +8 -12
- package/dist/skill/reference/components/file-upload/examples/gallery.tsx +2 -2
- package/dist/skill/reference/components/file-upload/examples/in-form.tsx +2 -4
- package/dist/skill/reference/components/file-upload/examples/narrow.tsx +1 -0
- package/dist/skill/reference/components/file-upload/examples/overview.tsx +1 -5
- package/dist/skill/reference/components/file-upload/examples/sizes.tsx +1 -1
- package/dist/skill/reference/components/file-upload/examples/states.tsx +4 -5
- package/dist/skill/reference/components/file-upload/examples/validation.tsx +2 -7
- package/dist/skill/reference/components/input/COMPONENT.md +3 -0
- package/dist/skill/reference/components/input/examples/in-form.tsx +0 -1
- package/dist/skill/reference/components/input/examples/validation.tsx +1 -1
- package/dist/skill/reference/components/kanban/COMPONENT.md +1 -2
- package/dist/skill/reference/components/list/COMPONENT.md +11 -6
- package/dist/skill/reference/components/list/examples/reorder.tsx +30 -3
- package/dist/skill/reference/components/login-form/COMPONENT.md +2 -2
- package/dist/skill/reference/components/login-form/examples/sizes.tsx +6 -2
- package/dist/skill/reference/components/message/COMPONENT.md +12 -7
- package/dist/skill/reference/components/message/examples/status.tsx +2 -1
- package/dist/skill/reference/components/message/examples/text-formatting.tsx +13 -3
- package/dist/skill/reference/components/modal/COMPONENT.md +5 -4
- package/dist/skill/reference/components/rich-text/COMPONENT.md +45 -7
- package/dist/skill/reference/components/rich-text/examples/entities.tsx +20 -0
- package/dist/skill/reference/components/select/COMPONENT.md +1 -2
- package/dist/skill/reference/components/sheet/COMPONENT.md +5 -4
- package/dist/skill/reference/components/smart-filter/COMPONENT.md +3 -5
- package/dist/skill/reference/components/sparkline/COMPONENT.md +40 -12
- package/dist/skill/reference/components/sparkline/examples/lower-is-better.tsx +46 -0
- package/dist/skill/reference/components/sparkline/examples/own-value.tsx +41 -0
- package/dist/skill/reference/components/sparkline/examples/reference.tsx +2 -1
- package/dist/skill/reference/components/tabs/COMPONENT.md +1 -1
- package/dist/skill/reference/components/tabs/examples/orientation.tsx +1 -1
- package/dist/skill/reference/components/tag-select/COMPONENT.md +0 -2
- package/dist/skill/reference/components/tag-select/examples/overview.tsx +0 -1
- package/dist/skill/reference/components/tag-select/examples/sizes.tsx +0 -1
- package/dist/skill/reference/components/textarea/COMPONENT.md +6 -3
- package/dist/skill/reference/icon-set.ts +5 -1
- package/dist/skill/reference/layout/page/COMPONENT.md +13 -12
- package/dist/skill/reference/layout/page/examples/collapse.tsx +45 -31
- package/dist/skill/reference/layout/page/examples/router.tsx +47 -14
- package/dist/skill/ux.md +98 -4
- package/package.json +1 -1
- package/src/components/button/examples/in-form.tsx +0 -1
- package/src/components/card/COMPONENT.md +1 -1
- package/src/components/card/examples/screen.tsx +9 -11
- package/src/components/chat-list/COMPONENT.md +6 -5
- package/src/components/chat-list/examples/structure.tsx +4 -4
- package/src/components/command-menu/COMPONENT.md +1 -2
- package/src/components/command-menu/examples/states.tsx +1 -1
- package/src/components/composer/COMPONENT.md +5 -4
- package/src/components/composer/examples/formatting.tsx +1 -1
- package/src/components/data-table/COMPONENT.md +17 -16
- package/src/components/data-table/examples/server.tsx +2 -1
- package/src/components/datepicker/COMPONENT.md +2 -2
- package/src/components/dnd/COMPONENT.md +2 -1
- package/src/components/drawer/COMPONENT.md +9 -6
- package/src/components/drawer/examples/screen.tsx +1 -5
- package/src/components/drawer/examples/tab-switcher.tsx +158 -0
- package/src/components/field-list/COMPONENT.md +7 -7
- package/src/components/field-list/examples/limits.tsx +2 -2
- package/src/components/file-upload/COMPONENT.md +8 -12
- package/src/components/file-upload/examples/gallery.tsx +2 -2
- package/src/components/file-upload/examples/in-form.tsx +2 -4
- package/src/components/file-upload/examples/narrow.tsx +1 -0
- package/src/components/file-upload/examples/overview.tsx +1 -5
- package/src/components/file-upload/examples/sizes.tsx +1 -1
- package/src/components/file-upload/examples/states.tsx +4 -5
- package/src/components/file-upload/examples/validation.tsx +2 -7
- package/src/components/input/COMPONENT.md +3 -0
- package/src/components/input/examples/in-form.tsx +0 -1
- package/src/components/input/examples/validation.tsx +1 -1
- package/src/components/kanban/COMPONENT.md +1 -2
- package/src/components/list/COMPONENT.md +11 -6
- package/src/components/list/examples/reorder.tsx +30 -3
- package/src/components/login-form/COMPONENT.md +2 -2
- package/src/components/login-form/examples/sizes.tsx +6 -2
- package/src/components/message/COMPONENT.md +12 -7
- package/src/components/message/examples/status.tsx +2 -1
- package/src/components/message/examples/text-formatting.tsx +13 -3
- package/src/components/modal/COMPONENT.md +5 -4
- package/src/components/rich-text/COMPONENT.md +45 -7
- package/src/components/rich-text/examples/entities.tsx +20 -0
- package/src/components/select/COMPONENT.md +1 -2
- package/src/components/sheet/COMPONENT.md +5 -4
- package/src/components/smart-filter/COMPONENT.md +3 -5
- package/src/components/sparkline/COMPONENT.md +40 -12
- package/src/components/sparkline/examples/lower-is-better.tsx +46 -0
- package/src/components/sparkline/examples/own-value.tsx +41 -0
- package/src/components/sparkline/examples/reference.tsx +2 -1
- package/src/components/tabs/COMPONENT.md +1 -1
- package/src/components/tabs/examples/orientation.tsx +1 -1
- package/src/components/tag-select/COMPONENT.md +0 -2
- package/src/components/tag-select/examples/overview.tsx +0 -1
- package/src/components/tag-select/examples/sizes.tsx +0 -1
- package/src/components/textarea/COMPONENT.md +6 -3
- package/src/layout/page/COMPONENT.md +13 -12
- package/src/layout/page/examples/collapse.tsx +45 -31
- package/src/layout/page/examples/router.tsx +47 -14
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** Unique clients in dialogs: the period's own count is neither the sum nor the mean of the days, so the card passes it with the previous period's count — `value`, `compareTo`. */
|
|
2
|
+
import { Card, Sparkline, type SparklinePoint } from "prime-ui-kit";
|
|
3
|
+
|
|
4
|
+
import styles from "./examples.module.css";
|
|
5
|
+
|
|
6
|
+
/** Clients who wrote each day, 2 — 15 October 2026; one client writes on many days. */
|
|
7
|
+
const CLIENTS_BY_DAY: SparklinePoint[] = [
|
|
8
|
+
{ label: "2 окт", value: 184 },
|
|
9
|
+
{ label: "3 окт", value: 201 },
|
|
10
|
+
{ label: "4 окт", value: 146 },
|
|
11
|
+
{ label: "5 окт", value: 132 },
|
|
12
|
+
{ label: "6 окт", value: 218 },
|
|
13
|
+
{ label: "7 окт", value: 226 },
|
|
14
|
+
{ label: "8 окт", value: 209 },
|
|
15
|
+
{ label: "9 окт", value: 231 },
|
|
16
|
+
{ label: "10 окт", value: 240 },
|
|
17
|
+
{ label: "11 окт", value: 158 },
|
|
18
|
+
{ label: "12 окт", value: 141 },
|
|
19
|
+
{ label: "13 окт", value: 237 },
|
|
20
|
+
{ label: "14 окт", value: 252 },
|
|
21
|
+
{ label: "15 окт", value: 244 },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
/** Unique clients over the period and over the 14 days before. */
|
|
25
|
+
const UNIQUE_CLIENTS = 1_386;
|
|
26
|
+
const PREVIOUS_UNIQUE_CLIENTS = 1_270;
|
|
27
|
+
|
|
28
|
+
export default function SparklineOwnValueExample() {
|
|
29
|
+
return (
|
|
30
|
+
<Card.Root className={styles.card}>
|
|
31
|
+
<Card.Body>
|
|
32
|
+
<Sparkline
|
|
33
|
+
data={CLIENTS_BY_DAY}
|
|
34
|
+
label="Клиенты в диалогах"
|
|
35
|
+
value={UNIQUE_CLIENTS}
|
|
36
|
+
compareTo={PREVIOUS_UNIQUE_CLIENTS}
|
|
37
|
+
/>
|
|
38
|
+
</Card.Body>
|
|
39
|
+
</Card.Root>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Checkout conversion against its plan: a dashed reference line, the scale from zero to 5% and the change over the whole period — `reference`, `min`, `max`, `change`. */
|
|
1
|
+
/** Checkout conversion against its plan: a dashed reference line, the scale from zero to 5% and the change over the whole period in percentage points — `reference`, `min`, `max`, `change`, `changeUnit`. */
|
|
2
2
|
import { Card, Sparkline, type SparklinePoint } from "prime-ui-kit";
|
|
3
3
|
|
|
4
4
|
import styles from "./examples.module.css";
|
|
@@ -29,6 +29,7 @@ export default function SparklineReferenceExample() {
|
|
|
29
29
|
min={0}
|
|
30
30
|
max={5}
|
|
31
31
|
change="first"
|
|
32
|
+
changeUnit="points"
|
|
32
33
|
formatValue={formatPercent}
|
|
33
34
|
labels={{ reference: "План: {value}" }}
|
|
34
35
|
/>
|
|
@@ -199,7 +199,7 @@ Other attributes: Root `data-orientation`, `data-size`, `data-tone`, `data-full-
|
|
|
199
199
|
|
|
200
200
|
## Layout & spacing
|
|
201
201
|
- Tabs are a bar, not a surface: the root has no fill, padding, radius or `data-depth`. On a page or in a `Card.Body`, put it straight into the host's padded region and the panel content straight into `Tabs.Panel`. The strip's edges and the panel content share the host's content edge; the panel stands one tier gap below the strip (`--prime-space-3` … `--prime-space-8`).
|
|
202
|
-
- In a Modal or Drawer the tabs belong to the header: `Tabs.Root` wraps `X.Header` and `X.Body`, `Tabs.List` goes last into the header, the panels into the body. The header becomes the strip (painted like it, no hairline, edge to edge — the header hands the bar its side padding as `--prime-bleed-inline`), the active tab is the body rising into it, and the root renders no box (`display: contents`), so only the body scrolls and the tabs stay in view.
|
|
202
|
+
- In a Modal or Drawer the tabs belong to the header: `Tabs.Root` wraps `X.Header` and `X.Body`, `Tabs.List` goes last into the header, the panels into the body. The header becomes the strip (painted like it, no hairline, edge to edge — the header hands the bar its side padding as `--prime-bleed-inline`), the active tab is the body rising into it, and the root renders no box (`display: contents`), so only the body scrolls and the tabs stay in view. A panel in the body stands its blocks 32 apart — the step between the body's sections — so a tab of self-titled blocks (charts, titled cards) or of `X.Section`s needs no spacing wrapper.
|
|
203
203
|
|
|
204
204
|
```tsx
|
|
205
205
|
<Drawer.Content>
|
|
@@ -38,7 +38,7 @@ export default function TabsOrientationExample() {
|
|
|
38
38
|
<div className={styles.form}>
|
|
39
39
|
<Input.Root label="Имя и фамилия">
|
|
40
40
|
<Input.Wrapper>
|
|
41
|
-
<Input.Field defaultValue="Анна Смирнова"
|
|
41
|
+
<Input.Field defaultValue="Анна Смирнова" />
|
|
42
42
|
</Input.Wrapper>
|
|
43
43
|
</Input.Root>
|
|
44
44
|
<Input.Root label="Должность">
|
|
@@ -30,7 +30,6 @@ TagSelect field frame: label · control · hint/error (sin
|
|
|
30
30
|
│ ├── input[type=hidden] × value with `name`
|
|
31
31
|
│ └── chevron
|
|
32
32
|
└── list (portal) role="listbox", multi-select
|
|
33
|
-
├── panel hint labels.panelHint (`""` hides it)
|
|
34
33
|
├── «Создать» row with `creatable`: plus icon · labels.create · preview Badge
|
|
35
34
|
└── option row Checkbox.Indicator · Badge [· «⋯» Button → Popover menu]; picked options first
|
|
36
35
|
```
|
|
@@ -150,7 +149,6 @@ No `variant` or `tone`. The control is the field look; chips are the kit's soft
|
|
|
150
149
|
|
|
151
150
|
| Key | Default | Used for |
|
|
152
151
|
|---|---|---|
|
|
153
|
-
| `panelHint` | `"Выберите вариант или создайте новый"` | Line above the list; `""` hides it. |
|
|
154
152
|
| `create` | `"Создать"` | Action text before the preview of a new tag. |
|
|
155
153
|
| `remove` | `"Удалить {label}"` | Accessible name of a chip's remove button; `{label}` is the tag text. |
|
|
156
154
|
| `more` | `"Показать ещё {count}"` | Accessible name of the «+N» chip; `{count}` is the number of hidden tags. |
|
|
@@ -59,7 +59,8 @@ Unlike Input, Textarea has no Wrapper / Field parts: `Textarea.Root` renders the
|
|
|
59
59
|
| `id` | `string` | — | Id of the `<textarea>` (auto-generated when omitted); hint id is `<id>-hint`, error id is `<id>-error`. |
|
|
60
60
|
| `aria-describedby` | `string` | — | Merged before the hint/error ids. |
|
|
61
61
|
| `onCommit` | `(value: string) => void \| Promise<void>` | — | Inline save: fires with a changed value on blur and Mod+Enter; Escape reverts. Return a Promise: the field shows a spinner and stays editable; a rejection restores the value — show why through `error`. |
|
|
62
|
-
| `formatting` | `boolean` | `false` | Selecting text shows a floating toolbar of
|
|
62
|
+
| `formatting` | `boolean` | `false` | Selecting text shows a floating toolbar of eight Markdown tools and enables their hotkeys; a tool wraps the selection, a second press unwraps it. Off: plain text. |
|
|
63
|
+
| `autoComplete` | `string` | `"off"` with the password-manager opt-outs; inside `LoginForm.Form`, left to the browser | A token opts in to autofill and drops the password-manager opt-outs; without one the field stays off. Pass one only on sign-in and sign-up fields and for a new password (`new-password`). |
|
|
63
64
|
| `children` | `ReactNode` | — | Actions in the field's top end corner: `Textarea.CopyButton`, `Textarea.Action`. |
|
|
64
65
|
| `labels` | `Partial<TextareaLabels>` | — | Built-in strings, see Labels. |
|
|
65
66
|
| `className` | `string` | — | Class on the field frame `<div>` (label, field box, support row), as on every field root. |
|
|
@@ -116,7 +117,7 @@ Textarea has no `variant` or `tone`: one field treatment (fill, no visible borde
|
|
|
116
117
|
| Value | Looks like | Use when | Default |
|
|
117
118
|
|---|---|---|---|
|
|
118
119
|
| `focusRing` | `false`: no focus ring; focus fill and caret remain | A single composer field where focus is obvious | `true` |
|
|
119
|
-
| `formatting` | A floating toolbar over a selection (bold, italic, strikethrough, code, spoiler, link, quote) and the Mod-hotkeys; each writes Markdown around the selection | The text is shown later with its Markdown (Message renders the same subset) | `false` |
|
|
120
|
+
| `formatting` | A floating toolbar over a selection (bold, italic, underline, strikethrough, code, spoiler, link, quote) and the Mod-hotkeys; each writes Markdown around the selection | The text is shown later with its Markdown (Message renders the same subset) | `false` |
|
|
120
121
|
| `reserveSupportRow` | Empty support row of hint height | Live validation, fields side by side | `false` |
|
|
121
122
|
| `required` / `optional` | Red `*` / muted «необязательно» after the label | Mark the minority of the form | — / `false` |
|
|
122
123
|
|
|
@@ -164,7 +165,7 @@ Inline save (`onCommit`): the text at focus is the committed one; blur and Mod+E
|
|
|
164
165
|
| `Tab` | Focuses the field, then the buttons in its corner; Enter inserts a line break instead of submitting the form. |
|
|
165
166
|
| `Mod+Enter` | With `onCommit`: saves a changed text; focus stays in the field. |
|
|
166
167
|
| `Escape` | With `formatting`: first clears a selection with the toolbar. With `onCommit`: puts the committed text back. |
|
|
167
|
-
| `Mod + B` · `Mod + I` · `Mod + Shift + X` · `Mod + E` · `Mod + Shift + H` · `Mod + K` · `Mod + Shift + 9` | With `formatting`: bold, italic, strikethrough, code, spoiler, link and quote for the selection; the physical key counts, so any layout works. |
|
|
168
|
+
| `Mod + B` · `Mod + I` · `Mod + U` · `Mod + Shift + X` · `Mod + E` · `Mod + Shift + H` · `Mod + K` · `Mod + Shift + 9` | With `formatting`: bold, italic, underline, strikethrough, code, spoiler, link and quote for the selection; the physical key counts, so any layout works. |
|
|
168
169
|
| `←` · `→` | Move between the formatting buttons. |
|
|
169
170
|
| `Home` · `End` | Jump to the first / last formatting button. |
|
|
170
171
|
|
|
@@ -194,6 +195,7 @@ Inline save (`onCommit`): the text at focus is the committed one; blur and Mod+E
|
|
|
194
195
|
| `formatting` | `"Форматирование"` | Accessible name of the formatting toolbar. |
|
|
195
196
|
| `bold` | `"Жирный"` | Bold tool. |
|
|
196
197
|
| `italic` | `"Курсив"` | Italic tool. |
|
|
198
|
+
| `underline` | `"Подчёркнутый"` | Underline tool (`__…__`). |
|
|
197
199
|
| `strikethrough` | `"Зачёркнутый"` | Strikethrough tool. |
|
|
198
200
|
| `code` | `"Моноширинный"` | Code tool. |
|
|
199
201
|
| `spoiler` | `"Скрытый текст"` | Spoiler tool (`\|\|…\|\|`). |
|
|
@@ -225,6 +227,7 @@ Inline save (`onCommit`): the text at focus is the committed one; blur and Mod+E
|
|
|
225
227
|
- A copy `Button` under a read-only result → `Textarea.CopyButton` as a child of the root.
|
|
226
228
|
- Other children than `Textarea.CopyButton` / `Textarea.Action` → the root renders the textarea itself; children are only the corner actions.
|
|
227
229
|
- `formatting` on text that is shown as plain text → the reader sees `**` and `||`; turn it on only where the text is rendered with its Markdown.
|
|
230
|
+
- Expecting the browser to offer saved addresses in a note → autofill is off unless you pass `autoComplete` (a token such as `street-address` opts in).
|
|
228
231
|
|
|
229
232
|
## Related
|
|
230
233
|
- **Built from:** [Label](../label/COMPONENT.md) (`label`), [Hint](../hint/COMPONENT.md) (`hint`, `error`), [Tooltip](../tooltip/COMPONENT.md) (corner actions, formatting tools), [Spinner](../spinner/COMPONENT.md) (`onCommit`), [Button](../button/COMPONENT.md) and [Kbd](../kbd/COMPONENT.md) (formatting tools), Icon (`format.*`); `internal/textFormatting` + `internal/textFormattingToolbar` (the formatting shared with Composer), [VisuallyHidden](../visually-hidden/COMPONENT.md)
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
- Every route rendered inside `AppShell.Main`: the app is navigation and the page, and the page carries its own top (`Page.TopBar`), title (`Page.Title`, the `<h1>`) and body.
|
|
10
10
|
- A work screen (a list, a board, a chat, a schedule): `Page.TopBar` with the title (`Page.Heading`), the page's tools (`Page.Tools`: sections, search and filter, view), all its buttons (`Page.Actions`) and the active filters (`Page.Chips`).
|
|
11
11
|
- A filter stands next to what it filters. `Page.Tools` holds what acts on the whole page: sections, the view, a period that drives several blocks (the KPI cards and the table), and a search and filter only when it narrows several views of one set (a board and its list). A table's search, filter, chips, «Колонки» and selection menu always belong to its own tools row (DataTable `toolbar` + `toolbarChips`), on a page that is only the table too.
|
|
12
|
-
- A section with sub-pages (the «Мессенджеры» item of the Sidebar with
|
|
13
|
-
- A document page (settings, a long form, help)
|
|
12
|
+
- A section with sub-pages (the «Мессенджеры» item of the Sidebar with «Каналы», «Шаблоны» and «Статистика»): each sub-page is a route of its own, `Page.Title` stays the section's name, and the switch is a `SegmentedControl` of links (`SegmentedControl.Item asChild`) in `Page.Tools`, on a line of its own under the title at the start (see Top bar plan), so it stays put while each sub-page brings its own `Page.Actions` or none; the body is the current sub-page. The Sidebar keeps the section's item current on every sub-route — a router `NavLink` to the section's path without `end`, or `current={pathname.startsWith("/messengers")}`.
|
|
13
|
+
- A document page (settings, a long form, help) read top to bottom with no page tools: `Page.Header` in the flow — the large title and its buttons — and `Page.TopBar collapse` with the path in its `Page.Heading`, which repeats the title once it scrolls away. A dashboard or an analytics page titles itself in `Page.TopBar` like a list.
|
|
14
14
|
- A nested record: a `Breadcrumb` path in `Page.Heading`; in the bar the title reads as its last level.
|
|
15
15
|
- A text page held to a reading measure (`maxWidth="readable"`), a wide dashboard capped at the content width (`maxWidth="wide"`).
|
|
16
16
|
- The tiles of a dashboard — KPI cards, charts, panels — as one board (`Page.Grid` + `Page.Cell`).
|
|
@@ -94,7 +94,7 @@ Page.Root the page column (<div>); maxWidth, fill, labe
|
|
|
94
94
|
| `…rest` | `HTMLAttributes<HTMLElement>` | — | `children` (`Page.Heading`, `Page.Tools`, `Page.Actions`, `Page.Chips` — direct children), `className` and the other attributes. |
|
|
95
95
|
|
|
96
96
|
### Page.Header
|
|
97
|
-
`ref` → `HTMLDivElement`. The document header in the page flow (settings, long forms
|
|
97
|
+
`ref` → `HTMLDivElement`. The document header in the page flow (settings, long forms): a `Page.Heading` and its `Page.Actions` in one row; the actions wrap under it on a narrow column.
|
|
98
98
|
|
|
99
99
|
| Prop | Type | Default | Description |
|
|
100
100
|
|---|---|---|---|
|
|
@@ -123,7 +123,7 @@ Page.Root the page column (<div>); maxWidth, fill, labe
|
|
|
123
123
|
| `…rest` | `HTMLAttributes<HTMLParagraphElement>` | — | `children`, `className` and the other paragraph attributes. |
|
|
124
124
|
|
|
125
125
|
### Page.Tools
|
|
126
|
-
`ref` → `HTMLDivElement`. What acts on the whole page:
|
|
126
|
+
`ref` → `HTMLDivElement`. What acts on the whole page: sub-page links, view, a shared period, a filter over several views (a table's tools go in its `toolbar`). Sub-page links take a line of their own at the start. Named, a `group`.
|
|
127
127
|
|
|
128
128
|
| Prop | Type | Default | Description |
|
|
129
129
|
|---|---|---|---|
|
|
@@ -226,8 +226,8 @@ No DOM, no ref. Holds the page from anywhere inside it: a press on a `Sidebar.It
|
|
|
226
226
|
### Place of Page.Heading
|
|
227
227
|
| Value | Looks like | Use when | Default |
|
|
228
228
|
|---|---|---|---|
|
|
229
|
-
| in `Page.TopBar` | one line as high as the Sidebar brand row: path › title-m, the caption description under the whole line; both truncate |
|
|
230
|
-
| in `Page.Header` in the flow | the large document header: path over a heading-m title, body-m description, the header's `Page.Actions` beside it, wrapping under it | document pages
|
|
229
|
+
| in `Page.TopBar` | one line as high as the Sidebar brand row: path › title-m, the caption description under the whole line; both truncate | screens of data: lists, boards, chats, records, dashboards and analytics | |
|
|
230
|
+
| in `Page.Header` in the flow | the large document header: path over a heading-m title, body-m description, the header's `Page.Actions` beside it, wrapping under it | document pages with no page tools: settings, long forms, help | |
|
|
231
231
|
|
|
232
232
|
The size follows the place; the consumer passes nothing, and there are no title size props. One `Page.Title` (`<h1>`) per page, in one of the two places. A bar with no visible title still holds the `<h1>`: a `Page.Title` wrapped in `VisuallyHidden`, or a flow `Page.Title` (with `collapse` the bar repeats it).
|
|
233
233
|
|
|
@@ -236,7 +236,7 @@ The size follows the place; the consumer passes nothing, and there are no title
|
|
|
236
236
|
|---|---|---|---|
|
|
237
237
|
| `fill` (Root) | the page is as high as main; the body takes what the bar and the header leave; main keeps gutter-high air under it | a full-height table, board, chat or `Page.Split` in an `AppShell.Root fillViewport` | `false` |
|
|
238
238
|
| `sticky` (TopBar) | the bar stays at the top of main while the page scrolls under it | every page; `false` for a bar that should scroll away | `true` |
|
|
239
|
-
| `collapse` (TopBar) | the flow title rises into the bar's title row once it scrolls away | a document page
|
|
239
|
+
| `collapse` (TopBar) | the flow title rises into the bar's title row once it scrolls away | a document page with the path in the bar and the title in the flow | `false` |
|
|
240
240
|
| `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` |
|
|
241
241
|
| `busy` (Guard) | nothing until a person leaves: a press on the navigation or the path does nothing | the page's save request runs | `false` |
|
|
242
242
|
|
|
@@ -245,13 +245,13 @@ One plan, chosen from the natural widths of the groups (`data-plan` on the bar's
|
|
|
245
245
|
|
|
246
246
|
| Step | Looks like | Use when | Default |
|
|
247
247
|
|---|---|---|---|
|
|
248
|
-
| `one` | `[Heading 1fr][Tools][Actions]` on one line | everything fits | yes |
|
|
249
|
-
| `below` | the tools on a line of their own under the heading and the actions — the one tool row, as the DataTable `toolbar`: a search (`SmartFilter.Toolbar`, `Input.Root`) takes the free room, switchers, pickers and buttons keep their width at the end; under 36rem the search takes a line of its own and a `SegmentedControl.Root` / `Datepicker.Root` / Select fills the line it stands on | heading + tools + actions do not fit | |
|
|
248
|
+
| `one` | `[Heading 1fr][Tools][Actions]` on one line | everything fits, and the tools hold no navigation | yes |
|
|
249
|
+
| `below` | the tools on a line of their own under the heading and the actions — the one tool row, as the DataTable `toolbar`: a search (`SmartFilter.Toolbar`, `Input.Root`) takes the free room, switchers, pickers and buttons keep their width at the end; under 36rem the search takes a line of its own and a `SegmentedControl.Root` / `Datepicker.Root` / Select fills the line it stands on | heading + tools + actions do not fit; always for a section's sub-pages (the tools hold a navigation — a `SegmentedControl` of links), gathered at the start | |
|
|
250
250
|
| `icons-secondary` | as `below`; secondary Buttons with a `Button.Icon` show only the icon, the label is their name and their tooltip | heading + actions still do not fit | |
|
|
251
251
|
| `icons` | the primary Button gives way to its icon too | still too wide | |
|
|
252
252
|
| `fold` | the secondary Buttons fold into «⋯» (`labels.more`); the primary stays | still too wide, and «⋯» is narrower than their icons (a single secondary keeps its icon); past it a Breadcrumb path folds into «…»; if the path and the title still do not share the line, the heading stacks: the path on its own line over the title, the title and the description wrapping (`data-heading="stack"`); a heading without a path truncates | |
|
|
253
253
|
|
|
254
|
-
The actions stay on the first line beside the heading at every step; `Page.Chips` is always a line under everything; nothing overflows. The primary is the first solid `Button.Root`; a Button without an icon keeps its label at every step; anything that is not a `Button.Root` stays as it is.
|
|
254
|
+
A section's sub-pages never share the first line: there they would stand where each sub-page's own heading and actions leave room, and those differ («Подключить канал» on one, none on another), so the switch would move under the pointer. On a line of their own at the start they stand at one place on every sub-page and at every width. The actions stay on the first line beside the heading at every step; `Page.Chips` is always a line under everything; nothing overflows. The primary is the first solid `Button.Root`; a Button without an icon keeps its label at every step; anything that is not a `Button.Root` stays as it is.
|
|
255
255
|
|
|
256
256
|
### Grid columns
|
|
257
257
|
| Grid width | Cell `span` 1–3 | `span` 4 | `span` 5–6 | `span` 7–12 | `rows` |
|
|
@@ -342,9 +342,9 @@ A wide cell (`span` 7–11) written next to a narrow one (`span` 4–5) is a pai
|
|
|
342
342
|
| [structure.tsx](examples/structure.tsx) | A document page in the flow: the path over the large title, its line of data and the page's buttons beside them, then the body with a section — `Page.Header`, `Page.Heading`, `Page.Description`, `Page.Section`. |
|
|
343
343
|
| [top-bar.tsx](examples/top-bar.tsx) | A nested record in the top bar: the path ending in the title, a line of data, the page's tools and its buttons — `Page.TopBar`, `Page.Heading`, `Page.Tools`, `Page.Actions`. |
|
|
344
344
|
| [loading.tsx](examples/loading.tsx) | A page whose figures load after it opens: the line of data keeps its place under the title while it loads, so nothing in the bar moves — `loading`. |
|
|
345
|
-
| [collapse.tsx](examples/collapse.tsx) |
|
|
345
|
+
| [collapse.tsx](examples/collapse.tsx) | A document page whose large title scrolls away under the top bar: the bar holds the path and repeats the title after it once the title is out of view — `collapse`, `Page.Header`. |
|
|
346
346
|
| [tools.tsx](examples/tools.tsx) | The orders page's tools in its top bar: sections with counts, the search and filter that narrow both views, the view, in the order written; the active filters on a line under everything — `Page.Tools`, `Page.Chips`. |
|
|
347
|
-
| [router.tsx](examples/router.tsx) | A section with sub-pages: the title is the section, each sub-page is a route of its own, the switch in the bar is their links and the body cross-fades between them; render it inside a router — `Page.Tools`, `asChild`. |
|
|
347
|
+
| [router.tsx](examples/router.tsx) | A section with sub-pages: the title is the section, each sub-page is a route of its own with its own actions, the switch in the bar is their links on a line of their own and the body cross-fades between them; render it inside a router — `Page.Tools`, `asChild`. |
|
|
348
348
|
| [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`. |
|
|
349
349
|
| [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`. |
|
|
350
350
|
| [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`. |
|
|
@@ -365,6 +365,7 @@ A wide cell (`span` 7–11) written next to a narrow one (`span` 4–5) is a pai
|
|
|
365
365
|
- `SmartFilter.Root` inside the bar, around `Page.Tools` → it holds no DOM; wrap it around `Page.Root` so its Toolbar (in `Page.Tools`) and its Chips (in `Page.Chips`) share it.
|
|
366
366
|
- A table's search, filter, chips or «Колонки» in `Page.Tools` / `Page.Chips` → they read as filters of the whole page and move when the page grows a block; they go in the table's `toolbar` / `toolbarChips` on every page, the one that is only the table too. The bar keeps the title, sections, the view, a period that drives every block and the page's buttons.
|
|
367
367
|
- Sub-pages of a section as a second Sidebar level, a tab strip inside `Page.Body`, or a title that names the sub-page → the title stays the section, the sub-pages are route links in `Page.Tools` (`SegmentedControl.Item asChild`), and the section's Sidebar item stays current on every sub-route.
|
|
368
|
+
- A dashboard or analytics page with a bar of tools only (`collapse`) over a large title in the flow → the title and its line of data go in the bar's `Page.Heading` beside the tools, as on a list; the flow header is for document pages.
|
|
368
369
|
- `Page.Header` inside `Page.TopBar` → the bar takes `Page.Heading` and `Page.Actions` directly; `Page.Header` is the flow's document header.
|
|
369
370
|
- A hand-made menu button for the phone Sidebar → the bar draws it while the Sidebar is off-canvas.
|
|
370
371
|
- Hiding buttons with media queries on a phone → `Page.Actions` in the bar collapses and folds them by measured width.
|
|
@@ -1,60 +1,74 @@
|
|
|
1
|
-
/**
|
|
2
|
-
import { AppShell, Button, Card, Icon, Page,
|
|
3
|
-
import * as React from "react";
|
|
1
|
+
/** A document page whose large title scrolls away under the top bar: the bar holds the path and repeats the title after it once the title is out of view — `collapse`, `Page.Header`. */
|
|
2
|
+
import { AppShell, Breadcrumb, Button, Card, Icon, Page, Typography } from "prime-ui-kit";
|
|
4
3
|
|
|
5
4
|
import styles from "./examples.module.css";
|
|
6
5
|
|
|
7
|
-
const
|
|
6
|
+
const SECTIONS = [
|
|
8
7
|
{
|
|
9
|
-
id: "
|
|
10
|
-
title: "
|
|
11
|
-
text: "
|
|
8
|
+
id: "terms",
|
|
9
|
+
title: "Сроки",
|
|
10
|
+
text: "Клиент может вернуть заказ в течение 14 дней после получения. Срок считается от даты в акте приёмки.",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: "condition",
|
|
14
|
+
title: "Состояние товара",
|
|
15
|
+
text: "Товар принимается в заводской упаковке, без следов использования, с ярлыками и полным комплектом.",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: "refund",
|
|
19
|
+
title: "Возврат денег",
|
|
20
|
+
text: "Деньги возвращаются тем же способом, которым был оплачен заказ, в течение 10 рабочих дней после проверки.",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "delivery",
|
|
24
|
+
title: "Доставка при возврате",
|
|
25
|
+
text: "Если товар с браком, доставку оплачивает магазин. В остальных случаях — клиент по тарифу службы доставки.",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: "exceptions",
|
|
29
|
+
title: "Исключения",
|
|
30
|
+
text: "Не возвращаются товары, изготовленные по индивидуальному заказу, и цифровые лицензии после активации.",
|
|
12
31
|
},
|
|
13
|
-
{ id: "w40", title: "29 сентября – 5 октября", text: "Выручка 1,1 млн ₽, 298 заказов." },
|
|
14
|
-
{ id: "w39", title: "22–28 сентября", text: "Выручка 0,9 млн ₽, 264 заказа." },
|
|
15
|
-
{ id: "w38", title: "15–21 сентября", text: "Выручка 1,0 млн ₽, 281 заказ." },
|
|
16
|
-
{ id: "w37", title: "8–14 сентября", text: "Выручка 0,8 млн ₽, 240 заказов." },
|
|
17
32
|
];
|
|
18
33
|
|
|
19
34
|
export default function PageCollapseExample() {
|
|
20
|
-
const [period, setPeriod] = React.useState("week");
|
|
21
|
-
|
|
22
35
|
return (
|
|
23
36
|
<div className={`${styles.window} ${styles.tall}`}>
|
|
24
37
|
<AppShell.Root fillViewport className={styles.shell}>
|
|
25
38
|
<AppShell.Main>
|
|
26
|
-
<Page.Root>
|
|
39
|
+
<Page.Root maxWidth="readable">
|
|
27
40
|
<Page.TopBar collapse>
|
|
28
|
-
<Page.
|
|
29
|
-
<
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
41
|
+
<Page.Heading>
|
|
42
|
+
<Breadcrumb.Root>
|
|
43
|
+
<Breadcrumb.Item href="#documents">Документы</Breadcrumb.Item>
|
|
44
|
+
</Breadcrumb.Root>
|
|
45
|
+
</Page.Heading>
|
|
46
|
+
</Page.TopBar>
|
|
47
|
+
<Page.Header>
|
|
48
|
+
<Page.Heading>
|
|
49
|
+
<Page.Title>Политика возвратов</Page.Title>
|
|
50
|
+
<Page.Description>
|
|
51
|
+
Действует с 1 сентября для всех заказов магазина.
|
|
52
|
+
</Page.Description>
|
|
53
|
+
</Page.Heading>
|
|
34
54
|
<Page.Actions>
|
|
35
55
|
<Button.Root variant="soft" tone="neutral">
|
|
36
56
|
<Button.Icon>
|
|
37
57
|
<Icon name="action.download" />
|
|
38
58
|
</Button.Icon>
|
|
39
|
-
|
|
59
|
+
Скачать PDF
|
|
40
60
|
</Button.Root>
|
|
41
61
|
</Page.Actions>
|
|
42
|
-
</Page.TopBar>
|
|
43
|
-
<Page.Header>
|
|
44
|
-
<Page.Heading>
|
|
45
|
-
<Page.Title>Продажи</Page.Title>
|
|
46
|
-
<Page.Description>Интернет-магазин · на 14 октября, 9:40</Page.Description>
|
|
47
|
-
</Page.Heading>
|
|
48
62
|
</Page.Header>
|
|
49
63
|
<Page.Body>
|
|
50
|
-
{
|
|
51
|
-
<Card.Root key={
|
|
64
|
+
{SECTIONS.map((section) => (
|
|
65
|
+
<Card.Root key={section.id} variant="panel">
|
|
52
66
|
<Card.Header>
|
|
53
|
-
<Card.Title as="h2">{
|
|
67
|
+
<Card.Title as="h2">{section.title}</Card.Title>
|
|
54
68
|
</Card.Header>
|
|
55
69
|
<Card.Body>
|
|
56
70
|
<Typography variant="body-m" tone="secondary">
|
|
57
|
-
{
|
|
71
|
+
{section.text}
|
|
58
72
|
</Typography>
|
|
59
73
|
</Card.Body>
|
|
60
74
|
</Card.Root>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** A section with sub-pages: the title is the section, each sub-page is a route of its own, the switch in the bar is their links and the body cross-fades between them; render it inside a router — `Page.Tools`, `asChild`. */
|
|
1
|
+
/** A section with sub-pages: the title is the section, each sub-page is a route of its own with its own actions, the switch in the bar is their links on a line of their own and the body cross-fades between them; render it inside a router — `Page.Tools`, `asChild`. */
|
|
2
2
|
import {
|
|
3
3
|
Button,
|
|
4
4
|
Card,
|
|
@@ -12,10 +12,13 @@ import {
|
|
|
12
12
|
import { Link, Route, Routes, useLocation } from "react-router-dom";
|
|
13
13
|
|
|
14
14
|
type Channel = { id: string; name: string; dialogs: number; reply: string };
|
|
15
|
+
type Template = { id: string; name: string; uses: number };
|
|
15
16
|
|
|
17
|
+
// The action of each sub-page: its own label, none on the statistics.
|
|
16
18
|
const SUB_PAGES = [
|
|
17
|
-
{ to: "/messengers/channels", label: "Каналы" },
|
|
18
|
-
{ to: "/messengers/
|
|
19
|
+
{ to: "/messengers/channels", label: "Каналы", action: "Подключить канал" },
|
|
20
|
+
{ to: "/messengers/templates", label: "Шаблоны", action: "Новый шаблон" },
|
|
21
|
+
{ to: "/messengers/stats", label: "Статистика", action: null },
|
|
19
22
|
];
|
|
20
23
|
|
|
21
24
|
const CHANNELS: Channel[] = [
|
|
@@ -25,6 +28,23 @@ const CHANNELS: Channel[] = [
|
|
|
25
28
|
{ id: "avito", name: "Авито · Склад на Южной", dialogs: 59, reply: "25 мин" },
|
|
26
29
|
];
|
|
27
30
|
|
|
31
|
+
const TEMPLATES: Template[] = [
|
|
32
|
+
{ id: "greeting", name: "Приветствие в рабочее время", uses: 812 },
|
|
33
|
+
{ id: "night", name: "Ответ ночью", uses: 264 },
|
|
34
|
+
{ id: "delivery", name: "Сроки доставки", uses: 151 },
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const TEMPLATE_COLUMNS: DataTableColumn<Template>[] = [
|
|
38
|
+
{ id: "name", header: "Шаблон", cell: (row) => row.name },
|
|
39
|
+
{
|
|
40
|
+
id: "uses",
|
|
41
|
+
header: "Отправок",
|
|
42
|
+
numeric: true,
|
|
43
|
+
headerAlign: "end",
|
|
44
|
+
cell: (row) => row.uses,
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
|
|
28
48
|
const COLUMNS: DataTableColumn<Channel>[] = [
|
|
29
49
|
{ id: "name", header: "Канал", cell: (row) => row.name },
|
|
30
50
|
{
|
|
@@ -46,7 +66,7 @@ const COLUMNS: DataTableColumn<Channel>[] = [
|
|
|
46
66
|
export default function PageRouterExample() {
|
|
47
67
|
const location = useLocation();
|
|
48
68
|
// The first sub-page answers every other path of the section (here the preview's «/»).
|
|
49
|
-
const current = SUB_PAGES.find((page) => page.to === location.pathname)
|
|
69
|
+
const current = SUB_PAGES.find((page) => page.to === location.pathname) ?? SUB_PAGES[0];
|
|
50
70
|
|
|
51
71
|
return (
|
|
52
72
|
<Page.Root>
|
|
@@ -56,7 +76,7 @@ export default function PageRouterExample() {
|
|
|
56
76
|
<Page.Description>4 канала · 1 280 диалогов за октябрь</Page.Description>
|
|
57
77
|
</Page.Heading>
|
|
58
78
|
<Page.Tools aria-label="Мессенджеры">
|
|
59
|
-
<SegmentedControl.Root value={current} aria-label="Подразделы">
|
|
79
|
+
<SegmentedControl.Root value={current.to} aria-label="Подразделы">
|
|
60
80
|
{SUB_PAGES.map((page) => (
|
|
61
81
|
<SegmentedControl.Item key={page.to} value={page.to} asChild>
|
|
62
82
|
<Link to={page.to}>{page.label}</Link>
|
|
@@ -64,18 +84,20 @@ export default function PageRouterExample() {
|
|
|
64
84
|
))}
|
|
65
85
|
</SegmentedControl.Root>
|
|
66
86
|
</Page.Tools>
|
|
67
|
-
|
|
68
|
-
<
|
|
69
|
-
<Button.
|
|
70
|
-
<Icon
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
87
|
+
{current.action ? (
|
|
88
|
+
<Page.Actions>
|
|
89
|
+
<Button.Root>
|
|
90
|
+
<Button.Icon>
|
|
91
|
+
<Icon name="action.add" />
|
|
92
|
+
</Button.Icon>
|
|
93
|
+
{current.action}
|
|
94
|
+
</Button.Root>
|
|
95
|
+
</Page.Actions>
|
|
96
|
+
) : null}
|
|
75
97
|
</Page.TopBar>
|
|
76
98
|
<Page.Body>
|
|
77
99
|
{/* `location` keeps the leaving sub-page on its own route while it fades out. */}
|
|
78
|
-
<Crossfade state={current}>
|
|
100
|
+
<Crossfade state={current.to}>
|
|
79
101
|
<Routes location={location}>
|
|
80
102
|
<Route
|
|
81
103
|
path="/messengers/stats"
|
|
@@ -105,6 +127,17 @@ export default function PageRouterExample() {
|
|
|
105
127
|
</Page.Grid>
|
|
106
128
|
}
|
|
107
129
|
/>
|
|
130
|
+
<Route
|
|
131
|
+
path="/messengers/templates"
|
|
132
|
+
element={
|
|
133
|
+
<DataTable
|
|
134
|
+
columns={TEMPLATE_COLUMNS}
|
|
135
|
+
rows={TEMPLATES}
|
|
136
|
+
getRowKey={(row) => row.id}
|
|
137
|
+
paging="none"
|
|
138
|
+
/>
|
|
139
|
+
}
|
|
140
|
+
/>
|
|
108
141
|
<Route
|
|
109
142
|
path="*"
|
|
110
143
|
element={
|