@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
|
@@ -1,1009 +0,0 @@
|
|
|
1
|
-
# AppShell Components
|
|
2
|
-
|
|
3
|
-
> **AppShell version:** `1.7.0` (matches `packages/erp-kit/templates/scaffold/app/*/frontend/package.json` pinned `@tailor-platform/app-shell` semver)
|
|
4
|
-
> **Source of truth:** `@tailor-platform/app-shell` exports
|
|
5
|
-
> **Update process:** see "Keeping this file in sync" at the bottom
|
|
6
|
-
|
|
7
|
-
## Scope vs design-system.md
|
|
8
|
-
|
|
9
|
-
| This file (`components.md`) | `design-system.md` |
|
|
10
|
-
| ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
11
|
-
| **Imports**, compound structure, hooks, canonical **composition** (`Card` + `Table`, `DataTable`, `Dialog`, etc.) | **Tokens**, theme imports, typography/spacing/radius/elevation **tables**, breakpoints **intent** |
|
|
12
|
-
| JSX examples tied to ERP patterns (`patterns/*`) | **AppShell styling boundary** — plain utilities and no internal `astw:` prefix |
|
|
13
|
-
| Prop summaries + links to upstream `docs/components/*.md` | **Visual conformance**: no magic colors/px on custom markup, motion, dark mode |
|
|
14
|
-
|
|
15
|
-
**Rule of thumb:** “Which component / prop?” → **here.** “Which token / spacing step / elevation?” → **`design-system.md`** §§4–6.
|
|
16
|
-
|
|
17
|
-
This file intentionally does **not** duplicate full token catalogs. “Every heading here ≈ documented export cluster” maintenance lives in **Keeping this file in sync** — upstream npm remains authoritative for completeness.
|
|
18
|
-
|
|
19
|
-
Entries follow this shape:
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
**Import:** how to import it
|
|
23
|
-
**Purpose:** one sentence
|
|
24
|
-
**API:** key props or sub-components
|
|
25
|
-
**Example:** minimal JSX
|
|
26
|
-
**Used in patterns:** which patterns/<type>/<slug>.md cite this component
|
|
27
|
-
**Notes:** version-specific quirks (optional)
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
For the full upstream API of any component, follow the link to the published reference at the top of its section.
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## Layout primitives
|
|
35
|
-
|
|
36
|
-
### `AppShell`
|
|
37
|
-
|
|
38
|
-
**Import:** `import { AppShell } from '@tailor-platform/app-shell'`
|
|
39
|
-
**Purpose:** Application root — wraps `<App />` with AppShell context, theme, and routing.
|
|
40
|
-
**API:** Compound — `AppShell.Root`, plus subcomponents wired through `AppShellProps`. Configured once in `App.tsx`.
|
|
41
|
-
**Example:** see `project-setup.md`.
|
|
42
|
-
**Used in patterns:** all (root container).
|
|
43
|
-
|
|
44
|
-
### `Layout`
|
|
45
|
-
|
|
46
|
-
> Full API: [https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/layout.md](https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/layout.md)
|
|
47
|
-
|
|
48
|
-
**Import:** `import { Layout } from '@tailor-platform/app-shell'`
|
|
49
|
-
**Purpose:** Standard page container with header + 1–N column body. The most-used component — every page wraps content in `<Layout>`.
|
|
50
|
-
**API:** `Layout` (root) + `Layout.Column` + `Layout.Header`. `LayoutProps`: `fill` (boolean), `columns` (number, default auto-detected from children), `gap`, `title`, `actions`, `className`, `style`.
|
|
51
|
-
|
|
52
|
-
**`fill`** — stretches the layout to the available height and bounds the column row so children can scroll internally instead of growing the page. Use on table-first pages (`<Layout fill>` + `DataTable`): the title, table toolbar, sticky column headers, and pagination footer stay pinned while only the rows scroll — see **`patterns/list-dense-scan.md`**. Omit on pages that should flow and scroll naturally (forms, dashboards).
|
|
53
|
-
|
|
54
|
-
**Column-count → width rules** (column count is auto-detected from `Layout.Column` children):
|
|
55
|
-
|
|
56
|
-
| Columns | Breakpoint | Widths | Below breakpoint |
|
|
57
|
-
| ------- | ---------- | ------------------------------ | ---------------- |
|
|
58
|
-
| 1 | always | full | n/a |
|
|
59
|
-
| 2 | ≥ 1024px | flex + 280px | stacks |
|
|
60
|
-
| 3 | ≥ 1280px | 320px + flex + 280px | stacks |
|
|
61
|
-
| 4+ | ≥ 1280px | equal share — `repeat(N, 1fr)` | stacks |
|
|
62
|
-
|
|
63
|
-
Desktop breakpoints and desktop-first rationale: **`design-system.md`** §4 Breakpoints. This table is **`Layout` column mechanics only**.
|
|
64
|
-
|
|
65
|
-
**`Layout.Header`** — direct child of `<Layout>`, above any `<Layout.Column>`. Only the first is rendered if multiple are passed.
|
|
66
|
-
|
|
67
|
-
| Prop | Type | Description |
|
|
68
|
-
| ---------- | ------------------- | ------------------------------------------------ |
|
|
69
|
-
| `title` | `string` | Page title — `<h1>` on the left |
|
|
70
|
-
| `actions` | `React.ReactNode[]` | Buttons on the right |
|
|
71
|
-
| `children` | `React.ReactNode` | Full-width row below title — typical use is tabs |
|
|
72
|
-
|
|
73
|
-
**`Layout.Column`** — direct child, accepts `area` (`"left" | "main" | "right"`) for advanced placement override. If any column declares `area`, all columns switch to area-based widths (`left`=320, `main`=flex, `right`=280) and render in source order.
|
|
74
|
-
|
|
75
|
-
**Example — list page header with tabs:**
|
|
76
|
-
|
|
77
|
-
```tsx
|
|
78
|
-
import { Button, Layout, Tabs } from "@tailor-platform/app-shell";
|
|
79
|
-
|
|
80
|
-
<Layout>
|
|
81
|
-
<Layout.Header title="Purchase orders" actions={[<Button key="create">Create</Button>]}>
|
|
82
|
-
<Tabs.Root value={bucket} onValueChange={setBucket}>
|
|
83
|
-
<Tabs.List>
|
|
84
|
-
<Tabs.Tab value="all">All</Tabs.Tab>
|
|
85
|
-
<Tabs.Tab value="open">Open</Tabs.Tab>
|
|
86
|
-
</Tabs.List>
|
|
87
|
-
</Tabs.Root>
|
|
88
|
-
</Layout.Header>
|
|
89
|
-
<Layout.Column>{/* table — see patterns/list/dense-scan.md */}</Layout.Column>
|
|
90
|
-
</Layout>;
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
**Example — detail page, 2-column with area mode:**
|
|
94
|
-
|
|
95
|
-
```tsx
|
|
96
|
-
<Layout>
|
|
97
|
-
<Layout.Header title={order.number} actions={[<Button>Edit</Button>]} />
|
|
98
|
-
<Layout.Column area="main">
|
|
99
|
-
<DescriptionCard ... />
|
|
100
|
-
</Layout.Column>
|
|
101
|
-
<Layout.Column area="right">
|
|
102
|
-
<ActionPanel ... />
|
|
103
|
-
<ActivityCard ... />
|
|
104
|
-
</Layout.Column>
|
|
105
|
-
</Layout>
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
**Notes:** Children that aren't `Layout.Header` or `Layout.Column` are filtered out. Set column gaps with `<Layout gap={6} />` (supported steps: 4, 6, 8).
|
|
109
|
-
|
|
110
|
-
**Used in patterns:** every page pattern (`list/*`, `detail/*`, `form/*`).
|
|
111
|
-
|
|
112
|
-
### `Grid`
|
|
113
|
-
|
|
114
|
-
**Import:** `import { Grid } from '@tailor-platform/app-shell'`
|
|
115
|
-
**Purpose:** Presentational CSS-Grid container for laying tiles/cards into equal or custom columns with responsive reflow — the canonical wrapper for **metric / KPI strips** and card galleries. Purely layout; makes no data assumptions.
|
|
116
|
-
**API:** `GridProps` — `columns` (number | CSS track string like `"280px 1fr"` | responsive object `{ initial, sm, md, lg, xl }`), `gap` (spacing step, default `3`) plus `gapX` / `gapY`, `minChildWidth` (auto-fit: as many ≥Npx columns as fit, no breakpoints needed), `rows`, `flow`, `align`, `justify`. Sub-component **`Grid.Item`** for spanning/placement — `colSpan`, `rowSpan`, `colStart`, `colEnd` (all responsive). Root carries `data-slot="grid"`.
|
|
117
|
-
**Example — responsive KPI grid:**
|
|
118
|
-
|
|
119
|
-
```tsx
|
|
120
|
-
import { Grid, MetricCard } from "@tailor-platform/app-shell";
|
|
121
|
-
|
|
122
|
-
<Grid columns={{ initial: 1, md: 2, xl: 4 }} gap={4}>
|
|
123
|
-
<MetricCard title="Net total" value="$1,500" trend={{ direction: "up", value: "+5%" }} />
|
|
124
|
-
<MetricCard title="Open orders" value="42" />
|
|
125
|
-
<MetricCard title="Overdue" value="7" />
|
|
126
|
-
<MetricCard title="Suppliers" value="18" />
|
|
127
|
-
</Grid>;
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
**Used in patterns:** metric / KPI strips on `detail/*` and dashboards; any equal-column card layout.
|
|
131
|
-
|
|
132
|
-
**Notes:** Metric tiles and KPI cards **always** go in a `Grid` — never stacked one-per-row or in a single column. Use a responsive `columns` object (e.g. `{ initial: 1, md: 2, xl: 4 }`) so tiles reflow at smaller widths; reach for `minChildWidth` when the tile count is dynamic.
|
|
133
|
-
|
|
134
|
-
### `SidebarLayout`
|
|
135
|
-
|
|
136
|
-
**Import:** `import { SidebarLayout } from '@tailor-platform/app-shell'`
|
|
137
|
-
**Purpose:** Top-level layout that mounts the sidebar and renders the page outlet.
|
|
138
|
-
**API:** `SidebarLayoutProps` — `sidebar`, `header`, and `children` are full-region slots (each defaults to a built-in). `sidebar` defaults to `SidebarLayout.DefaultSidebar`; `header` defaults to `SidebarLayout.DefaultHeader`. Used in `App.tsx`.
|
|
139
|
-
**Used in patterns:** consumed by AppShell init, not directly by page patterns. See `project-setup.md`.
|
|
140
|
-
|
|
141
|
-
### `SidebarLayout.DefaultHeader` (`DefaultHeader`)
|
|
142
|
-
|
|
143
|
-
**Import:** `import { SidebarLayout } from '@tailor-platform/app-shell'` → `SidebarLayout.DefaultHeader` (also top-level `DefaultHeader`)
|
|
144
|
-
**Purpose:** The built-in top bar (trigger + breadcrumb, plus an `actions` cluster). Drop into `SidebarLayout`'s `header` slot to extend the header without rebuilding it.
|
|
145
|
-
**API:** `actions?: ReactNode | ReactNode[]` — the right-hand cluster (opinionated flex row). **Defaults to `[<AppearanceSwitcher />]`, and passing `actions` REPLACES the switcher** — include `<AppearanceSwitcher />` in the array to keep it. `actions={[]}` = empty right side.
|
|
146
|
-
**Used in patterns:** project-level header customization (notification bell, user menu). See `project-setup.md`.
|
|
147
|
-
|
|
148
|
-
### `SidebarLayout.DefaultSidebar` (`DefaultSidebar`), `SidebarGroup`, `SidebarItem`, `SidebarSeparator`
|
|
149
|
-
|
|
150
|
-
**Import:** `import { SidebarLayout, SidebarGroup, SidebarItem, SidebarSeparator } from '@tailor-platform/app-shell'` → `SidebarLayout.DefaultSidebar` (also top-level `DefaultSidebar`)
|
|
151
|
-
**Purpose:** Sidebar composition. `DefaultSidebar` auto-resolves nav items from `appShellPageProps.meta` on each page; the others let you customize manually.
|
|
152
|
-
**Used in patterns:** sidebar is a project-level concern. See `project-setup.md`.
|
|
153
|
-
|
|
154
|
-
### `AppearanceSwitcher`
|
|
155
|
-
|
|
156
|
-
**Import:** `import { AppearanceSwitcher } from '@tailor-platform/app-shell'`
|
|
157
|
-
**Purpose:** Palette-icon dropdown for Light/Dark/System color mode. The default `SidebarLayout.DefaultHeader` action; also usable standalone (e.g. a sidebar footer). Include it in `DefaultHeader`'s `actions` array when customizing the header to keep it visible.
|
|
158
|
-
**API:** No props — reads/writes theme via `useTheme`.
|
|
159
|
-
**Used in patterns:** project-level. See `project-setup.md`.
|
|
160
|
-
|
|
161
|
-
### `CommandPalette`
|
|
162
|
-
|
|
163
|
-
**Import:** `import { CommandPalette } from '@tailor-platform/app-shell'`
|
|
164
|
-
**Purpose:** Cmd/Ctrl-K command palette. Auto-discovers searchable resources via `defineResource`.
|
|
165
|
-
**API:** Renderless — drop into the layout once.
|
|
166
|
-
**Used in patterns:** project-level. Useful for any app with >10 routes.
|
|
167
|
-
|
|
168
|
-
---
|
|
169
|
-
|
|
170
|
-
## Interaction surfaces
|
|
171
|
-
|
|
172
|
-
### `Button`
|
|
173
|
-
|
|
174
|
-
> Full API: [https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/button.md](https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/button.md)
|
|
175
|
-
|
|
176
|
-
**Import:** `import { Button } from '@tailor-platform/app-shell'`
|
|
177
|
-
**Purpose:** All buttons in the app — including polymorphic rendering via the `render` prop.
|
|
178
|
-
**API:** `ButtonProps` extends native `<button>` plus `variant` (`default | destructive | outline | secondary | ghost | link`), `size` (`default | sm | lg | icon | xs`), `render` (polymorphic — pass `<Link>` or another element to render-as).
|
|
179
|
-
**Example:**
|
|
180
|
-
|
|
181
|
-
```tsx
|
|
182
|
-
import { Button, Link } from '@tailor-platform/app-shell';
|
|
183
|
-
|
|
184
|
-
<Button render={<Link to="create" />}>Create</Button>
|
|
185
|
-
<Button variant="destructive" onClick={handleDelete}>Delete</Button>
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
**Used in patterns:** every pattern.
|
|
189
|
-
|
|
190
|
-
### `Link`
|
|
191
|
-
|
|
192
|
-
**Import:** `import { Link } from '@tailor-platform/app-shell'`
|
|
193
|
-
**Purpose:** Router-aware anchor. Re-exported from `react-router` so the rest of the app stays on the AppShell barrel.
|
|
194
|
-
**API:** `to`, `replace`, `state`, etc. — same as `react-router`.
|
|
195
|
-
**Used in patterns:** all (navigation).
|
|
196
|
-
|
|
197
|
-
### `NavLink`
|
|
198
|
-
|
|
199
|
-
**Import:** `import { NavLink } from '@tailor-platform/app-shell'`
|
|
200
|
-
**Purpose:** `Link` that knows when it is active — for nav menus and tab bars.
|
|
201
|
-
**API:** `to`, plus `className` / `style` / `children` as render functions receiving `{ isActive, isPending }`.
|
|
202
|
-
**Used in patterns:** navigation shells.
|
|
203
|
-
|
|
204
|
-
### `Dialog`
|
|
205
|
-
|
|
206
|
-
> Full API: [https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/dialog.md](https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/dialog.md)
|
|
207
|
-
|
|
208
|
-
**Import:** `import { Dialog } from '@tailor-platform/app-shell'`
|
|
209
|
-
**Purpose:** Modal dialog for confirmations, ≤5-field forms, blocking workflows.
|
|
210
|
-
**API:** Compound — `Dialog.Root`, `Dialog.Trigger`, `Dialog.Content`, `Dialog.Header`, `Dialog.Title`, `Dialog.Description`, `Dialog.Footer`, `Dialog.Close`. Controllable via `open` + `onOpenChange`.
|
|
211
|
-
**Example:**
|
|
212
|
-
|
|
213
|
-
```tsx
|
|
214
|
-
<Dialog.Root>
|
|
215
|
-
<Dialog.Trigger render={<Button variant="destructive" />}>Delete</Dialog.Trigger>
|
|
216
|
-
<Dialog.Content>
|
|
217
|
-
<Dialog.Header>
|
|
218
|
-
<Dialog.Title>Delete order #1234?</Dialog.Title>
|
|
219
|
-
<Dialog.Description>This cannot be undone.</Dialog.Description>
|
|
220
|
-
</Dialog.Header>
|
|
221
|
-
<Dialog.Footer>
|
|
222
|
-
<Dialog.Close render={<Button variant="outline" />}>Cancel</Dialog.Close>
|
|
223
|
-
<Button variant="destructive" onClick={onDelete}>
|
|
224
|
-
Delete
|
|
225
|
-
</Button>
|
|
226
|
-
</Dialog.Footer>
|
|
227
|
-
</Dialog.Content>
|
|
228
|
-
</Dialog.Root>
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
**Used in patterns:** `form/modal`, `interaction/confirm`.
|
|
232
|
-
|
|
233
|
-
### `Sheet`
|
|
234
|
-
|
|
235
|
-
> Full API: [https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/sheet.md](https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/sheet.md)
|
|
236
|
-
|
|
237
|
-
**Import:** `import { Sheet } from '@tailor-platform/app-shell'`
|
|
238
|
-
**Purpose:** Slide-in panel from any edge. Use for filters, side-work without losing context.
|
|
239
|
-
**API:** Compound — `Sheet.Root` (with `side: 'left' | 'right' | 'top' | 'bottom'`), `Sheet.Trigger`, `Sheet.Content`, `Sheet.Header`, `Sheet.Title`, `Sheet.Description`, `Sheet.Footer`, `Sheet.Close`.
|
|
240
|
-
**Example:**
|
|
241
|
-
|
|
242
|
-
```tsx
|
|
243
|
-
<Sheet.Root side="right">
|
|
244
|
-
<Sheet.Trigger render={<Button variant="outline" />}>Filters</Sheet.Trigger>
|
|
245
|
-
<Sheet.Content>
|
|
246
|
-
<Sheet.Header>
|
|
247
|
-
<Sheet.Title>Filter orders</Sheet.Title>
|
|
248
|
-
</Sheet.Header>
|
|
249
|
-
{/* filter inputs */}
|
|
250
|
-
<Sheet.Footer>
|
|
251
|
-
<Sheet.Close render={<Button variant="outline" />}>Clear</Sheet.Close>
|
|
252
|
-
<Button>Apply</Button>
|
|
253
|
-
</Sheet.Footer>
|
|
254
|
-
</Sheet.Content>
|
|
255
|
-
</Sheet.Root>
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
**Used in patterns:** `list/*` (filter sheet variant).
|
|
259
|
-
|
|
260
|
-
**Notes:** Size the panel with `Sheet.Content`'s **`size`** prop (`"sm" | "md" | "lg" | "xl" | "full"`, default `"sm"`) — not a width utility.
|
|
261
|
-
|
|
262
|
-
### `Menu`
|
|
263
|
-
|
|
264
|
-
> Full API: [https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/menu.md](https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/menu.md)
|
|
265
|
-
|
|
266
|
-
**Import:** `import { Menu } from '@tailor-platform/app-shell'`
|
|
267
|
-
**Purpose:** Dropdown menu — row actions, overflow actions, grouped commands.
|
|
268
|
-
**API:** Compound — `Menu.Root`, `Menu.Trigger`, `Menu.Content`, `Menu.Item`, `Menu.Separator`, `Menu.Group`, `Menu.GroupLabel`. Supports checkbox/radio items and nested sub-menus.
|
|
269
|
-
**Example:**
|
|
270
|
-
|
|
271
|
-
```tsx
|
|
272
|
-
<Menu.Root>
|
|
273
|
-
<Menu.Trigger>
|
|
274
|
-
<Button variant="ghost" size="icon">
|
|
275
|
-
<EllipsisVertical />
|
|
276
|
-
</Button>
|
|
277
|
-
</Menu.Trigger>
|
|
278
|
-
<Menu.Content>
|
|
279
|
-
<Menu.Item onSelect={() => handleAssign(id)}>Assign</Menu.Item>
|
|
280
|
-
<Menu.Item onSelect={() => handleDuplicate(id)}>Duplicate</Menu.Item>
|
|
281
|
-
<Menu.Separator />
|
|
282
|
-
<Menu.Item onSelect={() => handleDelete(id)}>Delete</Menu.Item>
|
|
283
|
-
</Menu.Content>
|
|
284
|
-
</Menu.Root>
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
**Used in patterns:** `list/*` (row actions), `detail/*` (overflow actions).
|
|
288
|
-
|
|
289
|
-
**Notes:** **`list-dense-scan`** uses whole-row / primary-column navigation — keep row `Menu` items **non-navigation** (Assign, Duplicate, Delete). Avoid redundant **View**/**Open**. Detail overflows may include navigation only when not duplicating hero content.
|
|
290
|
-
|
|
291
|
-
### `Tooltip`
|
|
292
|
-
|
|
293
|
-
**Import:** `import { Tooltip } from '@tailor-platform/app-shell'`
|
|
294
|
-
**Purpose:** Contextual hint on hover/focus. Use sparingly — for icon-only buttons or constrained labels.
|
|
295
|
-
**API:** Compound — `Tooltip.Root`, `Tooltip.Trigger`, `Tooltip.Content`.
|
|
296
|
-
**Used in patterns:** any pattern with icon-only buttons (must have `aria-label` AND a tooltip).
|
|
297
|
-
|
|
298
|
-
### `Tabs`
|
|
299
|
-
|
|
300
|
-
**Import:** `import { Tabs } from '@tailor-platform/app-shell'`
|
|
301
|
-
**Purpose:** In-page tab navigation — split one record's sections (Overview / Line items / Activity) or bucket a list (All / Open / …) into switchable panels. Presentational; owns only the active-tab state.
|
|
302
|
-
**API:** Compound — `Tabs.Root` (`variant`: `default | line | capsule`; controlled `value` + `onValueChange`, or uncontrolled `defaultValue`), `Tabs.List`, `Tabs.Tab` (`value`), `Tabs.Panel` (`value`). Note: the sub-component is **`Tabs.Tab`**, not `Tabs.Trigger`.
|
|
303
|
-
**Example:**
|
|
304
|
-
|
|
305
|
-
```tsx
|
|
306
|
-
<Tabs.Root defaultValue="overview" variant="line">
|
|
307
|
-
<Tabs.List>
|
|
308
|
-
<Tabs.Tab value="overview">Overview</Tabs.Tab>
|
|
309
|
-
<Tabs.Tab value="items">Line items</Tabs.Tab>
|
|
310
|
-
</Tabs.List>
|
|
311
|
-
<Tabs.Panel value="overview">{/* … */}</Tabs.Panel>
|
|
312
|
-
<Tabs.Panel value="items">{/* … */}</Tabs.Panel>
|
|
313
|
-
</Tabs.Root>
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
**Used in patterns:** `list-dense-scan` (bucket tabs composed **above** `DataTable.Root`, synced to `useCollectionVariables` — see the `DataTable` "Bucket tabs" note), `detail/*` (sectioned record content).
|
|
317
|
-
|
|
318
|
-
**Notes:** For lists, AppShell's own filtering surface is **toolbar chips** (`DataTable.Filters`), not tabs — reach for `Tabs` only when the business genuinely thinks in a small set of named buckets. Don't render a `Tab` per enum value where a filter chip belongs.
|
|
319
|
-
|
|
320
|
-
---
|
|
321
|
-
|
|
322
|
-
## Display
|
|
323
|
-
|
|
324
|
-
### `Badge`
|
|
325
|
-
|
|
326
|
-
> Full API: [https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/badge.md](https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/badge.md)
|
|
327
|
-
|
|
328
|
-
**Import:** `import { Badge } from '@tailor-platform/app-shell'`
|
|
329
|
-
**Purpose:** Status labels and small categorical chips.
|
|
330
|
-
**API:** `BadgeProps` — `variant` (15 total):
|
|
331
|
-
|
|
332
|
-
- **Filled** (high emphasis): `default` (primary), `success`, `warning`, `error`, `neutral`, `info`
|
|
333
|
-
- **Subtle** (low emphasis, tinted): `subtle-success`, `subtle-warning`, `subtle-error`, `subtle-info`
|
|
334
|
-
- **Outline** (renders a status dot — for row/list statuses): `outline-success`, `outline-warning`, `outline-error`, `outline-info`, `outline-neutral`
|
|
335
|
-
|
|
336
|
-
Plus `badgeVariants` CVA for custom-styled siblings.
|
|
337
|
-
**Example:**
|
|
338
|
-
|
|
339
|
-
```tsx
|
|
340
|
-
// Primary / lifecycle status — filled semantic variant
|
|
341
|
-
<Badge variant="success">Confirmed</Badge>
|
|
342
|
-
// Secondary status (delivery, billing) — outline with status dot
|
|
343
|
-
<Badge variant="outline-warning">Partially received</Badge>
|
|
344
|
-
// Tag / label — subtle
|
|
345
|
-
<Badge variant="subtle-info">New</Badge>
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
**Used in patterns:** `list/*` (status column → `outline-*`), `detail/*` (header status).
|
|
349
|
-
|
|
350
|
-
**Notes:** Encode status by **semantic color** with a primary/secondary split: a record's **primary/lifecycle status** uses a **filled** semantic variant (one per row / one in a detail header); **secondary statuses** (delivery, billing) use **`outline-*`** (status dot); tags use **`subtle-*`**. Reserve **`default`** (brand) for non-status emphasis. Full rule: **`design-system.md`** → Composition & emphasis rules.
|
|
351
|
-
|
|
352
|
-
### `Table`
|
|
353
|
-
|
|
354
|
-
> Full API: [https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/table.md](https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/table.md)
|
|
355
|
-
|
|
356
|
-
**Import:** `import { Table } from '@tailor-platform/app-shell'`
|
|
357
|
-
**Purpose:** Semantic data table with scrollable container.
|
|
358
|
-
**API:** Compound — `Table.Root`, `Table.Header`, `Table.Body`, `Table.Footer`, `Table.Row`, `Table.Head`, `Table.Cell`, `Table.Caption`. `Table.Root` accepts `containerClassName` for the outer wrapper, `className` for the inner `<table>`. `Table.Head` and `Table.Cell` accept **`align`** (`"left" | "center" | "right"`, default `"left"`) — prefer this over ad-hoc `className="text-right"` and pair the same alignment on the head and its column's cells (right for numeric/money, center for compact status/icon columns).
|
|
359
|
-
**Example:**
|
|
360
|
-
|
|
361
|
-
```tsx
|
|
362
|
-
<Table.Root>
|
|
363
|
-
<Table.Header>
|
|
364
|
-
<Table.Row>
|
|
365
|
-
<Table.Head>Order</Table.Head>
|
|
366
|
-
<Table.Head>Status</Table.Head>
|
|
367
|
-
<Table.Head align="right">Total</Table.Head>
|
|
368
|
-
</Table.Row>
|
|
369
|
-
</Table.Header>
|
|
370
|
-
<Table.Body>
|
|
371
|
-
{orders.map((o) => (
|
|
372
|
-
<Table.Row key={o.id}>
|
|
373
|
-
<Table.Cell>{o.number}</Table.Cell>
|
|
374
|
-
<Table.Cell>
|
|
375
|
-
<Badge variant={statusVariant(o.status)}>{o.status}</Badge>
|
|
376
|
-
</Table.Cell>
|
|
377
|
-
<Table.Cell align="right">{formatMoney(o.total)}</Table.Cell>
|
|
378
|
-
</Table.Row>
|
|
379
|
-
))}
|
|
380
|
-
</Table.Body>
|
|
381
|
-
</Table.Root>
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
**Used in patterns:** `list-dense-scan` hand-built subsets / static tables (`DataTable` is preferred for wired lists).
|
|
385
|
-
|
|
386
|
-
**Notes:**
|
|
387
|
-
|
|
388
|
-
- **Inside a card?** Zero the card's horizontal padding — drop `Card.Content` (bare list form) or pass `Card.Content className="px-0!"` (header+content form) — and leave the table container's padding alone. `Table.Head` / `Table.Cell` carry their own `first:pl-6` / `last:pr-6`, so a `containerClassName="px-6"` double-pads and the first column lands 24px right of the card title. See the `Card` entry for the two canonical forms and a DON'T example. Dense cell typography (**`text-sm`**, **`tabular-nums`** for figures, **`font-mono`** for identifiers) → **`design-system.md`** §4 Typography.
|
|
389
|
-
- **Whole row is clickable.** Use `<Table.Row onClick={() => navigate(detailPath)} className="cursor-pointer">`. For keyboard and screen-reader users, also wrap the primary identifier cell content in `<Link>` (so the row is reachable via Tab; `Table.Row` is a `<tr>` and cannot itself be a Link — wrapping a `<tr>` in `<a>` is invalid HTML). **No per-row "View" / "Open" / "→" buttons.** Per-row `Menu` (overflow `…`) is the only allowed per-row action surface and is reserved for non-navigation actions like Archive, Duplicate.
|
|
390
|
-
|
|
391
|
-
### `DataTable`
|
|
392
|
-
|
|
393
|
-
> Full API: [https://github.com/tailor-platform/app-shell/blob/main/docs/components/data-table.md](https://github.com/tailor-platform/app-shell/blob/main/docs/components/data-table.md)
|
|
394
|
-
|
|
395
|
-
**Import:** compound namespace + helpers from `'@tailor-platform/app-shell'`, e.g. `DataTable`, `useDataTable`, `useCollectionVariables`, `createColumnHelper`, and types such as `Column`, `UseDataTableReturn`.
|
|
396
|
-
|
|
397
|
-
**Purpose:** Production list screens over GraphQL **connections**. Owns toolbar filter chips (**`DataTable.Filters`** from column `filter` configs), header sort, **`DataTable.Pagination`** (cursor-first; First/Last when `total` is provided), loading skeleton/error row, **`onClickRow`**, **`rowActions`** (kebab column), **`onSelectionChange`** (checkbox column), **expandable rows** (**`rowExpansion`** — a chevron column plus a full-width detail panel per row; `render` with optional `canExpand` / `getLabel`, and `expandedIds` + `onChange` for controlled mode), **column pinning** (`pin: "left" | "right"`) and built-in **column settings** (`<DataTable.Toolbar columnSettings>` — user show/hide + reorder + pin, persisted per-user via **`tableId`**).
|
|
398
|
-
|
|
399
|
-
**Primitives:** Builds on low-level **`Table`**; do not reinvent pagination/filters manually unless the dataset is trivial.
|
|
400
|
-
|
|
401
|
-
**Shape:**
|
|
402
|
-
|
|
403
|
-
```tsx
|
|
404
|
-
const { variables, control } = useCollectionVariables({
|
|
405
|
-
params: { pageSize: 20 },
|
|
406
|
-
// tableMetadata: tableMetadata.po, // typed vars when generated
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
const table = useDataTable({
|
|
410
|
-
columns,
|
|
411
|
-
data: fetching ? undefined : mappedFromQuery,
|
|
412
|
-
loading: fetching,
|
|
413
|
-
control,
|
|
414
|
-
tableId: "purchase-orders", // persist user column layout to localStorage
|
|
415
|
-
onClickRow: (row) => navigate(detailHref(row)),
|
|
416
|
-
// onSelectionChange, rowActions, sort: …
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
<DataTable.Root value={table}>
|
|
420
|
-
<DataTable.Toolbar columnSettings>
|
|
421
|
-
<DataTable.Filters />
|
|
422
|
-
</DataTable.Toolbar>
|
|
423
|
-
<DataTable.Table />
|
|
424
|
-
<DataTable.Footer>
|
|
425
|
-
<DataTable.Pagination pageSizeOptions={[10, 20, 50]} />
|
|
426
|
-
</DataTable.Footer>
|
|
427
|
-
</DataTable.Root>;
|
|
428
|
-
```
|
|
429
|
-
|
|
430
|
-
**Row navigation:** whole row is clickable via **`onClickRow`** → `navigate(detailHref(row))`; wrap the primary identifier cell in `<Link>` for keyboard/SR access. Never add a per-row "View" / "Open" / "→" button. (A first-class row-interaction API is under design — see the row-interaction tracking issue.)
|
|
431
|
-
|
|
432
|
-
**Column pinning & settings:** set `pin: "left" | "right"` on a `Column` to freeze it during horizontal scroll — selection auto-pins left, row-actions auto-pins right (a `width` is optional but recommended for stable sizing). Pass **`columnSettings`** to **`DataTable.Toolbar`** to render the built-in "Columns" control (show/hide, reorder, re-pin) at the top-right; pass a stable, **unique** **`tableId`** to persist each user's layout to `localStorage` (a per-user preference — intentionally not in the URL like filters/sort).
|
|
433
|
-
|
|
434
|
-
**Column alignment:** each `Column` accepts **`align`** (`"left" | "right"`) applied to both header and body cell. Numeric `type` columns (`"number"`, `"money"`) default to `"right"` automatically so digits align on the decimal place — pass `align="left"` to opt out; everything else defaults to `"left"`.
|
|
435
|
-
|
|
436
|
-
**Metadata path:** Prefer `createColumnHelper` + `inferColumns(tableMetadata.order)` (`@tailor-platform/sdk-plugin-app-shell` codegen) when available so enum/datetime/string filters bind to the right editors.
|
|
437
|
-
|
|
438
|
-
**Bucket tabs / segmented UX:** AppShell defines **toolbar chips**, not lifecycle tabs. When design places **`Tabs`** (All / Draft / …) inside the card, compose them **above** `DataTable.Root` and synchronize tab-driven bucket state with **`useCollectionVariables`** (`variables.query` / filters)—see **`patterns/list/dense-scan.md`**.
|
|
439
|
-
|
|
440
|
-
**Used in patterns:** `list-dense-scan` (preferred for live collections).
|
|
441
|
-
|
|
442
|
-
### `Card`
|
|
443
|
-
|
|
444
|
-
**Import:** `import { Card } from '@tailor-platform/app-shell'`
|
|
445
|
-
**Purpose:** Generic container with header, content, optional action.
|
|
446
|
-
**API:** Compound — `Card.Root`, `Card.Header` (props: `title`, `description`, plus children for actions), `Card.Content`.
|
|
447
|
-
**Example:**
|
|
448
|
-
|
|
449
|
-
```tsx
|
|
450
|
-
<Card.Root>
|
|
451
|
-
<Card.Header title="Recent orders" description="Last 7 days">
|
|
452
|
-
<Button size="sm" variant="outline">
|
|
453
|
-
View all
|
|
454
|
-
</Button>
|
|
455
|
-
</Card.Header>
|
|
456
|
-
<Card.Content>{/* anything */}</Card.Content>
|
|
457
|
-
</Card.Root>
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
**Used in patterns:** `detail/*` (related-data sections), `form/wizard` (step container).
|
|
461
|
-
|
|
462
|
-
**Notes:**
|
|
463
|
-
|
|
464
|
-
- **A table inside a card needs ONE geometry change, not two** (token-backed spacing rationale → **`design-system.md`** §4 Spacing): the card stops imposing horizontal padding. Drop `Card.Content` for the bare form, or pass `Card.Content className="px-0!"` for the header+content form. That is all. `Table.Head` and `Table.Cell` already carry an intrinsic `first:pl-6` / `last:pr-6`, which supplies the inset on its own — so the table container must add **none**. Padding on the container stacks on top of the cell's own and pushes the first column 24px past the card title.
|
|
465
|
-
|
|
466
|
-
**Bare table-in-card (list pages, no card-level title):**
|
|
467
|
-
|
|
468
|
-
```tsx
|
|
469
|
-
<Card.Root>
|
|
470
|
-
<Table.Root>{/* … */}</Table.Root>
|
|
471
|
-
</Card.Root>
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
**Header + table (detail-page sections like "Line items"):**
|
|
475
|
-
|
|
476
|
-
```tsx
|
|
477
|
-
<Card.Root>
|
|
478
|
-
<Card.Header title="Line items" />
|
|
479
|
-
<Card.Content className="px-0!">
|
|
480
|
-
<Table.Root>{/* … */}</Table.Root>
|
|
481
|
-
</Card.Content>
|
|
482
|
-
</Card.Root>
|
|
483
|
-
```
|
|
484
|
-
|
|
485
|
-
**DON'T — the first column sits 24px right of the card title:**
|
|
486
|
-
|
|
487
|
-
```tsx
|
|
488
|
-
<Card.Root>
|
|
489
|
-
<Card.Content className="px-0!">
|
|
490
|
-
{/* double-pads: the container's 24px adds to the cell's own first:pl-6 */}
|
|
491
|
-
<Table.Root containerClassName="px-6">{/* … */}</Table.Root>
|
|
492
|
-
</Card.Content>
|
|
493
|
-
</Card.Root>
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
### `MetricCard`
|
|
497
|
-
|
|
498
|
-
**Import:** `import { MetricCard } from '@tailor-platform/app-shell'`
|
|
499
|
-
**Purpose:** KPI tile for dashboards or hero metric strip.
|
|
500
|
-
**API:** `MetricCardProps` — `title`, `value`, `trend: { direction, value }`, `description`, `icon`.
|
|
501
|
-
**Example:** metric tiles are laid out in a `Grid` (never one-per-row):
|
|
502
|
-
|
|
503
|
-
```tsx
|
|
504
|
-
<Grid columns={{ initial: 1, md: 2, xl: 4 }} gap={4}>
|
|
505
|
-
<MetricCard
|
|
506
|
-
title="Net total"
|
|
507
|
-
value="$1,500"
|
|
508
|
-
trend={{ direction: "up", value: "+5%" }}
|
|
509
|
-
description="vs last month"
|
|
510
|
-
icon={<DollarSign />}
|
|
511
|
-
/>
|
|
512
|
-
<MetricCard title="Open orders" value="42" />
|
|
513
|
-
{/* …more tiles */}
|
|
514
|
-
</Grid>
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
**Used in patterns:** KPI tiles, dashboards, **`detail/*`** metric strips where specs call for them.
|
|
518
|
-
|
|
519
|
-
**Notes:** Always wrap metric tiles in **`Grid`** (see the `Grid` entry) — a column of single-width `MetricCard`s stacked one-per-row is an anti-pattern.
|
|
520
|
-
|
|
521
|
-
### `DocumentProgressCard`
|
|
522
|
-
|
|
523
|
-
**Import:** `import { DocumentProgressCard } from '@tailor-platform/app-shell'`
|
|
524
|
-
**Purpose:** Presentational card for a document's lifecycle / fulfilment state — an optional headline percentage, a stacked progress bar, and a status legend. Domain-agnostic and view-only: pass an arbitrary set of `segments` (e.g. shipped / returned / pending) plus an explicit `percent`; derive both in the consumer.
|
|
525
|
-
**API:** `DocumentProgressCardProps` — `segments` (required; array of `{ label, value, color }`), `percent?` (0–100, headline shown top-right), `title?`, `legend?` (defaults to `segments`; supply only when the legend should differ from the bar, e.g. overlapping buckets), `total?` (bar denominator; defaults to the sum of segment values — a larger value leaves an unfilled remainder), `className?`. Segment `color`: `indigo | pink | green | amber | red | blue | neutral`.
|
|
526
|
-
**Example:**
|
|
527
|
-
|
|
528
|
-
```tsx
|
|
529
|
-
<DocumentProgressCard
|
|
530
|
-
title="Shipment status"
|
|
531
|
-
percent={60}
|
|
532
|
-
segments={[
|
|
533
|
-
{ label: "Shipped", value: 30, color: "green" },
|
|
534
|
-
{ label: "Returned", value: 3, color: "red" },
|
|
535
|
-
{ label: "Pending", value: 17, color: "neutral" },
|
|
536
|
-
]}
|
|
537
|
-
/>
|
|
538
|
-
```
|
|
539
|
-
|
|
540
|
-
**Used in patterns:** `detail/*` — fulfilment / lifecycle summary cards (e.g. a purchase-order receipt progress) in the main column or right rail.
|
|
541
|
-
|
|
542
|
-
### `Avatar`
|
|
543
|
-
|
|
544
|
-
**Import:** `import { Avatar } from '@tailor-platform/app-shell'`
|
|
545
|
-
**Purpose:** User/entity avatar with fallback initials.
|
|
546
|
-
**API:** Compound — `Avatar.Root`, `Avatar.Image`, `Avatar.Fallback`. Plus `avatarVariants` CVA.
|
|
547
|
-
**Used in patterns:** `detail/*` (assignee/owner, comments threads).
|
|
548
|
-
|
|
549
|
-
### `DescriptionCard`
|
|
550
|
-
|
|
551
|
-
**Import:** `import { DescriptionCard } from '@tailor-platform/app-shell'`
|
|
552
|
-
**Purpose:** Key/value display for a single record's metadata.
|
|
553
|
-
**API:** `DescriptionCardProps` — `data`, `title`, `fields` (array of `{ key, label, render? }`), `columns` (1 | 2), `headerAction`.
|
|
554
|
-
**Example:**
|
|
555
|
-
|
|
556
|
-
```tsx
|
|
557
|
-
<DescriptionCard
|
|
558
|
-
title="Order details"
|
|
559
|
-
data={order}
|
|
560
|
-
columns={2}
|
|
561
|
-
fields={[
|
|
562
|
-
{ key: "number", label: "Order number" },
|
|
563
|
-
{ key: "status", label: "Status", render: (v) => <Badge>{v}</Badge> },
|
|
564
|
-
{ key: "createdAt", label: "Created", render: formatDate },
|
|
565
|
-
]}
|
|
566
|
-
/>
|
|
567
|
-
```
|
|
568
|
-
|
|
569
|
-
**Used in:** `page/detail` (body sections).
|
|
570
|
-
|
|
571
|
-
### `ActionPanel`
|
|
572
|
-
|
|
573
|
-
**Import:** `import { ActionPanel } from '@tailor-platform/app-shell'`
|
|
574
|
-
**Purpose:** Right-rail panel listing workflow actions for a detail page (approve, reject, archive, etc.).
|
|
575
|
-
**API:** `ActionPanelProps` — `title`, `actions`, `className`. Each action is `{ key, label, icon, onClick?, disabled?, loading?, variant? }`; `key`, `label` and `icon` are all **required**, the handler is `onClick` (not `onSelect`), and `variant` is `"default" | "destructive"`. There is no `hidden` — omit a row by not spreading it in. The row type is not exported on its own; annotate an array as `ActionPanelProps["actions"]`.
|
|
576
|
-
**Example:**
|
|
577
|
-
|
|
578
|
-
```tsx
|
|
579
|
-
<ActionPanel
|
|
580
|
-
title="Actions"
|
|
581
|
-
actions={[
|
|
582
|
-
{ key: "approve", label: "Approve", icon: <Check />, onClick: handleApprove },
|
|
583
|
-
...(canReject
|
|
584
|
-
? [
|
|
585
|
-
{
|
|
586
|
-
key: "reject",
|
|
587
|
-
label: "Reject",
|
|
588
|
-
icon: <X />,
|
|
589
|
-
onClick: handleReject,
|
|
590
|
-
variant: "destructive" as const,
|
|
591
|
-
loading: rejecting,
|
|
592
|
-
},
|
|
593
|
-
]
|
|
594
|
-
: []),
|
|
595
|
-
]}
|
|
596
|
-
/>
|
|
597
|
-
```
|
|
598
|
-
|
|
599
|
-
**Used in:** `page/detail`.
|
|
600
|
-
|
|
601
|
-
**Notes:**
|
|
602
|
-
|
|
603
|
-
- **Workflow only — never navigation.** `ActionPanel` lists state-change actions on the current record (Approve, Reject, Archive, Generate Variants, Manage Categories, Duplicate). It must NEVER contain back-navigation, breadcrumb-replacement, or "Go to X list" / "Back to X" links — those live in `Layout.Header`'s breadcrumb. If an entry would just navigate the user somewhere else, it does not belong here.
|
|
604
|
-
|
|
605
|
-
### `ActivityCard`
|
|
606
|
-
|
|
607
|
-
**Import:** `import { ActivityCard } from '@tailor-platform/app-shell'`
|
|
608
|
-
**Purpose:** Timeline of events on a record (audit log, status changes, comments).
|
|
609
|
-
**API:** Compound — `ActivityCard.Root`, `ActivityCard.Items` (generic over item type), plus `ActivityCardProps`, `ActivityCardItem`, `ActivityCardItemProps`. Items render with timestamp + actor + description.
|
|
610
|
-
**Used in:** `page/detail` (right column, for revision history / audit trail).
|
|
611
|
-
|
|
612
|
-
### `Alert`
|
|
613
|
-
|
|
614
|
-
**Import:** `import { Alert } from '@tailor-platform/app-shell'`
|
|
615
|
-
**Purpose:** Inline, in-page banner for a persistent status message — a form/record error, a warning, or a success/info notice attached to a section. (Transient notifications use `useToast`; blocking confirmations use `Dialog` — see `interaction/confirm`.)
|
|
616
|
-
**API:** Compound — `Alert.Root` (`variant`: `neutral | success | warning | error | info`, default `neutral`; a matching icon is rendered automatically; optional `action?: ReactNode`, `dismissible?: boolean`, `onDismiss?: () => void`), `Alert.Title`, `Alert.Description`.
|
|
617
|
-
**Example:**
|
|
618
|
-
|
|
619
|
-
```tsx
|
|
620
|
-
<Alert.Root variant="error">
|
|
621
|
-
<Alert.Title>Couldn't load line items</Alert.Title>
|
|
622
|
-
<Alert.Description>Check your connection and try again.</Alert.Description>
|
|
623
|
-
</Alert.Root>
|
|
624
|
-
```
|
|
625
|
-
|
|
626
|
-
**Used in patterns:** any data-backed screen's **error** state (inline error + retry) and record-level warnings — the error affordance the composition rules require (**`design-system.md`** → Composition & emphasis rules → States).
|
|
627
|
-
|
|
628
|
-
**Notes:** Encode severity by `variant` (semantic color), same discipline as `Badge` — don't use `error` for a routine notice. Pair a retry/next-step control via `action` rather than a separate stray button.
|
|
629
|
-
|
|
630
|
-
---
|
|
631
|
-
|
|
632
|
-
## Forms
|
|
633
|
-
|
|
634
|
-
> **Which form stack?** AppShell's `Form` / `Field` / `Fieldset` wrap Base UI primitives and are the
|
|
635
|
-
> default — they need no extra dependency. They own **accessibility wiring and visual state only**
|
|
636
|
-
> (`htmlFor`, `aria-describedby`, `data-invalid` / `data-dirty` / `data-touched`); they do **not** own
|
|
637
|
-
> your values. React Hook Form is **optional** and consumer-installed — reach for it only when a form
|
|
638
|
-
> genuinely needs cross-field validation, field arrays, or a Zod resolver. The two compose; they are
|
|
639
|
-
> not alternatives. `react-hook-form` stopped being a runtime dependency in 1.4.0; it is a dev-only
|
|
640
|
-
> dependency of the package today, used to test the RHF integration contracts — if you use it,
|
|
641
|
-
> install it in your own app.
|
|
642
|
-
|
|
643
|
-
### `Form`
|
|
644
|
-
|
|
645
|
-
> Full API: [https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/form.md](https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/form.md)
|
|
646
|
-
|
|
647
|
-
**Import:** `import { Form } from '@tailor-platform/app-shell'`
|
|
648
|
-
**Purpose:** Form root that wraps Base UI's form primitive. Provides shared validation context for
|
|
649
|
-
child `Field.Root`s, consolidated error display, and server-error routing by field `name`.
|
|
650
|
-
**API:** `FormProps` — `onFormSubmit`, `onSubmit`, `errors`, `actionsRef`, `validationMode`,
|
|
651
|
-
`noValidate`, `id`. Generic over `FormValues`.
|
|
652
|
-
**Actions outside the form:** give the `Form` an `id` and point a detached submit button at it with
|
|
653
|
-
the native `form` attribute. This is how a page-header Save reaches a body form (1.13.0+):
|
|
654
|
-
|
|
655
|
-
```tsx
|
|
656
|
-
<Layout.Header
|
|
657
|
-
title="Create product"
|
|
658
|
-
actions={[<Button key="save" type="submit" form="product-form">Save</Button>]}
|
|
659
|
-
/>
|
|
660
|
-
<Form id="product-form" onFormSubmit={save}>…</Form>
|
|
661
|
-
```
|
|
662
|
-
|
|
663
|
-
**Submit:** use `onFormSubmit(values)` — it receives parsed form values and is the default. Use the
|
|
664
|
-
low-level `onSubmit` **only** when handing the native event to React Hook Form's `handleSubmit`.
|
|
665
|
-
**Never** hand-roll `<form onSubmit={e => new FormData(e.currentTarget)}>` — that skips validation
|
|
666
|
-
and error routing.
|
|
667
|
-
**Server errors:** pass `errors={{ fieldName: "message" }}`; they route to the matching
|
|
668
|
-
`Field.Error` and clear when the user edits that field.
|
|
669
|
-
**Example:** see `form/single-page.md`.
|
|
670
|
-
**Used in patterns:** all `form/*`.
|
|
671
|
-
|
|
672
|
-
### `Field`
|
|
673
|
-
|
|
674
|
-
**Import:** `import { Field } from '@tailor-platform/app-shell'`
|
|
675
|
-
**Purpose:** Single form field with label + control + error message wiring.
|
|
676
|
-
**API:** Compound — `Field.Root`, `Field.Label`, `Field.Control`, `Field.Description`, `Field.Error`,
|
|
677
|
-
`Field.Validity`. `Field.Root` establishes a context boundary; every Base UI-backed AppShell control
|
|
678
|
-
placed inside it inherits label association, `aria-describedby`, `disabled`, and invalid state
|
|
679
|
-
automatically.
|
|
680
|
-
**`Field.Control` is already a styled input** — write `<Field.Control />`, not
|
|
681
|
-
`<Field.Control render={<Input />} />`. `Input` and `Field.Control` share the same base classes, so
|
|
682
|
-
the `render` form just double-wraps. Reach for `Input` directly when you need a control outside a
|
|
683
|
-
`Field.Root`, or when the value is React-controlled.
|
|
684
|
-
**RHF interop (optional):** `Field.Root` accepts `isTouched`, `isDirty`, `invalid`, and `error`,
|
|
685
|
-
matching RHF's `fieldState` shape — so `<Field.Root {...fieldState}>` works with no adapter.
|
|
686
|
-
**Used in patterns:** all `form/*`.
|
|
687
|
-
|
|
688
|
-
### How values reach your submit handler
|
|
689
|
-
|
|
690
|
-
There are three separate mechanisms. Picking the wrong mental model is the most common
|
|
691
|
-
form mistake, so be explicit about which one a screen uses.
|
|
692
|
-
|
|
693
|
-
**1. `Form` + `Field.Root` → `onFormSubmit` (the default).** `onFormSubmit` does **not** read
|
|
694
|
-
`FormData`; it collects values from the `Field.Root`s registered inside the `Form`, keyed by each
|
|
695
|
-
field's `name`. Every AppShell control works this way once wrapped in a `Field.Root name="…"` —
|
|
696
|
-
including `Select`, `Combobox`, and `Autocomplete`. They need **no `name` of their own and no React
|
|
697
|
-
state**:
|
|
698
|
-
|
|
699
|
-
```tsx
|
|
700
|
-
<Form onFormSubmit={(values) => save(values)}>
|
|
701
|
-
<Field.Root name="category">
|
|
702
|
-
<Field.Label>Category</Field.Label>
|
|
703
|
-
<Select items={CATEGORIES} placeholder="Select category" />
|
|
704
|
-
</Field.Root>
|
|
705
|
-
</Form>
|
|
706
|
-
```
|
|
707
|
-
|
|
708
|
-
**2. Native submission** — a plain `<form>`, `new FormData(form)`, or a server action. This reads the
|
|
709
|
-
DOM, so each control needs its own `name`. `Select`, `Combobox`, and `Autocomplete` gained `name`
|
|
710
|
-
(plus `form`, `required`, `inputRef`) in 1.13.0; before that they contributed nothing to a native
|
|
711
|
-
payload.
|
|
712
|
-
|
|
713
|
-
**3. React Hook Form** — optional, consumer-installed. RHF owns the values; drive the control with
|
|
714
|
-
`value` / `onValueChange` from a `Controller` and spread `fieldState` onto `Field.Root`. Warranted
|
|
715
|
-
for cross-field validation, field arrays, or a Zod resolver — not for ordinary CRUD forms.
|
|
716
|
-
|
|
717
|
-
#### Object items
|
|
718
|
-
|
|
719
|
-
Under mechanism 1, a non-string item is serialised into the submitted value:
|
|
720
|
-
|
|
721
|
-
| Item shape | Value in `onFormSubmit` |
|
|
722
|
-
| -------------------------------------- | ------------------------------------ |
|
|
723
|
-
| `string` | the string |
|
|
724
|
-
| `{ value, label }` | `value`, automatically |
|
|
725
|
-
| any other object | **JSON string** — usually not wanted |
|
|
726
|
-
| any other object + `itemToStringValue` | whatever that function returns |
|
|
727
|
-
|
|
728
|
-
So for arbitrary objects, pass `itemToStringValue` to choose the submitted key. It is distinct from
|
|
729
|
-
`mapItem`, which controls what the user sees:
|
|
730
|
-
|
|
731
|
-
```tsx
|
|
732
|
-
<Combobox
|
|
733
|
-
items={warehouses}
|
|
734
|
-
mapItem={(w) => ({ label: w.name, key: String(w.id) })}
|
|
735
|
-
itemToStringValue={(w) => String(w.id)}
|
|
736
|
-
/>
|
|
737
|
-
```
|
|
738
|
-
|
|
739
|
-
Multi-select submits an array.
|
|
740
|
-
|
|
741
|
-
### `Fieldset`
|
|
742
|
-
|
|
743
|
-
**Import:** `import { Fieldset } from '@tailor-platform/app-shell'`
|
|
744
|
-
**Purpose:** Group related fields under a legend (subtle section header).
|
|
745
|
-
**API:** Compound — `Fieldset.Root`, `Fieldset.Legend`.
|
|
746
|
-
**Used in patterns:** `form/sectioned`, `form/wizard`.
|
|
747
|
-
|
|
748
|
-
### `Input`
|
|
749
|
-
|
|
750
|
-
**Import:** `import { Input } from '@tailor-platform/app-shell'`
|
|
751
|
-
**Purpose:** Text input. Maps to spec field types: `string`, `email`, `number`, `password`, `tel`, `url`.
|
|
752
|
-
**API:** `InputProps` — extends native `<input>` props.
|
|
753
|
-
**Used in patterns:** all `form/*`.
|
|
754
|
-
|
|
755
|
-
### `Textarea`
|
|
756
|
-
|
|
757
|
-
> Full API: [https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/textarea.md](https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/textarea.md)
|
|
758
|
-
|
|
759
|
-
**Import:** `import { Textarea } from '@tailor-platform/app-shell'`
|
|
760
|
-
**Purpose:** Multi-line text input. Maps to spec field types: `text`, long-form `string`. Use instead of `Input` whenever the value is prose (notes, descriptions, replies, reasons).
|
|
761
|
-
**API:** `TextareaProps` — Base UI's field control (`value`, `defaultValue`, `onChange`, `onValueChange`, `disabled`, `required`, `readOnly`, `name`, aria-\*) rendered as a `<textarea>`, plus `rows`. `cols` / `wrap` are not accepted — the control is `w-full`, so neither can take effect.
|
|
762
|
-
**Sizing:** no fixed height — `rows` sets the visible line count and the user can drag it taller. `min-h-16` is a hard floor, so `rows` only takes effect from 3 up. Width is the parent's job: the control is `w-full`, and `cols` is not accepted because it could never win against that. Do **not** reach for `Input` and a height override; `Input` is locked to `h-9`, and an application must not use AppShell's internal `astw:` classes.
|
|
763
|
-
**Field integration:** drops straight into `Field.Root` for label/description/error wiring exactly like `Input` and `Checkbox` — no bespoke `error` prop.
|
|
764
|
-
**Example:**
|
|
765
|
-
|
|
766
|
-
```tsx
|
|
767
|
-
<Field.Root name="reason">
|
|
768
|
-
<Field.Label>Reason</Field.Label>
|
|
769
|
-
<Textarea rows={4} placeholder="Why is this being rejected?" />
|
|
770
|
-
</Field.Root>
|
|
771
|
-
```
|
|
772
|
-
|
|
773
|
-
**Used in patterns:** `form/composer`, `form/*` (long-text fields).
|
|
774
|
-
|
|
775
|
-
### `Checkbox`
|
|
776
|
-
|
|
777
|
-
**Import:** `import { Checkbox } from '@tailor-platform/app-shell'`
|
|
778
|
-
**Purpose:** Boolean form control. Maps to spec field type: `boolean`. Also used for row selection and filter toggles.
|
|
779
|
-
**API:** `CheckboxProps` — extends Base UI `Checkbox.Root` (`checked`/`defaultChecked`, `onCheckedChange`, `indeterminate`, `disabled`, `required`, `name`, `inputRef`) and adds an inline `label`. Integrates with `Field` for invalid/disabled/label state exactly like `Input`/`Select` — no bespoke `error` prop.
|
|
780
|
-
**Accessible name:** the inline `label` prop (enclosing) or a sibling `Field.Label`; for a bare box (e.g. a table row-select cell) pass `aria-label`.
|
|
781
|
-
**Used in patterns:** `form/*` (boolean fields), `list/*` (row selection), DataTable filter/column controls.
|
|
782
|
-
|
|
783
|
-
### `Select`
|
|
784
|
-
|
|
785
|
-
**Import:** `import { Select } from '@tailor-platform/app-shell'`
|
|
786
|
-
**Purpose:** Dropdown for fixed enumerations.
|
|
787
|
-
**API:** Compound. Sync version (small option lists). For async/typeahead, see `Combobox` and `Autocomplete`. Type: `SelectAsyncFetcher<T>` for the async variant.
|
|
788
|
-
**Accessible name:** inside a `Form` the field label provides it automatically. When used **standalone** (outside a `Form`), pass `aria-label` (or `aria-labelledby` / `id`) — these now forward to the underlying combobox element, so it isn't left named only by its current value. Same applies to `Combobox` and `Autocomplete`.
|
|
789
|
-
**Used in patterns:** all `form/*` (enum fields).
|
|
790
|
-
|
|
791
|
-
### `Combobox`
|
|
792
|
-
|
|
793
|
-
**Import:** `import { Combobox } from '@tailor-platform/app-shell'`
|
|
794
|
-
**Purpose:** Single-select with search, supports async data fetching.
|
|
795
|
-
**API:** Compound. `ComboboxAsyncFetcher<T>` for paginated/queried option sources (e.g. lookups).
|
|
796
|
-
**Used in patterns:** `form/*` (foreign-key lookups).
|
|
797
|
-
|
|
798
|
-
### `Autocomplete`
|
|
799
|
-
|
|
800
|
-
**Import:** `import { Autocomplete } from '@tailor-platform/app-shell'`
|
|
801
|
-
**Purpose:** Free-text input with completion suggestions (multi-select capable).
|
|
802
|
-
**API:** Compound. `AutocompleteAsyncFetcher<T>` for async suggestion sources. `ItemGroup<T>` for grouped suggestions.
|
|
803
|
-
**Used in patterns:** `form/*` (tags, free-text + suggested values).
|
|
804
|
-
|
|
805
|
-
---
|
|
806
|
-
|
|
807
|
-
## AI
|
|
808
|
-
|
|
809
|
-
### `AIChat`
|
|
810
|
-
|
|
811
|
-
> Full API: [https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/ai-chat.md](https://raw.githubusercontent.com/tailor-platform/app-shell/refs/heads/main/docs/components/ai-chat.md)
|
|
812
|
-
|
|
813
|
-
**Import:** `import { AIChat } from '@tailor-platform/app-shell'`
|
|
814
|
-
**Purpose:** Building blocks for an LLM assistant UI — a streaming conversation view over a composer, plus reasoning, tool-call, and citation parts. The root places three regions in a fixed order, `Layout`-style: `AIChat.Header` (optional) over `AIChat.Conversation` over `AIChat.Composer` (optional). Each region carries its own props; the root carries `status`.
|
|
815
|
-
**API:** Root (`status`) + regions — `AIChat.Header` (`title`, `icon`, `actions`), `AIChat.Conversation` (`autoScroll`, transcript as children), `AIChat.Composer` (`onSubmit`, `onStop`, `value`/`defaultValue`/`onValueChange`, `placeholder`, `disabled`, `submitOnEnter`, `actions`) — + transcript parts: `AIChat.Message`, `.Response`, `.EmptyState`, `.Suggestions`/`.Suggestion`, `.Actions`/`.Action`, `.Reasoning`/`.ReasoningTrigger`/`.ReasoningContent`, `.ChainOfThought*`, `.Tool*`, `.Sources*`, `.History`.
|
|
816
|
-
**Composer:** Body is `Textarea` over one action row per `form/composer`'s layout. Enter submits (IME-safe), Shift+Enter newlines, and `status` from `useAIChat()` drives the busy/Stop state.
|
|
817
|
-
**Header:** a 48px strip (graphic + `text-sm font-semibold` title + right action slot) closed by a full-width rule; renders only when `title` or `actions` is set.
|
|
818
|
-
**Renders no chrome:** no border or background of its own — wrap in `Card`, `Sheet`, or a `Layout.Column`, with `overflow-hidden` so the header rule stays inside rounded corners.
|
|
819
|
-
**Used in patterns:** none yet — a component, not a catalogue pattern (platform-planning#1748).
|
|
820
|
-
|
|
821
|
-
---
|
|
822
|
-
|
|
823
|
-
## Auth & access
|
|
824
|
-
|
|
825
|
-
### `AuthProvider`
|
|
826
|
-
|
|
827
|
-
**Import:** `import { AuthProvider } from '@tailor-platform/app-shell'`
|
|
828
|
-
**Purpose:** Wraps the app to expose auth state via `useAuth`. Mount in `App.tsx`.
|
|
829
|
-
**API:** `AuthProviderProps` — `client` (from `createAuthClient`), `autoLogin`, `guardComponent`.
|
|
830
|
-
**Used in patterns:** project-level. See `project-setup.md`.
|
|
831
|
-
|
|
832
|
-
### `createAuthClient`
|
|
833
|
-
|
|
834
|
-
**Import:** `import { createAuthClient, type EnhancedAuthClient } from '@tailor-platform/app-shell'`
|
|
835
|
-
**Purpose:** Factory for the auth client, configured with platform URL + client ID.
|
|
836
|
-
**API:** `createAuthClient(config: AuthClientConfig): EnhancedAuthClient`.
|
|
837
|
-
**Used in patterns:** project-level.
|
|
838
|
-
|
|
839
|
-
### `useAuth`, `useAuthSuspense`
|
|
840
|
-
|
|
841
|
-
**Import:** `import { useAuth, useAuthSuspense } from '@tailor-platform/app-shell'`
|
|
842
|
-
**Purpose:** Read auth state in components. `useAuth` returns nullable state; `useAuthSuspense` suspends until ready (use inside route loaders / suspense boundaries).
|
|
843
|
-
**API:** Returns `AuthState` (user, status, login/logout actions).
|
|
844
|
-
**Used in patterns:** any pattern needing user identity.
|
|
845
|
-
|
|
846
|
-
### `AuthClient` (type)
|
|
847
|
-
|
|
848
|
-
**Import:** `import { type AuthClient } from '@tailor-platform/app-shell'`
|
|
849
|
-
**Purpose:** Public auth client interface (re-exported from `@tailor-platform/auth-public-client`).
|
|
850
|
-
|
|
851
|
-
### `WithGuard`
|
|
852
|
-
|
|
853
|
-
**Import:** `import { WithGuard } from '@tailor-platform/app-shell'`
|
|
854
|
-
**Purpose:** Permission gate around a UI subtree. Hides, denies, or shows a loading state based on the guard result.
|
|
855
|
-
**API:** `WithGuardProps` — `guard: Guard`, `fallback`, `mode: 'hidden' | 'deny'`.
|
|
856
|
-
**Used in patterns:** `detail/*` (action gating), `list/*` (row-level action visibility).
|
|
857
|
-
|
|
858
|
-
### Guard helpers — `pass`, `hidden`, `redirectTo`
|
|
859
|
-
|
|
860
|
-
**Import:** `import { pass, hidden, redirectTo } from '@tailor-platform/app-shell'`
|
|
861
|
-
**Purpose:** Return values for guard functions. `pass()` allows, `hidden()` hides, `redirectTo(path)` navigates.
|
|
862
|
-
**Used in patterns:** any `Guard` definition.
|
|
863
|
-
|
|
864
|
-
### `Guard`, `GuardContext`, `GuardResult` (types)
|
|
865
|
-
|
|
866
|
-
Types for authoring guard functions used by `WithGuard` and `appShellPageProps.guards`.
|
|
867
|
-
|
|
868
|
-
---
|
|
869
|
-
|
|
870
|
-
## Routing helpers
|
|
871
|
-
|
|
872
|
-
### `useNavigate`, `useParams`, `useSearchParams`, `useLocation`, `useRouteError`
|
|
873
|
-
|
|
874
|
-
**Import:** `import { useNavigate, useParams, useSearchParams, useLocation, useRouteError } from '@tailor-platform/app-shell'`
|
|
875
|
-
**Purpose:** Re-exported from `react-router`. Use the AppShell barrel — never import from `react-router` directly.
|
|
876
|
-
**Used in patterns:** all (navigation, route params, query state).
|
|
877
|
-
|
|
878
|
-
### `useMatch`, `useResolvedPath`, `useNavigation`
|
|
879
|
-
|
|
880
|
-
**Import:** `import { useMatch, useResolvedPath, useNavigation } from '@tailor-platform/app-shell'`
|
|
881
|
-
**Purpose:** `useMatch` tests a pattern against the current location (active states); `useResolvedPath` resolves a relative path; `useNavigation` exposes the in-flight navigation for pending UI.
|
|
882
|
-
**Used in patterns:** navigation shells, list→detail transitions.
|
|
883
|
-
|
|
884
|
-
### `useBlocker`, `useBeforeUnload`
|
|
885
|
-
|
|
886
|
-
**Import:** `import { useBlocker, useBeforeUnload } from '@tailor-platform/app-shell'`
|
|
887
|
-
**Purpose:** Guard navigation away from unsaved work — `useBlocker` for in-app navigation, `useBeforeUnload` for closing or reloading the tab.
|
|
888
|
-
**Used in patterns:** form-heavy screens.
|
|
889
|
-
|
|
890
|
-
### Types
|
|
891
|
-
|
|
892
|
-
**Import:** `import type { Location, NavigateFunction, NavigateOptions, To, Params, PathMatch, LinkProps, NavLinkProps, Navigation, Blocker, BlockerFunction } from '@tailor-platform/app-shell'`
|
|
893
|
-
**Purpose:** The React Router types that go with the hooks above, so app code never imports types from `react-router` either.
|
|
894
|
-
|
|
895
|
-
### Not exported
|
|
896
|
-
|
|
897
|
-
`createBrowserRouter`, `RouterProvider`, `MemoryRouter`, `Routes`, `Route` — AppShell builds the router; a second one nested inside it breaks navigation. `useLoaderData`, `Form`, `useSubmit`, `useFetcher`, `useActionData` — AppShell does not wire up React Router's data layer. Load data in the page component or the app's data layer.
|
|
898
|
-
|
|
899
|
-
### Testing
|
|
900
|
-
|
|
901
|
-
**Import:** `import { AppShell, TestRouter } from '@tailor-platform/app-shell/testing'`
|
|
902
|
-
**Purpose:** Test routing without a `react-router` dependency. `AppShell` from this entry also accepts `memory` / `initialEntries`, for mounting a page at a fixed URL; `TestRouter` gives a single component router context, and takes `path` when that component reads the route (`useParams` is `{}` without it).
|
|
903
|
-
|
|
904
|
-
### `createTypedPaths`
|
|
905
|
-
|
|
906
|
-
**Import:** `import { createTypedPaths } from '@tailor-platform/app-shell'`
|
|
907
|
-
**Purpose:** Type-safe path builder generated from the route tree.
|
|
908
|
-
**API:** `createTypedPaths<TRoutes>()` returns a `paths.for(...)` helper.
|
|
909
|
-
**Used in patterns:** project-level. See `project-setup.md`.
|
|
910
|
-
|
|
911
|
-
### `RouteParams`, `PageComponent`, `PageMeta`, `AppShellPageProps`, `AppShellRegister`, `ContextData` (types)
|
|
912
|
-
|
|
913
|
-
Types for declaring page props (`appShellPageProps = { meta, guards }`), reading typed route params, and registering route types globally. See `project-setup.md` for usage.
|
|
914
|
-
|
|
915
|
-
---
|
|
916
|
-
|
|
917
|
-
## Hooks
|
|
918
|
-
|
|
919
|
-
### `useToast`
|
|
920
|
-
|
|
921
|
-
**Import:** `import { useToast } from '@tailor-platform/app-shell'`
|
|
922
|
-
**Purpose:** Imperative toast feedback after mutations.
|
|
923
|
-
**API:** Returns the `sonner` `toast` function — `toast.success(message)`, `toast.error(message)`, `toast.loading(message)`, plus options for duration, action button, etc.
|
|
924
|
-
**Used in patterns:** `interaction/toast`. Called from any mutation handler.
|
|
925
|
-
|
|
926
|
-
### `useTheme`
|
|
927
|
-
|
|
928
|
-
**Import:** `import { useTheme } from '@tailor-platform/app-shell'`
|
|
929
|
-
**Purpose:** Read/write the active theme (light/dark/system).
|
|
930
|
-
**API:** Returns `ThemeProviderState`.
|
|
931
|
-
**Used in patterns:** any theme-toggle UI.
|
|
932
|
-
|
|
933
|
-
### `useAppShell`, `useAppShellConfig`, `useAppShellData`
|
|
934
|
-
|
|
935
|
-
**Import:** `import { useAppShell, useAppShellConfig, useAppShellData } from '@tailor-platform/app-shell'`
|
|
936
|
-
**Purpose:** Access AppShell context — the resolved `AppShellRegister` data, config, and runtime state.
|
|
937
|
-
**Used in patterns:** advanced — when a component needs to read app-wide config or registered resources.
|
|
938
|
-
|
|
939
|
-
### `usePageMeta`, `useOverrideBreadcrumb`
|
|
940
|
-
|
|
941
|
-
**Import:** `import { usePageMeta, useOverrideBreadcrumb } from '@tailor-platform/app-shell'`
|
|
942
|
-
**Purpose:** Read the current page's `meta` (resolved from `appShellPageProps.meta`) or override the breadcrumb title at runtime (e.g. show the order number once data loads).
|
|
943
|
-
**Used in patterns:** `detail/*` (dynamic breadcrumbs from loaded entity).
|
|
944
|
-
|
|
945
|
-
---
|
|
946
|
-
|
|
947
|
-
## i18n & resource definitions
|
|
948
|
-
|
|
949
|
-
### `defineI18nLabels`
|
|
950
|
-
|
|
951
|
-
**Import:** `import { defineI18nLabels } from '@tailor-platform/app-shell'`
|
|
952
|
-
**Purpose:** Declare i18n labels in a typed way. Returns `I18nLabels<Def, L>`.
|
|
953
|
-
**Used in patterns:** project-level for multi-locale apps.
|
|
954
|
-
|
|
955
|
-
### `defineModule`, `defineResource`
|
|
956
|
-
|
|
957
|
-
**Import:** `import { defineModule, defineResource } from '@tailor-platform/app-shell'`
|
|
958
|
-
**Purpose:** Register an app module / a resource (entity with CRUD pages). Wires routes, sidebar, and command palette automatically.
|
|
959
|
-
**API:** `defineModule(props: DefineModuleProps): Module`, `defineResource(props: DefineResourceProps): Resource`.
|
|
960
|
-
**Used in patterns:** project-level. See `project-setup.md`.
|
|
961
|
-
|
|
962
|
-
### `MappedItem`, `Module`, `Resource`, `ResourceComponentProps` (types)
|
|
963
|
-
|
|
964
|
-
Types returned/consumed by the define-\* helpers above.
|
|
965
|
-
|
|
966
|
-
---
|
|
967
|
-
|
|
968
|
-
## Style helpers
|
|
969
|
-
|
|
970
|
-
### `avatarVariants`, `badgeVariants`, `buttonVariants`
|
|
971
|
-
|
|
972
|
-
**Import:** `import { avatarVariants, badgeVariants, buttonVariants } from '@tailor-platform/app-shell'`
|
|
973
|
-
**Purpose:** CVA (`class-variance-authority`) variant functions backing `Avatar`, `Badge`, `Button`. Use when authoring a custom component that should match an AppShell variant inline.
|
|
974
|
-
**Used in patterns:** custom-component fallbacks (see `design-system.md` § "When AppShell doesn't have a component you need").
|
|
975
|
-
|
|
976
|
-
### `ErrorBoundaryComponent` (type)
|
|
977
|
-
|
|
978
|
-
**Import:** `import { type ErrorBoundaryComponent } from '@tailor-platform/app-shell'`
|
|
979
|
-
**Purpose:** Type for an error boundary component slot in routing.
|
|
980
|
-
|
|
981
|
-
---
|
|
982
|
-
|
|
983
|
-
## Keeping this file in sync
|
|
984
|
-
|
|
985
|
-
When `@tailor-platform/app-shell` publishes a new version:
|
|
986
|
-
|
|
987
|
-
1. Bump `package.json` in the scaffold templates (`templates/scaffold/app/*/frontend/`) to the new version.
|
|
988
|
-
2. Update the AppShell version header at the top of this file.
|
|
989
|
-
3. Diff exports between old and new:
|
|
990
|
-
|
|
991
|
-
```bash
|
|
992
|
-
# Run in a scratch dir:
|
|
993
|
-
mkdir -p /tmp/appshell-diff && cd /tmp/appshell-diff
|
|
994
|
-
npm init -y >/dev/null && npm install --no-save --silent @tailor-platform/app-shell@<NEW_VERSION>
|
|
995
|
-
node -e "console.log(Object.keys(require('@tailor-platform/app-shell')).sort().join('\n'))" \
|
|
996
|
-
> new-exports.txt
|
|
997
|
-
# Compare against the headings in this file:
|
|
998
|
-
grep -E '^### ' \
|
|
999
|
-
packages/erp-kit/skills/erp-kit-app-6-impl-frontend/references/components.md \
|
|
1000
|
-
| sed 's/^### //; s/ ,.*//' | sort > current-headings.txt
|
|
1001
|
-
diff current-headings.txt new-exports.txt
|
|
1002
|
-
```
|
|
1003
|
-
|
|
1004
|
-
4. For each new export — add a section using the fixed shape above.
|
|
1005
|
-
5. For each removed export — delete its section, then grep `references/patterns/` for the component name and update or retire the patterns that cited it.
|
|
1006
|
-
6. For each changed export (new prop, behavior change) — update the section and add a one-line note under "Notes:".
|
|
1007
|
-
7. Run `pnpm erp-kit update skills` to regenerate `.agents/skills/`.
|
|
1008
|
-
|
|
1009
|
-
The pattern-citation review check (`erp-kit-app-7-impl-review` → `design-parity.md`) catches drift indirectly: if a pattern lists a component that no longer exists, generated pages will fail the review.
|