prime-ui-kit 0.21.1 → 0.21.3
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-6L7VWEY6.js → chunk-BAJRN3QN.js} +2 -2
- package/dist/chunks/{chunk-QFHE5GKW.js → chunk-HMLQCKRL.js} +605 -556
- package/dist/chunks/{chunk-S27VR4ON.js → chunk-JO7E6SZQ.js} +105 -40
- package/dist/chunks/{chunk-S4H2ZKWJ.js → chunk-R5LI5BO3.js} +2150 -1615
- package/dist/chunks/{chunk-IVS3J7AS.js → chunk-SUGCIPD7.js} +1 -1
- 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/kanban/Kanban.d.ts +0 -2
- package/dist/components/list/List.d.ts +7 -1
- package/dist/components/message/Message.d.ts +7 -3
- package/dist/components/message/MessageParts.d.ts +7 -2
- package/dist/components/rich-text/RichText.d.ts +12 -4
- package/dist/components/scroll-container/ScrollContainer.d.ts +1 -1
- 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 +1 -1
- package/dist/icon-set.d.ts +6 -1
- package/dist/icon-set.js +10 -2
- package/dist/icons/glyph.d.ts +12 -1
- package/dist/icons/glyphs/app-window.d.ts +2 -0
- 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 +10 -1
- package/dist/index.css +1 -1
- package/dist/index.js +7 -3
- package/dist/internal/ToolRow.d.ts +3 -1
- package/dist/internal/barPlan.d.ts +7 -1
- package/dist/internal/blockStack.d.ts +7 -0
- package/dist/internal/overlay/DialogParts.d.ts +9 -7
- package/dist/internal/richText.d.ts +32 -1
- package/dist/internal/selectionIndicator.d.ts +9 -3
- 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 +3 -2
- package/dist/skill/cheatsheet.md +1 -1
- package/dist/skill/checklist.md +6 -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/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 +18 -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/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/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/message/COMPONENT.md +17 -11
- package/dist/skill/reference/components/message/examples/bot-actions.tsx +6 -2
- 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/scroll-container/COMPONENT.md +5 -5
- package/dist/skill/reference/components/scroll-container/examples/overscroll.tsx +2 -2
- 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 +2 -2
- 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 +4 -3
- package/dist/skill/reference/icon-set.ts +6 -1
- package/dist/skill/reference/layout/app-shell/COMPONENT.md +1 -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 +79 -2
- package/package.json +1 -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 +18 -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/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/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/message/COMPONENT.md +17 -11
- package/src/components/message/examples/bot-actions.tsx +6 -2
- 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/scroll-container/COMPONENT.md +5 -5
- package/src/components/scroll-container/examples/overscroll.tsx +2 -2
- 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 +2 -2
- 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 +4 -3
- package/src/layout/app-shell/COMPONENT.md +1 -1
- 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
|
@@ -18,7 +18,7 @@ playground page. What each screen teaches is in [Screen rules](#screen-rules) at
|
|
|
18
18
|
| [Settings page](#settings-page) | page | [screen.tsx](reference/layout/page/examples/screen.tsx) | the path in a collapsing top bar, the large title in the flow, a card with its own header per section, form with its own save, Switches that apply at once, danger zone with a confirm |
|
|
19
19
|
| [Form in a Drawer](#form-in-a-drawer) | drawer | [screen.tsx](reference/components/drawer/examples/screen.tsx) | the title, counts and the Drawer trigger in the top bar, the search in the table's toolbar; Drawer form: groups, errors on submit, focus on the first invalid field, loading, toast |
|
|
20
20
|
| [Record editor](#record-editor) | field-list | [screen.tsx](reference/components/field-list/examples/screen.tsx) | a document page (a long form): the title and a line of description in `Page.Heading`, «Сохранить тариф» in `Page.Actions`, both in a `Page.Header` in the flow; a plan card edited in card sections: name and description, specs in a `FieldList` (icon-only `Select` and `ColorPresets` in compact columns, pinned rows, reorder), the price and its changes by month in one list with the base row pinned, a setup fee in three currencies in one row under one heading, save with «Сохранено» on the button |
|
|
21
|
-
| [Dashboard](#dashboard) | card | [screen.tsx](reference/components/card/examples/screen.tsx) | the
|
|
21
|
+
| [Dashboard](#dashboard) | card | [screen.tsx](reference/components/card/examples/screen.tsx) | an overview titled in its `Page.TopBar`: the title + a line of data, the period switch and the report; KPI row that cross-fades to the new period, a Sparkline revenue trend, invoiced vs paid in a ChartFrame, panels with progress and a split, short table + link to the list |
|
|
22
22
|
| [Screen states](#screen-states) | crossfade | [screen.tsx](reference/components/crossfade/examples/screen.tsx) | title + the statement date in `Page.TopBar`, page error in a Banner with retry, region loading with a Skeleton, Crossfade between states, table error in place, first-run EmptyPage |
|
|
23
23
|
| [Messenger](#messenger) | chat | [screen.tsx](reference/components/chat/examples/screen.tsx) | title + the unread count in `Page.TopBar`; a full-height Page.Split of a `ChatList` with its search (live last message, ticks, unread counts, «печатает…») and a `Chat`: `Chat.Header` with the back button, avatar, title, the status that turns into «печатает…» (`typing`) and the search button, `Chat.Search`, `Chat.Messages` from `items` + `renderMessage` (dates, runs and the unread band from the data, history loaded above with `hasOlder` / `onLoadOlder`, a first load in skeletons), text, a photo, a file and sent voice, reply and edit from the menu through `Composer.Context messageId` (`replyTo` / `editOf`), the jump to the quoted message (`Message.Reply target`), optimistic sends whose messages rise from the composer while the client's answer slides in, «печатает…» both ways (`onActivityChange` → `Chat.Root typing`), unread counts from `onNewMessage` and `onRead`, the Composer with attachments in `Chat.Footer` |
|
|
24
24
|
| [Sales pipeline board](#sales-pipeline-board) | kanban | [screen.tsx](reference/components/kanban/examples/screen.tsx) | `Page.TopBar` titles the page (`h1` + a Description with the open deals and their sum) with SmartFilter search and a board / list SegmentedControl in `Page.Tools` and the one primary action in `Page.Actions`; Crossfade between a `plain` Kanban (stages without wells, deal cards on the page) and a DataTable of the same deals, column totals in `renderColumnMeta`, moves saved through an `onValueChange` promise that the server can refuse, the deal in a Drawer with a DescriptionList and stage actions, skeleton first load |
|
|
@@ -38,22 +38,57 @@ its `Page.TopBar` (sticky) and its `Page.Body`, plus a `Page.Header` in the flow
|
|
|
38
38
|
**One title per page.** `Page.Title` is the page's only `<h1>`, a `Page.Description` with it is one
|
|
39
39
|
line that carries data («Среда, 14 октября · 3 задачи», «Отправлен · оплатить до 14 октября»), and a
|
|
40
40
|
nested record puts the path up (a `Breadcrumb.Root` before the title) — all three inside
|
|
41
|
-
`Page.Heading`, the title group. Where the heading stands follows the
|
|
41
|
+
`Page.Heading`, the title group. Where the heading stands follows what the body is; its size follows
|
|
42
42
|
the place:
|
|
43
43
|
|
|
44
|
-
- **
|
|
44
|
+
- **Every screen of data** — a list, a board, a chat, a schedule, a record, and every overview
|
|
45
|
+
(a dashboard, analytics, statistics, finances, a builder): `Page.Heading` stands in
|
|
45
46
|
`Page.TopBar` beside the page's tools and buttons ([the top bar](#the-top-bar)); there is no header
|
|
46
|
-
in the flow.
|
|
47
|
-
- **Document pages** — settings, a long form, an article or help text
|
|
48
|
-
|
|
47
|
+
in the flow, and the body starts with the first block.
|
|
48
|
+
- **Document pages** — settings, a long form, an article or help text, read top to bottom in one
|
|
49
|
+
column with no page tools (no period, view or sections): `Page.Header` in the flow holds
|
|
50
|
+
`Page.Heading` (the large title with one sentence of `Page.Description`) and the page's save
|
|
49
51
|
action in `Page.Actions`; optionally a `Page.TopBar collapse` with only the path in its
|
|
50
52
|
`Page.Heading`, which repeats the title once it scrolls away.
|
|
51
|
-
- **Overviews** — dashboards: a `Page.TopBar collapse` with the page's tools (the period) in
|
|
52
|
-
`Page.Tools` and its buttons (a report) in `Page.Actions`, and the titled `Page.Header` in the flow.
|
|
53
53
|
|
|
54
|
+
The test: a page with tools (a period, a view, sections), tiles or charts is a screen of data, and its
|
|
55
|
+
title stands in the bar. `collapse` belongs only to a bar that holds a `Page.Heading` (the path of a
|
|
56
|
+
document page); a bar of tools alone over a large title in the flow is two headers for one page.
|
|
54
57
|
Never two titles; never no `<h1>`. A bar whose page shows no title still holds a `Page.Title` — inside
|
|
55
58
|
`VisuallyHidden` — unless a flow `Page.Header` has one.
|
|
56
59
|
|
|
60
|
+
```tsx partial
|
|
61
|
+
// bad — an overview split in two: the bar holds only the period, the title stands in the flow
|
|
62
|
+
<Page.Root>
|
|
63
|
+
<Page.TopBar collapse>
|
|
64
|
+
<Page.Tools aria-label="Аналитика">…</Page.Tools>
|
|
65
|
+
</Page.TopBar>
|
|
66
|
+
<Page.Header>
|
|
67
|
+
<Page.Heading>
|
|
68
|
+
<Page.Title>Аналитика</Page.Title>
|
|
69
|
+
<Page.Description>Продажи · на 8 октября, 9:40</Page.Description>
|
|
70
|
+
</Page.Heading>
|
|
71
|
+
</Page.Header>
|
|
72
|
+
<Page.Body>…</Page.Body>
|
|
73
|
+
</Page.Root>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```tsx good
|
|
77
|
+
// good — the overview titles itself in its bar, like every screen of data
|
|
78
|
+
<Page.Root>
|
|
79
|
+
<Page.TopBar>
|
|
80
|
+
<Page.Heading>
|
|
81
|
+
<Page.Title>Аналитика</Page.Title>
|
|
82
|
+
<Page.Description>Продажи · на 8 октября, 9:40</Page.Description>
|
|
83
|
+
</Page.Heading>
|
|
84
|
+
<Page.Tools aria-label="Аналитика">
|
|
85
|
+
<Datepicker.Root mode="range" aria-label="Период" />
|
|
86
|
+
</Page.Tools>
|
|
87
|
+
</Page.TopBar>
|
|
88
|
+
<Page.Body>…</Page.Body>
|
|
89
|
+
</Page.Root>
|
|
90
|
+
```
|
|
91
|
+
|
|
57
92
|
```
|
|
58
93
|
AppShell.Root once per app (layouts.md#app-frame-once-per-app)
|
|
59
94
|
├─ AppShell.Nav → Sidebar navigation rail, one layer above the page
|
|
@@ -74,9 +109,9 @@ AppShell.Root once per app (layouts.md#app-frame-once-per-a
|
|
|
74
109
|
│ └─ Page.Cell span (of 12), rows; the tile fills it
|
|
75
110
|
└─ Page.Section a new topic: h2 label (+ Page.Actions), 40 from its neighbours
|
|
76
111
|
|
|
77
|
-
Document page
|
|
112
|
+
Document page: the title in the flow
|
|
78
113
|
└─ Page.Root maxWidth="wide" | "readable"
|
|
79
|
-
├─ Page.TopBar collapse the path
|
|
114
|
+
├─ Page.TopBar collapse only the path in its Page.Heading; repeats the title once it scrolls away
|
|
80
115
|
├─ Page.Header Page.Heading (the one h1, a sentence of description) + Page.Actions; 24 above the body
|
|
81
116
|
└─ Page.Body
|
|
82
117
|
```
|
|
@@ -191,8 +226,9 @@ with «Сделки» and «Документы». Each facet is a route of its o
|
|
|
191
226
|
the current link of the switch, never a second title or a title that names the facet.
|
|
192
227
|
- **The switch is links in `Page.Tools`**: a `SegmentedControl` whose items are router links
|
|
193
228
|
(`SegmentedControl.Item asChild`), `value` = the current path. It is a navigation (Tab moves
|
|
194
|
-
through the links, the current one is `aria-current="page"`),
|
|
195
|
-
own under the title
|
|
229
|
+
through the links, the current one is `aria-current="page"`), and the bar always gives it a line
|
|
230
|
+
of its own under the title, at the start edge, so the switch stands still from one sub-page to the
|
|
231
|
+
next whatever each sub-page puts beside the title.
|
|
196
232
|
- **The body is the sub-page**, swapped in a `Crossfade` keyed by the path (`Routes` given the
|
|
197
233
|
`location`, so the leaving sub-page stays on its route while it fades).
|
|
198
234
|
- **The Sidebar stays on the section.** Its item is current on every sub-route: a `NavLink` to
|
|
@@ -345,7 +381,7 @@ Hierarchy comes from space and a handful of type roles, not from size jumps, col
|
|
|
345
381
|
- **One primary per area** (the page, card, dialog, form): `solid`, last in its row. Secondary:
|
|
346
382
|
`soft` + `tone="neutral"`. Dismiss / revert: `ghost` + `neutral` in pages and cards, `outline` +
|
|
347
383
|
`neutral` in Modal / Drawer footers.
|
|
348
|
-
- Placement: every button of the page in one `Page.Actions` — of `Page.TopBar` on a
|
|
384
|
+
- Placement: every button of the page in one `Page.Actions` — of `Page.TopBar` on a screen of data, of the flow `Page.Header` on a document page — the primary last; card actions in `Card.Footer`; dialog actions in
|
|
349
385
|
`Modal.Footer` / `Drawer.Footer`; row actions in the last column; actions on the selected rows of a
|
|
350
386
|
table in its selection menu ([controls of a table](#controls-of-a-table)).
|
|
351
387
|
- A dialog footer is the dialog's answer: Cancel and the primary. Deleting the record the dialog
|
|
@@ -444,7 +480,8 @@ row of a `FieldList` follows the same count ([forms](#7-forms)).
|
|
|
444
480
|
|
|
445
481
|
### Where the filters go
|
|
446
482
|
|
|
447
|
-
A control stands with what it changes. Ask of each one: what does it narrow or switch?
|
|
483
|
+
A control stands with what it changes. Ask of each one: what does it narrow or switch? (In a
|
|
484
|
+
drawer, the open tab is a «what» too: [a control for the whole tab](#a-record-in-a-drawer).)
|
|
448
485
|
|
|
449
486
|
- **One table** — its search and filter fields, their chips, its column chooser and the actions on
|
|
450
487
|
its selected rows belong to the `DataTable`, on every page: the page that is only this table, a
|
|
@@ -619,8 +656,10 @@ A control stands with what it changes. Ask of each one: what does it narrow or s
|
|
|
619
656
|
|
|
620
657
|
### Tables
|
|
621
658
|
|
|
622
|
-
- Paging is built in: `paging="pages"` (default, Pagination
|
|
623
|
-
|
|
659
|
+
- Paging is built in: `paging="pages"` (default, Pagination in the footer once there is a second
|
|
660
|
+
page), `paging="infinite"` for feeds (its footer shows only while the next rows load),
|
|
661
|
+
`paging="none"` for short lists on dashboards and details. The «Показано 1–6 из 10» range is
|
|
662
|
+
`showRange`, only where the count matters to the task ([helper text is opt-in](ux.md#3-label-economy)).
|
|
624
663
|
- When the server holds more than you load (a CRM list, a register): `source="server"` — `rows` is the
|
|
625
664
|
page the server returned, `rowCount` its total; `sort` / `page` / the SmartFilter value make the
|
|
626
665
|
request, a new search or filter sets `page` to 1, and the old rows stay with `loading` until the
|
|
@@ -642,6 +681,8 @@ A control stands with what it changes. Ask of each one: what does it narrow or s
|
|
|
642
681
|
first child of a `Dnd.SortableItem` — so the on / off state reads first, like a checkbox, and the
|
|
643
682
|
grip keeps the end edge ([reorder.tsx](reference/components/list/examples/reorder.tsx)).
|
|
644
683
|
- Never a toggle between the label and the grip: «Почта … [Switch] [grip]» reads as two handles.
|
|
684
|
+
- Rows that cannot move stay in the same list with `List.Item locked` — the lock takes the grip's
|
|
685
|
+
place, so every row keeps one grid ([one kind, one list](ux.md#2-the-shape-of-the-data-decides-the-layout)).
|
|
645
686
|
|
|
646
687
|
## 9. Feedback
|
|
647
688
|
|
|
@@ -685,7 +726,8 @@ changes) instead.
|
|
|
685
726
|
A toast is no layer of that stack: `notify()` from inside a Drawer leaves it open, and a press on
|
|
686
727
|
the toast closes nothing below it. Titled groups of a dialog's body (a client's contacts, its deals)
|
|
687
728
|
are `Drawer.Section` / `Modal.Section` with their own `Drawer.Actions` / `Modal.Actions`, not a
|
|
688
|
-
hand-made heading row
|
|
729
|
+
hand-made heading row — and only where the heading names what the blocks do not
|
|
730
|
+
([label economy](ux.md#3-label-economy)); a footer's `Drawer.Meta` / `Modal.Meta` goes above the buttons by itself when
|
|
689
731
|
the footer runs short.
|
|
690
732
|
|
|
691
733
|
### A record in a drawer
|
|
@@ -716,6 +758,13 @@ wherever it opens:
|
|
|
716
758
|
the save the button leaves, so the success is a `Notification`.
|
|
717
759
|
- **Tabs are topics.** Each tab holds one topic, and a record's history (its log) is always a tab of
|
|
718
760
|
its own. Tabs that outgrow the width never merge: the strip scrolls ([switchers](responsive.md#switchers)).
|
|
761
|
+
- **A control for the whole tab stands in the header.** A switch that changes every block of the
|
|
762
|
+
open tab — the language of its texts, the period of its figures — is one control in
|
|
763
|
+
`Drawer.Actions`, before the buttons, rendered only while a tab it applies to is open
|
|
764
|
+
([tab-switcher.tsx](reference/components/drawer/examples/tab-switcher.tsx)). It is the same rule as
|
|
765
|
+
[where the filters go](#where-the-filters-go): what it changes is the tab, and the tab's place is
|
|
766
|
+
the header. A control that changes one block stays in that block. A period starts from the
|
|
767
|
+
period of the page the drawer opened from, so the drawer's figures match the row it came from.
|
|
719
768
|
- **Data at the drawer's level.** The drawer loads the record and the data of its tabs; a tab never
|
|
720
769
|
fetches on mount, so coming back to it shows what it showed instead of a skeleton that collapses
|
|
721
770
|
it. A tab that keeps a draft or its scroll keeps its panel with `Tabs.Panel keepMounted`. The
|
|
@@ -758,6 +807,45 @@ wherever it opens:
|
|
|
758
807
|
</Drawer.Content>
|
|
759
808
|
```
|
|
760
809
|
|
|
810
|
+
```tsx partial
|
|
811
|
+
// bad — the tab's language switch repeated in the heading of every section
|
|
812
|
+
<Tabs.Panel value="description">
|
|
813
|
+
<Drawer.Section label="Название">
|
|
814
|
+
<Drawer.Actions>
|
|
815
|
+
<SegmentedControl.Root aria-label="Язык" defaultValue="ru">…</SegmentedControl.Root>
|
|
816
|
+
</Drawer.Actions>
|
|
817
|
+
…
|
|
818
|
+
</Drawer.Section>
|
|
819
|
+
<Drawer.Section label="Описание">
|
|
820
|
+
<Drawer.Actions>
|
|
821
|
+
<SegmentedControl.Root aria-label="Язык" defaultValue="ru">…</SegmentedControl.Root>
|
|
822
|
+
</Drawer.Actions>
|
|
823
|
+
…
|
|
824
|
+
</Drawer.Section>
|
|
825
|
+
</Tabs.Panel>
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
```tsx good
|
|
829
|
+
// good — one switch for the open tab, in the header before ⋯, only on the tab it applies to
|
|
830
|
+
// declare: const tab: string
|
|
831
|
+
<Drawer.Header>
|
|
832
|
+
<Drawer.Title>Кресло «Орион»</Drawer.Title>
|
|
833
|
+
<Drawer.Actions>
|
|
834
|
+
{tab === "description" ? (
|
|
835
|
+
<SegmentedControl.Root aria-label="Язык текстов" defaultValue="ru">
|
|
836
|
+
<SegmentedControl.Item value="ru">RU</SegmentedControl.Item>
|
|
837
|
+
<SegmentedControl.Item value="en">EN</SegmentedControl.Item>
|
|
838
|
+
</SegmentedControl.Root>
|
|
839
|
+
) : null}
|
|
840
|
+
<Button.Root variant="ghost" tone="neutral" aria-label="Действия с моделью">
|
|
841
|
+
<Button.Icon>
|
|
842
|
+
<Icon name="action.more" />
|
|
843
|
+
</Button.Icon>
|
|
844
|
+
</Button.Root>
|
|
845
|
+
</Drawer.Actions>
|
|
846
|
+
</Drawer.Header>
|
|
847
|
+
```
|
|
848
|
+
|
|
761
849
|
## 11. Narrow screens
|
|
762
850
|
|
|
763
851
|
- Layouts are [intrinsic](responsive.md#intrinsic-grids) — no breakpoints needed, and they work in
|
|
@@ -836,7 +924,7 @@ export function RevenuePanel() {
|
|
|
836
924
|
|
|
837
925
|
For a plain KPI row use `Card.Root variant="stat-trend"` (Label · Value · Delta), each in a
|
|
838
926
|
`Page.Cell span={3}` of the page's `Page.Grid` — see [the dashboard screen](reference/components/card/examples/screen.tsx). When the trend over days matters, put a
|
|
839
|
-
`Sparkline` in the `Card.Body` instead: it brings the value
|
|
927
|
+
`Sparkline` in the `Card.Body` instead: it brings the value and a line to scrub, the change with `compareTo`.
|
|
840
928
|
|
|
841
929
|
## Screen rules
|
|
842
930
|
|
|
@@ -906,11 +994,11 @@ What each screen in [the index](#screens) demonstrates — keep these when you s
|
|
|
906
994
|
|
|
907
995
|
[card/examples/screen.tsx](reference/components/card/examples/screen.tsx)
|
|
908
996
|
|
|
909
|
-
- An overview
|
|
997
|
+
- An overview titles itself in its `Page.TopBar` like any screen of data: `Page.Title` «Обзор» with a `Page.Description` line of data (what and as of when) in `Page.Heading`, beside the page's tools and buttons; no header in the flow, the body starts with the tiles.
|
|
910
998
|
- The period is a `SegmentedControl` in the bar's `Page.Tools` and the report a `soft` + `neutral` button with an icon in its `Page.Actions`: the period changes the values on this same screen. Tabs (`Tabs`) are for different content, not for a period.
|
|
911
999
|
- Every tile of the screen is one `Page.Grid`: KPI `Card variant="stat-trend"` in `Page.Cell span={3}`, 16 px on both axes; `Card.Delta` with a `tone` by the meaning of the change: overdue growing is `danger`, its decline `success`.
|
|
912
1000
|
- Another period — other values: each KPI tile is wrapped in `Crossfade state={period}` and flows instead of blinking; a Crossfade right in a `Page.Cell` fills it, so the tiles of a row keep one height.
|
|
913
|
-
- A trend over days is a `Sparkline` in a `Card` in a full-width cell: the
|
|
1001
|
+
- A trend over days is a `Sparkline` in a `Card` in a full-width cell: the period's sum (`summary`) and a line you can scrub with a finger; a new series appears by itself.
|
|
914
1002
|
- A chart with axes and several series is a `ChartFrame` in `Page.Cell span={8} rows={2}` beside two panels; `ChartFrame.Plot height="fill"` takes their height. A sized plot area (`renderPlot`), a legend that turns series off and a table for screen readers; series colors come from `series`, never your own.
|
|
915
1003
|
- Panels are `Card variant="panel"` with `Card.Title as="h2"` in `Card.Header` and quiet context on the right after the title (`caption` + `muted`).
|
|
916
1004
|
- Progress of one value is a `ProgressBar` with `label` and `showValue`; parts of a whole are `ProgressBar segments` with `legend` and `formatValue`: statuses are colored by `tone`, categories by `color`.
|
|
@@ -146,7 +146,7 @@ A chart color does one job, and the job picks the colors:
|
|
|
146
146
|
| `title-m` | 16/24 600 | page section heading (`Page.Section` draws it), modal title |
|
|
147
147
|
| `title-l` | 18/24 600 | large block title |
|
|
148
148
|
| `heading-s` | 20/28 600 | page sub-heading |
|
|
149
|
-
| `heading-m` | 24/32 600 | the page title in the flow (`Page.Title` of a document page
|
|
149
|
+
| `heading-m` | 24/32 600 | the page title in the flow (`Page.Title` of a document page); in `Page.TopBar` the same `Page.Title` is `title-m` |
|
|
150
150
|
| `heading-l` | 30/36 600 | marketing / auth title |
|
|
151
151
|
| `display-*` | 36–60 | hero numbers only |
|
|
152
152
|
| `code` | 13/20 mono | identifiers, inline code |
|
package/dist/skill/layouts.md
CHANGED
|
@@ -112,8 +112,8 @@ export function OrdersPage() {
|
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
What stands in the bar — the path ending in the title, the tools, every button, the active filters —
|
|
115
|
-
is [the top bar](composition.md#the-top-bar);
|
|
116
|
-
|
|
115
|
+
is [the top bar](composition.md#the-top-bar); the one exception, a document page with its title in
|
|
116
|
+
the flow, is [the page skeleton](composition.md#1-page-skeleton).
|
|
117
117
|
|
|
118
118
|
With React Router the frame's `children` is `<Outlet />` and every item is `Sidebar.Item asChild`
|
|
119
119
|
around a `NavLink` ([the router example](reference/layout/sidebar/examples/router.tsx)). The same frame
|
|
@@ -152,8 +152,8 @@ shows only icons); none on the children of a sub-list.
|
|
|
152
152
|
|
|
153
153
|
## Page wrapper
|
|
154
154
|
|
|
155
|
-
- App pages (dashboard, list, detail, a board): `Page.Root` — the full width of the
|
|
156
|
-
page's title and tools are in its `Page.TopBar`, its blocks go into `Page.Body`
|
|
155
|
+
- App pages (dashboard, analytics, list, detail, a board): `Page.Root` — the full width of the
|
|
156
|
+
panel; the page's title and tools are in its `Page.TopBar`, its blocks go into `Page.Body`
|
|
157
157
|
([the page skeleton](composition.md#1-page-skeleton)).
|
|
158
158
|
- Document pages — settings and long forms: `Page.Root maxWidth="wide"` with `Page.Header` in the
|
|
159
159
|
flow (the page's h1) and a `Card.Root` with its own `Card.Header` per section
|
|
@@ -220,7 +220,7 @@ No `labels`.
|
|
|
220
220
|
| [flat.tsx](examples/flat.tsx) | A flat tile without the raised shadow next to the default one, for dense grids — `flat`. |
|
|
221
221
|
| [states.tsx](examples/states.tsx) | A KPI tile while its report loads next to the loaded one, in the `stat-trend` and `mini` templates — `loading`. |
|
|
222
222
|
| [narrow.tsx](examples/narrow.tsx) | The card is a size container: the split template stacks its cells below 22rem and the trend value shrinks below 20rem — `variant`. |
|
|
223
|
-
| [screen.tsx](examples/screen.tsx) | A dashboard: the title
|
|
223
|
+
| [screen.tsx](examples/screen.tsx) | A dashboard: the title with a line of data, the period switch and the report in the page's top bar; one grid of KPI tiles that cross-fade to the new period, a revenue trend, invoiced against paid beside two panels, and the latest payments with a link to the list — `Page.TopBar`, `Page.Grid`. |
|
|
224
224
|
|
|
225
225
|
## Mistakes
|
|
226
226
|
- A `<div>` with a border styled as a card → use `Card.Root`; depth comes from fill, not lines.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** A dashboard: the title
|
|
1
|
+
/** A dashboard: the title with a line of data, the period switch and the report in the page's top bar; one grid of KPI tiles that cross-fade to the new period, a revenue trend, invoiced against paid beside two panels, and the latest payments with a link to the list — `Page.TopBar`, `Page.Grid`. */
|
|
2
2
|
import {
|
|
3
3
|
Badge,
|
|
4
4
|
Button,
|
|
@@ -157,10 +157,14 @@ export default function CardScreenExample() {
|
|
|
157
157
|
|
|
158
158
|
return (
|
|
159
159
|
<Page.Root>
|
|
160
|
-
{/* An overview
|
|
161
|
-
|
|
162
|
-
<Page.TopBar
|
|
163
|
-
<Page.
|
|
160
|
+
{/* An overview titles itself in its bar like any work screen: the title with its line of
|
|
161
|
+
data, the period that drives the tiles, the report. */}
|
|
162
|
+
<Page.TopBar>
|
|
163
|
+
<Page.Heading>
|
|
164
|
+
<Page.Title>Обзор</Page.Title>
|
|
165
|
+
<Page.Description>Продажи и оплаты · на 8 октября, 9:40</Page.Description>
|
|
166
|
+
</Page.Heading>
|
|
167
|
+
<Page.Tools aria-label="Обзор">
|
|
164
168
|
<SegmentedControl.Root
|
|
165
169
|
aria-label="Период"
|
|
166
170
|
value={period}
|
|
@@ -180,12 +184,6 @@ export default function CardScreenExample() {
|
|
|
180
184
|
</Button.Root>
|
|
181
185
|
</Page.Actions>
|
|
182
186
|
</Page.TopBar>
|
|
183
|
-
<Page.Header>
|
|
184
|
-
<Page.Heading>
|
|
185
|
-
<Page.Title>Обзор</Page.Title>
|
|
186
|
-
<Page.Description>Продажи и оплаты · на 8 октября, 9:40</Page.Description>
|
|
187
|
-
</Page.Heading>
|
|
188
|
-
</Page.Header>
|
|
189
187
|
<Page.Body>
|
|
190
188
|
{/* One board: every tile of the screen in one grid, 16 apart on both axes. */}
|
|
191
189
|
<Page.Grid>
|
|
@@ -29,7 +29,7 @@ ChatList.Root <div> column filling its host (container `chat-lis
|
|
|
29
29
|
│ └─ Crossfade loading (placeholder List rows) ⇄ empty (EmptyPage compact) ⇄ the list
|
|
30
30
|
│ └─ List.Root <ul> aria-label «Диалоги»; spacer <li aria-hidden> stand for rows out of view
|
|
31
31
|
│ └─ ChatList.Item List.Item <li> + <button> | <a href> | your element (asChild); current from value; one Tab stop
|
|
32
|
-
│ ├─ ChatList.ItemIcon before the name: avatar slot (aria-hidden); after it: a glyph
|
|
32
|
+
│ ├─ ChatList.ItemIcon before the name: avatar slot (aria-hidden); after it: a glyph (role="img" with aria-label)
|
|
33
33
|
│ ├─ ChatList.ItemText the name; muted glyph after it
|
|
34
34
|
│ ├─ ChatList.ItemDescription author · media word · text — cross-fades with draft and «печатает…»
|
|
35
35
|
│ ├─ (meta) delivery ticks · time
|
|
@@ -89,12 +89,12 @@ ChatList.Root <div> column filling its host (container `chat-lis
|
|
|
89
89
|
| `…rest` | `ButtonHTMLAttributes<HTMLButtonElement>` | — | `className` and the native attributes of the row element. |
|
|
90
90
|
|
|
91
91
|
### ChatList.ItemIcon
|
|
92
|
-
`ref` → `HTMLSpanElement`. Before the name: the avatar slot (`aria-hidden`), an `Avatar.Root` sized by the row. After the name: a glyph beside it (verified, bot,
|
|
92
|
+
`ref` → `HTMLSpanElement`. Before the name: the avatar slot (`aria-hidden`), an `Avatar.Root` sized by the row. After the name: a glyph beside it (verified, bot, channel type), any kit icon sized by the row; with `aria-label` it is `role="img"` of that name.
|
|
93
93
|
|
|
94
94
|
| Prop | Type | Default | Description |
|
|
95
95
|
|---|---|---|---|
|
|
96
|
-
| `children` | `ReactNode` | — (required) | An `Avatar.Root` (with `Avatar.Status`), or after the name an
|
|
97
|
-
| `…rest` | `Omit<HTMLAttributes<HTMLSpanElement>, "children">` | — | `className` and the other `span` attributes. |
|
|
96
|
+
| `children` | `ReactNode` | — (required) | An `Avatar.Root` (with `Avatar.Status`), or after the name an icon: `<Icon name>` or a glyph of `prime-ui-kit/icons` (`<SendIcon />`), as is. |
|
|
97
|
+
| `…rest` | `Omit<HTMLAttributes<HTMLSpanElement>, "children">` | — | `className`, `aria-label` (names a glyph after the name: its channel, «Официальный аккаунт») and the other `span` attributes. |
|
|
98
98
|
|
|
99
99
|
### ChatList.ItemText
|
|
100
100
|
`ref` → `HTMLSpanElement`. The name of the dialog: one line, truncated, the glyphs after it kept whole; the search query is marked.
|
|
@@ -200,7 +200,7 @@ Root attribute: `data-size`. Every motion honours reduced motion (durations coll
|
|
|
200
200
|
|
|
201
201
|
- The list is a `<ul>` named «Диалоги» (`labels.list`); each row an `<li>` with a button, a link with `href`, or your link with `asChild`.
|
|
202
202
|
- The open dialog is `aria-current="true"` on a button, `"page"` on a link. Selection does not follow the focus: arrows only move it (a dialog may load a conversation); Enter, Space and a click open.
|
|
203
|
-
- The row is named by its content: the name, glyphs
|
|
203
|
+
- The row is named by its content: the name, the glyphs (`ChatList.ItemIcon` `aria-label`, «Без звука»), the preview, the delivery mark («Прочитано»), the time, then «упоминание» and «непрочитанных: 3» instead of the bare badges; the avatar is `aria-hidden`.
|
|
204
204
|
- While the other side types, the preview is `aria-hidden` and «печатает…» is read; a draft reads «Черновик: …».
|
|
205
205
|
- A row with a menu has `aria-keyshortcuts="Shift+F10"`; the menu is a `Dropdown` (`menu` / `menuitem`).
|
|
206
206
|
- The search field is `type="search"` named «Поиск по диалогам»; after a search a polite status says «Найдено: 4» or «Ничего не найдено».
|
|
@@ -257,6 +257,7 @@ Root attribute: `data-size`. Every motion honours reduced motion (durations coll
|
|
|
257
257
|
- Filtering inside `renderItem` (returning `null`) → filter `items`: the list counts, announces and glides by `items`.
|
|
258
258
|
- Pinned dialogs mixed into the time order → put them first in `items`; `pinned` only draws the pin.
|
|
259
259
|
- `onValueChange` used to mark a dialog read on focus → arrows only move the focus; mark read when the conversation shows it (`Chat.Messages onRead`) or on open.
|
|
260
|
+
- A glyph after the name cloned with `label` and `size` → put the icon in `ChatList.ItemIcon` as is and name the part with `aria-label`: the row sizes it.
|
|
260
261
|
- An `Avatar.Root size="s"` to fit the row → leave `size` out; the slot sizes the avatar to the tier.
|
|
261
262
|
- A «⋯» button nested inside the row for the menu → `ChatList.ItemMenu`: it opens on right click, a long press and Shift+F10.
|
|
262
263
|
- Deleting from the menu without a question → open a `ConfirmDialog` from the menu item.
|
|
@@ -111,13 +111,13 @@ export default function ChatListStructureExample() {
|
|
|
111
111
|
</ChatList.ItemIcon>
|
|
112
112
|
<ChatList.ItemText>{item.name}</ChatList.ItemText>
|
|
113
113
|
{item.verified ? (
|
|
114
|
-
<ChatList.ItemIcon>
|
|
115
|
-
<Icon name="status.success" tone="accent"
|
|
114
|
+
<ChatList.ItemIcon aria-label="Официальный аккаунт">
|
|
115
|
+
<Icon name="status.success" tone="accent" />
|
|
116
116
|
</ChatList.ItemIcon>
|
|
117
117
|
) : null}
|
|
118
118
|
{item.group ? (
|
|
119
|
-
<ChatList.ItemIcon>
|
|
120
|
-
<Icon name="object.users"
|
|
119
|
+
<ChatList.ItemIcon aria-label="Группа">
|
|
120
|
+
<Icon name="object.users" />
|
|
121
121
|
</ChatList.ItemIcon>
|
|
122
122
|
) : null}
|
|
123
123
|
<ChatList.ItemDescription
|
|
@@ -136,7 +136,7 @@ CommandMenu.Root Modal + top-aligned palette panel, query and lo
|
|
|
136
136
|
| `…rest` | `HTMLAttributes<HTMLSpanElement>` | — | `children` (the title), `className` and the other span attributes. |
|
|
137
137
|
|
|
138
138
|
### CommandMenu.Empty
|
|
139
|
-
`ref` → `HTMLDivElement`. A compact EmptyPage (`role="status"`) shown while nothing matches and nothing loads: `labels.empty
|
|
139
|
+
`ref` → `HTMLDivElement`. A compact EmptyPage (`role="status"`) shown while nothing matches and nothing loads: `labels.empty`, text only. An action for the query is a `persistent` `CommandMenu.Item` at the end of the list.
|
|
140
140
|
|
|
141
141
|
| Prop | Type | Default | Description |
|
|
142
142
|
|---|---|---|---|
|
|
@@ -236,7 +236,6 @@ One look: the floating layer of the ladder (it is a Modal), `--prime-modal-radiu
|
|
|
236
236
|
|---|---|---|
|
|
237
237
|
| `search` | `"Поиск"` | Default placeholder and accessible name of `CommandMenu.Input`. |
|
|
238
238
|
| `empty` | `"Ничего не найдено"` | `CommandMenu.Empty`: nothing matches the query. |
|
|
239
|
-
| `emptyHint` | `"Попробуйте изменить запрос"` | Second line of `CommandMenu.Empty`; `""` hides it. |
|
|
240
239
|
| `loading` | `"Загрузка…"` | Announced while `loading` or `loadingMore`. |
|
|
241
240
|
| `retry` | `"Повторить"` | The retry button under `loadError` (`onRetry`). |
|
|
242
241
|
|
|
@@ -46,7 +46,7 @@ export default function CommandMenuStatesExample() {
|
|
|
46
46
|
onSearchChange={setSearch}
|
|
47
47
|
loading={state === "loading"}
|
|
48
48
|
aria-label="Выбор склада"
|
|
49
|
-
labels={{ empty: "
|
|
49
|
+
labels={{ empty: "В этом городе склада пока нет" }}
|
|
50
50
|
>
|
|
51
51
|
<CommandMenu.Input placeholder="Город склада" />
|
|
52
52
|
<CommandMenu.List>
|
|
@@ -109,7 +109,7 @@ In an optimistic chat the send returns at once: add the message to the list with
|
|
|
109
109
|
| `defaultRecordMode` | `"voice" \| "video"` | `"voice"` | Initial record mode, uncontrolled. |
|
|
110
110
|
| `onRecordModeChange` | `(mode: "voice" \| "video") => void` | — | A double click / double tap on the record button (or ↑ / ↓ on it) switched voice and video. |
|
|
111
111
|
| `queue` | `Pick<UploadQueue, "items" \| "add" \| "retry" \| "remove" \| "clear" \| "move">` | — | Attachments, usually `useUploadQueue(…)`: the paperclip, a paste and a drop add to it, and a tray above the row shows them as one reorderable strip of tiles. Without `queue` paste and drop of files do nothing. |
|
|
112
|
-
| `formatting` | `boolean` | `true` | Selecting text shows a floating toolbar of
|
|
112
|
+
| `formatting` | `boolean` | `true` | Selecting text shows a floating toolbar of eight Markdown tools and enables their hotkeys; a tool wraps the selection, a second press unwraps it. `false` turns both off. |
|
|
113
113
|
| `size` | `"xs" \| "s" \| "m" \| "l" \| "xl"` | host tier, else `"m"` | Tier of the field, the buttons and the bar text. Without it the tier of its host, else `m`. |
|
|
114
114
|
| `disabled` | `boolean` | `false` | A closed conversation: the field, the paperclip and the button are disabled; nothing is pasted or dropped. A disabled `Fieldset` around it sets it too (`data-disabled` included). |
|
|
115
115
|
| `inputRef` | `Ref<HTMLTextAreaElement>` | — | The message `<textarea>`: focus it after «Ответить» in a message menu. |
|
|
@@ -197,7 +197,7 @@ Composer has no `variant`; what the row shows follows its state.
|
|
|
197
197
|
### Flags
|
|
198
198
|
| Value | Looks like | Use when | Default |
|
|
199
199
|
|---|---|---|---|
|
|
200
|
-
| `formatting` | a floating toolbar over a selection (bold, italic, strikethrough, code, spoiler, link, quote); Mod-hotkeys | always, unless the chat shows plain text only | `true` |
|
|
200
|
+
| `formatting` | a floating toolbar over a selection (bold, italic, underline, strikethrough, code, spoiler, link, quote); Mod-hotkeys | always, unless the chat shows plain text only | `true` |
|
|
201
201
|
| `disabled` | the field, paperclip and button disabled | a closed conversation, no permission to write | `false` |
|
|
202
202
|
| `queue` | the tray above the field: one strip of tiles — photos, videos and files; paste and drop take files | the chat accepts files | — |
|
|
203
203
|
| `onSendVoice` / `onSendVideoNote` | an empty field offers the record button | the chat takes voice / video messages | — |
|
|
@@ -250,7 +250,7 @@ Motion: the tray opens and closes as a Crossfade (fade and height glide, the row
|
|
|
250
250
|
| `Mod + Enter` | Always sends, on a touch screen too. |
|
|
251
251
|
| `↑` | In an empty field opens your last message for editing (`onEditLast`). |
|
|
252
252
|
| `Escape` | Clears a selection with the toolbar, then cancels the reply or edit; while recording throws the recording away and stops there, so an enclosing Modal or Drawer stays open. |
|
|
253
|
-
| `Mod + B` · `Mod + I` · `Mod + Shift + X` · `Mod + E` · `Mod + Shift + H` · `Mod + K` · `Mod + Shift + 9` | Bold, italic, strikethrough, code, spoiler, link and quote for the selection; the physical key counts, so any layout works. |
|
|
253
|
+
| `Mod + B` · `Mod + I` · `Mod + U` · `Mod + Shift + X` · `Mod + E` · `Mod + Shift + H` · `Mod + K` · `Mod + Shift + 9` | Bold, italic, underline, strikethrough, code, spoiler, link and quote for the selection; the physical key counts, so any layout works. |
|
|
254
254
|
| `Enter` · `Space` | On the record button: record hands-free at once. During a hands-free recording, wherever the focus is in the composer: Enter sends the recording (a paused one too), Space pauses and resumes it — the timer and the waveform stand, the dot turns into a pause glyph. |
|
|
255
255
|
| `↑` · `↓` | On the record button, with voice and video both offered: switches voice and video (`aria-keyshortcuts`, named in the button's description). |
|
|
256
256
|
| `←` · `→` | Move between the formatting buttons. |
|
|
@@ -310,6 +310,7 @@ Motion: the tray opens and closes as a Crossfade (fade and height glide, the row
|
|
|
310
310
|
| `formatting` | `"Форматирование"` | Accessible name of the formatting toolbar. |
|
|
311
311
|
| `bold` | `"Жирный"` | Bold tool. |
|
|
312
312
|
| `italic` | `"Курсив"` | Italic tool. |
|
|
313
|
+
| `underline` | `"Подчёркнутый"` | Underline tool (`__…__`). |
|
|
313
314
|
| `strikethrough` | `"Зачёркнутый"` | Strikethrough tool. |
|
|
314
315
|
| `code` | `"Моноширинный"` | Code tool. |
|
|
315
316
|
| `spoiler` | `"Скрытый текст"` | Spoiler tool (`\|\|…\|\|`). |
|
|
@@ -333,7 +334,7 @@ Motion: the tray opens and closes as a Crossfade (fade and height glide, the row
|
|
|
333
334
|
| [attach-menu.tsx](examples/attach-menu.tsx) | The paperclip as a menu of attachment kinds: photos and videos, documents, any file, and an invoice from the system that puts its link into the message and returns the focus to the field — `Composer.Item`, `Composer.ItemIcon`, `accept`, `onSelect`, `inputRef`. |
|
|
334
335
|
| [reply-edit.tsx](examples/reply-edit.tsx) | Answering a client's message and correcting your own: the bar above the field quotes the message, Escape or the cross cancels, ↑ in an empty field opens your last message, send becomes save and hands over the message id — `Composer.Context`, `mode`, `messageId`, `onDismiss`, `onEditLast`. |
|
|
335
336
|
| [typing.tsx](examples/typing.tsx) | The other side's status line follows what you do: typing, recording a voice or a video message, then nothing — `onActivityChange`. |
|
|
336
|
-
| [formatting.tsx](examples/formatting.tsx) | Selected text gets a toolbar of bold, italic, strikethrough, code, spoiler, link and quote, each with its shortcut, written as Markdown around the selection — `formatting`. |
|
|
337
|
+
| [formatting.tsx](examples/formatting.tsx) | Selected text gets a toolbar of bold, italic, underline, strikethrough, code, spoiler, link and quote, each with its shortcut, written as Markdown around the selection — `formatting`. |
|
|
337
338
|
| [voice.tsx](examples/voice.tsx) | Voice and round video messages: hold the button to record and release to send, slide left to cancel, slide up or tap to record hands-free; a double tap or double click switches voice and video — `onSendVoice`, `onSendVideoNote`, `recordMode`. |
|
|
338
339
|
| [bot-keyboard.tsx](examples/bot-keyboard.tsx) | A bot's reply keyboard under the field: a key sends its text as a message, the field asks for a key, the keyboard hides after use and the toggle brings it back — `Composer.Keyboard`, `rows`, `placeholder`, `oneTime`. |
|
|
339
340
|
| [states.tsx](examples/states.tsx) | A closed conversation is disabled, a slow send keeps the text with a busy button until the server answers — `disabled`, `onSend`. |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Selected text gets a toolbar of bold, italic, strikethrough, code, spoiler, link and quote, each with its shortcut, written as Markdown around the selection — `formatting`. */
|
|
1
|
+
/** Selected text gets a toolbar of bold, italic, underline, strikethrough, code, spoiler, link and quote, each with its shortcut, written as Markdown around the selection — `formatting`. */
|
|
2
2
|
import { Composer } from "prime-ui-kit";
|
|
3
3
|
|
|
4
4
|
import styles from "./examples.module.css";
|