@tailor-platform/app-shell 1.15.0 → 1.17.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 +811 -131
- package/dist/app-shell.js +7155 -5797
- package/dist/{appshell-DLVBFo5J.js → appshell-CahhZy7v.js} +656 -524
- package/dist/semantic-contrast.test.ts +154 -0
- package/dist/style-entry.d.ts +147 -92
- package/dist/testing.d.ts +152 -95
- package/dist/testing.js +1 -1
- package/dist/theme-bridge.test.ts +101 -1
- package/dist/theme.bridge.css +91 -0
- package/dist/theme.css +6 -1
- package/dist/themes/_template.css +7 -1
- package/dist/themes/bloom.css +0 -6
- package/dist/themes/cream.css +0 -6
- package/dist/themes/default.css +389 -69
- package/dist/vite-plugin.d.ts +147 -92
- package/package.json +8 -8
- package/skills/app-shell-patterns/SKILL.md +108 -19
- 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 +132 -0
- package/skills/app-shell-patterns/references/api/use-app-shell-data.md +150 -0
- package/skills/app-shell-patterns/references/api/use-app-shell.md +150 -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 +104 -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 +181 -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 +1168 -0
- package/skills/app-shell-patterns/references/components/date-picker.md +259 -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/filter-rail.md +165 -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 +472 -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/sidebar-section.md +114 -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 +356 -0
- package/skills/app-shell-patterns/references/{fundamental → concepts}/graphql.md +31 -18
- package/skills/app-shell-patterns/references/concepts/modules-and-resources.md +229 -0
- package/skills/app-shell-patterns/references/concepts/routing-navigation.md +425 -0
- package/skills/app-shell-patterns/references/concepts/sidebar-navigation.md +420 -0
- package/skills/app-shell-patterns/references/concepts/styling-theming.md +785 -0
- package/skills/app-shell-patterns/references/migrations.md +55 -0
- package/skills/app-shell-patterns/references/pages/{detail.md → document-detail.md} +10 -33
- package/skills/app-shell-patterns/references/patterns/form-composer.md +43 -45
- package/skills/app-shell-patterns/references/patterns/form-modal.md +37 -92
- 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 +136 -139
- package/skills/app-shell-patterns/references/patterns/interaction-toast.md +10 -34
- package/skills/app-shell-patterns/references/patterns/list-dense-scan.md +13 -88
- package/skills/app-shell-patterns/references/fundamental/components.md +0 -1009
- package/skills/app-shell-patterns/references/fundamental/design-system.md +0 -440
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: SidebarLayout
|
|
3
|
+
description: Default AppShell layout with a built-in sidebar, content header, optional app-wide top bar, and an escape-hatch body slot
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- GENERATED by docs-kit from docs-src/components/sidebar-layout.docs.outline.md — do not edit by hand. -->
|
|
7
|
+
|
|
8
|
+
# SidebarLayout
|
|
9
|
+
|
|
10
|
+
`SidebarLayout` is the default AppShell layout. By default it renders:
|
|
11
|
+
|
|
12
|
+
- `SidebarLayout.DefaultSidebar`
|
|
13
|
+
- `SidebarLayout.DefaultHeader`
|
|
14
|
+
- the current route outlet
|
|
15
|
+
|
|
16
|
+
You can replace the sidebar, replace the content header, add a full-width `topBar` above the whole shell, or take over the entire region beside the sidebar with the `body` slot.
|
|
17
|
+
|
|
18
|
+
If you want the opinionated "global app header + icon rail" mode, use [`GlobalHeaderLayout`](./global-header-layout.md), which is built on top of `SidebarLayout`.
|
|
19
|
+
|
|
20
|
+
## Import
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { SidebarLayout } from "@tailor-platform/app-shell";
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Basic usage
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { AppShell, SidebarLayout } from "@tailor-platform/app-shell";
|
|
30
|
+
|
|
31
|
+
function App() {
|
|
32
|
+
return (
|
|
33
|
+
<AppShell modules={modules}>
|
|
34
|
+
<SidebarLayout />
|
|
35
|
+
</AppShell>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This gives you:
|
|
41
|
+
|
|
42
|
+
- ✅ Responsive sidebar with auto-generated navigation from modules
|
|
43
|
+
- ✅ Breadcrumb navigation
|
|
44
|
+
- ✅ Theme toggle via the built-in header
|
|
45
|
+
- ✅ Mobile-friendly collapse behavior
|
|
46
|
+
|
|
47
|
+
## Props
|
|
48
|
+
|
|
49
|
+
### Common props
|
|
50
|
+
|
|
51
|
+
| Prop | Type | Default | Description |
|
|
52
|
+
| ------------- | ----------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
53
|
+
| `sidebar` | `React.ReactNode` | `<SidebarLayout.DefaultSidebar />` | Replaces the entire sidebar region. |
|
|
54
|
+
| `defaultOpen` | `boolean` | `true` | Whether the sidebar starts expanded on desktop. |
|
|
55
|
+
| `collapsible` | `boolean` | `true` | Whether the sidebar can be collapsed. When `false`, toggle controls are hidden and `defaultOpen` is ignored. |
|
|
56
|
+
| `topBar` | `React.ReactNode` | - | Full-width bar above both the sidebar and the content region. |
|
|
57
|
+
|
|
58
|
+
### Default content mode
|
|
59
|
+
|
|
60
|
+
Use this when AppShell should keep owning the content column.
|
|
61
|
+
|
|
62
|
+
| Prop | Type | Default | Description |
|
|
63
|
+
| ---------- | --------------------------------------------------------------- | --------------------------------- | ----------------------------------------------------------- |
|
|
64
|
+
| `header` | `React.ReactNode` | `<SidebarLayout.DefaultHeader />` | Replaces the content header above the main column. |
|
|
65
|
+
| `children` | `(props: { Outlet: () => React.ReactNode }) => React.ReactNode` | current route outlet | Custom content renderer that wraps or surrounds the outlet. |
|
|
66
|
+
|
|
67
|
+
### Body-slot mode
|
|
68
|
+
|
|
69
|
+
Use this when you need to compose your own columns beside the sidebar.
|
|
70
|
+
|
|
71
|
+
| Prop | Type | Default | Description |
|
|
72
|
+
| ------ | ----------------- | -------- | ------------------------------------------------------------------------------------------------------------- |
|
|
73
|
+
| `body` | `React.ReactNode` | required | Replaces everything to the right of the sidebar. Compose it with `ContentContainer`, `Outlet`, and `Trigger`. |
|
|
74
|
+
|
|
75
|
+
`body` is mutually exclusive with `header` and `children`, because it replaces the region those props normally describe.
|
|
76
|
+
|
|
77
|
+
## Extending the built-in header
|
|
78
|
+
|
|
79
|
+
The supported "small customization" path is to pass `SidebarLayout.DefaultHeader` into the `header` slot and fill its `actions` cluster.
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { AppearanceSwitcher, Button, SidebarLayout } from "@tailor-platform/app-shell";
|
|
83
|
+
import { BellIcon } from "lucide-react";
|
|
84
|
+
|
|
85
|
+
<SidebarLayout
|
|
86
|
+
header={
|
|
87
|
+
<SidebarLayout.DefaultHeader
|
|
88
|
+
actions={[
|
|
89
|
+
<Button key="notifications" variant="outline" size="icon" aria-label="Notifications">
|
|
90
|
+
<BellIcon className="size-4" />
|
|
91
|
+
</Button>,
|
|
92
|
+
<AppearanceSwitcher key="appearance" />,
|
|
93
|
+
]}
|
|
94
|
+
/>
|
|
95
|
+
}
|
|
96
|
+
/>;
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`actions` replaces the entire right-hand cluster. If you still want the built-in appearance switcher, include `<AppearanceSwitcher />` yourself.
|
|
100
|
+
|
|
101
|
+
## Replacing the sidebar
|
|
102
|
+
|
|
103
|
+
Pass `sidebar` to replace the whole left-side region. The built-in component is [`SidebarLayout.DefaultSidebar`](./default-sidebar.md), also exported as `DefaultSidebar`.
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
import {
|
|
107
|
+
SidebarGroup,
|
|
108
|
+
SidebarItem,
|
|
109
|
+
SidebarLayout,
|
|
110
|
+
SidebarSeparator,
|
|
111
|
+
} from "@tailor-platform/app-shell";
|
|
112
|
+
|
|
113
|
+
<SidebarLayout
|
|
114
|
+
sidebar={
|
|
115
|
+
<SidebarLayout.DefaultSidebar>
|
|
116
|
+
<SidebarItem to="/" />
|
|
117
|
+
<SidebarSeparator />
|
|
118
|
+
<SidebarGroup title="Main">
|
|
119
|
+
<SidebarItem to="/dashboard" />
|
|
120
|
+
<SidebarItem to="/orders" />
|
|
121
|
+
</SidebarGroup>
|
|
122
|
+
</SidebarLayout.DefaultSidebar>
|
|
123
|
+
}
|
|
124
|
+
/>;
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Adding an app-wide top bar
|
|
128
|
+
|
|
129
|
+
`topBar` renders above the whole shell, spanning both the sidebar and the content region.
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
<SidebarLayout topBar={<MyGlobalTopBar />} sidebar={<SidebarLayout.DefaultSidebar hideHeader />} />
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
When `topBar` is present, the fixed sidebar is offset below it. The bar should be `3.5rem` tall (`h-14`) to match the built-in layout.
|
|
136
|
+
|
|
137
|
+
If you specifically want AppShell's opinionated global-header mode, use [`GlobalHeaderLayout`](./global-header-layout.md), which wires the top bar, icon rail, and matching default sidebar for you.
|
|
138
|
+
|
|
139
|
+
## Owning the region beside the sidebar
|
|
140
|
+
|
|
141
|
+
Use `body` when the stock content column is too restrictive and you need your own side columns.
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
<SidebarLayout
|
|
145
|
+
body={
|
|
146
|
+
<>
|
|
147
|
+
<aside className="w-64 shrink-0 overflow-y-auto border-r">
|
|
148
|
+
<TableOfContents />
|
|
149
|
+
</aside>
|
|
150
|
+
<SidebarLayout.ContentContainer header={<SidebarLayout.DefaultHeader />}>
|
|
151
|
+
<SidebarLayout.Outlet />
|
|
152
|
+
</SidebarLayout.ContentContainer>
|
|
153
|
+
<aside className="w-96 shrink-0 overflow-y-auto border-l">
|
|
154
|
+
<AssistantPanel />
|
|
155
|
+
</aside>
|
|
156
|
+
</>
|
|
157
|
+
}
|
|
158
|
+
/>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`SidebarLayout.ContentContainer` is the stock main column: inset padding, pinned header slot, scroll region, and `useAppShellScrollContainer()` support. `SidebarLayout.Trigger` exposes the built-in sidebar toggle so custom headers do not need DOM workarounds.
|
|
162
|
+
|
|
163
|
+
## Reading and controlling the sidebar
|
|
164
|
+
|
|
165
|
+
Use `useAppShellSidebar()` to read and control the sidebar state instead of observing internal DOM attributes or clicking the trigger through the DOM.
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
import { useAppShellSidebar } from "@tailor-platform/app-shell";
|
|
169
|
+
|
|
170
|
+
function CustomHeader() {
|
|
171
|
+
const { open, isMobile, toggle } = useAppShellSidebar();
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<div className="flex items-center justify-between border-b px-4 py-3">
|
|
175
|
+
<button type="button" onClick={toggle}>
|
|
176
|
+
{open ? "Hide navigation" : "Show navigation"}
|
|
177
|
+
</button>
|
|
178
|
+
<span>{isMobile ? "Mobile" : "Desktop"}</span>
|
|
179
|
+
</div>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Outside `SidebarLayout`, the hook returns a safe fallback (`open: true`, `isMobile: false`, no-op setters) rather than throwing.
|
|
185
|
+
|
|
186
|
+
## Reusing the built-in breadcrumb
|
|
187
|
+
|
|
188
|
+
`DynamicBreadcrumb` is exported when you want the same route-driven breadcrumb in a custom header or top bar:
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
import { DynamicBreadcrumb, SidebarLayout } from "@tailor-platform/app-shell";
|
|
192
|
+
|
|
193
|
+
<header className="flex items-center gap-3 border-b px-4 py-3">
|
|
194
|
+
<SidebarLayout.Trigger />
|
|
195
|
+
<DynamicBreadcrumb />
|
|
196
|
+
</header>;
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Accessing the content scroll container
|
|
200
|
+
|
|
201
|
+
The AppShell is viewport-bounded (`h-svh`), so the **document itself does not scroll** — the content area does. Code that previously relied on `window`/document scroll (reading `window.scrollY`, listening to `window`'s `scroll` event, `window.scrollTo(...)`, or an `IntersectionObserver` with the default viewport root) should target the content scroll container instead.
|
|
202
|
+
|
|
203
|
+
Use the `useAppShellScrollContainer()` hook to get a ref to that element from any page:
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
import { useAppShellScrollContainer } from "@tailor-platform/app-shell";
|
|
207
|
+
import { useEffect, useState } from "react";
|
|
208
|
+
|
|
209
|
+
function ReadingProgress() {
|
|
210
|
+
const scrollRef = useAppShellScrollContainer();
|
|
211
|
+
const [progress, setProgress] = useState(0);
|
|
212
|
+
|
|
213
|
+
useEffect(() => {
|
|
214
|
+
const el = scrollRef.current;
|
|
215
|
+
if (!el) return;
|
|
216
|
+
const onScroll = () => {
|
|
217
|
+
const max = el.scrollHeight - el.clientHeight;
|
|
218
|
+
setProgress(max > 0 ? el.scrollTop / max : 0);
|
|
219
|
+
};
|
|
220
|
+
onScroll();
|
|
221
|
+
el.addEventListener("scroll", onScroll, { passive: true });
|
|
222
|
+
return () => el.removeEventListener("scroll", onScroll);
|
|
223
|
+
}, [scrollRef]);
|
|
224
|
+
|
|
225
|
+
return <progress value={progress} />;
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
The same element handles imperative scrolling (`scrollRef.current?.scrollTo({ top: 0, behavior: "smooth" })`) and works as an `IntersectionObserver` root (`new IntersectionObserver(cb, { root: scrollRef.current })`).
|
|
230
|
+
|
|
231
|
+
Notes:
|
|
232
|
+
|
|
233
|
+
- The element mounts with the layout, above your page, so read `ref.current` inside an effect — it is populated by the time effects run, not during render.
|
|
234
|
+
- On a [`<Layout fill>`](./layout.md#fill-mode) page this element does **not** scroll; its children (for example a `DataTable`) manage their own scrolling.
|
|
235
|
+
- Outside a `SidebarLayout` (a fully custom layout) the returned ref's `current` is always `null` — such layouts own their own scroll region.
|
|
236
|
+
- For non-React access (CSS, tests, plain DOM) the container also carries a `data-appshell-scroll-container` attribute: `document.querySelector("[data-appshell-scroll-container]")`.
|
|
237
|
+
|
|
238
|
+
## Styling
|
|
239
|
+
|
|
240
|
+
The sidebar and layout are styled with the library's internal `astw:`-prefixed utilities. Write **plain** Tailwind utilities in your own markup — see [Styling AppShell components](../concepts/styling-theming.md#styling-appshell-components).
|
|
241
|
+
|
|
242
|
+
## Accessibility
|
|
243
|
+
|
|
244
|
+
SidebarLayout includes built-in accessibility features:
|
|
245
|
+
|
|
246
|
+
- **Keyboard navigation** for sidebar interaction
|
|
247
|
+
- **ARIA labels** on built-in controls
|
|
248
|
+
- **Focus management** when the sidebar opens on mobile
|
|
249
|
+
- **Responsive behavior** that works with keyboard, mouse, and touch input
|
|
250
|
+
|
|
251
|
+
## Related
|
|
252
|
+
|
|
253
|
+
- [AppShell](./app-shell.md) - root component
|
|
254
|
+
- [DefaultHeader](./default-header.md) - built-in content header (`SidebarLayout.DefaultHeader`)
|
|
255
|
+
- [DefaultSidebar](./default-sidebar.md) - built-in sidebar (`SidebarLayout.DefaultSidebar`)
|
|
256
|
+
- [GlobalHeaderLayout](./global-header-layout.md) - opinionated app-wide header mode built on SidebarLayout
|
|
257
|
+
- [AppearanceSwitcher](./appearance-switcher.md) - color-theme dropdown for header actions
|
|
258
|
+
- [usePageMeta](../api/use-page-meta.md) - route metadata lookup used by sidebar items
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: SidebarSection
|
|
3
|
+
description: Static, non-collapsible heading for grouping flat sidebar navigation items
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- GENERATED by docs-kit from docs-src/components/sidebar-section.docs.outline.md — do not edit by hand. -->
|
|
7
|
+
|
|
8
|
+
# SidebarSection
|
|
9
|
+
|
|
10
|
+
`SidebarSection` places a static heading above a run of flat navigation items. Unlike [`SidebarGroup`](./sidebar-group.md), a section is neither collapsible nor navigable, and its items keep the same styling and indentation as top-level items.
|
|
11
|
+
|
|
12
|
+
## Import
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { SidebarSection } from "@tailor-platform/app-shell";
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Basic Usage
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import {
|
|
22
|
+
DefaultSidebar,
|
|
23
|
+
SidebarItem,
|
|
24
|
+
SidebarSection,
|
|
25
|
+
SidebarSeparator,
|
|
26
|
+
} from "@tailor-platform/app-shell";
|
|
27
|
+
|
|
28
|
+
<DefaultSidebar>
|
|
29
|
+
<SidebarItem to="/overview" />
|
|
30
|
+
|
|
31
|
+
<SidebarSeparator />
|
|
32
|
+
|
|
33
|
+
<SidebarSection title="Services">
|
|
34
|
+
<SidebarItem to="/ai-gateways" />
|
|
35
|
+
<SidebarItem to="/applications" />
|
|
36
|
+
<SidebarItem to="/auth-connections" />
|
|
37
|
+
</SidebarSection>
|
|
38
|
+
|
|
39
|
+
<SidebarSeparator />
|
|
40
|
+
|
|
41
|
+
<SidebarSection title="Logs">
|
|
42
|
+
<SidebarItem to="/activity-logs" />
|
|
43
|
+
<SidebarItem to="/dataplane-logs" />
|
|
44
|
+
</SidebarSection>
|
|
45
|
+
</DefaultSidebar>;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Props
|
|
49
|
+
|
|
50
|
+
| Prop | Type | Default | Description |
|
|
51
|
+
| ---------- | --------------------------- | ------------ | --------------------------------- |
|
|
52
|
+
| `title` | `string \| LocalizedString` | **Required** | Section heading (supports i18n) |
|
|
53
|
+
| `children` | `React.ReactNode` | **Required** | Child items (usually SidebarItem) |
|
|
54
|
+
|
|
55
|
+
## Behavior
|
|
56
|
+
|
|
57
|
+
- **Not interactive.** The heading is plain text: it is not a link and has no expand/collapse toggle.
|
|
58
|
+
- **Flat items.** Children render at the same level as top-level `SidebarItem`s, not as an indented submenu.
|
|
59
|
+
- **Icon rail.** When the sidebar collapses to an icon rail, the heading is hidden and the items stay in the rail as ordinary icons. Unlike `SidebarGroup`, there is no hover flyout.
|
|
60
|
+
- **No automatic dividers.** Add a `SidebarSeparator` between sections where you want a line.
|
|
61
|
+
|
|
62
|
+
## Internationalization
|
|
63
|
+
|
|
64
|
+
Titles support i18n with `defineI18nLabels`:
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { defineI18nLabels } from "@tailor-platform/app-shell";
|
|
68
|
+
|
|
69
|
+
const labels = defineI18nLabels({
|
|
70
|
+
en: { services: "Services" },
|
|
71
|
+
ja: { services: "サービス" },
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
<SidebarSection title={labels.t("services")}>
|
|
75
|
+
<SidebarItem to="/ai-gateways" />
|
|
76
|
+
</SidebarSection>;
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## When to Use
|
|
80
|
+
|
|
81
|
+
**Use SidebarSection when:**
|
|
82
|
+
|
|
83
|
+
- You want to label a run of items with a heading, but keep them always visible
|
|
84
|
+
- The items are peers of your top-level items, not children of a parent page
|
|
85
|
+
- You want the items to stay as individual icons in the icon rail
|
|
86
|
+
|
|
87
|
+
**Use SidebarGroup when:**
|
|
88
|
+
|
|
89
|
+
- Users should be able to collapse the items
|
|
90
|
+
- The items belong under a parent with its own icon (or landing page via `to`)
|
|
91
|
+
- You need nesting
|
|
92
|
+
|
|
93
|
+
| Feature | SidebarSection | SidebarGroup |
|
|
94
|
+
| ------------------- | ----------------- | ------------------------- |
|
|
95
|
+
| **Collapsible** | ❌ No | ✅ Yes |
|
|
96
|
+
| **Heading is link** | ❌ No | Optional (`to` prop) |
|
|
97
|
+
| **Icon** | ❌ No | Optional |
|
|
98
|
+
| **Child styling** | Same as top level | Indented submenu |
|
|
99
|
+
| **Icon rail** | Heading hidden | Group icon opens a flyout |
|
|
100
|
+
| **Nesting** | Not intended | Can contain groups |
|
|
101
|
+
|
|
102
|
+
## Accessibility
|
|
103
|
+
|
|
104
|
+
The children are rendered as their own list, labelled by the heading, so screen readers announce the section name (for example, "Services, list, 3 items") when entering it.
|
|
105
|
+
|
|
106
|
+
## Related Components
|
|
107
|
+
|
|
108
|
+
- [SidebarGroup](./sidebar-group.md) - Collapsible, nested navigation groups
|
|
109
|
+
- [SidebarItem](./sidebar-item.md) - Individual navigation items
|
|
110
|
+
- [DefaultSidebar](./default-sidebar.md) - Container for sidebar navigation
|
|
111
|
+
|
|
112
|
+
## Related Concepts
|
|
113
|
+
|
|
114
|
+
- [Sidebar Navigation](../concepts/sidebar-navigation.md) - Sidebar customization guide
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Spinner
|
|
3
|
+
description: Lightweight loading indicator component with accessible defaults and preset sizes
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- GENERATED by docs-kit from docs-src/components/spinner.docs.outline.md — do not edit by hand. -->
|
|
7
|
+
|
|
8
|
+
# Spinner
|
|
9
|
+
|
|
10
|
+
`Spinner` is AppShell's reusable loading indicator. It renders a small rotating SVG and is used throughout the built-in UI for loading states such as `ActionPanel`, command palette search, and CSV import progress.
|
|
11
|
+
|
|
12
|
+
## Import
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { Spinner } 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 <Spinner aria-label="Loading" />;
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Props
|
|
29
|
+
|
|
30
|
+
`Spinner` accepts all standard `<svg>` props plus one AppShell prop:
|
|
31
|
+
|
|
32
|
+
| Prop | Type | Default | Description |
|
|
33
|
+
| ------ | ----------------------------------- | ----------- | -------------------------------------------------------------------------- |
|
|
34
|
+
| `size` | `"xs" \| "sm" \| "default" \| "lg"` | `"default"` | Preset square size. Ignored when `width` or `height` is passed explicitly. |
|
|
35
|
+
|
|
36
|
+
Preset sizes map to:
|
|
37
|
+
|
|
38
|
+
| `size` | Pixels |
|
|
39
|
+
| ----------- | ------ |
|
|
40
|
+
| `"xs"` | `12` |
|
|
41
|
+
| `"sm"` | `14` |
|
|
42
|
+
| `"default"` | `16` |
|
|
43
|
+
| `"lg"` | `20` |
|
|
44
|
+
|
|
45
|
+
## Accessibility
|
|
46
|
+
|
|
47
|
+
`Spinner` defaults to decorative output unless you give it an accessible name:
|
|
48
|
+
|
|
49
|
+
- with `aria-label` or `aria-labelledby`, it renders with `role="status"`
|
|
50
|
+
- with `aria-hidden={true}`, it stays decorative
|
|
51
|
+
- with neither, it is treated as decorative and gets `aria-hidden="true"`
|
|
52
|
+
|
|
53
|
+
Use a label when the spinner is the primary visible loading affordance:
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
<Spinner size="sm" aria-label="Loading orders" />
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
When the surrounding control already has its own accessible name, keep the spinner decorative:
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
<Button disabled>
|
|
63
|
+
<Spinner size="sm" aria-hidden />
|
|
64
|
+
Saving
|
|
65
|
+
</Button>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Sizing and styling
|
|
69
|
+
|
|
70
|
+
Pass ordinary Tailwind utilities through `className` for color and layout, or override the dimensions directly with `width` / `height`.
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
<Spinner className="text-muted-foreground" />
|
|
74
|
+
<Spinner size="lg" className="text-primary" aria-label="Generating report" />
|
|
75
|
+
<Spinner width={24} height={24} aria-label="Loading" />
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Related
|
|
79
|
+
|
|
80
|
+
- [ActionPanel](./action-panel.md) - uses `Spinner` for per-row loading states
|
|
81
|
+
- [WithGuard](./with-guard.md) - common place to render a loading spinner while guards resolve
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Table
|
|
3
|
+
description: Semantic HTML table with pre-styled sub-components
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- GENERATED by docs-kit from docs-src/components/table.docs.outline.md — do not edit by hand. -->
|
|
7
|
+
|
|
8
|
+
# Table
|
|
9
|
+
|
|
10
|
+
The `Table` component provides a set of pre-styled, semantic HTML table sub-components. It wraps a standard `<table>` element in a horizontally scrollable container.
|
|
11
|
+
|
|
12
|
+
## Import
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { Table } 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
|
+
<Table.Root>
|
|
26
|
+
<Table.Header>
|
|
27
|
+
<Table.Row>
|
|
28
|
+
<Table.Head>Name</Table.Head>
|
|
29
|
+
<Table.Head>Email</Table.Head>
|
|
30
|
+
<Table.Head>Role</Table.Head>
|
|
31
|
+
</Table.Row>
|
|
32
|
+
</Table.Header>
|
|
33
|
+
<Table.Body>
|
|
34
|
+
<Table.Row>
|
|
35
|
+
<Table.Cell>Alice</Table.Cell>
|
|
36
|
+
<Table.Cell>alice@example.com</Table.Cell>
|
|
37
|
+
<Table.Cell>Admin</Table.Cell>
|
|
38
|
+
</Table.Row>
|
|
39
|
+
</Table.Body>
|
|
40
|
+
</Table.Root>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Sub-components
|
|
46
|
+
|
|
47
|
+
| Sub-component | HTML element | Description |
|
|
48
|
+
| --------------- | ------------ | -------------------------------------- |
|
|
49
|
+
| `Table.Root` | `<table>` | Root element with scrollable container |
|
|
50
|
+
| `Table.Header` | `<thead>` | Table header section |
|
|
51
|
+
| `Table.Body` | `<tbody>` | Table body section |
|
|
52
|
+
| `Table.Footer` | `<tfoot>` | Table footer section |
|
|
53
|
+
| `Table.Row` | `<tr>` | Table row (hover and selection styles) |
|
|
54
|
+
| `Table.Head` | `<th>` | Header cell |
|
|
55
|
+
| `Table.Cell` | `<td>` | Data cell |
|
|
56
|
+
| `Table.Caption` | `<caption>` | Table caption |
|
|
57
|
+
|
|
58
|
+
## Props
|
|
59
|
+
|
|
60
|
+
### Table.Root Props
|
|
61
|
+
|
|
62
|
+
| Prop | Type | Default | Description |
|
|
63
|
+
| -------------------- | --------------------------- | ------- | ----------------------------------------------------------------- |
|
|
64
|
+
| `className` | `string` | - | Additional CSS classes for the `<table>` element |
|
|
65
|
+
| `containerClassName` | `string` | - | Additional CSS classes for the outer scrollable `<div>` container |
|
|
66
|
+
| `containerRef` | `React.Ref<HTMLDivElement>` | - | Ref forwarded to the outer scrollable `<div>` container |
|
|
67
|
+
|
|
68
|
+
All other standard HTML `<table>` props are accepted.
|
|
69
|
+
|
|
70
|
+
All other sub-components (`Table.Header`, `Table.Body`, `Table.Footer`, `Table.Row`, `Table.Head`, `Table.Cell`, `Table.Caption`) accept `className` and their corresponding standard HTML element props.
|
|
71
|
+
|
|
72
|
+
`Table.Head` and `Table.Cell` also accept `align?: "left" | "center" | "right"` for semantic text alignment without relying on utility-class overrides.
|
|
73
|
+
|
|
74
|
+
## Examples
|
|
75
|
+
|
|
76
|
+
### With Footer
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
<Table.Root>
|
|
80
|
+
<Table.Header>
|
|
81
|
+
<Table.Row>
|
|
82
|
+
<Table.Head>Product</Table.Head>
|
|
83
|
+
<Table.Head>Qty</Table.Head>
|
|
84
|
+
<Table.Head>Price</Table.Head>
|
|
85
|
+
</Table.Row>
|
|
86
|
+
</Table.Header>
|
|
87
|
+
<Table.Body>
|
|
88
|
+
<Table.Row>
|
|
89
|
+
<Table.Cell>Widget A</Table.Cell>
|
|
90
|
+
<Table.Cell>10</Table.Cell>
|
|
91
|
+
<Table.Cell>$100.00</Table.Cell>
|
|
92
|
+
</Table.Row>
|
|
93
|
+
<Table.Row>
|
|
94
|
+
<Table.Cell>Widget B</Table.Cell>
|
|
95
|
+
<Table.Cell>5</Table.Cell>
|
|
96
|
+
<Table.Cell>$75.00</Table.Cell>
|
|
97
|
+
</Table.Row>
|
|
98
|
+
</Table.Body>
|
|
99
|
+
<Table.Footer>
|
|
100
|
+
<Table.Row>
|
|
101
|
+
<Table.Cell colSpan={2}>Total</Table.Cell>
|
|
102
|
+
<Table.Cell>$175.00</Table.Cell>
|
|
103
|
+
</Table.Row>
|
|
104
|
+
</Table.Footer>
|
|
105
|
+
</Table.Root>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### With Caption
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
<Table.Root>
|
|
112
|
+
<Table.Caption>Order line items</Table.Caption>
|
|
113
|
+
<Table.Header>
|
|
114
|
+
<Table.Row>
|
|
115
|
+
<Table.Head>Item</Table.Head>
|
|
116
|
+
<Table.Head>Status</Table.Head>
|
|
117
|
+
</Table.Row>
|
|
118
|
+
</Table.Header>
|
|
119
|
+
<Table.Body>
|
|
120
|
+
<Table.Row>
|
|
121
|
+
<Table.Cell>Item 1</Table.Cell>
|
|
122
|
+
<Table.Cell>Shipped</Table.Cell>
|
|
123
|
+
</Table.Row>
|
|
124
|
+
</Table.Body>
|
|
125
|
+
</Table.Root>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Right-aligned numeric columns
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
<Table.Root>
|
|
132
|
+
<Table.Header>
|
|
133
|
+
<Table.Row>
|
|
134
|
+
<Table.Head>Item</Table.Head>
|
|
135
|
+
<Table.Head align="right">Amount</Table.Head>
|
|
136
|
+
</Table.Row>
|
|
137
|
+
</Table.Header>
|
|
138
|
+
<Table.Body>
|
|
139
|
+
<Table.Row>
|
|
140
|
+
<Table.Cell>Widget A</Table.Cell>
|
|
141
|
+
<Table.Cell align="right">123</Table.Cell>
|
|
142
|
+
</Table.Row>
|
|
143
|
+
</Table.Body>
|
|
144
|
+
</Table.Root>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Center-aligned status column
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
<Table.Root>
|
|
151
|
+
<Table.Header>
|
|
152
|
+
<Table.Row>
|
|
153
|
+
<Table.Head>Item</Table.Head>
|
|
154
|
+
<Table.Head align="center">Status</Table.Head>
|
|
155
|
+
</Table.Row>
|
|
156
|
+
</Table.Header>
|
|
157
|
+
<Table.Body>
|
|
158
|
+
<Table.Row>
|
|
159
|
+
<Table.Cell>Widget A</Table.Cell>
|
|
160
|
+
<Table.Cell align="center">Active</Table.Cell>
|
|
161
|
+
</Table.Row>
|
|
162
|
+
</Table.Body>
|
|
163
|
+
</Table.Root>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Constrained Height with Scroll
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
<Table.Root containerClassName="max-h-64 overflow-y-auto">
|
|
170
|
+
<Table.Header>
|
|
171
|
+
<Table.Row>
|
|
172
|
+
<Table.Head>Name</Table.Head>
|
|
173
|
+
</Table.Row>
|
|
174
|
+
</Table.Header>
|
|
175
|
+
<Table.Body>
|
|
176
|
+
{items.map((item) => (
|
|
177
|
+
<Table.Row key={item.id}>
|
|
178
|
+
<Table.Cell>{item.name}</Table.Cell>
|
|
179
|
+
</Table.Row>
|
|
180
|
+
))}
|
|
181
|
+
</Table.Body>
|
|
182
|
+
</Table.Root>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Related Components
|
|
186
|
+
|
|
187
|
+
- [Badge](./badge.md) - Display status inside table cells
|
|
188
|
+
- [Layout](./layout.md) - Place tables inside page layouts
|