@tailor-platform/app-shell 1.14.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/LICENSE.md +21 -0
  2. package/dist/app-shell-core.css +1 -1
  3. package/dist/app-shell.d.ts +1203 -316
  4. package/dist/app-shell.js +4562 -3307
  5. package/dist/{appshell-CtS8Y3LW.js → appshell-B0wh5Lq0.js} +850 -549
  6. package/dist/style-entry.d.ts +118 -98
  7. package/dist/testing.d.ts +118 -98
  8. package/dist/testing.js +1 -1
  9. package/dist/themes/_template.css +1 -1
  10. package/dist/vite-plugin.d.ts +118 -98
  11. package/package.json +13 -13
  12. package/skills/app-shell-patterns/SKILL.md +108 -24
  13. package/skills/app-shell-patterns/references/api/create-ai-gateway-client.md +115 -0
  14. package/skills/app-shell-patterns/references/api/create-typed-paths.md +117 -0
  15. package/skills/app-shell-patterns/references/api/define-i18n-labels.md +143 -0
  16. package/skills/app-shell-patterns/references/api/define-module.md +247 -0
  17. package/skills/app-shell-patterns/references/api/define-resource.md +307 -0
  18. package/skills/app-shell-patterns/references/api/guards/hidden.md +202 -0
  19. package/skills/app-shell-patterns/references/api/guards/overview.md +354 -0
  20. package/skills/app-shell-patterns/references/api/guards/pass.md +129 -0
  21. package/skills/app-shell-patterns/references/api/guards/redirect-to.md +307 -0
  22. package/skills/app-shell-patterns/references/api/router/use-location.md +240 -0
  23. package/skills/app-shell-patterns/references/api/router/use-navigate.md +138 -0
  24. package/skills/app-shell-patterns/references/api/router/use-params.md +218 -0
  25. package/skills/app-shell-patterns/references/api/use-ai-chat.md +110 -0
  26. package/skills/app-shell-patterns/references/api/use-app-shell-config.md +126 -0
  27. package/skills/app-shell-patterns/references/api/use-app-shell-data.md +146 -0
  28. package/skills/app-shell-patterns/references/api/use-app-shell.md +143 -0
  29. package/skills/app-shell-patterns/references/api/use-auth.md +145 -0
  30. package/skills/app-shell-patterns/references/api/use-override-breadcrumb.md +74 -0
  31. package/skills/app-shell-patterns/references/api/use-page-meta.md +96 -0
  32. package/skills/app-shell-patterns/references/api/use-register-command-palette-actions.md +90 -0
  33. package/skills/app-shell-patterns/references/api/use-resolved-locale.md +67 -0
  34. package/skills/app-shell-patterns/references/api/use-route-error.md +214 -0
  35. package/skills/app-shell-patterns/references/api/use-theme.md +108 -0
  36. package/skills/app-shell-patterns/references/api/use-time-zone.md +80 -0
  37. package/skills/app-shell-patterns/references/api/use-toast.md +107 -0
  38. package/skills/app-shell-patterns/references/components/action-panel.md +168 -0
  39. package/skills/app-shell-patterns/references/components/activity-card.md +142 -0
  40. package/skills/app-shell-patterns/references/components/ai-chat.md +315 -0
  41. package/skills/app-shell-patterns/references/components/alert.md +202 -0
  42. package/skills/app-shell-patterns/references/components/app-shell.md +530 -0
  43. package/skills/app-shell-patterns/references/components/appearance-switcher.md +87 -0
  44. package/skills/app-shell-patterns/references/components/attachment.md +138 -0
  45. package/skills/app-shell-patterns/references/components/autocomplete.md +278 -0
  46. package/skills/app-shell-patterns/references/components/avatar.md +80 -0
  47. package/skills/app-shell-patterns/references/components/badge.md +309 -0
  48. package/skills/app-shell-patterns/references/components/button.md +164 -0
  49. package/skills/app-shell-patterns/references/components/card.md +109 -0
  50. package/skills/app-shell-patterns/references/components/checkbox.md +169 -0
  51. package/skills/app-shell-patterns/references/components/combobox.md +318 -0
  52. package/skills/app-shell-patterns/references/components/command-palette.md +413 -0
  53. package/skills/app-shell-patterns/references/components/csv-importer.md +214 -0
  54. package/skills/app-shell-patterns/references/components/data-table.md +953 -0
  55. package/skills/app-shell-patterns/references/components/date-picker.md +248 -0
  56. package/skills/app-shell-patterns/references/components/default-header.md +75 -0
  57. package/skills/app-shell-patterns/references/components/default-sidebar.md +136 -0
  58. package/skills/app-shell-patterns/references/components/description-card.md +569 -0
  59. package/skills/app-shell-patterns/references/components/dialog.md +164 -0
  60. package/skills/app-shell-patterns/references/components/document-progress-card.md +154 -0
  61. package/skills/app-shell-patterns/references/components/form.md +378 -0
  62. package/skills/app-shell-patterns/references/components/global-header-layout.md +132 -0
  63. package/skills/app-shell-patterns/references/components/grid.md +184 -0
  64. package/skills/app-shell-patterns/references/components/input.md +83 -0
  65. package/skills/app-shell-patterns/references/components/layout.md +539 -0
  66. package/skills/app-shell-patterns/references/components/menu.md +218 -0
  67. package/skills/app-shell-patterns/references/components/metric-card.md +94 -0
  68. package/skills/app-shell-patterns/references/components/select.md +283 -0
  69. package/skills/app-shell-patterns/references/components/sheet.md +237 -0
  70. package/skills/app-shell-patterns/references/components/sidebar-group.md +466 -0
  71. package/skills/app-shell-patterns/references/components/sidebar-item.md +458 -0
  72. package/skills/app-shell-patterns/references/components/sidebar-layout.md +258 -0
  73. package/skills/app-shell-patterns/references/components/spinner.md +81 -0
  74. package/skills/app-shell-patterns/references/components/table.md +188 -0
  75. package/skills/app-shell-patterns/references/components/tabs.md +158 -0
  76. package/skills/app-shell-patterns/references/components/textarea.md +122 -0
  77. package/skills/app-shell-patterns/references/components/timeline.md +317 -0
  78. package/skills/app-shell-patterns/references/components/toolbar.md +138 -0
  79. package/skills/app-shell-patterns/references/components/tooltip.md +144 -0
  80. package/skills/app-shell-patterns/references/components/with-guard.md +445 -0
  81. package/skills/app-shell-patterns/references/concepts/authentication.md +301 -0
  82. package/skills/app-shell-patterns/references/concepts/custom-components.md +59 -0
  83. package/skills/app-shell-patterns/references/concepts/file-based-routing.md +350 -0
  84. package/skills/app-shell-patterns/references/{fundamental → concepts}/graphql.md +11 -4
  85. package/skills/app-shell-patterns/references/concepts/modules-and-resources.md +229 -0
  86. package/skills/app-shell-patterns/references/concepts/routing-navigation.md +387 -0
  87. package/skills/app-shell-patterns/references/concepts/sidebar-navigation.md +388 -0
  88. package/skills/app-shell-patterns/references/{fundamental/design-system.md → concepts/styling-theming.md} +260 -105
  89. package/skills/app-shell-patterns/references/migrations.md +34 -0
  90. package/skills/app-shell-patterns/references/pages/document-detail.md +1125 -0
  91. package/skills/app-shell-patterns/references/patterns/form-composer.md +44 -46
  92. package/skills/app-shell-patterns/references/patterns/form-modal.md +39 -100
  93. package/skills/app-shell-patterns/references/patterns/form-sectioned.md +12 -38
  94. package/skills/app-shell-patterns/references/patterns/form-single-page.md +11 -32
  95. package/skills/app-shell-patterns/references/patterns/form-wizard.md +12 -53
  96. package/skills/app-shell-patterns/references/patterns/interaction-confirm.md +11 -27
  97. package/skills/app-shell-patterns/references/patterns/interaction-multi-select.md +14 -28
  98. package/skills/app-shell-patterns/references/patterns/interaction-toast.md +10 -34
  99. package/skills/app-shell-patterns/references/patterns/list-dense-scan.md +11 -86
  100. package/skills/app-shell-patterns/references/fundamental/components.md +0 -981
  101. package/skills/app-shell-patterns/references/patterns/detail-hero-with-actions.md +0 -201
@@ -0,0 +1,142 @@
1
+ ---
2
+ title: ActivityCard
3
+ description: Timeline of recent document activities with avatars and overflow dialog
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/components/activity-card.docs.outline.md — do not edit by hand. -->
7
+
8
+ # ActivityCard
9
+
10
+ The `ActivityCard` component displays a timeline of recent activities (e.g. changes on a PO, SO, or GR document). Each entry shows an avatar, user name, description, and timestamp. A limited number of activities are shown in the card; additional activities are available via a clickable overflow that opens a dialog with a scrollable full list.
11
+
12
+ ## Import
13
+
14
+ ```tsx
15
+ import {
16
+ ActivityCard,
17
+ type ActivityCardItem,
18
+ type ActivityCardBaseItem,
19
+ type ActivityCardProps,
20
+ } from "@tailor-platform/app-shell";
21
+ ```
22
+
23
+ Use `ActivityCardItem` for each item in the standalone API. Use `ActivityCardBaseItem` as the minimum constraint when extending items for the compound API.
24
+
25
+ ## Basic Usage
26
+
27
+ <example-preview name="basic-usage"></example-preview>
28
+
29
+ ```tsx
30
+ function BasicUsage() {
31
+ return <ActivityCard items={items} title="Updates" />;
32
+ }
33
+ ```
34
+
35
+ ## Overflow and dialog
36
+
37
+ By default the card shows the 6 most recent activities. If there are more, a button appears at the bottom (e.g. **"2 more activities"**). Clicking it opens a modal dialog titled "All activities" with the full list in a scrollable area. The overflow label can be switched to a count style (**"+2"**) via the `overflowLabel` prop.
38
+
39
+ ```tsx
40
+ <ActivityCard items={manyItems} title="Updates" maxVisible={6} overflowLabel="more" />
41
+ // or overflowLabel="count" for "+N"
42
+ ```
43
+
44
+ ## Grouping by day
45
+
46
+ Set `groupBy="day"` to group activities under labels like "TODAY", "YESTERDAY", or a formatted date.
47
+
48
+ ```tsx
49
+ <ActivityCard items={items} title="Updates" groupBy="day" />
50
+ ```
51
+
52
+ ## Props
53
+
54
+ | Prop | Type | Default | Description |
55
+ | --------------- | -------------------- | -------- | ------------------------------------------------- |
56
+ | `items` | `ActivityCardItem[]` | required | List of items (newest first). |
57
+ | `title` | `string` | - | Card title, e.g. "Updates". |
58
+ | `maxVisible` | `number` | `6` | Max activities shown in the card before overflow. |
59
+ | `overflowLabel` | `"more" \| "count"` | `"more"` | "N more activities" vs "+N". |
60
+ | `groupBy` | `"none" \| "day"` | `"none"` | Optional grouping by day. |
61
+ | `className` | `string` | - | Applied to the card root. |
62
+
63
+ Each activity must include: `id`, `description`, `timestamp` (Date or string). Optional: `actor` (`{ name, avatarUrl? }`) — omit for system events with no specific actor (initials fallback when `avatarUrl` is absent).
64
+
65
+ ---
66
+
67
+ ## Compound API
68
+
69
+ Use the compound API when you need fully custom item rendering — custom icons, links, badges, or mixed item kinds. Items still must satisfy `ActivityCardBaseItem` (`id` + `timestamp`). You extend `ActivityCardBaseItem` with any additional fields you need.
70
+
71
+ ### Import
72
+
73
+ ```tsx
74
+ import { ActivityCard, type ActivityCardBaseItem } from "@tailor-platform/app-shell";
75
+ ```
76
+
77
+ ### Parts
78
+
79
+ | Part | Description |
80
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
81
+ | `ActivityCard.Root` | Outer card container. Accepts the same `items`, `title`, `maxVisible`, `overflowLabel`, `groupBy` props as the standalone API, plus `children`. |
82
+ | `ActivityCard.Items` | Iterates over items and renders each via a render-prop children function. Generic over your item type. |
83
+ | `ActivityCard.Item` | A single row in the timeline. Accepts an optional `indicator` (any `ReactNode`) for the left column. |
84
+
85
+ ### ActivityCard.Root Props
86
+
87
+ | Prop | Type | Default | Description |
88
+ | --------------- | ------------------- | -------- | --------------------------------------------------------------------- |
89
+ | `items` | `T[]` | required | List of items (newest first). `T` must extend `ActivityCardBaseItem`. |
90
+ | `title` | `string` | - | Card title, e.g. "Updates". |
91
+ | `maxVisible` | `number` | `6` | Max items shown in the card before overflow. |
92
+ | `overflowLabel` | `"more" \| "count"` | `"more"` | "N more activities" vs "+N". |
93
+ | `groupBy` | `"none" \| "day"` | `"none"` | Optional grouping by day. |
94
+ | `className` | `string` | - | Applied to the card root. |
95
+ | `children` | `React.ReactNode` | required | Must contain `ActivityCard.Items`. |
96
+
97
+ ### ActivityCard.Item Props
98
+
99
+ | Prop | Type | Default | Description |
100
+ | ----------- | ----------------- | ------- | ------------------------------------------------------------------------------------------ |
101
+ | `indicator` | `React.ReactNode` | - | Element rendered in the left column (e.g. Avatar, icon). Omit for a default timeline node. |
102
+ | `children` | `React.ReactNode` | - | Content for the item row (text, badges, links, etc.). |
103
+ | `className` | `string` | - | Additional CSS classes. |
104
+
105
+ ### Example
106
+
107
+ ```tsx
108
+ import { ActivityCard, type ActivityCardBaseItem } from "@tailor-platform/app-shell";
109
+
110
+ interface MyItem extends ActivityCardBaseItem {
111
+ kind: "approval" | "update";
112
+ label?: string;
113
+ message?: string;
114
+ }
115
+
116
+ const items: MyItem[] = [
117
+ { id: "1", timestamp: new Date(), kind: "approval", label: "PO approved" },
118
+ { id: "2", timestamp: new Date(), kind: "update", message: "Status changed to CONFIRMED" },
119
+ ];
120
+
121
+ <ActivityCard.Root items={items} title="Updates" groupBy="day">
122
+ <ActivityCard.Items<MyItem>>
123
+ {(item) =>
124
+ item.kind === "approval" ? (
125
+ <ActivityCard.Item indicator={<ApprovedIcon />}>
126
+ <p>{item.label}</p>
127
+ </ActivityCard.Item>
128
+ ) : (
129
+ <ActivityCard.Item>
130
+ <p>{item.message}</p>
131
+ </ActivityCard.Item>
132
+ )
133
+ }
134
+ </ActivityCard.Items>
135
+ </ActivityCard.Root>;
136
+ ```
137
+
138
+ ---
139
+
140
+ ## See also
141
+
142
+ - [Avatar](./avatar.md) — underlying avatar primitive used for profile images and initials
@@ -0,0 +1,315 @@
1
+ ---
2
+ title: AIChat
3
+ description: Building blocks for an LLM assistant UI — a streaming conversation view over a composer, plus reasoning, tool-call, and citation parts
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/components/ai-chat.docs.outline.md — do not edit by hand. -->
7
+
8
+ # AIChat
9
+
10
+ `AIChat` owns the frame for an assistant UI and places its three regions in a fixed order, the way [`Layout`](./layout.md) places `Layout.Header` and `Layout.Column`: **`AIChat.Header`** (optional) over **`AIChat.Conversation`** (required) over **`AIChat.Composer`** (optional). Each region carries its own props; the root carries only the chat's `status`. You compose the transcript inside `AIChat.Conversation` from the attached parts — `AIChat.Message`, `AIChat.Response`, `AIChat.Reasoning`, `AIChat.Tool`, `AIChat.Sources`, and more — against your own [`useAIChat()`](../api/use-ai-chat.md) state.
11
+
12
+ It renders no border or background of its own. Wrap it in [`Card`](./card.md), [`Sheet`](./sheet.md), or a `Layout.Column` for the surrounding surface.
13
+
14
+ ## Import
15
+
16
+ ```tsx
17
+ import { AIChat, useAIChat, createAIGatewayClient } from "@tailor-platform/app-shell";
18
+ ```
19
+
20
+ ## Basic usage
21
+
22
+ ```tsx
23
+ function Assistant() {
24
+ const client = useMemo(() => createAIGatewayClient({ gatewayUri, authClient }), [authClient]);
25
+ const { messages, status, sendMessage, stop } = useAIChat({ client, model: "gpt-5" });
26
+
27
+ return (
28
+ // `overflow-hidden` keeps the header rule inside the card's rounded corners.
29
+ <Card.Root className="flex h-full flex-col overflow-hidden">
30
+ <AIChat status={status}>
31
+ <AIChat.Header title="Assistant" />
32
+ <AIChat.Conversation>
33
+ {messages.length === 0 ? (
34
+ <AIChat.EmptyState title="Ask the assistant" />
35
+ ) : (
36
+ messages.map((message) => (
37
+ <AIChat.Message key={message.id} from={message.role}>
38
+ <AIChat.Response>{message.content}</AIChat.Response>
39
+ </AIChat.Message>
40
+ ))
41
+ )}
42
+ </AIChat.Conversation>
43
+ <AIChat.Composer onSubmit={sendMessage} onStop={stop} />
44
+ </AIChat>
45
+ </Card.Root>
46
+ );
47
+ }
48
+ ```
49
+
50
+ `message.role` ("user" | "assistant") from `useAIChat` lines up directly with `AIChat.Message`'s `from` prop — no mapping step. `AIChat` streams for real when the AI Gateway sends real SSE chunks; there is no client-side typewriter effect.
51
+
52
+ The regions can appear in any source order — the root always renders Header, then Conversation, then Composer. Omit `AIChat.Composer` for a read-only transcript.
53
+
54
+ They must be **direct** children. The root matches them by component identity, so a region wrapped in one of your own components — `const AppComposer = () => <AIChat.Composer … />` — is not recognised, and is dropped with a console warning like any other unexpected child. To preset props, export the props instead of the element: `<AIChat.Composer {...appComposerProps} />`.
55
+
56
+ ## Props
57
+
58
+ ### `AIChat`
59
+
60
+ | Prop | Type | Default | Description |
61
+ | ----------- | -------------------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------- |
62
+ | `children` | `ReactNode` | required | `AIChat.Header`, `AIChat.Conversation`, and `AIChat.Composer`, in any order. |
63
+ | `status` | `"ready" \| "submitted" \| "streaming" \| "error"` | `"ready"` | The chat's state. Plugs directly into `useAIChat()`'s `status`; `AIChat.Composer` reads it. |
64
+ | `className` | `string` | - | Merged onto the root. It already fills a block parent (`h-full`) or a flex-column parent (`flex-1`). |
65
+
66
+ Other props spread onto the root `<div>`.
67
+
68
+ ### `AIChat.Header`
69
+
70
+ | Prop | Type | Default | Description |
71
+ | ----------- | ----------- | ------- | ------------------------------------------------------------------------------------------------ |
72
+ | `title` | `ReactNode` | - | Title text. |
73
+ | `icon` | `ReactNode` | sparkle | Leading graphic. Pass `null` for none, or a control (e.g. a collapse button) for a docked panel. |
74
+ | `actions` | `ReactNode` | - | Right-aligned slot — compose it from `AIChat.Action`. |
75
+ | `className` | `string` | - | |
76
+
77
+ ### `AIChat.Conversation`
78
+
79
+ | Prop | Type | Default | Description |
80
+ | ------------ | ----------- | -------- | ------------------------------------------------------------------------------------- |
81
+ | `children` | `ReactNode` | required | The transcript. Composed from the attached parts, or `AIChat.EmptyState` while empty. |
82
+ | `autoScroll` | `boolean` | `true` | Follow content growth while the reader is pinned to the bottom. |
83
+ | `className` | `string` | - | |
84
+
85
+ Other props spread onto the region's outer `<div>`.
86
+
87
+ ### `AIChat.Composer`
88
+
89
+ | Prop | Type | Default | Description |
90
+ | --------------- | --------------------------- | -------- | -------------------------------------------------------------------------------- |
91
+ | `onSubmit` | `(message: string) => void` | required | Called with the trimmed prompt. |
92
+ | `onStop` | `() => void` | - | Called from the Stop button while the chat is busy. Omit for a plain busy state. |
93
+ | `value` | `string` | - | Controlled draft. Cleared via `onValueChange("")` after a successful submit. |
94
+ | `defaultValue` | `string` | `""` | Uncontrolled draft's initial value. |
95
+ | `onValueChange` | `(value: string) => void` | - | Called on every draft change, including the post-submit clear. |
96
+ | `placeholder` | `string` | - | |
97
+ | `disabled` | `boolean` | `false` | Disables the composer — not the transcript above it. |
98
+ | `submitOnEnter` | `boolean` | `true` | Enter submits (IME-safe); Shift+Enter always inserts a newline. |
99
+ | `actions` | `ReactNode` | - | Open slot on the action row — a visibility toggle, a model picker, a select. |
100
+ | `className` | `string` | - | |
101
+
102
+ ## Prop pass-through
103
+
104
+ Most props stay inside their region. These `AIChat.Composer` props land on **another AppShell component**, so they carry that component's contract — and any future change to it — rather than one `AIChat` defines:
105
+
106
+ | Prop | Reaches | Note |
107
+ | ------------- | ---------------------------------------------------------------------- | --------------------------------------- |
108
+ | `value` | [`Textarea`](./textarea.md) `value` | The composer body is a real `Textarea`. |
109
+ | `placeholder` | [`Textarea`](./textarea.md) `placeholder` | |
110
+ | `disabled` | [`Textarea`](./textarea.md) **and** the attach [`Button`](./button.md) | One prop, two components. |
111
+ | `onStop` | [`Button`](./button.md) `onClick` | Becomes the Stop button's handler. |
112
+
113
+ `onValueChange` is wrapped rather than forwarded — it is called from the `Textarea`'s `onChange`, and again with `""` after a submit. `defaultValue` seeds the composer's own state and is never forwarded. Nothing on `AIChat`, `AIChat.Header`, or `AIChat.Conversation` reaches another AppShell component.
114
+
115
+ Three attached parts wrap an AppShell component. They expose only the props the part's job needs rather than inheriting the wrapped component's surface, so its visual treatment is fixed and not yours to change:
116
+
117
+ | Part | Wraps | Accepts | Fixed |
118
+ | ----------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------- | ---------------------------------- |
119
+ | `AIChat.Suggestion` | [`Button`](./button.md) | `suggestion`, `onSelect`, `className`, `disabled`, `children` | `variant="secondary"`, `size="sm"` |
120
+ | `AIChat.Action` | [`Button`](./button.md) inside a [`Tooltip`](./tooltip.md) | `label`, `onClick`, `className`, `disabled`, `children` | `variant="ghost"`, `size="icon"` |
121
+ | `AIChat.ChainOfThoughtSearchResult` | [`Badge`](./badge.md) | `className`, `children`, `variant` | — |
122
+
123
+ `variant` stays open on `ChainOfThoughtSearchResult` because conveying status is what a `Badge` is for. `AIChat.Action`'s `label` becomes both the accessible name and the tooltip text.
124
+
125
+ One thing to know about `className` on these: it is merged with `cn()`, which is not configured for AppShell's internal prefix, so it cannot reliably override a base utility from the wrapped component. Add properties the component doesn't set, and reach for the wrapped component's own props or variants to change ones it does — see [Styling AppShell components](../concepts/styling-theming.md#styling-appshell-components).
126
+
127
+ ## Filling the page
128
+
129
+ `AIChat` fills whatever height its parent gives it — `h-full` for a block parent, `flex-1 min-h-0` for a flex column — and never grows the page: the transcript scrolls internally while the header and composer stay pinned. Give the surface around it a definite height.
130
+
131
+ Inside a `<Layout fill>` column (the column is `flex flex-col`, so the card takes the leftover space):
132
+
133
+ ```tsx
134
+ <Layout fill>
135
+ <Layout.Header title="Assistant" />
136
+ <Layout.Column>
137
+ <Card.Root className="flex min-h-0 flex-1 flex-col overflow-hidden">
138
+ <AIChat status={status}>
139
+ <AIChat.Header title="Assistant" />
140
+ <AIChat.Conversation>{/* … */}</AIChat.Conversation>
141
+ <AIChat.Composer onSubmit={sendMessage} />
142
+ </AIChat>
143
+ </Card.Root>
144
+ </Layout.Column>
145
+ </Layout>
146
+ ```
147
+
148
+ `min-h-0` is what lets the card shrink below its content's natural height so the transcript scrolls instead of pushing the composer off-screen. In a docked panel or `Sheet` whose height is already fixed, `h-full` on the card is enough.
149
+
150
+ ## Header
151
+
152
+ A 48px strip above the transcript: leading graphic, title, and an open action slot on the right, closed by a rule that runs the full width of the surface. Omit it for a bare transcript-and-composer surface, and give the card `overflow-hidden` so the rule stays inside its rounded corners.
153
+
154
+ ```tsx
155
+ <AIChat.Header
156
+ title="Assistant"
157
+ actions={
158
+ <>
159
+ <AIChat.Action label="Conversation history" onClick={openHistory}>
160
+ <History className="size-3.5" aria-hidden />
161
+ </AIChat.Action>
162
+ <AIChat.Action label="Clear conversation" onClick={clear}>
163
+ <Eraser className="size-3.5" aria-hidden />
164
+ </AIChat.Action>
165
+ </>
166
+ }
167
+ />
168
+ ```
169
+
170
+ For a docked right panel, put the collapse control in `icon` so it takes the leading position:
171
+
172
+ ```tsx
173
+ <AIChat.Header
174
+ title="Assistant"
175
+ icon={
176
+ <AIChat.Action label="Collapse panel" onClick={onClose}>
177
+ <ChevronsRight className="size-3.5" aria-hidden />
178
+ </AIChat.Action>
179
+ }
180
+ />
181
+ ```
182
+
183
+ ## Attached parts
184
+
185
+ ### Message
186
+
187
+ ```tsx
188
+ <AIChat.Message from="assistant">
189
+ <AIChat.Response>{message.content}</AIChat.Response>
190
+ </AIChat.Message>
191
+ ```
192
+
193
+ User turns render as a right-aligned primary bubble; assistant turns take the full width with no bubble, so reasoning, tool calls, and citations stack inside the same column above the response text.
194
+
195
+ ### Response
196
+
197
+ Renders the markdown subset a streamed LLM response actually emits — bold, inline code, links, headings, bullet/numbered lists — without a markdown dependency. Only `http(s):`, `mailto:`, and same-site relative links render as clickable; any other target renders as plain text, since the text passing through here is untrusted model output. For full CommonMark, swap `<AIChat.Response>` for `react-markdown` or the AI SDK's `streamdown` — call sites keep the same shape.
198
+
199
+ ```tsx
200
+ <AIChat.Response>{message.content}</AIChat.Response>
201
+ ```
202
+
203
+ ### EmptyState / Suggestions
204
+
205
+ `AIChat.EmptyState` stacks `icon`, then the `title`/`description` block, then `children` — so starter suggestions sit alongside the text rather than replacing it:
206
+
207
+ ```tsx
208
+ <AIChat.EmptyState
209
+ icon={<Sparkles className="size-6 text-primary" aria-hidden />}
210
+ title="Ask the assistant"
211
+ description="Grounded in your help articles."
212
+ >
213
+ <AIChat.Suggestions>
214
+ <AIChat.Suggestion suggestion="How do I create a purchase order?" onSelect={sendMessage} />
215
+ </AIChat.Suggestions>
216
+ </AIChat.EmptyState>
217
+ ```
218
+
219
+ `AIChat.Suggestion` submits its `suggestion` text as if the reader had typed and sent it via `onSelect`.
220
+
221
+ ### Actions
222
+
223
+ Icon-button row under a finished assistant turn — copy, retry, feedback. Render it only once the turn has finished so streaming turns stay uncluttered.
224
+
225
+ ```tsx
226
+ <AIChat.Actions>
227
+ <AIChat.Action label="Copy" onClick={() => navigator.clipboard.writeText(message.content)}>
228
+ <Copy className="size-3.5" aria-hidden />
229
+ </AIChat.Action>
230
+ </AIChat.Actions>
231
+ ```
232
+
233
+ ### Reasoning
234
+
235
+ Collapsible "thinking" block for reasoning models. Auto-opens while `isStreaming` is true and auto-closes when it turns false, unless the reader has manually toggled it.
236
+
237
+ ```tsx
238
+ <AIChat.Reasoning isStreaming={reasoning.streaming} duration={reasoning.duration}>
239
+ <AIChat.ReasoningTrigger />
240
+ <AIChat.ReasoningContent>{reasoning.text}</AIChat.ReasoningContent>
241
+ </AIChat.Reasoning>
242
+ ```
243
+
244
+ ### ChainOfThought
245
+
246
+ Structured step timeline for agentic turns — the discrete plan being executed, each step with a status and optional result chips. Use `Reasoning` for free-form thinking text and this for multi-step tool plans.
247
+
248
+ ```tsx
249
+ <AIChat.ChainOfThought defaultOpen>
250
+ <AIChat.ChainOfThoughtHeader />
251
+ <AIChat.ChainOfThoughtContent>
252
+ <AIChat.ChainOfThoughtStep label="Searching the knowledge base" status="complete">
253
+ <AIChat.ChainOfThoughtSearchResults>
254
+ <AIChat.ChainOfThoughtSearchResult>12 hits</AIChat.ChainOfThoughtSearchResult>
255
+ </AIChat.ChainOfThoughtSearchResults>
256
+ </AIChat.ChainOfThoughtStep>
257
+ <AIChat.ChainOfThoughtStep label="Drafting the answer" status="active" />
258
+ </AIChat.ChainOfThoughtContent>
259
+ </AIChat.ChainOfThought>
260
+ ```
261
+
262
+ `status` is `"complete" | "active" | "pending"`.
263
+
264
+ ### Tool
265
+
266
+ Collapsible tool-call card. Maps 1:1 to the AI SDK's tool-part lifecycle, so a streaming loop can update a call in place as parts arrive.
267
+
268
+ ```tsx
269
+ <AIChat.Tool>
270
+ <AIChat.ToolHeader toolName="search_kb" state={call.state} />
271
+ <AIChat.ToolContent>
272
+ <AIChat.ToolInput input={call.input} />
273
+ <AIChat.ToolOutput output={call.output} errorText={call.errorText} />
274
+ </AIChat.ToolContent>
275
+ </AIChat.Tool>
276
+ ```
277
+
278
+ `state` is `"input-streaming" | "input-available" | "output-available" | "output-error"`.
279
+
280
+ ### Sources
281
+
282
+ Compact "Used N sources" citation trigger under a grounded answer.
283
+
284
+ ```tsx
285
+ <AIChat.Sources>
286
+ <AIChat.SourcesTrigger count={sources.length} />
287
+ <AIChat.SourcesContent>
288
+ {sources.map((source) => (
289
+ <AIChat.Source key={source.id} title={source.title} onClick={() => openDocument(source.id)} />
290
+ ))}
291
+ </AIChat.SourcesContent>
292
+ </AIChat.Sources>
293
+ ```
294
+
295
+ ### History
296
+
297
+ Grouped list of past conversations for reopening an earlier chat. Layout-agnostic — render it in a popover behind a header action, or as a sidebar section of a full chat page. Group titles and date bucketing are yours; `AIChat.History` has no opinion on date ranges.
298
+
299
+ ```tsx
300
+ <AIChat.History
301
+ groups={[{ title: "Today", items: [{ id: "1", title: "Creating a purchase order" }] }]}
302
+ activeId={activeId}
303
+ onSelect={loadConversation}
304
+ onDelete={deleteConversation}
305
+ />
306
+ ```
307
+
308
+ ## Related components
309
+
310
+ - [Layout](./layout.md) — the same children-placed-by-the-root shape
311
+ - [Textarea](./textarea.md) — the composer's body control
312
+ - [Card](./card.md)
313
+ - [Button](./button.md)
314
+ - [useAIChat](../api/use-ai-chat.md)
315
+ - [createAIGatewayClient](../api/create-ai-gateway-client.md)
@@ -0,0 +1,202 @@
1
+ ---
2
+ title: Alert
3
+ description: Contextual status messages with automatic variant icons
4
+ ---
5
+
6
+ <!-- GENERATED by docs-kit from docs-src/components/alert.docs.outline.md — do not edit by hand. -->
7
+
8
+ # Alert
9
+
10
+ The `Alert` component is a compound component for displaying contextual status messages. It automatically renders a matching icon for each variant and supports optional action buttons and dismiss behavior.
11
+
12
+ ## Import
13
+
14
+ ```tsx
15
+ import { Alert } from "@tailor-platform/app-shell";
16
+ ```
17
+
18
+ ## Basic Usage
19
+
20
+ <example-preview name="basic-usage"></example-preview>
21
+
22
+ ```tsx
23
+ function BasicUsage() {
24
+ return (
25
+ <Alert.Root variant="success">
26
+ <Alert.Title>Saved</Alert.Title>
27
+ <Alert.Description>Your changes have been saved.</Alert.Description>
28
+ </Alert.Root>
29
+ );
30
+ }
31
+ ```
32
+
33
+ ## Sub-components
34
+
35
+ | Sub-component | Description |
36
+ | ------------------- | ------------------------------------------------- |
37
+ | `Alert.Root` | Container with variant styling and automatic icon |
38
+ | `Alert.Title` | Bold title line of the alert |
39
+ | `Alert.Description` | Additional descriptive text below the title |
40
+
41
+ ## Props
42
+
43
+ _Generated from the type surface — first-party props only._
44
+
45
+ ### AlertProps
46
+
47
+ | Prop | Type | Default | Description |
48
+ | -------------- | ------------------------------------------------------------------ | ----------- | ---------------------------------------------------- |
49
+ | `action?` | `React.ReactNode` | - | Action element rendered below the description |
50
+ | `dismissible?` | `boolean` | - | Shows a dismiss button; hides the alert when clicked |
51
+ | `onDismiss?` | `() => void` | - | Callback invoked when the dismiss button is clicked |
52
+ | `variant?` | `"error" \| "neutral" \| "success" \| "warning" \| "info" \| null` | `"neutral"` | Visual style and automatic icon |
53
+
54
+ ## Exports
55
+
56
+ - `Alert` — const
57
+ - `AlertProps` — type
58
+ - `alertVariants` — const
59
+
60
+ All standard HTML `<div>` props are also accepted.
61
+
62
+ ## Variants
63
+
64
+ Each variant automatically renders a contextual icon:
65
+
66
+ ```tsx
67
+ <Alert.Root variant="neutral">
68
+ <Alert.Title>Note</Alert.Title>
69
+ <Alert.Description>General information.</Alert.Description>
70
+ </Alert.Root>
71
+
72
+ <Alert.Root variant="success">
73
+ <Alert.Title>Success</Alert.Title>
74
+ <Alert.Description>Operation completed successfully.</Alert.Description>
75
+ </Alert.Root>
76
+
77
+ <Alert.Root variant="warning">
78
+ <Alert.Title>Warning</Alert.Title>
79
+ <Alert.Description>Proceed with caution.</Alert.Description>
80
+ </Alert.Root>
81
+
82
+ <Alert.Root variant="error">
83
+ <Alert.Title>Error</Alert.Title>
84
+ <Alert.Description>Something went wrong.</Alert.Description>
85
+ </Alert.Root>
86
+
87
+ <Alert.Root variant="info">
88
+ <Alert.Title>Info</Alert.Title>
89
+ <Alert.Description>Here is some useful information.</Alert.Description>
90
+ </Alert.Root>
91
+ ```
92
+
93
+ | Variant | Automatic Icon | Color palette |
94
+ | --------- | ------------------- | --------------- |
95
+ | `neutral` | Message circle icon | Muted surface |
96
+ | `success` | Check circle icon | Green |
97
+ | `warning` | Alert triangle icon | Yellow |
98
+ | `error` | X circle icon | Red/destructive |
99
+ | `info` | Info icon | Blue |
100
+
101
+ ## With Action Button
102
+
103
+ Use the `action` prop to render an action element below the description:
104
+
105
+ ```tsx
106
+ <Alert.Root
107
+ variant="warning"
108
+ action={
109
+ <Button size="sm" variant="outline">
110
+ Review
111
+ </Button>
112
+ }
113
+ >
114
+ <Alert.Title>Review Required</Alert.Title>
115
+ <Alert.Description>This record has pending changes that need review.</Alert.Description>
116
+ </Alert.Root>
117
+ ```
118
+
119
+ ## Dismissible Alert
120
+
121
+ Set `dismissible` to show a close button. Use `onDismiss` to react when the alert is dismissed:
122
+
123
+ ```tsx
124
+ <Alert.Root variant="info" dismissible onDismiss={() => markAlertRead(alertId)}>
125
+ <Alert.Title>New Feature Available</Alert.Title>
126
+ <Alert.Description>Check out the new dashboard layout in Settings.</Alert.Description>
127
+ </Alert.Root>
128
+ ```
129
+
130
+ > **Note:** When `dismissible` is `true`, clicking the close button hides the alert via internal state. The `onDismiss` callback fires after the alert is hidden.
131
+
132
+ ## Examples
133
+
134
+ ### Form Validation Error
135
+
136
+ ```tsx
137
+ function OrderForm() {
138
+ const [error, setError] = useState<string | null>(null);
139
+
140
+ return (
141
+ <form>
142
+ {error && (
143
+ <Alert.Root variant="error" dismissible onDismiss={() => setError(null)}>
144
+ <Alert.Title>Submission Failed</Alert.Title>
145
+ <Alert.Description>{error}</Alert.Description>
146
+ </Alert.Root>
147
+ )}
148
+ {/* form fields */}
149
+ </form>
150
+ );
151
+ }
152
+ ```
153
+
154
+ ### Success Confirmation
155
+
156
+ ```tsx
157
+ <Alert.Root variant="success">
158
+ <Alert.Title>Invoice Created</Alert.Title>
159
+ <Alert.Description>Invoice #INV-0042 has been sent to the customer.</Alert.Description>
160
+ </Alert.Root>
161
+ ```
162
+
163
+ ### Warning with Action
164
+
165
+ ```tsx
166
+ <Alert.Root
167
+ variant="warning"
168
+ action={
169
+ <Button size="sm" variant="outline" onClick={() => navigate("/settings/billing")}>
170
+ Update Billing
171
+ </Button>
172
+ }
173
+ >
174
+ <Alert.Title>Payment Method Expiring</Alert.Title>
175
+ <Alert.Description>Your credit card on file expires at the end of this month.</Alert.Description>
176
+ </Alert.Root>
177
+ ```
178
+
179
+ ## Accessibility
180
+
181
+ - The root element has `role="alert"` so screen readers announce the message.
182
+ - The dismiss button has `aria-label="Dismiss"`.
183
+ - Variant icons are marked `aria-hidden` and are decorative only — the text content carries the meaning.
184
+
185
+ ## Styling
186
+
187
+ Alerts are styled with the library's internal `astw:`-prefixed utilities. Write **plain** Tailwind utilities in your own markup, and reach for `variant` rather than restyling what `Alert` sets itself — see [Styling AppShell components](../concepts/styling-theming.md#styling-appshell-components). Customize appearance using:
188
+
189
+ 1. **Using `className`** on `Alert.Root` for additional styles
190
+ 2. **Using `alertVariants`** utility to apply variant classes to custom elements
191
+
192
+ ```tsx
193
+ import { alertVariants } from "@tailor-platform/app-shell";
194
+ import { cn } from "@/lib/utils";
195
+
196
+ <div className={cn(alertVariants({ variant: "info" }), "my-4")}>Custom alert container</div>;
197
+ ```
198
+
199
+ ## Related Components
200
+
201
+ - [Badge](./badge.md) - Inline status labels
202
+ - [Button](./button.md) - Use as action element inside alerts