@tailor-platform/app-shell 1.15.0 → 1.16.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/dist/app-shell-core.css +1 -1
- package/dist/app-shell.d.ts +208 -114
- package/dist/app-shell.js +3449 -3446
- package/dist/{appshell-DLVBFo5J.js → appshell-B0wh5Lq0.js} +625 -512
- package/dist/style-entry.d.ts +116 -96
- package/dist/testing.d.ts +116 -96
- package/dist/testing.js +1 -1
- package/dist/vite-plugin.d.ts +116 -96
- package/package.json +8 -8
- package/skills/app-shell-patterns/SKILL.md +101 -14
- package/skills/app-shell-patterns/references/api/create-ai-gateway-client.md +115 -0
- package/skills/app-shell-patterns/references/api/create-typed-paths.md +117 -0
- package/skills/app-shell-patterns/references/api/define-i18n-labels.md +143 -0
- package/skills/app-shell-patterns/references/api/define-module.md +247 -0
- package/skills/app-shell-patterns/references/api/define-resource.md +307 -0
- package/skills/app-shell-patterns/references/api/guards/hidden.md +202 -0
- package/skills/app-shell-patterns/references/api/guards/overview.md +354 -0
- package/skills/app-shell-patterns/references/api/guards/pass.md +129 -0
- package/skills/app-shell-patterns/references/api/guards/redirect-to.md +307 -0
- package/skills/app-shell-patterns/references/api/router/use-location.md +240 -0
- package/skills/app-shell-patterns/references/api/router/use-navigate.md +138 -0
- package/skills/app-shell-patterns/references/api/router/use-params.md +218 -0
- package/skills/app-shell-patterns/references/api/use-ai-chat.md +110 -0
- package/skills/app-shell-patterns/references/api/use-app-shell-config.md +126 -0
- package/skills/app-shell-patterns/references/api/use-app-shell-data.md +146 -0
- package/skills/app-shell-patterns/references/api/use-app-shell.md +143 -0
- package/skills/app-shell-patterns/references/api/use-auth.md +145 -0
- package/skills/app-shell-patterns/references/api/use-override-breadcrumb.md +74 -0
- package/skills/app-shell-patterns/references/api/use-page-meta.md +96 -0
- package/skills/app-shell-patterns/references/api/use-register-command-palette-actions.md +90 -0
- package/skills/app-shell-patterns/references/api/use-resolved-locale.md +67 -0
- package/skills/app-shell-patterns/references/api/use-route-error.md +214 -0
- package/skills/app-shell-patterns/references/api/use-theme.md +108 -0
- package/skills/app-shell-patterns/references/api/use-time-zone.md +80 -0
- package/skills/app-shell-patterns/references/api/use-toast.md +107 -0
- package/skills/app-shell-patterns/references/components/action-panel.md +168 -0
- package/skills/app-shell-patterns/references/components/activity-card.md +142 -0
- package/skills/app-shell-patterns/references/components/ai-chat.md +315 -0
- package/skills/app-shell-patterns/references/components/alert.md +202 -0
- package/skills/app-shell-patterns/references/components/app-shell.md +530 -0
- package/skills/app-shell-patterns/references/components/appearance-switcher.md +87 -0
- package/skills/app-shell-patterns/references/components/attachment.md +138 -0
- package/skills/app-shell-patterns/references/components/autocomplete.md +278 -0
- package/skills/app-shell-patterns/references/components/avatar.md +80 -0
- package/skills/app-shell-patterns/references/components/badge.md +309 -0
- package/skills/app-shell-patterns/references/components/button.md +164 -0
- package/skills/app-shell-patterns/references/components/card.md +109 -0
- package/skills/app-shell-patterns/references/components/checkbox.md +169 -0
- package/skills/app-shell-patterns/references/components/combobox.md +318 -0
- package/skills/app-shell-patterns/references/components/command-palette.md +413 -0
- package/skills/app-shell-patterns/references/components/csv-importer.md +214 -0
- package/skills/app-shell-patterns/references/components/data-table.md +953 -0
- package/skills/app-shell-patterns/references/components/date-picker.md +248 -0
- package/skills/app-shell-patterns/references/components/default-header.md +75 -0
- package/skills/app-shell-patterns/references/components/default-sidebar.md +136 -0
- package/skills/app-shell-patterns/references/components/description-card.md +569 -0
- package/skills/app-shell-patterns/references/components/dialog.md +164 -0
- package/skills/app-shell-patterns/references/components/document-progress-card.md +154 -0
- package/skills/app-shell-patterns/references/components/form.md +378 -0
- package/skills/app-shell-patterns/references/components/global-header-layout.md +132 -0
- package/skills/app-shell-patterns/references/components/grid.md +184 -0
- package/skills/app-shell-patterns/references/components/input.md +83 -0
- package/skills/app-shell-patterns/references/components/layout.md +539 -0
- package/skills/app-shell-patterns/references/components/menu.md +218 -0
- package/skills/app-shell-patterns/references/components/metric-card.md +94 -0
- package/skills/app-shell-patterns/references/components/select.md +283 -0
- package/skills/app-shell-patterns/references/components/sheet.md +237 -0
- package/skills/app-shell-patterns/references/components/sidebar-group.md +466 -0
- package/skills/app-shell-patterns/references/components/sidebar-item.md +458 -0
- package/skills/app-shell-patterns/references/components/sidebar-layout.md +258 -0
- package/skills/app-shell-patterns/references/components/spinner.md +81 -0
- package/skills/app-shell-patterns/references/components/table.md +188 -0
- package/skills/app-shell-patterns/references/components/tabs.md +158 -0
- package/skills/app-shell-patterns/references/components/textarea.md +122 -0
- package/skills/app-shell-patterns/references/components/timeline.md +317 -0
- package/skills/app-shell-patterns/references/components/toolbar.md +138 -0
- package/skills/app-shell-patterns/references/components/tooltip.md +144 -0
- package/skills/app-shell-patterns/references/components/with-guard.md +445 -0
- package/skills/app-shell-patterns/references/concepts/authentication.md +301 -0
- package/skills/app-shell-patterns/references/concepts/custom-components.md +59 -0
- package/skills/app-shell-patterns/references/concepts/file-based-routing.md +350 -0
- package/skills/app-shell-patterns/references/{fundamental → concepts}/graphql.md +11 -4
- package/skills/app-shell-patterns/references/concepts/modules-and-resources.md +229 -0
- package/skills/app-shell-patterns/references/concepts/routing-navigation.md +387 -0
- package/skills/app-shell-patterns/references/concepts/sidebar-navigation.md +388 -0
- package/skills/app-shell-patterns/references/{fundamental/design-system.md → concepts/styling-theming.md} +258 -110
- package/skills/app-shell-patterns/references/migrations.md +34 -0
- package/skills/app-shell-patterns/references/pages/{detail.md → document-detail.md} +4 -27
- package/skills/app-shell-patterns/references/patterns/form-composer.md +43 -45
- package/skills/app-shell-patterns/references/patterns/form-modal.md +39 -100
- package/skills/app-shell-patterns/references/patterns/form-sectioned.md +12 -38
- package/skills/app-shell-patterns/references/patterns/form-single-page.md +11 -32
- package/skills/app-shell-patterns/references/patterns/form-wizard.md +12 -53
- package/skills/app-shell-patterns/references/patterns/interaction-confirm.md +11 -27
- package/skills/app-shell-patterns/references/patterns/interaction-multi-select.md +13 -27
- package/skills/app-shell-patterns/references/patterns/interaction-toast.md +10 -34
- package/skills/app-shell-patterns/references/patterns/list-dense-scan.md +11 -86
- package/skills/app-shell-patterns/references/fundamental/components.md +0 -1009
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Sheet
|
|
3
|
+
description: Slide-in panel backed by a Drawer with native swipe-to-dismiss support
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- GENERATED by docs-kit from docs-src/components/sheet.docs.outline.md — do not edit by hand. -->
|
|
7
|
+
|
|
8
|
+
# Sheet
|
|
9
|
+
|
|
10
|
+
The `Sheet` component is a slide-in panel that appears from any edge of the screen. It is backed by Base UI's Drawer primitive and includes native swipe-to-dismiss gesture support on touch devices.
|
|
11
|
+
|
|
12
|
+
## Import
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { Sheet } from "@tailor-platform/app-shell";
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Basic Usage
|
|
19
|
+
|
|
20
|
+
<example-preview name="basic-usage"></example-preview>
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
function BasicUsage() {
|
|
24
|
+
return (
|
|
25
|
+
<Sheet.Root side="right">
|
|
26
|
+
<Sheet.Trigger render={<Button />}>Open Settings</Sheet.Trigger>
|
|
27
|
+
<Sheet.Content>
|
|
28
|
+
<Sheet.Header>
|
|
29
|
+
<Sheet.Title>Settings</Sheet.Title>
|
|
30
|
+
<Sheet.Description>Manage your preferences.</Sheet.Description>
|
|
31
|
+
</Sheet.Header>
|
|
32
|
+
<Sheet.Footer>
|
|
33
|
+
<Sheet.Close render={<Button variant="outline" />}>Close</Sheet.Close>
|
|
34
|
+
</Sheet.Footer>
|
|
35
|
+
</Sheet.Content>
|
|
36
|
+
</Sheet.Root>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Sub-components
|
|
42
|
+
|
|
43
|
+
| Sub-component | Description |
|
|
44
|
+
| ------------------- | ---------------------------------------------------------------------------- |
|
|
45
|
+
| `Sheet.Root` | Manages open/close state and controls the slide direction |
|
|
46
|
+
| `Sheet.Trigger` | Element that opens the sheet when clicked |
|
|
47
|
+
| `Sheet.Content` | The main sheet panel; includes close button and backdrop when `modal={true}` |
|
|
48
|
+
| `Sheet.Header` | Layout wrapper for title and description |
|
|
49
|
+
| `Sheet.Footer` | Layout wrapper for action buttons |
|
|
50
|
+
| `Sheet.Title` | Sheet title (announced by screen readers) |
|
|
51
|
+
| `Sheet.Description` | Additional context below the title |
|
|
52
|
+
| `Sheet.Close` | Button that closes the sheet |
|
|
53
|
+
|
|
54
|
+
## Props
|
|
55
|
+
|
|
56
|
+
### Sheet.Root Props
|
|
57
|
+
|
|
58
|
+
| Prop | Type | Default | Description |
|
|
59
|
+
| -------------- | ---------------------------------------- | --------- | ------------------------------------------------- |
|
|
60
|
+
| `side` | `"top" \| "right" \| "bottom" \| "left"` | `"right"` | Which edge of the screen the sheet slides in from |
|
|
61
|
+
| `open` | `boolean` | - | Controlled open state |
|
|
62
|
+
| `defaultOpen` | `boolean` | `false` | Initial open state (uncontrolled) |
|
|
63
|
+
| `onOpenChange` | `(open: boolean) => void` | - | Callback when open state changes |
|
|
64
|
+
| `modal` | `boolean` | `true` | Whether the sheet is modal |
|
|
65
|
+
| `children` | `React.ReactNode` | - | Sheet sub-components |
|
|
66
|
+
|
|
67
|
+
When `modal={false}`, the sheet does not render a backdrop.
|
|
68
|
+
|
|
69
|
+
### Sheet.Content Props
|
|
70
|
+
|
|
71
|
+
| Prop | Type | Default | Description |
|
|
72
|
+
| ----------- | ---------------------------------------- | ------- | --------------------------------------------------------------- |
|
|
73
|
+
| `size` | `"sm" \| "md" \| "lg" \| "xl" \| "full"` | `"sm"` | Max-width of the sheet panel (applies to left/right sides only) |
|
|
74
|
+
| `className` | `string` | - | Additional CSS classes |
|
|
75
|
+
|
|
76
|
+
Also accepts all standard HTML `<div>` props.
|
|
77
|
+
|
|
78
|
+
### Sheet.Header Props
|
|
79
|
+
|
|
80
|
+
| Prop | Type | Default | Description |
|
|
81
|
+
| -------- | ----------------- | ------- | ------------------------------------------------------- |
|
|
82
|
+
| `action` | `React.ReactNode` | - | Action buttons displayed to the right of the title area |
|
|
83
|
+
|
|
84
|
+
The header renders a close button on the left, title in the center, and action buttons on the right.
|
|
85
|
+
|
|
86
|
+
### Sheet.Trigger / Sheet.Close Props
|
|
87
|
+
|
|
88
|
+
Accept a `render` prop for custom element rendering (Base UI render pattern), plus standard button props.
|
|
89
|
+
|
|
90
|
+
## Sizes
|
|
91
|
+
|
|
92
|
+
Control the width of the sheet panel using the `size` prop on `Sheet.Content`. This applies to `left` and `right` side sheets.
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
<Sheet.Root side="right">
|
|
96
|
+
<Sheet.Trigger render={<Button />}>Open Small</Sheet.Trigger>
|
|
97
|
+
<Sheet.Content size="sm">…</Sheet.Content> {/* 384px (24rem) — default */}
|
|
98
|
+
</Sheet.Root>
|
|
99
|
+
|
|
100
|
+
<Sheet.Root side="right">
|
|
101
|
+
<Sheet.Trigger render={<Button />}>Open Medium</Sheet.Trigger>
|
|
102
|
+
<Sheet.Content size="md">…</Sheet.Content> {/* 512px (32rem) */}
|
|
103
|
+
</Sheet.Root>
|
|
104
|
+
|
|
105
|
+
<Sheet.Root side="right">
|
|
106
|
+
<Sheet.Trigger render={<Button />}>Open Large</Sheet.Trigger>
|
|
107
|
+
<Sheet.Content size="lg">…</Sheet.Content> {/* 720px (45rem) */}
|
|
108
|
+
</Sheet.Root>
|
|
109
|
+
|
|
110
|
+
<Sheet.Root side="right">
|
|
111
|
+
<Sheet.Trigger render={<Button />}>Open XL</Sheet.Trigger>
|
|
112
|
+
<Sheet.Content size="xl">…</Sheet.Content> {/* 960px (60rem) */}
|
|
113
|
+
</Sheet.Root>
|
|
114
|
+
|
|
115
|
+
<Sheet.Root side="right">
|
|
116
|
+
<Sheet.Trigger render={<Button />}>Open Full</Sheet.Trigger>
|
|
117
|
+
<Sheet.Content size="full">…</Sheet.Content> {/* 100% width */}
|
|
118
|
+
</Sheet.Root>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Sides
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
<Sheet.Root side="right">…</Sheet.Root> {/* default — slides from right */}
|
|
125
|
+
<Sheet.Root side="left">…</Sheet.Root> {/* slides from left */}
|
|
126
|
+
<Sheet.Root side="top">…</Sheet.Root> {/* slides from top */}
|
|
127
|
+
<Sheet.Root side="bottom">…</Sheet.Root> {/* slides from bottom */}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The swipe-to-dismiss gesture direction is automatically determined by the `side` prop.
|
|
131
|
+
|
|
132
|
+
## Controlled Usage
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
const [open, setOpen] = useState(false);
|
|
136
|
+
|
|
137
|
+
<Sheet.Root side="right" open={open} onOpenChange={setOpen}>
|
|
138
|
+
<Sheet.Trigger render={<Button />}>Open</Sheet.Trigger>
|
|
139
|
+
<Sheet.Content>
|
|
140
|
+
<Sheet.Header>
|
|
141
|
+
<Sheet.Title>Filters</Sheet.Title>
|
|
142
|
+
</Sheet.Header>
|
|
143
|
+
<Sheet.Footer>
|
|
144
|
+
<Button onClick={() => setOpen(false)}>Apply</Button>
|
|
145
|
+
</Sheet.Footer>
|
|
146
|
+
</Sheet.Content>
|
|
147
|
+
</Sheet.Root>;
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Non-modal Sheet
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
<Sheet.Root side="right" modal={false}>
|
|
154
|
+
<Sheet.Trigger render={<Button />}>Open Inspector</Sheet.Trigger>
|
|
155
|
+
<Sheet.Content>
|
|
156
|
+
<Sheet.Header>
|
|
157
|
+
<Sheet.Title>Inspector</Sheet.Title>
|
|
158
|
+
</Sheet.Header>
|
|
159
|
+
</Sheet.Content>
|
|
160
|
+
</Sheet.Root>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Examples
|
|
164
|
+
|
|
165
|
+
### Header with Actions
|
|
166
|
+
|
|
167
|
+
Place action buttons (e.g., save, edit) to the right of the title using the `action` prop on `Sheet.Header`.
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
<Sheet.Root side="right">
|
|
171
|
+
<Sheet.Trigger render={<Button />}>Edit Record</Sheet.Trigger>
|
|
172
|
+
<Sheet.Content size="lg">
|
|
173
|
+
<Sheet.Header action={<Button size="sm">Save</Button>}>
|
|
174
|
+
<Sheet.Title>Edit Customer</Sheet.Title>
|
|
175
|
+
</Sheet.Header>
|
|
176
|
+
<div className="p-4">
|
|
177
|
+
<Input placeholder="Customer name" />
|
|
178
|
+
</div>
|
|
179
|
+
</Sheet.Content>
|
|
180
|
+
</Sheet.Root>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Filter Panel
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
function FilterPanel() {
|
|
187
|
+
return (
|
|
188
|
+
<Sheet.Root side="right">
|
|
189
|
+
<Sheet.Trigger render={<Button variant="outline" />}>Filters</Sheet.Trigger>
|
|
190
|
+
<Sheet.Content>
|
|
191
|
+
<Sheet.Header>
|
|
192
|
+
<Sheet.Title>Filter Orders</Sheet.Title>
|
|
193
|
+
<Sheet.Description>Narrow down orders by criteria.</Sheet.Description>
|
|
194
|
+
</Sheet.Header>
|
|
195
|
+
<div className="p-4 flex flex-col gap-4">
|
|
196
|
+
<Input placeholder="Customer name" />
|
|
197
|
+
<Input placeholder="Order number" />
|
|
198
|
+
</div>
|
|
199
|
+
<Sheet.Footer>
|
|
200
|
+
<Sheet.Close render={<Button variant="outline" />}>Clear</Sheet.Close>
|
|
201
|
+
<Button>Apply Filters</Button>
|
|
202
|
+
</Sheet.Footer>
|
|
203
|
+
</Sheet.Content>
|
|
204
|
+
</Sheet.Root>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Bottom Sheet on Mobile
|
|
210
|
+
|
|
211
|
+
```tsx
|
|
212
|
+
<Sheet.Root side="bottom">
|
|
213
|
+
<Sheet.Trigger render={<Button />}>More Options</Sheet.Trigger>
|
|
214
|
+
<Sheet.Content>
|
|
215
|
+
<Sheet.Header>
|
|
216
|
+
<Sheet.Title>Actions</Sheet.Title>
|
|
217
|
+
</Sheet.Header>
|
|
218
|
+
<div className="p-4 flex flex-col gap-2">
|
|
219
|
+
<Button variant="ghost">Edit</Button>
|
|
220
|
+
<Button variant="ghost">Duplicate</Button>
|
|
221
|
+
<Button variant="destructive">Delete</Button>
|
|
222
|
+
</div>
|
|
223
|
+
</Sheet.Content>
|
|
224
|
+
</Sheet.Root>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Accessibility
|
|
228
|
+
|
|
229
|
+
- Sheet title is announced by screen readers via `Sheet.Title`
|
|
230
|
+
- Focus is trapped inside the sheet while open
|
|
231
|
+
- Pressing `Escape` closes the sheet
|
|
232
|
+
- The close button is rendered inside `Sheet.Header` in the normal document flow
|
|
233
|
+
|
|
234
|
+
## Related Components
|
|
235
|
+
|
|
236
|
+
- [Dialog](./dialog.md) - Centered modal dialog for critical confirmations
|
|
237
|
+
- [Button](./button.md) - Use as trigger and action buttons
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: SidebarGroup
|
|
3
|
+
description: Collapsible group component for organizing sidebar navigation items with icons and nested structure
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- GENERATED by docs-kit from docs-src/components/sidebar-group.docs.outline.md — do not edit by hand. -->
|
|
7
|
+
|
|
8
|
+
# SidebarGroup
|
|
9
|
+
|
|
10
|
+
`SidebarGroup` creates a collapsible group in the sidebar to organize related navigation items. It supports icons, clickable headers, nested groups, and internationalization.
|
|
11
|
+
|
|
12
|
+
## Import
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { SidebarGroup } from "@tailor-platform/app-shell";
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Basic Usage
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { SidebarGroup, SidebarItem } from "@tailor-platform/app-shell";
|
|
22
|
+
import { Package } from "lucide-react";
|
|
23
|
+
|
|
24
|
+
<DefaultSidebar>
|
|
25
|
+
<SidebarGroup title="Products" icon={<Package />}>
|
|
26
|
+
<SidebarItem to="/products/all" />
|
|
27
|
+
<SidebarItem to="/products/categories" />
|
|
28
|
+
<SidebarItem to="/products/brands" />
|
|
29
|
+
</SidebarGroup>
|
|
30
|
+
</DefaultSidebar>;
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Props
|
|
34
|
+
|
|
35
|
+
| Prop | Type | Default | Description |
|
|
36
|
+
| ------------- | --------------------------- | ------------ | ---------------------------------------------- |
|
|
37
|
+
| `title` | `string \| LocalizedString` | **Required** | Group title (supports i18n) |
|
|
38
|
+
| `icon` | `React.ReactNode` | - | Icon displayed next to title |
|
|
39
|
+
| `to` | `string` | - | Makes title clickable (navigates to URL) |
|
|
40
|
+
| `defaultOpen` | `boolean` | `true` | Initial expanded/collapsed state |
|
|
41
|
+
| `children` | `React.ReactNode` | **Required** | Child items (SidebarItem, nested groups, etc.) |
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
### Collapsible
|
|
46
|
+
|
|
47
|
+
Groups can be expanded or collapsed by clicking the chevron icon:
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
<SidebarGroup title="Products" icon={<Package />}>
|
|
51
|
+
<SidebarItem to="/products/all" />
|
|
52
|
+
<SidebarItem to="/products/categories" />
|
|
53
|
+
</SidebarGroup>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Click the chevron (▶/▼) to toggle:
|
|
57
|
+
|
|
58
|
+
- **Expanded:** Shows all child items
|
|
59
|
+
- **Collapsed:** Hides child items, shows only title
|
|
60
|
+
|
|
61
|
+
### Clickable Header
|
|
62
|
+
|
|
63
|
+
Make the group title a clickable link:
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
<SidebarGroup
|
|
67
|
+
title="Settings"
|
|
68
|
+
icon={<Settings />}
|
|
69
|
+
to="/settings" // Header navigates here
|
|
70
|
+
>
|
|
71
|
+
<SidebarItem to="/settings/profile" />
|
|
72
|
+
<SidebarItem to="/settings/security" />
|
|
73
|
+
</SidebarGroup>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
When `to` is provided:
|
|
77
|
+
|
|
78
|
+
- Title is a clickable link
|
|
79
|
+
- Chevron still collapses/expands children
|
|
80
|
+
- Useful for groups with a landing page
|
|
81
|
+
|
|
82
|
+
### Default State
|
|
83
|
+
|
|
84
|
+
Control whether groups start expanded or collapsed:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
// Starts expanded (default)
|
|
88
|
+
<SidebarGroup title="Recent" defaultOpen={true}>
|
|
89
|
+
<SidebarItem to="/recent/today" />
|
|
90
|
+
</SidebarGroup>
|
|
91
|
+
|
|
92
|
+
// Starts collapsed
|
|
93
|
+
<SidebarGroup title="Archives" defaultOpen={false}>
|
|
94
|
+
<SidebarItem to="/archives/2024" />
|
|
95
|
+
<SidebarItem to="/archives/2023" />
|
|
96
|
+
</SidebarGroup>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Nested Groups
|
|
100
|
+
|
|
101
|
+
Create multi-level navigation:
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
<SidebarGroup title="Products" icon={<Package />}>
|
|
105
|
+
<SidebarItem to="/products/all" />
|
|
106
|
+
|
|
107
|
+
<SidebarGroup title="By Category">
|
|
108
|
+
<SidebarItem to="/products/electronics" />
|
|
109
|
+
<SidebarItem to="/products/clothing" />
|
|
110
|
+
</SidebarGroup>
|
|
111
|
+
|
|
112
|
+
<SidebarGroup title="Archives" defaultOpen={false}>
|
|
113
|
+
<SidebarItem to="/products/archives/2024" />
|
|
114
|
+
<SidebarItem to="/products/archives/2023" />
|
|
115
|
+
</SidebarGroup>
|
|
116
|
+
</SidebarGroup>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Internationalization
|
|
120
|
+
|
|
121
|
+
Titles support i18n with `defineI18nLabels`:
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
import { defineI18nLabels } from "@tailor-platform/app-shell";
|
|
125
|
+
|
|
126
|
+
const labels = defineI18nLabels({
|
|
127
|
+
products: {
|
|
128
|
+
en: "Products",
|
|
129
|
+
ja: "商品",
|
|
130
|
+
},
|
|
131
|
+
settings: {
|
|
132
|
+
en: "Settings",
|
|
133
|
+
ja: "設定",
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
<SidebarGroup title={labels.t("products")} icon={<Package />}>
|
|
138
|
+
<SidebarItem to="/products/all" />
|
|
139
|
+
</SidebarGroup>;
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Examples
|
|
143
|
+
|
|
144
|
+
### Basic Group
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
import { Package } from "lucide-react";
|
|
148
|
+
|
|
149
|
+
<SidebarGroup title="Products" icon={<Package />}>
|
|
150
|
+
<SidebarItem to="/products/all" />
|
|
151
|
+
<SidebarItem to="/products/categories" />
|
|
152
|
+
<SidebarItem to="/products/brands" />
|
|
153
|
+
</SidebarGroup>;
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Clickable Group with Landing Page
|
|
157
|
+
|
|
158
|
+
```tsx
|
|
159
|
+
import { Settings } from "lucide-react";
|
|
160
|
+
|
|
161
|
+
<SidebarGroup title="Settings" icon={<Settings />} to="/settings">
|
|
162
|
+
<SidebarItem to="/settings/profile" />
|
|
163
|
+
<SidebarItem to="/settings/security" />
|
|
164
|
+
<SidebarItem to="/settings/notifications" />
|
|
165
|
+
<SidebarItem to="/settings/billing" />
|
|
166
|
+
</SidebarGroup>;
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Clicking "Settings" navigates to `/settings`, while child items navigate to their specific pages.
|
|
170
|
+
|
|
171
|
+
### Multiple Groups
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
import { Package, ShoppingCart, Users, Settings } from "lucide-react";
|
|
175
|
+
|
|
176
|
+
<DefaultSidebar>
|
|
177
|
+
<SidebarItem to="/dashboard" />
|
|
178
|
+
|
|
179
|
+
<SidebarGroup title="Products" icon={<Package />}>
|
|
180
|
+
<SidebarItem to="/products/all" />
|
|
181
|
+
<SidebarItem to="/products/categories" />
|
|
182
|
+
</SidebarGroup>
|
|
183
|
+
|
|
184
|
+
<SidebarGroup title="Orders" icon={<ShoppingCart />}>
|
|
185
|
+
<SidebarItem to="/orders/pending" />
|
|
186
|
+
<SidebarItem to="/orders/shipped" />
|
|
187
|
+
<SidebarItem to="/orders/completed" />
|
|
188
|
+
</SidebarGroup>
|
|
189
|
+
|
|
190
|
+
<SidebarGroup title="Customers" icon={<Users />}>
|
|
191
|
+
<SidebarItem to="/customers/all" />
|
|
192
|
+
<SidebarItem to="/customers/segments" />
|
|
193
|
+
</SidebarGroup>
|
|
194
|
+
|
|
195
|
+
<SidebarSeparator />
|
|
196
|
+
|
|
197
|
+
<SidebarGroup title="Settings" icon={<Settings />} to="/settings">
|
|
198
|
+
<SidebarItem to="/settings/profile" />
|
|
199
|
+
<SidebarItem to="/settings/billing" />
|
|
200
|
+
</SidebarGroup>
|
|
201
|
+
</DefaultSidebar>;
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Nested Groups
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
import { FolderIcon } from "lucide-react";
|
|
208
|
+
|
|
209
|
+
<SidebarGroup title="Documents" icon={<FolderIcon />}>
|
|
210
|
+
<SidebarItem to="/documents/recent" />
|
|
211
|
+
|
|
212
|
+
<SidebarGroup title="Projects">
|
|
213
|
+
<SidebarItem to="/documents/project-a" />
|
|
214
|
+
<SidebarItem to="/documents/project-b" />
|
|
215
|
+
</SidebarGroup>
|
|
216
|
+
|
|
217
|
+
<SidebarGroup title="Archives" defaultOpen={false}>
|
|
218
|
+
<SidebarItem to="/documents/archives/2024" />
|
|
219
|
+
<SidebarItem to="/documents/archives/2023" />
|
|
220
|
+
<SidebarItem to="/documents/archives/2022" />
|
|
221
|
+
</SidebarGroup>
|
|
222
|
+
</SidebarGroup>;
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Collapsed by Default
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
<SidebarGroup title="Admin Tools" icon={<Wrench />} defaultOpen={false}>
|
|
229
|
+
<SidebarItem to="/admin/users" />
|
|
230
|
+
<SidebarItem to="/admin/logs" />
|
|
231
|
+
<SidebarItem to="/admin/system" />
|
|
232
|
+
</SidebarGroup>
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Useful for:
|
|
236
|
+
|
|
237
|
+
- Less frequently used sections
|
|
238
|
+
- Admin panels
|
|
239
|
+
- Advanced features
|
|
240
|
+
- Archives
|
|
241
|
+
|
|
242
|
+
### With Conditional Items
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
import { WithGuard } from "@tailor-platform/app-shell";
|
|
246
|
+
|
|
247
|
+
const isAdmin = ({ context }) => (context.currentUser?.role === "admin" ? pass() : hidden());
|
|
248
|
+
|
|
249
|
+
<SidebarGroup title="Settings" icon={<Settings />}>
|
|
250
|
+
<SidebarItem to="/settings/profile" />
|
|
251
|
+
<SidebarItem to="/settings/notifications" />
|
|
252
|
+
|
|
253
|
+
<WithGuard guards={[isAdmin]}>
|
|
254
|
+
<SidebarItem to="/settings/users" />
|
|
255
|
+
<SidebarItem to="/settings/permissions" />
|
|
256
|
+
</WithGuard>
|
|
257
|
+
</SidebarGroup>;
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### With External Links
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
import { HelpCircle, FileText, ExternalLink } from "lucide-react";
|
|
264
|
+
|
|
265
|
+
<SidebarGroup title="Help" icon={<HelpCircle />}>
|
|
266
|
+
<SidebarItem to="/help/faq" />
|
|
267
|
+
<SidebarItem to="https://docs.example.com" title="Documentation" icon={<FileText />} external />
|
|
268
|
+
<SidebarItem to="https://support.example.com" title="Support" icon={<ExternalLink />} external />
|
|
269
|
+
</SidebarGroup>;
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### With Custom Separator
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
<DefaultSidebar>
|
|
276
|
+
<SidebarGroup title="Main" icon={<Home />}>
|
|
277
|
+
<SidebarItem to="/dashboard" />
|
|
278
|
+
<SidebarItem to="/analytics" />
|
|
279
|
+
</SidebarGroup>
|
|
280
|
+
|
|
281
|
+
<SidebarSeparator />
|
|
282
|
+
|
|
283
|
+
<SidebarGroup title="Management" icon={<Settings />}>
|
|
284
|
+
<SidebarItem to="/products" />
|
|
285
|
+
<SidebarItem to="/orders" />
|
|
286
|
+
</SidebarGroup>
|
|
287
|
+
</DefaultSidebar>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Visual Structure
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
▼ Products ← Group header (clickable if `to` provided)
|
|
294
|
+
• All Products ← SidebarItem
|
|
295
|
+
• Categories ← SidebarItem
|
|
296
|
+
▼ Archives ← Nested SidebarGroup
|
|
297
|
+
• 2024 ← SidebarItem
|
|
298
|
+
• 2023 ← SidebarItem
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
When collapsed:
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
▶ Products ← Collapsed group
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## Active State
|
|
308
|
+
|
|
309
|
+
When a child item is active, the group:
|
|
310
|
+
|
|
311
|
+
- Remains expanded (if it was collapsed)
|
|
312
|
+
- Group title gets highlighted (if `to` is provided and matches current route)
|
|
313
|
+
|
|
314
|
+
```tsx
|
|
315
|
+
// User is on /settings/profile
|
|
316
|
+
<SidebarGroup title="Settings" to="/settings">
|
|
317
|
+
<SidebarItem to="/settings/profile" /> {/* Active */}
|
|
318
|
+
<SidebarItem to="/settings/security" />
|
|
319
|
+
</SidebarGroup>
|
|
320
|
+
|
|
321
|
+
// Group title is highlighted (matches /settings prefix)
|
|
322
|
+
// /settings/profile item is highlighted
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## Styling
|
|
326
|
+
|
|
327
|
+
### Custom Icon Styling
|
|
328
|
+
|
|
329
|
+
```tsx
|
|
330
|
+
<SidebarGroup title="Products" icon={<Package className="text-blue-500" />}>
|
|
331
|
+
{/* ... */}
|
|
332
|
+
</SidebarGroup>
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Group Title Styling
|
|
336
|
+
|
|
337
|
+
The title styling is controlled by AppShell's theme. `SidebarGroup` takes no `className`, and there is no group-title class to target — adjust the sidebar tokens, or target the button slot (which also matches plain `SidebarItem`s):
|
|
338
|
+
|
|
339
|
+
```css
|
|
340
|
+
:root {
|
|
341
|
+
--sidebar-foreground: oklch(0.2 0 0);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
[data-slot="sidebar-menu-button"] {
|
|
345
|
+
font-weight: 600;
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Accessibility
|
|
350
|
+
|
|
351
|
+
- Semantic HTML structure
|
|
352
|
+
- ARIA labels for expand/collapse state
|
|
353
|
+
- Keyboard navigation (Tab, Enter, Space)
|
|
354
|
+
- Screen reader announcements for state changes
|
|
355
|
+
- Proper heading hierarchy
|
|
356
|
+
|
|
357
|
+
## Best Practices
|
|
358
|
+
|
|
359
|
+
### Do:
|
|
360
|
+
|
|
361
|
+
- ✅ Group related items logically
|
|
362
|
+
- ✅ Use clear, descriptive group titles
|
|
363
|
+
- ✅ Provide icons for visual recognition
|
|
364
|
+
- ✅ Start collapsed for less-used sections
|
|
365
|
+
- ✅ Keep groups shallow (max 2 levels of nesting)
|
|
366
|
+
|
|
367
|
+
### Don't:
|
|
368
|
+
|
|
369
|
+
- ❌ Create groups with only 1 item (use SidebarItem directly)
|
|
370
|
+
- ❌ Nest more than 2 levels deep (hard to navigate)
|
|
371
|
+
- ❌ Use very long group titles (keep to 1-2 words)
|
|
372
|
+
- ❌ Mix unrelated items in same group
|
|
373
|
+
- ❌ Forget icons (helps with visual scanning)
|
|
374
|
+
|
|
375
|
+
## When to Use
|
|
376
|
+
|
|
377
|
+
**Use SidebarGroup when:**
|
|
378
|
+
|
|
379
|
+
- You have 3+ related navigation items
|
|
380
|
+
- Items share a common category or theme
|
|
381
|
+
- You want to organize a large navigation menu
|
|
382
|
+
- Users need to focus on specific sections
|
|
383
|
+
|
|
384
|
+
**Use SidebarItem directly when:**
|
|
385
|
+
|
|
386
|
+
- You have standalone top-level navigation
|
|
387
|
+
- Items don't fit into logical groups
|
|
388
|
+
- You want a flat, simple navigation structure
|
|
389
|
+
|
|
390
|
+
## Comparison
|
|
391
|
+
|
|
392
|
+
| Feature | SidebarGroup | SidebarItem |
|
|
393
|
+
| --------------- | ---------------------- | --------------- |
|
|
394
|
+
| **Purpose** | Organize related items | Individual link |
|
|
395
|
+
| **Collapsible** | ✅ Yes | ❌ No |
|
|
396
|
+
| **Contains** | Multiple items | Self (link) |
|
|
397
|
+
| **Icon** | Group identifier | Link identifier |
|
|
398
|
+
| **Clickable** | Optional (`to` prop) | Always |
|
|
399
|
+
| **Nesting** | Can contain groups | Leaf node |
|
|
400
|
+
|
|
401
|
+
## TypeScript
|
|
402
|
+
|
|
403
|
+
Full type safety:
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
import { type SidebarGroupProps } from "@tailor-platform/app-shell";
|
|
407
|
+
|
|
408
|
+
const groupProps: SidebarGroupProps = {
|
|
409
|
+
title: "Products",
|
|
410
|
+
icon: <Package />,
|
|
411
|
+
to: "/products",
|
|
412
|
+
defaultOpen: true,
|
|
413
|
+
children: <SidebarItem to="/products/all" />,
|
|
414
|
+
};
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
## Troubleshooting
|
|
418
|
+
|
|
419
|
+
### Group not expanding/collapsing
|
|
420
|
+
|
|
421
|
+
**Problem:** Clicking chevron doesn't toggle group
|
|
422
|
+
|
|
423
|
+
**Solution:**
|
|
424
|
+
|
|
425
|
+
1. Check browser console for errors
|
|
426
|
+
2. Ensure children are valid React elements
|
|
427
|
+
3. Verify AppShell is properly configured
|
|
428
|
+
|
|
429
|
+
### Title not clickable
|
|
430
|
+
|
|
431
|
+
**Problem:** Clicking title doesn't navigate
|
|
432
|
+
|
|
433
|
+
**Solution:** Add the `to` prop:
|
|
434
|
+
|
|
435
|
+
```tsx
|
|
436
|
+
<SidebarGroup title="Settings" to="/settings">
|
|
437
|
+
{/* ... */}
|
|
438
|
+
</SidebarGroup>
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
Without `to`, only the chevron is clickable (for expand/collapse).
|
|
442
|
+
|
|
443
|
+
### Icon not showing
|
|
444
|
+
|
|
445
|
+
**Problem:** Icon doesn't appear
|
|
446
|
+
|
|
447
|
+
**Solution:**
|
|
448
|
+
|
|
449
|
+
1. Check that icon is a valid React element
|
|
450
|
+
2. Import the icon correctly
|
|
451
|
+
3. Verify icon library is installed
|
|
452
|
+
|
|
453
|
+
## Related Components
|
|
454
|
+
|
|
455
|
+
- [SidebarItem](./sidebar-item.md) - Individual navigation items
|
|
456
|
+
- [DefaultSidebar](./sidebar-layout.md) - Container for groups
|
|
457
|
+
- [WithGuard](./with-guard.md) - Conditional rendering
|
|
458
|
+
|
|
459
|
+
## Related Concepts
|
|
460
|
+
|
|
461
|
+
- [Sidebar Navigation](../concepts/sidebar-navigation.md) - Sidebar customization guide
|
|
462
|
+
- [Internationalization](../api/define-i18n-labels.md) - Multi-language support
|
|
463
|
+
|
|
464
|
+
## API Reference
|
|
465
|
+
|
|
466
|
+
- [defineI18nLabels](../api/define-i18n-labels.md) - Internationalization helper
|