prime-ui-kit 0.13.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -6
- package/dist/chunks/{chunk-XNOJEX55.js → chunk-P6ZO37JM.js} +1 -1
- package/dist/chunks/{chunk-JV2KB5JZ.js → chunk-SYEX7OVT.js} +3572 -2865
- package/dist/chunks/{chunk-PK2GC77E.js → chunk-WXKRUVSE.js} +164 -140
- package/dist/color-picker.js +2 -2
- package/dist/components/banner/Banner.d.ts +5 -2
- package/dist/components/chart-frame/ChartFrame.d.ts +19 -6
- package/dist/components/chat/Chat.d.ts +2 -2
- package/dist/components/chat/ChatPinned.d.ts +2 -2
- package/dist/components/chat/MessageList.d.ts +1 -1
- package/dist/components/chat/chatContext.d.ts +1 -1
- package/dist/components/field-list/FieldList.d.ts +90 -0
- package/dist/components/index.d.ts +3 -1
- package/dist/components/input/Input.d.ts +2 -2
- package/dist/components/kanban/Kanban.d.ts +6 -3
- package/dist/components/page-content/PageContent.d.ts +55 -4
- package/dist/components/sparkline/Sparkline.d.ts +64 -15
- package/dist/components/sparkline/geometry.d.ts +26 -0
- package/dist/components/tooltip/Tooltip.d.ts +5 -2
- package/dist/hooks/usePosition.d.ts +15 -4
- package/dist/index.css +1 -1
- package/dist/index.js +4 -2
- package/dist/internal/ChartTooltip.d.ts +26 -0
- package/dist/internal/FieldAction.d.ts +6 -7
- package/dist/internal/fieldCell.d.ts +21 -0
- package/dist/internal/messageList.d.ts +2 -2
- package/dist/internal/palette.d.ts +7 -0
- package/dist/skill/SKILL.md +24 -14
- package/dist/skill/anti-slop.md +77 -4
- package/dist/skill/cheatsheet.md +24 -5
- package/dist/skill/checklist.md +19 -1
- package/dist/skill/choosing.md +10 -5
- package/dist/skill/components.md +4 -3
- package/dist/skill/composition.md +28 -15
- package/dist/skill/foundations.md +8 -6
- package/dist/skill/layouts.md +6 -6
- package/dist/skill/patterns/app-shell.module.css +1 -8
- package/dist/skill/patterns/app-shell.tsx +11 -9
- package/dist/skill/patterns/chat.tsx +23 -5
- package/dist/skill/patterns/dashboard.module.css +1 -31
- package/dist/skill/patterns/dashboard.tsx +150 -136
- package/dist/skill/patterns/detail-page.module.css +0 -3
- package/dist/skill/patterns/detail-page.tsx +4 -7
- package/dist/skill/patterns/form-drawer.tsx +2 -2
- package/dist/skill/patterns/kanban-board.tsx +4 -2
- package/dist/skill/patterns/list-page.tsx +2 -2
- package/dist/skill/patterns/media-library.module.css +0 -22
- package/dist/skill/patterns/media-library.tsx +17 -18
- package/dist/skill/patterns/record-editor.module.css +18 -0
- package/dist/skill/patterns/record-editor.tsx +356 -0
- package/dist/skill/patterns/screen-states.module.css +3 -17
- package/dist/skill/patterns/screen-states.tsx +70 -69
- package/dist/skill/patterns/settings-page.module.css +1 -21
- package/dist/skill/patterns/settings-page.tsx +58 -79
- package/dist/skill/reference/components/avatar/COMPONENT.md +4 -4
- package/dist/skill/reference/components/avatar/examples/presence.tsx +1 -1
- package/dist/skill/reference/components/avatar/examples/states.tsx +1 -1
- package/dist/skill/reference/components/banner/COMPONENT.md +6 -6
- package/dist/skill/reference/components/banner/examples/dismissible.tsx +22 -11
- package/dist/skill/reference/components/banner/examples/examples.module.css +3 -3
- package/dist/skill/reference/components/banner/examples/narrow.tsx +1 -1
- package/dist/skill/reference/components/breadcrumb/COMPONENT.md +1 -1
- package/dist/skill/reference/components/breadcrumb/examples/overflow.tsx +1 -1
- package/dist/skill/reference/components/card/COMPONENT.md +5 -4
- package/dist/skill/reference/components/card/examples/examples.module.css +0 -28
- package/dist/skill/reference/components/card/examples/kpi-media.tsx +13 -11
- package/dist/skill/reference/components/card/examples/narrow.tsx +1 -1
- package/dist/skill/reference/components/card/examples/panel-chart.tsx +45 -22
- package/dist/skill/reference/components/chart-frame/COMPONENT.md +10 -7
- package/dist/skill/reference/components/chart-frame/examples/tooltip.tsx +20 -24
- package/dist/skill/reference/components/chat/COMPONENT.md +3 -3
- package/dist/skill/reference/components/chat/examples/search.tsx +1 -1
- package/dist/skill/reference/components/chat-list/COMPONENT.md +1 -1
- package/dist/skill/reference/components/checkbox/examples/indicator.tsx +24 -2
- package/dist/skill/reference/components/color-picker/COMPONENT.md +2 -2
- package/dist/skill/reference/components/color-swatches/COMPONENT.md +1 -0
- package/dist/skill/reference/components/datepicker/COMPONENT.md +1 -0
- package/dist/skill/reference/components/dnd/COMPONENT.md +3 -3
- package/dist/skill/reference/components/field-list/COMPONENT.md +164 -0
- package/dist/skill/reference/components/field-list/examples/base-row.tsx +76 -0
- package/dist/skill/reference/components/field-list/examples/controlled.tsx +72 -0
- package/dist/skill/reference/components/field-list/examples/errors.tsx +85 -0
- package/dist/skill/reference/components/field-list/examples/examples.module.css +34 -0
- package/dist/skill/reference/components/field-list/examples/limits.tsx +55 -0
- package/dist/skill/reference/components/field-list/examples/locked.tsx +139 -0
- package/dist/skill/reference/components/field-list/examples/narrow.tsx +68 -0
- package/dist/skill/reference/components/field-list/examples/overview.tsx +66 -0
- package/dist/skill/reference/components/field-list/examples/reorder.tsx +42 -0
- package/dist/skill/reference/components/field-list/examples/sizes.tsx +42 -0
- package/dist/skill/reference/components/field-list/examples/states.tsx +51 -0
- package/dist/skill/reference/components/input/examples/examples.module.css +2 -7
- package/dist/skill/reference/components/kanban/COMPONENT.md +13 -9
- package/dist/skill/reference/components/kanban/examples/limits.tsx +2 -1
- package/dist/skill/reference/components/kanban/examples/variants.tsx +16 -8
- package/dist/skill/reference/components/list/COMPONENT.md +1 -1
- package/dist/skill/reference/components/media-viewer/COMPONENT.md +2 -2
- package/dist/skill/reference/components/message/COMPONENT.md +2 -2
- package/dist/skill/reference/components/notification/COMPONENT.md +1 -0
- package/dist/skill/reference/components/page-content/COMPONENT.md +70 -14
- package/dist/skill/reference/components/page-content/examples/grid.tsx +107 -0
- package/dist/skill/reference/components/page-content/examples/overview.tsx +2 -2
- package/dist/skill/reference/components/page-content/examples/sections.tsx +81 -0
- package/dist/skill/reference/components/page-toolbar/COMPONENT.md +1 -1
- package/dist/skill/reference/components/segmented-control/COMPONENT.md +1 -0
- package/dist/skill/reference/components/select/COMPONENT.md +4 -2
- package/dist/skill/reference/components/select/examples/icon-only.tsx +38 -0
- package/dist/skill/reference/components/sparkline/COMPONENT.md +83 -30
- package/dist/skill/reference/components/sparkline/examples/compact.tsx +1 -1
- package/dist/skill/reference/components/sparkline/examples/curve.tsx +28 -0
- package/dist/skill/reference/components/sparkline/examples/gaps.tsx +33 -0
- package/dist/skill/reference/components/sparkline/examples/overview.tsx +11 -2
- package/dist/skill/reference/components/sparkline/examples/period.tsx +7 -2
- package/dist/skill/reference/components/sparkline/examples/reference.tsx +37 -0
- package/dist/skill/reference/components/sparkline/examples/variants.tsx +2 -2
- package/dist/skill/reference/components/tabs/examples/examples.module.css +0 -6
- package/dist/skill/reference/components/tabs/examples/in-drawer.tsx +11 -13
- package/dist/skill/reference/components/timeline/examples/examples.module.css +0 -8
- package/dist/skill/reference/components/timeline/examples/narrow.tsx +2 -2
- package/dist/skill/reference/components/timeline/examples/sizes.tsx +3 -3
- package/dist/skill/reference/components/timeline/examples/variants.tsx +4 -4
- package/dist/skill/reference/components/tooltip/COMPONENT.md +6 -4
- package/dist/skill/reference/components/tooltip/examples/placement.tsx +2 -1
- package/dist/skill/reference/components/video-note/COMPONENT.md +1 -1
- package/dist/skill/reference/components/voice-player/COMPONENT.md +1 -1
- package/dist/skill/reference/layout/app-header/examples/in-app-shell.tsx +2 -2
- package/dist/skill/reference/layout/app-shell/COMPONENT.md +1 -1
- package/dist/skill/reference/layout/app-shell/examples/footer.tsx +2 -2
- package/dist/skill/reference/layout/app-shell/examples/overview.tsx +2 -2
- package/dist/skill/reference/layout/app-shell/examples/template.tsx +2 -2
- package/dist/skill/reference/layout/bottom-nav/examples/floating-action.tsx +2 -2
- package/dist/skill/reference/layout/bottom-nav/examples/floating.tsx +2 -2
- package/dist/skill/reference/layout/bottom-nav/examples/in-app-shell.tsx +2 -2
- package/dist/skill/responsive.md +5 -3
- package/dist/skill/ux.md +145 -0
- package/dist/tokens/semantic.d.ts +2 -0
- package/package.json +1 -1
- package/src/components/avatar/COMPONENT.md +4 -4
- package/src/components/avatar/examples/presence.tsx +1 -1
- package/src/components/avatar/examples/states.tsx +1 -1
- package/src/components/banner/COMPONENT.md +6 -6
- package/src/components/banner/examples/dismissible.tsx +22 -11
- package/src/components/banner/examples/examples.module.css +3 -3
- package/src/components/banner/examples/narrow.tsx +1 -1
- package/src/components/breadcrumb/COMPONENT.md +1 -1
- package/src/components/breadcrumb/examples/overflow.tsx +1 -1
- package/src/components/card/COMPONENT.md +5 -4
- package/src/components/card/examples/examples.module.css +0 -28
- package/src/components/card/examples/kpi-media.tsx +13 -11
- package/src/components/card/examples/narrow.tsx +1 -1
- package/src/components/card/examples/panel-chart.tsx +45 -22
- package/src/components/chart-frame/COMPONENT.md +10 -7
- package/src/components/chart-frame/examples/tooltip.tsx +20 -24
- package/src/components/chat/COMPONENT.md +3 -3
- package/src/components/chat/examples/search.tsx +1 -1
- package/src/components/chat-list/COMPONENT.md +1 -1
- package/src/components/checkbox/examples/indicator.tsx +24 -2
- package/src/components/color-picker/COMPONENT.md +2 -2
- package/src/components/color-swatches/COMPONENT.md +1 -0
- package/src/components/datepicker/COMPONENT.md +1 -0
- package/src/components/dnd/COMPONENT.md +3 -3
- package/src/components/field-list/COMPONENT.md +164 -0
- package/src/components/field-list/examples/base-row.tsx +76 -0
- package/src/components/field-list/examples/controlled.tsx +72 -0
- package/src/components/field-list/examples/errors.tsx +85 -0
- package/src/components/field-list/examples/examples.module.css +34 -0
- package/src/components/field-list/examples/limits.tsx +55 -0
- package/src/components/field-list/examples/locked.tsx +139 -0
- package/src/components/field-list/examples/narrow.tsx +68 -0
- package/src/components/field-list/examples/overview.tsx +66 -0
- package/src/components/field-list/examples/reorder.tsx +42 -0
- package/src/components/field-list/examples/sizes.tsx +42 -0
- package/src/components/field-list/examples/states.tsx +51 -0
- package/src/components/input/examples/examples.module.css +2 -7
- package/src/components/kanban/COMPONENT.md +13 -9
- package/src/components/kanban/examples/limits.tsx +2 -1
- package/src/components/kanban/examples/variants.tsx +16 -8
- package/src/components/list/COMPONENT.md +1 -1
- package/src/components/media-viewer/COMPONENT.md +2 -2
- package/src/components/message/COMPONENT.md +2 -2
- package/src/components/notification/COMPONENT.md +1 -0
- package/src/components/page-content/COMPONENT.md +70 -14
- package/src/components/page-content/examples/grid.tsx +107 -0
- package/src/components/page-content/examples/overview.tsx +2 -2
- package/src/components/page-content/examples/sections.tsx +81 -0
- package/src/components/page-toolbar/COMPONENT.md +1 -1
- package/src/components/segmented-control/COMPONENT.md +1 -0
- package/src/components/select/COMPONENT.md +4 -2
- package/src/components/select/examples/icon-only.tsx +38 -0
- package/src/components/sparkline/COMPONENT.md +83 -30
- package/src/components/sparkline/examples/compact.tsx +1 -1
- package/src/components/sparkline/examples/curve.tsx +28 -0
- package/src/components/sparkline/examples/gaps.tsx +33 -0
- package/src/components/sparkline/examples/overview.tsx +11 -2
- package/src/components/sparkline/examples/period.tsx +7 -2
- package/src/components/sparkline/examples/reference.tsx +37 -0
- package/src/components/sparkline/examples/variants.tsx +2 -2
- package/src/components/tabs/examples/examples.module.css +0 -6
- package/src/components/tabs/examples/in-drawer.tsx +11 -13
- package/src/components/timeline/examples/examples.module.css +0 -8
- package/src/components/timeline/examples/narrow.tsx +2 -2
- package/src/components/timeline/examples/sizes.tsx +3 -3
- package/src/components/timeline/examples/variants.tsx +4 -4
- package/src/components/tooltip/COMPONENT.md +6 -4
- package/src/components/tooltip/examples/placement.tsx +2 -1
- package/src/components/video-note/COMPONENT.md +1 -1
- package/src/components/voice-player/COMPONENT.md +1 -1
- package/src/layout/app-header/examples/in-app-shell.tsx +2 -2
- package/src/layout/app-shell/COMPONENT.md +1 -1
- package/src/layout/app-shell/examples/footer.tsx +2 -2
- package/src/layout/app-shell/examples/overview.tsx +2 -2
- package/src/layout/app-shell/examples/template.tsx +2 -2
- package/src/layout/bottom-nav/examples/floating-action.tsx +2 -2
- package/src/layout/bottom-nav/examples/floating.tsx +2 -2
- package/src/layout/bottom-nav/examples/in-app-shell.tsx +2 -2
- package/src/styles/theme-light.css +1 -0
|
@@ -78,21 +78,12 @@ export default function SettingsPagePattern() {
|
|
|
78
78
|
</PageContent.Description>
|
|
79
79
|
</PageContent.Header>
|
|
80
80
|
<PageContent.Body>
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
Попадают в счета, акты и письма клиентам.
|
|
88
|
-
</Typography>
|
|
89
|
-
</div>
|
|
90
|
-
<form
|
|
91
|
-
className={styles.panel}
|
|
92
|
-
noValidate
|
|
93
|
-
onSubmit={save}
|
|
94
|
-
onReset={() => setInnError(undefined)}
|
|
95
|
-
>
|
|
81
|
+
<PageContent.Section
|
|
82
|
+
layout="aside"
|
|
83
|
+
label="Компания"
|
|
84
|
+
description="Попадают в счета, акты и письма клиентам."
|
|
85
|
+
>
|
|
86
|
+
<form noValidate onSubmit={save} onReset={() => setInnError(undefined)}>
|
|
96
87
|
<Card.Root variant="panel">
|
|
97
88
|
<Card.Body>
|
|
98
89
|
<Fieldset disabled={saving}>
|
|
@@ -144,73 +135,61 @@ export default function SettingsPagePattern() {
|
|
|
144
135
|
</Card.Footer>
|
|
145
136
|
</Card.Root>
|
|
146
137
|
</form>
|
|
147
|
-
</
|
|
138
|
+
</PageContent.Section>
|
|
148
139
|
|
|
149
|
-
<
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
<Switch.Root
|
|
164
|
-
key={alert.name}
|
|
165
|
-
name={alert.name}
|
|
166
|
-
defaultChecked={alert.defaultChecked}
|
|
167
|
-
hint={alert.hint}
|
|
168
|
-
>
|
|
169
|
-
<Switch.Label>{alert.label}</Switch.Label>
|
|
170
|
-
</Switch.Root>
|
|
171
|
-
))}
|
|
172
|
-
</Fieldset>
|
|
173
|
-
</Card.Body>
|
|
174
|
-
</Card.Root>
|
|
175
|
-
</div>
|
|
176
|
-
</section>
|
|
177
|
-
|
|
178
|
-
<section className={styles.section} aria-labelledby="danger-title">
|
|
179
|
-
<div className={styles.lead}>
|
|
180
|
-
<Typography as="h2" variant="title-m" id="danger-title">
|
|
181
|
-
Рабочее пространство
|
|
182
|
-
</Typography>
|
|
183
|
-
<Typography variant="body-m" tone="secondary">
|
|
184
|
-
Действия, которые нельзя отменить.
|
|
185
|
-
</Typography>
|
|
186
|
-
</div>
|
|
187
|
-
<div className={styles.panel}>
|
|
188
|
-
<Card.Root variant="panel">
|
|
189
|
-
<Card.Body>
|
|
190
|
-
<div className={styles.danger}>
|
|
191
|
-
<div className={styles.dangerText}>
|
|
192
|
-
<Typography variant="title-s">Удалить пространство</Typography>
|
|
193
|
-
<Typography variant="body-s" tone="secondary">
|
|
194
|
-
Счета, клиенты и история будут удалены для всех участников.
|
|
195
|
-
</Typography>
|
|
196
|
-
</div>
|
|
197
|
-
<ConfirmDialog.Root
|
|
198
|
-
title="Удалить «Прайм Софт»?"
|
|
199
|
-
description="312 счетов, 48 клиентов и вся история удалятся без возможности восстановления."
|
|
200
|
-
confirmLabel="Удалить пространство"
|
|
201
|
-
onConfirm={removeWorkspace}
|
|
140
|
+
<PageContent.Section
|
|
141
|
+
layout="aside"
|
|
142
|
+
label="Уведомления"
|
|
143
|
+
description="Включаются сразу, без сохранения."
|
|
144
|
+
>
|
|
145
|
+
<Card.Root variant="panel">
|
|
146
|
+
<Card.Body>
|
|
147
|
+
<Fieldset aria-label="Уведомления">
|
|
148
|
+
{ALERTS.map((alert) => (
|
|
149
|
+
<Switch.Root
|
|
150
|
+
key={alert.name}
|
|
151
|
+
name={alert.name}
|
|
152
|
+
defaultChecked={alert.defaultChecked}
|
|
153
|
+
hint={alert.hint}
|
|
202
154
|
>
|
|
203
|
-
<
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
155
|
+
<Switch.Label>{alert.label}</Switch.Label>
|
|
156
|
+
</Switch.Root>
|
|
157
|
+
))}
|
|
158
|
+
</Fieldset>
|
|
159
|
+
</Card.Body>
|
|
160
|
+
</Card.Root>
|
|
161
|
+
</PageContent.Section>
|
|
162
|
+
|
|
163
|
+
<PageContent.Section
|
|
164
|
+
layout="aside"
|
|
165
|
+
label="Рабочее пространство"
|
|
166
|
+
description="Действия, которые нельзя отменить."
|
|
167
|
+
>
|
|
168
|
+
<Card.Root variant="panel">
|
|
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>
|
|
209
176
|
</div>
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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>
|
|
192
|
+
</PageContent.Section>
|
|
214
193
|
</PageContent.Body>
|
|
215
194
|
</PageContent.Root>
|
|
216
195
|
);
|
|
@@ -67,7 +67,7 @@ Avatar.Group overlapping row, gives its size to members
|
|
|
67
67
|
|
|
68
68
|
| Prop | Type | Default | Description |
|
|
69
69
|
|---|---|---|---|
|
|
70
|
-
| `status` | `"online" \| "offline" \| "away" \| "busy"` | — (required) | Presence state: green
|
|
70
|
+
| `status` | `"online" \| "offline" \| "away" \| "busy"` | — (required) | Presence state, told by shape and color: `online` a full green dot, `away` a warning crescent, `busy` a danger dot with a bar, `offline` a hollow gray ring. |
|
|
71
71
|
| `labels` | `Partial<AvatarStatusLabels>` | — | Accessible names of the states, see Labels. |
|
|
72
72
|
| `…rest` | `Omit<HTMLAttributes<HTMLSpanElement>, "children">` | — | `className` and the other span attributes. |
|
|
73
73
|
|
|
@@ -129,7 +129,7 @@ No keyboard interaction.
|
|
|
129
129
|
|
|
130
130
|
### ARIA
|
|
131
131
|
- `Avatar.Image` `alt`: empty when the name is written next to it, otherwise the name. Without a photo and without a name nearby, put `aria-label` on `Avatar.Root`.
|
|
132
|
-
- `Avatar.Status` is `role="img"` with `aria-label` from `labels`.
|
|
132
|
+
- `Avatar.Status` is `role="img"` with `aria-label` from `labels`. Every state has its own shape (full dot, crescent, dot with a bar, hollow ring), so presence never rests on color alone.
|
|
133
133
|
- `Avatar.Group` is `role="group"`; give it `aria-label`. Give `Avatar.Overflow` an `aria-label` («Ещё 3 участника»).
|
|
134
134
|
|
|
135
135
|
### Labels
|
|
@@ -148,8 +148,8 @@ No keyboard interaction.
|
|
|
148
148
|
| [overview.tsx](examples/overview.tsx) | A photo with initials underneath while it loads, and initials alone — `Avatar.Image`, `Avatar.Fallback`. |
|
|
149
149
|
| [variants.tsx](examples/variants.tsx) | Every palette hue of the fallback; derive it from a stable user id — `color`. |
|
|
150
150
|
| [sizes.tsx](examples/sizes.tsx) | Every diameter, 20 to 64 px; initials take 40% of it — `size`. |
|
|
151
|
-
| [states.tsx](examples/states.tsx) | A loaded photo, a broken URL that falls back to initials, and an icon fallback for a guest. |
|
|
152
|
-
| [presence.tsx](examples/presence.tsx) | A presence dot on the avatar edge
|
|
151
|
+
| [states.tsx](examples/states.tsx) | A loaded photo, a broken URL that falls back to initials, and an icon fallback for a guest — `Avatar.Image`, `Avatar.Fallback`. |
|
|
152
|
+
| [presence.tsx](examples/presence.tsx) | A presence dot on the avatar edge: each state has its own shape and color and is announced by its name — `Avatar.Status`, `labels`. |
|
|
153
153
|
| [team-group.tsx](examples/team-group.tsx) | Project members as an overlapping row with a «+N» cell; the group size goes to every member — `Avatar.Group`, `Avatar.Overflow`, `size`. |
|
|
154
154
|
| [src-from-state.tsx](examples/src-from-state.tsx) | A new photo source restarts loading; initials show until the new photo arrives — `src`. |
|
|
155
155
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** A presence dot on the avatar edge
|
|
1
|
+
/** A presence dot on the avatar edge: each state has its own shape and color and is announced by its name — `Avatar.Status`, `labels`. */
|
|
2
2
|
import { Avatar, Typography } from "prime-ui-kit";
|
|
3
3
|
|
|
4
4
|
import styles from "./examples.module.css";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** A loaded photo, a broken URL that falls back to initials, and an icon fallback for a guest. */
|
|
1
|
+
/** A loaded photo, a broken URL that falls back to initials, and an icon fallback for a guest — `Avatar.Image`, `Avatar.Fallback`. */
|
|
2
2
|
import { Avatar, Icon, Typography } from "prime-ui-kit";
|
|
3
3
|
|
|
4
4
|
const PHOTO = "https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=128&h=128&fit=crop";
|
|
@@ -46,7 +46,7 @@ Banner.Root <div>; variant, tone, size, placement
|
|
|
46
46
|
| `tone` | `"neutral" \| "accent" \| "success" \| "warning" \| "danger" \| "info"` | `"info"` | Semantic color of the message. |
|
|
47
47
|
| `size` | `"xs" \| "s" \| "m" \| "l" \| "xl"` | `"m"` | Spacing, icon and title follow the control tier; the description is one step smaller. |
|
|
48
48
|
| `placement` | `"inset" \| "page"` | `"inset"` | `inset` — rounded block in the flow or in a card; `page` — edge-to-edge strip above a page, content aligned to the page column. |
|
|
49
|
-
| `onDismiss` | `() => void` | — | Renders a close button (top-right, or last in `Banner.Actions`) and calls this on click; the parent unmounts the banner. |
|
|
49
|
+
| `onDismiss` | `() => void` | — | Renders a close button (top-right, or last in `Banner.Actions`) and calls this on click; the parent unmounts the banner, which closes up in place, and moves focus to a sensible place. |
|
|
50
50
|
| `labels` | `Partial<BannerLabels>` | — | Built-in strings, see Labels. |
|
|
51
51
|
| `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `className`, `role` (`alert`, `status`, `region`), `aria-label` and the other div attributes. |
|
|
52
52
|
|
|
@@ -117,7 +117,7 @@ Banner.Root <div>; variant, tone, size, placement
|
|
|
117
117
|
| dismissible | `onDismiss` | corner ghost Button (`xs`, `s` on `l` / `xl`), or the last outline Button in `Banner.Actions` |
|
|
118
118
|
| narrow | own width < 36rem (a banner with `Banner.Actions` is a size container) | actions move under the text |
|
|
119
119
|
|
|
120
|
-
No `open` prop: the parent mounts and unmounts the banner.
|
|
120
|
+
No `open` prop: the parent mounts and unmounts the banner. A mounted banner enters (a short fade and rise); an unmounted one closes up in place, so the content below glides up instead of jumping. To swap the banner for another block in the same spot (a «restore» button), wrap both in [Crossfade](../crossfade/COMPONENT.md).
|
|
121
121
|
|
|
122
122
|
## Layout & spacing
|
|
123
123
|
- `width: 100%`; text column capped at `--prime-layout-reading-max-width`.
|
|
@@ -134,7 +134,7 @@ No `open` prop: the parent mounts and unmounts the banner.
|
|
|
134
134
|
### ARIA
|
|
135
135
|
- The banner has no role of its own: give an error after an action `role="alert"`, a calm status `role="status"`, a page strip `role="region"` with `aria-label`.
|
|
136
136
|
- The icon is `aria-hidden`: the title carries the meaning, not the color.
|
|
137
|
-
- The close button is named by `labels.dismiss
|
|
137
|
+
- The close button is named by `labels.dismiss`. It leaves with the banner, so after dismissing the parent moves focus to a sensible place: the control that takes the banner's spot, or the next heading or action of the section (see `dismissible.tsx`).
|
|
138
138
|
|
|
139
139
|
### Labels
|
|
140
140
|
<!-- Generated from api.ts by `bun run docs:build`. Edit api.ts, not this section. -->
|
|
@@ -150,9 +150,9 @@ No `open` prop: the parent mounts and unmounts the banner.
|
|
|
150
150
|
| [variants.tsx](examples/variants.tsx) | Every treatment on every tone: soft by default, solid for urgent, outline for calm — `variant`, `tone`. |
|
|
151
151
|
| [sizes.tsx](examples/sizes.tsx) | Every tier: padding, icon and title follow the control tier, the description is one step smaller — `size`. |
|
|
152
152
|
| [structure.tsx](examples/structure.tsx) | Optional parts: a one-line title, a title with a description, and actions where the close button joins the row — `Banner.Description`, `Banner.Actions`, `onDismiss`. |
|
|
153
|
-
| [dismissible.tsx](examples/dismissible.tsx) | The parent owns visibility: the close button calls back and
|
|
153
|
+
| [dismissible.tsx](examples/dismissible.tsx) | The parent owns visibility: the close button calls back, the banner closes up and focus moves to the restore button; the button name comes from labels — `onDismiss`, `labels`. |
|
|
154
154
|
| [page-strip.tsx](examples/page-strip.tsx) | An edge-to-edge strip above a page and a rounded block inside a card — `placement`. |
|
|
155
|
-
| [narrow.tsx](examples/narrow.tsx) | Below 36rem of its own width the banner moves the actions under the text. |
|
|
155
|
+
| [narrow.tsx](examples/narrow.tsx) | Below 36rem of its own width the banner moves the actions under the text — `Banner.Actions`. |
|
|
156
156
|
|
|
157
157
|
## Mistakes
|
|
158
158
|
- A hand-made × next to the banner → pass `onDismiss`.
|
|
@@ -162,4 +162,4 @@ No `open` prop: the parent mounts and unmounts the banner.
|
|
|
162
162
|
|
|
163
163
|
## Related
|
|
164
164
|
- **Built from:** [Button](../button/COMPONENT.md) (close button), Icon (`action.close`)
|
|
165
|
-
- **See also:** [Notification](../notification/COMPONENT.md), [Hint](../hint/COMPONENT.md), [EmptyPage](../empty-page/COMPONENT.md), [Badge](../badge/COMPONENT.md)
|
|
165
|
+
- **See also:** [Crossfade](../crossfade/COMPONENT.md), [Notification](../notification/COMPONENT.md), [Hint](../hint/COMPONENT.md), [EmptyPage](../empty-page/COMPONENT.md), [Badge](../badge/COMPONENT.md)
|
|
@@ -1,18 +1,34 @@
|
|
|
1
|
-
/** The parent owns visibility: the close button calls back and
|
|
2
|
-
import { Banner, Button, Icon } from "prime-ui-kit";
|
|
1
|
+
/** The parent owns visibility: the close button calls back, the banner closes up and focus moves to the restore button; the button name comes from labels — `onDismiss`, `labels`. */
|
|
2
|
+
import { Banner, Button, Crossfade, Icon } from "prime-ui-kit";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
|
|
5
5
|
import styles from "./examples.module.css";
|
|
6
6
|
|
|
7
7
|
export default function BannerDismissibleExample() {
|
|
8
8
|
const [visible, setVisible] = React.useState(true);
|
|
9
|
+
const bannerRef = React.useRef<HTMLDivElement>(null);
|
|
10
|
+
const restoreRef = React.useRef<HTMLButtonElement>(null);
|
|
11
|
+
const toggled = React.useRef(false);
|
|
12
|
+
|
|
13
|
+
// The pressed button leaves with its block: focus goes to the control that takes its place.
|
|
14
|
+
React.useEffect(() => {
|
|
15
|
+
if (!toggled.current) return;
|
|
16
|
+
if (visible) bannerRef.current?.querySelector("button")?.focus();
|
|
17
|
+
else restoreRef.current?.focus();
|
|
18
|
+
}, [visible]);
|
|
19
|
+
|
|
20
|
+
const toggle = (next: boolean) => {
|
|
21
|
+
toggled.current = true;
|
|
22
|
+
setVisible(next);
|
|
23
|
+
};
|
|
9
24
|
|
|
10
25
|
return (
|
|
11
|
-
<
|
|
26
|
+
<Crossfade state={visible ? "banner" : "restore"} className={styles.region}>
|
|
12
27
|
{visible ? (
|
|
13
28
|
<Banner.Root
|
|
29
|
+
ref={bannerRef}
|
|
14
30
|
tone="accent"
|
|
15
|
-
onDismiss={() =>
|
|
31
|
+
onDismiss={() => toggle(false)}
|
|
16
32
|
labels={{ dismiss: "Скрыть объявление" }}
|
|
17
33
|
>
|
|
18
34
|
<Banner.Content>
|
|
@@ -24,15 +40,10 @@ export default function BannerDismissibleExample() {
|
|
|
24
40
|
</Banner.Content>
|
|
25
41
|
</Banner.Root>
|
|
26
42
|
) : (
|
|
27
|
-
<Button.Root
|
|
28
|
-
variant="outline"
|
|
29
|
-
tone="neutral"
|
|
30
|
-
className={styles.restore}
|
|
31
|
-
onClick={() => setVisible(true)}
|
|
32
|
-
>
|
|
43
|
+
<Button.Root ref={restoreRef} variant="outline" tone="neutral" onClick={() => toggle(true)}>
|
|
33
44
|
Вернуть баннер
|
|
34
45
|
</Button.Root>
|
|
35
46
|
)}
|
|
36
|
-
</
|
|
47
|
+
</Crossfade>
|
|
37
48
|
);
|
|
38
49
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Below 36rem of its own width the banner moves the actions under the text. */
|
|
1
|
+
/** Below 36rem of its own width the banner moves the actions under the text — `Banner.Actions`. */
|
|
2
2
|
import { Banner, Button, Icon } from "prime-ui-kit";
|
|
3
3
|
|
|
4
4
|
import styles from "./examples.module.css";
|
|
@@ -123,7 +123,7 @@ Root attributes: `data-size`, `data-collapsible` (`"true"` / `"false"`).
|
|
|
123
123
|
| [overview.tsx](examples/overview.tsx) | The path to this page: links to the levels above and the current page last — `href`, `current`. |
|
|
124
124
|
| [sizes.tsx](examples/sizes.tsx) | Every size tier; text and chevrons follow the control tier — `size`. |
|
|
125
125
|
| [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`. |
|
|
126
|
-
| [overflow.tsx](examples/overflow.tsx) | A long path: levels truncate, and in a 320px container the middle ones collapse into «…», which screen readers announce as hidden levels. |
|
|
126
|
+
| [overflow.tsx](examples/overflow.tsx) | A long path: levels truncate, and in a 320px container the middle ones collapse into «…», which screen readers announce as hidden levels — `Breadcrumb.Item`, `current`. |
|
|
127
127
|
| [ellipsis.tsx](examples/ellipsis.tsx) | Levels skipped on purpose shown as «…» with hidden text for screen readers — `Breadcrumb.Ellipsis`. |
|
|
128
128
|
|
|
129
129
|
## Mistakes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** A long path: levels truncate, and in a 320px container the middle ones collapse into «…», which screen readers announce as hidden levels. */
|
|
1
|
+
/** A long path: levels truncate, and in a 320px container the middle ones collapse into «…», which screen readers announce as hidden levels — `Breadcrumb.Item`, `current`. */
|
|
2
2
|
import { Breadcrumb } from "prime-ui-kit";
|
|
3
3
|
|
|
4
4
|
import styles from "./examples.module.css";
|
|
@@ -163,7 +163,7 @@ Card.Root asChild <a> or <button> (the only child) holding the pa
|
|
|
163
163
|
Without `asChild` a card is static: no hover, focus or press of its own. With it: `data-interactive` on the element.
|
|
164
164
|
|
|
165
165
|
## Layout & spacing
|
|
166
|
-
- Grid
|
|
166
|
+
- Cards on a page: one `PageContent.Grid` with a `PageContent.Cell span` per card (16 on both axes, the cards of a row share one height); a grid inside one block is the block's own `repeat(auto-fit, minmax(min(100%, 14rem), 1fr))`, gap `--prime-space-4`.
|
|
167
167
|
- Radius `--prime-card-radius`, no border. In `panel` and `list` the `Header` is a padded zone with a faint inset hairline below; in `stat-trend` it can pair a leading Badge or icon with a compact `Card.Value`.
|
|
168
168
|
- Padding `--prime-card-padding-m` (20); `Body` gap `--prime-card-gap` (16); fields inside `Body` 20 apart, one ladder step off the card.
|
|
169
169
|
- Depth comes from nesting (foundation §4): on the page — the AppShell panel is the page — a card is layer 1 (white in light) with the raised whisper; inside another card it is the next layer, a flat tile. The ladder stops at layer 4.
|
|
@@ -196,11 +196,11 @@ No `labels`.
|
|
|
196
196
|
| [overview.tsx](examples/overview.tsx) | A company settings panel: a header, fields on the surface fill and buttons in the footer — `Card.Header`, `Card.Body`, `Card.Footer`. |
|
|
197
197
|
| [variants.tsx](examples/variants.tsx) | KPI templates: an icon tile with a value, a badge with a value in the header row, and a large value with its change and a reference line — `variant`, `Card.Delta`, `Card.Meta`. |
|
|
198
198
|
| [kpi-media.tsx](examples/kpi-media.tsx) | A KPI with a sparkline or a fill level in the bottom slot of `mini` — `Card.Media`. |
|
|
199
|
-
| [panel-chart.tsx](examples/panel-chart.tsx) | A chart widget: a header with a short description and a period switch, a
|
|
199
|
+
| [panel-chart.tsx](examples/panel-chart.tsx) | A chart widget: a header with a short description and a period switch, and a Sparkline with the period total over its chart — `Card.Header`, `Card.Description`, `Card.Body`. |
|
|
200
200
|
| [interactive.tsx](examples/interactive.tsx) | Whole cards as links to their reports: one tab stop each, a lift on hover, a press and the focus ring — `asChild`. |
|
|
201
201
|
| [content-templates.tsx](examples/content-templates.tsx) | Content templates: a call to action, an events list and a campaign tile with a cover — `Card.Footer`, `Card.List`, `Card.Media`. |
|
|
202
202
|
| [flat.tsx](examples/flat.tsx) | A flat tile without the raised shadow next to the default one, for dense grids — `flat`. |
|
|
203
|
-
| [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
|
|
203
|
+
| [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`. |
|
|
204
204
|
|
|
205
205
|
## Mistakes
|
|
206
206
|
- A `<div>` with a border styled as a card → use `Card.Root`; depth comes from fill, not lines.
|
|
@@ -209,10 +209,11 @@ No `labels`.
|
|
|
209
209
|
- Custom padding on a `panel` root → padding belongs to `Header` / `Body` / `Footer`.
|
|
210
210
|
- A wrapper `<div>` around the label and the value of `mini` → put `Icon`, `Label`, `Value` straight into the root (or into a `split` cell); the template lays them out.
|
|
211
211
|
- A chart SVG with only a `viewBox` → give it a CSS height.
|
|
212
|
+
- A hand-drawn trend SVG in a chart widget → `Sparkline` in the `Body` (or `Media`); a chart with a legend and states → `ChartFrame`.
|
|
212
213
|
- A clickable `<div>` card with `onClick` → `asChild` with a real `<a href>` (Cmd-click, a new tab) or a `<button>`.
|
|
213
214
|
- Buttons or links inside an `asChild` card → nested interactive elements; move them out of the card.
|
|
214
215
|
- The reference figures written into `Card.Delta` or `Card.Label` → `Card.Meta`.
|
|
215
216
|
|
|
216
217
|
## Related
|
|
217
218
|
- **Built from:** —
|
|
218
|
-
- **See also:** [PageContent](../page-content/COMPONENT.md), [DescriptionList](../description-list/COMPONENT.md) (record details inside a `Card.Body`), [Fieldset](../fieldset/COMPONENT.md) (groups of fields inside a settings card), [DataTable](../data-table/COMPONENT.md), [Badge](../badge/COMPONENT.md), [ProgressBar](../progress-bar/COMPONENT.md), [SegmentedControl](../segmented-control/COMPONENT.md)
|
|
219
|
+
- **See also:** [PageContent](../page-content/COMPONENT.md), [DescriptionList](../description-list/COMPONENT.md) (record details inside a `Card.Body`), [Fieldset](../fieldset/COMPONENT.md) (groups of fields inside a settings card), [DataTable](../data-table/COMPONENT.md), [Badge](../badge/COMPONENT.md), [ProgressBar](../progress-bar/COMPONENT.md), [SegmentedControl](../segmented-control/COMPONENT.md), [Sparkline](../sparkline/COMPONENT.md) (a trend with its total inside a `panel`), [ChartFrame](../chart-frame/COMPONENT.md) (a full chart with legend and states)
|
|
@@ -28,34 +28,6 @@
|
|
|
28
28
|
width: min(100%, calc(var(--prime-space-24) * 6));
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
/* Sparkline: fixed height from tokens, stretches to the card width. */
|
|
32
|
-
.spark {
|
|
33
|
-
display: block;
|
|
34
|
-
width: 100%;
|
|
35
|
-
height: var(--prime-space-10);
|
|
36
|
-
color: var(--prime-color-accent-default);
|
|
37
|
-
overflow: visible;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.chart {
|
|
41
|
-
display: block;
|
|
42
|
-
width: 100%;
|
|
43
|
-
/* Fixed height: a viewBox-only SVG would otherwise scale to a square of the card width. */
|
|
44
|
-
height: calc(var(--prime-space-24) * 2);
|
|
45
|
-
color: var(--prime-color-accent-default);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
.chartFill {
|
|
49
|
-
fill: var(--prime-color-accent-soft);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.chartLine {
|
|
53
|
-
fill: none;
|
|
54
|
-
stroke: currentColor;
|
|
55
|
-
stroke-width: calc(2 * var(--prime-border-width));
|
|
56
|
-
vector-effect: non-scaling-stroke;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
31
|
.cover {
|
|
60
32
|
background: linear-gradient(
|
|
61
33
|
135deg,
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
/** A KPI with a sparkline or a fill level in the bottom slot of `mini` — `Card.Media`. */
|
|
2
|
-
import { Card, Icon, ProgressBar } from "prime-ui-kit";
|
|
2
|
+
import { Card, Icon, ProgressBar, Sparkline, type SparklinePoint } from "prime-ui-kit";
|
|
3
3
|
|
|
4
4
|
import styles from "./examples.module.css";
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const REQUESTS: SparklinePoint[] = [
|
|
7
|
+
{ label: "12:00", value: 9_120 },
|
|
8
|
+
{ label: "12:10", value: 9_640 },
|
|
9
|
+
{ label: "12:20", value: 9_380 },
|
|
10
|
+
{ label: "12:30", value: 10_910 },
|
|
11
|
+
{ label: "12:40", value: 10_470 },
|
|
12
|
+
{ label: "12:50", value: 11_760 },
|
|
13
|
+
{ label: "13:00", value: 11_290 },
|
|
14
|
+
{ label: "13:10", value: 12_310 },
|
|
15
|
+
{ label: "13:20", value: 12_840 },
|
|
16
|
+
];
|
|
7
17
|
|
|
8
18
|
export default function CardKpiMediaExample() {
|
|
9
19
|
return (
|
|
@@ -15,15 +25,7 @@ export default function CardKpiMediaExample() {
|
|
|
15
25
|
<Card.Label>Запросы в минуту</Card.Label>
|
|
16
26
|
<Card.Value>12 840</Card.Value>
|
|
17
27
|
<Card.Media>
|
|
18
|
-
|
|
19
|
-
<svg
|
|
20
|
-
className={styles.spark}
|
|
21
|
-
viewBox="0 0 120 40"
|
|
22
|
-
preserveAspectRatio="none"
|
|
23
|
-
aria-hidden="true"
|
|
24
|
-
>
|
|
25
|
-
<path d={SPARKLINE} className={styles.chartLine} />
|
|
26
|
-
</svg>
|
|
28
|
+
<Sparkline layout="compact" data={REQUESTS} label="Запросы в минуту за час" />
|
|
27
29
|
</Card.Media>
|
|
28
30
|
</Card.Root>
|
|
29
31
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** The card is a size container: the split template stacks its cells below 22rem and the trend value shrinks below 20rem
|
|
1
|
+
/** The card is a size container: the split template stacks its cells below 22rem and the trend value shrinks below 20rem — `variant`. */
|
|
2
2
|
import { Card, Icon } from "prime-ui-kit";
|
|
3
3
|
|
|
4
4
|
import styles from "./examples.module.css";
|
|
@@ -1,43 +1,66 @@
|
|
|
1
|
-
/** A chart widget: a header with a short description and a period switch, a
|
|
2
|
-
import { Card, SegmentedControl,
|
|
1
|
+
/** A chart widget: a header with a short description and a period switch, and a Sparkline with the period total over its chart — `Card.Header`, `Card.Description`, `Card.Body`. */
|
|
2
|
+
import { Card, SegmentedControl, Sparkline, type SparklinePoint } from "prime-ui-kit";
|
|
3
|
+
import * as React from "react";
|
|
3
4
|
|
|
4
5
|
import styles from "./examples.module.css";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
type Period = "week" | "month";
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const REVENUE: Record<Period, SparklinePoint[]> = {
|
|
10
|
+
week: [
|
|
11
|
+
{ label: "6 окт", value: 412_000 },
|
|
12
|
+
{ label: "7 окт", value: 468_000 },
|
|
13
|
+
{ label: "8 окт", value: 445_000 },
|
|
14
|
+
{ label: "9 окт", value: 603_000 },
|
|
15
|
+
{ label: "10 окт", value: 581_000 },
|
|
16
|
+
{ label: "11 окт", value: 214_000 },
|
|
17
|
+
{ label: "12 окт", value: 187_000 },
|
|
18
|
+
],
|
|
19
|
+
month: [
|
|
20
|
+
{ label: "сен, 1 нед.", value: 2_480_000 },
|
|
21
|
+
{ label: "сен, 2 нед.", value: 2_760_000 },
|
|
22
|
+
{ label: "сен, 3 нед.", value: 2_610_000 },
|
|
23
|
+
{ label: "сен, 4 нед.", value: 3_140_000 },
|
|
24
|
+
{ label: "окт, 1 нед.", value: 2_910_000 },
|
|
25
|
+
],
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** The same total for the period before: the badge at rest compares the headline with it. */
|
|
29
|
+
const PREVIOUS: Record<Period, number> = {
|
|
30
|
+
week: 2_640_000,
|
|
31
|
+
month: 12_900_000,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const formatRubles = (value: number) => `${value.toLocaleString("ru-RU")} ₽`;
|
|
12
35
|
|
|
13
36
|
export default function CardPanelChartExample() {
|
|
37
|
+
const [period, setPeriod] = React.useState<Period>("month");
|
|
38
|
+
|
|
14
39
|
return (
|
|
15
40
|
<div className={styles.panel}>
|
|
16
41
|
<Card.Root variant="panel">
|
|
17
42
|
<Card.Header>
|
|
18
43
|
<Card.Title>Выручка</Card.Title>
|
|
19
44
|
<Card.Description>Оплаченные счета, без возвратов</Card.Description>
|
|
20
|
-
<SegmentedControl.Root
|
|
45
|
+
<SegmentedControl.Root
|
|
46
|
+
size="xs"
|
|
47
|
+
value={period}
|
|
48
|
+
onValueChange={(value) => setPeriod(value as Period)}
|
|
49
|
+
aria-label="Период"
|
|
50
|
+
>
|
|
21
51
|
<SegmentedControl.Item value="week">Неделя</SegmentedControl.Item>
|
|
22
52
|
<SegmentedControl.Item value="month">Месяц</SegmentedControl.Item>
|
|
23
53
|
</SegmentedControl.Root>
|
|
24
54
|
</Card.Header>
|
|
25
55
|
<Card.Body>
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
56
|
+
<Sparkline
|
|
57
|
+
data={REVENUE[period]}
|
|
58
|
+
label="Оплачено за период"
|
|
59
|
+
summary="sum"
|
|
60
|
+
compareTo={PREVIOUS[period]}
|
|
61
|
+
formatValue={formatRubles}
|
|
62
|
+
/>
|
|
29
63
|
</Card.Body>
|
|
30
|
-
<Card.Media>
|
|
31
|
-
<svg
|
|
32
|
-
className={styles.chart}
|
|
33
|
-
viewBox="0 0 100 100"
|
|
34
|
-
preserveAspectRatio="none"
|
|
35
|
-
aria-hidden="true"
|
|
36
|
-
>
|
|
37
|
-
<path className={styles.chartFill} d={`${LINE} L100 100 L0 100 Z`} />
|
|
38
|
-
<path className={styles.chartLine} d={LINE} />
|
|
39
|
-
</svg>
|
|
40
|
-
</Card.Media>
|
|
41
64
|
</Card.Root>
|
|
42
65
|
</div>
|
|
43
66
|
);
|