prime-ui-kit 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/chunks/{chunk-PRP4B6OG.js → chunk-IVS3J7AS.js} +1 -1
- package/dist/chunks/{chunk-2ODXLPW3.js → chunk-QFHE5GKW.js} +1 -0
- package/dist/chunks/{chunk-7WWZYGRC.js → chunk-RZNGLELR.js} +4497 -3896
- package/dist/chunks/{chunk-A4WE3UNC.js → chunk-WYCTXD63.js} +18399 -17624
- package/dist/chunks/{chunk-SVFWPLNW.js → chunk-ZTZ2ML2B.js} +14 -3
- package/dist/color-picker.js +3 -3
- package/dist/components/badge/Badge.d.ts +17 -0
- package/dist/components/breadcrumb/Breadcrumb.d.ts +11 -2
- package/dist/components/button/Button.d.ts +1 -1
- package/dist/components/button-group/ButtonGroup.d.ts +1 -1
- package/dist/components/card/Card.d.ts +8 -4
- package/dist/components/chat/Chat.d.ts +3 -3
- package/dist/components/chat/MessageList.d.ts +5 -1
- package/dist/components/chat/groupMessages.d.ts +12 -4
- package/dist/components/chat-list/ChatList.d.ts +18 -9
- package/dist/components/chat-list/formatChatTime.d.ts +3 -3
- package/dist/components/checkbox/Checkbox.d.ts +6 -1
- package/dist/components/color-field/ColorField.d.ts +1 -1
- package/dist/components/color-picker/ColorPicker.d.ts +6 -1
- package/dist/components/color-picker/ColorPresets.d.ts +9 -1
- package/dist/components/crossfade/Crossfade.d.ts +1 -1
- package/dist/components/data-table/ColumnsMenu.d.ts +16 -20
- package/dist/components/data-table/DataTable.d.ts +16 -11
- package/dist/components/data-table/Head.d.ts +10 -1
- package/dist/components/data-table/Row.d.ts +7 -1
- package/dist/components/data-table/StateRows.d.ts +3 -1
- package/dist/components/data-table/types.d.ts +5 -0
- package/dist/components/digit-input/DigitInput.d.ts +1 -1
- package/dist/components/drawer/Drawer.d.ts +3 -2
- package/dist/components/field-list/FieldList.d.ts +24 -12
- package/dist/components/hint/Hint.d.ts +8 -2
- package/dist/components/index.d.ts +7 -4
- package/dist/components/input/Input.d.ts +27 -5
- package/dist/components/input/inputSuggestions.d.ts +39 -0
- package/dist/components/kanban/Kanban.d.ts +8 -9
- package/dist/components/list/List.d.ts +25 -6
- package/dist/components/message/Message.d.ts +15 -3
- package/dist/components/message/MessageSticker.d.ts +27 -0
- package/dist/components/message/formatMessageTime.d.ts +5 -2
- package/dist/components/modal/Modal.d.ts +3 -2
- package/dist/components/native-select/NativeSelect.d.ts +1 -1
- package/dist/components/radio/Radio.d.ts +11 -2
- package/dist/components/rich-text/RichText.d.ts +23 -0
- package/dist/components/scroll-container/ScrollContainer.d.ts +1 -1
- package/dist/components/scroll-container/scrollGlide.d.ts +26 -0
- package/dist/components/scroll-container/useScrollMotion.d.ts +25 -0
- package/dist/components/segmented-control/SegmentedControl.d.ts +1 -1
- package/dist/components/select/selectContext.d.ts +7 -0
- package/dist/components/slider/Slider.d.ts +1 -1
- package/dist/components/switch/Switch.d.ts +6 -1
- package/dist/components/tag-select/TagSelect.d.ts +1 -1
- package/dist/components/textarea/Textarea.d.ts +6 -1
- package/dist/components/timeline/Timeline.d.ts +1 -1
- package/dist/icon-set.js +2 -2
- package/dist/index.css +1 -1
- package/dist/index.js +5 -3
- package/dist/internal/ChoiceField.d.ts +3 -1
- package/dist/internal/FieldFrame.d.ts +8 -2
- package/dist/internal/fieldCell.d.ts +7 -1
- package/dist/internal/formatClock.d.ts +23 -2
- package/dist/internal/leaveGuard.d.ts +27 -0
- package/dist/internal/messageList.d.ts +2 -0
- package/dist/internal/overlay/DialogGuard.d.ts +3 -2
- package/dist/internal/overlay/DialogParts.d.ts +40 -6
- package/dist/internal/swatch.d.ts +5 -0
- package/dist/internal/tokenDefaults.d.ts +1 -0
- package/dist/layout/index.d.ts +1 -1
- package/dist/layout/page/Page.d.ts +48 -15
- package/dist/skill/anti-slop.md +28 -0
- package/dist/skill/api-contract.md +14 -7
- package/dist/skill/cheatsheet.md +28 -9
- package/dist/skill/checklist.md +9 -0
- package/dist/skill/choosing.md +25 -12
- package/dist/skill/components.md +1 -0
- package/dist/skill/composition.md +88 -16
- package/dist/skill/layouts.md +6 -4
- package/dist/skill/reference/components/badge/COMPONENT.md +14 -1
- package/dist/skill/reference/components/badge/examples/examples.module.css +7 -0
- package/dist/skill/reference/components/badge/examples/tag-row.tsx +34 -0
- package/dist/skill/reference/components/breadcrumb/COMPONENT.md +9 -4
- package/dist/skill/reference/components/breadcrumb/examples/router.tsx +17 -0
- package/dist/skill/reference/components/button/COMPONENT.md +1 -1
- package/dist/skill/reference/components/button-group/COMPONENT.md +1 -0
- package/dist/skill/reference/components/card/COMPONENT.md +7 -1
- package/dist/skill/reference/components/card/examples/states.tsx +59 -0
- package/dist/skill/reference/components/chat/COMPONENT.md +4 -1
- package/dist/skill/reference/components/chat/examples/time-zone.tsx +83 -0
- package/dist/skill/reference/components/chat-list/COMPONENT.md +12 -6
- package/dist/skill/reference/components/chat-list/examples/links.tsx +1 -1
- package/dist/skill/reference/components/chat-list/examples/router.tsx +63 -0
- package/dist/skill/reference/components/checkbox/COMPONENT.md +1 -0
- package/dist/skill/reference/components/color-field/COMPONENT.md +2 -1
- package/dist/skill/reference/components/color-picker/COMPONENT.md +14 -5
- package/dist/skill/reference/components/color-picker/examples/presets-custom.tsx +31 -0
- package/dist/skill/reference/components/color-swatches/COMPONENT.md +1 -0
- package/dist/skill/reference/components/confirm-dialog/COMPONENT.md +1 -1
- package/dist/skill/reference/components/crossfade/COMPONENT.md +1 -1
- package/dist/skill/reference/components/data-table/COMPONENT.md +46 -41
- package/dist/skill/reference/components/data-table/examples/actions-column.tsx +154 -0
- package/dist/skill/reference/components/data-table/examples/columns-visibility.tsx +3 -12
- package/dist/skill/reference/components/data-table/examples/controlled.tsx +1 -1
- package/dist/skill/reference/components/data-table/examples/narrow.tsx +4 -11
- package/dist/skill/reference/components/data-table/examples/numeric.tsx +9 -2
- package/dist/skill/reference/components/data-table/examples/row-link.tsx +18 -22
- package/dist/skill/reference/components/data-table/examples/screen.tsx +12 -1
- package/dist/skill/reference/components/data-table/examples/toolbar.tsx +26 -32
- package/dist/skill/reference/components/datepicker/COMPONENT.md +3 -1
- package/dist/skill/reference/components/datepicker/examples/deadline.tsx +33 -0
- package/dist/skill/reference/components/digit-input/COMPONENT.md +1 -0
- package/dist/skill/reference/components/dnd/COMPONENT.md +4 -3
- package/dist/skill/reference/components/dnd/examples/examples.module.css +4 -3
- package/dist/skill/reference/components/dnd/examples/handle.tsx +5 -5
- package/dist/skill/reference/components/dnd/examples/locked.tsx +1 -1
- package/dist/skill/reference/components/dnd/examples/table.tsx +6 -6
- package/dist/skill/reference/components/drawer/COMPONENT.md +38 -9
- package/dist/skill/reference/components/drawer/examples/client-card.tsx +32 -8
- package/dist/skill/reference/components/drawer/examples/header-actions.tsx +1 -1
- package/dist/skill/reference/components/drawer/examples/loading.tsx +58 -0
- package/dist/skill/reference/components/field-list/COMPONENT.md +40 -24
- package/dist/skill/reference/components/field-list/examples/base-row.tsx +2 -1
- package/dist/skill/reference/components/field-list/examples/locked.tsx +11 -11
- package/dist/skill/reference/components/field-list/examples/reorder.tsx +1 -1
- package/dist/skill/reference/components/field-list/examples/saving.tsx +83 -0
- package/dist/skill/reference/components/field-list/examples/screen.module.css +1 -1
- package/dist/skill/reference/components/field-list/examples/screen.tsx +168 -162
- package/dist/skill/reference/components/field-list/examples/totals.tsx +83 -0
- package/dist/skill/reference/components/file-upload/COMPONENT.md +1 -0
- package/dist/skill/reference/components/hint/COMPONENT.md +16 -2
- package/dist/skill/reference/components/hint/examples/variants.tsx +48 -0
- package/dist/skill/reference/components/input/COMPONENT.md +39 -9
- package/dist/skill/reference/components/input/examples/affixes.tsx +4 -2
- package/dist/skill/reference/components/input/examples/dismiss.tsx +29 -0
- package/dist/skill/reference/components/input/examples/suggestions.tsx +26 -0
- package/dist/skill/reference/components/input/examples/time.tsx +24 -0
- package/dist/skill/reference/components/input/examples/with-select.tsx +44 -0
- package/dist/skill/reference/components/kanban/COMPONENT.md +12 -8
- package/dist/skill/reference/components/kanban/examples/columns.tsx +4 -2
- package/dist/skill/reference/components/kanban/examples/states.tsx +7 -5
- package/dist/skill/reference/components/list/COMPONENT.md +39 -13
- package/dist/skill/reference/components/list/examples/reorder.tsx +42 -7
- package/dist/skill/reference/components/list/examples/row-controls.tsx +80 -0
- package/dist/skill/reference/components/list/examples/with-icon.tsx +23 -2
- package/dist/skill/reference/components/login-form/COMPONENT.md +8 -7
- package/dist/skill/reference/components/login-form/examples/states.tsx +12 -14
- package/dist/skill/reference/components/message/COMPONENT.md +30 -9
- package/dist/skill/reference/components/message/examples/preview.tsx +28 -0
- package/dist/skill/reference/components/message/examples/sticker.tsx +35 -0
- package/dist/skill/reference/components/modal/COMPONENT.md +35 -10
- package/dist/skill/reference/components/modal/examples/long-content.tsx +37 -18
- package/dist/skill/reference/components/native-select/COMPONENT.md +1 -0
- package/dist/skill/reference/components/notification/COMPONENT.md +1 -1
- package/dist/skill/reference/components/radio/COMPONENT.md +2 -0
- package/dist/skill/reference/components/rich-text/COMPONENT.md +93 -0
- package/dist/skill/reference/components/rich-text/examples/overview.tsx +19 -0
- package/dist/skill/reference/components/scroll-container/COMPONENT.md +8 -5
- package/dist/skill/reference/components/segmented-control/COMPONENT.md +4 -2
- package/dist/skill/reference/components/segmented-control/examples/in-form.tsx +1 -1
- package/dist/skill/reference/components/select/COMPONENT.md +7 -3
- package/dist/skill/reference/components/sheet/COMPONENT.md +18 -7
- package/dist/skill/reference/components/slider/COMPONENT.md +1 -0
- package/dist/skill/reference/components/slider/examples/controlled.tsx +1 -1
- package/dist/skill/reference/components/switch/COMPONENT.md +1 -0
- package/dist/skill/reference/components/tag-select/COMPONENT.md +1 -0
- package/dist/skill/reference/components/textarea/COMPONENT.md +1 -0
- package/dist/skill/reference/components/timeline/COMPONENT.md +3 -3
- package/dist/skill/reference/components/timeline/examples/structure.tsx +2 -1
- package/dist/skill/reference/layout/app-shell/COMPONENT.md +2 -2
- package/dist/skill/reference/layout/bottom-nav/COMPONENT.md +1 -0
- package/dist/skill/reference/layout/page/COMPONENT.md +42 -20
- package/dist/skill/reference/layout/page/examples/examples.module.css +7 -0
- package/dist/skill/reference/layout/page/examples/guard.tsx +87 -0
- package/dist/skill/reference/layout/page/examples/loading.tsx +57 -0
- package/dist/skill/reference/layout/page/examples/screen.module.css +1 -1
- package/dist/skill/reference/layout/page/examples/screen.tsx +93 -104
- package/dist/skill/reference/layout/page/examples/sections.tsx +2 -15
- package/dist/skill/reference/layout/sidebar/COMPONENT.md +1 -0
- package/dist/skill/responsive.md +19 -12
- package/dist/skill/ux.md +5 -3
- package/dist/tokens/semantic.d.ts +3 -1
- package/dist/tokens/themes/dark.d.ts +1 -1
- package/package.json +2 -2
- package/src/components/badge/COMPONENT.md +14 -1
- package/src/components/badge/examples/examples.module.css +7 -0
- package/src/components/badge/examples/tag-row.tsx +34 -0
- package/src/components/breadcrumb/COMPONENT.md +9 -4
- package/src/components/breadcrumb/examples/router.tsx +17 -0
- package/src/components/button/COMPONENT.md +1 -1
- package/src/components/button-group/COMPONENT.md +1 -0
- package/src/components/card/COMPONENT.md +7 -1
- package/src/components/card/examples/states.tsx +59 -0
- package/src/components/chat/COMPONENT.md +4 -1
- package/src/components/chat/examples/time-zone.tsx +83 -0
- package/src/components/chat-list/COMPONENT.md +12 -6
- package/src/components/chat-list/examples/links.tsx +1 -1
- package/src/components/chat-list/examples/router.tsx +63 -0
- package/src/components/checkbox/COMPONENT.md +1 -0
- package/src/components/color-field/COMPONENT.md +2 -1
- package/src/components/color-picker/COMPONENT.md +14 -5
- package/src/components/color-picker/examples/presets-custom.tsx +31 -0
- package/src/components/color-swatches/COMPONENT.md +1 -0
- package/src/components/confirm-dialog/COMPONENT.md +1 -1
- package/src/components/crossfade/COMPONENT.md +1 -1
- package/src/components/data-table/COMPONENT.md +46 -41
- package/src/components/data-table/examples/actions-column.tsx +154 -0
- package/src/components/data-table/examples/columns-visibility.tsx +3 -12
- package/src/components/data-table/examples/controlled.tsx +1 -1
- package/src/components/data-table/examples/narrow.tsx +4 -11
- package/src/components/data-table/examples/numeric.tsx +9 -2
- package/src/components/data-table/examples/row-link.tsx +18 -22
- package/src/components/data-table/examples/screen.tsx +12 -1
- package/src/components/data-table/examples/toolbar.tsx +26 -32
- package/src/components/datepicker/COMPONENT.md +3 -1
- package/src/components/datepicker/examples/deadline.tsx +33 -0
- package/src/components/digit-input/COMPONENT.md +1 -0
- package/src/components/dnd/COMPONENT.md +4 -3
- package/src/components/dnd/examples/examples.module.css +4 -3
- package/src/components/dnd/examples/handle.tsx +5 -5
- package/src/components/dnd/examples/locked.tsx +1 -1
- package/src/components/dnd/examples/table.tsx +6 -6
- package/src/components/drawer/COMPONENT.md +38 -9
- package/src/components/drawer/examples/client-card.tsx +32 -8
- package/src/components/drawer/examples/header-actions.tsx +1 -1
- package/src/components/drawer/examples/loading.tsx +58 -0
- package/src/components/field-list/COMPONENT.md +40 -24
- package/src/components/field-list/examples/base-row.tsx +2 -1
- package/src/components/field-list/examples/locked.tsx +11 -11
- package/src/components/field-list/examples/reorder.tsx +1 -1
- package/src/components/field-list/examples/saving.tsx +83 -0
- package/src/components/field-list/examples/screen.module.css +1 -1
- package/src/components/field-list/examples/screen.tsx +168 -162
- package/src/components/field-list/examples/totals.tsx +83 -0
- package/src/components/file-upload/COMPONENT.md +1 -0
- package/src/components/hint/COMPONENT.md +16 -2
- package/src/components/hint/examples/variants.tsx +48 -0
- package/src/components/input/COMPONENT.md +39 -9
- package/src/components/input/examples/affixes.tsx +4 -2
- package/src/components/input/examples/dismiss.tsx +29 -0
- package/src/components/input/examples/suggestions.tsx +26 -0
- package/src/components/input/examples/time.tsx +24 -0
- package/src/components/input/examples/with-select.tsx +44 -0
- package/src/components/kanban/COMPONENT.md +12 -8
- package/src/components/kanban/examples/columns.tsx +4 -2
- package/src/components/kanban/examples/states.tsx +7 -5
- package/src/components/list/COMPONENT.md +39 -13
- package/src/components/list/examples/reorder.tsx +42 -7
- package/src/components/list/examples/row-controls.tsx +80 -0
- package/src/components/list/examples/with-icon.tsx +23 -2
- package/src/components/login-form/COMPONENT.md +8 -7
- package/src/components/login-form/examples/states.tsx +12 -14
- package/src/components/message/COMPONENT.md +30 -9
- package/src/components/message/examples/preview.tsx +28 -0
- package/src/components/message/examples/sticker.tsx +35 -0
- package/src/components/modal/COMPONENT.md +35 -10
- package/src/components/modal/examples/long-content.tsx +37 -18
- package/src/components/native-select/COMPONENT.md +1 -0
- package/src/components/notification/COMPONENT.md +1 -1
- package/src/components/radio/COMPONENT.md +2 -0
- package/src/components/rich-text/COMPONENT.md +93 -0
- package/src/components/rich-text/examples/overview.tsx +19 -0
- package/src/components/scroll-container/COMPONENT.md +8 -5
- package/src/components/segmented-control/COMPONENT.md +4 -2
- package/src/components/segmented-control/examples/in-form.tsx +1 -1
- package/src/components/select/COMPONENT.md +7 -3
- package/src/components/sheet/COMPONENT.md +18 -7
- package/src/components/slider/COMPONENT.md +1 -0
- package/src/components/slider/examples/controlled.tsx +1 -1
- package/src/components/switch/COMPONENT.md +1 -0
- package/src/components/tag-select/COMPONENT.md +1 -0
- package/src/components/textarea/COMPONENT.md +1 -0
- package/src/components/timeline/COMPONENT.md +3 -3
- package/src/components/timeline/examples/structure.tsx +2 -1
- package/src/layout/app-shell/COMPONENT.md +2 -2
- package/src/layout/bottom-nav/COMPONENT.md +1 -0
- package/src/layout/page/COMPONENT.md +42 -20
- package/src/layout/page/examples/examples.module.css +7 -0
- package/src/layout/page/examples/guard.tsx +87 -0
- package/src/layout/page/examples/loading.tsx +57 -0
- package/src/layout/page/examples/screen.module.css +1 -1
- package/src/layout/page/examples/screen.tsx +93 -104
- package/src/layout/page/examples/sections.tsx +2 -15
- package/src/layout/sidebar/COMPONENT.md +1 -0
- package/src/styles/theme-dark.css +1 -1
- package/src/styles/theme-light.css +2 -1
- package/dist/components/data-table/context.d.ts +0 -14
- package/dist/components/scroll-container/useWheelToInline.d.ts +0 -10
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** A settings page as a document: the path in the top bar that repeats the title once it scrolls away, the large title in the flow,
|
|
1
|
+
/** A settings page as a document: the path in the top bar that repeats the title once it scrolls away, the large title in the flow, each section a card with its own heading, a form saved by its own button, switches that apply at once and a danger zone with a confirm — `collapse`, `maxWidth`, `Card.Header`. */
|
|
2
2
|
import {
|
|
3
3
|
Breadcrumb,
|
|
4
4
|
Button,
|
|
@@ -88,118 +88,107 @@ export default function PageScreenExample() {
|
|
|
88
88
|
</Page.Heading>
|
|
89
89
|
</Page.Header>
|
|
90
90
|
<Page.Body>
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
<Card.
|
|
98
|
-
<
|
|
99
|
-
<
|
|
100
|
-
<Input.
|
|
91
|
+
<form noValidate onSubmit={save} onReset={() => setInnError(undefined)}>
|
|
92
|
+
<Card.Root variant="panel">
|
|
93
|
+
<Card.Header>
|
|
94
|
+
<Card.Title as="h2">Компания</Card.Title>
|
|
95
|
+
<Card.Description>Попадают в счета, акты и письма клиентам.</Card.Description>
|
|
96
|
+
</Card.Header>
|
|
97
|
+
<Card.Body>
|
|
98
|
+
<Fieldset disabled={saving}>
|
|
99
|
+
<Input.Root label="Название">
|
|
100
|
+
<Input.Wrapper>
|
|
101
|
+
<Input.Field name="name" defaultValue="ООО «Прайм Софт»" />
|
|
102
|
+
</Input.Wrapper>
|
|
103
|
+
</Input.Root>
|
|
104
|
+
<div className={styles.pair}>
|
|
105
|
+
<Input.Root label="ИНН" error={innError} hint="10 или 12 цифр" reserveSupportRow>
|
|
101
106
|
<Input.Wrapper>
|
|
102
|
-
<Input.Field name="
|
|
107
|
+
<Input.Field name="inn" inputMode="numeric" defaultValue="7704512908" />
|
|
103
108
|
</Input.Wrapper>
|
|
104
109
|
</Input.Root>
|
|
105
|
-
<
|
|
106
|
-
<
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
</
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
))}
|
|
126
|
-
</Select.Content>
|
|
127
|
-
</Select.Root>
|
|
128
|
-
</div>
|
|
129
|
-
<Textarea.Root
|
|
130
|
-
name="address"
|
|
131
|
-
label="Юридический адрес"
|
|
132
|
-
optional
|
|
133
|
-
rows={2}
|
|
134
|
-
defaultValue="125009, Москва, ул. Тверская, д. 7, офис 412"
|
|
135
|
-
/>
|
|
136
|
-
</Fieldset>
|
|
137
|
-
</Card.Body>
|
|
138
|
-
<Card.Footer>
|
|
139
|
-
<Button.Root type="reset" variant="ghost" tone="neutral" disabled={saving}>
|
|
140
|
-
Отменить изменения
|
|
141
|
-
</Button.Root>
|
|
142
|
-
<Button.Root type="submit" loading={saving}>
|
|
143
|
-
{saved ? "Сохранено" : "Сохранить"}
|
|
144
|
-
</Button.Root>
|
|
145
|
-
</Card.Footer>
|
|
146
|
-
</Card.Root>
|
|
147
|
-
</form>
|
|
148
|
-
</Page.Section>
|
|
149
|
-
|
|
150
|
-
<Page.Section
|
|
151
|
-
layout="aside"
|
|
152
|
-
label="Уведомления"
|
|
153
|
-
description="Включаются сразу, без сохранения."
|
|
154
|
-
>
|
|
155
|
-
<Card.Root variant="panel">
|
|
156
|
-
<Card.Body>
|
|
157
|
-
<Fieldset aria-label="Уведомления">
|
|
158
|
-
{ALERTS.map((alert) => (
|
|
159
|
-
<Switch.Root
|
|
160
|
-
key={alert.name}
|
|
161
|
-
name={alert.name}
|
|
162
|
-
defaultChecked={alert.defaultChecked}
|
|
163
|
-
hint={alert.hint}
|
|
164
|
-
>
|
|
165
|
-
<Switch.Label>{alert.label}</Switch.Label>
|
|
166
|
-
</Switch.Root>
|
|
167
|
-
))}
|
|
110
|
+
<Select.Root label="Часовой пояс" defaultValue="Europe/Moscow">
|
|
111
|
+
<Select.Trigger>
|
|
112
|
+
<Select.Value />
|
|
113
|
+
</Select.Trigger>
|
|
114
|
+
<Select.Content searchable>
|
|
115
|
+
{TIMEZONES.map((zone) => (
|
|
116
|
+
<Select.Item key={zone.value} value={zone.value}>
|
|
117
|
+
{zone.label}
|
|
118
|
+
</Select.Item>
|
|
119
|
+
))}
|
|
120
|
+
</Select.Content>
|
|
121
|
+
</Select.Root>
|
|
122
|
+
</div>
|
|
123
|
+
<Textarea.Root
|
|
124
|
+
name="address"
|
|
125
|
+
label="Юридический адрес"
|
|
126
|
+
optional
|
|
127
|
+
rows={2}
|
|
128
|
+
defaultValue="125009, Москва, ул. Тверская, д. 7, офис 412"
|
|
129
|
+
/>
|
|
168
130
|
</Fieldset>
|
|
169
131
|
</Card.Body>
|
|
132
|
+
<Card.Footer>
|
|
133
|
+
<Button.Root type="reset" variant="ghost" tone="neutral" disabled={saving}>
|
|
134
|
+
Отменить изменения
|
|
135
|
+
</Button.Root>
|
|
136
|
+
<Button.Root type="submit" loading={saving}>
|
|
137
|
+
{saved ? "Сохранено" : "Сохранить"}
|
|
138
|
+
</Button.Root>
|
|
139
|
+
</Card.Footer>
|
|
170
140
|
</Card.Root>
|
|
171
|
-
</
|
|
141
|
+
</form>
|
|
172
142
|
|
|
173
|
-
<
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
<Card.
|
|
179
|
-
<
|
|
180
|
-
|
|
181
|
-
<
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
</div>
|
|
187
|
-
<ConfirmDialog.Root
|
|
188
|
-
title="Удалить «Прайм Софт»?"
|
|
189
|
-
description="312 счетов, 48 клиентов и вся история удалятся без возможности восстановления."
|
|
190
|
-
confirmLabel="Удалить пространство"
|
|
191
|
-
onConfirm={removeWorkspace}
|
|
143
|
+
<Card.Root variant="panel">
|
|
144
|
+
<Card.Header>
|
|
145
|
+
<Card.Title as="h2">Уведомления</Card.Title>
|
|
146
|
+
<Card.Description>Включаются сразу, без сохранения.</Card.Description>
|
|
147
|
+
</Card.Header>
|
|
148
|
+
<Card.Body>
|
|
149
|
+
<Fieldset aria-label="Уведомления">
|
|
150
|
+
{ALERTS.map((alert) => (
|
|
151
|
+
<Switch.Root
|
|
152
|
+
key={alert.name}
|
|
153
|
+
name={alert.name}
|
|
154
|
+
defaultChecked={alert.defaultChecked}
|
|
155
|
+
hint={alert.hint}
|
|
192
156
|
>
|
|
193
|
-
<
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
157
|
+
<Switch.Label>{alert.label}</Switch.Label>
|
|
158
|
+
</Switch.Root>
|
|
159
|
+
))}
|
|
160
|
+
</Fieldset>
|
|
161
|
+
</Card.Body>
|
|
162
|
+
</Card.Root>
|
|
163
|
+
|
|
164
|
+
<Card.Root variant="panel">
|
|
165
|
+
<Card.Header>
|
|
166
|
+
<Card.Title as="h2">Рабочее пространство</Card.Title>
|
|
167
|
+
<Card.Description>Действия, которые нельзя отменить.</Card.Description>
|
|
168
|
+
</Card.Header>
|
|
169
|
+
<Card.Body>
|
|
170
|
+
<div className={styles.danger}>
|
|
171
|
+
<div className={styles.dangerText}>
|
|
172
|
+
<Typography variant="title-s">Удалить пространство</Typography>
|
|
173
|
+
<Typography variant="body-s" tone="secondary">
|
|
174
|
+
Счета, клиенты и история будут удалены для всех участников.
|
|
175
|
+
</Typography>
|
|
199
176
|
</div>
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
177
|
+
<ConfirmDialog.Root
|
|
178
|
+
title="Удалить «Прайм Софт»?"
|
|
179
|
+
description="312 счетов, 48 клиентов и вся история удалятся без возможности восстановления."
|
|
180
|
+
confirmLabel="Удалить пространство"
|
|
181
|
+
onConfirm={removeWorkspace}
|
|
182
|
+
>
|
|
183
|
+
<ConfirmDialog.Trigger>
|
|
184
|
+
<Button.Root variant="outline" tone="danger">
|
|
185
|
+
Удалить
|
|
186
|
+
</Button.Root>
|
|
187
|
+
</ConfirmDialog.Trigger>
|
|
188
|
+
</ConfirmDialog.Root>
|
|
189
|
+
</div>
|
|
190
|
+
</Card.Body>
|
|
191
|
+
</Card.Root>
|
|
203
192
|
</Page.Body>
|
|
204
193
|
</Page.Root>
|
|
205
194
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/** A page with titled sections: tiles of one screen close together, a new topic set off by air, a link at the end of the heading
|
|
2
|
-
import { Card, DataTable, type DataTableColumn, LinkButton, Page
|
|
1
|
+
/** A page with titled sections: tiles of one screen close together, a new topic set off by air, a link at the end of the heading — `Page.Section`, `label`, `description`, `Page.Actions`. */
|
|
2
|
+
import { Card, DataTable, type DataTableColumn, LinkButton, Page } from "prime-ui-kit";
|
|
3
3
|
|
|
4
4
|
import styles from "./examples.module.css";
|
|
5
5
|
|
|
@@ -55,19 +55,6 @@ export default function PageSectionsExample() {
|
|
|
55
55
|
</Page.Actions>
|
|
56
56
|
<DataTable columns={COLUMNS} rows={INVOICES} getRowKey={(row) => row.id} paging="none" />
|
|
57
57
|
</Page.Section>
|
|
58
|
-
<Page.Section
|
|
59
|
-
layout="aside"
|
|
60
|
-
label="Реквизиты в счетах"
|
|
61
|
-
description="Попадают в каждый новый счёт."
|
|
62
|
-
>
|
|
63
|
-
<Card.Root variant="panel">
|
|
64
|
-
<Card.Body>
|
|
65
|
-
<Typography variant="body-m" tone="secondary">
|
|
66
|
-
ООО «Прайм Софт», ИНН 7701234567, р/с в Т-Банке.
|
|
67
|
-
</Typography>
|
|
68
|
-
</Card.Body>
|
|
69
|
-
</Card.Root>
|
|
70
|
-
</Page.Section>
|
|
71
58
|
</Page.Body>
|
|
72
59
|
</div>
|
|
73
60
|
);
|
|
@@ -299,6 +299,7 @@ Put `<Sidebar.Toggle variant="header" />` next to `Sidebar.Brand` in the header,
|
|
|
299
299
|
## States
|
|
300
300
|
| State | Driven by | DOM |
|
|
301
301
|
|---|---|---|
|
|
302
|
+
| held | a `Page.Guard` that is `busy` or `dirty` on the page | a press on `Sidebar.Item` or `Sidebar.Brand` stops before it navigates (a router link included) and the panel stays; `dirty` asks first, then repeats it |
|
|
302
303
|
| mode | `mode` / `defaultMode` | Root `data-mode`, `data-panel-mode` (the last visible mode while hidden); `<nav inert>` while hidden |
|
|
303
304
|
| off-canvas | `offCanvas="always"`, or `"auto"` + viewport < 768px | Root `data-off-canvas`, `data-state="open" \| "closed"`; `<nav inert>` while closed; the kit scrim (`role="presentation"`) while open; in an `AppShell` the shell Root `data-off-canvas` |
|
|
304
305
|
| placing | the viewport crossed the off-canvas breakpoint (not a person's choice) | Root `data-placing` for one painted frame: the rail lands at its new width with no motion (no growing from 0, no folding rows, no sliding panel) |
|
package/dist/skill/responsive.md
CHANGED
|
@@ -48,7 +48,8 @@ A layout inside a page needs no breakpoint: it takes its columns from the room i
|
|
|
48
48
|
|
|
49
49
|
- The tiles of a page (KPI cards, charts, panels) are one `Page.Grid` with a
|
|
50
50
|
`Page.Cell span` per tile: it folds by its own width (below 30rem every tile takes the row,
|
|
51
|
-
then small tiles pair up, from 64rem each its span).
|
|
51
|
+
then small tiles pair up, from 64rem each its span). Write a wide tile (`span` 7–11) next to a
|
|
52
|
+
narrow one (4–5): between 40 and 64rem the two pair up as 2/3 + 1/3, so an 8 + 4 row keeps no hole.
|
|
52
53
|
- A grid inside one block (thumbnails, short fields of one record) is the block's own
|
|
53
54
|
`grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--prime-layout-tile-min-width)), 1fr))`
|
|
54
55
|
— `auto-fill`, so a lone item keeps its column width instead of stretching across the row.
|
|
@@ -61,11 +62,11 @@ Use these as they are; never wrap them in your own breakpoints.
|
|
|
61
62
|
|
|
62
63
|
| Need | Built in |
|
|
63
64
|
|---|---|
|
|
64
|
-
| app frame | `AppShell.Main` hands the page its gutters 16 → 24 → 32
|
|
65
|
+
| app frame | `AppShell.Main` hands the page its gutters 16 → 24 → 32, top air 24 → 32 and bottom air 64 (the gutter under a `fill` page; above a floating BottomNav it keeps the capsule's room); `Page.TopBar` un-sticks on screens lower than 480px and respects the top safe area |
|
|
65
66
|
| app navigation | Sidebar: on-canvas from 768px, an off-canvas panel below (`offCanvas="auto"`) opened by the menu button `Page.TopBar` draws by itself while the Sidebar is off-canvas; `BottomNav` in `AppShell.Footer` for 2–6 app sections on phones — flat or a floating glass capsule (`floating`) with an optional round `BottomNav.Action`, icons with or without labels (`iconOnly`); the shell hides it by itself while the Sidebar rail is on screen (from 768px with `offCanvas="auto"`) |
|
|
66
|
-
| page top bar | `Page.TopBar` lays out its groups from their natural widths: one line while they fit, then the tools on a line of their own, then icon-only buttons, then «⋯», and the heading
|
|
67
|
+
| page top bar | `Page.TopBar` lays out its groups from their natural widths: one line while they fit, then the tools on a line of their own, then icon-only buttons, then «⋯», and the heading gives last ([below](#the-pages-top-bar--pagetopbar)). `Page.Header` in the flow: actions wrap under the title |
|
|
67
68
|
| switchers | [Switchers](#switchers) never wrap or truncate: they scroll inside themselves |
|
|
68
|
-
| tables | DataTable scrolls inside itself, edge shadows show hidden columns, `stickyFirstColumn
|
|
69
|
+
| tables | DataTable scrolls inside itself, edge shadows show hidden columns, `stickyFirstColumn` and `stickyLastColumn` (row actions), `columnsMenu` for a column chooser in the header row, the toolbar stacks below a 30rem table, sticky head off on short screens |
|
|
69
70
|
| floating layers | Popover (opened from a Trigger), Dropdown, Select (and Datepicker, ColorPresets) never wider than the viewport − 16, 8 from the edges, flip when out of room; below 640 they open as a bottom sheet — scrim, grab handle, swipe down to close, page scroll locked; Tooltip and TagSelect stay anchored |
|
|
70
71
|
| dialogs | Modal is a bottom sheet with a handle below 640 (swipe down closes it while `closeOnOutsideClick` allows); footer actions stack on phones and in a dialog narrower than 360px; `Sheet` is a bottom sheet for a short task at every width (centred at 560 on a tablet or desktop) and closes with a swipe down from its handle or header; a Drawer has no swipe — buttons, Escape and the scrim close it |
|
|
71
72
|
| date picking | Datepicker shows two months and side presets only when they fit; otherwise one month and presets above |
|
|
@@ -85,12 +86,16 @@ in this order, and nothing ever overflows:
|
|
|
85
86
|
|
|
86
87
|
1. **One line** — `Page.Heading`, `Page.Tools` and `Page.Actions` side by side while they fit.
|
|
87
88
|
2. **Tools below** — the tools take a line of their own under the first one and fill its width: a
|
|
88
|
-
search (`SmartFilter.Toolbar`, `Input.Root`) grows first, the switchers
|
|
89
|
-
when one line is not enough.
|
|
89
|
+
search (`SmartFilter.Toolbar`, `Input.Root`) grows first, the switchers and a period
|
|
90
|
+
(`Datepicker.Root`) share the rest and wrap when one line is not enough. Beside a search that
|
|
91
|
+
would get too little room the SmartFilter button shows only its icon and count, on the same row.
|
|
92
|
+
The actions stay on the first line beside the heading at every width.
|
|
90
93
|
3. **Icons** — every Button with an icon shows only the icon, the secondary ones first, then the
|
|
91
94
|
primary; its label stays its accessible name and becomes its tooltip.
|
|
92
95
|
4. **«⋯»** — the secondary Buttons fold into a menu (`labels.more`); the primary always stays.
|
|
93
|
-
5. **The heading
|
|
96
|
+
5. **The heading gives** — only after every button step: the middle levels of the path fold into
|
|
97
|
+
«…»; a heading with a path that still does not fit stacks (the path on its own line over the
|
|
98
|
+
title, the title and its description wrapping), so no level is cut to a fragment; a heading without a path truncates.
|
|
94
99
|
|
|
95
100
|
`Page.Chips` is always a line of its own under everything, gone while no filter is set. The heading
|
|
96
101
|
keeps its natural width: the bar sizes the title, so there is nothing to tune.
|
|
@@ -182,7 +187,7 @@ export function OrdersPage() {
|
|
|
182
187
|
inside takes that tier.
|
|
183
188
|
- A Button without an icon keeps its label at every step and leaves the bar less room before it
|
|
184
189
|
folds: give each one a `Button.Icon`.
|
|
185
|
-
- A SegmentedControl in `Page.Tools` needs no `fullWidth`: the bar sets it.
|
|
190
|
+
- A SegmentedControl or a Datepicker in `Page.Tools` needs no `fullWidth`: the bar sets it.
|
|
186
191
|
- The primary action is on screen at every width — as its icon at the narrowest; it never folds and
|
|
187
192
|
never disappears.
|
|
188
193
|
- Section totals go into `SegmentedControl.Count`, not into stat cards above the table.
|
|
@@ -199,8 +204,10 @@ export function OrdersPage() {
|
|
|
199
204
|
- Every switcher — Tabs, SegmentedControl, a horizontal ButtonGroup and BottomNav — scrolls inside
|
|
200
205
|
itself when its items do not fit: never a second line, never a truncated item. Its hidden edges
|
|
201
206
|
fade, a vertical mouse wheel scrolls it sideways, touch pans it, the current item is scrolled into
|
|
202
|
-
view, and the indicator moves only after a person's choice. A SegmentedControl
|
|
203
|
-
icons collapses to icons (each named by its
|
|
207
|
+
view, and the indicator moves only after a person's choice. A SegmentedControl first tightens its
|
|
208
|
+
segments' padding, and one whose items all have icons then collapses to icons (each named by its
|
|
209
|
+
tooltip) before it scrolls. On a 320px phone two sections with counts fit a line of their own;
|
|
210
|
+
more, or long labels, scroll — keep the section a person needs first at the start.
|
|
204
211
|
- Your duty as its host: give the switcher a bounded width. A flex or grid child that holds one sets
|
|
205
212
|
`min-width: 0`, otherwise the switcher grows the row instead of scrolling
|
|
206
213
|
([foundation §9](reference/foundation.md#9-layout-and-responsiveness)).
|
|
@@ -218,8 +225,8 @@ export function OrdersPage() {
|
|
|
218
225
|
|
|
219
226
|
## Components on narrow widths — what you still decide
|
|
220
227
|
|
|
221
|
-
**Tables.** Let DataTable scroll inside itself; offer a column chooser (`
|
|
222
|
-
|
|
228
|
+
**Tables.** Let DataTable scroll inside itself; offer a column chooser (`columnsMenu`, in the header
|
|
229
|
+
row; the key column `hideable: false`); `stickyFirstColumn` for the name. On phones a table / cards switch in `Page.Tools` is fine — silently dropping columns
|
|
223
230
|
by breakpoint is not. Never ask to rotate the phone.
|
|
224
231
|
|
|
225
232
|
**Card grids.** [Intrinsic grids](#intrinsic-grids), never a breakpoint. Tiles of a row share one
|
package/dist/skill/ux.md
CHANGED
|
@@ -55,8 +55,10 @@ Every word on screen must carry something the person does not see already.
|
|
|
55
55
|
list already counts. The list label names the rows.
|
|
56
56
|
- **No label that repeats its heading.** A field «Цена» inside the section «Цена» needs no label of
|
|
57
57
|
its own beyond what the section says; a group of one field is the field.
|
|
58
|
-
- **A unit lives in one place.** In the field (`Input.InlineAffix`) or in the heading, never both
|
|
59
|
-
|
|
58
|
+
- **A unit lives in one place.** In the field (`Input.InlineAffix`) or in the heading, never both;
|
|
59
|
+
never in the field's own label («Бюджет», not «Бюджет, ₽»). Prefer the field: the unit stays
|
|
60
|
+
beside the number when the row stacks, and a screen reader hears it with the field (the affix
|
|
61
|
+
describes the input; `aria-label="рублей"` on it when the sign reads badly).
|
|
60
62
|
- **No text that explains the layout.** «Двигатель, места и скорость всегда первыми» — the lock on
|
|
61
63
|
those rows says it. A hint says what the person cannot see (a format, a consequence, a limit).
|
|
62
64
|
- **One name per thing.** The same action, entity and status keep one word on the whole screen
|
|
@@ -97,7 +99,7 @@ Pick the lightest step that keeps the person safe ([choosing.md](choosing.md) ha
|
|
|
97
99
|
| One standalone action that is easy to redo by hand | `Button.Root holdToConfirm` |
|
|
98
100
|
| Irreversible loss of work, or an outward action that cannot be called back once it leaves the product (an invoice or a message sent to a client, a payment) | `ConfirmDialog` that names the thing and the consequence |
|
|
99
101
|
| Bulk destructive | `ConfirmDialog` that names the count («Удалить 12 счетов?») |
|
|
100
|
-
| Leaving a form with changes | `Modal.Guard` / `Drawer.Guard dirty` |
|
|
102
|
+
| Leaving a form with changes | `Modal.Guard` / `Drawer.Guard dirty`; a form that is the page — `Page.Guard dirty` |
|
|
101
103
|
|
|
102
104
|
A confirm on every action trains people to click through it; the one that mattered is then missed.
|
|
103
105
|
Which button starts each step and how the confirm behaves:
|
|
@@ -22,7 +22,7 @@ export declare const semanticTokens: {
|
|
|
22
22
|
readonly inverse: "{color.gray.925}";
|
|
23
23
|
readonly scrim: "color-mix(in srgb, {color.gray.925} 44%, transparent)";
|
|
24
24
|
/** Soft shade over an edge that hides scrolled content (DataTable columns). */
|
|
25
|
-
readonly edgeShadow: "color-mix(in srgb, {color.gray.925}
|
|
25
|
+
readonly edgeShadow: "color-mix(in srgb, {color.gray.925} 8%, transparent)";
|
|
26
26
|
/**
|
|
27
27
|
* Translucent glass over content (floating BottomNav), always with a strong backdrop blur
|
|
28
28
|
* (`--prime-glass-saturation` lifts the colors under it): dense, as the iOS tab bar — the
|
|
@@ -801,6 +801,8 @@ export declare const semanticTokens: {
|
|
|
801
801
|
readonly videoNote: "14.5rem";
|
|
802
802
|
/** The box of a sent round video message (`VideoNote`): its diameter, at most the row. */
|
|
803
803
|
readonly videoNoteBox: "16.75rem";
|
|
804
|
+
/** The square box of a sticker (`Message.Sticker`), at most the row. */
|
|
805
|
+
readonly sticker: "10rem";
|
|
804
806
|
/**
|
|
805
807
|
* A message changing size (a reaction row, a transcript that opens): the bubble's box, its
|
|
806
808
|
* parts and the messages around glide in one calm stroke, between `fast` and `base`; zeroed
|
|
@@ -11,7 +11,7 @@ export declare const darkThemeOverrides: {
|
|
|
11
11
|
readonly inverse: "{color.gray.100}";
|
|
12
12
|
readonly scrim: "color-mix(in srgb, {color.black} 60%, transparent)";
|
|
13
13
|
/** Darker than the scrim's share: a shade on a 900 surface needs more ink to read. */
|
|
14
|
-
readonly edgeShadow: "color-mix(in srgb, {color.black}
|
|
14
|
+
readonly edgeShadow: "color-mix(in srgb, {color.black} 28%, transparent)";
|
|
15
15
|
readonly glass: "color-mix(in srgb, {color.gray.875} 76%, transparent)";
|
|
16
16
|
readonly glassEdge: "color-mix(in srgb, {color.white} 28%, transparent)";
|
|
17
17
|
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prime-ui-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"packageManager": "bun@1.3.13",
|
|
5
|
-
"description": "React 19 UI kit for product interfaces:
|
|
5
|
+
"description": "React 19 UI kit for product interfaces: 79 composable components on one design contract — forms, selects, tables, overlays, navigation, app shell. CSS Modules, --prime-* tokens, light and dark themes, TypeScript, a11y, Next.js App Router ready. Ships COMPONENT.md docs, copyable examples and an agent skill.",
|
|
6
6
|
"bin": {
|
|
7
7
|
"prime-ui-kit": "bin/prime-ui-kit.js"
|
|
8
8
|
},
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
- A selected value, keyword or applied filter the user can remove (`onRemove`).
|
|
13
13
|
- Values in a filter panel that toggle on press and hide with a hover action (the `pressed` triad, `Badge.Action`).
|
|
14
14
|
- A short code as a square tile (a file format «PDF») — `shape="square"`.
|
|
15
|
+
- Several badges as one value (the tags of a client, a record's labels) — `Badge.Group`: it wraps and keeps one gap.
|
|
15
16
|
|
|
16
17
|
## When not to use
|
|
17
18
|
- A multi-select field with chips → use [TagSelect](../tag-select/COMPONENT.md) (it renders badges itself).
|
|
@@ -33,6 +34,8 @@ Badge.Root <span>: fill, tier dimensions
|
|
|
33
34
|
│ (a toggle <button> with the pressed triad; a <span> with a trailing segment; none when read-only)
|
|
34
35
|
├─ Badge.Action optional end segment revealed on hover / focus (always shown on touch screens)
|
|
35
36
|
└─ remove segment with onRemove: full height, the whole end is the hit area (Icon action.close)
|
|
37
|
+
|
|
38
|
+
Badge.Group <div>: a wrapping row of Badge.Root, one value; `size` sets every badge's tier
|
|
36
39
|
```
|
|
37
40
|
|
|
38
41
|
## API
|
|
@@ -60,6 +63,14 @@ Badge.Root <span>: fill, tier dimensions
|
|
|
60
63
|
| `children` | `ReactNode` | — | Text, `Badge.Dot`, `Badge.Icon`, one `Badge.Action`. Only `Badge.Icon` children (no remove or action) make a square icon-only badge. |
|
|
61
64
|
| `…rest` | `Omit<HTMLAttributes<HTMLSpanElement>, "onClick" \| "color">` | — | `aria-label` (an icon-only badge named by it is an image) and the other span attributes; no `onClick` — a pressable chip is the toggle. |
|
|
62
65
|
|
|
66
|
+
### Badge.Group
|
|
67
|
+
`ref` → `HTMLDivElement`. A row of badges as one value (the tags of a record): it wraps onto more lines, the badges a chip gap apart.
|
|
68
|
+
|
|
69
|
+
| Prop | Type | Default | Description |
|
|
70
|
+
|---|---|---|---|
|
|
71
|
+
| `size` | `"xs" \| "s" \| "m" \| "l" \| "xl"` | the host tier, one step down | Tier of every badge in the group; a badge's own `size` wins. Small tiers stand closer. |
|
|
72
|
+
| `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children` (the `Badge.Root`s), `className`, `aria-label` (a named group is `role="group"`) and the other div attributes. |
|
|
73
|
+
|
|
63
74
|
### Badge.Icon
|
|
64
75
|
`ref` → `HTMLSpanElement`. A `<span>` holding one icon at the tier icon size. At the first or last position it becomes a full-height edge segment.
|
|
65
76
|
|
|
@@ -163,7 +174,7 @@ A status takes `tone`; a category takes `color`. The two never go together (the
|
|
|
163
174
|
- `Badge.Dot` is 6px, 8px from `l`; alone it takes the tier of the surrounding control; `color` paints it in the solid step of that hue.
|
|
164
175
|
- The root never clips: the text ellipsizes in its own box, so the segments' touch areas reach past the chip.
|
|
165
176
|
- `Badge.Action` room is reserved, so revealing it never changes the badge width.
|
|
166
|
-
- Several badges in a row: `
|
|
177
|
+
- Several badges in a row: `Badge.Group` — it wraps, badges 8 apart (4 at the `xs` and `s` tiers).
|
|
167
178
|
- In a list row the badge is the trailing column; the title column gets `min-width: 0` and an ellipsis.
|
|
168
179
|
|
|
169
180
|
## Accessibility
|
|
@@ -206,6 +217,7 @@ A status takes `tone`; a category takes `color`. The two never go together (the
|
|
|
206
217
|
| [server-tags.tsx](examples/server-tags.tsx) | Order tags removed on the server: a badge waits dimmed with a spinner, leaves once the server agrees and stays with an announcement when it refuses — `onRemove`, `labels`. |
|
|
207
218
|
| [filter-values.tsx](examples/filter-values.tsx) | Filter values as toggles with a hide action that slides in without changing the width — `pressed`, `onPressedChange`, `Badge.Action`, `persistent`. |
|
|
208
219
|
| [square.tsx](examples/square.tsx) | File formats as square tiles of text, large enough for three letters; the hue sorts them by kind — `shape`, `size`, `color`. |
|
|
220
|
+
| [tag-row.tsx](examples/tag-row.tsx) | The tags of a client as one value: the row wraps in a narrow column and keeps one gap between badges — `Badge.Group`, `size`. |
|
|
209
221
|
| [controlled.tsx](examples/controlled.tsx) | Delivery cities as toggle chips whose state the screen owns: the summary counts the chosen ones — `pressed`, `onPressedChange`. |
|
|
210
222
|
|
|
211
223
|
## Mistakes
|
|
@@ -217,6 +229,7 @@ A status takes `tone`; a category takes `color`. The two never go together (the
|
|
|
217
229
|
- Several removable badges with the default «Удалить» → pass `labels.remove` with the badge text.
|
|
218
230
|
- A colored badge with no text → keep a word; color alone is not a signal.
|
|
219
231
|
- An explicit `size` inside a control → drop it; the badge takes the tier one step down.
|
|
232
|
+
- A row of badges in a hand-made flex wrapper with its own gap → `Badge.Group`.
|
|
220
233
|
- `onRemove` together with `Badge.Action` → one end segment per badge.
|
|
221
234
|
- Removing the badge from your list first and putting it back when the request fails → return the request's promise and remove it after it succeeds; the badge waits meanwhile.
|
|
222
235
|
|
|
@@ -23,3 +23,10 @@
|
|
|
23
23
|
align-items: center;
|
|
24
24
|
gap: var(--prime-space-2);
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
/* tag-row.tsx: a 320 px column, narrow enough for the row of badges to wrap. */
|
|
28
|
+
.column {
|
|
29
|
+
display: grid;
|
|
30
|
+
gap: var(--prime-space-6);
|
|
31
|
+
inline-size: min(100%, calc(var(--prime-space-20) * 4));
|
|
32
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** The tags of a client as one value: the row wraps in a narrow column and keeps one gap between badges — `Badge.Group`, `size`. */
|
|
2
|
+
import { Badge } from "prime-ui-kit";
|
|
3
|
+
|
|
4
|
+
import styles from "./examples.module.css";
|
|
5
|
+
|
|
6
|
+
const TAGS = [
|
|
7
|
+
{ label: "Ключевой клиент", color: "purple" },
|
|
8
|
+
{ label: "Оптовые закупки", color: "blue" },
|
|
9
|
+
{ label: "Отсрочка 30 дней", color: "orange" },
|
|
10
|
+
{ label: "ЭДО", color: "teal" },
|
|
11
|
+
{ label: "Москва", color: "gray" },
|
|
12
|
+
{ label: "Новый договор", color: "green" },
|
|
13
|
+
] as const;
|
|
14
|
+
|
|
15
|
+
export default function BadgeTagRowExample() {
|
|
16
|
+
return (
|
|
17
|
+
<div className={styles.column}>
|
|
18
|
+
<Badge.Group aria-label="Теги клиента">
|
|
19
|
+
{TAGS.map((tag) => (
|
|
20
|
+
<Badge.Root key={tag.label} color={tag.color}>
|
|
21
|
+
{tag.label}
|
|
22
|
+
</Badge.Root>
|
|
23
|
+
))}
|
|
24
|
+
</Badge.Group>
|
|
25
|
+
<Badge.Group size="s" aria-label="Теги заказа">
|
|
26
|
+
{TAGS.slice(0, 4).map((tag) => (
|
|
27
|
+
<Badge.Root key={tag.label} color={tag.color}>
|
|
28
|
+
{tag.label}
|
|
29
|
+
</Badge.Root>
|
|
30
|
+
))}
|
|
31
|
+
</Badge.Group>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -23,7 +23,7 @@ import { Breadcrumb } from "prime-ui-kit";
|
|
|
23
23
|
## Anatomy
|
|
24
24
|
```
|
|
25
25
|
Breadcrumb.Root <nav aria-label> + <ol>; size; chevrons between levels; auto-collapse into a «…» menu
|
|
26
|
-
├─ Breadcrumb.Item <li>: a link (href → LinkButton), text, or the current page (current)
|
|
26
|
+
├─ Breadcrumb.Item <li>: a link (href → LinkButton, or a router link with asChild), text, or the current page (current)
|
|
27
27
|
└─ Breadcrumb.Ellipsis <li> with «…» for levels skipped on purpose
|
|
28
28
|
```
|
|
29
29
|
|
|
@@ -42,14 +42,15 @@ Breadcrumb.Root <nav aria-label> + <ol>; size; chevrons between levels
|
|
|
42
42
|
| `…rest` | `HTMLAttributes<HTMLElement>` | — | `className` and the other `nav` attributes; an `aria-label` here overrides `labels.nav`. |
|
|
43
43
|
|
|
44
44
|
### Breadcrumb.Item
|
|
45
|
-
`ref` → `HTMLLIElement`. `<li>`: a muted `LinkButton` (`href`), plain text, or the current page (`current`).
|
|
45
|
+
`ref` → `HTMLLIElement`. `<li>`: a muted `LinkButton` (`href`, or the consumer's router link with `asChild`), plain text, or the current page (`current`). A press on the link goes through `Page.Guard`.
|
|
46
46
|
|
|
47
47
|
| Prop | Type | Default | Description |
|
|
48
48
|
|---|---|---|---|
|
|
49
|
-
| `href` | `string` | — | Renders a link; without it the item is text. |
|
|
49
|
+
| `href` | `string` | — | Renders a link; without it (and without `asChild`) the item is text. |
|
|
50
|
+
| `asChild` | `boolean` | `false` | The single child (a router `Link`) is the level's link with the same look; its own text is the level. In the «…» menu of a folded path it is the menu item. |
|
|
50
51
|
| `current` | `boolean` | — | Current page: `aria-current="page"` (on the link when `href` is set), primary text, medium weight. Usually the last item, without `href`. |
|
|
51
52
|
| `aria-label` | `string` | — | Name of a link without visible text (e.g. a home icon); set on the link, not the `li`. |
|
|
52
|
-
| `children` | `ReactNode` | — | Text or an `Icon
|
|
53
|
+
| `children` | `ReactNode` | — | Text or an `Icon`; with `asChild` one element. A string also becomes the `title` of a text item (full text when truncated). |
|
|
53
54
|
| `…rest` | `Omit<LiHTMLAttributes<HTMLLIElement>, "aria-label">` | — | `className` and the other `li` attributes. |
|
|
54
55
|
|
|
55
56
|
### Breadcrumb.Ellipsis
|
|
@@ -77,6 +78,7 @@ Breadcrumb.Root <nav aria-label> + <ol>; size; chevrons between levels
|
|
|
77
78
|
| text (no `href`, no `current`) | muted text | a level without its own page | yes |
|
|
78
79
|
| current (`current`) | primary text, medium weight | the last item — this page | |
|
|
79
80
|
| icon link (`href` + `aria-label`, `Icon` child) | icon at the tier icon size | a «home» root | |
|
|
81
|
+
| router link (`asChild`, one `Link` child) | the same muted link, the consumer's element | an app with a client router: the path moves without a reload | |
|
|
80
82
|
|
|
81
83
|
Use links for every ancestor and `current` on the last item; `s` above a `heading-m` page title. Avoid `href` on the current item and two `current` items.
|
|
82
84
|
|
|
@@ -89,6 +91,7 @@ Use links for every ancestor and `current` on the last item; `s` above a `headin
|
|
|
89
91
|
| auto-collapse | 2+ levels whose whole path does not fit the width uncut (measured on every resize) | `data-collapsible="true"`, `data-collapsed="true"`; middle levels are `display: none` and replaced by «… ›»: a ghost menu button (`Dropdown.Trigger`, named by `labels.ellipsis`) whose menu lists them — links stay links, a level without `href` is a disabled row |
|
|
90
92
|
| deep collapse | the path folded as above still does not fit | `data-collapsed="deep"`; the first level folds too: «…» › current page, the menu lists every level before it |
|
|
91
93
|
| collapse menu open | a press, `Enter` or `ArrowDown` on the «…» | `aria-expanded="true"` on the button; a `role="menu"` panel at the tier size |
|
|
94
|
+
| held | a `Page.Guard` that is `busy` or `dirty` on the page | a press on a level's link (in the path or the «…» menu) stops before it navigates; `dirty` asks first, then repeats it |
|
|
92
95
|
|
|
93
96
|
Root attributes: `data-size`, `data-collapsible` (`"true"` / `"false"`), `data-collapsed` (`"true"` / `"deep"`).
|
|
94
97
|
|
|
@@ -133,12 +136,14 @@ Root attributes: `data-size`, `data-collapsible` (`"true"` / `"false"`), `data-c
|
|
|
133
136
|
| [with-icon.tsx](examples/with-icon.tsx) | The root level as a home icon; a link without text is named for screen readers — `aria-label`. |
|
|
134
137
|
| [overflow.tsx](examples/overflow.tsx) | A long path: levels truncate, and in a 320px container the middle ones collapse into a «…» menu that lists them — `Breadcrumb.Item`, `current`. |
|
|
135
138
|
| [ellipsis.tsx](examples/ellipsis.tsx) | Levels skipped on purpose shown as «…» whose hidden text names them for screen readers — `Breadcrumb.Ellipsis`, `labels`. |
|
|
139
|
+
| [router.tsx](examples/router.tsx) | Router links as the levels above: the path moves without a reload; render it inside a router — `asChild`, `current`. |
|
|
136
140
|
|
|
137
141
|
## Mistakes
|
|
138
142
|
- Separators by hand between items → the root draws the chevrons.
|
|
139
143
|
- `<Breadcrumb.Item href="…" current>` → the current page has no `href`.
|
|
140
144
|
- Breadcrumb inside a flex row collapsing to zero width → give it `flex: 1 1 auto; min-width: 0`.
|
|
141
145
|
- Home icon link without `aria-label` → add `aria-label="Главная"`.
|
|
146
|
+
- `href` + `onClick` with `preventDefault()` and `navigate()` for a router → `asChild` with the router's `Link`.
|
|
142
147
|
|
|
143
148
|
## Related
|
|
144
149
|
- **Built from:** [LinkButton](../link-button/COMPONENT.md) (`tone="muted"`), [Button](../button/COMPONENT.md) and [Dropdown](../dropdown/COMPONENT.md) (the collapse menu), Icon (`nav.chevronRight`), [VisuallyHidden](../visually-hidden/COMPONENT.md)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Router links as the levels above: the path moves without a reload; render it inside a router — `asChild`, `current`. */
|
|
2
|
+
import { Breadcrumb } from "prime-ui-kit";
|
|
3
|
+
import { Link } from "react-router-dom";
|
|
4
|
+
|
|
5
|
+
export default function BreadcrumbRouterExample() {
|
|
6
|
+
return (
|
|
7
|
+
<Breadcrumb.Root>
|
|
8
|
+
<Breadcrumb.Item asChild>
|
|
9
|
+
<Link to="/crm">CRM</Link>
|
|
10
|
+
</Breadcrumb.Item>
|
|
11
|
+
<Breadcrumb.Item asChild>
|
|
12
|
+
<Link to="/crm/clients">Клиенты</Link>
|
|
13
|
+
</Breadcrumb.Item>
|
|
14
|
+
<Breadcrumb.Item current>ООО «Северный ветер»</Breadcrumb.Item>
|
|
15
|
+
</Breadcrumb.Root>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -66,7 +66,7 @@ Button.Root <button> (or the single child with asChild); variant, tone, s
|
|
|
66
66
|
| `labels` | `Partial<ButtonLabels>` | — | Built-in strings, see Labels. |
|
|
67
67
|
| `asChild` | `boolean` | `false` | Merges Button props and styles onto the single child element (a link) instead of rendering `<button>`. `disabled`/`loading` become `aria-disabled`; `progress` and `holdToConfirm` need a `<button>`. |
|
|
68
68
|
| `disabled` | `boolean` | — | Disabled state; `loading` also disables. With `asChild` the child leaves the Tab order and a link loses its `href`. |
|
|
69
|
-
| `children` | `ReactNode` | — | Label and `Button.Icon`. Only `Button.Icon` children → a square icon-only button that needs `aria-label`. A changed label morphs letter by letter. With `asChild`, the one child element. |
|
|
69
|
+
| `children` | `ReactNode` | — | Label and `Button.Icon`. Only `Button.Icon` children → a square icon-only button that needs `aria-label`. A changed label morphs letter by letter. With `asChild`, the one child element; its text is the label too. |
|
|
70
70
|
| `aria-label` | `string` | — | The name of a button without a visible label; required with `shape="circle"`. |
|
|
71
71
|
| `…rest` | `Omit<ButtonHTMLAttributes<HTMLButtonElement>, "size" \| "aria-pressed">` | — | `onClick`, `type` (`"button"` by default, not passed on with `asChild`), `className`, `aria-*`, `data-*` and the other button attributes. |
|
|
72
72
|
|
|
@@ -47,6 +47,7 @@ The root is a field root: `className`, `ref` and the native attributes land on t
|
|
|
47
47
|
| `required` | `boolean` | `false` | Red `*` after the label and `aria-required` on the `group`. |
|
|
48
48
|
| `optional` | `boolean` | `false` | Muted marker after the label (`labels.optional`). |
|
|
49
49
|
| `hint` | `ReactNode` | — | Help text under the control (`aria-describedby`). Hidden while `error` is shown. |
|
|
50
|
+
| `hintTone` | `"neutral" \| "success" \| "warning" \| "danger"` | `"neutral"` | Status color of `hint` («Осталось 12 дней» in `warning`). The words carry the status, the color repeats it; an `error` replaces the hint and its tone. A validation error is `error`, never a `danger` hint. |
|
|
50
51
|
| `error` | `ReactNode` | — | Error message in the hint slot; implies `invalid`. |
|
|
51
52
|
| `invalid` | `boolean` | `false` | Danger inset ring, `aria-invalid` and `data-invalid` on the `group`; the control shakes once when an error arrives. |
|
|
52
53
|
| `reserveSupportRow` | `boolean` | `false` | Always render the support row, so an appearing error does not shift the layout. |
|