@tailor-platform/app-shell 1.2.0 → 1.3.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.
@@ -0,0 +1,704 @@
1
+ # AppShell Components
2
+
3
+ > **AppShell version:** `0.36.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/*`) | **`astw:`** rules — only on AppShell `*ClassName` props; plain utilities on **your** elements |
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`: `columns` (number, default auto-detected from children), `gap`, `title`, `actions`, `className`, `style`.
51
+
52
+ **Column-count → width rules** (column count is auto-detected from `Layout.Column` children):
53
+
54
+ | Columns | Breakpoint | Widths | Below breakpoint |
55
+ | ------- | ---------- | ------------------------------ | ---------------- |
56
+ | 1 | always | full | n/a |
57
+ | 2 | ≥ 1024px | flex + 280px | stacks |
58
+ | 3 | ≥ 1280px | 320px + flex + 280px | stacks |
59
+ | 4+ | ≥ 1280px | equal share — `repeat(N, 1fr)` | stacks |
60
+
61
+ Desktop breakpoints and desktop-first rationale: **`design-system.md`** §4 Breakpoints. This table is **`Layout` column mechanics only**.
62
+
63
+ **`Layout.Header`** — direct child of `<Layout>`, above any `<Layout.Column>`. Only the first is rendered if multiple are passed.
64
+
65
+ | Prop | Type | Description |
66
+ | ---------- | ------------------- | ------------------------------------------------ |
67
+ | `title` | `string` | Page title — `<h1>` on the left |
68
+ | `actions` | `React.ReactNode[]` | Buttons on the right |
69
+ | `children` | `React.ReactNode` | Full-width row below title — typical use is tabs |
70
+
71
+ **`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.
72
+
73
+ **Example — list page header with tabs:**
74
+
75
+ ```tsx
76
+ import { Button, Layout, Tabs } from "@tailor-platform/app-shell";
77
+
78
+ <Layout>
79
+ <Layout.Header title="Purchase orders" actions={[<Button key="create">Create</Button>]}>
80
+ <Tabs.Root value={bucket} onValueChange={setBucket}>
81
+ <Tabs.List>
82
+ <Tabs.Trigger value="all">All</Tabs.Trigger>
83
+ <Tabs.Trigger value="open">Open</Tabs.Trigger>
84
+ </Tabs.List>
85
+ </Tabs.Root>
86
+ </Layout.Header>
87
+ <Layout.Column>{/* table — see patterns/list/dense-scan.md */}</Layout.Column>
88
+ </Layout>;
89
+ ```
90
+
91
+ **Example — detail page, 2-column with area mode:**
92
+
93
+ ```tsx
94
+ <Layout>
95
+ <Layout.Header title={order.number} actions={[<Button>Edit</Button>]} />
96
+ <Layout.Column area="main">
97
+ <DescriptionCard ... />
98
+ </Layout.Column>
99
+ <Layout.Column area="right">
100
+ <ActionPanel ... />
101
+ <ActivityCard ... />
102
+ </Layout.Column>
103
+ </Layout>
104
+ ```
105
+
106
+ **Notes:** Children that aren't `Layout.Header` or `Layout.Column` are filtered out. Column gap overrides (`<Layout className="astw:gap-6" />`) → **`design-system.md`** §5 (`astw:` rules).
107
+
108
+ **Used in patterns:** every page pattern (`list/*`, `detail/*`, `form/*`).
109
+
110
+ ### `SidebarLayout`
111
+
112
+ **Import:** `import { SidebarLayout } from '@tailor-platform/app-shell'`
113
+ **Purpose:** Top-level layout that mounts the sidebar and renders the page outlet.
114
+ **API:** `SidebarLayoutProps` — sidebar config, header config, content slot. Used in `App.tsx`.
115
+ **Used in patterns:** consumed by AppShell init, not directly by page patterns. See `project-setup.md`.
116
+
117
+ ### `DefaultSidebar`, `SidebarGroup`, `SidebarItem`, `SidebarSeparator`
118
+
119
+ **Import:** `import { DefaultSidebar, SidebarGroup, SidebarItem, SidebarSeparator } from '@tailor-platform/app-shell'`
120
+ **Purpose:** Sidebar composition. `DefaultSidebar` auto-resolves nav items from `appShellPageProps.meta` on each page; the others let you customize manually.
121
+ **Used in patterns:** sidebar is a project-level concern. See `project-setup.md`.
122
+
123
+ ### `CommandPalette`
124
+
125
+ **Import:** `import { CommandPalette } from '@tailor-platform/app-shell'`
126
+ **Purpose:** Cmd/Ctrl-K command palette. Auto-discovers searchable resources via `defineResource`.
127
+ **API:** Renderless — drop into the layout once.
128
+ **Used in patterns:** project-level. Useful for any app with >10 routes.
129
+
130
+ ---
131
+
132
+ ## Interaction surfaces
133
+
134
+ ### `Button`
135
+
136
+ > 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)
137
+
138
+ **Import:** `import { Button } from '@tailor-platform/app-shell'`
139
+ **Purpose:** All buttons in the app — including polymorphic rendering via the `render` prop.
140
+ **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).
141
+ **Example:**
142
+
143
+ ```tsx
144
+ import { Button, Link } from '@tailor-platform/app-shell';
145
+
146
+ <Button render={<Link to="create" />}>Create</Button>
147
+ <Button variant="destructive" onClick={handleDelete}>Delete</Button>
148
+ ```
149
+
150
+ **Used in patterns:** every pattern.
151
+
152
+ ### `Link`
153
+
154
+ **Import:** `import { Link } from '@tailor-platform/app-shell'`
155
+ **Purpose:** Router-aware anchor. Re-exported from `react-router` so the rest of the app stays on the AppShell barrel.
156
+ **API:** `to`, `replace`, `state`, etc. — same as `react-router`.
157
+ **Used in patterns:** all (navigation).
158
+
159
+ ### `Dialog`
160
+
161
+ > 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)
162
+
163
+ **Import:** `import { Dialog } from '@tailor-platform/app-shell'`
164
+ **Purpose:** Modal dialog for confirmations, ≤5-field forms, blocking workflows.
165
+ **API:** Compound — `Dialog.Root`, `Dialog.Trigger`, `Dialog.Content`, `Dialog.Header`, `Dialog.Title`, `Dialog.Description`, `Dialog.Footer`, `Dialog.Close`. Controllable via `open` + `onOpenChange`.
166
+ **Example:**
167
+
168
+ ```tsx
169
+ <Dialog.Root>
170
+ <Dialog.Trigger render={<Button variant="destructive" />}>Delete</Dialog.Trigger>
171
+ <Dialog.Content>
172
+ <Dialog.Header>
173
+ <Dialog.Title>Delete order #1234?</Dialog.Title>
174
+ <Dialog.Description>This cannot be undone.</Dialog.Description>
175
+ </Dialog.Header>
176
+ <Dialog.Footer>
177
+ <Dialog.Close render={<Button variant="outline" />}>Cancel</Dialog.Close>
178
+ <Button variant="destructive" onClick={onDelete}>
179
+ Delete
180
+ </Button>
181
+ </Dialog.Footer>
182
+ </Dialog.Content>
183
+ </Dialog.Root>
184
+ ```
185
+
186
+ **Used in patterns:** `form/modal`, `interaction/confirm`.
187
+
188
+ ### `Sheet`
189
+
190
+ > 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)
191
+
192
+ **Import:** `import { Sheet } from '@tailor-platform/app-shell'`
193
+ **Purpose:** Slide-in panel from any edge. Use for filters, side-work without losing context.
194
+ **API:** Compound — `Sheet.Root` (with `side: 'left' | 'right' | 'top' | 'bottom'`), `Sheet.Trigger`, `Sheet.Content`, `Sheet.Header`, `Sheet.Title`, `Sheet.Description`, `Sheet.Footer`, `Sheet.Close`.
195
+ **Example:**
196
+
197
+ ```tsx
198
+ <Sheet.Root side="right">
199
+ <Sheet.Trigger render={<Button variant="outline" />}>Filters</Sheet.Trigger>
200
+ <Sheet.Content>
201
+ <Sheet.Header>
202
+ <Sheet.Title>Filter orders</Sheet.Title>
203
+ </Sheet.Header>
204
+ {/* filter inputs */}
205
+ <Sheet.Footer>
206
+ <Sheet.Close render={<Button variant="outline" />}>Clear</Sheet.Close>
207
+ <Button>Apply</Button>
208
+ </Sheet.Footer>
209
+ </Sheet.Content>
210
+ </Sheet.Root>
211
+ ```
212
+
213
+ **Used in patterns:** `list/*` (filter sheet variant).
214
+
215
+ **Notes:** Size the panel with **`contentClassName`** (often `astw:*` utilities). Rules → **`design-system.md`** §5.
216
+
217
+ ### `Menu`
218
+
219
+ > 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)
220
+
221
+ **Import:** `import { Menu } from '@tailor-platform/app-shell'`
222
+ **Purpose:** Dropdown menu — row actions, overflow actions, grouped commands.
223
+ **API:** Compound — `Menu.Root`, `Menu.Trigger`, `Menu.Content`, `Menu.Item`, `Menu.Separator`, `Menu.Group`, `Menu.GroupLabel`. Supports checkbox/radio items and nested sub-menus.
224
+ **Example:**
225
+
226
+ ```tsx
227
+ <Menu.Root>
228
+ <Menu.Trigger>
229
+ <Button variant="ghost" size="icon">
230
+ <EllipsisVertical />
231
+ </Button>
232
+ </Menu.Trigger>
233
+ <Menu.Content>
234
+ <Menu.Item onSelect={() => handleAssign(id)}>Assign</Menu.Item>
235
+ <Menu.Item onSelect={() => handleDuplicate(id)}>Duplicate</Menu.Item>
236
+ <Menu.Separator />
237
+ <Menu.Item onSelect={() => handleDelete(id)}>Delete</Menu.Item>
238
+ </Menu.Content>
239
+ </Menu.Root>
240
+ ```
241
+
242
+ **Used in patterns:** `list/*` (row actions), `detail/*` (overflow actions).
243
+
244
+ **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.
245
+
246
+ ### `Tooltip`
247
+
248
+ **Import:** `import { Tooltip } from '@tailor-platform/app-shell'`
249
+ **Purpose:** Contextual hint on hover/focus. Use sparingly — for icon-only buttons or constrained labels.
250
+ **API:** Compound — `Tooltip.Root`, `Tooltip.Trigger`, `Tooltip.Content`.
251
+ **Used in patterns:** any pattern with icon-only buttons (must have `aria-label` AND a tooltip).
252
+
253
+ ---
254
+
255
+ ## Display
256
+
257
+ ### `Badge`
258
+
259
+ > 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)
260
+
261
+ **Import:** `import { Badge } from '@tailor-platform/app-shell'`
262
+ **Purpose:** Status labels and small categorical chips.
263
+ **API:** `BadgeProps` — `variant`: `default | success | warning | neutral | error | destructive`. Plus `badgeVariants` CVA for custom-styled siblings.
264
+ **Example:**
265
+
266
+ ```tsx
267
+ <Badge variant="success">Active</Badge>
268
+ ```
269
+
270
+ **Used in patterns:** `list/*` (status column), `detail/*` (header status).
271
+
272
+ ### `Table`
273
+
274
+ > 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)
275
+
276
+ **Import:** `import { Table } from '@tailor-platform/app-shell'`
277
+ **Purpose:** Semantic data table with scrollable container.
278
+ **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>`.
279
+ **Example:**
280
+
281
+ ```tsx
282
+ <Table.Root>
283
+ <Table.Header>
284
+ <Table.Row>
285
+ <Table.Head>Order</Table.Head>
286
+ <Table.Head>Status</Table.Head>
287
+ <Table.Head className="astw:text-right">Total</Table.Head>
288
+ </Table.Row>
289
+ </Table.Header>
290
+ <Table.Body>
291
+ {orders.map((o) => (
292
+ <Table.Row key={o.id}>
293
+ <Table.Cell>{o.number}</Table.Cell>
294
+ <Table.Cell>
295
+ <Badge variant={statusVariant(o.status)}>{o.status}</Badge>
296
+ </Table.Cell>
297
+ <Table.Cell className="astw:text-right">{formatMoney(o.total)}</Table.Cell>
298
+ </Table.Row>
299
+ ))}
300
+ </Table.Body>
301
+ </Table.Root>
302
+ ```
303
+
304
+ **Used in patterns:** `list-dense-scan` hand-built subsets / static tables (`DataTable` is preferred for wired lists).
305
+
306
+ **Notes:**
307
+
308
+ - **Inside a card?** Pass `containerClassName="astw:px-6"` on `Table.Root` for the horizontal inset, and either drop `Card.Content` (bare list form) or pass `Card.Content className="astw:px-0"` (header+content form). Skipping the `containerClassName` lands the first column flush against the card edge. See the `Card` entry for the two canonical forms and a DON'T example. Dense cell typography (**`text-body-sm`**, **`text-mono`**) → **`design-system.md`** §4 Typography.
309
+ - **Whole row is clickable.** Use `<Table.Row onClick={() => navigate(detailPath)} className="astw: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.
310
+
311
+ ### `DataTable`
312
+
313
+ > 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)
314
+
315
+ **Import:** compound namespace + helpers from `'@tailor-platform/app-shell'`, e.g. `DataTable`, `useDataTable`, `useCollectionVariables`, `createColumnHelper`, and types such as `Column`, `UseDataTableReturn`.
316
+
317
+ **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).
318
+
319
+ **Primitives:** Builds on low-level **`Table`**; do not reinvent pagination/filters manually unless the dataset is trivial.
320
+
321
+ **Shape:**
322
+
323
+ ```tsx
324
+ const { variables, control } = useCollectionVariables({
325
+ params: { pageSize: 20 },
326
+ // tableMetadata: tableMetadata.po, // typed vars when generated
327
+ });
328
+
329
+ const table = useDataTable({
330
+ columns,
331
+ data: fetching ? undefined : mappedFromQuery,
332
+ loading: fetching,
333
+ control,
334
+ onClickRow: (row) => navigate(detailHref(row)),
335
+ // onSelectionChange, rowActions, sort: …
336
+ });
337
+
338
+ <DataTable.Root value={table}>
339
+ <DataTable.Toolbar>
340
+ <DataTable.Filters />
341
+ </DataTable.Toolbar>
342
+ <DataTable.Table />
343
+ <DataTable.Footer>
344
+ <DataTable.Pagination pageSizeOptions={[10, 20, 50]} />
345
+ </DataTable.Footer>
346
+ </DataTable.Root>;
347
+ ```
348
+
349
+ **Metadata path:** Prefer `createColumnHelper` + `inferColumns(tableMetadata.order)` (`@tailor-platform/app-shell-sdk-plugin` codegen) when available so enum/datetime/string filters bind to the right editors.
350
+
351
+ **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`**.
352
+
353
+ **Used in patterns:** `list-dense-scan` (preferred for live collections).
354
+
355
+ ### `Card`
356
+
357
+ **Import:** `import { Card } from '@tailor-platform/app-shell'`
358
+ **Purpose:** Generic container with header, content, optional action.
359
+ **API:** Compound — `Card.Root`, `Card.Header` (props: `title`, `description`, plus children for actions), `Card.Content`.
360
+ **Example:**
361
+
362
+ ```tsx
363
+ <Card.Root>
364
+ <Card.Header title="Recent orders" description="Last 7 days">
365
+ <Button size="sm" variant="outline">
366
+ View all
367
+ </Button>
368
+ </Card.Header>
369
+ <Card.Content>{/* anything */}</Card.Content>
370
+ </Card.Root>
371
+ ```
372
+
373
+ **Used in patterns:** `detail/*` (related-data sections), `form/wizard` (step container).
374
+
375
+ **Notes:**
376
+
377
+ - **Tables inside a card need TWO co-requisite geometry changes** (token-backed spacing rationale → **`design-system.md`** §4 Spacing): (a) Card stops imposing horizontal padding — drop `Card.Content` for the bare form, or pass `Card.Content className="astw:px-0"` for the header+content form. (b) `Table.Root` provides the inset itself via `containerClassName="astw:px-6"`. Skipping (b) lands the first column flush against the card edge — `Table.Cell`'s intrinsic `astw:first:pl-6` does NOT render reliably in this composition.
378
+
379
+ **Bare table-in-card (list pages, no card-level title):**
380
+
381
+ ```tsx
382
+ <Card.Root>
383
+ <Table.Root containerClassName="astw:px-6">{/* … */}</Table.Root>
384
+ </Card.Root>
385
+ ```
386
+
387
+ **Header + table (detail-page sections like "Line items"):**
388
+
389
+ ```tsx
390
+ <Card.Root>
391
+ <Card.Header title="Line items" />
392
+ <Card.Content className="astw:px-0">
393
+ <Table.Root containerClassName="astw:px-6">{/* … */}</Table.Root>
394
+ </Card.Content>
395
+ </Card.Root>
396
+ ```
397
+
398
+ **DON'T — first column lands flush against the card edge:**
399
+
400
+ ```tsx
401
+ <Card.Root>
402
+ <Card.Content className="astw:px-0">
403
+ <Table.Root>{/* missing containerClassName="astw:px-6" */}</Table.Root>
404
+ </Card.Content>
405
+ </Card.Root>
406
+ ```
407
+
408
+ ### `MetricCard`
409
+
410
+ **Import:** `import { MetricCard } from '@tailor-platform/app-shell'`
411
+ **Purpose:** KPI tile for dashboards or hero metric strip.
412
+ **API:** `MetricCardProps` — `title`, `value`, `trend: { direction, value }`, `description`, `icon`.
413
+ **Example:**
414
+
415
+ ```tsx
416
+ <MetricCard
417
+ title="Net total"
418
+ value="$1,500"
419
+ trend={{ direction: "up", value: "+5%" }}
420
+ description="vs last month"
421
+ icon={<DollarSign />}
422
+ />
423
+ ```
424
+
425
+ **Used in patterns:** KPI tiles, dashboards, **`detail/*`** metric strips where specs call for them.
426
+
427
+ ### `Avatar`
428
+
429
+ **Import:** `import { Avatar } from '@tailor-platform/app-shell'`
430
+ **Purpose:** User/entity avatar with fallback initials.
431
+ **API:** Compound — `Avatar.Root`, `Avatar.Image`, `Avatar.Fallback`. Plus `avatarVariants` CVA.
432
+ **Used in patterns:** `detail/*` (assignee/owner, comments threads).
433
+
434
+ ### `DescriptionCard`
435
+
436
+ **Import:** `import { DescriptionCard } from '@tailor-platform/app-shell'`
437
+ **Purpose:** Key/value display for a single record's metadata.
438
+ **API:** `DescriptionCardProps` — `data`, `title`, `fields` (array of `{ key, label, render? }`), `columns` (1 | 2), `headerAction`.
439
+ **Example:**
440
+
441
+ ```tsx
442
+ <DescriptionCard
443
+ title="Order details"
444
+ data={order}
445
+ columns={2}
446
+ fields={[
447
+ { key: "number", label: "Order number" },
448
+ { key: "status", label: "Status", render: (v) => <Badge>{v}</Badge> },
449
+ { key: "createdAt", label: "Created", render: formatDate },
450
+ ]}
451
+ />
452
+ ```
453
+
454
+ **Used in patterns:** `detail/hero-with-actions` (body sections).
455
+
456
+ ### `ActionPanel`
457
+
458
+ **Import:** `import { ActionPanel } from '@tailor-platform/app-shell'`
459
+ **Purpose:** Right-rail panel listing workflow actions for a detail page (approve, reject, archive, etc.).
460
+ **API:** `ActionPanelProps` — `title`, `actions` (array of `{ label, onSelect, variant?, disabled?, hidden? }`), `className`.
461
+ **Example:**
462
+
463
+ ```tsx
464
+ <ActionPanel
465
+ title="Actions"
466
+ actions={[
467
+ { label: "Approve", variant: "default", onSelect: handleApprove },
468
+ { label: "Reject", variant: "destructive", onSelect: handleReject, disabled: !canReject },
469
+ ]}
470
+ />
471
+ ```
472
+
473
+ **Used in patterns:** `detail/hero-with-actions`.
474
+
475
+ **Notes:**
476
+
477
+ - **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.
478
+
479
+ ### `ActivityCard`
480
+
481
+ **Import:** `import { ActivityCard } from '@tailor-platform/app-shell'`
482
+ **Purpose:** Timeline of events on a record (audit log, status changes, comments).
483
+ **API:** Compound — `ActivityCard.Root`, `ActivityCard.Items` (generic over item type), plus `ActivityCardProps`, `ActivityCardItem`, `ActivityCardItemProps`. Items render with timestamp + actor + description.
484
+ **Used in patterns:** `detail/hero-with-actions` (right column or bottom section).
485
+
486
+ ---
487
+
488
+ ## Forms
489
+
490
+ ### `Form`
491
+
492
+ > 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)
493
+
494
+ **Import:** `import { Form } from '@tailor-platform/app-shell'`
495
+ **Purpose:** Form root wired to react-hook-form. Use with `Field`, `Fieldset`, and Zod for validation.
496
+ **API:** `FormProps` — `errors`, `actionsRef`, `validationMode`, `noValidate`, plus a namespace exposing form-related sub-helpers. Generic over `FormValues`.
497
+ **Example:** see `form/single-page.md`.
498
+ **Used in patterns:** all `form/*`.
499
+
500
+ ### `Field`
501
+
502
+ **Import:** `import { Field } from '@tailor-platform/app-shell'`
503
+ **Purpose:** Single form field with label + control + error message wiring.
504
+ **API:** Compound. Wraps any input control (`Input`, `Select`, `Combobox`, etc.) and binds it to react-hook-form via `name`.
505
+ **Used in patterns:** all `form/*`.
506
+
507
+ ### `Fieldset`
508
+
509
+ **Import:** `import { Fieldset } from '@tailor-platform/app-shell'`
510
+ **Purpose:** Group related fields under a legend (subtle section header).
511
+ **API:** Compound — `Fieldset.Root`, `Fieldset.Legend`.
512
+ **Used in patterns:** `form/sectioned`, `form/wizard`.
513
+
514
+ ### `Input`
515
+
516
+ **Import:** `import { Input } from '@tailor-platform/app-shell'`
517
+ **Purpose:** Text input. Maps to spec field types: `string`, `email`, `number`, `password`, `tel`, `url`.
518
+ **API:** `InputProps` — extends native `<input>` props.
519
+ **Used in patterns:** all `form/*`.
520
+
521
+ ### `Select`
522
+
523
+ **Import:** `import { Select } from '@tailor-platform/app-shell'`
524
+ **Purpose:** Dropdown for fixed enumerations.
525
+ **API:** Compound. Sync version (small option lists). For async/typeahead, see `Combobox` and `Autocomplete`. Type: `SelectAsyncFetcher<T>` for the async variant.
526
+ **Used in patterns:** all `form/*` (enum fields).
527
+
528
+ ### `Combobox`
529
+
530
+ **Import:** `import { Combobox } from '@tailor-platform/app-shell'`
531
+ **Purpose:** Single-select with search, supports async data fetching.
532
+ **API:** Compound. `ComboboxAsyncFetcher<T>` for paginated/queried option sources (e.g. lookups).
533
+ **Used in patterns:** `form/*` (foreign-key lookups).
534
+
535
+ ### `Autocomplete`
536
+
537
+ **Import:** `import { Autocomplete } from '@tailor-platform/app-shell'`
538
+ **Purpose:** Free-text input with completion suggestions (multi-select capable).
539
+ **API:** Compound. `AutocompleteAsyncFetcher<T>` for async suggestion sources. `ItemGroup<T>` for grouped suggestions.
540
+ **Used in patterns:** `form/*` (tags, free-text + suggested values).
541
+
542
+ ---
543
+
544
+ ## Auth & access
545
+
546
+ ### `AuthProvider`
547
+
548
+ **Import:** `import { AuthProvider } from '@tailor-platform/app-shell'`
549
+ **Purpose:** Wraps the app to expose auth state via `useAuth`. Mount in `App.tsx`.
550
+ **API:** `AuthProviderProps` — `client` (from `createAuthClient`), `autoLogin`, `guardComponent`.
551
+ **Used in patterns:** project-level. See `project-setup.md`.
552
+
553
+ ### `createAuthClient`
554
+
555
+ **Import:** `import { createAuthClient, type EnhancedAuthClient } from '@tailor-platform/app-shell'`
556
+ **Purpose:** Factory for the auth client, configured with platform URL + client ID.
557
+ **API:** `createAuthClient(config: AuthClientConfig): EnhancedAuthClient`.
558
+ **Used in patterns:** project-level.
559
+
560
+ ### `useAuth`, `useAuthSuspense`
561
+
562
+ **Import:** `import { useAuth, useAuthSuspense } from '@tailor-platform/app-shell'`
563
+ **Purpose:** Read auth state in components. `useAuth` returns nullable state; `useAuthSuspense` suspends until ready (use inside route loaders / suspense boundaries).
564
+ **API:** Returns `AuthState` (user, status, login/logout actions).
565
+ **Used in patterns:** any pattern needing user identity.
566
+
567
+ ### `AuthClient` (type)
568
+
569
+ **Import:** `import { type AuthClient } from '@tailor-platform/app-shell'`
570
+ **Purpose:** Public auth client interface (re-exported from `@tailor-platform/auth-public-client`).
571
+
572
+ ### `WithGuard`
573
+
574
+ **Import:** `import { WithGuard } from '@tailor-platform/app-shell'`
575
+ **Purpose:** Permission gate around a UI subtree. Hides, denies, or shows a loading state based on the guard result.
576
+ **API:** `WithGuardProps` — `guard: Guard`, `fallback`, `mode: 'hidden' | 'deny'`.
577
+ **Used in patterns:** `detail/*` (action gating), `list/*` (row-level action visibility).
578
+
579
+ ### Guard helpers — `pass`, `hidden`, `redirectTo`
580
+
581
+ **Import:** `import { pass, hidden, redirectTo } from '@tailor-platform/app-shell'`
582
+ **Purpose:** Return values for guard functions. `pass()` allows, `hidden()` hides, `redirectTo(path)` navigates.
583
+ **Used in patterns:** any `Guard` definition.
584
+
585
+ ### `Guard`, `GuardContext`, `GuardResult` (types)
586
+
587
+ Types for authoring guard functions used by `WithGuard` and `appShellPageProps.guards`.
588
+
589
+ ---
590
+
591
+ ## Routing helpers
592
+
593
+ ### `useNavigate`, `useParams`, `useSearchParams`, `useLocation`, `useRouteError`
594
+
595
+ **Import:** `import { useNavigate, useParams, useSearchParams, useLocation, useRouteError } from '@tailor-platform/app-shell'`
596
+ **Purpose:** Re-exported from `react-router`. Use the AppShell barrel — never import from `react-router` directly.
597
+ **Used in patterns:** all (navigation, route params, query state).
598
+
599
+ ### `createTypedPaths`
600
+
601
+ **Import:** `import { createTypedPaths } from '@tailor-platform/app-shell'`
602
+ **Purpose:** Type-safe path builder generated from the route tree.
603
+ **API:** `createTypedPaths<TRoutes>()` returns a `paths.for(...)` helper.
604
+ **Used in patterns:** project-level. See `project-setup.md`.
605
+
606
+ ### `RouteParams`, `PageComponent`, `PageMeta`, `AppShellPageProps`, `AppShellRegister`, `ContextData` (types)
607
+
608
+ Types for declaring page props (`appShellPageProps = { meta, guards, loader }`), reading typed route params, and registering route types globally. See `project-setup.md` for usage.
609
+
610
+ ---
611
+
612
+ ## Hooks
613
+
614
+ ### `useToast`
615
+
616
+ **Import:** `import { useToast } from '@tailor-platform/app-shell'`
617
+ **Purpose:** Imperative toast feedback after mutations.
618
+ **API:** Returns the `sonner` `toast` function — `toast.success(message)`, `toast.error(message)`, `toast.loading(message)`, plus options for duration, action button, etc.
619
+ **Used in patterns:** `interaction/toast`. Called from any mutation handler.
620
+
621
+ ### `useTheme`
622
+
623
+ **Import:** `import { useTheme } from '@tailor-platform/app-shell'`
624
+ **Purpose:** Read/write the active theme (light/dark/system).
625
+ **API:** Returns `ThemeProviderState`.
626
+ **Used in patterns:** any theme-toggle UI.
627
+
628
+ ### `useAppShell`, `useAppShellConfig`, `useAppShellData`
629
+
630
+ **Import:** `import { useAppShell, useAppShellConfig, useAppShellData } from '@tailor-platform/app-shell'`
631
+ **Purpose:** Access AppShell context — the resolved `AppShellRegister` data, config, and runtime state.
632
+ **Used in patterns:** advanced — when a component needs to read app-wide config or registered resources.
633
+
634
+ ### `usePageMeta`, `useOverrideBreadcrumb`
635
+
636
+ **Import:** `import { usePageMeta, useOverrideBreadcrumb } from '@tailor-platform/app-shell'`
637
+ **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).
638
+ **Used in patterns:** `detail/*` (dynamic breadcrumbs from loaded entity).
639
+
640
+ ---
641
+
642
+ ## i18n & resource definitions
643
+
644
+ ### `defineI18nLabels`
645
+
646
+ **Import:** `import { defineI18nLabels } from '@tailor-platform/app-shell'`
647
+ **Purpose:** Declare i18n labels in a typed way. Returns `I18nLabels<Def, L>`.
648
+ **Used in patterns:** project-level for multi-locale apps.
649
+
650
+ ### `defineModule`, `defineResource`
651
+
652
+ **Import:** `import { defineModule, defineResource } from '@tailor-platform/app-shell'`
653
+ **Purpose:** Register an app module / a resource (entity with CRUD pages). Wires routes, sidebar, and command palette automatically.
654
+ **API:** `defineModule(props: DefineModuleProps): Module`, `defineResource(props: DefineResourceProps): Resource`.
655
+ **Used in patterns:** project-level. See `project-setup.md`.
656
+
657
+ ### `MappedItem`, `Module`, `Resource`, `ResourceComponentProps` (types)
658
+
659
+ Types returned/consumed by the define-\* helpers above.
660
+
661
+ ---
662
+
663
+ ## Style helpers
664
+
665
+ ### `avatarVariants`, `badgeVariants`, `buttonVariants`
666
+
667
+ **Import:** `import { avatarVariants, badgeVariants, buttonVariants } from '@tailor-platform/app-shell'`
668
+ **Purpose:** CVA (`class-variance-authority`) variant functions backing `Avatar`, `Badge`, `Button`. Use when authoring a custom component that should match an AppShell variant inline.
669
+ **Used in patterns:** custom-component fallbacks (see `design-system.md` § "When AppShell doesn't have a component you need").
670
+
671
+ ### `ErrorBoundaryComponent` (type)
672
+
673
+ **Import:** `import { type ErrorBoundaryComponent } from '@tailor-platform/app-shell'`
674
+ **Purpose:** Type for an error boundary component slot in routing.
675
+
676
+ ---
677
+
678
+ ## Keeping this file in sync
679
+
680
+ When `@tailor-platform/app-shell` publishes a new version:
681
+
682
+ 1. Bump `package.json` in the scaffold templates (`templates/scaffold/app/*/frontend/`) to the new version.
683
+ 2. Update the AppShell version header at the top of this file.
684
+ 3. Diff exports between old and new:
685
+
686
+ ```bash
687
+ # Run in a scratch dir:
688
+ mkdir -p /tmp/appshell-diff && cd /tmp/appshell-diff
689
+ npm init -y >/dev/null && npm install --no-save --silent @tailor-platform/app-shell@<NEW_VERSION>
690
+ node -e "console.log(Object.keys(require('@tailor-platform/app-shell')).sort().join('\n'))" \
691
+ > new-exports.txt
692
+ # Compare against the headings in this file:
693
+ grep -E '^### ' \
694
+ packages/erp-kit/skills/erp-kit-app-6-impl-frontend/references/components.md \
695
+ | sed 's/^### //; s/ ,.*//' | sort > current-headings.txt
696
+ diff current-headings.txt new-exports.txt
697
+ ```
698
+
699
+ 4. For each new export — add a section using the fixed shape above.
700
+ 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.
701
+ 6. For each changed export (new prop, behavior change) — update the section and add a one-line note under "Notes:".
702
+ 7. Run `pnpm erp-kit update skills` to regenerate `.agents/skills/`.
703
+
704
+ 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.