prime-ui-kit 0.9.1 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -12
- package/dist/chunks/{chunk-NHOWNIAR.js → chunk-6JTZOA5I.js} +1472 -671
- package/dist/chunks/{chunk-DB2Y3XXA.js → chunk-OAE4IQX2.js} +2845 -1732
- package/dist/chunks/{chunk-KCQFOORX.js → chunk-U5SR2LZR.js} +17 -4
- package/dist/color-picker.js +2 -2
- package/dist/components/button/Button.d.ts +19 -2
- package/dist/components/card/Card.d.ts +1 -1
- package/dist/components/code-block/CodeBlock.d.ts +1 -1
- package/dist/components/color-picker/ColorPicker.d.ts +1 -1
- package/dist/components/data-table/DataTable.d.ts +6 -1
- package/dist/components/data-table/Row.d.ts +3 -1
- package/dist/components/data-table/rows.d.ts +4 -0
- package/dist/components/data-table/types.d.ts +5 -0
- package/dist/components/digit-input/DigitInput.d.ts +6 -1
- package/dist/components/dnd/Dnd.d.ts +1 -1
- package/dist/components/dnd/dragSession.d.ts +9 -0
- package/dist/components/dnd/useDropTarget.d.ts +5 -0
- package/dist/components/dnd/useFlipList.d.ts +3 -3
- package/dist/components/drawer/Drawer.d.ts +8 -5
- package/dist/components/dropdown/Dropdown.d.ts +17 -0
- package/dist/components/index.d.ts +9 -2
- package/dist/components/input/Input.d.ts +16 -1
- package/dist/components/input/passwordStrength.d.ts +9 -0
- package/dist/components/kanban/Kanban.d.ts +129 -0
- package/dist/components/modal/Modal.d.ts +5 -2
- package/dist/components/page-toolbar/PageToolbar.d.ts +53 -0
- package/dist/components/progress-bar/ProgressBar.d.ts +16 -1
- package/dist/components/segmented-control/SegmentedControl.d.ts +5 -2
- package/dist/components/sparkline/Sparkline.d.ts +26 -0
- package/dist/components/tabs/Tabs.d.ts +5 -2
- package/dist/hooks/useEdgeOverflow.d.ts +16 -0
- package/dist/hooks/useMediaQuery.d.ts +7 -0
- package/dist/hooks/useSwipeDismiss.d.ts +34 -0
- package/dist/icons/registry.d.ts +2 -0
- package/dist/index.css +2977 -1306
- package/dist/index.d.ts +1 -0
- package/dist/index.js +17 -3
- package/dist/internal/CheckMark.d.ts +12 -0
- package/dist/internal/MorphText.d.ts +12 -0
- package/dist/internal/RollingNumber.d.ts +14 -0
- package/dist/internal/overlay/FloatingPanel.d.ts +3 -1
- package/dist/internal/overlay/useFloatingLayer.d.ts +11 -1
- package/dist/internal/surfaceDepth.d.ts +25 -0
- package/dist/internal/swatch.d.ts +4 -1
- package/dist/internal/touchTarget.d.ts +4 -0
- package/dist/layout/app-header/AppHeader.d.ts +110 -0
- package/dist/layout/app-shell/AppShell.d.ts +16 -11
- package/dist/layout/bottom-nav/BottomNav.d.ts +80 -0
- package/dist/layout/index.d.ts +5 -1
- package/dist/motion/celebrate.d.ts +18 -0
- package/dist/tokens/layers.d.ts +37 -0
- package/dist/tokens/naming.d.ts +1 -1
- package/dist/tokens/primitives.d.ts +4 -0
- package/dist/tokens/semantic.d.ts +122 -56
- package/dist/tokens/themes/dark.d.ts +10 -14
- package/package.json +3 -2
- package/src/components/accordion/COMPONENT.md +5 -5
- package/src/components/avatar/COMPONENT.md +1 -1
- package/src/components/badge/COMPONENT.md +2 -2
- package/src/components/banner/COMPONENT.md +1 -1
- package/src/components/button/COMPONENT.md +26 -5
- package/src/components/button/examples/download.tsx +45 -0
- package/src/components/button/examples/hold-to-confirm.tsx +23 -0
- package/src/components/button/examples/label-morph.tsx +33 -0
- package/src/components/card/COMPONENT.md +4 -2
- package/src/components/card/examples/narrow.tsx +2 -2
- package/src/components/card/examples/panel-chart.tsx +1 -1
- package/src/components/card/examples/variants.tsx +1 -1
- package/src/components/checkbox/examples/examples.module.css +5 -3
- package/src/components/code-block/COMPONENT.md +6 -6
- package/src/components/code-block/examples/overview.tsx +1 -1
- package/src/components/code-block/examples/variants.tsx +1 -1
- package/src/components/color-picker/COMPONENT.md +1 -1
- package/src/components/color-swatches/COMPONENT.md +5 -5
- package/src/components/command-menu/COMPONENT.md +1 -1
- package/src/components/crossfade/COMPONENT.md +1 -1
- package/src/components/crossfade/examples/overview.tsx +3 -3
- package/src/components/data-table/COMPONENT.md +24 -10
- package/src/components/data-table/examples/columns-visibility.tsx +167 -0
- package/src/components/digit-input/COMPONENT.md +15 -13
- package/src/components/digit-input/examples/examples.module.css +8 -0
- package/src/components/digit-input/examples/in-form.tsx +2 -5
- package/src/components/digit-input/examples/on-complete.tsx +7 -6
- package/src/components/digit-input/examples/sizes.tsx +1 -1
- package/src/components/divider/COMPONENT.md +1 -1
- package/src/components/dnd/COMPONENT.md +3 -3
- package/src/components/dnd/examples/examples.module.css +4 -4
- package/src/components/drawer/COMPONENT.md +17 -9
- package/src/components/drawer/examples/date-sheet.tsx +41 -0
- package/src/components/drawer/examples/examples.module.css +5 -0
- package/src/components/drawer/examples/placement.tsx +4 -2
- package/src/components/dropdown/COMPONENT.md +20 -6
- package/src/components/dropdown/examples/checkbox-items.tsx +48 -0
- package/src/components/dropdown/examples/examples.module.css +1 -1
- package/src/components/empty-page/COMPONENT.md +1 -1
- package/src/components/empty-page/examples/examples.module.css +1 -1
- package/src/components/example-frame/COMPONENT.md +1 -1
- package/src/components/input/COMPONENT.md +10 -1
- package/src/components/input/examples/password-strength.tsx +12 -0
- package/src/components/kanban/COMPONENT.md +181 -0
- package/src/components/kanban/examples/controlled.tsx +78 -0
- package/src/components/kanban/examples/examples.module.css +31 -0
- package/src/components/kanban/examples/limits.tsx +58 -0
- package/src/components/kanban/examples/narrow.tsx +76 -0
- package/src/components/kanban/examples/overview.tsx +130 -0
- package/src/components/kanban/examples/states.tsx +75 -0
- package/src/components/kanban/examples/structure.tsx +76 -0
- package/src/components/login-form/COMPONENT.md +5 -5
- package/src/components/login-form/examples/register.tsx +2 -2
- package/src/components/login-form/examples/reset-password.tsx +2 -2
- package/src/components/modal/COMPONENT.md +11 -8
- package/src/components/modal/examples/examples.module.css +2 -2
- package/src/components/notification/COMPONENT.md +2 -2
- package/src/components/page-content/COMPONENT.md +1 -1
- package/src/components/page-content/examples/examples.module.css +1 -1
- package/src/components/page-toolbar/COMPONENT.md +142 -0
- package/src/components/page-toolbar/examples/examples.module.css +16 -0
- package/src/components/page-toolbar/examples/narrow.tsx +103 -0
- package/src/components/page-toolbar/examples/overview.tsx +113 -0
- package/src/components/page-toolbar/examples/save-changes.tsx +40 -0
- package/src/components/page-toolbar/examples/without-search.tsx +60 -0
- package/src/components/popover/COMPONENT.md +5 -4
- package/src/components/progress-bar/COMPONENT.md +6 -2
- package/src/components/progress-bar/examples/examples.module.css +7 -0
- package/src/components/progress-bar/examples/milestone.tsx +43 -0
- package/src/components/progress-bar/examples/steps.tsx +35 -0
- package/src/components/progress-circle/COMPONENT.md +1 -1
- package/src/components/scroll-container/COMPONENT.md +1 -1
- package/src/components/segmented-control/COMPONENT.md +8 -8
- package/src/components/segmented-control/examples/full-width.tsx +1 -1
- package/src/components/select/COMPONENT.md +2 -1
- package/src/components/skeleton/COMPONENT.md +1 -1
- package/src/components/skeleton/examples/with-crossfade.tsx +3 -3
- package/src/components/smart-filter/COMPONENT.md +2 -0
- package/src/components/sparkline/COMPONENT.md +98 -0
- package/src/components/sparkline/examples/examples.module.css +13 -0
- package/src/components/sparkline/examples/overview.tsx +27 -0
- package/src/components/sparkline/examples/period.tsx +46 -0
- package/src/components/spinner/COMPONENT.md +1 -1
- package/src/components/tabs/COMPONENT.md +24 -22
- package/src/components/tabs/examples/closable.tsx +1 -1
- package/src/components/tabs/examples/examples.module.css +14 -0
- package/src/components/tabs/examples/orientation.tsx +87 -33
- package/src/components/tooltip/COMPONENT.md +8 -6
- package/src/components/tooltip/examples/examples.module.css +2 -2
- package/src/layout/app-header/COMPONENT.md +178 -0
- package/src/layout/app-header/examples/breadcrumbs.tsx +36 -0
- package/src/layout/app-header/examples/examples.module.css +47 -0
- package/src/layout/app-header/examples/in-app-shell.tsx +70 -0
- package/src/layout/app-header/examples/narrow.tsx +29 -0
- package/src/layout/app-header/examples/overview.tsx +36 -0
- package/src/layout/app-shell/COMPONENT.md +35 -29
- package/src/layout/app-shell/examples/examples.module.css +17 -2
- package/src/layout/app-shell/examples/footer.tsx +59 -0
- package/src/layout/app-shell/examples/overview.tsx +19 -8
- package/src/layout/bottom-nav/COMPONENT.md +153 -0
- package/src/layout/bottom-nav/examples/examples.module.css +39 -0
- package/src/layout/bottom-nav/examples/floating.tsx +89 -0
- package/src/layout/bottom-nav/examples/icon-only.tsx +41 -0
- package/src/layout/bottom-nav/examples/in-app-shell.tsx +64 -0
- package/src/layout/bottom-nav/examples/overview.tsx +44 -0
- package/src/layout/bottom-nav/examples/router.tsx +31 -0
- package/src/layout/bottom-nav/examples/structure.tsx +47 -0
- package/src/layout/sidebar/COMPONENT.md +14 -13
- package/src/layout/sidebar/examples/examples.module.css +5 -5
- package/src/styles/globals.css +125 -2
- package/src/styles/theme-dark.css +39 -13
- package/src/styles/theme-light.css +84 -16
- package/src/styles/tokens.css +2 -0
|
@@ -26,8 +26,8 @@ import { Tabs } from "prime-ui-kit";
|
|
|
26
26
|
|
|
27
27
|
## Anatomy
|
|
28
28
|
```
|
|
29
|
-
Tabs.Root value, size, orientation, tone, fullWidth, min/maxItemWidth;
|
|
30
|
-
├─ Tabs.List role="tablist" on a ScrollContainer, sliding folder
|
|
29
|
+
Tabs.Root value, size, orientation, tone, fullWidth, min/maxItemWidth; the frame (a layer)
|
|
30
|
+
├─ Tabs.List role="tablist" on a ScrollContainer, sliding folder; collapses, then scrolls
|
|
31
31
|
│ ├─ Tabs.Item one tab (role="tab") in an item wrapper; onRemove adds a close button; parts:
|
|
32
32
|
│ │ ├─ Tabs.Icon decorative icon; hidden first, kept last
|
|
33
33
|
│ │ ├─ Tabs.Label title; keeps its width when it turns medium weight
|
|
@@ -42,25 +42,25 @@ Tabs.Root value, size, orientation, tone, fullWidth, min/maxItem
|
|
|
42
42
|
<!-- Generated from api.ts by `bun run docs:build`. Edit api.ts, not this section. -->
|
|
43
43
|
|
|
44
44
|
### Tabs.Root
|
|
45
|
-
`ref` → `HTMLDivElement`. `<div>` that owns the active value, size and orientation and lays out the list and the panel
|
|
45
|
+
`ref` → `HTMLDivElement`. `<div>` that owns the active value, size and orientation and lays out the list and the panel. It is the frame and a layer of the surface ladder in both orientations: a strip two steps off the layer and the panel in the layer's own color — above the panel when horizontal, at its inline start when vertical.
|
|
46
46
|
|
|
47
47
|
| Prop | Type | Default | Description |
|
|
48
48
|
|---|---|---|---|
|
|
49
49
|
| `value` | `string` | — | Active tab (controlled). |
|
|
50
50
|
| `defaultValue` | `string` | `""` | Initial active tab (uncontrolled). With `""` no tab is selected. |
|
|
51
51
|
| `onValueChange` | `(value: string) => void` | — | Called with the new active value. |
|
|
52
|
-
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | List direction and arrow keys.
|
|
52
|
+
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | List direction and arrow keys. Vertical: a column of sections at the panel's inline start, the active one the panel reaching into the column; when the container is narrower than 600px the column becomes the horizontal strip above the panel. |
|
|
53
53
|
| `size` | `"xs" \| "s" \| "m" \| "l" \| "xl"` | `"m"` | Control tier: text, icon, spacing, folder radius and panel padding. A horizontal tab is the control height plus the folder rise on both sides; a vertical one is the control height. |
|
|
54
|
-
| `fullWidth` | `boolean` | `true` | Horizontal tabs
|
|
54
|
+
| `fullWidth` | `boolean` | `true` | Horizontal tabs fill the list and tend to equal widths within `minItemWidth` … `maxItemWidth`, never narrower than their content: a long label keeps its width, short ones share the rest; when they do not fit, the list collapses, then scrolls. `false` sizes each tab to its content within the same bounds. |
|
|
55
55
|
| `tone` | `"neutral" \| "accent"` | `"neutral"` | Colour of the active tab: `neutral` is primary text with an accent icon, `accent` puts text and icon in accent. |
|
|
56
|
-
| `minItemWidth` | `number \| string` | `2.5 × control height` | Narrowest a horizontal tab with a label gets, px or a CSS length;
|
|
56
|
+
| `minItemWidth` | `number \| string` | `2.5 × control height` | Narrowest a horizontal tab with a label gets, px or a CSS length; a tab is also never narrower than its content (up to `maxItemWidth`). When tabs do not fit, the list collapses, then scrolls. Icon-only tabs are square. |
|
|
57
57
|
| `maxItemWidth` | `number \| string` | `7 × control height` | Widest a horizontal tab gets, px or a CSS length (`"none"` lifts the cap); a longer label ends with an ellipsis. |
|
|
58
58
|
| `labels` | `Partial<TabsLabels>` | — | Built-in strings, see Labels. |
|
|
59
59
|
| `children` | `ReactNode` | — | `Tabs.List` and `Tabs.Panel`s. |
|
|
60
60
|
| `…rest` | `Omit<HTMLAttributes<HTMLDivElement>, "defaultValue">` | — | `className` and the other div attributes. |
|
|
61
61
|
|
|
62
62
|
### Tabs.List
|
|
63
|
-
`ref` → `HTMLDivElement`. `role="tablist"` on a `ScrollContainer` (horizontal, edge fade, hidden scrollbar) with the sliding folder (
|
|
63
|
+
`ref` → `HTMLDivElement`. `role="tablist"` on a `ScrollContainer` (horizontal, edge fade, hidden scrollbar) with the sliding folder (in both orientations), which glides only into a choice by click or keys and is placed without motion on mount, resize and collapse. When tabs do not fit or a label would be cut, it hides icons and descriptions, then labels (icons with tooltips stay; only when every tab has an icon); then the list scrolls; a label is never cut to make room. The active tab is kept in view and clear of the edge fades (the first and the last tab scroll all the way to the end); only the list scrolls, never the page.
|
|
64
64
|
|
|
65
65
|
| Prop | Type | Default | Description |
|
|
66
66
|
|---|---|---|---|
|
|
@@ -128,7 +128,7 @@ Tabs.Root value, size, orientation, tone, fullWidth, min/maxItem
|
|
|
128
128
|
| `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `className` and the other div attributes. |
|
|
129
129
|
|
|
130
130
|
## Variants
|
|
131
|
-
Tabs have no `variant`: navigation tabs are always a folder (horizontal) or
|
|
131
|
+
Tabs have no `variant`: navigation tabs are always a folder — rising from the panel's top edge (horizontal) or reaching out of its side (vertical).
|
|
132
132
|
|
|
133
133
|
### tone
|
|
134
134
|
| Value | Looks like | Use when | Default |
|
|
@@ -139,8 +139,8 @@ Tabs have no `variant`: navigation tabs are always a folder (horizontal) or pill
|
|
|
139
139
|
### orientation
|
|
140
140
|
| Value | Looks like | Use when | Default |
|
|
141
141
|
|---|---|---|---|
|
|
142
|
-
| `horizontal` | a `
|
|
143
|
-
| `vertical` |
|
|
142
|
+
| `horizontal` | a layer of the surface ladder: a `fill-muted-hover` strip (two steps off the layer) over a padded panel in the layer's own color, tabs edge to edge; the active tab is the panel rising into the strip with concave flares, gliding between tabs; primary text, medium weight, accent icon; hover is the same shape in `fill-faint` | switching sections above the content | yes |
|
|
143
|
+
| `vertical` | the same folder on its side: a column of sections in the `fill-muted-hover` strip at the panel's inline start; the active section is the panel reaching into the column, rounded on the outer side, with concave flares above and below where it meets the panel; hover is the same shape in `fill-faint`. Below a 600px container the column becomes the horizontal strip above the panel (it scrolls, never wraps) | settings pages with a side list of sections | |
|
|
144
144
|
|
|
145
145
|
### size
|
|
146
146
|
| Value | Looks like | Use when | Default |
|
|
@@ -156,13 +156,13 @@ A horizontal tab is the control height of the tier plus the rise above and below
|
|
|
156
156
|
### Flags
|
|
157
157
|
| Value | Looks like | Use when | Default |
|
|
158
158
|
|---|---|---|---|
|
|
159
|
-
| `fullWidth` | horizontal tabs
|
|
159
|
+
| `fullWidth` | horizontal tabs fill the list and tend to equal widths (`flex: 1 1 0`, up to `maxItemWidth`), content centred; a tab is never narrower than its content or `minItemWidth`, so a long label keeps its width and the short ones share the rest; `false` sizes each tab to its content, the strip still spans the frame | `false` for tabs of very different label lengths | `true` |
|
|
160
160
|
|
|
161
161
|
### minItemWidth · maxItemWidth
|
|
162
162
|
| Value | Looks like | Use when | Default |
|
|
163
163
|
|---|---|---|---|
|
|
164
164
|
| defaults | a horizontal tab is 2.5 to 7 control heights wide (90 … 252 at `m`); tabs never stretch into wide bars | most screens | yes |
|
|
165
|
-
| lengths (`128`, `"16rem"`) | browser tabs: grow up to `maxItemWidth` with the label cut by an ellipsis past it,
|
|
165
|
+
| lengths (`128`, `"16rem"`) | browser tabs: grow up to `maxItemWidth` with the label cut by an ellipsis past it, never narrower than `minItemWidth` or their title up to the cap; in a crowded list the list scrolls | open documents, records, chats — many tabs with long titles | |
|
|
166
166
|
| `maxItemWidth="none"` | tabs share the whole strip | a few sections that must fill a wide frame | |
|
|
167
167
|
|
|
168
168
|
### Item content
|
|
@@ -180,23 +180,25 @@ Avoid icons or descriptions on only some tabs (uneven rows; without an icon on e
|
|
|
180
180
|
| State | Driven by | DOM |
|
|
181
181
|
|---|---|---|
|
|
182
182
|
| active | `value` / `defaultValue` | item `aria-selected="true"`, `data-state="active"`, `tabIndex=0`; others `data-state="inactive"`, `tabIndex=-1` |
|
|
183
|
-
| hover | pointer | text → primary;
|
|
183
|
+
| hover | pointer | text → primary; the folder shape in `fill-faint`, under the folder |
|
|
184
184
|
| pressed | pointer down | the tab content scales to `--prime-motion-press-scale-compact` |
|
|
185
|
-
| focus-visible | keyboard | focus ring inside the tab, above the folder; the panel shows an inset ring
|
|
185
|
+
| focus-visible | keyboard | focus ring inside the tab, above the folder; the panel shows an inset ring |
|
|
186
186
|
| disabled | `disabled` on Item | native `disabled`, `data-disabled="true"`, `text-disabled`; a removable tab loses its close button |
|
|
187
187
|
| removable | `onRemove` on Item | item wrapper `data-removable="true"`, close button, tab `aria-keyshortcuts="Delete"` |
|
|
188
188
|
| two-line | `Tabs.Description` child | `data-two-line="true"` |
|
|
189
189
|
| collapsed | tabs wider than the list, or a label that would be cut (horizontal) | list `data-collapse="full" \| "compact" \| "icon"`: `compact` hides icons and descriptions; `icon` hides labels (sr-only, shown in a `Tooltip`), counts and close buttons, only when every tab has an icon |
|
|
190
|
-
| overflow | tabs at `minItemWidth`
|
|
190
|
+
| overflow | tabs at their narrowest (content width, `minItemWidth` or icon squares) still wider than the list | `data-overflow-start` / `data-overflow-end` on the list (ScrollContainer), faded edges as deep as the hidden part at most (they grow and melt with the scroll, never switch); the active tab is kept in view and clear of the fades on mount and on every value change, the first and the last tab scroll all the way to the end — only the list scrolls, never the page |
|
|
191
191
|
|
|
192
|
-
|
|
192
|
+
The indicator glides (`emphasized` + `base`, `data-animate="true"`) only into a choice by click, arrow keys or closing the active tab; on mount, a value set from outside, a resize, font loading, tabs added or removed and collapse it is placed without motion, and it stays still under `prefers-reduced-motion`. The list scrolls smoothly to the active tab only after such a choice too.
|
|
193
|
+
|
|
194
|
+
Other attributes: Root `data-orientation`, `data-size`, `data-tone`, `data-full-width`, inline `--tabs-item-min` / `--tabs-item-max` when set; List `data-indicator="folder"`, its indicator `data-axis="x" | "y"` (follows the list's direction, so a vertical list in a narrow container gets the top folder); Item `data-value` on the tab, `data-state` / `data-disabled` on its wrapper too; Label `data-text`. Inactive panels are unmounted; a panel's content enters each time it opens.
|
|
193
195
|
|
|
194
196
|
## Layout & spacing
|
|
195
|
-
-
|
|
196
|
-
- Vertical
|
|
197
|
-
- The list never wraps: it collapses, then scrolls horizontally with faded edges. Give the list's container a width (`min-width: 0` on flex children).
|
|
197
|
+
- The root is the frame and a layer of the ladder in both orientations (`data-depth`, `radius-xl`, the strip two steps off the layer); the list sits flush on the panel; the panel pads its content by tier (`--prime-space-4` … `--prime-space-8`). Do not wrap Tabs in a Card — it already is one.
|
|
198
|
+
- Vertical: the column is as wide as its widest section (at least four control heights, at most 40% of the root), inset by the folder rise from the frame on the outer side, flush with the panel on the other.
|
|
199
|
+
- The list never wraps: it collapses, then scrolls horizontally with faded edges (hidden scrollbar, `overscroll-behavior: contain`). Give the list's container a width (`min-width: 0` on flex children).
|
|
200
|
+
- A horizontal tab is never narrower than its content (`min-width: max-content`; the tab bounds that content between `minItemWidth` and `maxItemWidth`), so a label is never cut to make room. Full width, tabs tend to equal widths, not widths in proportion to their labels (`flex: 1 1 0`): a long label keeps its width, the short ones share the rest.
|
|
198
201
|
- A vertical Tabs.Root is a size container: give it a width (it measures itself to switch to a row).
|
|
199
|
-
- In a vertical layout align the panel heading with the first tab by making the heading row one control tall (`min-height: var(--prime-control-m-height)`).
|
|
200
202
|
|
|
201
203
|
## Accessibility
|
|
202
204
|
|
|
@@ -232,9 +234,9 @@ Other attributes: Root `data-orientation`, `data-size`, `data-tone`, `data-full-
|
|
|
232
234
|
| [sizes.tsx](examples/sizes.tsx) | Every size tier: text, icon, folder radius and spacing grow together — `size`. |
|
|
233
235
|
| [states.tsx](examples/states.tsx) | A disabled tab that clicks and arrow keys skip — `disabled`. |
|
|
234
236
|
| [with-icon.tsx](examples/with-icon.tsx) | A muted icon before the label and a hairline before the service section — `Tabs.Icon`, `Tabs.Label`, `Tabs.Separator`. |
|
|
235
|
-
| [orientation.tsx](examples/orientation.tsx) |
|
|
237
|
+
| [orientation.tsx](examples/orientation.tsx) | Account settings with a side list of sections: the active section reaches out of the panel, and below 600px the list moves above it — `orientation`. |
|
|
236
238
|
| [overflow.tsx](examples/overflow.tsx) | Drag the frame narrower: icons go first, then labels, and icons with tooltips stay; then the list scrolls — `Tabs.Icon`. |
|
|
237
|
-
| [closable.tsx](examples/closable.tsx) | Open order cards as browser tabs: each closes by its button, Delete or a middle click; tabs stay between two widths and
|
|
239
|
+
| [closable.tsx](examples/closable.tsx) | Open order cards as browser tabs: each closes by its button, Delete or a middle click; tabs stay between two widths, and the list scrolls when they do not fit — `onRemove`, `minItemWidth`, `maxItemWidth`. |
|
|
238
240
|
| [two-line.tsx](examples/two-line.tsx) | A label and a counter on the first line, a summary on the second — `Tabs.Count`, `Tabs.Description`. |
|
|
239
241
|
| [controlled.tsx](examples/controlled.tsx) | The active tab lives in parent state, e.g. synced with the URL — `value`, `onValueChange`. |
|
|
240
242
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Open order cards as browser tabs: each closes by its button, Delete or a middle click; tabs stay between two widths and
|
|
1
|
+
/** Open order cards as browser tabs: each closes by its button, Delete or a middle click; tabs stay between two widths, and the list scrolls when they do not fit — `onRemove`, `minItemWidth`, `maxItemWidth`. */
|
|
2
2
|
import { Button, Tabs, Typography } from "prime-ui-kit";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
|
|
@@ -8,6 +8,20 @@
|
|
|
8
8
|
margin-inline: auto;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
/* A settings block: wide enough for the side list next to a form, never wider than the preview. */
|
|
12
|
+
.wide {
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
width: min(100%, calc(20 * var(--prime-control-m-height)));
|
|
15
|
+
margin-inline: auto;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Fields and switches of a settings section: field → field rhythm (foundation §1). */
|
|
19
|
+
.form {
|
|
20
|
+
display: grid;
|
|
21
|
+
gap: var(--prime-space-5);
|
|
22
|
+
max-width: calc(10 * var(--prime-control-m-height));
|
|
23
|
+
}
|
|
24
|
+
|
|
11
25
|
/* The same column, which the reader can drag narrower to watch the tabs collapse and scroll. */
|
|
12
26
|
.resizable {
|
|
13
27
|
composes: frame;
|
|
@@ -1,40 +1,94 @@
|
|
|
1
|
-
/**
|
|
2
|
-
import { Tabs, Typography } from "prime-ui-kit";
|
|
1
|
+
/** Account settings with a side list of sections: the active section reaches out of the panel, and below 600px the list moves above it — `orientation`. */
|
|
2
|
+
import { Button, Icon, Input, Switch, Tabs, Typography } from "prime-ui-kit";
|
|
3
3
|
|
|
4
4
|
import styles from "./examples.module.css";
|
|
5
5
|
|
|
6
|
-
const SECTIONS = [
|
|
7
|
-
{ value: "profile", label: "Профиль", text: "Имя, должность и контакты сотрудника." },
|
|
8
|
-
{ value: "notifications", label: "Уведомления", text: "Письма о заказах и еженедельная сводка." },
|
|
9
|
-
{ value: "deletion", label: "Удаление", text: "Аккаунт и все данные будут удалены." },
|
|
10
|
-
];
|
|
11
|
-
|
|
12
6
|
export default function TabsOrientationExample() {
|
|
13
7
|
return (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<Tabs.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
8
|
+
<Tabs.Root orientation="vertical" defaultValue="notifications" className={styles.wide}>
|
|
9
|
+
<Tabs.List aria-label="Настройки аккаунта">
|
|
10
|
+
<Tabs.Item value="profile">
|
|
11
|
+
<Tabs.Icon>
|
|
12
|
+
<Icon name="object.user" />
|
|
13
|
+
</Tabs.Icon>
|
|
14
|
+
<Tabs.Label>Профиль</Tabs.Label>
|
|
15
|
+
</Tabs.Item>
|
|
16
|
+
<Tabs.Item value="notifications">
|
|
17
|
+
<Tabs.Icon>
|
|
18
|
+
<Icon name="object.bell" />
|
|
19
|
+
</Tabs.Icon>
|
|
20
|
+
<Tabs.Label>Уведомления</Tabs.Label>
|
|
21
|
+
</Tabs.Item>
|
|
22
|
+
<Tabs.Item value="security">
|
|
23
|
+
<Tabs.Icon>
|
|
24
|
+
<Icon name="object.key" />
|
|
25
|
+
</Tabs.Icon>
|
|
26
|
+
<Tabs.Label>Безопасность</Tabs.Label>
|
|
27
|
+
</Tabs.Item>
|
|
28
|
+
<Tabs.Separator />
|
|
29
|
+
<Tabs.Item value="deletion">
|
|
30
|
+
<Tabs.Icon>
|
|
31
|
+
<Icon name="action.delete" />
|
|
32
|
+
</Tabs.Icon>
|
|
33
|
+
<Tabs.Label>Удаление</Tabs.Label>
|
|
34
|
+
</Tabs.Item>
|
|
35
|
+
</Tabs.List>
|
|
36
|
+
|
|
37
|
+
<Tabs.Panel value="profile">
|
|
38
|
+
<div className={styles.form}>
|
|
39
|
+
<Input.Root label="Имя и фамилия">
|
|
40
|
+
<Input.Wrapper>
|
|
41
|
+
<Input.Field defaultValue="Анна Смирнова" autoComplete="name" />
|
|
42
|
+
</Input.Wrapper>
|
|
43
|
+
</Input.Root>
|
|
44
|
+
<Input.Root label="Должность">
|
|
45
|
+
<Input.Wrapper>
|
|
46
|
+
<Input.Field defaultValue="Руководитель отдела продаж" />
|
|
47
|
+
</Input.Wrapper>
|
|
48
|
+
</Input.Root>
|
|
49
|
+
</div>
|
|
50
|
+
</Tabs.Panel>
|
|
51
|
+
|
|
52
|
+
<Tabs.Panel value="notifications">
|
|
53
|
+
<div className={styles.form}>
|
|
54
|
+
<Switch.Root defaultChecked hint="Письмо, как только заказ оплачен или отменён">
|
|
55
|
+
<Switch.Label>Статусы заказов</Switch.Label>
|
|
56
|
+
</Switch.Root>
|
|
57
|
+
<Switch.Root defaultChecked hint="По понедельникам в 09:00">
|
|
58
|
+
<Switch.Label>Сводка за неделю</Switch.Label>
|
|
59
|
+
</Switch.Root>
|
|
60
|
+
<Switch.Root hint="Новые функции и вебинары">
|
|
61
|
+
<Switch.Label>Новости продукта</Switch.Label>
|
|
62
|
+
</Switch.Root>
|
|
63
|
+
</div>
|
|
64
|
+
</Tabs.Panel>
|
|
65
|
+
|
|
66
|
+
<Tabs.Panel value="security">
|
|
67
|
+
<div className={styles.form}>
|
|
68
|
+
<Input.Root label="Новый пароль" hint="Не короче 12 символов">
|
|
69
|
+
<Input.Wrapper>
|
|
70
|
+
<Input.Field type="password" autoComplete="new-password" />
|
|
71
|
+
</Input.Wrapper>
|
|
72
|
+
</Input.Root>
|
|
73
|
+
<Switch.Root defaultChecked hint="Код из приложения при каждом входе">
|
|
74
|
+
<Switch.Label>Двухфакторная проверка</Switch.Label>
|
|
75
|
+
</Switch.Root>
|
|
76
|
+
</div>
|
|
77
|
+
</Tabs.Panel>
|
|
78
|
+
|
|
79
|
+
<Tabs.Panel value="deletion">
|
|
80
|
+
<div className={styles.form}>
|
|
81
|
+
<Typography variant="body-m" tone="secondary">
|
|
82
|
+
Аккаунт и все данные будут удалены через 30 дней. До этого срока удаление можно
|
|
83
|
+
отменить.
|
|
84
|
+
</Typography>
|
|
85
|
+
<div>
|
|
86
|
+
<Button.Root tone="danger" variant="soft">
|
|
87
|
+
Удалить аккаунт
|
|
88
|
+
</Button.Root>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</Tabs.Panel>
|
|
92
|
+
</Tabs.Root>
|
|
39
93
|
);
|
|
40
94
|
}
|
|
@@ -74,16 +74,18 @@ No DOM: clones the single child, composes its `ref`, appends the tooltip id to i
|
|
|
74
74
|
| `…rest` | `Omit<HTMLAttributes<HTMLDivElement>, "id" \| "role" \| "onPointerEnter" \| "onPointerLeave">` | — | `className`, `style` and the other attributes of the chip. |
|
|
75
75
|
|
|
76
76
|
## Variants
|
|
77
|
-
Tooltip has no `variant` or `tone`: it is always a flat inverse chip (`tooltip-bg`, `tooltip-text`) with an arrow and no shadow, so it reads the same on
|
|
77
|
+
Tooltip has no `variant` or `tone`: it is always a flat inverse chip (`tooltip-bg`, `tooltip-text`) — dark in the light theme, light in the dark one — with an arrow and no shadow, so it reads the same on every layer. The chip is a host of its own: it points the text and fill roles at `tooltip-muted` / `tooltip-fill`, so a Kbd or a secondary line inside reads on it. Content flows inline: a label and its key stay on one line, block children stack. The arrow (`--prime-tooltip-arrow-width` × `--prime-tooltip-arrow-height`) always points at the trigger's centre, also after flipping, aligning or shifting, and never slides into the chip's rounded corner.
|
|
78
78
|
|
|
79
79
|
### size (Content)
|
|
80
|
+
A chip of tier T is as tall as a menu item of tier T; text, padding and radius step together (`--prime-tooltip-<tier>-*`).
|
|
81
|
+
|
|
80
82
|
| Value | Looks like | Use when | Default |
|
|
81
83
|
|---|---|---|---|
|
|
82
|
-
| `xs` |
|
|
83
|
-
| `s` |
|
|
84
|
-
| `m` |
|
|
85
|
-
| `l` |
|
|
86
|
-
| `xl` |
|
|
84
|
+
| `xs` | 12/16, padding 4 × 6, radius 4 — 24 tall | Next to xs controls | |
|
|
85
|
+
| `s` | 12/16, padding 6 × 8, radius 6 — 28 tall | Dense toolbars, s controls | |
|
|
86
|
+
| `m` | 13/20, padding 6 × 10, radius 6 — 32 tall | Most controls | yes |
|
|
87
|
+
| `l` | 14/20, padding 8 × 12, radius 8 — 36 tall | l controls, longer sentences | |
|
|
88
|
+
| `xl` | 16/24, padding 8 × 16, radius 8 — 40 tall | xl controls | |
|
|
87
89
|
|
|
88
90
|
### side (Content)
|
|
89
91
|
| Value | Looks like | Use when | Default |
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
gap: var(--prime-space-1);
|
|
8
8
|
padding: var(--prime-space-1);
|
|
9
9
|
border-radius: var(--prime-radius-l);
|
|
10
|
-
background: var(--prime-color-
|
|
11
|
-
box-shadow: var(--prime-
|
|
10
|
+
background: var(--prime-color-layer-nested);
|
|
11
|
+
box-shadow: var(--prime-shadow-raised);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/* disabled-trigger.tsx: a focusable wrapper around the disabled button, with the outer ring. */
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# AppHeader
|
|
2
|
+
|
|
3
|
+
**Category:** page
|
|
4
|
+
**Kind:** layout
|
|
5
|
+
|
|
6
|
+
> The bar at the top of the app's content panel: where you are, global search and a few actions.
|
|
7
|
+
|
|
8
|
+
## When to use
|
|
9
|
+
- The top row of an app built on [AppShell](../app-shell/COMPONENT.md): the section title or the path, the ⌘K search entry, notifications, the account, one primary action.
|
|
10
|
+
- The phone header: the menu button that opens the off-canvas Sidebar, the title, search as an icon.
|
|
11
|
+
|
|
12
|
+
## When not to use
|
|
13
|
+
- The page heading, its description and page actions inside main → use [PageContent](../../components/page-content/COMPONENT.md) (`PageContent.Title` is the `<h1>`).
|
|
14
|
+
- Tabs, filters and search for the data on the page → use [PageToolbar](../../components/page-toolbar/COMPONENT.md).
|
|
15
|
+
- App navigation → use [Sidebar](../sidebar/COMPONENT.md) and, on a phone, [BottomNav](../bottom-nav/COMPONENT.md); the header holds at most the menu button.
|
|
16
|
+
- The search dialog itself → use [CommandMenu](../../components/command-menu/COMPONENT.md); `AppHeader.Search` only opens it.
|
|
17
|
+
|
|
18
|
+
## Import
|
|
19
|
+
```tsx
|
|
20
|
+
import { AppHeader } from "prime-ui-kit";
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Anatomy
|
|
24
|
+
```
|
|
25
|
+
AppHeader.Root <header>, one sticky row as high as the Sidebar brand row
|
|
26
|
+
├─ AppHeader.Start leading zone, takes the free width
|
|
27
|
+
│ ├─ AppHeader.MenuButton opens the off-canvas Sidebar (below 768px by default)
|
|
28
|
+
│ ├─ AppHeader.Separator short vertical line between groups (a back Button | a Breadcrumb)
|
|
29
|
+
│ └─ AppHeader.Title name, truncates (or a Breadcrumb instead)
|
|
30
|
+
│ ├─ AppHeader.Icon decorative glyph on a tile shaped like a soft button m
|
|
31
|
+
│ └─ AppHeader.Description muted caption under the name
|
|
32
|
+
├─ AppHeader.Search field-looking button that opens the CommandMenu
|
|
33
|
+
└─ AppHeader.Actions trailing buttons: notifications, account, primary action
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## API
|
|
37
|
+
|
|
38
|
+
<!-- Generated from api.ts by `bun run docs:build`. Edit api.ts, not this section. -->
|
|
39
|
+
|
|
40
|
+
### AppHeader.Root
|
|
41
|
+
`ref` → `HTMLElement`. The `<header>` bar at the top of the content panel: one row as high as the Sidebar brand row, on the panel surface with no divider, sticky with the top safe-area inset (static below 480px of viewport height); inline padding is the shell gutter, so it lines up with the page in main (16 outside a shell). Its controls are size `m`; icon buttons inside are `soft` (a light fill), not `ghost`. A container (`prime-app-header`): below 36rem the icon tile and the description go and the search folds into an icon.
|
|
42
|
+
|
|
43
|
+
| Prop | Type | Default | Description |
|
|
44
|
+
|---|---|---|---|
|
|
45
|
+
| `labels` | `Partial<AppHeaderLabels>` | — | Built-in strings, see Labels. |
|
|
46
|
+
| `…rest` | `HTMLAttributes<HTMLElement>` | — | `children` (`AppHeader.Start`, `AppHeader.Search`, `AppHeader.Actions`), `className` and the other attributes. |
|
|
47
|
+
|
|
48
|
+
### AppHeader.Start
|
|
49
|
+
`ref` → `HTMLDivElement`. The leading zone that takes the free width: the menu button, a back button, the title or a Breadcrumb.
|
|
50
|
+
|
|
51
|
+
| Prop | Type | Default | Description |
|
|
52
|
+
|---|---|---|---|
|
|
53
|
+
| `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children`, `className` and the other div attributes. |
|
|
54
|
+
|
|
55
|
+
### AppHeader.Title
|
|
56
|
+
`ref` → `HTMLDivElement`. Where you are: an optional `AppHeader.Icon`, the name (title-s, truncates) and an optional `AppHeader.Description` under it — the anatomy of the Sidebar brand. Not a heading: the page `<h1>` is PageContent.Title.
|
|
57
|
+
|
|
58
|
+
| Prop | Type | Default | Description |
|
|
59
|
+
|---|---|---|---|
|
|
60
|
+
| `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children` (the name, `AppHeader.Icon`, `AppHeader.Description` in any order), `className` and the other div attributes. |
|
|
61
|
+
|
|
62
|
+
### AppHeader.Icon
|
|
63
|
+
`ref` → `HTMLSpanElement`. Decorative glyph before the title (`aria-hidden`) on a tile shaped like the bar's soft buttons: control m square (36), its radius and the subtle fill.
|
|
64
|
+
|
|
65
|
+
| Prop | Type | Default | Description |
|
|
66
|
+
|---|---|---|---|
|
|
67
|
+
| `…rest` | `HTMLAttributes<HTMLSpanElement>` | — | `children` (an `Icon`), `className` and the other span attributes. |
|
|
68
|
+
|
|
69
|
+
### AppHeader.Description
|
|
70
|
+
`ref` → `HTMLSpanElement`. Muted caption under the title (a workspace, a period); hidden on a narrow header.
|
|
71
|
+
|
|
72
|
+
| Prop | Type | Default | Description |
|
|
73
|
+
|---|---|---|---|
|
|
74
|
+
| `…rest` | `HTMLAttributes<HTMLSpanElement>` | — | `children`, `className` and the other span attributes. |
|
|
75
|
+
|
|
76
|
+
### AppHeader.Separator
|
|
77
|
+
`ref` → `HTMLDivElement`. A short vertical `Divider` (20) between groups in a zone — a back button and the path — with 16 of air on each side.
|
|
78
|
+
|
|
79
|
+
| Prop | Type | Default | Description |
|
|
80
|
+
|---|---|---|---|
|
|
81
|
+
| `…rest` | `Omit<DividerProps, "orientation" \| "children">` | — | `className` and the other div attributes. |
|
|
82
|
+
|
|
83
|
+
### AppHeader.Search
|
|
84
|
+
`ref` → `HTMLButtonElement`. The global search entry: a `<button type="button">` drawn as a field (search icon, placeholder text, key hint) that opens your CommandMenu. Below 36rem of header width it folds into a square button named by its text.
|
|
85
|
+
|
|
86
|
+
| Prop | Type | Default | Description |
|
|
87
|
+
|---|---|---|---|
|
|
88
|
+
| `children` | `ReactNode` | — (required) | The placeholder text; also the accessible name. |
|
|
89
|
+
| `shortcut` | `ReactNode` | `"⌘K"` | The key hint at the end (a `Kbd`, hidden from assistive tech); `null` hides it. Bind the key yourself. |
|
|
90
|
+
| `…rest` | `ButtonHTMLAttributes<HTMLButtonElement>` | — | `onClick`, `className` and the other button attributes. |
|
|
91
|
+
|
|
92
|
+
### AppHeader.Actions
|
|
93
|
+
`ref` → `HTMLDivElement`. The trailing row of buttons: notifications, the account, one primary action. Never wraps.
|
|
94
|
+
|
|
95
|
+
| Prop | Type | Default | Description |
|
|
96
|
+
|---|---|---|---|
|
|
97
|
+
| `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children`, `className` and the other div attributes. |
|
|
98
|
+
|
|
99
|
+
### AppHeader.MenuButton
|
|
100
|
+
`ref` → `HTMLButtonElement`. A soft neutral icon `Button` named by `labels.menu` that opens the off-canvas Sidebar; wire `onClick` and `aria-expanded`.
|
|
101
|
+
|
|
102
|
+
| Prop | Type | Default | Description |
|
|
103
|
+
|---|---|---|---|
|
|
104
|
+
| `show` | `"narrow" \| "always"` | `"narrow"` | `narrow` — only below 768px, where a Sidebar with `offCanvas="auto"` leaves the layout; `always` — on every width (`offCanvas="always"`). |
|
|
105
|
+
| `…rest` | `ButtonHTMLAttributes<HTMLButtonElement>` | — | `onClick`, `aria-expanded`, `aria-label` (replaces `labels.menu`), `className` and the other button attributes. |
|
|
106
|
+
|
|
107
|
+
## Variants
|
|
108
|
+
|
|
109
|
+
### show (MenuButton)
|
|
110
|
+
| Value | Looks like | Use when | Default |
|
|
111
|
+
|---|---|---|---|
|
|
112
|
+
| `narrow` | The menu button shows only below 768px | Sidebar with `offCanvas="auto"` | yes |
|
|
113
|
+
| `always` | The menu button on every width | Sidebar with `offCanvas="always"`, or you decide visibility yourself | |
|
|
114
|
+
|
|
115
|
+
### Structure
|
|
116
|
+
| Value | Looks like | Use when | Default |
|
|
117
|
+
|---|---|---|---|
|
|
118
|
+
| `AppHeader.Title` | Icon, name and a caption under it, like the Sidebar brand | A top-level section | |
|
|
119
|
+
| Breadcrumb in Start | A soft back button, `AppHeader.Separator` and the path | A nested record page | |
|
|
120
|
+
| with `AppHeader.Search` | A field-looking button with a key hint between Start and Actions | The app has a CommandMenu | |
|
|
121
|
+
| with `AppHeader.Actions` | A row of buttons at the end | Notifications, account, one primary action | |
|
|
122
|
+
|
|
123
|
+
## States
|
|
124
|
+
| State | Driven by | DOM |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| narrow header | header width below 36rem (container `prime-app-header`) | the icon tile and the description hide; the search folds into a square button, its text stays as the name |
|
|
127
|
+
| menu button hidden | `show="narrow"` and viewport from 768px | `data-show="narrow"` on MenuButton |
|
|
128
|
+
| short viewport | viewport below 480px high (a phone on its side) | Root stops sticking |
|
|
129
|
+
|
|
130
|
+
## Layout & spacing
|
|
131
|
+
- Row min height = control m + `--prime-space-2` (44), padding-block `--prime-space-3` (the top grows to the safe-area inset): 68 in all, the height of the Sidebar header, so the brand and the title share one line.
|
|
132
|
+
- Inline padding: the shell gutters (16 → 24 → 32, the same as `AppShell.Main`) in the shell's panel, so the header lines up with the page; `--prime-space-4` elsewhere.
|
|
133
|
+
- Icon buttons are `soft` neutral (MenuButton is), never `ghost`: the search folds into a filled square too, so every button on the bar has a shape.
|
|
134
|
+
- Gaps: `--prime-space-3` between zones, `--prime-space-2` inside Start and Actions; `AppHeader.Separator` adds `--prime-space-2` on each side (16 in all) and is 20 high.
|
|
135
|
+
- `AppHeader.Icon` is a 36 tile with the radius and fill of a soft neutral button m, so it lines up with the buttons on the bar.
|
|
136
|
+
- On the panel surface with no divider or shadow (depth from fill); `z-index: --prime-z-sticky`.
|
|
137
|
+
- Search: up to 288 wide, shrinks first; field tier m and the fill of the panel layer it sits on. Controls inside are size `m`.
|
|
138
|
+
|
|
139
|
+
## Accessibility
|
|
140
|
+
|
|
141
|
+
### Keyboard
|
|
142
|
+
| Key | Action |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `Tab` | Moves through the menu button, the path links, the search and the actions in reading order. |
|
|
145
|
+
| `Enter` · `Space` | Presses the focused button: opens the menu, the search or runs the action. |
|
|
146
|
+
|
|
147
|
+
### ARIA
|
|
148
|
+
- Root is a `<header>`: the banner landmark when it sits at the top level of the page.
|
|
149
|
+
- Search is a button named by its text; the key hint is `aria-hidden`, and the app binds the shortcut.
|
|
150
|
+
- MenuButton is named by `labels.menu`; pass `aria-expanded` (whether the Sidebar is open).
|
|
151
|
+
- Title is not a heading: the page `<h1>` stays with PageContent.Title.
|
|
152
|
+
|
|
153
|
+
### Labels
|
|
154
|
+
<!-- Generated from api.ts by `bun run docs:build`. Edit api.ts, not this section. -->
|
|
155
|
+
|
|
156
|
+
| Key | Default | Used for |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| `menu` | `"Открыть меню"` | Name of `AppHeader.MenuButton`. |
|
|
159
|
+
|
|
160
|
+
## Examples
|
|
161
|
+
| Example | Shows |
|
|
162
|
+
|---|---|
|
|
163
|
+
| [overview.tsx](examples/overview.tsx) | The top bar of a screen: where you are, global search, notifications and the primary action — `AppHeader.Title`, `AppHeader.Search`, `AppHeader.Actions`. |
|
|
164
|
+
| [breadcrumbs.tsx](examples/breadcrumbs.tsx) | A nested page: a back button, a separator and the path instead of a title, actions on the record at the end — `AppHeader.Separator`, `AppHeader.Actions`. |
|
|
165
|
+
| [in-app-shell.tsx](examples/in-app-shell.tsx) | The header in the app frame: one row with the Sidebar brand across the two planes, sticky over main — `AppShell`, `Sidebar.Brand`. |
|
|
166
|
+
| [narrow.tsx](examples/narrow.tsx) | On a phone: the menu button opens the navigation, the description goes and the search folds into an icon — `AppHeader.MenuButton`, `show`. |
|
|
167
|
+
|
|
168
|
+
## Mistakes
|
|
169
|
+
- A border or shadow under the header → it sits on the panel surface; the fill is the boundary.
|
|
170
|
+
- `AppHeader.Title` as the page `<h1>` → the heading belongs to PageContent.Title in main.
|
|
171
|
+
- A real text input for global search → `AppHeader.Search` opens the CommandMenu, where typing happens.
|
|
172
|
+
- More than three actions → keep one primary action; the rest go into the page or a Dropdown.
|
|
173
|
+
- A hand-made menu button with a media query → `AppHeader.MenuButton` follows the Sidebar breakpoint.
|
|
174
|
+
- `ghost` icon buttons in the header → `variant="soft" tone="neutral"`: a light fill gives each button a shape on the bar.
|
|
175
|
+
|
|
176
|
+
## Related
|
|
177
|
+
- **Built from:** [Button](../../components/button/COMPONENT.md), [Kbd](../../components/kbd/COMPONENT.md), [Divider](../../components/divider/COMPONENT.md), Icon (`action.search`, `nav.menu`)
|
|
178
|
+
- **See also:** [AppShell](../app-shell/COMPONENT.md), [Sidebar](../sidebar/COMPONENT.md), [PageContent](../../components/page-content/COMPONENT.md), [PageToolbar](../../components/page-toolbar/COMPONENT.md), [CommandMenu](../../components/command-menu/COMPONENT.md), [Breadcrumb](../../components/breadcrumb/COMPONENT.md)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** A nested page: a back button, a separator and the path instead of a title, actions on the record at the end — `AppHeader.Separator`, `AppHeader.Actions`. */
|
|
2
|
+
import { AppHeader, Breadcrumb, Button, Icon } from "prime-ui-kit";
|
|
3
|
+
|
|
4
|
+
import styles from "./examples.module.css";
|
|
5
|
+
|
|
6
|
+
export default function AppHeaderBreadcrumbsExample() {
|
|
7
|
+
return (
|
|
8
|
+
<div className={styles.window}>
|
|
9
|
+
<AppHeader.Root>
|
|
10
|
+
<AppHeader.Start>
|
|
11
|
+
<Button.Root variant="soft" tone="neutral" aria-label="Назад к клиентам">
|
|
12
|
+
<Button.Icon>
|
|
13
|
+
<Icon name="nav.chevronLeft" />
|
|
14
|
+
</Button.Icon>
|
|
15
|
+
</Button.Root>
|
|
16
|
+
<AppHeader.Separator />
|
|
17
|
+
<Breadcrumb.Root>
|
|
18
|
+
<Breadcrumb.Item href="#crm">CRM</Breadcrumb.Item>
|
|
19
|
+
<Breadcrumb.Item href="#clients">Клиенты</Breadcrumb.Item>
|
|
20
|
+
<Breadcrumb.Item current>ООО «Север»</Breadcrumb.Item>
|
|
21
|
+
</Breadcrumb.Root>
|
|
22
|
+
</AppHeader.Start>
|
|
23
|
+
<AppHeader.Actions>
|
|
24
|
+
<Button.Root variant="soft" tone="neutral">
|
|
25
|
+
Экспорт
|
|
26
|
+
</Button.Root>
|
|
27
|
+
<Button.Root variant="soft" tone="neutral" aria-label="Ещё действия">
|
|
28
|
+
<Button.Icon>
|
|
29
|
+
<Icon name="action.more" />
|
|
30
|
+
</Button.Icon>
|
|
31
|
+
</Button.Root>
|
|
32
|
+
</AppHeader.Actions>
|
|
33
|
+
</AppHeader.Root>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/* Layout of the AppHeader scenarios: an app window and a phone-wide screen. Semantic tokens only. */
|
|
2
|
+
|
|
3
|
+
/* The top of an app window: the content panel (the page) with the header on it. */
|
|
4
|
+
.window {
|
|
5
|
+
box-sizing: border-box;
|
|
6
|
+
width: 100%;
|
|
7
|
+
overflow: hidden;
|
|
8
|
+
border-radius: var(--prime-card-radius);
|
|
9
|
+
background: var(--prime-color-layer-current);
|
|
10
|
+
box-shadow:
|
|
11
|
+
0 0 0 var(--prime-border-width) var(--prime-color-border-subtle),
|
|
12
|
+
var(--prime-shadow-raised);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* narrow.tsx: the same window, phone-wide, so the header folds its search. */
|
|
16
|
+
.phone {
|
|
17
|
+
width: min(100%, var(--prime-drawer-width-s));
|
|
18
|
+
margin-inline: auto;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* in-app-shell.tsx: a whole app window with the rail on the page. */
|
|
22
|
+
.stage {
|
|
23
|
+
box-sizing: border-box;
|
|
24
|
+
display: flex;
|
|
25
|
+
width: 100%;
|
|
26
|
+
height: calc(var(--prime-space-24) * 4);
|
|
27
|
+
overflow: hidden;
|
|
28
|
+
border-radius: var(--prime-card-radius);
|
|
29
|
+
background: var(--prime-color-layer-current);
|
|
30
|
+
box-shadow:
|
|
31
|
+
0 0 0 var(--prime-border-width) var(--prime-color-border-subtle),
|
|
32
|
+
var(--prime-shadow-raised);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* The shell fills the window frame instead of the viewport. */
|
|
36
|
+
.shell {
|
|
37
|
+
height: 100%;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* The product mark inside `Sidebar.BrandLogo`: an accent tile with a glyph. */
|
|
41
|
+
.logo {
|
|
42
|
+
display: grid;
|
|
43
|
+
place-items: center;
|
|
44
|
+
border-radius: var(--prime-radius-m);
|
|
45
|
+
background: var(--prime-color-accent-default);
|
|
46
|
+
color: var(--prime-color-accent-fg);
|
|
47
|
+
}
|