@bfrs/agentic-components 0.1.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 (186) hide show
  1. package/BFRS_AGENTIC_COMPONENTS.md +1236 -0
  2. package/README.md +132 -0
  3. package/dist/components/data-display/DataTable/DataTable.d.ts +2 -0
  4. package/dist/components/data-display/DataTable/DataTable.types.d.ts +153 -0
  5. package/dist/components/data-display/DataTable/TableBulkActions.d.ts +2 -0
  6. package/dist/components/data-display/DataTable/TableColumnVisibility.d.ts +2 -0
  7. package/dist/components/data-display/DataTable/TableEmptyState.d.ts +2 -0
  8. package/dist/components/data-display/DataTable/TableErrorState.d.ts +2 -0
  9. package/dist/components/data-display/DataTable/TablePagination.d.ts +2 -0
  10. package/dist/components/data-display/DataTable/TableRowActions.d.ts +2 -0
  11. package/dist/components/data-display/DataTable/TableSkeleton.d.ts +2 -0
  12. package/dist/components/data-display/DataTable/TableToolbar.d.ts +2 -0
  13. package/dist/components/data-display/DataTable/index.d.ts +10 -0
  14. package/dist/components/data-display/MetricCard/MetricCard.d.ts +14 -0
  15. package/dist/components/data-display/MetricCard/MetricCard.types.d.ts +15 -0
  16. package/dist/components/data-display/MetricCard/index.d.ts +2 -0
  17. package/dist/components/feedback/EmptyState/EmptyState.d.ts +10 -0
  18. package/dist/components/feedback/EmptyState/EmptyState.types.d.ts +12 -0
  19. package/dist/components/feedback/EmptyState/index.d.ts +2 -0
  20. package/dist/components/feedback/ErrorState/ErrorState.d.ts +8 -0
  21. package/dist/components/feedback/ErrorState/ErrorState.types.d.ts +10 -0
  22. package/dist/components/feedback/ErrorState/index.d.ts +2 -0
  23. package/dist/components/feedback/LoadingState/LoadingState.d.ts +6 -0
  24. package/dist/components/feedback/LoadingState/LoadingState.types.d.ts +8 -0
  25. package/dist/components/feedback/LoadingState/index.d.ts +2 -0
  26. package/dist/components/feedback/Toast/Toast.context.d.ts +3 -0
  27. package/dist/components/feedback/Toast/Toast.d.ts +3 -0
  28. package/dist/components/feedback/Toast/Toast.types.d.ts +48 -0
  29. package/dist/components/feedback/Toast/index.d.ts +3 -0
  30. package/dist/components/filters/DateRangePicker/DateRangePicker.d.ts +5 -0
  31. package/dist/components/filters/DateRangePicker/DateRangePicker.types.d.ts +48 -0
  32. package/dist/components/filters/DateRangePicker/DateRangePicker.utils.d.ts +35 -0
  33. package/dist/components/filters/DateRangePicker/index.d.ts +3 -0
  34. package/dist/components/filters/FilterBar/FilterBar.d.ts +15 -0
  35. package/dist/components/filters/FilterBar/FilterBar.types.d.ts +21 -0
  36. package/dist/components/filters/FilterBar/index.d.ts +2 -0
  37. package/dist/components/filters/FilterDrawer/FilterDrawer.d.ts +2 -0
  38. package/dist/components/filters/FilterDrawer/FilterDrawer.types.d.ts +17 -0
  39. package/dist/components/filters/FilterDrawer/index.d.ts +2 -0
  40. package/dist/components/layout/FormSection/FormSection.d.ts +14 -0
  41. package/dist/components/layout/FormSection/FormSection.types.d.ts +14 -0
  42. package/dist/components/layout/FormSection/index.d.ts +2 -0
  43. package/dist/components/layout/PageHeader/PageHeader.d.ts +13 -0
  44. package/dist/components/layout/PageHeader/PageHeader.types.d.ts +14 -0
  45. package/dist/components/layout/PageHeader/index.d.ts +2 -0
  46. package/dist/components/layout/SectionHeader/SectionHeader.d.ts +9 -0
  47. package/dist/components/layout/SectionHeader/SectionHeader.types.d.ts +10 -0
  48. package/dist/components/layout/SectionHeader/index.d.ts +2 -0
  49. package/dist/components/navigation/ActionMenu/ActionMenu.d.ts +2 -0
  50. package/dist/components/navigation/ActionMenu/ActionMenu.types.d.ts +22 -0
  51. package/dist/components/navigation/ActionMenu/index.d.ts +2 -0
  52. package/dist/components/navigation/Tabs/Tabs.d.ts +2 -0
  53. package/dist/components/navigation/Tabs/Tabs.types.d.ts +17 -0
  54. package/dist/components/navigation/Tabs/index.d.ts +2 -0
  55. package/dist/components/overlays/ConfirmDialog/ConfirmDialog.d.ts +2 -0
  56. package/dist/components/overlays/ConfirmDialog/ConfirmDialog.types.d.ts +19 -0
  57. package/dist/components/overlays/ConfirmDialog/index.d.ts +2 -0
  58. package/dist/components/overlays/Drawer/Drawer.d.ts +2 -0
  59. package/dist/components/overlays/Drawer/Drawer.types.d.ts +24 -0
  60. package/dist/components/overlays/Drawer/index.d.ts +2 -0
  61. package/dist/components/overlays/Modal/Modal.d.ts +2 -0
  62. package/dist/components/overlays/Modal/Modal.types.d.ts +22 -0
  63. package/dist/components/overlays/Modal/index.d.ts +2 -0
  64. package/dist/components/primitives/Badge/Badge.d.ts +9 -0
  65. package/dist/components/primitives/Badge/Badge.types.d.ts +13 -0
  66. package/dist/components/primitives/Badge/index.d.ts +2 -0
  67. package/dist/components/primitives/Button/Button.d.ts +15 -0
  68. package/dist/components/primitives/Button/Button.types.d.ts +17 -0
  69. package/dist/components/primitives/Button/index.d.ts +2 -0
  70. package/dist/components/primitives/Card/Card.d.ts +9 -0
  71. package/dist/components/primitives/Card/Card.types.d.ts +8 -0
  72. package/dist/components/primitives/Card/index.d.ts +2 -0
  73. package/dist/components/primitives/Chip/Chip.d.ts +10 -0
  74. package/dist/components/primitives/Chip/Chip.types.d.ts +14 -0
  75. package/dist/components/primitives/Chip/index.d.ts +2 -0
  76. package/dist/components/primitives/Input/Input.d.ts +16 -0
  77. package/dist/components/primitives/Input/Input.types.d.ts +18 -0
  78. package/dist/components/primitives/Input/index.d.ts +2 -0
  79. package/dist/components/ui/actions/Button/Button.d.ts +2 -0
  80. package/dist/components/ui/actions/Button/index.d.ts +1 -0
  81. package/dist/components/ui/actions/IconButton/IconButton.d.ts +2 -0
  82. package/dist/components/ui/actions/IconButton/index.d.ts +1 -0
  83. package/dist/components/ui/data-display/Avatar/Avatar.d.ts +15 -0
  84. package/dist/components/ui/data-display/Avatar/index.d.ts +1 -0
  85. package/dist/components/ui/data-display/Pagination/Pagination.d.ts +7 -0
  86. package/dist/components/ui/data-display/Pagination/index.d.ts +1 -0
  87. package/dist/components/ui/data-display/Table/Table.d.ts +28 -0
  88. package/dist/components/ui/data-display/Table/TableEmptyState.d.ts +2 -0
  89. package/dist/components/ui/data-display/Table/TableSkeleton.d.ts +5 -0
  90. package/dist/components/ui/data-display/Table/index.d.ts +3 -0
  91. package/dist/components/ui/feedback/Alert/Alert.d.ts +18 -0
  92. package/dist/components/ui/feedback/Alert/index.d.ts +1 -0
  93. package/dist/components/ui/feedback/Badge/Badge.d.ts +2 -0
  94. package/dist/components/ui/feedback/Badge/index.d.ts +1 -0
  95. package/dist/components/ui/feedback/Chip/Chip.d.ts +2 -0
  96. package/dist/components/ui/feedback/Chip/index.d.ts +1 -0
  97. package/dist/components/ui/feedback/EmptyState/EmptyState.d.ts +2 -0
  98. package/dist/components/ui/feedback/EmptyState/index.d.ts +1 -0
  99. package/dist/components/ui/feedback/Skeleton/Skeleton.d.ts +10 -0
  100. package/dist/components/ui/feedback/Skeleton/index.d.ts +1 -0
  101. package/dist/components/ui/feedback/Spinner/Spinner.d.ts +6 -0
  102. package/dist/components/ui/feedback/Spinner/index.d.ts +1 -0
  103. package/dist/components/ui/forms/Checkbox/Checkbox.d.ts +14 -0
  104. package/dist/components/ui/forms/Checkbox/index.d.ts +1 -0
  105. package/dist/components/ui/forms/FormField/FormField.d.ts +17 -0
  106. package/dist/components/ui/forms/FormField/index.d.ts +1 -0
  107. package/dist/components/ui/forms/Input/Input.d.ts +2 -0
  108. package/dist/components/ui/forms/Input/index.d.ts +1 -0
  109. package/dist/components/ui/forms/Label/Label.d.ts +9 -0
  110. package/dist/components/ui/forms/Label/index.d.ts +1 -0
  111. package/dist/components/ui/forms/Radio/Radio.d.ts +14 -0
  112. package/dist/components/ui/forms/Radio/index.d.ts +1 -0
  113. package/dist/components/ui/forms/SearchableSelect/SearchableSelect.d.ts +18 -0
  114. package/dist/components/ui/forms/SearchableSelect/index.d.ts +1 -0
  115. package/dist/components/ui/forms/Select/Select.d.ts +20 -0
  116. package/dist/components/ui/forms/Select/index.d.ts +1 -0
  117. package/dist/components/ui/forms/Switch/Switch.d.ts +7 -0
  118. package/dist/components/ui/forms/Switch/index.d.ts +1 -0
  119. package/dist/components/ui/forms/Textarea/Textarea.d.ts +9 -0
  120. package/dist/components/ui/forms/Textarea/index.d.ts +1 -0
  121. package/dist/components/ui/index.d.ts +53 -0
  122. package/dist/components/ui/navigation/Breadcrumbs/Breadcrumbs.d.ts +11 -0
  123. package/dist/components/ui/navigation/Breadcrumbs/index.d.ts +1 -0
  124. package/dist/components/ui/navigation/Tabs/Tabs.d.ts +2 -0
  125. package/dist/components/ui/navigation/Tabs/index.d.ts +1 -0
  126. package/dist/components/ui/overlays/Dialog/Dialog.d.ts +2 -0
  127. package/dist/components/ui/overlays/Dialog/index.d.ts +1 -0
  128. package/dist/components/ui/overlays/Drawer/Drawer.d.ts +2 -0
  129. package/dist/components/ui/overlays/Drawer/index.d.ts +1 -0
  130. package/dist/components/ui/overlays/Dropdown/Dropdown.d.ts +16 -0
  131. package/dist/components/ui/overlays/Dropdown/index.d.ts +1 -0
  132. package/dist/components/ui/overlays/Popover/Popover.d.ts +8 -0
  133. package/dist/components/ui/overlays/Popover/index.d.ts +1 -0
  134. package/dist/components/ui/overlays/Tooltip/Tooltip.d.ts +8 -0
  135. package/dist/components/ui/overlays/Tooltip/index.d.ts +1 -0
  136. package/dist/components/ui/patterns/BusinessInfoDisplayCard/BusinessInfoDisplayCard.d.ts +37 -0
  137. package/dist/components/ui/patterns/BusinessInfoDisplayCard/BusinessInfoDisplayCardSkeleton.d.ts +7 -0
  138. package/dist/components/ui/patterns/BusinessInfoDisplayCard/index.d.ts +2 -0
  139. package/dist/components/ui/patterns/ChatBubble/ChatBubble.d.ts +11 -0
  140. package/dist/components/ui/patterns/ChatBubble/index.d.ts +1 -0
  141. package/dist/components/ui/patterns/ChatComposer/ChatComposer.d.ts +19 -0
  142. package/dist/components/ui/patterns/ChatComposer/index.d.ts +1 -0
  143. package/dist/components/ui/patterns/FullPageLoader/FullPageLoader.d.ts +17 -0
  144. package/dist/components/ui/patterns/FullPageLoader/FullPageLoaderSpinner.d.ts +4 -0
  145. package/dist/components/ui/patterns/FullPageLoader/index.d.ts +1 -0
  146. package/dist/components/ui/patterns/LayoutShell/LayoutShell.d.ts +8 -0
  147. package/dist/components/ui/patterns/LayoutShell/index.d.ts +1 -0
  148. package/dist/components/ui/patterns/PageHeader/PageHeader.d.ts +2 -0
  149. package/dist/components/ui/patterns/PageHeader/index.d.ts +1 -0
  150. package/dist/components/ui/patterns/StepProgressCard/StepProgressCard.d.ts +24 -0
  151. package/dist/components/ui/patterns/StepProgressCard/StepProgressCardSkeleton.d.ts +7 -0
  152. package/dist/components/ui/patterns/StepProgressCard/index.d.ts +2 -0
  153. package/dist/components/ui/primitives/Box/Box.d.ts +7 -0
  154. package/dist/components/ui/primitives/Box/index.d.ts +1 -0
  155. package/dist/components/ui/primitives/Container/Container.d.ts +10 -0
  156. package/dist/components/ui/primitives/Container/index.d.ts +1 -0
  157. package/dist/components/ui/primitives/Grid/Grid.d.ts +9 -0
  158. package/dist/components/ui/primitives/Grid/index.d.ts +1 -0
  159. package/dist/components/ui/primitives/Icon/Icon.d.ts +15 -0
  160. package/dist/components/ui/primitives/Icon/index.d.ts +1 -0
  161. package/dist/components/ui/primitives/Paper/Paper.d.ts +12 -0
  162. package/dist/components/ui/primitives/Paper/index.d.ts +1 -0
  163. package/dist/components/ui/primitives/Stack/Stack.d.ts +17 -0
  164. package/dist/components/ui/primitives/Stack/index.d.ts +1 -0
  165. package/dist/components/ui/primitives/Text/Text.d.ts +16 -0
  166. package/dist/components/ui/primitives/Text/index.d.ts +1 -0
  167. package/dist/index.d.ts +3 -0
  168. package/dist/index.js +12652 -0
  169. package/dist/index.js.map +1 -0
  170. package/dist/lib/cn.d.ts +2 -0
  171. package/dist/lib/utils.d.ts +1 -0
  172. package/dist/style.css +1 -0
  173. package/dist/theme/index.d.ts +2 -0
  174. package/dist/theme/theme.types.d.ts +1 -0
  175. package/dist/theme/tokens.d.ts +11 -0
  176. package/dist/tokens/colors.d.ts +35 -0
  177. package/dist/tokens/index.d.ts +8 -0
  178. package/dist/tokens/motion.d.ts +7 -0
  179. package/dist/tokens/radius.d.ts +8 -0
  180. package/dist/tokens/shadows.d.ts +6 -0
  181. package/dist/tokens/sizes.d.ts +75 -0
  182. package/dist/tokens/spacing.d.ts +12 -0
  183. package/dist/tokens/typography.d.ts +12 -0
  184. package/dist/tokens/zIndex.d.ts +9 -0
  185. package/package.json +94 -0
  186. package/scripts/postinstall.cjs +76 -0
@@ -0,0 +1,1236 @@
1
+ # @bfrs/agentic-components — Agent Context
2
+
3
+ This file is auto-generated by the `@bfrs/agentic-components` package on install.
4
+ It gives AI coding agents full knowledge of the component library so they can write
5
+ correct, idiomatic UI code without guessing.
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ Configure npm auth in the consuming app:
12
+
13
+ ```ini
14
+ registry=https://registry.npmjs.org/
15
+ //registry.npmjs.org/:_authToken=${NPM_TOKEN}
16
+ ```
17
+
18
+ ```bash
19
+ npm install @bfrs/agentic-components
20
+ ```
21
+
22
+ ## Setup
23
+
24
+ Import the stylesheet once at your app entry point:
25
+
26
+ ```tsx
27
+ import "@bfrs/agentic-components/styles";
28
+ ```
29
+
30
+ Import components by name:
31
+
32
+ ```tsx
33
+ import { Button, Input, Modal, DataTable, DateRangePicker, ToastProvider, useToast } from "@bfrs/agentic-components";
34
+ ```
35
+
36
+ **Peer dependencies required:** `react >= 18.2.0`, `react-dom >= 18.2.0`
37
+
38
+ ---
39
+
40
+ ## Design System Conventions
41
+
42
+ - **Sizes** are always `"sm" | "md" | "lg"` — default is `"md"` unless noted
43
+ - **Tones** are always `"neutral" | "primary" | "success" | "warning" | "danger" | "info"`
44
+ - **Variants** control visual style (filled vs. outline vs. ghost, etc.)
45
+ - All interactive components forward refs and spread native HTML props
46
+ - Styling uses **Tailwind CSS** + **CVA** — do not add raw Tailwind classes on top of variant-controlled elements
47
+ - Use the `cn()` utility from the library for conditional class merging
48
+
49
+ ```tsx
50
+ import { cn } from "@bfrs/agentic-components";
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Components
56
+
57
+ ### Primitives
58
+
59
+ ---
60
+
61
+ #### `Box`
62
+
63
+ Generic polymorphic wrapper. Use when you need a semantic HTML element with class merging.
64
+
65
+ ```tsx
66
+ <Box as="section" className="my-4">…</Box>
67
+ ```
68
+
69
+ | Prop | Type | Default |
70
+ |------|------|---------|
71
+ | `as` | `ElementType` | `"div"` |
72
+ | `className` | `string` | — |
73
+
74
+ ---
75
+
76
+ #### `Container`
77
+
78
+ Responsive max-width wrapper with horizontal padding.
79
+
80
+ ```tsx
81
+ <Container size="md">…</Container>
82
+ ```
83
+
84
+ | Prop | Type | Default |
85
+ |------|------|---------|
86
+ | `size` | `"sm" \| "md" \| "lg" \| "full"` | `"lg"` |
87
+
88
+ ---
89
+
90
+ #### `Paper`
91
+
92
+ Card-like surface. Use for panels, cards, and content sections.
93
+
94
+ ```tsx
95
+ <Paper variant="elevated" padding="lg">…</Paper>
96
+ ```
97
+
98
+ | Prop | Type | Default |
99
+ |------|------|---------|
100
+ | `variant` | `"default" \| "muted" \| "elevated" \| "outlined" \| "glass"` | `"default"` |
101
+ | `padding` | `"none" \| "sm" \| "md" \| "lg"` | `"md"` |
102
+
103
+ ---
104
+
105
+ #### `Stack`
106
+
107
+ Flexbox layout. Use instead of writing flex utility classes directly.
108
+
109
+ ```tsx
110
+ <Stack direction="row" gap={4} align="center">
111
+ <Button>Save</Button>
112
+ <Button variant="ghost">Cancel</Button>
113
+ </Stack>
114
+ ```
115
+
116
+ | Prop | Type | Default |
117
+ |------|------|---------|
118
+ | `direction` | `"row" \| "column"` | `"column"` |
119
+ | `gap` | `0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 8 \| 10 \| 12` | `4` |
120
+ | `align` | `CSSProperties["alignItems"]` | — |
121
+ | `justify` | `CSSProperties["justifyContent"]` | — |
122
+ | `wrap` | `boolean` | `false` |
123
+
124
+ ---
125
+
126
+ #### `Grid`
127
+
128
+ Responsive CSS grid layout.
129
+
130
+ ```tsx
131
+ <Grid columns={3} gap="md">
132
+ <Card />
133
+ <Card />
134
+ <Card />
135
+ </Grid>
136
+ ```
137
+
138
+ | Prop | Type | Default |
139
+ |------|------|---------|
140
+ | `columns` | `1 \| 2 \| 3 \| 4` | `3` |
141
+ | `gap` | `"sm" \| "md" \| "lg"` | `"md"` |
142
+
143
+ ---
144
+
145
+ #### `Text`
146
+
147
+ Semantic typography. Always use this instead of raw `<p>`, `<h1>`, `<span>` for text.
148
+
149
+ ```tsx
150
+ <Text variant="h2">Welcome back</Text>
151
+ <Text variant="body" tone="muted">Last seen 2 hours ago</Text>
152
+ ```
153
+
154
+ | Prop | Type | Default |
155
+ |------|------|---------|
156
+ | `variant` | `"display" \| "h1" \| "h2" \| "h3" \| "title" \| "body" \| "body-sm" \| "caption" \| "label"` | `"body"` |
157
+ | `tone` | `"primary" \| "secondary" \| "muted" \| "disabled" \| "danger" \| "success" \| "accent"` | `"primary"` |
158
+ | `as` | `ElementType` | inferred from variant |
159
+
160
+ ---
161
+
162
+ #### `Icon`
163
+
164
+ Phosphor icon wrapper with consistent sizing and accessibility.
165
+
166
+ ```tsx
167
+ import { MagnifyingGlass } from "@phosphor-icons/react";
168
+
169
+ <Icon icon={MagnifyingGlass} size="md" weight="bold" />
170
+ ```
171
+
172
+ | Prop | Type | Default |
173
+ |------|------|---------|
174
+ | `icon` | `PhosphorIconComponent` | **required** |
175
+ | `size` | `"sm" \| "md" \| "lg" \| number` | `"md"` |
176
+ | `weight` | `"thin" \| "light" \| "regular" \| "bold" \| "fill" \| "duotone"` | `"regular"` |
177
+ | `decorative` | `boolean` | `true` |
178
+
179
+ > When `decorative={false}`, add an `aria-label` to the wrapping element.
180
+
181
+ ---
182
+
183
+ ### Actions
184
+
185
+ ---
186
+
187
+ #### `Button`
188
+
189
+ Primary interactive element. Covers all CTA patterns.
190
+
191
+ ```tsx
192
+ <Button variant="primary" size="md" onClick={handleSave}>
193
+ Save changes
194
+ </Button>
195
+
196
+ <Button variant="destructive" loading={isDeleting}>
197
+ Delete account
198
+ </Button>
199
+
200
+ <Button variant="outline" leftIcon={<Icon icon={Plus} />}>
201
+ Add item
202
+ </Button>
203
+ ```
204
+
205
+ | Prop | Type | Default |
206
+ |------|------|---------|
207
+ | `variant` | `"primary" \| "secondary" \| "outline" \| "ghost" \| "destructive" \| "link"` | `"primary"` |
208
+ | `size` | `"sm" \| "md" \| "lg"` | `"md"` |
209
+ | `fullWidth` | `boolean` | `false` |
210
+ | `leftIcon` | `ReactNode` | — |
211
+ | `rightIcon` | `ReactNode` | — |
212
+ | `loading` | `boolean` | `false` |
213
+ | `disabled` | `boolean` | `false` |
214
+
215
+ ---
216
+
217
+ #### `IconButton`
218
+
219
+ Square button for icon-only actions. Always provide `aria-label`.
220
+
221
+ ```tsx
222
+ <IconButton
223
+ icon={<Icon icon={Trash} />}
224
+ variant="ghost"
225
+ size="sm"
226
+ aria-label="Delete item"
227
+ onClick={handleDelete}
228
+ />
229
+ ```
230
+
231
+ | Prop | Type | Default |
232
+ |------|------|---------|
233
+ | `icon` | `ReactNode` | **required** |
234
+ | `aria-label` | `string` | **required** |
235
+ | `variant` | `"primary" \| "secondary" \| "outline" \| "ghost" \| "danger"` | `"ghost"` |
236
+ | `size` | `"sm" \| "md" \| "lg"` | `"md"` |
237
+ | `loading` | `boolean` | `false` |
238
+
239
+ ---
240
+
241
+ ### Forms
242
+
243
+ > **Rule:** Always wrap form controls in `FormField` — it handles label, helper text, error text, and aria wiring automatically.
244
+
245
+ ---
246
+
247
+ #### `FormField`
248
+
249
+ Wraps any form control with label, helper, and error text. Connects them via `aria-describedby`.
250
+
251
+ ```tsx
252
+ <FormField
253
+ label="Email address"
254
+ required
255
+ helperText="We'll never share your email."
256
+ errorText={errors.email}
257
+ >
258
+ <Input type="email" value={email} onChange={…} />
259
+ </FormField>
260
+ ```
261
+
262
+ | Prop | Type | Default |
263
+ |------|------|---------|
264
+ | `label` | `ReactNode` | — |
265
+ | `required` | `boolean` | `false` |
266
+ | `helperText` | `ReactNode` | — |
267
+ | `errorText` | `ReactNode` | — |
268
+ | `disabled` | `boolean` | `false` |
269
+ | `children` | `ReactElement` | **required** |
270
+
271
+ ---
272
+
273
+ #### `Label`
274
+
275
+ Standalone label. Prefer `FormField` which renders this automatically.
276
+
277
+ ```tsx
278
+ <Label required>Business name</Label>
279
+ ```
280
+
281
+ | Prop | Type | Default |
282
+ |------|------|---------|
283
+ | `required` | `boolean` | `false` |
284
+ | `disabled` | `boolean` | `false` |
285
+
286
+ ---
287
+
288
+ #### `Input`
289
+
290
+ Standard text input.
291
+
292
+ ```tsx
293
+ <Input
294
+ placeholder="Search…"
295
+ size="md"
296
+ leftIcon={<Icon icon={MagnifyingGlass} />}
297
+ />
298
+
299
+ <Input value={val} state="error" onChange={…} />
300
+ ```
301
+
302
+ | Prop | Type | Default |
303
+ |------|------|---------|
304
+ | `size` | `"sm" \| "md" \| "lg"` | `"md"` |
305
+ | `state` | `"default" \| "error"` | `"default"` |
306
+ | `error` | `boolean` | `false` |
307
+ | `leftIcon` | `ReactNode` | — |
308
+ | `rightIcon` | `ReactNode` | — |
309
+
310
+ Accepts all native `<input>` props.
311
+
312
+ ---
313
+
314
+ #### `Textarea`
315
+
316
+ Multi-line text input.
317
+
318
+ ```tsx
319
+ <Textarea
320
+ rows={6}
321
+ placeholder="Describe your issue…"
322
+ error={!!errors.description}
323
+ />
324
+ ```
325
+
326
+ | Prop | Type | Default |
327
+ |------|------|---------|
328
+ | `size` | `"sm" \| "md" \| "lg"` | `"md"` |
329
+ | `error` | `boolean` | `false` |
330
+ | `rows` | `number` | `4` |
331
+
332
+ Accepts all native `<textarea>` props.
333
+
334
+ ---
335
+
336
+ #### `Select`
337
+
338
+ Single-value dropdown. Options are `{ value: string; label: string }`.
339
+
340
+ ```tsx
341
+ <Select
342
+ options={[
343
+ { value: "in", label: "India" },
344
+ { value: "us", label: "United States" },
345
+ ]}
346
+ value={country}
347
+ onValueChange={setCountry}
348
+ placeholder="Select country"
349
+ />
350
+ ```
351
+
352
+ | Prop | Type | Default |
353
+ |------|------|---------|
354
+ | `options` | `{ value: string; label: string }[]` | **required** |
355
+ | `value` | `string` | — |
356
+ | `onValueChange` | `(value: string) => void` | — |
357
+ | `placeholder` | `string` | `"Select"` |
358
+ | `size` | `"sm" \| "md" \| "lg"` | `"md"` |
359
+ | `disabled` | `boolean` | `false` |
360
+ | `error` | `boolean` | `false` |
361
+
362
+ ---
363
+
364
+ #### `DateRangePicker`
365
+
366
+ Preset and custom calendar date-range filter. Presets commit immediately; custom ranges use Apply/Cancel.
367
+
368
+ ```tsx
369
+ import { DateRangePicker, presetToRange, type DateRangeValue } from "@bfrs/agentic-components";
370
+
371
+ const [range, setRange] = useState<DateRangeValue>({
372
+ preset: "Last 30 days",
373
+ ...presetToRange("Last 30 days")
374
+ });
375
+
376
+ <DateRangePicker value={range} onChange={setRange} maxRangeDays={365} />;
377
+ ```
378
+
379
+ | Prop | Type | Default |
380
+ |------|------|---------|
381
+ | `value` | `DateRangeValue` | — |
382
+ | `onChange` | `(value: DateRangeValue) => void` | — |
383
+ | `presets` | `DateRangePreset[]` | default presets |
384
+ | `size` | `"sm" \| "md" \| "lg"` | `"sm"` |
385
+ | `maxRangeDays` | `number` | — |
386
+ | `months` | `1 \| 2` | `2` |
387
+ | `open` / `onOpenChange` | controlled popover state | — |
388
+
389
+ Keep API date formatting, route updates, and business limits in the consuming app.
390
+
391
+ ---
392
+
393
+ #### `SearchableSelect`
394
+
395
+ Combobox with search. Use when options list is long (10+).
396
+
397
+ ```tsx
398
+ <SearchableSelect
399
+ options={cities}
400
+ value={city}
401
+ onValueChange={setCity}
402
+ placeholder="Select city"
403
+ searchPlaceholder="Search cities…"
404
+ clearable
405
+ />
406
+ ```
407
+
408
+ | Prop | Type | Default |
409
+ |------|------|---------|
410
+ | `options` | `{ value: string; label: string }[]` | **required** |
411
+ | `value` | `string` | — |
412
+ | `onValueChange` | `(value: string \| undefined) => void` | — |
413
+ | `placeholder` | `string` | `"Select"` |
414
+ | `searchPlaceholder` | `string` | `"Search..."` |
415
+ | `emptyText` | `string` | `"No results found"` |
416
+ | `loading` | `boolean` | `false` |
417
+ | `disabled` | `boolean` | `false` |
418
+ | `error` | `boolean` | `false` |
419
+ | `clearable` | `boolean` | `true` |
420
+
421
+ ---
422
+
423
+ #### `Checkbox`
424
+
425
+ Square checklist control for independent true/false decisions or multi-select choices.
426
+ Use `Radio` instead when exactly one option in a group can be selected.
427
+
428
+ ```tsx
429
+ <Checkbox
430
+ checked={agreed}
431
+ onCheckedChange={setAgreed}
432
+ label="Accept terms"
433
+ description="Use checkboxes when each option can be selected independently."
434
+ />
435
+
436
+ <Checkbox label="Partially selected" checked="indeterminate" />
437
+ ```
438
+
439
+ | Prop | Type | Default |
440
+ |------|------|---------|
441
+ | `label` | `ReactNode` | — |
442
+ | `description` | `ReactNode` | — |
443
+ | `size` | `"sm" \| "md" \| "lg"` | `"md"` |
444
+ | `error` | `boolean` | `false` |
445
+ | `checked` | `boolean \| "indeterminate"` | — |
446
+ | `onCheckedChange` | `(checked: boolean \| "indeterminate") => void` | — |
447
+
448
+ ---
449
+
450
+ #### `Radio`
451
+
452
+ Radio group. Renders a list of mutually exclusive options.
453
+
454
+ ```tsx
455
+ <Radio
456
+ value={plan}
457
+ onValueChange={setPlan}
458
+ options={[
459
+ { value: "free", label: "Free" },
460
+ { value: "pro", label: "Pro" },
461
+ { value: "enterprise", label: "Enterprise" },
462
+ ]}
463
+ />
464
+ ```
465
+
466
+ | Prop | Type | Default |
467
+ |------|------|---------|
468
+ | `options` | `{ value: string; label: string }[]` | **required** |
469
+ | `value` | `string` | — |
470
+ | `onValueChange` | `(value: string) => void` | — |
471
+ | `error` | `boolean` | `false` |
472
+
473
+ ---
474
+
475
+ #### `Switch`
476
+
477
+ Toggle switch with optional label.
478
+
479
+ ```tsx
480
+ <Switch
481
+ checked={notifications}
482
+ onCheckedChange={setNotifications}
483
+ label="Email notifications"
484
+ />
485
+ ```
486
+
487
+ | Prop | Type | Default |
488
+ |------|------|---------|
489
+ | `label` | `string` | — |
490
+ | `checked` | `boolean` | — |
491
+ | `onCheckedChange` | `(checked: boolean) => void` | — |
492
+
493
+ ---
494
+
495
+ ### Feedback
496
+
497
+ ---
498
+
499
+ #### `Badge`
500
+
501
+ Small inline status label.
502
+
503
+ ```tsx
504
+ <Badge tone="success">Active</Badge>
505
+ <Badge tone="warning">Pending</Badge>
506
+ <Badge tone="danger">Blocked</Badge>
507
+ ```
508
+
509
+ | Prop | Type | Default |
510
+ |------|------|---------|
511
+ | `size` | `"sm" \| "md" \| "lg"` | `"sm"` |
512
+ | `tone` | `"neutral" \| "primary" \| "success" \| "warning" \| "danger" \| "info"` | `"neutral"` |
513
+
514
+ ---
515
+
516
+ #### `Chip`
517
+
518
+ Removable tag. Use in filter bars and multi-select UIs.
519
+
520
+ ```tsx
521
+ <Chip
522
+ tone="primary"
523
+ variant="soft"
524
+ leftIcon={<Icon icon={Tag} />}
525
+ onRemove={() => removeFilter("status")}
526
+ >
527
+ Status: Active
528
+ </Chip>
529
+ ```
530
+
531
+ | Prop | Type | Default |
532
+ |------|------|---------|
533
+ | `variant` | `"filled" \| "soft" \| "outline"` | `"soft"` |
534
+ | `tone` | `"neutral" \| "primary" \| "success" \| "warning" \| "danger"` | `"neutral"` |
535
+ | `leftIcon` | `ReactNode` | — |
536
+ | `onRemove` | `() => void` | — |
537
+ | `removeLabel` | `string` | `"Remove"` |
538
+
539
+ ---
540
+
541
+ #### `Alert`
542
+
543
+ Contextual message banner. Auto-selects an icon based on tone.
544
+
545
+ ```tsx
546
+ <Alert
547
+ tone="warning"
548
+ title="Your trial ends in 3 days"
549
+ action={<Button size="sm">Upgrade now</Button>}
550
+ >
551
+ Upgrade to keep access to all features.
552
+ </Alert>
553
+ ```
554
+
555
+ | Prop | Type | Default |
556
+ |------|------|---------|
557
+ | `tone` | `"info" \| "success" \| "warning" \| "danger"` | `"info"` |
558
+ | `title` | `ReactNode` | — |
559
+ | `action` | `ReactNode` | — |
560
+ | `icon` | `ReactNode` | auto (from tone) |
561
+
562
+ ---
563
+
564
+ #### `ToastProvider`, `useToast`, `ToastManager`
565
+
566
+ App-wide transient feedback manager. Wrap the app once, then call toast helpers from event handlers.
567
+
568
+ ```tsx
569
+ function SaveButton() {
570
+ const { success, danger } = useToast();
571
+
572
+ async function save() {
573
+ try {
574
+ await saveRequest();
575
+ success("Changes saved");
576
+ } catch {
577
+ danger({ title: "Save failed", description: "Try again in a moment." });
578
+ }
579
+ }
580
+
581
+ return <Button onClick={save}>Save</Button>;
582
+ }
583
+
584
+ <ToastProvider placement="bottom-center">
585
+ <SaveButton />
586
+ </ToastProvider>;
587
+ ```
588
+
589
+ | Prop / API | Type | Default |
590
+ |------|------|---------|
591
+ | `placement` | `"top-left" \| "top-center" \| "top-right" \| "bottom-left" \| "bottom-center" \| "bottom-right"` | `"bottom-center"` |
592
+ | `maxToasts` | `number` | `4` |
593
+ | `defaultDuration` | `number` | `2600` |
594
+ | `toast` | `(input: ToastInput) => string` | — |
595
+ | `success` / `warning` / `danger` / `info` | semantic helper functions | — |
596
+ | `dismiss` / `clear` | manager controls | — |
597
+
598
+ Do not put API calls, route logic, or app stores inside the library toast manager.
599
+
600
+ ---
601
+
602
+ #### `Spinner`
603
+
604
+ Loading indicator. Use inside buttons, inline loaders, or page sections.
605
+
606
+ ```tsx
607
+ <Spinner size="md" label="Fetching orders…" />
608
+ ```
609
+
610
+ | Prop | Type | Default |
611
+ |------|------|---------|
612
+ | `size` | `"sm" \| "md" \| "lg"` | `"md"` |
613
+ | `label` | `string` | `"Loading"` |
614
+
615
+ ---
616
+
617
+ #### `Skeleton`
618
+
619
+ Shimmer placeholder while content loads. Match the variant to the shape of the real content.
620
+
621
+ ```tsx
622
+ <Skeleton variant="text" /> // single line
623
+ <Skeleton variant="card" /> // card-height block
624
+ <Skeleton variant="avatar" /> // circle
625
+ <Skeleton variant="block" /> // rectangular block
626
+ ```
627
+
628
+ | Prop | Type | Default |
629
+ |------|------|---------|
630
+ | `variant` | `"text" \| "block" \| "card" \| "avatar"` | `"block"` |
631
+
632
+ ---
633
+
634
+ #### `EmptyState`
635
+
636
+ Centered empty state for lists, tables, and search results.
637
+
638
+ ```tsx
639
+ <EmptyState
640
+ icon={<Icon icon={Package} size="lg" />}
641
+ title="No orders yet"
642
+ description="Orders placed by your customers will appear here."
643
+ action={<Button>Create order</Button>}
644
+ />
645
+ ```
646
+
647
+ | Prop | Type | Default |
648
+ |------|------|---------|
649
+ | `title` | `ReactNode` | **required** |
650
+ | `icon` | `ReactNode` | — |
651
+ | `description` | `ReactNode` | — |
652
+ | `action` | `ReactNode` | — |
653
+
654
+ ---
655
+
656
+ ### Overlays
657
+
658
+ ---
659
+
660
+ #### `Modal`
661
+
662
+ Centered modal. Use for confirmations, forms, and focused tasks.
663
+
664
+ ```tsx
665
+ <Modal
666
+ trigger={<Button>Delete account</Button>}
667
+ title="Are you sure?"
668
+ description="This action cannot be undone."
669
+ footer={
670
+ <Stack direction="row" gap={2} justify="flex-end">
671
+ <Button variant="ghost">Cancel</Button>
672
+ <Button variant="destructive" onClick={handleDelete}>Delete</Button>
673
+ </Stack>
674
+ }
675
+ >
676
+ All your data will be permanently removed.
677
+ </Modal>
678
+ ```
679
+
680
+ | Prop | Type | Default |
681
+ |------|------|---------|
682
+ | `title` | `ReactNode` | **required** |
683
+ | `children` | `ReactNode` | **required** |
684
+ | `trigger` | `ReactNode` | — |
685
+ | `description` | `ReactNode` | — |
686
+ | `footer` | `ReactNode` | — |
687
+ | `size` | `"sm" \| "md" \| "lg" \| "xl" \| "full"` | `"md"` |
688
+ | `open` | `boolean` | — |
689
+ | `onOpenChange` | `(open: boolean) => void` | — |
690
+
691
+ `Dialog` is a deprecated compatibility alias. Use `Modal` in new code.
692
+
693
+ ---
694
+
695
+ #### `Drawer`
696
+
697
+ Slide-out panel. Use for detail views, settings, and secondary flows.
698
+
699
+ ```tsx
700
+ <Drawer
701
+ trigger={<Button variant="outline">View details</Button>}
702
+ title="Order #1234"
703
+ placement="right"
704
+ size="xl"
705
+ >
706
+ <OrderDetail id="1234" />
707
+ </Drawer>
708
+ ```
709
+
710
+ | Prop | Type | Default |
711
+ |------|------|---------|
712
+ | `title` | `ReactNode` | **required** |
713
+ | `children` | `ReactNode` | **required** |
714
+ | `placement` | `"left" \| "right" \| "bottom"` | `"right"` |
715
+ | `size` | `"sm" \| "md" \| "lg" \| "xl"` | `"md"` |
716
+ | `trigger` | `ReactNode` | — |
717
+ | `description` | `ReactNode` | — |
718
+ | `open` | `boolean` | — |
719
+ | `onOpenChange` | `(open: boolean) => void` | — |
720
+
721
+ ---
722
+
723
+ #### `Dropdown`
724
+
725
+ Context menu attached to a trigger. Items support destructive and checked states.
726
+
727
+ ```tsx
728
+ <Dropdown
729
+ trigger={<IconButton icon={<Icon icon={DotsThree} />} aria-label="More actions" />}
730
+ align="end"
731
+ items={[
732
+ { label: "Edit", onSelect: handleEdit },
733
+ { label: "Duplicate", onSelect: handleDuplicate },
734
+ { label: "Delete", onSelect: handleDelete, destructive: true },
735
+ ]}
736
+ />
737
+ ```
738
+
739
+ | Prop | Type | Default |
740
+ |------|------|---------|
741
+ | `trigger` | `ReactNode` | **required** |
742
+ | `items` | `{ label: string; onSelect: () => void; disabled?: boolean; destructive?: boolean; checked?: boolean }[]` | **required** |
743
+ | `align` | `"start" \| "center" \| "end"` | `"end"` |
744
+ | `size` | `"sm" \| "md" \| "lg"` | `"md"` |
745
+
746
+ ---
747
+
748
+ #### `Tooltip`
749
+
750
+ Floating label on hover. Provide `content` as the tooltip text.
751
+
752
+ ```tsx
753
+ <Tooltip content="Copy to clipboard" side="top">
754
+ <IconButton icon={<Icon icon={Copy} />} aria-label="Copy" />
755
+ </Tooltip>
756
+ ```
757
+
758
+ | Prop | Type | Default |
759
+ |------|------|---------|
760
+ | `content` | `ReactNode` | **required** |
761
+ | `children` | `ReactNode` | **required** |
762
+ | `side` | `"top" \| "right" \| "bottom" \| "left"` | `"top"` |
763
+ | `delayDuration` | `number` | `350` |
764
+
765
+ ---
766
+
767
+ #### `Popover`
768
+
769
+ Floating content panel. Use for filters, pickers, and inline forms.
770
+
771
+ ```tsx
772
+ <Popover
773
+ trigger={<Button variant="outline">Filter</Button>}
774
+ align="start"
775
+ >
776
+ <FilterForm />
777
+ </Popover>
778
+ ```
779
+
780
+ | Prop | Type | Default |
781
+ |------|------|---------|
782
+ | `trigger` | `ReactNode` | **required** |
783
+ | `children` | `ReactNode` | **required** |
784
+ | `align` | `"start" \| "center" \| "end"` | `"center"` |
785
+
786
+ ---
787
+
788
+ ### Data Display
789
+
790
+ ---
791
+
792
+ #### `Avatar`
793
+
794
+ User avatar with image, initials fallback, and online status.
795
+
796
+ ```tsx
797
+ <Avatar
798
+ src={user.avatarUrl}
799
+ name={user.fullName}
800
+ size="md"
801
+ status="online"
802
+ />
803
+ ```
804
+
805
+ | Prop | Type | Default |
806
+ |------|------|---------|
807
+ | `src` | `string` | — |
808
+ | `alt` | `string` | — |
809
+ | `name` | `string` | — |
810
+ | `size` | `"sm" \| "md" \| "lg"` | `"md"` |
811
+ | `status` | `"online" \| "busy" \| "offline"` | — |
812
+
813
+ > When `src` is absent, renders initials derived from `name`.
814
+
815
+ ---
816
+
817
+ #### `TablePagination`
818
+
819
+ Table page navigation. Handles ellipsis, edge pages, and optional page-size controls.
820
+
821
+ ```tsx
822
+ <TablePagination
823
+ page={currentPage}
824
+ totalPages={totalPages}
825
+ pageSize={pageSize}
826
+ onPageChange={setCurrentPage}
827
+ onPageSizeChange={setPageSize}
828
+ />
829
+ ```
830
+
831
+ | Prop | Type | Default |
832
+ |------|------|---------|
833
+ | `page` | `number` | **required** |
834
+ | `totalPages` | `number` | **required** |
835
+ | `onPageChange` | `(page: number) => void` | **required** |
836
+ | `pageSize` | `number` | — |
837
+ | `onPageSizeChange` | `(pageSize: number) => void` | — |
838
+
839
+ ---
840
+
841
+ #### `DataTable`
842
+
843
+ Generic data table with sorting, loading skeleton, row actions, selection, pagination, and empty/error states.
844
+
845
+ ```tsx
846
+ <DataTable
847
+ columns={[
848
+ { id: "name", header: "Name", accessorKey: "name", sortable: true },
849
+ { id: "status", header: "Status", cell: (row) => <Badge tone={row.status === "active" ? "success" : "neutral"}>{row.status}</Badge> },
850
+ ]}
851
+ data={orders}
852
+ loading={isLoading}
853
+ sorting={sorting}
854
+ onSortingChange={setSorting}
855
+ onRowClick={(row) => navigate(`/orders/${row.id}`)}
856
+ rowActions={(row) => (
857
+ <ActionMenu trigger={…} items={[…]} />
858
+ )}
859
+ emptyTitle="No orders found"
860
+ emptyDescription="Try adjusting your filters."
861
+ />
862
+ ```
863
+
864
+ | Prop | Type | Default |
865
+ |------|------|---------|
866
+ | `columns` | `DataTableColumn<T>[]` | **required** |
867
+ | `data` | `T[]` | **required** |
868
+ | `loading` | `boolean` | `false` |
869
+ | `enableSorting` | `boolean` | `true` |
870
+ | `sorting` | `{ columnId: string; direction: "asc" \| "desc" }` | — |
871
+ | `onSortingChange` | `(sorting) => void` | — |
872
+ | `enableColumnPinning` | `boolean` | `true` |
873
+ | `enableColumnReordering` | `boolean` | `true` |
874
+ | `onRowClick` | `(row: T) => void` | — |
875
+ | `rowActions` | `(row: T) => ReactNode` | — |
876
+ | `selection` | `boolean` | `false` |
877
+ | `density` | `"compact" \| "default" \| "comfortable"` | `"default"` |
878
+ | `emptyTitle` | `ReactNode` | `"No records found"` |
879
+ | `emptyDescription` | `ReactNode` | — |
880
+
881
+ `DataTableColumn<T>`:
882
+ ```ts
883
+ {
884
+ id: string;
885
+ header: ReactNode;
886
+ accessorKey?: keyof T;
887
+ accessorFn?: (row: T) => unknown;
888
+ sortable?: boolean;
889
+ cell?: (row: T) => ReactNode;
890
+ }
891
+ ```
892
+
893
+ `enableSorting`, `enableColumnPinning`, and `enableColumnReordering` are enabled by default. Pass `false` to disable each behavior for a simpler table.
894
+
895
+ When `loading` is true, `DataTable` renders built-in table-row skeleton placeholders rather than a spinner. The consumer app only owns the loading boolean.
896
+
897
+ ---
898
+
899
+ ### Navigation
900
+
901
+ ---
902
+
903
+ #### `Tabs`
904
+
905
+ Tabbed content switcher.
906
+
907
+ ```tsx
908
+ <Tabs
909
+ variant="line"
910
+ defaultValue="overview"
911
+ items={[
912
+ { value: "overview", label: "Overview", content: <Overview /> },
913
+ { value: "orders", label: "Orders", content: <Orders /> },
914
+ { value: "settings", label: "Settings", content: <Settings /> },
915
+ ]}
916
+ />
917
+ ```
918
+
919
+ | Prop | Type | Default |
920
+ |------|------|---------|
921
+ | `items` | `{ value: string; label: ReactNode; content: ReactNode }[]` | **required** |
922
+ | `variant` | `"line" \| "pill"` | `"line"` |
923
+ | `defaultValue` | `string` | — |
924
+ | `value` | `string` | — |
925
+ | `onValueChange` | `(value: string) => void` | — |
926
+
927
+ ---
928
+
929
+ #### `Breadcrumbs`
930
+
931
+ Navigation trail. Last item is rendered as plain text (current page).
932
+
933
+ ```tsx
934
+ <Breadcrumbs
935
+ items={[
936
+ { label: "Home", href: "/" },
937
+ { label: "Orders", href: "/orders" },
938
+ { label: "Order #1234" },
939
+ ]}
940
+ />
941
+ ```
942
+
943
+ | Prop | Type | Default |
944
+ |------|------|---------|
945
+ | `items` | `{ label: ReactNode; href?: string }[]` | **required** |
946
+
947
+ ---
948
+
949
+ ### Patterns
950
+
951
+ > Patterns are opinionated compositions for common full-page and feature-level layouts.
952
+
953
+ ---
954
+
955
+ #### `PageHeader`
956
+
957
+ Standardized page title section. Use at the top of every page.
958
+
959
+ ```tsx
960
+ <PageHeader
961
+ eyebrow="Orders"
962
+ title="All orders"
963
+ description="View and manage customer orders."
964
+ actions={<Button leftIcon={<Icon icon={Plus} />}>New order</Button>}
965
+ secondaryActions={<Button variant="outline">Export</Button>}
966
+ onBack={() => navigate(-1)}
967
+ />
968
+ ```
969
+
970
+ | Prop | Type | Default |
971
+ |------|------|---------|
972
+ | `title` | `ReactNode` | **required** |
973
+ | `eyebrow` | `ReactNode` | — |
974
+ | `description` | `ReactNode` | — |
975
+ | `onBack` | `() => void` | — |
976
+ | `actions` | `ReactNode` | — |
977
+ | `secondaryActions` | `ReactNode` | — |
978
+
979
+ ---
980
+
981
+ #### `LayoutShell`
982
+
983
+ Full-page app shell with sticky header and collapsible sidebar.
984
+
985
+ ```tsx
986
+ <LayoutShell
987
+ header={<AppHeader />}
988
+ sidebar={<SideNav />}
989
+ >
990
+ <Outlet />
991
+ </LayoutShell>
992
+ ```
993
+
994
+ | Prop | Type | Default |
995
+ |------|------|---------|
996
+ | `children` | `ReactNode` | **required** |
997
+ | `header` | `ReactNode` | — |
998
+ | `sidebar` | `ReactNode` | — |
999
+
1000
+ ---
1001
+
1002
+ #### `ChatBubble`
1003
+
1004
+ Chat message bubble. Renders differently for `user`, `assistant`, and `system` senders.
1005
+
1006
+ ```tsx
1007
+ <ChatBubble sender="assistant" timestamp="2:34 PM" loading={isStreaming}>
1008
+ Here's a summary of your recent orders…
1009
+ </ChatBubble>
1010
+
1011
+ <ChatBubble sender="user" timestamp="2:35 PM">
1012
+ Can you filter by last 7 days?
1013
+ </ChatBubble>
1014
+ ```
1015
+
1016
+ | Prop | Type | Default |
1017
+ |------|------|---------|
1018
+ | `sender` | `"user" \| "assistant" \| "system"` | **required** |
1019
+ | `children` | `ReactNode` | **required** |
1020
+ | `timestamp` | `ReactNode` | — |
1021
+ | `status` | `ReactNode` | — |
1022
+ | `loading` | `boolean` | `false` |
1023
+ | `errorAction` | `ReactNode` | — |
1024
+
1025
+ ---
1026
+
1027
+ #### `ChatComposer`
1028
+
1029
+ Chat input with attachment and action slots. Submits on `Ctrl+Enter`.
1030
+
1031
+ ```tsx
1032
+ <ChatComposer
1033
+ value={message}
1034
+ onValueChange={setMessage}
1035
+ onSubmit={handleSend}
1036
+ loading={isSending}
1037
+ placeholder="Ask me anything"
1038
+ attachmentSlot={<IconButton icon={<Icon icon={Paperclip} />} aria-label="Attach" />}
1039
+ />
1040
+ ```
1041
+
1042
+ | Prop | Type | Default |
1043
+ |------|------|---------|
1044
+ | `value` | `string` | **required** |
1045
+ | `onValueChange` | `(value: string) => void` | **required** |
1046
+ | `onSubmit` | `() => void` | — |
1047
+ | `loading` | `boolean` | `false` |
1048
+ | `disabled` | `boolean` | `false` |
1049
+ | `placeholder` | `string` | `"Ask me anything"` |
1050
+ | `attachmentSlot` | `ReactNode` | — |
1051
+ | `actionSlot` | `ReactNode` | — |
1052
+
1053
+ ---
1054
+
1055
+ #### `FullPageLoader`
1056
+
1057
+ Branded full-screen loading screen. Use during auth redirects and account setup.
1058
+
1059
+ ```tsx
1060
+ <FullPageLoader
1061
+ titlePrefix="Setting up your "
1062
+ titleHighlight="workspace"
1063
+ titleSuffix="…"
1064
+ description="This takes just a moment."
1065
+ statusLabel="Configuring account"
1066
+ />
1067
+ ```
1068
+
1069
+ | Prop | Type | Default |
1070
+ |------|------|---------|
1071
+ | `titlePrefix` | `ReactNode` | `"Your account is ready. I'll take you to your "` |
1072
+ | `titleHighlight` | `ReactNode` | `"dashboard"` |
1073
+ | `titleSuffix` | `ReactNode` | `" now."` |
1074
+ | `description` | `ReactNode` | `"Your account is being configured…"` |
1075
+ | `fullScreen` | `boolean` | `true` |
1076
+ | `statusLabel` | `string` | `"Loading account dashboard"` |
1077
+
1078
+ ---
1079
+
1080
+ #### `BusinessInfoDisplayCard`
1081
+
1082
+ Rich business identity card with header, logo, chips, and info sections.
1083
+
1084
+ ```tsx
1085
+ <BusinessInfoDisplayCard
1086
+ businessName="Acme Corp"
1087
+ initials="AC"
1088
+ chips={[{ label: "Verified", tone: "success" }]}
1089
+ sections={[
1090
+ {
1091
+ title: "Contact",
1092
+ items: [
1093
+ { label: "Email", value: "hello@acme.com" },
1094
+ { label: "Phone", value: "+91 98765 43210" },
1095
+ ],
1096
+ },
1097
+ ]}
1098
+ />
1099
+ ```
1100
+
1101
+ | Prop | Type | Default |
1102
+ |------|------|---------|
1103
+ | `businessName` | `ReactNode` | **required** |
1104
+ | `sections` | `BusinessInfoSection[]` | **required** |
1105
+ | `initials` | `string` | — |
1106
+ | `logoSrc` | `string` | — |
1107
+ | `logoAlt` | `string` | — |
1108
+ | `chips` | `{ label: string; tone?: Tone }[]` | — |
1109
+ | `background` | `string` | — |
1110
+ | `gradient` | `string` | — |
1111
+ | `headerBackground` | `string` | — |
1112
+ | `headerGradient` | `string` | — |
1113
+
1114
+ `BusinessInfoSection`:
1115
+ ```ts
1116
+ { title: string; items: { label: string; value: ReactNode }[] }
1117
+ ```
1118
+
1119
+ ---
1120
+
1121
+ #### `StepProgressCard`
1122
+
1123
+ Step-by-step progress indicator. Calculates `complete` / `current` / `upcoming` state automatically from `currentStep`.
1124
+
1125
+ ```tsx
1126
+ <StepProgressCard
1127
+ eyebrow="Onboarding"
1128
+ title="Let's get you set up"
1129
+ currentStep={1}
1130
+ animated
1131
+ steps={[
1132
+ { label: "Create account" },
1133
+ { label: "Verify email" },
1134
+ { label: "Add your first product" },
1135
+ ]}
1136
+ />
1137
+ ```
1138
+
1139
+ | Prop | Type | Default |
1140
+ |------|------|---------|
1141
+ | `steps` | `{ label: ReactNode; description?: ReactNode }[]` | **required** |
1142
+ | `currentStep` | `number` | `0` |
1143
+ | `eyebrow` | `ReactNode` | `"Account Summary"` |
1144
+ | `title` | `ReactNode` | `"Getting your details ready…"` |
1145
+ | `surface` | `"card" \| "plain"` | `"card"` |
1146
+ | `animated` | `boolean` | `true` |
1147
+
1148
+ ---
1149
+
1150
+ ## Common Patterns
1151
+
1152
+ ### Form with validation
1153
+
1154
+ ```tsx
1155
+ <Stack gap={4}>
1156
+ <FormField label="Full name" required errorText={errors.name}>
1157
+ <Input value={name} onChange={(e) => setName(e.target.value)} state={errors.name ? "error" : "default"} />
1158
+ </FormField>
1159
+
1160
+ <FormField label="Plan" required errorText={errors.plan}>
1161
+ <Select options={planOptions} value={plan} onValueChange={setPlan} error={!!errors.plan} />
1162
+ </FormField>
1163
+
1164
+ <Stack direction="row" gap={2} justify="flex-end">
1165
+ <Button variant="ghost">Cancel</Button>
1166
+ <Button loading={isSubmitting} onClick={handleSubmit}>Save</Button>
1167
+ </Stack>
1168
+ </Stack>
1169
+ ```
1170
+
1171
+ ### Table page
1172
+
1173
+ ```tsx
1174
+ <Container>
1175
+ <PageHeader
1176
+ title="Orders"
1177
+ actions={<Button leftIcon={<Icon icon={Plus} />}>New order</Button>}
1178
+ />
1179
+ <Card>
1180
+ <DataTable
1181
+ columns={columns}
1182
+ data={orders}
1183
+ loading={isLoading}
1184
+ sorting={sorting}
1185
+ onSortingChange={setSorting}
1186
+ pagination={{ page, totalPages, onPageChange: setPage }}
1187
+ />
1188
+ </Card>
1189
+ </Container>
1190
+ ```
1191
+
1192
+ ### Confirm delete dialog
1193
+
1194
+ ```tsx
1195
+ <ConfirmDialog
1196
+ open={showConfirm}
1197
+ onOpenChange={setShowConfirm}
1198
+ destructive
1199
+ title="Delete order?"
1200
+ description="This cannot be undone."
1201
+ confirmLabel="Delete"
1202
+ loading={isDeleting}
1203
+ onConfirm={handleDelete}
1204
+ />
1205
+ ```
1206
+
1207
+ ### Chat interface
1208
+
1209
+ ```tsx
1210
+ <LayoutShell header={<AppHeader />}>
1211
+ <Stack gap={0}>
1212
+ {messages.map((msg) => (
1213
+ <ChatBubble key={msg.id} sender={msg.sender} timestamp={msg.time}>
1214
+ {msg.text}
1215
+ </ChatBubble>
1216
+ ))}
1217
+ {isStreaming && <ChatBubble sender="assistant" loading />}
1218
+ </Stack>
1219
+ <ChatComposer
1220
+ value={input}
1221
+ onValueChange={setInput}
1222
+ onSubmit={sendMessage}
1223
+ loading={isStreaming}
1224
+ />
1225
+ </LayoutShell>
1226
+ ```
1227
+
1228
+ ---
1229
+
1230
+ ## What NOT to do
1231
+
1232
+ - Do not use raw Tailwind classes for spacing, color, or typography — use `Stack`, `Text`, and component props instead
1233
+ - Do not build custom modals, drawers, or dropdowns — use `Modal`, `ConfirmDialog`, `Drawer`, and `ActionMenu`
1234
+ - Do not render form labels manually — use `FormField` which wires aria attributes automatically
1235
+ - Do not use `<h1>`–`<h6>` or `<p>` directly — use `<Text variant="h1">` etc.
1236
+ - Do not add `loading` spinners manually — all interactive components accept a `loading` prop