prime-ui-kit 0.9.1 → 0.9.2

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.
Files changed (107) hide show
  1. package/README.md +22 -8
  2. package/dist/chunks/{chunk-KCQFOORX.js → chunk-IQELQNMR.js} +1 -1
  3. package/dist/chunks/{chunk-DB2Y3XXA.js → chunk-LXGRKN34.js} +2323 -1500
  4. package/dist/chunks/{chunk-NHOWNIAR.js → chunk-ZEFCDEEQ.js} +790 -536
  5. package/dist/color-picker.js +2 -2
  6. package/dist/components/data-table/DataTable.d.ts +6 -1
  7. package/dist/components/data-table/types.d.ts +5 -0
  8. package/dist/components/dnd/Dnd.d.ts +1 -1
  9. package/dist/components/dnd/dragSession.d.ts +9 -0
  10. package/dist/components/dnd/useDropTarget.d.ts +5 -0
  11. package/dist/components/dnd/useFlipList.d.ts +3 -3
  12. package/dist/components/drawer/Drawer.d.ts +8 -5
  13. package/dist/components/dropdown/Dropdown.d.ts +17 -0
  14. package/dist/components/index.d.ts +5 -1
  15. package/dist/components/kanban/Kanban.d.ts +129 -0
  16. package/dist/components/modal/Modal.d.ts +5 -2
  17. package/dist/components/page-toolbar/PageToolbar.d.ts +53 -0
  18. package/dist/components/segmented-control/SegmentedControl.d.ts +5 -2
  19. package/dist/components/tabs/Tabs.d.ts +5 -2
  20. package/dist/hooks/useEdgeOverflow.d.ts +12 -0
  21. package/dist/hooks/useMediaQuery.d.ts +7 -0
  22. package/dist/hooks/useSwipeDismiss.d.ts +34 -0
  23. package/dist/index.css +2271 -1163
  24. package/dist/index.js +10 -2
  25. package/dist/internal/overlay/FloatingPanel.d.ts +3 -1
  26. package/dist/internal/overlay/useFloatingLayer.d.ts +11 -1
  27. package/dist/internal/touchTarget.d.ts +4 -0
  28. package/dist/layout/app-header/AppHeader.d.ts +110 -0
  29. package/dist/layout/app-shell/AppShell.d.ts +14 -9
  30. package/dist/layout/bottom-nav/BottomNav.d.ts +80 -0
  31. package/dist/layout/index.d.ts +5 -1
  32. package/dist/tokens/primitives.d.ts +4 -0
  33. package/dist/tokens/semantic.d.ts +56 -0
  34. package/dist/tokens/themes/dark.d.ts +4 -0
  35. package/package.json +3 -2
  36. package/src/components/accordion/COMPONENT.md +1 -1
  37. package/src/components/badge/COMPONENT.md +2 -2
  38. package/src/components/banner/COMPONENT.md +1 -1
  39. package/src/components/checkbox/examples/examples.module.css +4 -2
  40. package/src/components/crossfade/COMPONENT.md +1 -1
  41. package/src/components/data-table/COMPONENT.md +19 -6
  42. package/src/components/data-table/examples/columns-visibility.tsx +167 -0
  43. package/src/components/digit-input/COMPONENT.md +10 -10
  44. package/src/components/digit-input/examples/examples.module.css +8 -0
  45. package/src/components/digit-input/examples/in-form.tsx +2 -5
  46. package/src/components/digit-input/examples/sizes.tsx +1 -1
  47. package/src/components/divider/COMPONENT.md +1 -1
  48. package/src/components/dnd/COMPONENT.md +3 -3
  49. package/src/components/drawer/COMPONENT.md +17 -9
  50. package/src/components/drawer/examples/date-sheet.tsx +41 -0
  51. package/src/components/drawer/examples/examples.module.css +5 -0
  52. package/src/components/drawer/examples/placement.tsx +4 -2
  53. package/src/components/dropdown/COMPONENT.md +19 -5
  54. package/src/components/dropdown/examples/checkbox-items.tsx +48 -0
  55. package/src/components/empty-page/COMPONENT.md +1 -1
  56. package/src/components/kanban/COMPONENT.md +181 -0
  57. package/src/components/kanban/examples/controlled.tsx +78 -0
  58. package/src/components/kanban/examples/examples.module.css +31 -0
  59. package/src/components/kanban/examples/limits.tsx +58 -0
  60. package/src/components/kanban/examples/narrow.tsx +76 -0
  61. package/src/components/kanban/examples/overview.tsx +130 -0
  62. package/src/components/kanban/examples/states.tsx +75 -0
  63. package/src/components/kanban/examples/structure.tsx +76 -0
  64. package/src/components/login-form/COMPONENT.md +1 -1
  65. package/src/components/modal/COMPONENT.md +9 -6
  66. package/src/components/notification/COMPONENT.md +2 -2
  67. package/src/components/page-content/COMPONENT.md +1 -1
  68. package/src/components/page-toolbar/COMPONENT.md +142 -0
  69. package/src/components/page-toolbar/examples/examples.module.css +16 -0
  70. package/src/components/page-toolbar/examples/narrow.tsx +103 -0
  71. package/src/components/page-toolbar/examples/overview.tsx +113 -0
  72. package/src/components/page-toolbar/examples/save-changes.tsx +40 -0
  73. package/src/components/page-toolbar/examples/without-search.tsx +60 -0
  74. package/src/components/popover/COMPONENT.md +4 -3
  75. package/src/components/progress-bar/COMPONENT.md +1 -1
  76. package/src/components/progress-circle/COMPONENT.md +1 -1
  77. package/src/components/scroll-container/COMPONENT.md +1 -1
  78. package/src/components/segmented-control/COMPONENT.md +8 -8
  79. package/src/components/segmented-control/examples/full-width.tsx +1 -1
  80. package/src/components/select/COMPONENT.md +2 -1
  81. package/src/components/skeleton/COMPONENT.md +1 -1
  82. package/src/components/smart-filter/COMPONENT.md +2 -0
  83. package/src/components/spinner/COMPONENT.md +1 -1
  84. package/src/components/tabs/COMPONENT.md +11 -8
  85. package/src/components/tabs/examples/closable.tsx +1 -1
  86. package/src/layout/app-header/COMPONENT.md +178 -0
  87. package/src/layout/app-header/examples/breadcrumbs.tsx +36 -0
  88. package/src/layout/app-header/examples/examples.module.css +47 -0
  89. package/src/layout/app-header/examples/in-app-shell.tsx +70 -0
  90. package/src/layout/app-header/examples/narrow.tsx +29 -0
  91. package/src/layout/app-header/examples/overview.tsx +36 -0
  92. package/src/layout/app-shell/COMPONENT.md +27 -21
  93. package/src/layout/app-shell/examples/examples.module.css +15 -0
  94. package/src/layout/app-shell/examples/footer.tsx +59 -0
  95. package/src/layout/app-shell/examples/overview.tsx +19 -8
  96. package/src/layout/bottom-nav/COMPONENT.md +153 -0
  97. package/src/layout/bottom-nav/examples/examples.module.css +39 -0
  98. package/src/layout/bottom-nav/examples/floating.tsx +89 -0
  99. package/src/layout/bottom-nav/examples/icon-only.tsx +41 -0
  100. package/src/layout/bottom-nav/examples/in-app-shell.tsx +64 -0
  101. package/src/layout/bottom-nav/examples/overview.tsx +44 -0
  102. package/src/layout/bottom-nav/examples/router.tsx +31 -0
  103. package/src/layout/bottom-nav/examples/structure.tsx +47 -0
  104. package/src/layout/sidebar/COMPONENT.md +11 -10
  105. package/src/styles/theme-dark.css +3 -0
  106. package/src/styles/theme-light.css +24 -0
  107. package/src/styles/tokens.css +2 -0
@@ -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 surface field fill. 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 surface 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-bg-surface);
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 canvas. */
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-bg-canvas);
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
+ }
@@ -0,0 +1,70 @@
1
+ /** The header in the app frame: one row with the Sidebar brand across the two planes, sticky over main — `AppShell`, `Sidebar.Brand`. */
2
+ import { AppHeader, AppShell, Icon, PageContent, Sidebar, Typography } from "prime-ui-kit";
3
+
4
+ import styles from "./examples.module.css";
5
+
6
+ const ORDERS = [
7
+ "№ 4821 · ООО «Север» · 84 000 ₽",
8
+ "№ 4820 · ИП Котов · 12 500 ₽",
9
+ "№ 4819 · ООО «Вектор» · 230 000 ₽",
10
+ "№ 4818 · АО «Меридиан» · 47 900 ₽",
11
+ "№ 4817 · ООО «Полюс» · 9 800 ₽",
12
+ "№ 4816 · ИП Белова · 156 000 ₽",
13
+ ];
14
+
15
+ export default function AppHeaderInAppShellExample() {
16
+ return (
17
+ <div className={styles.stage}>
18
+ <AppShell.Root fillViewport className={styles.shell}>
19
+ <AppShell.Nav>
20
+ <Sidebar.Root offCanvas="never">
21
+ <Sidebar.Header>
22
+ <Sidebar.Brand href="#home" description="Отдел продаж">
23
+ <Sidebar.BrandLogo>
24
+ <span className={styles.logo}>
25
+ <Icon name="nav.layoutGrid" />
26
+ </span>
27
+ </Sidebar.BrandLogo>
28
+ Acme CRM
29
+ </Sidebar.Brand>
30
+ </Sidebar.Header>
31
+ <Sidebar.Content>
32
+ <Sidebar.Item>
33
+ <Sidebar.ItemIcon>
34
+ <Icon name="nav.home" />
35
+ </Sidebar.ItemIcon>
36
+ Обзор
37
+ </Sidebar.Item>
38
+ <Sidebar.Item current>
39
+ <Sidebar.ItemIcon>
40
+ <Icon name="object.package" />
41
+ </Sidebar.ItemIcon>
42
+ Заказы
43
+ </Sidebar.Item>
44
+ </Sidebar.Content>
45
+ </Sidebar.Root>
46
+ </AppShell.Nav>
47
+ <AppHeader.Root>
48
+ <AppHeader.Start>
49
+ <AppHeader.Title>
50
+ Заказы
51
+ <AppHeader.Description>128 в работе</AppHeader.Description>
52
+ </AppHeader.Title>
53
+ </AppHeader.Start>
54
+ <AppHeader.Search>Поиск</AppHeader.Search>
55
+ </AppHeader.Root>
56
+ <AppShell.Main>
57
+ <PageContent.Section>
58
+ <PageContent.Body>
59
+ {ORDERS.map((order) => (
60
+ <Typography key={order} variant="body-m">
61
+ {order}
62
+ </Typography>
63
+ ))}
64
+ </PageContent.Body>
65
+ </PageContent.Section>
66
+ </AppShell.Main>
67
+ </AppShell.Root>
68
+ </div>
69
+ );
70
+ }
@@ -0,0 +1,29 @@
1
+ /** On a phone: the menu button opens the navigation, the description goes and the search folds into an icon — `AppHeader.MenuButton`, `show`. */
2
+ import { AppHeader, Button, Icon } from "prime-ui-kit";
3
+
4
+ import styles from "./examples.module.css";
5
+
6
+ export default function AppHeaderNarrowExample() {
7
+ return (
8
+ <div className={`${styles.window} ${styles.phone}`}>
9
+ <AppHeader.Root>
10
+ <AppHeader.Start>
11
+ {/* `always`: this frame is phone-wide on any screen; in an app keep the default `narrow`. */}
12
+ <AppHeader.MenuButton show="always" aria-expanded={false} />
13
+ <AppHeader.Title>
14
+ Заказы
15
+ <AppHeader.Description>128 в работе</AppHeader.Description>
16
+ </AppHeader.Title>
17
+ </AppHeader.Start>
18
+ <AppHeader.Search>Поиск заказов</AppHeader.Search>
19
+ <AppHeader.Actions>
20
+ <Button.Root variant="soft" tone="neutral" aria-label="Новый заказ">
21
+ <Button.Icon>
22
+ <Icon name="action.add" />
23
+ </Button.Icon>
24
+ </Button.Root>
25
+ </AppHeader.Actions>
26
+ </AppHeader.Root>
27
+ </div>
28
+ );
29
+ }
@@ -0,0 +1,36 @@
1
+ /** The top bar of a screen: where you are, global search, notifications and the primary action — `AppHeader.Title`, `AppHeader.Search`, `AppHeader.Actions`. */
2
+ import { AppHeader, Button, Icon } from "prime-ui-kit";
3
+
4
+ import styles from "./examples.module.css";
5
+
6
+ export default function AppHeaderOverviewExample() {
7
+ return (
8
+ <div className={styles.window}>
9
+ <AppHeader.Root>
10
+ <AppHeader.Start>
11
+ <AppHeader.Title>
12
+ <AppHeader.Icon>
13
+ <Icon name="nav.dashboard" />
14
+ </AppHeader.Icon>
15
+ Обзор
16
+ <AppHeader.Description>Отдел продаж · октябрь</AppHeader.Description>
17
+ </AppHeader.Title>
18
+ </AppHeader.Start>
19
+ <AppHeader.Search>Поиск заказов и клиентов</AppHeader.Search>
20
+ <AppHeader.Actions>
21
+ <Button.Root variant="soft" tone="neutral" aria-label="Уведомления">
22
+ <Button.Icon>
23
+ <Icon name="object.bell" />
24
+ </Button.Icon>
25
+ </Button.Root>
26
+ <Button.Root>
27
+ <Button.Icon>
28
+ <Icon name="action.add" />
29
+ </Button.Icon>
30
+ Новый заказ
31
+ </Button.Root>
32
+ </AppHeader.Actions>
33
+ </AppHeader.Root>
34
+ </div>
35
+ );
36
+ }
@@ -1,16 +1,17 @@
1
1
  # AppShell
2
2
 
3
- **Category:** layout
3
+ **Category:** page
4
4
  **Kind:** layout
5
5
 
6
6
  > The app frame: a navigation rail on the canvas and a content panel on the surface.
7
7
 
8
8
  ## When to use
9
- - The root layout of an application: navigation column, optional sticky header, scrolling main column.
9
+ - The root layout of an application: navigation column, an optional AppHeader, scrolling main column, a bottom bar for phone navigation.
10
10
  - Any page that needs the kit's responsive gutters and the surface context for cards and fields.
11
11
 
12
12
  ## When not to use
13
- - The navigation itself → use [Sidebar](../sidebar/COMPONENT.md) inside `AppShell.Nav`.
13
+ - The navigation itself → use [Sidebar](../sidebar/COMPONENT.md) inside `AppShell.Nav`, [BottomNav](../bottom-nav/COMPONENT.md) inside `AppShell.Footer`.
14
+ - The top bar (title, search, actions, the menu button) → use [AppHeader](../app-header/COMPONENT.md) as a child of Root.
14
15
  - Page heading, actions and sections inside main → use [PageContent](../../components/page-content/COMPONENT.md).
15
16
  - A temporary side panel over the page → use [Drawer](../../components/drawer/COMPONENT.md).
16
17
  - A scroll region inside a page → use [ScrollContainer](../../components/scroll-container/COMPONENT.md).
@@ -24,9 +25,10 @@ import { AppShell } from "prime-ui-kit";
24
25
  ```
25
26
  AppShell.Root grid: nav column | content panel (bg-surface)
26
27
  ├─ AppShell.Nav navigation column on the canvas (usually Sidebar.Root)
27
- ├─ AppShell.Header sticky top bar of the panel
28
- └─ AppShell.Main <main>, scrolls, carries the gutters
29
- AppShell.Template Root + Nav + Header + Main in one component
28
+ ├─ AppHeader.Root sticky top bar of the panel (a separate component)
29
+ ├─ AppShell.Main <main>, scrolls, carries the gutters
30
+ └─ AppShell.Footer sticky bottom bar of the panel (usually BottomNav.Root)
31
+ AppShell.Template Root + Nav + the header + Main + Footer in one component
30
32
  ```
31
33
  Every child of Root that is not `AppShell.Nav` is placed into the content panel.
32
34
 
@@ -40,7 +42,7 @@ Every child of Root that is not `AppShell.Nav` is placed into the content panel.
40
42
  | Prop | Type | Default | Description |
41
43
  |---|---|---|---|
42
44
  | `fillViewport` | `boolean` | `false` | The shell is exactly the viewport high and only `AppShell.Main` scrolls; otherwise the document scrolls and the nav is sticky. |
43
- | `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children` (Nav, Header, Main), `className` and the other div attributes. |
45
+ | `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children` (Nav, `AppHeader.Root`, Main, Footer), `className` and the other div attributes. |
44
46
 
45
47
  ### AppShell.Nav
46
48
  `ref` → `HTMLDivElement`. The navigation column slot (not a landmark: Sidebar renders the `<nav>`).
@@ -49,28 +51,29 @@ Every child of Root that is not `AppShell.Nav` is placed into the content panel.
49
51
  |---|---|---|---|
50
52
  | `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children` (usually `Sidebar.Root`), `className` and the other div attributes. |
51
53
 
52
- ### AppShell.Header
53
- `ref` → `HTMLElement`. Sticky `<header>` row of the panel for breadcrumbs, search and actions.
54
+ ### AppShell.Main
55
+ `ref` → `HTMLElement`. The `<main>` with the canonical gutters: a vertical `ScrollContainer`.
54
56
 
55
57
  | Prop | Type | Default | Description |
56
58
  |---|---|---|---|
59
+ | `contentWidth` | `"contained" \| "full"` | `"full"` | `full` — the whole panel with gutters; `contained` — a centred column up to `--prime-layout-content-max-width`. |
57
60
  | `…rest` | `HTMLAttributes<HTMLElement>` | — | `children`, `className` and the other attributes. |
58
61
 
59
- ### AppShell.Main
60
- `ref` → `HTMLElement`. The `<main>` with the canonical gutters: a vertical `ScrollContainer`.
62
+ ### AppShell.Footer
63
+ `ref` → `HTMLDivElement`. Sticky bottom bar of the panel for `BottomNav`; no padding of its own. A container (`prime-shell-footer`): BottomNav inside shows only while the panel is narrower than 640px.
61
64
 
62
65
  | Prop | Type | Default | Description |
63
66
  |---|---|---|---|
64
- | `contentWidth` | `"contained" \| "full"` | `"full"` | `full` — the whole panel with gutters; `contained` — a centred column up to `--prime-layout-content-max-width`. |
65
- | `…rest` | `HTMLAttributes<HTMLElement>` | — | `children`, `className` and the other attributes. |
67
+ | `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children` (usually `BottomNav.Root`), `className` and the other div attributes. |
66
68
 
67
69
  ### AppShell.Template
68
- `ref` → the `<main>`. Root + Nav + Header + Main in one; main scrolls to the top when `scrollResetKey` changes.
70
+ `ref` → the `<main>`. Root + Nav + the header + Main + Footer in one; main scrolls to the top when `scrollResetKey` changes.
69
71
 
70
72
  | Prop | Type | Default | Description |
71
73
  |---|---|---|---|
72
74
  | `nav` | `ReactNode` | — | Navigation column content; without it the panel takes the full width. |
73
- | `header` | `ReactNode` | — | Header content; no header row when omitted. |
75
+ | `header` | `ReactNode` | — | The top bar of the panel, an `AppHeader.Root`; no header when omitted. |
76
+ | `footer` | `ReactNode` | — | Footer content (`BottomNav`); no footer when omitted. |
74
77
  | `mainProps` | `Omit<AppShellMainProps, "children">` | — | Props for Main (e.g. `contentWidth`). |
75
78
  | `scrollResetKey` | `unknown` | — | Main scrolls back to the top whenever this value changes; pass the router pathname. |
76
79
  | `children` | `ReactNode` | — | Page content inside Main. |
@@ -95,7 +98,8 @@ Every child of Root that is not `AppShell.Nav` is placed into the content panel.
95
98
  |---|---|---|---|
96
99
  | with `AppShell.Nav` | Two columns: canvas rail + surface panel | Apps with navigation | |
97
100
  | without Nav | Panel takes the full width | Single-page tools, auth screens | |
98
- | with `AppShell.Header` | Sticky bar at the top of the panel | Breadcrumbs, page actions, mobile menu button | |
101
+ | with `AppHeader.Root` | Sticky bar at the top of the panel | Title or breadcrumbs, global search, actions, the mobile menu button | |
102
+ | with `AppShell.Footer` | Sticky bar at the bottom of the panel, shown while it holds a visible bar | BottomNav on a phone | |
99
103
 
100
104
  `AppShell.Template` with `nav={<Sidebar.Root …/>}` and `PageContent` inside is the standard app; `contentWidth="contained"` + `PageContent.Root maxWidth="readable"` for docs and articles.
101
105
 
@@ -104,11 +108,12 @@ Every child of Root that is not `AppShell.Nav` is placed into the content panel.
104
108
  |---|---|---|
105
109
  | fixed frame | `fillViewport` | `data-fill-viewport="true"` on Root |
106
110
  | content width | `contentWidth` | `data-content-width` on Main |
111
+ | footer bar | panel width (container `prime-shell-footer` on Footer) | BottomNav inside leaves from 640px of panel width; the empty footer takes no room |
107
112
 
108
113
  ## Layout & spacing
109
114
  - Two full-height planes edge to edge: no inset, radius, shadow or border — the boundary is the fill change (canvas → surface).
110
- - Gutters in Main and Header: `--prime-layout-gutter-s` (16) → `-m` (24) from 640px → `-l` (32) from 1024px. Main top padding `--prime-space-6` (24) → `--prime-space-10` (40) from 1024px; bottom `--prime-space-16`.
111
- - Header: min height = control m + 2 × `--prime-space-3`, padding-block `--prime-space-3`, `z-index: --prime-z-sticky`.
115
+ - Gutters in Main: `--prime-layout-gutter-s` (16) → `-m` (24) from 640px → `-l` (32) from 1024px. Main top padding `--prime-space-6` (24) → `--prime-space-10` (40) from 1024px; bottom `--prime-space-16`.
116
+ - Footer: no padding of its own (BottomNav keeps the bottom safe-area inset), sticky at the bottom, `z-index: --prime-z-sticky`.
112
117
  - The panel is a surface context: fields use the surface field fill, Cards inside become sunken tiles without shadow.
113
118
 
114
119
  ## Accessibility
@@ -117,7 +122,7 @@ Every child of Root that is not `AppShell.Nav` is placed into the content panel.
117
122
  No keyboard interaction.
118
123
 
119
124
  ### ARIA
120
- - Main is the `<main>` landmark and Header is `<header>`; the navigation landmark comes from Sidebar (`<nav>`).
125
+ - Main is the `<main>` landmark; the banner comes from AppHeader (`<header>`), the navigation landmarks from Sidebar and BottomNav (`<nav>`).
121
126
  - Give the page one `<h1>` (PageContent.Title).
122
127
 
123
128
  ### Labels
@@ -128,8 +133,9 @@ No `labels`.
128
133
  ## Examples
129
134
  | Example | Shows |
130
135
  |---|---|
131
- | [overview.tsx](examples/overview.tsx) | The app frame: Sidebar in the nav column, breadcrumbs in the sticky header, the page in main; only main scrolls — `fillViewport`. |
136
+ | [overview.tsx](examples/overview.tsx) | The app frame: Sidebar in the nav column, breadcrumbs in the AppHeader, the page in main; only main scrolls — `fillViewport`. |
132
137
  | [contained.tsx](examples/contained.tsx) | A shell without navigation whose main column is centred and capped for long reads — `contentWidth`. |
138
+ | [footer.tsx](examples/footer.tsx) | A phone-wide app: the bar in the footer stays at the bottom while main scrolls under it, and leaves once the panel is 640px wide — `AppShell.Footer`. |
133
139
  | [template.tsx](examples/template.tsx) | Root, nav, header and main in one component; main scrolls back to the top whenever the page changes — `AppShell.Template` with `scrollResetKey`. |
134
140
 
135
141
  ## Mistakes
@@ -141,4 +147,4 @@ No `labels`.
141
147
 
142
148
  ## Related
143
149
  - **Built from:** [ScrollContainer](../../components/scroll-container/COMPONENT.md)
144
- - **See also:** [Sidebar](../sidebar/COMPONENT.md), [PageContent](../../components/page-content/COMPONENT.md), [Breadcrumb](../../components/breadcrumb/COMPONENT.md)
150
+ - **See also:** [AppHeader](../app-header/COMPONENT.md), [Sidebar](../sidebar/COMPONENT.md), [BottomNav](../bottom-nav/COMPONENT.md), [PageContent](../../components/page-content/COMPONENT.md), [Breadcrumb](../../components/breadcrumb/COMPONENT.md)
@@ -27,3 +27,18 @@
27
27
  .shell {
28
28
  height: 100%;
29
29
  }
30
+
31
+ /* footer.tsx: the same window, phone-wide, so the bar in the footer stays (it leaves from 640px). */
32
+ .phone {
33
+ box-sizing: border-box;
34
+ display: flex;
35
+ width: min(100%, var(--prime-drawer-width-s));
36
+ height: calc(var(--prime-space-24) * 5);
37
+ margin-inline: auto;
38
+ overflow: hidden;
39
+ border-radius: var(--prime-card-radius);
40
+ background: var(--prime-color-bg-surface);
41
+ box-shadow:
42
+ 0 0 0 var(--prime-border-width) var(--prime-color-border-subtle),
43
+ var(--prime-shadow-raised);
44
+ }
@@ -0,0 +1,59 @@
1
+ /** A phone-wide app: the bar in the footer stays at the bottom while main scrolls under it, and leaves once the panel is 640px wide — `AppShell.Footer`. */
2
+ import { AppHeader, AppShell, BottomNav, Icon, PageContent, Typography } from "prime-ui-kit";
3
+
4
+ import styles from "./examples.module.css";
5
+
6
+ const SECTIONS = [
7
+ { label: "Главная", icon: "nav.home" },
8
+ { label: "Счета", icon: "object.receipt" },
9
+ { label: "Клиенты", icon: "object.users" },
10
+ { label: "Ещё", icon: "action.more" },
11
+ ] as const;
12
+
13
+ const INVOICES = [
14
+ "Счёт № 1207 · 84 000 ₽",
15
+ "Счёт № 1206 · 12 500 ₽",
16
+ "Счёт № 1205 · 230 000 ₽",
17
+ "Счёт № 1204 · 47 900 ₽",
18
+ "Счёт № 1203 · 9 800 ₽",
19
+ "Счёт № 1202 · 156 000 ₽",
20
+ "Счёт № 1201 · 31 200 ₽",
21
+ "Счёт № 1200 · 64 700 ₽",
22
+ ];
23
+
24
+ export default function AppShellFooterExample() {
25
+ return (
26
+ <div className={styles.phone}>
27
+ <AppShell.Root fillViewport className={styles.shell}>
28
+ <AppHeader.Root>
29
+ <AppHeader.Start>
30
+ <AppHeader.Title>Счета</AppHeader.Title>
31
+ </AppHeader.Start>
32
+ </AppHeader.Root>
33
+ <AppShell.Main>
34
+ <PageContent.Section>
35
+ <PageContent.Body>
36
+ {INVOICES.map((invoice) => (
37
+ <Typography key={invoice} variant="body-m">
38
+ {invoice}
39
+ </Typography>
40
+ ))}
41
+ </PageContent.Body>
42
+ </PageContent.Section>
43
+ </AppShell.Main>
44
+ <AppShell.Footer>
45
+ <BottomNav.Root>
46
+ {SECTIONS.map((item, index) => (
47
+ <BottomNav.Item key={item.label} current={index === 1}>
48
+ <BottomNav.ItemIcon>
49
+ <Icon name={item.icon} />
50
+ </BottomNav.ItemIcon>
51
+ {item.label}
52
+ </BottomNav.Item>
53
+ ))}
54
+ </BottomNav.Root>
55
+ </AppShell.Footer>
56
+ </AppShell.Root>
57
+ </div>
58
+ );
59
+ }
@@ -1,5 +1,14 @@
1
- /** The app frame: Sidebar in the nav column, breadcrumbs in the sticky header, the page in main; only main scrolls — `fillViewport`. */
2
- import { AppShell, Breadcrumb, Button, Icon, PageContent, Sidebar, Typography } from "prime-ui-kit";
1
+ /** The app frame: Sidebar in the nav column, breadcrumbs in the AppHeader, the page in main; only main scrolls — `fillViewport`. */
2
+ import {
3
+ AppHeader,
4
+ AppShell,
5
+ Breadcrumb,
6
+ Button,
7
+ Icon,
8
+ PageContent,
9
+ Sidebar,
10
+ Typography,
11
+ } from "prime-ui-kit";
3
12
 
4
13
  import styles from "./examples.module.css";
5
14
 
@@ -37,12 +46,14 @@ export default function AppShellOverviewExample() {
37
46
  </Sidebar.Content>
38
47
  </Sidebar.Root>
39
48
  </AppShell.Nav>
40
- <AppShell.Header>
41
- <Breadcrumb.Root>
42
- <Breadcrumb.Item href="#crm">CRM</Breadcrumb.Item>
43
- <Breadcrumb.Item current>Обзор</Breadcrumb.Item>
44
- </Breadcrumb.Root>
45
- </AppShell.Header>
49
+ <AppHeader.Root>
50
+ <AppHeader.Start>
51
+ <Breadcrumb.Root>
52
+ <Breadcrumb.Item href="#crm">CRM</Breadcrumb.Item>
53
+ <Breadcrumb.Item current>Обзор</Breadcrumb.Item>
54
+ </Breadcrumb.Root>
55
+ </AppHeader.Start>
56
+ </AppHeader.Root>
46
57
  <AppShell.Main>
47
58
  <PageContent.Section>
48
59
  <PageContent.Header>