@elabs-ai/components-ui 4.0.0 → 4.2.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 (339) hide show
  1. package/README.md +10 -8
  2. package/dist/chunk-FCH4ZN6G.js +57 -0
  3. package/dist/chunk-FCH4ZN6G.js.map +1 -0
  4. package/dist/form.d.ts +28 -0
  5. package/dist/form.js +123 -0
  6. package/dist/form.js.map +1 -0
  7. package/dist/index.d.ts +2597 -188
  8. package/dist/index.js +12855 -3578
  9. package/dist/index.js.map +1 -1
  10. package/dist/lib/cn.js +10 -1
  11. package/dist/lib/cn.js.map +1 -1
  12. package/package.json +21 -7
  13. package/src/__contract__/attribution-panel.contract.test.tsx +49 -0
  14. package/src/__contract__/badge.contract.test.tsx +49 -0
  15. package/src/__contract__/bounded-number.contract.test.tsx +49 -0
  16. package/src/__contract__/button.contract.test.tsx +49 -0
  17. package/src/__contract__/color-picker.contract.test.tsx +49 -0
  18. package/src/__contract__/combobox.contract.test.tsx +49 -0
  19. package/src/__contract__/command-trigger.contract.test.tsx +49 -0
  20. package/src/__contract__/copyable-value.contract.test.tsx +49 -0
  21. package/src/__contract__/date-picker.contract.test.tsx +49 -0
  22. package/src/__contract__/date-range-picker.contract.test.tsx +49 -0
  23. package/src/__contract__/empty-state.contract.test.tsx +49 -0
  24. package/src/__contract__/error-state.contract.test.tsx +49 -0
  25. package/src/__contract__/icon-button.contract.test.tsx +49 -0
  26. package/src/__contract__/input.contract.test.tsx +49 -0
  27. package/src/__contract__/key-value-editor.contract.test.tsx +49 -0
  28. package/src/__contract__/list-editor.contract.test.tsx +49 -0
  29. package/src/__contract__/loading-state.contract.test.tsx +49 -0
  30. package/src/__contract__/metric-card.contract.test.tsx +49 -0
  31. package/src/__contract__/model-picker.contract.test.tsx +49 -0
  32. package/src/__contract__/nav-notifications.contract.test.tsx +49 -0
  33. package/src/__contract__/number-input.contract.test.tsx +49 -0
  34. package/src/__contract__/rating.contract.test.tsx +49 -0
  35. package/src/__contract__/schema-form.contract.test.tsx +49 -0
  36. package/src/__contract__/section-header.contract.test.tsx +49 -0
  37. package/src/__contract__/segmented-field.contract.test.tsx +49 -0
  38. package/src/__contract__/slider-number.contract.test.tsx +49 -0
  39. package/src/__contract__/status-badge.contract.test.tsx +49 -0
  40. package/src/__contract__/tag-input.contract.test.tsx +49 -0
  41. package/src/__contract__/text.contract.test.tsx +49 -0
  42. package/src/__contract__/textarea.contract.test.tsx +49 -0
  43. package/src/__contract__/timeline.contract.test.tsx +49 -0
  44. package/src/__contract__/toggle.contract.test.tsx +49 -0
  45. package/src/__contract__/transfer.contract.test.tsx +49 -0
  46. package/src/__contract__/tree-select.contract.test.tsx +49 -0
  47. package/src/__contract__/tree.contract.test.tsx +49 -0
  48. package/src/__contract__/virtual-select.contract.test.tsx +49 -0
  49. package/src/__contract__/workspace-picker.contract.test.tsx +49 -0
  50. package/src/_peer-deps.test.ts +59 -0
  51. package/src/blocks-comparison-table.stories.tsx +2 -2
  52. package/src/components/accordion/accordion.tsx +13 -4
  53. package/src/components/advanced-group/advanced-group.tsx +1 -1
  54. package/src/components/alert/alert.tsx +15 -4
  55. package/src/components/alert-dialog/alert-dialog.test.tsx +32 -0
  56. package/src/components/alert-dialog/alert-dialog.tsx +28 -6
  57. package/src/components/app-shell/app-shell.stories.tsx +44 -2
  58. package/src/components/app-shell/app-shell.test.tsx +99 -0
  59. package/src/components/app-shell/app-shell.tsx +56 -4
  60. package/src/components/app-sidebar/app-sidebar.stories.tsx +9 -1
  61. package/src/components/attribution-panel/attribution-panel.tsx +3 -1
  62. package/src/components/attribution-panel/attributions.generated.ts +83 -79
  63. package/src/components/avatar/avatar.tsx +4 -1
  64. package/src/components/badge/badge.stories.tsx +8 -0
  65. package/src/components/badge/badge.test.tsx +8 -0
  66. package/src/components/badge/badge.tsx +15 -5
  67. package/src/components/bento-grid/bento-grid.test.tsx +24 -3
  68. package/src/components/bento-grid/bento-grid.tsx +11 -1
  69. package/src/components/bounded-number/bounded-number.test.tsx +1 -1
  70. package/src/components/bounded-number/bounded-number.tsx +78 -75
  71. package/src/components/breadcrumb/breadcrumb.stories.tsx +38 -0
  72. package/src/components/breadcrumb/breadcrumb.test.tsx +24 -1
  73. package/src/components/breadcrumb/breadcrumb.tsx +10 -4
  74. package/src/components/button/button.stories.tsx +116 -8
  75. package/src/components/button/button.tsx +18 -12
  76. package/src/components/button-group/button-group.tsx +1 -1
  77. package/src/components/calendar/calendar.tsx +3 -2
  78. package/src/components/card/card.stories.tsx +11 -6
  79. package/src/components/card/card.test.tsx +24 -2
  80. package/src/components/card/card.tsx +48 -7
  81. package/src/components/carousel/carousel.test.tsx +169 -0
  82. package/src/components/carousel/carousel.tsx +93 -32
  83. package/src/components/change-review/change-review.stories.tsx +145 -1
  84. package/src/components/change-review/change-review.test.tsx +143 -0
  85. package/src/components/change-review/change-review.tsx +214 -24
  86. package/src/components/checkbox/checkbox.tsx +2 -1
  87. package/src/components/collapsible-panel/use-collapsible-panel.ts +0 -3
  88. package/src/components/color-picker/color-picker.tsx +22 -15
  89. package/src/components/combobox/combobox.stories.tsx +10 -0
  90. package/src/components/combobox/combobox.test.tsx +54 -0
  91. package/src/components/combobox/combobox.tsx +25 -11
  92. package/src/components/command/command.stories.tsx +16 -6
  93. package/src/components/command/command.test.tsx +88 -0
  94. package/src/components/command/command.tsx +38 -13
  95. package/src/components/command/index.ts +1 -0
  96. package/src/components/command-trigger/command-trigger.stories.tsx +39 -0
  97. package/src/components/command-trigger/command-trigger.test.tsx +18 -0
  98. package/src/components/command-trigger/command-trigger.tsx +70 -0
  99. package/src/components/command-trigger/index.ts +1 -0
  100. package/src/components/context-menu/context-menu.tsx +16 -7
  101. package/src/components/context-rail/context-rail.stories.tsx +285 -0
  102. package/src/components/context-rail/context-rail.test.tsx +263 -0
  103. package/src/components/context-rail/context-rail.tsx +678 -0
  104. package/src/components/context-rail/index.ts +1 -0
  105. package/src/components/copyable-value/copyable-value.stories.tsx +10 -0
  106. package/src/components/copyable-value/copyable-value.test.tsx +28 -1
  107. package/src/components/copyable-value/copyable-value.tsx +13 -2
  108. package/src/components/date-picker/date-picker.stories.tsx +9 -0
  109. package/src/components/date-picker/date-picker.test.tsx +52 -0
  110. package/src/components/date-picker/date-picker.tsx +13 -15
  111. package/src/components/date-range-picker/date-range-picker.stories.tsx +9 -0
  112. package/src/components/date-range-picker/date-range-picker.test.tsx +76 -1
  113. package/src/components/date-range-picker/date-range-picker.tsx +39 -28
  114. package/src/components/descriptions/descriptions.tsx +1 -1
  115. package/src/components/dialog/dialog.test.tsx +8 -3
  116. package/src/components/dialog/dialog.tsx +14 -6
  117. package/src/components/drawer/drawer.tsx +23 -6
  118. package/src/components/dropdown-menu/dropdown-menu.stories.tsx +1 -1
  119. package/src/components/dropdown-menu/dropdown-menu.tsx +4 -4
  120. package/src/components/empty-state/empty-state.test.tsx +26 -0
  121. package/src/components/empty-state/empty-state.tsx +6 -1
  122. package/src/components/expand-dialog/expand-dialog.tsx +1 -2
  123. package/src/components/field/field-context.ts +59 -0
  124. package/src/components/field/field.stories.tsx +142 -0
  125. package/src/components/field/field.test.tsx +415 -0
  126. package/src/components/field/field.tsx +342 -0
  127. package/src/components/field/index.ts +9 -0
  128. package/src/components/field-row/field-row.stories.tsx +85 -1
  129. package/src/components/field-row/field-row.test.tsx +145 -0
  130. package/src/components/field-row/field-row.tsx +50 -6
  131. package/src/components/file-upload/file-upload.stories.tsx +16 -0
  132. package/src/components/file-upload/file-upload.test.tsx +90 -12
  133. package/src/components/file-upload/file-upload.tsx +164 -31
  134. package/src/components/form/form.tsx +8 -3
  135. package/src/components/hover-card/hover-card.tsx +1 -0
  136. package/src/components/icon-button/icon-button.test.tsx +1 -1
  137. package/src/components/icon-button/icon-button.tsx +3 -3
  138. package/src/components/input/input.stories.tsx +121 -0
  139. package/src/components/input/input.test.tsx +13 -0
  140. package/src/components/input/input.tsx +8 -4
  141. package/src/components/input-group/input-group.stories.tsx +74 -0
  142. package/src/components/input-group/input-group.tsx +18 -9
  143. package/src/components/input-otp/input-otp.tsx +8 -2
  144. package/src/components/keyboard-shortcuts/index.ts +6 -0
  145. package/src/components/keyboard-shortcuts/keyboard-shortcuts.stories.tsx +177 -0
  146. package/src/components/keyboard-shortcuts/keyboard-shortcuts.test.tsx +73 -0
  147. package/src/components/keyboard-shortcuts/keyboard-shortcuts.tsx +203 -0
  148. package/src/components/label/label.tsx +1 -1
  149. package/src/components/link-preview/link-preview.tsx +1 -1
  150. package/src/components/list-editor/list-editor.test.tsx +24 -0
  151. package/src/components/list-editor/list-editor.tsx +126 -52
  152. package/src/components/locale-provider/index.ts +6 -1
  153. package/src/components/locale-provider/locale-keys.test.ts +134 -0
  154. package/src/components/locale-provider/locale-provider.stories.tsx +89 -1
  155. package/src/components/locale-provider/locale-provider.test.tsx +257 -1
  156. package/src/components/locale-provider/locale-provider.tsx +63 -8
  157. package/src/components/locale-provider/messages.ts +822 -2
  158. package/src/components/match-highlight/match-highlight.stories.tsx +1 -1
  159. package/src/components/mention-input/mention-input-mirror.stories.tsx +9 -1
  160. package/src/components/mention-input/mention-input.stories.tsx +3 -3
  161. package/src/components/mention-input/mention-input.test.tsx +51 -1
  162. package/src/components/mention-input/mention-input.tsx +66 -46
  163. package/src/components/mention-input/mention-value.ts +8 -2
  164. package/src/components/menubar/menubar.tsx +16 -6
  165. package/src/components/metric-card/metric-card.stories.tsx +5 -3
  166. package/src/components/metric-card/metric-card.tsx +21 -2
  167. package/src/components/model-picker/model-picker.stories.tsx +63 -3
  168. package/src/components/model-picker/model-picker.test.tsx +63 -0
  169. package/src/components/model-picker/model-picker.tsx +62 -36
  170. package/src/components/nav-main/nav-main.tsx +8 -4
  171. package/src/components/nav-notifications/nav-notifications.stories.tsx +110 -0
  172. package/src/components/nav-notifications/nav-notifications.test.tsx +11 -0
  173. package/src/components/nav-notifications/nav-notifications.tsx +67 -9
  174. package/src/components/nav-user/nav-user.tsx +5 -5
  175. package/src/components/navigation-menu/navigation-menu.stories.tsx +22 -0
  176. package/src/components/navigation-menu/navigation-menu.test.tsx +174 -0
  177. package/src/components/navigation-menu/navigation-menu.tsx +204 -15
  178. package/src/components/number-input/number-input.stories.tsx +7 -3
  179. package/src/components/number-input/number-input.test.tsx +47 -0
  180. package/src/components/number-input/number-input.tsx +65 -24
  181. package/src/components/page-shell/page-shell.stories.tsx +163 -0
  182. package/src/components/page-shell/page-shell.test.tsx +229 -0
  183. package/src/components/page-shell/page-shell.tsx +108 -25
  184. package/src/components/pagination/pagination.test.tsx +109 -0
  185. package/src/components/pagination/pagination.tsx +27 -19
  186. package/src/components/popover/popover.tsx +1 -0
  187. package/src/components/progress/progress.tsx +2 -0
  188. package/src/components/radio-group/radio-group.tsx +1 -1
  189. package/src/components/rating/rating.tsx +3 -1
  190. package/src/components/resizable/resizable.stories.tsx +114 -2
  191. package/src/components/resizable/resizable.test.tsx +76 -0
  192. package/src/components/resizable/resizable.tsx +32 -6
  193. package/src/components/revision-timeline/revision-timeline.stories.tsx +8 -1
  194. package/src/components/revision-timeline/revision-timeline.test.tsx +26 -0
  195. package/src/components/revision-timeline/revision-timeline.tsx +53 -5
  196. package/src/components/schema-form/from-json-schema.test.ts +390 -0
  197. package/src/components/schema-form/from-json-schema.ts +375 -0
  198. package/src/components/schema-form/index.ts +81 -0
  199. package/src/components/schema-form/schema-form-spec.ts +698 -0
  200. package/src/components/schema-form/schema-form-store.ts +506 -0
  201. package/src/components/schema-form/schema-form.stories.tsx +566 -0
  202. package/src/components/schema-form/schema-form.test.tsx +1021 -0
  203. package/src/components/schema-form/schema-form.tsx +1381 -0
  204. package/src/components/section-header/section-header.stories.tsx +37 -0
  205. package/src/components/section-header/section-header.tsx +14 -3
  206. package/src/components/select/select.tsx +13 -7
  207. package/src/components/separator/separator.tsx +1 -0
  208. package/src/components/sheet/sheet.test.tsx +39 -0
  209. package/src/components/sheet/sheet.tsx +40 -9
  210. package/src/components/side-dock/index.ts +1 -0
  211. package/src/components/side-dock/side-dock.stories.tsx +137 -0
  212. package/src/components/side-dock/side-dock.test.tsx +299 -0
  213. package/src/components/side-dock/side-dock.tsx +515 -0
  214. package/src/components/sidebar/index.ts +1 -0
  215. package/src/components/sidebar/sidebar-frame.test.tsx +162 -0
  216. package/src/components/sidebar/sidebar.stories.tsx +421 -1
  217. package/src/components/sidebar/sidebar.test.tsx +71 -2
  218. package/src/components/sidebar/sidebar.tsx +264 -38
  219. package/src/components/skeleton/skeleton.tsx +1 -0
  220. package/src/components/skip-link/index.ts +1 -0
  221. package/src/components/skip-link/skip-link.stories.tsx +106 -0
  222. package/src/components/skip-link/skip-link.test.tsx +20 -0
  223. package/src/components/skip-link/skip-link.tsx +34 -0
  224. package/src/components/slider/slider.tsx +1 -1
  225. package/src/components/slider-number/slider-number.stories.tsx +4 -1
  226. package/src/components/slider-number/slider-number.test.tsx +1 -1
  227. package/src/components/sonner/sonner.tsx +2 -0
  228. package/src/components/spinner/spinner.test.tsx +18 -0
  229. package/src/components/spinner/spinner.tsx +14 -4
  230. package/src/components/split-panel/index.ts +6 -1
  231. package/src/components/split-panel/split-panel.stories.tsx +18 -2
  232. package/src/components/split-panel/split-panel.test.tsx +20 -0
  233. package/src/components/split-panel/split-panel.tsx +28 -8
  234. package/src/components/state-panel/state-panel.stories.tsx +52 -0
  235. package/src/components/state-panel/state-panel.test.tsx +125 -0
  236. package/src/components/state-panel/state-panel.tsx +110 -24
  237. package/src/components/status-badge/status-badge.stories.tsx +8 -0
  238. package/src/components/switch/switch.tsx +3 -1
  239. package/src/components/table/table.stories.tsx +64 -0
  240. package/src/components/table/table.test.tsx +149 -1
  241. package/src/components/table/table.tsx +71 -2
  242. package/src/components/tabs/index.ts +10 -1
  243. package/src/components/tabs/tabs.stories.tsx +48 -0
  244. package/src/components/tabs/tabs.test.tsx +67 -0
  245. package/src/components/tabs/tabs.tsx +176 -72
  246. package/src/components/tag-input/tag-input.tsx +6 -3
  247. package/src/components/team-switcher/team-switcher.tsx +35 -6
  248. package/src/components/textarea/textarea.tsx +2 -2
  249. package/src/components/theme-switcher/theme-switcher.stories.tsx +76 -0
  250. package/src/components/theme-switcher/theme-switcher.test.tsx +182 -0
  251. package/src/components/theme-switcher/theme-switcher.tsx +140 -12
  252. package/src/components/theme-switcher/use-theme-transition.ts +2 -2
  253. package/src/components/timeline/timeline.stories.tsx +27 -0
  254. package/src/components/timeline/timeline.tsx +10 -3
  255. package/src/components/toggle/toggle.tsx +7 -2
  256. package/src/components/toggle-group/toggle-group.tsx +2 -0
  257. package/src/components/toolbar/toolbar.stories.tsx +10 -2
  258. package/src/components/tooltip/tooltip.tsx +2 -1
  259. package/src/components/top-nav/top-nav.tsx +1 -1
  260. package/src/components/transfer/transfer.tsx +35 -30
  261. package/src/components/tree/tree.stories.tsx +2 -2
  262. package/src/components/tree/tree.test.tsx +41 -0
  263. package/src/components/tree/tree.tsx +91 -31
  264. package/src/components/tree/use-tree-keyboard.ts +37 -14
  265. package/src/components/tree-select/tree-select.stories.tsx +9 -0
  266. package/src/components/tree-select/tree-select.test.tsx +5 -0
  267. package/src/components/tree-select/tree-select.tsx +11 -14
  268. package/src/components/typography/prose.test.tsx +3 -2
  269. package/src/components/typography/prose.tsx +3 -3
  270. package/src/components/typography/typography.stories.tsx +228 -0
  271. package/src/components/view-toolbar/view-toolbar.stories.tsx +41 -1
  272. package/src/components/view-toolbar/view-toolbar.test.tsx +33 -0
  273. package/src/components/view-toolbar/view-toolbar.tsx +37 -4
  274. package/src/components/virtual-select/virtual-select.stories.tsx +9 -0
  275. package/src/components/virtual-select/virtual-select.test.tsx +29 -3
  276. package/src/components/virtual-select/virtual-select.tsx +56 -18
  277. package/src/components/wizard/wizard.test.tsx +9 -0
  278. package/src/components/wizard/wizard.tsx +13 -5
  279. package/src/components/workspace-picker/index.ts +3 -0
  280. package/src/components/workspace-picker/workspace-picker-state.ts +50 -0
  281. package/src/components/workspace-picker/workspace-picker.stories.tsx +126 -0
  282. package/src/components/workspace-picker/workspace-picker.test.tsx +207 -0
  283. package/src/components/workspace-picker/workspace-picker.tsx +172 -0
  284. package/src/illustrations/empty-list-illustration.tsx +26 -0
  285. package/src/illustrations/error-illustration.tsx +60 -0
  286. package/src/illustrations/first-run-illustration.tsx +27 -0
  287. package/src/illustrations/illustration-base.tsx +108 -0
  288. package/src/illustrations/illustrations.stories.tsx +94 -0
  289. package/src/illustrations/illustrations.test.tsx +98 -0
  290. package/src/illustrations/index.ts +16 -0
  291. package/src/illustrations/no-access-illustration.tsx +45 -0
  292. package/src/illustrations/no-results-illustration.tsx +46 -0
  293. package/src/illustrations/offline-illustration.tsx +37 -0
  294. package/src/illustrations/success-illustration.tsx +40 -0
  295. package/src/index.ts +80 -2
  296. package/src/lib/agent-event-model.test.ts +12 -0
  297. package/src/lib/agent-event-model.ts +42 -0
  298. package/src/lib/approval-option.test.ts +17 -0
  299. package/src/lib/approval-option.ts +53 -0
  300. package/src/lib/check-result.ts +33 -0
  301. package/src/lib/cn.ts +9 -0
  302. package/src/lib/csv.ts +48 -0
  303. package/src/lib/diff-line.test.ts +36 -0
  304. package/src/lib/diff-line.ts +63 -0
  305. package/src/lib/diff-rows.test.ts +76 -0
  306. package/src/lib/diff-rows.ts +94 -0
  307. package/src/lib/format-duration.test.ts +22 -0
  308. package/src/lib/format-duration.ts +30 -0
  309. package/src/lib/has-renderable-content.test.ts +49 -0
  310. package/src/lib/has-renderable-content.ts +32 -0
  311. package/src/lib/merge-refs.ts +2 -0
  312. package/src/lib/operating-mode.test.ts +36 -0
  313. package/src/lib/operating-mode.ts +81 -0
  314. package/src/lib/optional-peer.ts +59 -0
  315. package/src/lib/session-launch.ts +37 -0
  316. package/src/lib/slash-command.test.ts +44 -0
  317. package/src/lib/slash-command.ts +45 -0
  318. package/src/lib/trigger-query.test.ts +94 -0
  319. package/src/lib/trigger-query.ts +88 -0
  320. package/src/lib/use-controllable-state.ts +47 -0
  321. package/src/lib/use-mobile.test.tsx +47 -0
  322. package/src/lib/use-mobile.ts +34 -12
  323. package/src/motion.stories.tsx +6 -0
  324. package/src/templates-object-detail-hub.stories.tsx +2 -2
  325. package/src/templates-screen-states.stories.tsx +5 -5
  326. package/src/templates-settings.stories.tsx +1 -1
  327. package/src/blocks/sidebar-02/app-sidebar.tsx +0 -160
  328. package/src/blocks/sidebar-02/logo.tsx +0 -18
  329. package/src/blocks/sidebar-02/nav-main.tsx +0 -13
  330. package/src/blocks/sidebar-02/nav-notifications.tsx +0 -7
  331. package/src/blocks/sidebar-02/sidebar-02.stories.tsx +0 -23
  332. package/src/blocks/sidebar-02/team-switcher.tsx +0 -7
  333. package/src/blocks/sidebar-04/app-sidebar.tsx +0 -236
  334. package/src/blocks/sidebar-04/mail-context.tsx +0 -29
  335. package/src/blocks/sidebar-04/nav-user.tsx +0 -6
  336. package/src/blocks/sidebar-04/sidebar-04.stories.tsx +0 -150
  337. package/src/blocks/sidebar-05/app-sidebar.tsx +0 -375
  338. package/src/blocks/sidebar-05/sidebar-05.stories.tsx +0 -18
  339. package/src/blocks/sidebar-05/team-switcher.tsx +0 -6
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { ClassValue } from 'clsx';
2
2
  import { LucideIcon, LucideProps } from 'lucide-react';
3
3
  import * as react from 'react';
4
- import react__default, { HTMLAttributes, ReactNode, InputHTMLAttributes, ButtonHTMLAttributes, ComponentProps, ComponentPropsWithoutRef, ReactElement, TextareaHTMLAttributes, TdHTMLAttributes, ThHTMLAttributes, LiHTMLAttributes, AnchorHTMLAttributes, OlHTMLAttributes } from 'react';
5
- import * as AccordionPrimitive from '@radix-ui/react-accordion';
4
+ import react__default, { ReactNode, HTMLAttributes, SVGProps, InputHTMLAttributes, ButtonHTMLAttributes, ComponentProps, ComponentPropsWithoutRef, ReactElement, TextareaHTMLAttributes, ForwardRefExoticComponent, RefAttributes, TdHTMLAttributes, ThHTMLAttributes, LiHTMLAttributes, AnchorHTMLAttributes, OlHTMLAttributes } from 'react';
6
5
  import * as class_variance_authority_types from 'class-variance-authority/types';
7
- import * as _radix_ui_react_separator from '@radix-ui/react-separator';
8
6
  import { VariantProps } from 'class-variance-authority';
7
+ import * as AccordionPrimitive from '@radix-ui/react-accordion';
8
+ import * as _radix_ui_react_separator from '@radix-ui/react-separator';
9
9
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
10
10
  import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
11
11
  import * as AspectRatioPrimitive from '@radix-ui/react-aspect-ratio';
@@ -21,10 +21,7 @@ import * as ContextMenuPrimitive from '@radix-ui/react-context-menu';
21
21
  import * as vaul from 'vaul';
22
22
  import { Drawer as Drawer$1 } from 'vaul';
23
23
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
24
- import * as _radix_ui_react_slot from '@radix-ui/react-slot';
25
24
  import * as _radix_ui_react_label from '@radix-ui/react-label';
26
- import * as react_hook_form from 'react-hook-form';
27
- import { FieldValues, FieldPath, ControllerProps } from 'react-hook-form';
28
25
  import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
29
26
  import * as input_otp from 'input-otp';
30
27
  import * as PopoverPrimitive from '@radix-ui/react-popover';
@@ -34,6 +31,7 @@ import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu';
34
31
  import * as ProgressPrimitive from '@radix-ui/react-progress';
35
32
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
36
33
  import * as ResizablePrimitive from 'react-resizable-panels';
34
+ import { z } from 'zod';
37
35
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
38
36
  import * as SelectPrimitive from '@radix-ui/react-select';
39
37
  import * as SliderPrimitive from '@radix-ui/react-slider';
@@ -54,8 +52,14 @@ import { Virtualizer } from '@tanstack/react-virtual';
54
52
  */
55
53
  declare function cn(...inputs: ClassValue[]): string;
56
54
 
57
- /** Returns true when the viewport is below the mobile breakpoint (768px). */
58
- declare function useIsMobile(): boolean;
55
+ /**
56
+ * Returns true when the viewport is below `breakpoint` (default 768px, the
57
+ * mobile breakpoint). Additive optional argument (ADR 0035 §5) — every
58
+ * existing zero-arg call site is unchanged. A caller with its own threshold
59
+ * (e.g. `ContextRail`'s `overlayBreakpoint`) passes it directly instead of a
60
+ * second hook.
61
+ */
62
+ declare function useIsMobile(breakpoint?: number): boolean;
59
63
 
60
64
  /**
61
65
  * Browser file-download helpers — the single home for the
@@ -86,6 +90,25 @@ declare function downloadBlob(blob: Blob, filename: string): void;
86
90
  */
87
91
  declare function downloadUrl(url: string, filename?: string): Promise<void>;
88
92
 
93
+ /**
94
+ * Shared CSV (RFC 4180) primitives — value stringification + injection-guarded
95
+ * field quoting. Pure, no DOM, SSR-safe.
96
+ *
97
+ * The single home for logic previously duplicated between `@elabs-ai/components-data`'s
98
+ * `toCsv` and `@elabs-ai/components-charts`'s `ChartFrame` local serializer (charts may not
99
+ * depend on data per the one-way package rule, so both import this instead of
100
+ * one importing the other).
101
+ */
102
+ /** Stringify a cell value for CSV: dates → ISO, objects → JSON, else `String()`. */
103
+ declare function csvStringifyValue(value: unknown): string;
104
+ /**
105
+ * Quote/escape one CSV field: prefixes a leading `'` when the field starts
106
+ * with a formula-trigger character and is not a plain number (CSV-injection
107
+ * guard), then RFC-4180-quotes when it contains the delimiter, a double
108
+ * quote, or a line break.
109
+ */
110
+ declare function csvQuoteField(field: string, delimiter: string): string;
111
+
89
112
  /** How long the transient "copied" state stays true before it resets. */
90
113
  declare const COPY_FEEDBACK_MS = 1500;
91
114
  interface UseCopyToClipboardOptions {
@@ -505,6 +528,642 @@ type StreamdownTranslationMap = Record<StreamdownTranslationKey, string>;
505
528
  */
506
529
  declare function useStreamdownTranslations(): StreamdownTranslationMap;
507
530
 
531
+ /**
532
+ * One verification verdict about an action — a linter, a type check, a test run,
533
+ * a policy hook. Shared vocabulary across packages: `ChangeReview` (#112) shows the
534
+ * checks a proposed edit already passed, `AgentEvent` (#109) shows the checks a
535
+ * runtime hook ran around a tool call. One runtime concept, one shape.
536
+ *
537
+ * Presentational only (D5): this type records a verdict someone else computed.
538
+ * Nothing in brand-ui ever runs a check.
539
+ *
540
+ * Rendering contract, binding on every consumer: `ok` must reach the user through
541
+ * an ICON and ACCESSIBLE TEXT, never through colour alone — the greyscale test in
542
+ * `.claude/rules/accessibility.md`.
543
+ */
544
+ interface CheckResult {
545
+ /** What ran, verbatim as the runtime names it: "eslint", "tsc", "pre_tool_use". */
546
+ label: string;
547
+ /** Did it pass? The verdict; the only required field besides `label`. */
548
+ ok: boolean;
549
+ /** One line of explanation. Renders as a secondary line, collapsed when long. */
550
+ detail?: string;
551
+ /** Wall-clock duration in milliseconds. Format with `formatElapsed`. */
552
+ durationMs?: number;
553
+ /** When it ran relative to the action it gates. Groups results into sections. */
554
+ phase?: "before" | "after";
555
+ }
556
+ /** A count summary, when the individual verdicts are not available. */
557
+ interface CheckSummary {
558
+ /** How many checks ran. */
559
+ ran: number;
560
+ /** How many of them passed. `passed <= ran`. */
561
+ passed: number;
562
+ }
563
+
564
+ /**
565
+ * Human-readable elapsed time — one formatter for every "how long did this take"
566
+ * surface in the system: `TurnStatus`'s running turn (#105), `ChangeReview`'s check
567
+ * rows (#112), `AgentEvent`'s hook durations (#109).
568
+ *
569
+ * Exported so a consumer's own elapsed-time surfaces agree with ours.
570
+ * Adapted from `brainless`'s turn-status elapsed formatter (MIT, see `ATTRIBUTION.md`).
571
+ *
572
+ * Rungs: sub-second → "420ms" · under ten seconds → "8.0s" · under a minute → "45s" ·
573
+ * beyond → "2m05s".
574
+ */
575
+ declare function formatElapsed(elapsedMs: number): string;
576
+
577
+ /** True when a raw error MESSAGE names a module the runtime could not load. */
578
+ declare function isModuleNotFoundMessage(message: string): boolean;
579
+ /**
580
+ * True when `value` is (or looks like) a failed dynamic `import()` of a
581
+ * missing optional peer. Accepts anything a `.catch()` or an error boundary
582
+ * might see: an `Error` instance (checked by `code` first, then message), or
583
+ * `undefined`/other for anything that clearly is not one.
584
+ */
585
+ declare function isOptionalPeerMissing(value: unknown): boolean;
586
+
587
+ /**
588
+ * The generic, component-agnostic half of a trigger-driven inline palette —
589
+ * "is the caret sitting inside a `trigger + query` run, and how do I splice a
590
+ * chosen result back in". Zero React, zero DOM, zero knowledge of mentions.
591
+ *
592
+ * Lifted out of `MentionInput`'s private `findQuery`/`isWordBoundary`
593
+ * (docs/decisions/2026-09-01-brainless-adoption-architecture.md § 5) so a second
594
+ * trigger-driven surface (a slash-command palette) reuses the algorithm instead
595
+ * of re-implementing it. `MentionInput` consumes this module unchanged — see
596
+ * `mention-input.tsx`.
597
+ */
598
+ /**
599
+ * Where a trigger character is allowed to START a query.
600
+ *
601
+ * `"word"` — index 0, or preceded by whitespace / "(" / "[". (`MentionInput`'s
602
+ * behaviour, unchanged — an "@" inside an email address must not open a popup.)
603
+ * `"line-start"` — index 0, or preceded by "\n". (A slash palette: "/help" opens, "cd /usr" does not.)
604
+ */
605
+ type TriggerBoundary = "word" | "line-start";
606
+ /** An in-progress `trigger + query` run under the caret. */
607
+ interface TriggerQuery {
608
+ /** Offset of the trigger character in `text`. */
609
+ start: number;
610
+ /** The query WITHOUT the trigger character. */
611
+ query: string;
612
+ }
613
+ interface FindTriggerQueryOptions {
614
+ /** @default "word" */
615
+ boundary?: TriggerBoundary;
616
+ /**
617
+ * Veto a candidate whose trigger character has already been consumed by a
618
+ * committed token — `MentionInput` passes `mentionAt(...)` here so an
619
+ * inserted "@Ada Lovelace" cannot re-open the popup. Omit when there are no
620
+ * committed tokens (a slash palette has none).
621
+ */
622
+ isTriggerConsumed?: (start: number) => boolean;
623
+ }
624
+ /**
625
+ * Is the caret sitting inside a `trigger + query` run?
626
+ *
627
+ * DERIVED from committed text + caret, never intercepted at keydown — a
628
+ * keydown-driven trigger must `preventDefault()` every printable character and
629
+ * re-insert it by hand, which destroys IME composition, native undo, spellcheck
630
+ * and paste. Deriving means the popup opens identically whether the trigger
631
+ * arrived by typing, pasting, an IME commit, or a click that moved the caret
632
+ * back into a half-typed query.
633
+ */
634
+ declare function findTriggerQuery(text: string, caret: number, trigger: string, options?: FindTriggerQueryOptions): TriggerQuery | null;
635
+ /** The plain-text half of an insert: splice `insertText` over the run, and say where the caret lands. */
636
+ declare function replaceTriggerRun(text: string, queryStart: number, caret: number, insertText: string): {
637
+ text: string;
638
+ caret: number;
639
+ };
640
+
641
+ /**
642
+ * The command model behind a `/`-triggered slash-command palette
643
+ * (`PromptInputSlash` in `@elabs-ai/components-ai`, and the terminal CLI
644
+ * look-alike family's own palette — issue #117).
645
+ *
646
+ * Promoted here (not duplicated) because `@elabs-ai/components-ai` and
647
+ * `@elabs-ai/components-terminal` are layer-2 DAG SIBLINGS and may not import
648
+ * each other — `ui` is upstream of both, so this is the one legal shared home
649
+ * (docs/decisions/2026-09-01-brainless-adoption-architecture.md § 4, the
650
+ * promotion rule: "a helper shared by two layer-2 siblings moves UP to `ui`,
651
+ * it is never duplicated sideways"). No DOM, no keyboard wiring, no rendering
652
+ * — the popover, the caret tracking and the row markup stay in each
653
+ * package's own presentational component.
654
+ */
655
+
656
+ /** One entry a slash palette offers. Ships no vocabulary — entirely prop-driven. */
657
+ interface SlashCommand {
658
+ /** Stable name, WITHOUT the leading "/" (e.g. `"help"`, not `"/help"`). */
659
+ name: string;
660
+ /** One line shown next to the name. */
661
+ description?: string;
662
+ /** Extra prefix-match aids beyond `name` (matched case-insensitively). */
663
+ keywords?: string[];
664
+ /** Leading glyph. Decorative — the row is identified by `name`. */
665
+ icon?: ReactNode;
666
+ }
667
+ /**
668
+ * Case-insensitive PREFIX match on `name`, falling back to a prefix match on
669
+ * any `keyword`. Prefix (not substring) is deliberate: `/hel` should surface
670
+ * `/help`, not e.g. a hypothetical `/channel`.
671
+ */
672
+ declare function defaultSlashCommandFilter(command: SlashCommand, query: string): boolean;
673
+ /** Next index in `[0, count)`, wrapping at both ends. `-1` when `count` is 0. */
674
+ declare function stepIndex(count: number, from: number, direction: 1 | -1): number;
675
+
676
+ /**
677
+ * The N-option, scoped-approval model behind `ApprovalCardOptions`
678
+ * (`@elabs-ai/components-ai`'s `confirmation.tsx`, #103) and the terminal CLI
679
+ * look-alike family's own permission row (issue #117) — a real coding-agent
680
+ * permission prompt is rarely a plain yes/no; it asks an N-option question
681
+ * whose options encode SCOPE ("Yes", "Yes, and don't ask again this
682
+ * session", "No, and tell the agent what to do instead").
683
+ *
684
+ * Promoted here (not duplicated) because `@elabs-ai/components-ai` and
685
+ * `@elabs-ai/components-terminal` are layer-2 DAG SIBLINGS and may not import
686
+ * each other — `ui` is upstream of both
687
+ * (docs/decisions/2026-09-01-brainless-adoption-architecture.md § 4). The
688
+ * SYMBOLS have zero SDK coupling; only their previous host module
689
+ * (`confirmation.tsx`) imports `ai`'s `ToolUIPart`, so only the vocabulary —
690
+ * never the component — moves.
691
+ */
692
+ /**
693
+ * How far a chosen option's permission reaches. Deliberately a closed,
694
+ * app-agnostic vocabulary (not a free string) so a consumer can derive an
695
+ * accessible fallback description per option (see
696
+ * `APPROVAL_SCOPE_DESCRIPTION_KEYS` below) — the one thing every option of a
697
+ * given scope always means, regardless of the agent-specific label wording.
698
+ */
699
+ type ApprovalScope = "once" | "session" | "always" | "deny";
700
+ interface ApprovalOption {
701
+ id: string;
702
+ label: string;
703
+ /**
704
+ * What choosing this option actually does. Optional: when omitted, the
705
+ * consumer renders a scope-derived sentence instead, so scope always
706
+ * reaches assistive tech through real text — never only through colour or
707
+ * a `data-*` attribute (WCAG 1.4.1).
708
+ */
709
+ description?: string;
710
+ scope: ApprovalScope;
711
+ /** Optional key hint shown beside the option, e.g. "1". */
712
+ keyHint?: string;
713
+ }
714
+ /**
715
+ * The locale-message KEY (not the translated text — `ui`'s locale catalogue,
716
+ * `components/locale-provider/messages.ts`, holds the English fallback and
717
+ * every other locale's translation) for the scope-derived sentence used only
718
+ * when `option.description` is omitted.
719
+ */
720
+ declare const APPROVAL_SCOPE_DESCRIPTION_KEYS: Record<ApprovalScope, string>;
721
+
722
+ /**
723
+ * The unified-diff line model behind `DiffView` (`@elabs-ai/components-ai`,
724
+ * #102) and the terminal CLI look-alike family's own diff hunk (issue #117).
725
+ *
726
+ * Promoted here (not duplicated) because `@elabs-ai/components-ai` and
727
+ * `@elabs-ai/components-terminal` are layer-2 DAG SIBLINGS and may not import
728
+ * each other — `ui` is upstream of both
729
+ * (docs/decisions/2026-09-01-brainless-adoption-architecture.md § 4). This
730
+ * module is the shiki-free half: the line shape, the marker glyph and the
731
+ * screen-reader polarity label. Intra-line syntax highlighting (Shiki) and
732
+ * the diff's presentational chrome stay in `@elabs-ai/components-ai`'s
733
+ * `diff-view.tsx` — `ui` does not depend on Shiki and never will for one
734
+ * component (see the decision doc § 3).
735
+ *
736
+ * The `DiffLine` model and the polarity-prefix technique are adapted from
737
+ * `theswerd/brainless` (MIT) — see `ATTRIBUTION.md`.
738
+ */
739
+ /** What role a line plays in the diff. */
740
+ type DiffLineType = "add" | "del" | "context" | "hunk" | "meta";
741
+ /** One line of a unified diff. Absent gutter numbers are load-bearing (see below). */
742
+ interface DiffLine {
743
+ type: DiffLineType;
744
+ /** Line number in the original file. Absent on `add` — there is no old line. */
745
+ oldNumber?: number;
746
+ /** Line number in the new file. Absent on `del` — there is no new line. */
747
+ newNumber?: number;
748
+ /** The line's text, without its leading `+` / `-` / ` ` marker. */
749
+ text: string;
750
+ }
751
+ /**
752
+ * The single-character marker glyph for a real source line (`add`/`del`/
753
+ * `context`). `hunk`/`meta` lines are diff headers, not source, and render
754
+ * through a full-width row instead — this returns `""` for them.
755
+ */
756
+ declare function diffLineMarker(type: DiffLineType): string;
757
+ /**
758
+ * The `ui` locale-message KEY (not the translated text) for the `sr-only`
759
+ * screen-reader polarity word an `add`/`del` row carries ALONGSIDE its marker
760
+ * glyph and its fill tint — colour is never the only channel (WCAG 1.4.1).
761
+ * `undefined` for `context`/`hunk`/`meta`, which carry no polarity.
762
+ */
763
+ declare function diffLineAccessibleLabel(type: DiffLineType): "ai.diffView.addedLine" | "ai.diffView.removedLine" | undefined;
764
+
765
+ /**
766
+ * One rendered row: either a real diff line, or a collapsed run of
767
+ * consecutive `context` lines longer than the caller's `contextLines`.
768
+ */
769
+ type DiffRow = {
770
+ kind: "line";
771
+ line: DiffLine;
772
+ index: number;
773
+ } | {
774
+ kind: "collapsed";
775
+ runStart: number;
776
+ hiddenCount: number;
777
+ };
778
+ /**
779
+ * Collapse long runs of consecutive `context` lines behind a single
780
+ * `"collapsed"` row, keeping `Math.ceil(contextLines / 2)` lines of context
781
+ * at the top of the run and `Math.floor(contextLines / 2)` at the bottom —
782
+ * so a reader always sees context on both sides of a hidden gap. A run
783
+ * already in `expanded` (by its start index) renders in full instead.
784
+ *
785
+ * Pure: no state, no effect. `useDiffRows` below is the stateful wrapper
786
+ * that owns the `expanded` set for a component.
787
+ */
788
+ declare function collapseDiffRows(lines: DiffLine[], contextLines: number | undefined, expanded?: ReadonlySet<number>): DiffRow[];
789
+ /**
790
+ * Stateful wrapper around `collapseDiffRows`: owns the set of run-start
791
+ * indices a caller has expanded via the "show more" control, and returns the
792
+ * current row list alongside an `expand` action.
793
+ */
794
+ declare function useDiffRows(lines: DiffLine[], contextLines: number | undefined): {
795
+ rows: DiffRow[];
796
+ expand: (runStart: number) => void;
797
+ };
798
+
799
+ /**
800
+ * The operating-mode and reasoning-effort vocabulary behind
801
+ * `PromptInputMode`/`PromptInputEffort` (`@elabs-ai/components-ai`, #104/#107)
802
+ * and the terminal CLI look-alike family's own composer chips (issue #117).
803
+ *
804
+ * Promoted here (not duplicated) because `@elabs-ai/components-ai` and
805
+ * `@elabs-ai/components-terminal` are layer-2 DAG SIBLINGS and may not import
806
+ * each other — `ui` is upstream of both
807
+ * (docs/decisions/2026-09-01-brainless-adoption-architecture.md § 4). Both
808
+ * types are caller-supplied vocabulary objects — never a vendor union — which
809
+ * #117 requires: no vendor mode/effort union may appear in a public type.
810
+ */
811
+
812
+ /**
813
+ * One app-defined operating mode — how autonomously the agent may act while
814
+ * this mode is active. `brand-ui` ships no vocabulary: `id`/`label` are
815
+ * entirely the consumer's (e.g. `"auto"`/`"Auto"`, `"plan"`/`"Plan first"`,
816
+ * or a completely different product's own terms).
817
+ */
818
+ interface OperatingMode {
819
+ /** Stable identifier — round-trips through `value`/`onValueChange`. */
820
+ id: string;
821
+ /** Visible + accessible name. */
822
+ label: string;
823
+ /** One line of guidance shown under the label in the menu. */
824
+ description?: string;
825
+ /** A shortcut hint rendered as a `Kbd` chip next to the label (e.g. `"⇧ Tab"`). */
826
+ keyHint?: string;
827
+ /** Leading glyph. Decorative — the mode is identified by `label`, not the icon. */
828
+ icon?: ReactNode;
829
+ }
830
+ /**
831
+ * One rung of an app-defined reasoning-effort scale. `brand-ui` ships no
832
+ * vocabulary: `id`/`label` are entirely the consumer's (e.g.
833
+ * `"low"`/`"Low"` … `"max"`/`"Max"`, or a completely different product's own
834
+ * terms and however many rungs it wants).
835
+ */
836
+ interface EffortLevel {
837
+ /** Stable identifier — round-trips through `value`/`onValueChange`. */
838
+ id: string;
839
+ /** Visible + accessible name for this rung. */
840
+ label: string;
841
+ }
842
+ /**
843
+ * Growing-square size rungs (Tailwind's own spacing scale — `size-2.5` through
844
+ * `size-6`), indexed by ordinal position so a caller never invents a raw
845
+ * pixel value. All in ONE `tailwind-merge` class group (`size`), so
846
+ * overriding a base size class is a guaranteed, order-independent swap
847
+ * rather than a `w-*`/`h-*` vs `size-*` conflict tailwind-merge can't see.
848
+ */
849
+ declare const EFFORT_SIZE_RUNGS: readonly ["size-2.5", "size-3", "size-3.5", "size-4", "size-4.5", "size-5", "size-5.5", "size-6"];
850
+ /**
851
+ * The size class for rung `index` of `count` evenly-spaced rungs — the
852
+ * growing-square ramp `PromptInputEffort` (and the terminal composer's own
853
+ * effort chips) render, low to high.
854
+ */
855
+ declare function effortRungForIndex(index: number, count: number): (typeof EFFORT_SIZE_RUNGS)[number];
856
+
857
+ /** The canonical, closed 7-state status enum (research 10 §B.1). */
858
+ declare const STATUSES: readonly ["pending", "running", "complete", "awaiting-approval", "denied", "failed", "skipped"];
859
+ type Status = (typeof STATUSES)[number];
860
+ /** Closed tone set for the out-of-vocabulary escape hatch (CALM treatments only). */
861
+ declare const STATUS_TONES: readonly ["neutral", "info", "success", "warning", "destructive"];
862
+ type StatusTone = (typeof STATUS_TONES)[number];
863
+ /**
864
+ * An out-of-vocabulary status. Prefer the canonical `Status` enum; reach for
865
+ * this only when the domain genuinely has a state the 7 do not express (e.g. a
866
+ * run engine's `stopped_guardrail`). Map it ONCE, near your domain — not per
867
+ * call site.
868
+ */
869
+ interface CustomStatus {
870
+ label: string;
871
+ tone: StatusTone;
872
+ /** Optional Lucide glyph. Omitted → label-only (no default glyph). */
873
+ icon?: LucideIcon;
874
+ }
875
+ /** Narrows `Status | CustomStatus` — the object form is always the escape hatch. */
876
+ declare function isCustomStatus(status: Status | CustomStatus): status is CustomStatus;
877
+ /**
878
+ * The canonical semantic ROLE per status — the single source of truth for
879
+ * status colour (#392). Any other status-keyed colour map in the repo
880
+ * (`Timeline`'s `NODE_STYLE`, or a future one) must be TESTED against this,
881
+ * not hand-authored — a second literal copy is exactly how `NODE_STYLE`
882
+ * drifted (`running` rendered `--primary` while this map said `--info`).
883
+ * Do NOT interpolate `bg-${STATUS_ROLE[status]}` into a class map: Tailwind
884
+ * scans source statically, so a template-literal class emits no CSS. Keep
885
+ * consuming maps as literal class strings, verified against this export by a
886
+ * test.
887
+ */
888
+ declare const STATUS_ROLE: {
889
+ readonly pending: "secondary";
890
+ readonly running: "info";
891
+ readonly complete: "success";
892
+ readonly "awaiting-approval": "warning";
893
+ readonly denied: "muted";
894
+ readonly failed: "destructive";
895
+ readonly skipped: "secondary";
896
+ };
897
+ /** Default human-readable label per status (override via `children`). */
898
+ declare const STATUS_LABELS: Record<Status, string>;
899
+ /**
900
+ * Lucide glyph per out-of-vocabulary TONE — the same five-tone escape hatch
901
+ * `CustomStatus` uses (`STATUS_TONES`). A consumer that encodes a bare TONE
902
+ * with no fuller `Status` semantics (e.g. `@elabs-ai/components-flow`'s `FlowNode.tone`,
903
+ * #387) derives its non-colour cue from here instead of inventing a second
904
+ * icon vocabulary — each entry reuses the SAME icon `STATUS_ICONS` already
905
+ * pairs with that tone's one canonical status (`success`→`complete`'s
906
+ * `CheckCircle2`, `warning`→`awaiting-approval`'s `Clock`,
907
+ * `destructive`→`failed`'s `AlertCircle`). `neutral`/`info` have no entry:
908
+ * nothing consumes them yet, and reaching for a glyph on every neutral/
909
+ * default-toned element would be assistive-tech noise on the common case —
910
+ * extend this map, don't fork a new one, the day something needs them.
911
+ */
912
+ declare const STATUS_TONE_ICONS: Partial<Record<StatusTone, LucideIcon>>;
913
+ interface StatusIconProps extends Omit<LucideProps, "ref"> {
914
+ /** The canonical execution status (closed enum). */
915
+ status: Status;
916
+ }
917
+ /**
918
+ * The icon + status-color atom `StatusBadge` itself composes — for tight rows
919
+ * (test-result rows, timeline/rail nodes) where a full badge is too heavy.
920
+ * Decorative by default (`aria-hidden`); the adjacent row text must carry the
921
+ * status name for AT users.
922
+ */
923
+ declare const StatusIcon: react.ForwardRefExoticComponent<StatusIconProps & react.RefAttributes<SVGSVGElement>>;
924
+ declare const statusBadgeVariants: (props?: ({
925
+ status?: "pending" | "running" | "complete" | "awaiting-approval" | "denied" | "failed" | "skipped" | null | undefined;
926
+ tone?: "success" | "warning" | "destructive" | "info" | "neutral" | null | undefined;
927
+ size?: "md" | "sm" | null | undefined;
928
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
929
+ interface StatusBadgeProps extends HTMLAttributes<HTMLSpanElement>, Omit<VariantProps<typeof statusBadgeVariants>, "status" | "tone"> {
930
+ /** The canonical execution status, or a mapped out-of-vocabulary one (#363). */
931
+ status: Status | CustomStatus;
932
+ /** Render label-only (no status icon). */
933
+ hideIcon?: boolean;
934
+ }
935
+ declare const StatusBadge: react.ForwardRefExoticComponent<StatusBadgeProps & react.RefAttributes<HTMLSpanElement>>;
936
+ /** The editor/markdown `Timeline` 3-state vocabulary (`@elabs-ai/components-editor`). */
937
+ type TimelineStatus = "done" | "active" | "pending";
938
+ /**
939
+ * Map the Timeline `done|active|pending` vocabulary onto the canonical
940
+ * `Status` (research 10 §B.1 mapping b — lossless; the timeline only
941
+ * expresses 3 of the 7 states). The AI-SDK `ToolUIPart` mapper lives in
942
+ * `@elabs-ai/components-ai` (`statusFromToolState`, tool.tsx) so `@elabs-ai/components-ui` stays free of
943
+ * the `ai` dependency (D6).
944
+ */
945
+ declare function fromTimelineStatus(status: TimelineStatus): Status;
946
+
947
+ /**
948
+ * The lifecycle/hook-event model behind `AgentEvent` (`@elabs-ai/components-ai`,
949
+ * #109) and the terminal CLI look-alike family's own event line (issue #117).
950
+ *
951
+ * Promoted here (not duplicated) because `@elabs-ai/components-ai` and
952
+ * `@elabs-ai/components-terminal` are layer-2 DAG SIBLINGS and may not import
953
+ * each other — `ui` is upstream of both
954
+ * (docs/decisions/2026-09-01-brainless-adoption-architecture.md § 4).
955
+ * `agentEventOutcomeStatus` maps onto the existing closed 7-state `Status`
956
+ * (`components/status-badge/status-badge.tsx`), which already lives in
957
+ * `ui` — no eighth status is introduced.
958
+ */
959
+
960
+ /**
961
+ * When an event fired relative to the action it gates. A separate, WIDER
962
+ * vocabulary than `CheckResult.phase` (`"before" | "after"`, per-check): this
963
+ * one also admits `"lifecycle"` for events with no gated action (a turn's
964
+ * `user_prompt_submit`/`stop`). The two `phase` concepts answer different
965
+ * questions — "when did this event fire" vs "when did this check run" — and
966
+ * are never unified (§ 6.1 of the architecture decision above).
967
+ */
968
+ type AgentEventPhase = "before" | "after" | "lifecycle";
969
+ /** An event's verdict. Maps onto the existing closed `Status` — see `agentEventOutcomeStatus`. */
970
+ type AgentEventOutcome = "ok" | "blocked" | "failed";
971
+ /**
972
+ * `outcome` → the canonical 7-state `Status`. No new status value is added
973
+ * (issue #109 acceptance criteria); `blocked` maps to `denied` — a runtime
974
+ * hook refusing an action is the same shape as a human denying one.
975
+ */
976
+ declare function agentEventOutcomeStatus(outcome: AgentEventOutcome): Status;
977
+
978
+ /**
979
+ * The session-launch vocabulary behind `SessionHeader`
980
+ * (`@elabs-ai/components-ai`, #110) and the terminal CLI look-alike family's
981
+ * own launch banner (issue #117, T7 — the "Empty" and "First-run" states).
982
+ *
983
+ * Promoted here (not duplicated) because `@elabs-ai/components-ai` and
984
+ * `@elabs-ai/components-terminal` are layer-2 DAG SIBLINGS and may not import
985
+ * each other — `ui` is upstream of both
986
+ * (docs/decisions/2026-09-01-brainless-adoption-architecture.md § 4). Pure
987
+ * item types, no behaviour.
988
+ */
989
+
990
+ interface SessionCapability {
991
+ /** Short capability name, e.g. "Web search". */
992
+ label: string;
993
+ /** One-line detail rendered under the label. */
994
+ description?: string;
995
+ /** Decorative leading glyph — a Lucide icon element. */
996
+ icon?: ReactNode;
997
+ }
998
+ interface SessionWhatsNewItem {
999
+ /** What changed, e.g. "Faster file search". */
1000
+ label: string;
1001
+ /** Optional link to release notes / a changelog entry. */
1002
+ href?: string;
1003
+ }
1004
+ interface SessionQuickAction {
1005
+ /** Visible label, e.g. "New chat". */
1006
+ label: string;
1007
+ /** Shortcut hint, rendered with the `Kbd` primitive (e.g. "⌘N"). */
1008
+ keyHint?: string;
1009
+ /** Invoked when the action is chosen. */
1010
+ onSelect?: () => void;
1011
+ }
1012
+
1013
+ interface IllustrationProps extends SVGProps<SVGSVGElement> {
1014
+ /**
1015
+ * Rendered width & height (any CSS length — pass a `rem` value to stay
1016
+ * density/zoom-aware). Illustrations are drawn to read clearly from about
1017
+ * `4rem` (64px) up to `10rem` (160px).
1018
+ * @default "7rem"
1019
+ */
1020
+ size?: string | number;
1021
+ }
1022
+ /**
1023
+ * Accent-semantics convention (#48 finding 1): an illustration draws at most
1024
+ * ONE accent mark (via `illustrationAccent()` below), and it exists ONLY
1025
+ * when it carries information the silhouette (the `currentColor`-stroked
1026
+ * subject) does not already supply on its own — never as ornamental
1027
+ * flourish wearing a meaning-bearing token. Applied across the seven
1028
+ * shipped illustrations:
1029
+ * - **Meaning-bearing (kept):** the "×" that turns a magnifying glass into
1030
+ * "no results" (`NoResultsIllustration`), the keyhole that turns a padlock
1031
+ * body into "restricted" (`NoAccessIllustration`), the checkmark that
1032
+ * turns a bare ring into "success" (`SuccessIllustration`), the
1033
+ * exclamation that turns a torn document into "warning" rather than
1034
+ * merely "broken" (`ErrorIllustration`).
1035
+ * - **Was decorative-only, removed (#48):** the "add" badge on
1036
+ * `EmptyListIllustration` (three rows already read as "empty list" on
1037
+ * their own), the sparkle on `FirstRunIllustration` (the planted flag
1038
+ * already reads as "start here"), and the broken-link fragments on
1039
+ * `OfflineIllustration` (a slashed cloud already reads as "disconnected" —
1040
+ * the universal "no signal" idiom). Their accent-free silhouettes carry
1041
+ * the full state alone, matching how `ErrorIllustration`'s silhouette
1042
+ * already did before this convention was written down.
1043
+ * Every illustration is `aria-hidden` regardless (the state's title/
1044
+ * description text is the ACCESSIBLE channel — see `illustrationSvgProps`
1045
+ * below), so this is a visual-consistency rule, not an a11y requirement on
1046
+ * its own; don't regress the silhouette-carries-meaning property while
1047
+ * redrawing any of the four kept accents above.
1048
+ */
1049
+ /**
1050
+ * The custom property every illustration's single meaning-bearing accent
1051
+ * reads through. `StatePanel` sets it on the illustration slot's wrapper for
1052
+ * `kind="error"` (`var(--destructive-text)`) so the accent follows the
1053
+ * panel's tint instead of staying pinned to one hue inside a re-colored slot
1054
+ * (#24 fix round 1, P0-2) — without this, an illustration whose accent
1055
+ * defaults to the brand hue renders a lime badge on a red error panel. Falls
1056
+ * back to each illustration's own default hue when no ambient override is
1057
+ * set.
1058
+ */
1059
+ declare const ILLUSTRATION_ACCENT_VAR = "--illustration-accent";
1060
+ /**
1061
+ * Build the `style` value for an illustration's accent ink: honors the
1062
+ * ambient `--illustration-accent` override when set, otherwise `fallback`.
1063
+ * `fallback` must be the correct **mark rung** for the accent's hue — e.g.
1064
+ * `var(--primary-text)` (NOT `var(--primary)`, a plate color that measures
1065
+ * 1.42:1 on `--card` in the `light` theme — #24 fix round 1, P0-1; see
1066
+ * `.claude/rules/styling-and-tokens.md` "Which status rung a graphical MARK
1067
+ * reaches for"), `var(--success-text)` for a positive-outcome accent, or
1068
+ * `var(--destructive-text)` for an error accent — the TEXT rung, deliberately
1069
+ * distinct from the FILL rung (`--destructive`) `StatePanel` puts the
1070
+ * SUBJECT on for `kind="error"`, so the two don't collapse onto one colour
1071
+ * (#48 finding 2).
1072
+ */
1073
+ declare function illustrationAccent(fallback: string): string;
1074
+
1075
+ /**
1076
+ * Empty list / zero-data-yet state. Three line-art rows read as "empty list"
1077
+ * on their own silhouette — no accent mark, per the accent-semantics
1078
+ * convention in `illustration-base.tsx` (#48 finding 1): a floating "add"
1079
+ * badge here would repeat information the rows already supply, not add any.
1080
+ */
1081
+ declare const EmptyListIllustration: react.ForwardRefExoticComponent<Omit<IllustrationProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
1082
+
1083
+ /**
1084
+ * Search / filter with zero matches. A line-art magnifying glass with a
1085
+ * `--primary-text` "×" inside the lens standing in for "nothing matched".
1086
+ * The "×" is meaning-bearing (per the accent-semantics convention in
1087
+ * `illustration-base.tsx`, #48 finding 1) — a bare magnifying glass alone
1088
+ * reads as "search", not "no results".
1089
+ */
1090
+ declare const NoResultsIllustration: react.ForwardRefExoticComponent<Omit<IllustrationProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
1091
+
1092
+ /**
1093
+ * Permission / access-denied state. A line-art padlock with a `--primary-text`
1094
+ * keyhole — reads as "restricted", not "broken". The keyhole is meaning-bearing
1095
+ * (per the accent-semantics convention in `illustration-base.tsx`, #48
1096
+ * finding 1) — it's what distinguishes a padlock from a generic rounded box.
1097
+ */
1098
+ declare const NoAccessIllustration: react.ForwardRefExoticComponent<Omit<IllustrationProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
1099
+
1100
+ /**
1101
+ * Recoverable-failure state. A line-art document split into two halves with a
1102
+ * visible gap between them — distinguishable from `NoAccessIllustration`/
1103
+ * `OfflineIllustration` by silhouette alone (a split document reads as
1104
+ * "broken" even in greyscale), per the WCAG 1.4.1 "never color-only" rule.
1105
+ * The exclamation mark IS meaning-bearing (per the accent-semantics
1106
+ * convention in `illustration-base.tsx`, #48 finding 1) — it turns "torn
1107
+ * document" into "warning", information the silhouette alone doesn't carry —
1108
+ * so it stays, in the upper-right quadrant of the right-hand half, clear of
1109
+ * both documents' outlines.
1110
+ *
1111
+ * Redrawn for #24 fix round 1 (P1-3) — the previous cracked-card + tiny alert
1112
+ * triangle read as a lightning bolt or a broken-image placeholder and the
1113
+ * triangle's exclamation collapsed to an illegible blob at 4rem.
1114
+ *
1115
+ * Redrawn again for #48 finding 3 — the mark previously sat at (76-84,
1116
+ * 54-95), exactly where the two document halves' torn edges converge, so it
1117
+ * read as a knot of overlapping lines rather than a "!". Moved to
1118
+ * (98-113, 44-85), 8-15 units clear of the nearest tear line at every
1119
+ * y-coordinate it spans.
1120
+ */
1121
+ declare const ErrorIllustration: react.ForwardRefExoticComponent<Omit<IllustrationProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
1122
+
1123
+ /**
1124
+ * Disconnected / no-network state. A line-art cloud crossed by a slash — the
1125
+ * universal "disabled/no signal" idiom — reads as "offline" on its own
1126
+ * silhouette. No accent mark, per the accent-semantics convention in
1127
+ * `illustration-base.tsx` (#48 finding 1).
1128
+ *
1129
+ * Redrawn for #24 fix round 1 (P1-4) — the previous cloud path's closing curve
1130
+ * left a visible hook/spur, and the dashed tether + falling node read as a
1131
+ * raindrop rather than a severed connection while pulling the ink centre 11.5
1132
+ * units below the shared stage centre.
1133
+ *
1134
+ * Redrawn again for #48 finding 4 — the two small rounded-rect "chain link"
1135
+ * fragments below the slash read as loose debris/dashes rather than a
1136
+ * "broken link" gesture. Removed rather than redrawn: the cloud+slash
1137
+ * silhouette already fully conveys "offline" without them (the same
1138
+ * reasoning that dropped the decorative accents from `EmptyListIllustration`/
1139
+ * `FirstRunIllustration`).
1140
+ */
1141
+ declare const OfflineIllustration: react.ForwardRefExoticComponent<Omit<IllustrationProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
1142
+
1143
+ /**
1144
+ * Completed / positive-outcome state. A line-art ring with a `--success-text`
1145
+ * checkmark — a ring + check needs no rays. The checkmark is meaning-bearing
1146
+ * (per the accent-semantics convention in `illustration-base.tsx`, #48
1147
+ * finding 1) — a bare ring alone carries no state at all.
1148
+ *
1149
+ * Redrawn for #24 fix round 1 (P0-1, P1-4) — the checkmark previously used
1150
+ * `--primary` (re-creating the "success chips read as primary" confusion #334
1151
+ * removed from the tokens) at `strokeWidth={6}` (off the shared accent-weight
1152
+ * rule), and the three radiating ticks straddled the now-removed dashed stage
1153
+ * (two crossed it, one didn't), reading as a clock/sun rather than a
1154
+ * celebration.
1155
+ */
1156
+ declare const SuccessIllustration: react.ForwardRefExoticComponent<Omit<IllustrationProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
1157
+
1158
+ /**
1159
+ * First-run / onboarding state. A line-art planted flag — reads as "start
1160
+ * here" on its own silhouette, distinct from `SuccessIllustration`. No
1161
+ * accent mark, per the accent-semantics convention in `illustration-base.tsx`
1162
+ * (#48 finding 1): a decorative sparkle here would repeat information the
1163
+ * flag already supplies, not add any.
1164
+ */
1165
+ declare const FirstRunIllustration: react.ForwardRefExoticComponent<Omit<IllustrationProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
1166
+
508
1167
  declare const Accordion: react.ForwardRefExoticComponent<(AccordionPrimitive.AccordionSingleProps | AccordionPrimitive.AccordionMultipleProps) & react.RefAttributes<HTMLDivElement>>;
509
1168
  declare const AccordionItem: react.ForwardRefExoticComponent<Omit<AccordionPrimitive.AccordionItemProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
510
1169
  declare const AccordionTrigger: react.ForwardRefExoticComponent<Omit<AccordionPrimitive.AccordionTriggerProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
@@ -552,7 +1211,7 @@ declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttri
552
1211
 
553
1212
  declare const buttonVariants: (props?: ({
554
1213
  variant?: "link" | "default" | "secondary" | "outline" | "destructive" | "outline-subtle" | "ghost" | null | undefined;
555
- size?: "default" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg" | null | undefined;
1214
+ size?: "default" | "sm" | "icon" | "lg" | "icon-sm" | "icon-lg" | null | undefined;
556
1215
  } & class_variance_authority_types.ClassProp) | undefined) => string;
557
1216
  interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
558
1217
  /** Render the child element as the button (Radix Slot) instead of a <button>. */
@@ -579,6 +1238,28 @@ declare const SidebarProvider: react.ForwardRefExoticComponent<Omit<react.ClassA
579
1238
  defaultOpen?: boolean;
580
1239
  open?: boolean;
581
1240
  onOpenChange?: (open: boolean) => void;
1241
+ /**
1242
+ * Drives the frame's inset treatment from an ANCESTOR the whole frame can
1243
+ * see — `SidebarInset` (#342 fix) reads it as `data-variant` on this
1244
+ * wrapper via `group-data-[variant=inset]/sidebar-wrapper:`, which reaches
1245
+ * regardless of DOM order (unlike the legacy `peer-*` combinator, which
1246
+ * only matches a Sidebar that comes AFTER). Optional and unset by
1247
+ * default, so an existing caller that only sets `variant` on `Sidebar`
1248
+ * is unaffected.
1249
+ */
1250
+ variant?: "sidebar" | "floating" | "inset";
1251
+ /**
1252
+ * Default `"app"` — today's behaviour, byte-identical. `"nested"` is for
1253
+ * a `SidebarProvider` a compound component (e.g. `ContextRail`, ADR 0035
1254
+ * §4) mounts internally so `useSidebar()` reports ITS OWN state to its
1255
+ * own parts: it still provides `SidebarContext` and the two
1256
+ * `--sidebar-width*` custom properties (which survive `display:
1257
+ * contents`), but renders no frame box, no `data-slot`/`data-variant`/
1258
+ * `data-state`, registers no global `⌘B`/`Ctrl+B` listener, and writes no
1259
+ * `sidebar_state` cookie — so a nested rail can never be mistaken for a
1260
+ * second app frame. See the emission table in ADR 0035 §4.
1261
+ */
1262
+ frame?: "app" | "nested";
582
1263
  }, "ref"> & react.RefAttributes<HTMLDivElement>>;
583
1264
  declare const Sidebar: react.ForwardRefExoticComponent<Omit<react.ClassAttributes<HTMLDivElement> & react.HTMLAttributes<HTMLDivElement> & {
584
1265
  side?: "left" | "right";
@@ -587,7 +1268,41 @@ declare const Sidebar: react.ForwardRefExoticComponent<Omit<react.ClassAttribute
587
1268
  }, "ref"> & react.RefAttributes<HTMLDivElement>>;
588
1269
  declare const SidebarTrigger: react.ForwardRefExoticComponent<Omit<ButtonProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
589
1270
  declare const SidebarRail: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
590
- declare const SidebarInset: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1271
+ /**
1272
+ * Which sides of the floating "inset" surface get a gutter, once an ancestor
1273
+ * drives the treatment (`SidebarProvider variant="inset"`, or the legacy
1274
+ * immediately-preceding `Sidebar variant="inset"`).
1275
+ *
1276
+ * - `"auto"` (default) — today's rule, unchanged: a gutter on every side
1277
+ * except the leading edge (`m-2 ms-0`, because the classic layout puts the
1278
+ * sidebar there), plus the leading edge's gutter returns (`ms-2`) once that
1279
+ * sidebar collapses and its own gap closes.
1280
+ * - `"none"` — no gutter margin (the unconditional radius/shadow below still
1281
+ * apply).
1282
+ * - An object — pick sides explicitly. `{ start: true, bottom: true }` is the
1283
+ * "flush rail" geometry: a leading + bottom gutter only, no top, no
1284
+ * trailing, because the trailing edge sits flush against a rail — a tab
1285
+ * must touch the page it belongs to.
1286
+ *
1287
+ * PRECEDENCE (fix round 1, #342): a caller composing BOTH mechanisms at once
1288
+ * — `SidebarProvider variant="inset"` AND a LEFT `Sidebar variant="inset"`,
1289
+ * the shape a left-hand shell (e.g. the sidebar-02 rebuild) uses — never hits
1290
+ * a class-order race, because the ancestor-scoped and legacy peer-scoped
1291
+ * margin classes are BOTH derived from this same `gutter` value, so whenever
1292
+ * both selectors match they emit identical declarations instead of competing
1293
+ * ones; the resolved geometry is always exactly what `gutter` says, decided
1294
+ * by this prop, never by the generated stylesheet's rule order.
1295
+ */
1296
+ type SidebarInsetGutter = "auto" | "none" | {
1297
+ top?: boolean;
1298
+ bottom?: boolean;
1299
+ start?: boolean;
1300
+ end?: boolean;
1301
+ };
1302
+ interface SidebarInsetProps extends ComponentProps<"main"> {
1303
+ gutter?: SidebarInsetGutter;
1304
+ }
1305
+ declare const SidebarInset: react.ForwardRefExoticComponent<Omit<SidebarInsetProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
591
1306
  declare const SidebarInput: react.ForwardRefExoticComponent<Omit<InputProps & react.RefAttributes<HTMLInputElement>, "ref"> & react.RefAttributes<HTMLInputElement>>;
592
1307
  declare const SidebarHeader: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
593
1308
  declare const SidebarFooter: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
@@ -715,12 +1430,40 @@ interface AppShellProps {
715
1430
  className?: string;
716
1431
  /** Class for the scrolling main content region. */
717
1432
  mainClassName?: string;
1433
+ /**
1434
+ * The `<main>` region's id, and the skip link's target. Override it when a
1435
+ * page mounts more than one shell — two elements sharing `main-content`
1436
+ * would make the skip link ambiguous. @default "main-content"
1437
+ */
1438
+ mainId?: string;
718
1439
  }
719
1440
  /**
720
1441
  * App-first layout: fixed-height viewport with an optional sidebar, a top bar,
721
1442
  * and a scrollable main region. Pure layout — bring your own nav components.
722
- */
723
- declare function AppShell({ sidebar, topNav, children, className, mainClassName }: AppShellProps): react.JSX.Element;
1443
+ *
1444
+ * The `sidebar` slot is hidden below `md` with no fallback of its own: this
1445
+ * shell does not know whether `sidebar` already manages its own responsive
1446
+ * behavior. `<Sidebar>` (`../sidebar`) does — it renders as an offcanvas
1447
+ * `Sheet` below the mobile breakpoint entirely on its own, through a Radix
1448
+ * portal that is unaffected by this wrapper's `hidden md:flex` (a portal
1449
+ * mounts into `document.body`, not into this DOM subtree) — pair it with a
1450
+ * `<SidebarTrigger>` inside `topNav` for full mobile navigation. Wrapping an
1451
+ * arbitrary `sidebar` node in a SECOND, shell-owned `Sheet` here would look
1452
+ * like a fix but silently break that exact pattern: a Radix `Sheet`/`Dialog`
1453
+ * only mounts its content while open, so `<Sidebar>` would be unmounted
1454
+ * (not just hidden) whenever the shell's own drawer is closed — and with it,
1455
+ * the very trigger a caller uses to open ITS mobile view. A bare nav node
1456
+ * (no built-in responsive behavior of its own) has no such fallback; give it
1457
+ * one explicitly, e.g. by rendering a `<Sheet>` alongside `topNav` in the
1458
+ * consuming app.
1459
+ *
1460
+ * The `SidebarProvider` + `Sidebar` + `SidebarTrigger` composition above is
1461
+ * regression-locked in `app-shell.test.tsx` at a mobile viewport width: no
1462
+ * AppShell code change is needed to reach navigation below `md`, because
1463
+ * `SidebarProvider` is a plain React context and is never blocked by this
1464
+ * component's internal wrapper `<div>`.
1465
+ */
1466
+ declare const AppShell: react.ForwardRefExoticComponent<AppShellProps & react.RefAttributes<HTMLDivElement>>;
724
1467
 
725
1468
  declare const AspectRatio: react.ForwardRefExoticComponent<AspectRatioPrimitive.AspectRatioProps & react.RefAttributes<HTMLDivElement>>;
726
1469
 
@@ -821,7 +1564,7 @@ declare const badgeVariants: (props?: ({
821
1564
  } & class_variance_authority_types.ClassProp) | undefined) => string;
822
1565
  interface BadgeProps extends HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badgeVariants> {
823
1566
  }
824
- declare function Badge({ className, variant, ...props }: BadgeProps): react.JSX.Element;
1567
+ declare const Badge: react.ForwardRefExoticComponent<BadgeProps & react.RefAttributes<HTMLSpanElement>>;
825
1568
 
826
1569
  interface BentoGridProps extends HTMLAttributes<HTMLDivElement> {
827
1570
  /** Additional className merged via cn(). */
@@ -947,7 +1690,7 @@ interface NumberInputProps extends Omit<HTMLAttributes<HTMLDivElement>, "onChang
947
1690
  * Controlled via `value`/`onValueChange`; uncontrolled via `defaultValue`.
948
1691
  * Keyboard ↑/↓ = ±step; Shift+↑/↓ = ±step×10. Clamps on blur (not per keystroke).
949
1692
  */
950
- declare const NumberInput: react.ForwardRefExoticComponent<NumberInputProps & react.RefAttributes<HTMLDivElement>>;
1693
+ declare const NumberInput: react.ForwardRefExoticComponent<NumberInputProps & react.RefAttributes<HTMLInputElement>>;
951
1694
 
952
1695
  interface BoundedNumberProps extends NumberInputProps {
953
1696
  /**
@@ -971,7 +1714,7 @@ interface BoundedNumberProps extends NumberInputProps {
971
1714
  * `null` AND the field is not focused, so the underlying input stays fully
972
1715
  * clickable/typable and still round-trips to `null` on an empty blur.
973
1716
  */
974
- declare const BoundedNumber: react.ForwardRefExoticComponent<BoundedNumberProps & react.RefAttributes<HTMLDivElement>>;
1717
+ declare const BoundedNumber: react.ForwardRefExoticComponent<BoundedNumberProps & react.RefAttributes<HTMLInputElement>>;
975
1718
 
976
1719
  declare const Breadcrumb: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & react.RefAttributes<HTMLElement>>;
977
1720
  declare const BreadcrumbList: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.OlHTMLAttributes<HTMLOListElement>, HTMLOListElement>, "ref"> & react.RefAttributes<HTMLOListElement>>;
@@ -1067,8 +1810,8 @@ interface CarouselProps {
1067
1810
  declare const Carousel: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & CarouselProps & react.RefAttributes<HTMLDivElement>>;
1068
1811
  declare const CarouselContent: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & react.RefAttributes<HTMLDivElement>>;
1069
1812
  declare const CarouselItem: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & react.RefAttributes<HTMLDivElement>>;
1070
- declare function CarouselPrevious({ className, ...props }: ComponentProps<typeof Button>): react.JSX.Element;
1071
- declare function CarouselNext({ className, ...props }: ComponentProps<typeof Button>): react.JSX.Element;
1813
+ declare const CarouselPrevious: react.ForwardRefExoticComponent<Omit<ButtonProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
1814
+ declare const CarouselNext: react.ForwardRefExoticComponent<Omit<ButtonProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
1072
1815
 
1073
1816
  /** Who / what proposed the change set (presentational only; never fetches). */
1074
1817
  interface ChangeProvenance {
@@ -1097,6 +1840,13 @@ interface ChangeHunk {
1097
1840
  status?: ChangeHunkStatus;
1098
1841
  /** Per-hunk provenance override (overrides the review-level provenance). */
1099
1842
  provenance?: ChangeProvenance;
1843
+ /**
1844
+ * Verification results for this hunk (lint / types / tests / policy hooks).
1845
+ * Purely informational — a failing check never blocks approval, it only
1846
+ * informs the reviewer's decision. Grouped into "Before" / "After" sections
1847
+ * when both phases are present.
1848
+ */
1849
+ checks?: CheckResult[];
1100
1850
  }
1101
1851
  /** State surface exposed by the ChangeReview context. */
1102
1852
  interface ChangeReviewState {
@@ -1192,7 +1942,7 @@ interface ChangeReviewHunkProps extends Omit<HTMLAttributes<HTMLLIElement>, "chi
1192
1942
  * Approval state is signalled with TWO non-color cues:
1193
1943
  * - icon: Check (approved) vs plain toggle (pending)
1194
1944
  * - label: "Approved" badge vs "Approve" button text
1195
- * This ensures the state is clear in all three themes including the low-chroma
1945
+ * This ensures the state is clear in every theme including the low-chroma
1196
1946
  * monochrome surfaces (colorblind-safe).
1197
1947
  */
1198
1948
  declare const ChangeReviewHunk: react.ForwardRefExoticComponent<ChangeReviewHunkProps & react.RefAttributes<HTMLLIElement>>;
@@ -1331,6 +2081,12 @@ interface ComboboxOption {
1331
2081
  value: string;
1332
2082
  }
1333
2083
  interface ComboboxProps {
2084
+ /**
2085
+ * The option list — every option is mounted in the DOM (cmdk has no built-in
2086
+ * windowing), so this is fine for typical form/menu-sized lists but not for
2087
+ * open-ended data. For thousands of options, use `VirtualSelect` instead,
2088
+ * which windows rendering via `@tanstack/react-virtual`.
2089
+ */
1334
2090
  options: ComboboxOption[];
1335
2091
  value?: string;
1336
2092
  onValueChange?: (value: string) => void;
@@ -1569,10 +2325,29 @@ declare const Command: react.ForwardRefExoticComponent<CommandProps & react.RefA
1569
2325
  * external input above the tree).
1570
2326
  */
1571
2327
  declare function useCommandActiveItemId(): string | undefined;
1572
- declare function CommandDialog({ children, filter, ...props }: ComponentPropsWithoutRef<typeof Dialog> & {
2328
+ type CommandDialogProps = ComponentPropsWithoutRef<typeof Dialog> & {
1573
2329
  /** Custom cmdk ranking (e.g. strict substring instead of fuzzy). */
1574
2330
  filter?: ComponentPropsWithoutRef<typeof Command$1>["filter"];
1575
- }): react.JSX.Element;
2331
+ /**
2332
+ * The dialog's accessible name, rendered `sr-only`.
2333
+ *
2334
+ * OPTIONAL, and deliberately so: callers that already render their own
2335
+ * `DialogTitle` in `children` must not be forced to move it, and
2336
+ * `@elabs-ai/components-ai`'s `VoiceSelectorDialog` passes this whole prop
2337
+ * type straight through. Supply it when you have no visible title — a
2338
+ * `Dialog` with no accessible name is a Radix warning and an axe violation.
2339
+ */
2340
+ title?: ReactNode;
2341
+ };
2342
+ /**
2343
+ * A ⌘K command palette in a modal `Dialog`.
2344
+ *
2345
+ * This IS the palette presentation of `Command` — there is no separate
2346
+ * "selector" component. For an inline pill that opens the same grouped,
2347
+ * searchable list anchored under itself (a composer footer), reach for
2348
+ * `ModelPicker` instead.
2349
+ */
2350
+ declare function CommandDialog({ children, filter, title, ...props }: CommandDialogProps): react.JSX.Element;
1576
2351
  declare const CommandInput: react.ForwardRefExoticComponent<Omit<Omit<Pick<Pick<react.DetailedHTMLProps<react.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "key" | keyof react.InputHTMLAttributes<HTMLInputElement>> & {
1577
2352
  ref?: React.Ref<HTMLInputElement>;
1578
2353
  } & {
@@ -1630,6 +2405,31 @@ declare const CommandItem: react.ForwardRefExoticComponent<Omit<{
1630
2405
  } & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1631
2406
  declare function CommandShortcut({ className, ...props }: HTMLAttributes<HTMLSpanElement>): react.JSX.Element;
1632
2407
 
2408
+ interface CommandTriggerProps extends ComponentProps<"button"> {
2409
+ /** The visible and announced label. Defaults to "Search". */
2410
+ label?: string;
2411
+ /** The shortcut hint. Defaults to the platform-correct ⌘ K / Ctrl K. */
2412
+ shortcut?: string;
2413
+ }
2414
+ /**
2415
+ * The command-palette opener, shaped like a search field: label left, shortcut
2416
+ * pinned right, collapsing to the icon alone under `sm`.
2417
+ *
2418
+ * The button’s accessible name comes entirely from `aria-label` — that is what
2419
+ * stops the `Kbd`’s shortcut glyph from concatenating into it (#117); a
2420
+ * non-empty `aria-label` short-circuits accessible-name computation before the
2421
+ * DOM is ever consulted. The visible label and the `Kbd` are ALSO marked
2422
+ * `aria-hidden`, per `accessibility.md`, as defence in depth: if `aria-label`
2423
+ * is ever dropped, that turns a silent regression into a loud one — an empty
2424
+ * accessible name rather than a plausible wrong one. They do not do the work
2425
+ * themselves.
2426
+ *
2427
+ * `shortcut` reads `navigator` at render time when omitted, which can differ
2428
+ * between server and client — a consumer that server-renders this component
2429
+ * should pass `shortcut` explicitly to avoid a hydration mismatch.
2430
+ */
2431
+ declare const CommandTrigger: react.ForwardRefExoticComponent<Omit<CommandTriggerProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
2432
+
1633
2433
  interface ConfirmDialogProps {
1634
2434
  /** Controlled open state — the app owns it. */
1635
2435
  open: boolean;
@@ -1724,6 +2524,77 @@ declare const ContextMenuLabel: react.ForwardRefExoticComponent<Omit<ContextMenu
1724
2524
  declare const ContextMenuSeparator: react.ForwardRefExoticComponent<Omit<ContextMenuPrimitive.ContextMenuSeparatorProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1725
2525
  declare function ContextMenuShortcut({ className, ...props }: HTMLAttributes<HTMLSpanElement>): react.JSX.Element;
1726
2526
 
2527
+ /** One switchable section of a `ContextRail`. */
2528
+ interface ContextRailSection {
2529
+ /** Stable identifier — the switcher's `SidebarMenuButton` key and the
2530
+ * value reported to `activeSectionId`/`onActiveSectionChange`. */
2531
+ id: string;
2532
+ /** Visible label. Feeds the switcher entry's accessible name and the
2533
+ * body's heading — never rendered as visible text in the switcher
2534
+ * itself, which stays icon-only in every state. */
2535
+ label: string;
2536
+ /** Icon shown in the switcher, in both the expanded and collapsed
2537
+ * (48px icon strip) presentations. Decorative — wrapped `aria-hidden`. */
2538
+ icon: ReactNode;
2539
+ /** Optional count badge. Visible in BOTH states (unlike
2540
+ * `SidebarMenuBadge`, which hides under `collapsible="icon"`) and folded
2541
+ * into the switcher entry's accessible name, e.g. "Sources 3 items". */
2542
+ count?: number;
2543
+ /** Rendered only while this section is active — the rail mounts exactly
2544
+ * one section's content at a time. */
2545
+ content: ReactNode;
2546
+ /** Disables the switcher entry; clicking it is a no-op. */
2547
+ disabled?: boolean;
2548
+ }
2549
+ interface ContextRailProps extends Omit<ComponentProps<"div">, "onSelect" | "children"> {
2550
+ /** The sections the switcher can pick between. An empty array renders
2551
+ * the `empty` slot instead of a switcher. */
2552
+ sections: ContextRailSection[];
2553
+ /** Controlled active section id. */
2554
+ activeSectionId?: string;
2555
+ /** Initial active section id (uncontrolled). Defaults to `sections[0]`. */
2556
+ defaultActiveSectionId?: string;
2557
+ /** Fires with the clicked section's id — including a re-click of the
2558
+ * already-active section (open/close is a separate concern, see `open`). */
2559
+ onActiveSectionChange?: (sectionId: string) => void;
2560
+ /** Controlled expanded/collapsed state. Clicking the ACTIVE switcher
2561
+ * entry toggles this; clicking an INACTIVE entry sets it `true`. */
2562
+ open?: boolean;
2563
+ /** Initial expanded/collapsed state (uncontrolled). Defaults to `true`. */
2564
+ defaultOpen?: boolean;
2565
+ onOpenChange?: (open: boolean) => void;
2566
+ /** Expanded width, published as `--sidebar-width`. @default "20rem" */
2567
+ width?: string;
2568
+ /** Replaces the default localized empty state when `sections` is empty. */
2569
+ empty?: ReactNode;
2570
+ /**
2571
+ * Below this viewport width the rail renders its own 48px strip plus a
2572
+ * `Sheet` for the expanded body instead of mounting `Sidebar` — dev-only
2573
+ * warns if set below 768. @default 768
2574
+ */
2575
+ overlayBreakpoint?: number;
2576
+ }
2577
+ /**
2578
+ * A right-hand rail whose collapsed state is a 48px icon strip that doubles
2579
+ * as its own section switcher. Built on `Sidebar`/`SidebarProvider`
2580
+ * (`frame="nested"`, ADR 0035 §4) as an implementation detail — the public
2581
+ * seam is `sections` + `activeSectionId`/`onActiveSectionChange` (which
2582
+ * section) and `open`/`onOpenChange` (expanded or collapsed), both
2583
+ * controlled/uncontrolled. Below `overlayBreakpoint` it renders its own
2584
+ * strip plus a `Sheet` instead of mounting `Sidebar`. See
2585
+ * `docs/ADR/0035-context-rail-and-side-dock.md` §3.
2586
+ *
2587
+ * Known constraint (task-11f-brief.md Finding 5): below `overlayBreakpoint`
2588
+ * the expanded body is a `Sheet`, which always spans the full browser
2589
+ * viewport, while the persistent 48px strip is bounded by whatever container
2590
+ * the host gives the rail. In a host container shorter than the viewport
2591
+ * (any app shell with a toolbar above the rail), the strip stops mid-screen
2592
+ * while the sheet keeps going — the two read as unrelated surfaces. Give
2593
+ * `ContextRail` a full-viewport-height host container below the breakpoint
2594
+ * to avoid this seam.
2595
+ */
2596
+ declare const ContextRail: react.ForwardRefExoticComponent<Omit<ContextRailProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
2597
+
1727
2598
  interface CopyableValueProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "value" | "children"> {
1728
2599
  /**
1729
2600
  * The EXACT text written to the clipboard — the unrounded, un-abbreviated
@@ -1758,13 +2629,13 @@ interface DatePickerProps {
1758
2629
  className?: string;
1759
2630
  }
1760
2631
  /** Single-date picker (Popover + Calendar). Controlled or uncontrolled. */
1761
- declare function DatePicker({ value, onValueChange, placeholder, className, }: DatePickerProps): react.JSX.Element;
2632
+ declare const DatePicker: react.ForwardRefExoticComponent<DatePickerProps & react.RefAttributes<HTMLButtonElement>>;
1762
2633
 
1763
2634
  interface DateRangePreset {
1764
2635
  label: string;
1765
2636
  getRange: () => DateRange;
1766
2637
  }
1767
- interface DateRangePickerProps {
2638
+ interface DateRangePickerProps extends Omit<HTMLAttributes<HTMLButtonElement>, "onSelect" | "children" | "value" | "defaultValue"> {
1768
2639
  value?: DateRange;
1769
2640
  defaultValue?: DateRange;
1770
2641
  onValueChange?: (range?: DateRange) => void;
@@ -1849,7 +2720,12 @@ declare function DropdownMenuShortcut({ className, ...props }: React.HTMLAttribu
1849
2720
  interface EmptyStateProps {
1850
2721
  title: ReactNode;
1851
2722
  description?: ReactNode;
1852
- /** Optional icon/illustration shown above the title. */
2723
+ /**
2724
+ * Optional icon shown above the title, clamped to a fixed 40×40 (this
2725
+ * wrapper only ever forwards `icon` to `StatePanel`, never `illustration`
2726
+ * — for a larger, unclamped illustration use
2727
+ * `StatePanel kind="empty" illustration={...}` directly).
2728
+ */
1853
2729
  icon?: ReactNode;
1854
2730
  /** Primary/secondary actions. */
1855
2731
  actions?: ReactNode;
@@ -1981,14 +2857,129 @@ interface ExpandDialogProps extends Omit<ExpandDialogContentProps, "title" | "ch
1981
2857
  */
1982
2858
  declare const ExpandDialog: react.ForwardRefExoticComponent<ExpandDialogProps & react.RefAttributes<HTMLDivElement>>;
1983
2859
 
2860
+ interface FieldRootProps extends HTMLAttributes<HTMLDivElement> {
2861
+ /**
2862
+ * Whether the field is currently invalid. Drives `aria-invalid` on every
2863
+ * `FieldControl` and error styling on `FieldLabel` — independent of
2864
+ * whether a `FieldError` with content is actually mounted, so a caller can
2865
+ * mark the control invalid before its message has settled.
2866
+ */
2867
+ invalid?: boolean;
2868
+ /** Whether the field is required. Drives `aria-required` on every `FieldControl`. */
2869
+ required?: boolean;
2870
+ }
2871
+ /**
2872
+ * Compound-anatomy field: `FieldRoot` owns id generation and `aria-describedby`
2873
+ * composition; `FieldLabel`/`FieldControl`/`FieldDescription`/`FieldError` read
2874
+ * that state from context and can be composed in ANY order/layout — including
2875
+ * more than one `FieldControl` in one row (e.g. first/last name) or a
2876
+ * `FieldDescription` placed before the control. Mirrors the same accessibility
2877
+ * wiring `FieldRow` (`../field-row`) already validated (id/`aria-describedby`/
2878
+ * `aria-invalid`/`role="alert"`), adapted to a shared lifted-state context so
2879
+ * it holds across independently-composed parts; `FieldRow` remains the
2880
+ * convenience wrapper for the common single-control case and is unaffected by
2881
+ * this addition (#43).
2882
+ *
2883
+ * @example
2884
+ * ```tsx
2885
+ * <FieldRoot invalid={!!error} required>
2886
+ * <FieldLabel>{label}</FieldLabel>
2887
+ * <FieldControl><Input /></FieldControl>
2888
+ * <FieldDescription>{helpText}</FieldDescription>
2889
+ * <FieldError>{error}</FieldError>
2890
+ * </FieldRoot>
2891
+ * ```
2892
+ */
2893
+ declare const FieldRoot: react.ForwardRefExoticComponent<FieldRootProps & react.RefAttributes<HTMLDivElement>>;
2894
+ declare const FieldLabel: react.ForwardRefExoticComponent<Omit<Omit<_radix_ui_react_label.LabelProps & react.RefAttributes<HTMLLabelElement>, "ref"> & react.RefAttributes<HTMLLabelElement>, "ref"> & react.RefAttributes<HTMLLabelElement>>;
2895
+ interface FieldControlProps {
2896
+ /**
2897
+ * The single field control (`Input`, `Textarea`, `Select`, …). Receives
2898
+ * `id`/`aria-describedby`/`aria-invalid`/`aria-required` via a Radix
2899
+ * `Slot` — must be a single element that forwards those props to a real
2900
+ * form control. Compose more than one `FieldControl` inside one
2901
+ * `FieldRoot` for a multi-control row (each gets its own independent id;
2902
+ * give every control but the first its own explicit `id`, the same way
2903
+ * you would for any two form controls that must not collide). `FieldLabel`
2904
+ * can only associate with ONE control (the first to mount), so give every
2905
+ * OTHER control in the row its own `aria-label` — a shared visual label
2906
+ * plus a placeholder is not a real accessible name for the rest.
2907
+ */
2908
+ children: ReactElement<{
2909
+ id?: string;
2910
+ "aria-describedby"?: string;
2911
+ }>;
2912
+ }
2913
+ declare const FieldControl: react.ForwardRefExoticComponent<FieldControlProps & react.RefAttributes<HTMLElement>>;
2914
+ /**
2915
+ * Optional field help text. Renders nothing — and registers no
2916
+ * `aria-describedby` reference — when `children` is falsy (`false`/`0`/`""`/
2917
+ * `null`/`undefined`), an empty array, or an array containing only falsy
2918
+ * values (`{list.map(...)}` on an empty list; `[a && "x", b && "y"]` with
2919
+ * both false) — matching `FieldRow`'s `description ? … : null` convention:
2920
+ * `{hint && <FieldDescription>{hint}</FieldDescription>}` is the supported
2921
+ * way to express "no description".
2922
+ *
2923
+ * **Known limit:** a child that is itself a COMPONENT that renders nothing
2924
+ * (returns `null`/an empty fragment) is not knowable from the element
2925
+ * before render, so it still produces an empty paragraph that
2926
+ * `aria-describedby` points at. `FieldRow` and the wider React ecosystem
2927
+ * share this limit — pass a falsy child instead of a component that may
2928
+ * render nothing.
2929
+ */
2930
+ declare const FieldDescription: react.ForwardRefExoticComponent<HTMLAttributes<HTMLParagraphElement> & react.RefAttributes<HTMLParagraphElement>>;
2931
+ /**
2932
+ * Validation error text, announced via `role="alert"`. Renders nothing —
2933
+ * and registers no `aria-describedby` reference — when `children` is falsy
2934
+ * (`false`/`0`/`""`/`null`/`undefined`), an empty array, or an array
2935
+ * containing only falsy values (`{errors.map(...)}` on an empty array is
2936
+ * exactly how a real form renders "no errors") — matching `FieldRow`'s
2937
+ * `error ? … : null` convention: `{error && <FieldError>{error}</FieldError>}`
2938
+ * is the supported way to express "no error".
2939
+ *
2940
+ * **Known limit:** a child that is itself a COMPONENT that renders nothing
2941
+ * (returns `null`/an empty fragment) is not knowable from the element
2942
+ * before render, so it still produces an empty `role="alert"` element that
2943
+ * `aria-describedby` points at (a screen reader announces an empty alert).
2944
+ * `FieldRow` and the wider React ecosystem share this limit — pass a falsy
2945
+ * child instead of a component that may render nothing.
2946
+ */
2947
+ declare const FieldError: react.ForwardRefExoticComponent<HTMLAttributes<HTMLParagraphElement> & react.RefAttributes<HTMLParagraphElement>>;
2948
+
1984
2949
  interface FieldRowProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
1985
2950
  /** Field label — rendered as a real `<label>`, click-to-focus associated with the control. */
1986
2951
  label: ReactNode;
1987
- /** Optional help/description text, always visible (not gated by an error). */
2952
+ /**
2953
+ * Optional help/description text, always visible (not gated by an error).
2954
+ * Renders nothing — and contributes no id to `aria-describedby` — when
2955
+ * `description` is falsy (`false`/`0`/`""`/`null`/`undefined`), an empty
2956
+ * array, or an array containing only falsy values (`{list.map(...)}` on an
2957
+ * empty list; `[a && "x", b && "y"]` with both false).
2958
+ *
2959
+ * **Known limit:** a value that is itself a COMPONENT that renders nothing
2960
+ * (returns `null`/an empty fragment) is not knowable before render, so it
2961
+ * still produces an empty paragraph that `aria-describedby` points at.
2962
+ * `FieldDescription` and the wider React ecosystem share this limit — pass
2963
+ * a falsy value instead of a component that may render nothing, e.g.
2964
+ * `description={hasHint ? hintText : undefined}`, never
2965
+ * `description={<MaybeRendersNull />}`.
2966
+ */
1988
2967
  description?: ReactNode;
1989
2968
  /**
1990
2969
  * Validation error text. When present: sets `aria-invalid` on the control,
1991
2970
  * is appended to `aria-describedby`, and is announced via `role="alert"`.
2971
+ * Renders nothing — and leaves `aria-invalid="false"` — when `error` is
2972
+ * falsy (`false`/`0`/`""`/`null`/`undefined`), an empty array, or an array
2973
+ * containing only falsy values (`{errors.map(...)}` on an empty list — the
2974
+ * idiomatic "no errors" shape).
2975
+ *
2976
+ * **Known limit:** a value that is itself a COMPONENT that renders nothing
2977
+ * (returns `null`/an empty fragment) is not knowable before render, so it
2978
+ * still produces an empty `role="alert"` element that `aria-describedby`
2979
+ * points at. `FieldError` and the wider React ecosystem share this limit —
2980
+ * pass a falsy value instead of a component that may render nothing, e.g.
2981
+ * `error={hasError ? message : undefined}`, never
2982
+ * `error={<MaybeRendersNull />}`.
1992
2983
  */
1993
2984
  error?: ReactNode;
1994
2985
  /**
@@ -2025,6 +3016,12 @@ interface UploadFile {
2025
3016
  /** Error message shown when status is "error". */
2026
3017
  errorMessage?: string;
2027
3018
  }
3019
+ /** Why `addFiles` (picker OR drag-and-drop) declined a file. */
3020
+ type FileRejectionReason = "accept" | "maxSize" | "maxFiles" | "multiple";
3021
+ interface FileRejection {
3022
+ file: File;
3023
+ reason: FileRejectionReason;
3024
+ }
2028
3025
  interface FileUploadContextValue {
2029
3026
  files: UploadFile[];
2030
3027
  addFiles: (incoming: File[]) => void;
@@ -2045,6 +3042,12 @@ interface FileUploadProps extends HTMLAttributes<HTMLDivElement> {
2045
3042
  files?: UploadFile[];
2046
3043
  /** Called when files are added or removed. */
2047
3044
  onFilesChange?: (files: UploadFile[]) => void;
3045
+ /**
3046
+ * Called with the files a picker selection OR a drag-and-drop declined —
3047
+ * wrong type (`accept`), over `maxSize`, over `maxFiles`, or extra files
3048
+ * dropped when `multiple` is false — each with its {@link FileRejectionReason}.
3049
+ */
3050
+ onFilesRejected?: (rejections: FileRejection[]) => void;
2048
3051
  /** Accepted MIME types / extensions (forwarded to <input accept>). */
2049
3052
  accept?: string;
2050
3053
  /** Allow multiple files at once. */
@@ -2068,18 +3071,26 @@ interface FileUploadProps extends HTMLAttributes<HTMLDivElement> {
2068
3071
  * Controlled via `files`/`onFilesChange`; uncontrolled by default.
2069
3072
  */
2070
3073
  declare const FileUpload: react.ForwardRefExoticComponent<FileUploadProps & react.RefAttributes<HTMLDivElement>>;
2071
- interface FileUploadDropzoneProps extends HTMLAttributes<HTMLElement> {
2072
- /** Label for the visually-hidden file picker link (for SR users). */
3074
+ interface FileUploadDropzoneProps extends HTMLAttributes<HTMLDivElement> {
3075
+ /** Label for the default "Browse files" button. */
2073
3076
  browseLabel?: string;
2074
3077
  }
2075
3078
  /**
2076
3079
  * FileUploadDropzone — the drag-and-drop target.
2077
3080
  *
2078
- * Uses a `<label>` wrapping the hidden `<input>` so the ENTIRE zone is ONE hit
2079
- * target — no `<div onClick>`. Keyboard users get the Browse button as a
2080
- * complementary path.
3081
+ * A plain `<div>` drop surface with exactly ONE keyboard-reachable control:
3082
+ *
3083
+ * - Default content: a real `<button>` ("Browse files") is the tab stop; the
3084
+ * zone itself carries no role and no tab stop, so nothing interactive is
3085
+ * nested inside another interactive element.
3086
+ * - Custom `children`: there is no inner button, so the zone itself becomes
3087
+ * the control (`role="button"`, a tab stop, Enter/Space). Custom children
3088
+ * must then be non-interactive content.
3089
+ *
3090
+ * A pointer click anywhere on the zone also opens the picker — a mouse
3091
+ * convenience on top of the keyboard path above, never the only path.
2081
3092
  */
2082
- declare const FileUploadDropzone: react.ForwardRefExoticComponent<FileUploadDropzoneProps & react.RefAttributes<HTMLElement>>;
3093
+ declare const FileUploadDropzone: react.ForwardRefExoticComponent<FileUploadDropzoneProps & react.RefAttributes<HTMLDivElement>>;
2083
3094
  type FileUploadListProps = HTMLAttributes<HTMLUListElement>;
2084
3095
  /**
2085
3096
  * FileUploadList — the `role="status"` region that lists accepted files.
@@ -2104,26 +3115,6 @@ interface FileUploadItemProps extends HTMLAttributes<HTMLLIElement> {
2104
3115
  */
2105
3116
  declare const FileUploadItem: react.ForwardRefExoticComponent<FileUploadItemProps & react.RefAttributes<HTMLLIElement>>;
2106
3117
 
2107
- declare const Form: <TFieldValues extends FieldValues, TContext = any, TTransformedValues = TFieldValues>({ children, watch, getValues, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, }: react_hook_form.FormProviderProps<TFieldValues, TContext, TTransformedValues>) => React.JSX.Element;
2108
- declare function FormField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>(props: ControllerProps<TFieldValues, TName>): react.JSX.Element;
2109
- declare function useFormField(): {
2110
- invalid: boolean;
2111
- isDirty: boolean;
2112
- isTouched: boolean;
2113
- isValidating: boolean;
2114
- error?: react_hook_form.FieldError;
2115
- id: string;
2116
- name: string;
2117
- formItemId: string;
2118
- formDescriptionId: string;
2119
- formMessageId: string;
2120
- };
2121
- declare const FormItem: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & react.RefAttributes<HTMLDivElement>>;
2122
- declare const FormLabel: react.ForwardRefExoticComponent<Omit<Omit<_radix_ui_react_label.LabelProps & react.RefAttributes<HTMLLabelElement>, "ref"> & react.RefAttributes<HTMLLabelElement>, "ref"> & react.RefAttributes<HTMLLabelElement>>;
2123
- declare const FormControl: react.ForwardRefExoticComponent<Omit<_radix_ui_react_slot.SlotProps & react.RefAttributes<HTMLElement>, "ref"> & react.RefAttributes<HTMLElement>>;
2124
- declare const FormDescription: react.ForwardRefExoticComponent<HTMLAttributes<HTMLParagraphElement> & react.RefAttributes<HTMLParagraphElement>>;
2125
- declare const FormMessage: react.ForwardRefExoticComponent<HTMLAttributes<HTMLParagraphElement> & react.RefAttributes<HTMLParagraphElement>>;
2126
-
2127
3118
  declare const HoverCard: react.FC<HoverCardPrimitive.HoverCardProps>;
2128
3119
  declare const HoverCardTrigger: react.ForwardRefExoticComponent<HoverCardPrimitive.HoverCardTriggerProps & react.RefAttributes<HTMLAnchorElement>>;
2129
3120
  declare const HoverCardContent: react.ForwardRefExoticComponent<Omit<HoverCardPrimitive.HoverCardContentProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
@@ -2173,7 +3164,7 @@ type TextareaProps = TextareaHTMLAttributes<HTMLTextAreaElement>;
2173
3164
  declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
2174
3165
 
2175
3166
  declare const inputGroupVariants: (props?: ({
2176
- variant?: "outline" | "surface" | "card" | null | undefined;
3167
+ variant?: "outline" | "card" | "surface" | null | undefined;
2177
3168
  } & class_variance_authority_types.ClassProp) | undefined) => string;
2178
3169
  type InputGroupProps = ComponentProps<"div"> & VariantProps<typeof inputGroupVariants>;
2179
3170
  declare const InputGroup: react.ForwardRefExoticComponent<Omit<InputGroupProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
@@ -2200,6 +3191,43 @@ declare const InputOTPSeparator: react.ForwardRefExoticComponent<react.HTMLAttri
2200
3191
  /** Keyboard key hint, e.g. <Kbd>⌘K</Kbd>. */
2201
3192
  declare const Kbd: react.ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & react.RefAttributes<HTMLElement>>;
2202
3193
 
3194
+ /** One keyboard shortcut: the action it performs and its ordered key tokens. */
3195
+ interface Shortcut {
3196
+ action: string;
3197
+ /** Ordered key tokens, e.g. `["⌘", "K"]`. Rendered via {@link Kbd}. */
3198
+ keys: string[];
3199
+ }
3200
+ /**
3201
+ * A named group of shortcuts. There is deliberately no `count` field — the
3202
+ * displayed count is always derived from `items.length`, never supplied by
3203
+ * the caller (see issue #113: brainless, the upstream this was adapted from,
3204
+ * shipped a `count` with no `items`, an honestly-unverifiable number).
3205
+ */
3206
+ interface ShortcutGroup {
3207
+ id: string;
3208
+ label: string;
3209
+ items: Shortcut[];
3210
+ /** Whether this group starts expanded when search is inactive. @default false */
3211
+ defaultOpen?: boolean;
3212
+ }
3213
+ interface KeyboardShortcutsProps extends Omit<ComponentProps<"div">, "onChange"> {
3214
+ groups: ShortcutGroup[];
3215
+ /** Show the built-in search field. @default true */
3216
+ searchable?: boolean;
3217
+ /** Controlled search query, if the app owns it. */
3218
+ query?: string;
3219
+ onQueryChange?: (query: string) => void;
3220
+ }
3221
+ /**
3222
+ * A grouped, searchable presentation of a shortcut set. Renders **content
3223
+ * only** — the app supplies the `Dialog`/`Sheet` shell, so the same
3224
+ * component works in a modal, a settings page or a sidebar.
3225
+ *
3226
+ * Group counts are always derived from `items.length` (or the number of
3227
+ * matching items while a search is active) — never a value passed in.
3228
+ */
3229
+ declare const KeyboardShortcuts: react.ForwardRefExoticComponent<Omit<KeyboardShortcutsProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
3230
+
2203
3231
  interface KeyValueRow {
2204
3232
  key: string;
2205
3233
  value: string;
@@ -2331,10 +3359,42 @@ interface ListEditorProps extends Omit<HTMLAttributes<HTMLDivElement>, "onChange
2331
3359
  *
2332
3360
  * Controlled via `value`/`onValueChange`; uncontrolled via `defaultValue`.
2333
3361
  */
2334
- declare const ListEditor: react.ForwardRefExoticComponent<ListEditorProps & react.RefAttributes<HTMLDivElement>>;
3362
+ declare const ListEditor: react.ForwardRefExoticComponent<ListEditorProps & react.RefAttributes<HTMLDivElement>>;
3363
+
3364
+ /**
3365
+ * ICU cardinal-plural category, per `Intl.PluralRules` ("zero" | "one" | "two"
3366
+ * | "few" | "many" | "other"). Locales vary in which categories they use —
3367
+ * English has only "one"/"other"; Polish and Russian also use "few"/"many" —
3368
+ * so a `PluralMessage` may omit any category it doesn't need. `"other"` is the
3369
+ * universal fallback every locale defines.
3370
+ */
3371
+ type PluralCategory = Intl.LDMLPluralRule;
3372
+ /**
3373
+ * A per-count message: one string per plural category, selected at render
3374
+ * time via `Intl.PluralRules(locale).select(count)`. Each string still
3375
+ * supports the same `{name}`-style interpolation as a plain message.
3376
+ * Note: when passed to `t()`, `count` in `vars` must be a number, not a
3377
+ * numeric string, to select the correct plural category.
3378
+ */
3379
+ type PluralMessage = Partial<Record<PluralCategory, string>>;
3380
+ /** A single message value: a plain string, or a plural-form map. */
3381
+ type MessageValue = string | PluralMessage;
3382
+ /**
3383
+ * Shipped English (en-US) default microcopy bundle.
3384
+ *
3385
+ * Keys are intentionally terse, semantic, and framework-agnostic so they
3386
+ * translate cleanly into any target locale. Keep this list small and real —
3387
+ * only add a key here when a component actually needs it.
3388
+ */
3389
+ declare const DEFAULT_MESSAGES: Record<string, MessageValue>;
2335
3390
 
2336
- /** A flat map of string keys to their translated values. */
2337
- type Messages = Record<string, string>;
3391
+ /**
3392
+ * A flat map of string keys to their translated values — a plain string, or a
3393
+ * `PluralMessage` (one string per ICU cardinal-plural category, e.g.
3394
+ * `{ one: "{count} item", other: "{count} items" }`) for microcopy whose
3395
+ * wording changes with a count. See `PluralMessage` in `./messages`.
3396
+ */
3397
+ type Messages = Record<string, MessageValue>;
2338
3398
  interface LocaleContextValue {
2339
3399
  /** BCP-47 locale tag, e.g. "en-US", "ar-EG", "de-DE". */
2340
3400
  locale: string;
@@ -2342,8 +3402,13 @@ interface LocaleContextValue {
2342
3402
  dir: "ltr" | "rtl";
2343
3403
  /**
2344
3404
  * Translate a key.
2345
- * Falls back to: consumer messages English default the key itself.
2346
- * Supports simple `{name}`-style variable interpolation.
3405
+ * Falls back to: an external `translate` resolver (if the provider was
3406
+ * given one) → consumer `messages` English default → the key itself.
3407
+ * Supports simple `{name}`-style variable interpolation, and ICU
3408
+ * cardinal-plural forms (`Intl.PluralRules`) when the resolved message is a
3409
+ * `PluralMessage` map and `vars.count` is a number. Note: `count` must be a
3410
+ * number, not a numeric string (e.g., `count: 3`, not `count: "3"`) to select
3411
+ * the correct plural category.
2347
3412
  */
2348
3413
  t: (key: string, vars?: Record<string, string | number>) => string;
2349
3414
  /** Format a number using the active locale. Memoized per locale+opts hash. */
@@ -2368,6 +3433,21 @@ interface LocaleProviderProps {
2368
3433
  * to the English bundle.
2369
3434
  */
2370
3435
  messages?: Messages;
3436
+ /**
3437
+ * Optional external resolver — hand brand-ui's microcopy off to an app's own
3438
+ * i18n runtime (next-intl, react-intl, i18next, …) instead of maintaining a
3439
+ * second, flattened message catalogue. Called with the raw key and vars
3440
+ * (not pre-interpolated), so a real ICU formatter gets real values and can
3441
+ * do its own pluralization/number/date formatting.
3442
+ *
3443
+ * Return a string to use it as-is (brand-ui does NOT re-run its own
3444
+ * `{name}` interpolation on it — the app's runtime already formatted it).
3445
+ * Return `undefined`/`null` to decline a key; brand-ui then falls back to
3446
+ * `messages` → `DEFAULT_MESSAGES` → the raw key, in that order — so a
3447
+ * resolver only needs to cover the keys it actually wants to override.
3448
+ * See `docs/I18N.md`.
3449
+ */
3450
+ translate?: (key: string, vars?: Record<string, string | number>) => string | undefined | null;
2371
3451
  children: ReactNode;
2372
3452
  }
2373
3453
  /**
@@ -2382,7 +3462,7 @@ interface LocaleProviderProps {
2382
3462
  * every Radix primitive reads via context regardless of DOM position (ADR-0014).
2383
3463
  * The `<div dir={dir}>` continues to carry direction for non-Radix content.
2384
3464
  */
2385
- declare function LocaleProvider({ locale, dir, messages, children, }: LocaleProviderProps): react.JSX.Element;
3465
+ declare function LocaleProvider({ locale, dir, messages, translate, children, }: LocaleProviderProps): react.JSX.Element;
2386
3466
  /**
2387
3467
  * Read the active locale, direction, `t`, `formatNumber`, and `formatDate`.
2388
3468
  *
@@ -2392,15 +3472,6 @@ declare function LocaleProvider({ locale, dir, messages, children, }: LocaleProv
2392
3472
  */
2393
3473
  declare function useLocale(): LocaleContextValue;
2394
3474
 
2395
- /**
2396
- * Shipped English (en-US) default microcopy bundle.
2397
- *
2398
- * Keys are intentionally terse, semantic, and framework-agnostic so they
2399
- * translate cleanly into any target locale. Keep this list small and real —
2400
- * only add a key here when a component actually needs it.
2401
- */
2402
- declare const DEFAULT_MESSAGES: Record<string, string>;
2403
-
2404
3475
  interface LoadingStateProps {
2405
3476
  /** Accessible status label. Defaults to "Loading…". */
2406
3477
  label?: ReactNode;
@@ -2806,14 +3877,22 @@ interface ModelPickerProps extends Omit<HTMLAttributes<HTMLDivElement>, "onSelec
2806
3877
  open?: boolean;
2807
3878
  /** Fires whenever the popover would open/close — a trigger click, or a row select. */
2808
3879
  onOpenChange?: (open: boolean) => void;
3880
+ /**
3881
+ * Rendered inside the popover BELOW the list — a persistent action row that is
3882
+ * not one of the options (a free-text entry, a "browse…" affordance).
3883
+ * Outside `CommandList` on purpose: it must not be filtered by the search query
3884
+ * and must not participate in cmdk's roving selection.
3885
+ */
3886
+ footer?: ReactNode;
2809
3887
  }
2810
3888
  /**
2811
3889
  * A compact pill that opens a grouped, searchable target list anchored under
2812
3890
  * itself — sized to sit in a composer footer.
2813
3891
  *
2814
- * The inline sibling of `@elabs-ai/components-ai`'s `ModelSelector`,
2815
- * which is the same `Command` internals in a modal `Dialog`. Reach for that one
2816
- * for a full command palette; reach for this one for an in-place picker.
3892
+ * **Which one to reach for.** An inline pill in a composer footer, anchored
3893
+ * under itself this component. A full ⌘K palette compose `CommandDialog` +
3894
+ * `Command*` from this package directly; there is no separate "selector"
3895
+ * component wrapping them.
2817
3896
  *
2818
3897
  * **`Command` lives inside a `Popover`, never a `DropdownMenu`, and that is not
2819
3898
  * a stylistic choice.** `DropdownMenuContent` owns roving tabindex and its own
@@ -2950,12 +4029,45 @@ interface NavNotificationsProps {
2950
4029
  notifications: NavNotification[];
2951
4030
  /** Label for the "view all" footer item. @default "View all notifications" */
2952
4031
  viewAllLabel?: string;
4032
+ /**
4033
+ * Which side of the trigger the menu opens on.
4034
+ *
4035
+ * The default is `"right"`, which is right for the surface this component was
4036
+ * extracted from — a bell sitting in a left-hand nav rail. It is WRONG for a
4037
+ * trigger at the end of a top bar: Radix collision-handling then flips the
4038
+ * menu back across the trigger and it covers the controls beside it. Set
4039
+ * `side="bottom"` (usually with `align="end"`) for a top-bar bell.
4040
+ *
4041
+ * @default "right"
4042
+ */
4043
+ side?: ComponentProps<typeof DropdownMenuContent>["side"];
4044
+ /**
4045
+ * How the menu aligns along that side. Radix's own default is `"center"`;
4046
+ * pass `"end"` so a top-bar menu hangs from the trigger's outer edge instead
4047
+ * of straddling it.
4048
+ */
4049
+ align?: ComponentProps<typeof DropdownMenuContent>["align"];
4050
+ /**
4051
+ * Extra classes for the component ROOT — the bell trigger — merged last, so a
4052
+ * caller can override the shipped `rounded-full` (`component-api.md`).
4053
+ *
4054
+ * There is deliberately NO seam for the portalled menu surface: nothing needs
4055
+ * one today, and an unused prop is a worse API than a missing one. The one
4056
+ * thing a caller used to reach for it (dropping the rail's vertical inset for
4057
+ * a top-bar menu) is now derived from `side` instead — see below.
4058
+ */
4059
+ className?: string;
2953
4060
  }
2954
4061
  /**
2955
- * Sidebar notifications dropdown button. Shared primitive from sidebar-02 (issue #99).
2956
- * Renders a bell-icon ghost button that opens a dropdown listing recent notifications.
4062
+ * Notifications dropdown button. Shared primitive from sidebar-02 (issue #99).
4063
+ * Renders a bell-icon ghost button that opens a dropdown listing recent
4064
+ * notifications.
4065
+ *
4066
+ * Placement is caller-owned via `side`/`align`; the defaults are the original
4067
+ * rail placement, so every existing call site renders unchanged. `className`
4068
+ * styles the trigger, not the menu.
2957
4069
  */
2958
- declare function NavNotifications({ notifications, viewAllLabel, }: NavNotificationsProps): react.JSX.Element;
4070
+ declare function NavNotifications({ notifications, viewAllLabel, side, align, className, }: NavNotificationsProps): react.JSX.Element;
2959
4071
 
2960
4072
  interface NavUserUser {
2961
4073
  name: string;
@@ -2978,14 +4090,14 @@ declare function NavUser({ user }: NavUserProps): react.JSX.Element;
2978
4090
 
2979
4091
  declare const NavigationMenu: react.ForwardRefExoticComponent<Omit<NavigationMenuPrimitive.NavigationMenuProps & react.RefAttributes<HTMLElement>, "ref"> & react.RefAttributes<HTMLElement>>;
2980
4092
  declare const NavigationMenuList: react.ForwardRefExoticComponent<Omit<NavigationMenuPrimitive.NavigationMenuListProps & react.RefAttributes<HTMLUListElement>, "ref"> & react.RefAttributes<HTMLUListElement>>;
2981
- declare const NavigationMenuItem: react.ForwardRefExoticComponent<NavigationMenuPrimitive.NavigationMenuItemProps & react.RefAttributes<HTMLLIElement>>;
4093
+ declare const NavigationMenuItem: react.ForwardRefExoticComponent<Omit<NavigationMenuPrimitive.NavigationMenuItemProps & react.RefAttributes<HTMLLIElement>, "ref"> & react.RefAttributes<HTMLLIElement>>;
2982
4094
  declare const navigationMenuTriggerStyle: (props?: class_variance_authority_types.ClassProp | undefined) => string;
2983
4095
  declare const NavigationMenuTrigger: react.ForwardRefExoticComponent<Omit<NavigationMenuPrimitive.NavigationMenuTriggerProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
2984
4096
  declare const NavigationMenuContent: react.ForwardRefExoticComponent<Omit<NavigationMenuPrimitive.NavigationMenuContentProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
2985
4097
  declare const NavigationMenuLink: react.ForwardRefExoticComponent<NavigationMenuPrimitive.NavigationMenuLinkProps & react.RefAttributes<HTMLAnchorElement>>;
2986
4098
  declare const NavigationMenuViewport: react.ForwardRefExoticComponent<Omit<NavigationMenuPrimitive.NavigationMenuViewportProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
2987
4099
 
2988
- interface PageShellProps {
4100
+ interface PageShellProps extends ComponentProps<"div"> {
2989
4101
  children: ReactNode;
2990
4102
  /** Optional header row (often a <SectionHeader />, or a <ViewToolbar> — see headerVariant). */
2991
4103
  header?: ReactNode;
@@ -3004,11 +4116,42 @@ interface PageShellProps {
3004
4116
  headerVariant?: "default" | "toolbar";
3005
4117
  /** Constrain content width. Defaults to "xl". */
3006
4118
  width?: "md" | "lg" | "xl" | "full";
4119
+ /**
4120
+ * "body" (default) — the page scrolls with the document. Byte-identical to
4121
+ * the pre-#R6 behaviour; existing callers are unaffected.
4122
+ * "content" — this container is the scroll port. Use inside a `SidebarInset`
4123
+ * whose height is already bounded, so the top bar stays put. Defaults its own
4124
+ * `tabIndex` to `0` (a scroll container must be keyboard-operable — WCAG
4125
+ * 2.1.1, axe `scrollable-region-focusable`), following the `DialogBody`
4126
+ * precedent; pass `tabIndex={-1}` to opt out when the content already
4127
+ * supplies its own focusable child.
4128
+ * "fill" — fills its parent and scrolls nothing itself; a child (a table, a
4129
+ * canvas) owns the scrolling — and owns that child's keyboard reachability
4130
+ * too, the same way.
4131
+ */
4132
+ scroll?: "body" | "content" | "fill";
4133
+ /**
4134
+ * Reserve a fixed header row so a page title lands at identical coordinates
4135
+ * on every route, whether or not that route has a header. Default `false`.
4136
+ *
4137
+ * The row's height is a component-local CSS variable —
4138
+ * `--page-shell-header-gutter`, declared on the root, default `--spacing(12)`
4139
+ * (3rem / 48px at a 16px root — the height a one-line title already occupies
4140
+ * inside the `headerVariant="toolbar"` bar's own `py-3`). It is NOT a theme
4141
+ * token (`pnpm theme-parity:check` does not see it); retune it per surface the
4142
+ * same way `--focus-ring-color` is retargeted elsewhere in this package:
4143
+ * `<PageShell headerGutter className="[--page-shell-header-gutter:--spacing(16)]" />`.
4144
+ *
4145
+ * When `true` the header row renders **even if `header` is omitted** — that
4146
+ * empty row is the whole mechanism, and it is what `headerGutter={false}`
4147
+ * must never produce.
4148
+ */
4149
+ headerGutter?: boolean;
3007
4150
  className?: string;
3008
4151
  contentClassName?: string;
3009
4152
  }
3010
4153
  /** Page-level content container with consistent padding and max width. */
3011
- declare function PageShell({ children, header, headerVariant, width, className, contentClassName, }: PageShellProps): react.JSX.Element;
4154
+ declare const PageShell: react.ForwardRefExoticComponent<Omit<PageShellProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
3012
4155
 
3013
4156
  declare function Pagination({ className, ...props }: ComponentProps<"nav">): react.JSX.Element;
3014
4157
  declare const PaginationContent: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLUListElement>, HTMLUListElement>, "ref"> & react.RefAttributes<HTMLUListElement>>;
@@ -3016,7 +4159,7 @@ declare const PaginationItem: react.ForwardRefExoticComponent<Omit<react.Detaile
3016
4159
  type PaginationLinkProps = {
3017
4160
  isActive?: boolean;
3018
4161
  } & ComponentProps<"a">;
3019
- declare function PaginationLink({ className, isActive, ...props }: PaginationLinkProps): react.JSX.Element;
4162
+ declare const PaginationLink: react.ForwardRefExoticComponent<Omit<PaginationLinkProps, "ref"> & react.RefAttributes<HTMLAnchorElement>>;
3020
4163
  declare function PaginationPrevious({ className, ...props }: ComponentProps<"a">): react.JSX.Element;
3021
4164
  declare function PaginationNext({ className, ...props }: ComponentProps<"a">): react.JSX.Element;
3022
4165
  declare function PaginationEllipsis({ className, ...props }: ComponentProps<"span">): react.JSX.Element;
@@ -3073,8 +4216,8 @@ interface RatingProps extends Omit<HTMLAttributes<HTMLDivElement>, "onChange" |
3073
4216
  */
3074
4217
  declare const Rating: react.ForwardRefExoticComponent<RatingProps & react.RefAttributes<HTMLDivElement>>;
3075
4218
 
3076
- declare function ResizablePanelGroup({ className, ...props }: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>): react.JSX.Element;
3077
- declare const ResizablePanel: react.ForwardRefExoticComponent<Omit<react.HTMLAttributes<HTMLAnchorElement | HTMLElement | HTMLDivElement | HTMLObjectElement | HTMLTitleElement | HTMLBodyElement | HTMLMetaElement | HTMLParagraphElement | HTMLSelectElement | HTMLLinkElement | HTMLAreaElement | HTMLAudioElement | HTMLBaseElement | HTMLQuoteElement | HTMLBRElement | HTMLButtonElement | HTMLCanvasElement | HTMLTableColElement | HTMLDataElement | HTMLDataListElement | HTMLModElement | HTMLDetailsElement | HTMLDialogElement | HTMLDListElement | HTMLEmbedElement | HTMLFieldSetElement | HTMLFormElement | HTMLHeadingElement | HTMLHeadElement | HTMLHRElement | HTMLHtmlElement | HTMLIFrameElement | HTMLImageElement | HTMLInputElement | HTMLLabelElement | HTMLLegendElement | HTMLLIElement | HTMLMapElement | HTMLMeterElement | HTMLOListElement | HTMLOptGroupElement | HTMLOptionElement | HTMLOutputElement | HTMLPreElement | HTMLProgressElement | HTMLScriptElement | HTMLSlotElement | HTMLSourceElement | HTMLSpanElement | HTMLStyleElement | HTMLTableElement | HTMLTableSectionElement | HTMLTableCellElement | HTMLTemplateElement | HTMLTextAreaElement | HTMLTimeElement | HTMLTableRowElement | HTMLTrackElement | HTMLUListElement | HTMLVideoElement | HTMLTableCaptionElement | HTMLMenuElement | HTMLPictureElement>, "id" | "onResize"> & {
4219
+ declare const ResizablePanelGroup: ForwardRefExoticComponent<React.ComponentProps<typeof ResizablePrimitive.PanelGroup> & RefAttributes<ResizablePrimitive.ImperativePanelGroupHandle>>;
4220
+ declare const ResizablePanel: ForwardRefExoticComponent<Omit<react.HTMLAttributes<HTMLAnchorElement | HTMLElement | HTMLDivElement | HTMLSpanElement | HTMLObjectElement | HTMLTitleElement | HTMLBodyElement | HTMLMetaElement | HTMLParagraphElement | HTMLSelectElement | HTMLLinkElement | HTMLInputElement | HTMLAreaElement | HTMLAudioElement | HTMLBaseElement | HTMLQuoteElement | HTMLBRElement | HTMLButtonElement | HTMLCanvasElement | HTMLTableColElement | HTMLDataElement | HTMLDataListElement | HTMLModElement | HTMLDetailsElement | HTMLDialogElement | HTMLDListElement | HTMLEmbedElement | HTMLFieldSetElement | HTMLFormElement | HTMLHeadingElement | HTMLHeadElement | HTMLHRElement | HTMLHtmlElement | HTMLIFrameElement | HTMLImageElement | HTMLLabelElement | HTMLLegendElement | HTMLLIElement | HTMLMapElement | HTMLMeterElement | HTMLOListElement | HTMLOptGroupElement | HTMLOptionElement | HTMLOutputElement | HTMLPreElement | HTMLProgressElement | HTMLScriptElement | HTMLSlotElement | HTMLSourceElement | HTMLStyleElement | HTMLTableElement | HTMLTableSectionElement | HTMLTableCellElement | HTMLTemplateElement | HTMLTextAreaElement | HTMLTimeElement | HTMLTableRowElement | HTMLTrackElement | HTMLUListElement | HTMLVideoElement | HTMLTableCaptionElement | HTMLMenuElement | HTMLPictureElement>, "id" | "onResize"> & {
3078
4221
  className?: string | undefined;
3079
4222
  collapsedSize?: number | undefined;
3080
4223
  collapsible?: boolean | undefined;
@@ -3090,8 +4233,16 @@ declare const ResizablePanel: react.ForwardRefExoticComponent<Omit<react.HTMLAtt
3090
4233
  tagName?: keyof HTMLElementTagNameMap | undefined;
3091
4234
  } & {
3092
4235
  children?: react.ReactNode;
3093
- } & react.RefAttributes<ResizablePrimitive.ImperativePanelHandle>>;
3094
- declare function ResizableHandle({ withHandle, className, ...props }: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
4236
+ } & RefAttributes<ResizablePrimitive.ImperativePanelHandle>>;
4237
+ /**
4238
+ * NOT wrapped in `forwardRef`: `react-resizable-panels`' `PanelResizeHandle`
4239
+ * is a plain function component that hardcodes its own internal element ref
4240
+ * and does not accept `ref` as a prop at all (neither in its types nor at
4241
+ * runtime — verified: a `ref` passed to it resolves to `null`). There is no
4242
+ * DOM node here for a wrapper ref to attach to without changing what render
4243
+ * onto the actual drag surface, so adding `forwardRef` would be a dead prop.
4244
+ */
4245
+ declare function ResizableHandle({ withHandle, className, hitAreaMargins, ...props }: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
3095
4246
  withHandle?: boolean;
3096
4247
  }): react.JSX.Element;
3097
4248
 
@@ -3127,6 +4278,1112 @@ interface RevealGroupProps extends HTMLAttributes<HTMLDivElement>, VariantProps<
3127
4278
  */
3128
4279
  declare const RevealGroup: react.ForwardRefExoticComponent<RevealGroupProps & react.RefAttributes<HTMLDivElement>>;
3129
4280
 
4281
+ /**
4282
+ * schema-form-spec.ts — Serializable FormSpec for SchemaForm.
4283
+ *
4284
+ * SchemaForm is the GENERAL, app-UI spec-driven form renderer (issue #22):
4285
+ * describe a configuration form as data, render it. It is the sibling of
4286
+ * `@elabs-ai/components-ai`'s `MessageForm` / `fieldSpecSchema` — NOT a
4287
+ * generalization of it. The two are deliberately separate schemas because
4288
+ * they carry different trust models:
4289
+ *
4290
+ * - `MessageForm`'s `fieldSpecSchema` (`packages/ai/src/message-form-spec.ts`)
4291
+ * is what an LLM tool-call emits inside a chat message. Its vocabulary is
4292
+ * intentionally the SAFE subset — flat scalars only, no file input, no
4293
+ * password/credential format — so a model can never ask a user to hand it
4294
+ * a file or a secret through a chat-rendered form.
4295
+ * - `SchemaForm`'s `fieldSpecSchema` here is DEVELOPER-AUTHORED: a product
4296
+ * describes an integration/config form (connector settings, environment
4297
+ * variables, auth method) as data instead of hand-writing it. That is a
4298
+ * fundamentally different trust boundary, so it is allowed the fuller
4299
+ * vocabulary Onyx-style connector forms need: `list`, `key-value`, `file`,
4300
+ * and grouped alternative field sets (`group`, tabs or advanced-collapsed).
4301
+ *
4302
+ * Shares its overall shape (fields/values/validate/normalize) with
4303
+ * `message-form-spec.ts` by convention, not by import — merging them into one
4304
+ * union would either smuggle `file`/`group` into the chat-safe schema or
4305
+ * strip the safety comment from this one. See the issue-#22 result file for
4306
+ * the full reasoning.
4307
+ */
4308
+
4309
+ /** A single enum choice: a plain value, or a `{ const, title }` pair. */
4310
+ declare const enumOptionSchema: z.ZodUnion<[z.ZodString, z.ZodObject<{
4311
+ const: z.ZodString;
4312
+ title: z.ZodOptional<z.ZodString>;
4313
+ }, "strip", z.ZodTypeAny, {
4314
+ const: string;
4315
+ title?: string | undefined;
4316
+ }, {
4317
+ const: string;
4318
+ title?: string | undefined;
4319
+ }>]>;
4320
+ type EnumOption = z.infer<typeof enumOptionSchema>;
4321
+ /** The submitted value of an enum option. */
4322
+ declare function optionValue(option: EnumOption): string;
4323
+ /** The display label of an enum option (falls back to its value). */
4324
+ declare function optionLabel(option: EnumOption): string;
4325
+ declare const keyValueRowSchema: z.ZodObject<{
4326
+ key: z.ZodString;
4327
+ value: z.ZodString;
4328
+ /** Mask this row's value (rendered as `type="password"` with a reveal toggle). */
4329
+ secret: z.ZodOptional<z.ZodBoolean>;
4330
+ }, "strip", z.ZodTypeAny, {
4331
+ key: string;
4332
+ value: string;
4333
+ secret?: boolean | undefined;
4334
+ }, {
4335
+ key: string;
4336
+ value: string;
4337
+ secret?: boolean | undefined;
4338
+ }>;
4339
+ type FieldKeyValueRow = z.infer<typeof keyValueRowSchema>;
4340
+ /** A single-line or multi-line text field. */
4341
+ declare const stringFieldSchema: z.ZodObject<{
4342
+ default: z.ZodOptional<z.ZodString>;
4343
+ format: z.ZodOptional<z.ZodEnum<["email", "uri", "date", "date-time"]>>;
4344
+ minLength: z.ZodOptional<z.ZodNumber>;
4345
+ maxLength: z.ZodOptional<z.ZodNumber>;
4346
+ /** A serialized RegExp source string (client-enforced when present). */
4347
+ pattern: z.ZodOptional<z.ZodString>;
4348
+ /** Render a textarea instead of a single-line input. */
4349
+ multiline: z.ZodOptional<z.ZodBoolean>;
4350
+ /** Value key in the emitted form state (the `values` object key). */
4351
+ name: z.ZodString;
4352
+ /** Human label. Falls back to a humanized `name` when omitted. */
4353
+ label: z.ZodOptional<z.ZodString>;
4354
+ /** Helper text shown under the control. */
4355
+ description: z.ZodOptional<z.ZodString>;
4356
+ /** Whether a value is required before the form can submit. */
4357
+ required: z.ZodOptional<z.ZodBoolean>;
4358
+ /**
4359
+ * Conditional visibility: render (and validate/submit) this field only
4360
+ * when another field's current value equals `equals` — e.g. show a
4361
+ * "client secret" field only once `authMethod` equals `"oauth"`. Evaluated
4362
+ * by `isFieldVisible` against the form's current values; a hidden field is
4363
+ * excluded from rendering, validation and the first-invalid-focus walk, so
4364
+ * a hidden `required` field never blocks submit.
4365
+ */
4366
+ visibleWhen: z.ZodOptional<z.ZodObject<{
4367
+ /** Name of the controlling field. */
4368
+ field: z.ZodString;
4369
+ /** The controlling field's value that makes this field visible. */
4370
+ equals: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>;
4371
+ }, "strip", z.ZodTypeAny, {
4372
+ field: string;
4373
+ equals: string | number | boolean;
4374
+ }, {
4375
+ field: string;
4376
+ equals: string | number | boolean;
4377
+ }>>;
4378
+ type: z.ZodLiteral<"string">;
4379
+ }, "strip", z.ZodTypeAny, {
4380
+ name: string;
4381
+ type: "string";
4382
+ label?: string | undefined;
4383
+ default?: string | undefined;
4384
+ format?: "email" | "date" | "uri" | "date-time" | undefined;
4385
+ pattern?: string | undefined;
4386
+ maxLength?: number | undefined;
4387
+ minLength?: number | undefined;
4388
+ required?: boolean | undefined;
4389
+ description?: string | undefined;
4390
+ multiline?: boolean | undefined;
4391
+ visibleWhen?: {
4392
+ field: string;
4393
+ equals: string | number | boolean;
4394
+ } | undefined;
4395
+ }, {
4396
+ name: string;
4397
+ type: "string";
4398
+ label?: string | undefined;
4399
+ default?: string | undefined;
4400
+ format?: "email" | "date" | "uri" | "date-time" | undefined;
4401
+ pattern?: string | undefined;
4402
+ maxLength?: number | undefined;
4403
+ minLength?: number | undefined;
4404
+ required?: boolean | undefined;
4405
+ description?: string | undefined;
4406
+ multiline?: boolean | undefined;
4407
+ visibleWhen?: {
4408
+ field: string;
4409
+ equals: string | number | boolean;
4410
+ } | undefined;
4411
+ }>;
4412
+ type StringFieldSpec = z.infer<typeof stringFieldSchema>;
4413
+ /** A floating-point number field. */
4414
+ declare const numberFieldSchema: z.ZodObject<{
4415
+ default: z.ZodOptional<z.ZodNumber>;
4416
+ min: z.ZodOptional<z.ZodNumber>;
4417
+ max: z.ZodOptional<z.ZodNumber>;
4418
+ /** Value key in the emitted form state (the `values` object key). */
4419
+ name: z.ZodString;
4420
+ /** Human label. Falls back to a humanized `name` when omitted. */
4421
+ label: z.ZodOptional<z.ZodString>;
4422
+ /** Helper text shown under the control. */
4423
+ description: z.ZodOptional<z.ZodString>;
4424
+ /** Whether a value is required before the form can submit. */
4425
+ required: z.ZodOptional<z.ZodBoolean>;
4426
+ /**
4427
+ * Conditional visibility: render (and validate/submit) this field only
4428
+ * when another field's current value equals `equals` — e.g. show a
4429
+ * "client secret" field only once `authMethod` equals `"oauth"`. Evaluated
4430
+ * by `isFieldVisible` against the form's current values; a hidden field is
4431
+ * excluded from rendering, validation and the first-invalid-focus walk, so
4432
+ * a hidden `required` field never blocks submit.
4433
+ */
4434
+ visibleWhen: z.ZodOptional<z.ZodObject<{
4435
+ /** Name of the controlling field. */
4436
+ field: z.ZodString;
4437
+ /** The controlling field's value that makes this field visible. */
4438
+ equals: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>;
4439
+ }, "strip", z.ZodTypeAny, {
4440
+ field: string;
4441
+ equals: string | number | boolean;
4442
+ }, {
4443
+ field: string;
4444
+ equals: string | number | boolean;
4445
+ }>>;
4446
+ type: z.ZodLiteral<"number">;
4447
+ }, "strip", z.ZodTypeAny, {
4448
+ name: string;
4449
+ type: "number";
4450
+ label?: string | undefined;
4451
+ default?: number | undefined;
4452
+ max?: number | undefined;
4453
+ min?: number | undefined;
4454
+ required?: boolean | undefined;
4455
+ description?: string | undefined;
4456
+ visibleWhen?: {
4457
+ field: string;
4458
+ equals: string | number | boolean;
4459
+ } | undefined;
4460
+ }, {
4461
+ name: string;
4462
+ type: "number";
4463
+ label?: string | undefined;
4464
+ default?: number | undefined;
4465
+ max?: number | undefined;
4466
+ min?: number | undefined;
4467
+ required?: boolean | undefined;
4468
+ description?: string | undefined;
4469
+ visibleWhen?: {
4470
+ field: string;
4471
+ equals: string | number | boolean;
4472
+ } | undefined;
4473
+ }>;
4474
+ type NumberFieldSpec = z.infer<typeof numberFieldSchema>;
4475
+ /** A whole-number field. */
4476
+ declare const integerFieldSchema: z.ZodObject<{
4477
+ default: z.ZodOptional<z.ZodNumber>;
4478
+ min: z.ZodOptional<z.ZodNumber>;
4479
+ max: z.ZodOptional<z.ZodNumber>;
4480
+ /** Value key in the emitted form state (the `values` object key). */
4481
+ name: z.ZodString;
4482
+ /** Human label. Falls back to a humanized `name` when omitted. */
4483
+ label: z.ZodOptional<z.ZodString>;
4484
+ /** Helper text shown under the control. */
4485
+ description: z.ZodOptional<z.ZodString>;
4486
+ /** Whether a value is required before the form can submit. */
4487
+ required: z.ZodOptional<z.ZodBoolean>;
4488
+ /**
4489
+ * Conditional visibility: render (and validate/submit) this field only
4490
+ * when another field's current value equals `equals` — e.g. show a
4491
+ * "client secret" field only once `authMethod` equals `"oauth"`. Evaluated
4492
+ * by `isFieldVisible` against the form's current values; a hidden field is
4493
+ * excluded from rendering, validation and the first-invalid-focus walk, so
4494
+ * a hidden `required` field never blocks submit.
4495
+ */
4496
+ visibleWhen: z.ZodOptional<z.ZodObject<{
4497
+ /** Name of the controlling field. */
4498
+ field: z.ZodString;
4499
+ /** The controlling field's value that makes this field visible. */
4500
+ equals: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>;
4501
+ }, "strip", z.ZodTypeAny, {
4502
+ field: string;
4503
+ equals: string | number | boolean;
4504
+ }, {
4505
+ field: string;
4506
+ equals: string | number | boolean;
4507
+ }>>;
4508
+ type: z.ZodLiteral<"integer">;
4509
+ }, "strip", z.ZodTypeAny, {
4510
+ name: string;
4511
+ type: "integer";
4512
+ label?: string | undefined;
4513
+ default?: number | undefined;
4514
+ max?: number | undefined;
4515
+ min?: number | undefined;
4516
+ required?: boolean | undefined;
4517
+ description?: string | undefined;
4518
+ visibleWhen?: {
4519
+ field: string;
4520
+ equals: string | number | boolean;
4521
+ } | undefined;
4522
+ }, {
4523
+ name: string;
4524
+ type: "integer";
4525
+ label?: string | undefined;
4526
+ default?: number | undefined;
4527
+ max?: number | undefined;
4528
+ min?: number | undefined;
4529
+ required?: boolean | undefined;
4530
+ description?: string | undefined;
4531
+ visibleWhen?: {
4532
+ field: string;
4533
+ equals: string | number | boolean;
4534
+ } | undefined;
4535
+ }>;
4536
+ type IntegerFieldSpec = z.infer<typeof integerFieldSchema>;
4537
+ /** A boolean checkbox field. */
4538
+ declare const booleanFieldSchema: z.ZodObject<{
4539
+ default: z.ZodOptional<z.ZodBoolean>;
4540
+ /** Value key in the emitted form state (the `values` object key). */
4541
+ name: z.ZodString;
4542
+ /** Human label. Falls back to a humanized `name` when omitted. */
4543
+ label: z.ZodOptional<z.ZodString>;
4544
+ /** Helper text shown under the control. */
4545
+ description: z.ZodOptional<z.ZodString>;
4546
+ /** Whether a value is required before the form can submit. */
4547
+ required: z.ZodOptional<z.ZodBoolean>;
4548
+ /**
4549
+ * Conditional visibility: render (and validate/submit) this field only
4550
+ * when another field's current value equals `equals` — e.g. show a
4551
+ * "client secret" field only once `authMethod` equals `"oauth"`. Evaluated
4552
+ * by `isFieldVisible` against the form's current values; a hidden field is
4553
+ * excluded from rendering, validation and the first-invalid-focus walk, so
4554
+ * a hidden `required` field never blocks submit.
4555
+ */
4556
+ visibleWhen: z.ZodOptional<z.ZodObject<{
4557
+ /** Name of the controlling field. */
4558
+ field: z.ZodString;
4559
+ /** The controlling field's value that makes this field visible. */
4560
+ equals: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>;
4561
+ }, "strip", z.ZodTypeAny, {
4562
+ field: string;
4563
+ equals: string | number | boolean;
4564
+ }, {
4565
+ field: string;
4566
+ equals: string | number | boolean;
4567
+ }>>;
4568
+ type: z.ZodLiteral<"boolean">;
4569
+ }, "strip", z.ZodTypeAny, {
4570
+ name: string;
4571
+ type: "boolean";
4572
+ label?: string | undefined;
4573
+ default?: boolean | undefined;
4574
+ required?: boolean | undefined;
4575
+ description?: string | undefined;
4576
+ visibleWhen?: {
4577
+ field: string;
4578
+ equals: string | number | boolean;
4579
+ } | undefined;
4580
+ }, {
4581
+ name: string;
4582
+ type: "boolean";
4583
+ label?: string | undefined;
4584
+ default?: boolean | undefined;
4585
+ required?: boolean | undefined;
4586
+ description?: string | undefined;
4587
+ visibleWhen?: {
4588
+ field: string;
4589
+ equals: string | number | boolean;
4590
+ } | undefined;
4591
+ }>;
4592
+ type BooleanFieldSpec = z.infer<typeof booleanFieldSchema>;
4593
+ /** A single-select enum (one value from `options`). */
4594
+ declare const enumFieldSchema: z.ZodObject<{
4595
+ options: z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodObject<{
4596
+ const: z.ZodString;
4597
+ title: z.ZodOptional<z.ZodString>;
4598
+ }, "strip", z.ZodTypeAny, {
4599
+ const: string;
4600
+ title?: string | undefined;
4601
+ }, {
4602
+ const: string;
4603
+ title?: string | undefined;
4604
+ }>]>, "many">;
4605
+ default: z.ZodOptional<z.ZodString>;
4606
+ /** Value key in the emitted form state (the `values` object key). */
4607
+ name: z.ZodString;
4608
+ /** Human label. Falls back to a humanized `name` when omitted. */
4609
+ label: z.ZodOptional<z.ZodString>;
4610
+ /** Helper text shown under the control. */
4611
+ description: z.ZodOptional<z.ZodString>;
4612
+ /** Whether a value is required before the form can submit. */
4613
+ required: z.ZodOptional<z.ZodBoolean>;
4614
+ /**
4615
+ * Conditional visibility: render (and validate/submit) this field only
4616
+ * when another field's current value equals `equals` — e.g. show a
4617
+ * "client secret" field only once `authMethod` equals `"oauth"`. Evaluated
4618
+ * by `isFieldVisible` against the form's current values; a hidden field is
4619
+ * excluded from rendering, validation and the first-invalid-focus walk, so
4620
+ * a hidden `required` field never blocks submit.
4621
+ */
4622
+ visibleWhen: z.ZodOptional<z.ZodObject<{
4623
+ /** Name of the controlling field. */
4624
+ field: z.ZodString;
4625
+ /** The controlling field's value that makes this field visible. */
4626
+ equals: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>;
4627
+ }, "strip", z.ZodTypeAny, {
4628
+ field: string;
4629
+ equals: string | number | boolean;
4630
+ }, {
4631
+ field: string;
4632
+ equals: string | number | boolean;
4633
+ }>>;
4634
+ type: z.ZodLiteral<"enum">;
4635
+ }, "strip", z.ZodTypeAny, {
4636
+ name: string;
4637
+ type: "enum";
4638
+ options: (string | {
4639
+ const: string;
4640
+ title?: string | undefined;
4641
+ })[];
4642
+ label?: string | undefined;
4643
+ default?: string | undefined;
4644
+ required?: boolean | undefined;
4645
+ description?: string | undefined;
4646
+ visibleWhen?: {
4647
+ field: string;
4648
+ equals: string | number | boolean;
4649
+ } | undefined;
4650
+ }, {
4651
+ name: string;
4652
+ type: "enum";
4653
+ options: (string | {
4654
+ const: string;
4655
+ title?: string | undefined;
4656
+ })[];
4657
+ label?: string | undefined;
4658
+ default?: string | undefined;
4659
+ required?: boolean | undefined;
4660
+ description?: string | undefined;
4661
+ visibleWhen?: {
4662
+ field: string;
4663
+ equals: string | number | boolean;
4664
+ } | undefined;
4665
+ }>;
4666
+ type EnumFieldSpec = z.infer<typeof enumFieldSchema>;
4667
+ /** A multi-select enum (zero or more values from `options`). */
4668
+ declare const multiEnumFieldSchema: z.ZodObject<{
4669
+ options: z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodObject<{
4670
+ const: z.ZodString;
4671
+ title: z.ZodOptional<z.ZodString>;
4672
+ }, "strip", z.ZodTypeAny, {
4673
+ const: string;
4674
+ title?: string | undefined;
4675
+ }, {
4676
+ const: string;
4677
+ title?: string | undefined;
4678
+ }>]>, "many">;
4679
+ default: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
4680
+ /** Value key in the emitted form state (the `values` object key). */
4681
+ name: z.ZodString;
4682
+ /** Human label. Falls back to a humanized `name` when omitted. */
4683
+ label: z.ZodOptional<z.ZodString>;
4684
+ /** Helper text shown under the control. */
4685
+ description: z.ZodOptional<z.ZodString>;
4686
+ /** Whether a value is required before the form can submit. */
4687
+ required: z.ZodOptional<z.ZodBoolean>;
4688
+ /**
4689
+ * Conditional visibility: render (and validate/submit) this field only
4690
+ * when another field's current value equals `equals` — e.g. show a
4691
+ * "client secret" field only once `authMethod` equals `"oauth"`. Evaluated
4692
+ * by `isFieldVisible` against the form's current values; a hidden field is
4693
+ * excluded from rendering, validation and the first-invalid-focus walk, so
4694
+ * a hidden `required` field never blocks submit.
4695
+ */
4696
+ visibleWhen: z.ZodOptional<z.ZodObject<{
4697
+ /** Name of the controlling field. */
4698
+ field: z.ZodString;
4699
+ /** The controlling field's value that makes this field visible. */
4700
+ equals: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>;
4701
+ }, "strip", z.ZodTypeAny, {
4702
+ field: string;
4703
+ equals: string | number | boolean;
4704
+ }, {
4705
+ field: string;
4706
+ equals: string | number | boolean;
4707
+ }>>;
4708
+ type: z.ZodLiteral<"multi-enum">;
4709
+ }, "strip", z.ZodTypeAny, {
4710
+ name: string;
4711
+ type: "multi-enum";
4712
+ options: (string | {
4713
+ const: string;
4714
+ title?: string | undefined;
4715
+ })[];
4716
+ label?: string | undefined;
4717
+ default?: string[] | undefined;
4718
+ required?: boolean | undefined;
4719
+ description?: string | undefined;
4720
+ visibleWhen?: {
4721
+ field: string;
4722
+ equals: string | number | boolean;
4723
+ } | undefined;
4724
+ }, {
4725
+ name: string;
4726
+ type: "multi-enum";
4727
+ options: (string | {
4728
+ const: string;
4729
+ title?: string | undefined;
4730
+ })[];
4731
+ label?: string | undefined;
4732
+ default?: string[] | undefined;
4733
+ required?: boolean | undefined;
4734
+ description?: string | undefined;
4735
+ visibleWhen?: {
4736
+ field: string;
4737
+ equals: string | number | boolean;
4738
+ } | undefined;
4739
+ }>;
4740
+ type MultiEnumFieldSpec = z.infer<typeof multiEnumFieldSchema>;
4741
+ /** A repeating list of strings (Onyx's `list`) → renders `ListEditor`. */
4742
+ declare const listFieldSchema: z.ZodObject<{
4743
+ default: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
4744
+ minItems: z.ZodOptional<z.ZodNumber>;
4745
+ maxItems: z.ZodOptional<z.ZodNumber>;
4746
+ itemPlaceholder: z.ZodOptional<z.ZodString>;
4747
+ /** Value key in the emitted form state (the `values` object key). */
4748
+ name: z.ZodString;
4749
+ /** Human label. Falls back to a humanized `name` when omitted. */
4750
+ label: z.ZodOptional<z.ZodString>;
4751
+ /** Helper text shown under the control. */
4752
+ description: z.ZodOptional<z.ZodString>;
4753
+ /** Whether a value is required before the form can submit. */
4754
+ required: z.ZodOptional<z.ZodBoolean>;
4755
+ /**
4756
+ * Conditional visibility: render (and validate/submit) this field only
4757
+ * when another field's current value equals `equals` — e.g. show a
4758
+ * "client secret" field only once `authMethod` equals `"oauth"`. Evaluated
4759
+ * by `isFieldVisible` against the form's current values; a hidden field is
4760
+ * excluded from rendering, validation and the first-invalid-focus walk, so
4761
+ * a hidden `required` field never blocks submit.
4762
+ */
4763
+ visibleWhen: z.ZodOptional<z.ZodObject<{
4764
+ /** Name of the controlling field. */
4765
+ field: z.ZodString;
4766
+ /** The controlling field's value that makes this field visible. */
4767
+ equals: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>;
4768
+ }, "strip", z.ZodTypeAny, {
4769
+ field: string;
4770
+ equals: string | number | boolean;
4771
+ }, {
4772
+ field: string;
4773
+ equals: string | number | boolean;
4774
+ }>>;
4775
+ type: z.ZodLiteral<"list">;
4776
+ }, "strip", z.ZodTypeAny, {
4777
+ name: string;
4778
+ type: "list";
4779
+ label?: string | undefined;
4780
+ default?: string[] | undefined;
4781
+ required?: boolean | undefined;
4782
+ description?: string | undefined;
4783
+ visibleWhen?: {
4784
+ field: string;
4785
+ equals: string | number | boolean;
4786
+ } | undefined;
4787
+ minItems?: number | undefined;
4788
+ maxItems?: number | undefined;
4789
+ itemPlaceholder?: string | undefined;
4790
+ }, {
4791
+ name: string;
4792
+ type: "list";
4793
+ label?: string | undefined;
4794
+ default?: string[] | undefined;
4795
+ required?: boolean | undefined;
4796
+ description?: string | undefined;
4797
+ visibleWhen?: {
4798
+ field: string;
4799
+ equals: string | number | boolean;
4800
+ } | undefined;
4801
+ minItems?: number | undefined;
4802
+ maxItems?: number | undefined;
4803
+ itemPlaceholder?: string | undefined;
4804
+ }>;
4805
+ type ListFieldSpec = z.infer<typeof listFieldSchema>;
4806
+ /** A repeating key/value list, e.g. headers or env vars (Onyx's `string_pair_list`) → renders `KeyValueEditor`. */
4807
+ declare const keyValueFieldSchema: z.ZodObject<{
4808
+ default: z.ZodOptional<z.ZodArray<z.ZodObject<{
4809
+ key: z.ZodString;
4810
+ value: z.ZodString;
4811
+ /** Mask this row's value (rendered as `type="password"` with a reveal toggle). */
4812
+ secret: z.ZodOptional<z.ZodBoolean>;
4813
+ }, "strip", z.ZodTypeAny, {
4814
+ key: string;
4815
+ value: string;
4816
+ secret?: boolean | undefined;
4817
+ }, {
4818
+ key: string;
4819
+ value: string;
4820
+ secret?: boolean | undefined;
4821
+ }>, "many">>;
4822
+ keyPlaceholder: z.ZodOptional<z.ZodString>;
4823
+ valuePlaceholder: z.ZodOptional<z.ZodString>;
4824
+ /** Value key in the emitted form state (the `values` object key). */
4825
+ name: z.ZodString;
4826
+ /** Human label. Falls back to a humanized `name` when omitted. */
4827
+ label: z.ZodOptional<z.ZodString>;
4828
+ /** Helper text shown under the control. */
4829
+ description: z.ZodOptional<z.ZodString>;
4830
+ /** Whether a value is required before the form can submit. */
4831
+ required: z.ZodOptional<z.ZodBoolean>;
4832
+ /**
4833
+ * Conditional visibility: render (and validate/submit) this field only
4834
+ * when another field's current value equals `equals` — e.g. show a
4835
+ * "client secret" field only once `authMethod` equals `"oauth"`. Evaluated
4836
+ * by `isFieldVisible` against the form's current values; a hidden field is
4837
+ * excluded from rendering, validation and the first-invalid-focus walk, so
4838
+ * a hidden `required` field never blocks submit.
4839
+ */
4840
+ visibleWhen: z.ZodOptional<z.ZodObject<{
4841
+ /** Name of the controlling field. */
4842
+ field: z.ZodString;
4843
+ /** The controlling field's value that makes this field visible. */
4844
+ equals: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>;
4845
+ }, "strip", z.ZodTypeAny, {
4846
+ field: string;
4847
+ equals: string | number | boolean;
4848
+ }, {
4849
+ field: string;
4850
+ equals: string | number | boolean;
4851
+ }>>;
4852
+ type: z.ZodLiteral<"key-value">;
4853
+ }, "strip", z.ZodTypeAny, {
4854
+ name: string;
4855
+ type: "key-value";
4856
+ label?: string | undefined;
4857
+ default?: {
4858
+ key: string;
4859
+ value: string;
4860
+ secret?: boolean | undefined;
4861
+ }[] | undefined;
4862
+ required?: boolean | undefined;
4863
+ description?: string | undefined;
4864
+ keyPlaceholder?: string | undefined;
4865
+ valuePlaceholder?: string | undefined;
4866
+ visibleWhen?: {
4867
+ field: string;
4868
+ equals: string | number | boolean;
4869
+ } | undefined;
4870
+ }, {
4871
+ name: string;
4872
+ type: "key-value";
4873
+ label?: string | undefined;
4874
+ default?: {
4875
+ key: string;
4876
+ value: string;
4877
+ secret?: boolean | undefined;
4878
+ }[] | undefined;
4879
+ required?: boolean | undefined;
4880
+ description?: string | undefined;
4881
+ keyPlaceholder?: string | undefined;
4882
+ valuePlaceholder?: string | undefined;
4883
+ visibleWhen?: {
4884
+ field: string;
4885
+ equals: string | number | boolean;
4886
+ } | undefined;
4887
+ }>;
4888
+ type KeyValueFieldSpec = z.infer<typeof keyValueFieldSchema>;
4889
+ /** A file-upload field (Onyx's `file`) → renders `FileUpload`. No `default` — files cannot be defaulted. */
4890
+ declare const fileFieldSchema: z.ZodObject<{
4891
+ /** Forwarded to the native `<input accept>` (comma-separated extensions/MIME types). */
4892
+ accept: z.ZodOptional<z.ZodString>;
4893
+ multiple: z.ZodOptional<z.ZodBoolean>;
4894
+ /** Maximum individual file size, in bytes. */
4895
+ maxSize: z.ZodOptional<z.ZodNumber>;
4896
+ /** Maximum number of files (only meaningful when `multiple`). */
4897
+ maxFiles: z.ZodOptional<z.ZodNumber>;
4898
+ /** Value key in the emitted form state (the `values` object key). */
4899
+ name: z.ZodString;
4900
+ /** Human label. Falls back to a humanized `name` when omitted. */
4901
+ label: z.ZodOptional<z.ZodString>;
4902
+ /** Helper text shown under the control. */
4903
+ description: z.ZodOptional<z.ZodString>;
4904
+ /** Whether a value is required before the form can submit. */
4905
+ required: z.ZodOptional<z.ZodBoolean>;
4906
+ /**
4907
+ * Conditional visibility: render (and validate/submit) this field only
4908
+ * when another field's current value equals `equals` — e.g. show a
4909
+ * "client secret" field only once `authMethod` equals `"oauth"`. Evaluated
4910
+ * by `isFieldVisible` against the form's current values; a hidden field is
4911
+ * excluded from rendering, validation and the first-invalid-focus walk, so
4912
+ * a hidden `required` field never blocks submit.
4913
+ */
4914
+ visibleWhen: z.ZodOptional<z.ZodObject<{
4915
+ /** Name of the controlling field. */
4916
+ field: z.ZodString;
4917
+ /** The controlling field's value that makes this field visible. */
4918
+ equals: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>;
4919
+ }, "strip", z.ZodTypeAny, {
4920
+ field: string;
4921
+ equals: string | number | boolean;
4922
+ }, {
4923
+ field: string;
4924
+ equals: string | number | boolean;
4925
+ }>>;
4926
+ type: z.ZodLiteral<"file">;
4927
+ }, "strip", z.ZodTypeAny, {
4928
+ name: string;
4929
+ type: "file";
4930
+ label?: string | undefined;
4931
+ accept?: string | undefined;
4932
+ multiple?: boolean | undefined;
4933
+ required?: boolean | undefined;
4934
+ description?: string | undefined;
4935
+ maxSize?: number | undefined;
4936
+ maxFiles?: number | undefined;
4937
+ visibleWhen?: {
4938
+ field: string;
4939
+ equals: string | number | boolean;
4940
+ } | undefined;
4941
+ }, {
4942
+ name: string;
4943
+ type: "file";
4944
+ label?: string | undefined;
4945
+ accept?: string | undefined;
4946
+ multiple?: boolean | undefined;
4947
+ required?: boolean | undefined;
4948
+ description?: string | undefined;
4949
+ maxSize?: number | undefined;
4950
+ maxFiles?: number | undefined;
4951
+ visibleWhen?: {
4952
+ field: string;
4953
+ equals: string | number | boolean;
4954
+ } | undefined;
4955
+ }>;
4956
+ type FileFieldSpec = z.infer<typeof fileFieldSchema>;
4957
+ /**
4958
+ * Any one field in a FormSpec — pre-declared here (a plain TS union, not
4959
+ * `z.infer`) so `GroupItemSpec`/`GroupFieldSpec` below can reference it and
4960
+ * vice versa. TypeScript resolves mutual recursion between `type`/`interface`
4961
+ * declarations regardless of file order (no runtime value is involved); only
4962
+ * the `const` zod schemas further down need an explicit `z.ZodType<…>`
4963
+ * annotation to break the equivalent circular VALUE reference through
4964
+ * `z.lazy`.
4965
+ */
4966
+ type FieldSpec = StringFieldSpec | NumberFieldSpec | IntegerFieldSpec | BooleanFieldSpec | EnumFieldSpec | MultiEnumFieldSpec | ListFieldSpec | KeyValueFieldSpec | FileFieldSpec | GroupFieldSpec;
4967
+ /** One named branch of a `group` field's `groups` array. Recursive — a branch's `fields` are ordinary `FieldSpec`s, including nested groups. */
4968
+ interface GroupItemSpec {
4969
+ /** Stable key for this branch — also the value stored when `variant: "tabs"`. */
4970
+ key: string;
4971
+ label: string;
4972
+ description?: string;
4973
+ fields: FieldSpec[];
4974
+ }
4975
+ /**
4976
+ * Grouped alternative field sets (Onyx's `tab` / `string_tab`) → renders
4977
+ * `Tabs` (`variant: "tabs"`, mutually exclusive — e.g. "OAuth" vs "API key")
4978
+ * or a stack of `AdvancedGroup` disclosures (`variant: "advanced"` — always-
4979
+ * available secondary fields, not mutually exclusive).
4980
+ *
4981
+ * For `variant: "tabs"`, the field's OWN value (`values[field.name]`) is the
4982
+ * active branch's `key` — the group behaves like a single-select enum over
4983
+ * its branches. Only the active branch's fields are validated/required;
4984
+ * `variant: "advanced"` has no notion of an active branch, so every branch's
4985
+ * fields are always validated.
4986
+ */
4987
+ interface GroupFieldSpec {
4988
+ type: "group";
4989
+ name: string;
4990
+ label?: string;
4991
+ description?: string;
4992
+ required?: boolean;
4993
+ /** See `visibleWhen` on `baseField` — conditional visibility for the whole group (and its subtree). */
4994
+ visibleWhen?: {
4995
+ field: string;
4996
+ equals: string | number | boolean;
4997
+ };
4998
+ variant: "tabs" | "advanced";
4999
+ groups: GroupItemSpec[];
5000
+ /** Default active branch key. Only meaningful for `variant: "tabs"`. @default groups[0].key */
5001
+ default?: string;
5002
+ }
5003
+ declare const groupItemSchema: z.ZodType<GroupItemSpec>;
5004
+ declare const groupFieldSchema: z.ZodType<GroupFieldSpec>;
5005
+ /**
5006
+ * NOTE: cast through `unknown` — `z.discriminatedUnion`'s own inferred output
5007
+ * type is not assignable to the hand-declared `FieldSpec` union once one
5008
+ * member (`groupFieldSchema`) is itself hand-typed via `z.ZodType<…>` rather
5009
+ * than inferred; the runtime validator (discriminate on `type`, then run each
5010
+ * member's real `.parse`) is unaffected; only the static type is asserted.
5011
+ */
5012
+ declare const fieldSpecSchema: z.ZodType<FieldSpec>;
5013
+ /**
5014
+ * The serializable form specification SchemaForm reads, renders and submits
5015
+ * as `{ formName, values }`.
5016
+ */
5017
+ declare const formSpecSchema: z.ZodObject<{
5018
+ /** Stable identifier echoed back in the submit payload. */
5019
+ formName: z.ZodString;
5020
+ /** Heading rendered above the fields (also the accessible form name). */
5021
+ title: z.ZodOptional<z.ZodString>;
5022
+ /** Supplemental description under the title. */
5023
+ description: z.ZodOptional<z.ZodString>;
5024
+ /** The ordered fields to render. */
5025
+ fields: z.ZodArray<z.ZodType<FieldSpec, z.ZodTypeDef, FieldSpec>, "many">;
5026
+ /** Submit button label. @default "Submit" */
5027
+ submitLabel: z.ZodOptional<z.ZodString>;
5028
+ }, "strip", z.ZodTypeAny, {
5029
+ fields: FieldSpec[];
5030
+ formName: string;
5031
+ title?: string | undefined;
5032
+ description?: string | undefined;
5033
+ submitLabel?: string | undefined;
5034
+ }, {
5035
+ fields: FieldSpec[];
5036
+ formName: string;
5037
+ title?: string | undefined;
5038
+ description?: string | undefined;
5039
+ submitLabel?: string | undefined;
5040
+ }>;
5041
+ type FormSpec = Omit<z.infer<typeof formSpecSchema>, "fields"> & {
5042
+ fields: FieldSpec[];
5043
+ };
5044
+ /** A single field's value in the form state. */
5045
+ type FormValue = string | number | boolean | string[] | FieldKeyValueRow[] | File[] | undefined;
5046
+ /** The `values` object keyed by field `name`. */
5047
+ type FormValues = Record<string, FormValue>;
5048
+ /** The payload passed to `onSubmit`. */
5049
+ interface FormSubmitState {
5050
+ /** Echoes `spec.formName`. */
5051
+ formName: string;
5052
+ /** The current field values keyed by field name. */
5053
+ values: FormValues;
5054
+ }
5055
+ /** A validated, render-ready FormSpec. */
5056
+ interface NormalizedFormSpec {
5057
+ formName: string;
5058
+ title?: string;
5059
+ description?: string;
5060
+ submitLabel?: string;
5061
+ fields: FieldSpec[];
5062
+ }
5063
+ declare function normalizeFormSpec(spec: unknown): {
5064
+ ok: true;
5065
+ spec: NormalizedFormSpec;
5066
+ } | {
5067
+ ok: false;
5068
+ reason: string;
5069
+ };
5070
+ /** Find a field by name anywhere in the tree, including inside `group` branches. */
5071
+ declare function findFieldByName(fields: FieldSpec[], name: string): FieldSpec | undefined;
5072
+ /**
5073
+ * Does `field` currently satisfy its own `visibleWhen` (if it has one)? A
5074
+ * field with no `visibleWhen` is always visible. Shared by the render loops
5075
+ * (schema-form.tsx) and `collectValidatableFields` below, so what's shown and
5076
+ * what's validated/submitted never disagree.
5077
+ */
5078
+ declare function isFieldVisible(field: FieldSpec, values: FormValues): boolean;
5079
+ /**
5080
+ * The fields that currently participate in validation/submission: every
5081
+ * scalar field, plus — for a `group` field — either the ACTIVE branch's
5082
+ * fields (`variant: "tabs"`, keyed by `values[field.name]`) or ALL branches'
5083
+ * fields (`variant: "advanced"`, nothing is mutually exclusive there). A
5084
+ * field (or, for a hidden `group`, its whole subtree) whose `visibleWhen`
5085
+ * does not currently hold is excluded entirely — a hidden `required` field
5086
+ * must never block submit.
5087
+ */
5088
+ declare function collectValidatableFields(fields: FieldSpec[], values: FormValues): FieldSpec[];
5089
+ /** The label to show for a field (explicit `label`, else a humanized `name`). */
5090
+ declare function fieldLabel(field: FieldSpec): string;
5091
+ /** Seed the initial values from every field's `default` (+ sensible empties), recursively. */
5092
+ declare function initialFormValues(fields: FieldSpec[]): FormValues;
5093
+ /**
5094
+ * Validate one field's value against its declarative constraints.
5095
+ * Returns a short human error message, or `null` when the value is valid.
5096
+ * The vocabulary: required · email · url · min · max · minLength · maxLength ·
5097
+ * pattern · numeric (integer whole-number) · minItems/maxItems (list).
5098
+ */
5099
+ declare function validateField(field: FieldSpec, value: FormValue): string | null;
5100
+ /** Validate every VALIDATABLE field (see `collectValidatableFields`); returns a `{ [name]: error | null }` map. */
5101
+ declare function validateForm(fields: FieldSpec[], values: FormValues): Record<string, string | null>;
5102
+ /** Does `file` satisfy an `<input accept>`-style pattern (extensions, MIME types, or `type/*`)? */
5103
+ declare function fileMatchesAccept(file: File, accept: string | undefined): boolean;
5104
+ interface FileIssue {
5105
+ reason: "wrong-type" | "too-large";
5106
+ message: string;
5107
+ }
5108
+ /** Client-side per-file check for the designed `file` field states: wrong type, too large. */
5109
+ declare function checkFileIssue(file: File, field: FileFieldSpec): FileIssue | null;
5110
+
5111
+ interface SchemaFormProviderProps {
5112
+ /** A validated/normalized spec (a plain `FormSpec` also satisfies this). */
5113
+ spec: NormalizedFormSpec;
5114
+ /**
5115
+ * Controlled values. When provided the component is controlled and
5116
+ * `onChange` is the only way to update state.
5117
+ */
5118
+ values?: FormValues;
5119
+ /** Called with the next full values object on any field change. */
5120
+ onChange?: (values: FormValues) => void;
5121
+ /** Called with `{ formName, values }` when a valid form is submitted. */
5122
+ onSubmit?: (state: FormSubmitState) => void;
5123
+ /** Disable every control (form is read-only). A deliberate, durable state. */
5124
+ disabled?: boolean;
5125
+ /** Terminal submitted state: controls are inert, values visible, no submit. */
5126
+ submitted?: boolean;
5127
+ /** In-flight submit: controls transiently blocked, submit shows a spinner. */
5128
+ submitting?: boolean;
5129
+ /** No fields to render yet (e.g. the spec is still being fetched) → skeleton. */
5130
+ loading?: boolean;
5131
+ /** A terminal, form-level submission error rendered above the submit control. */
5132
+ error?: ReactNode;
5133
+ children: ReactNode;
5134
+ }
5135
+ /**
5136
+ * Lifts the form values. Controlled (pass `values`) or uncontrolled.
5137
+ * Derives `isControlled = values !== undefined` and never flips modes.
5138
+ */
5139
+ declare function SchemaFormProvider({ spec, values: valuesProp, onChange, onSubmit, disabled, submitted, submitting, loading, error, children, }: SchemaFormProviderProps): react.JSX.Element;
5140
+ interface SchemaFormFieldProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
5141
+ /** The field's `name` (its key in the spec + values). Resolved anywhere in the tree, including inside `group` branches. */
5142
+ name: string;
5143
+ }
5144
+ /**
5145
+ * Renders one field by name: label, control, description, inline error.
5146
+ * Boolean fields render their own inline label (checkbox + label); `group`
5147
+ * fields render their OWN label/description internally (a Tabs strip or a
5148
+ * stack of disclosures isn't a single labelled control), so the standalone
5149
+ * `<Label>` above is suppressed for both.
5150
+ *
5151
+ * Enforces its OWN `visibleWhen` (returns `null` when hidden) rather than
5152
+ * trusting the caller to have filtered it out first: the documented custom-
5153
+ * layout composition (`SchemaFormProvider` + the parts, see `SchemaForm`'s
5154
+ * own doc comment) lets a consumer place `<SchemaFormField name="…" />`
5155
+ * directly, bypassing `SchemaFormFields`'/`GroupTabsControl`'s/
5156
+ * `AdvancedGroupBranch`'s own `isFieldVisible` filters — without this check
5157
+ * the same spec would render a hidden field in a custom layout while
5158
+ * validation/submission (which always excludes it) disagree.
5159
+ */
5160
+ declare const SchemaFormField: react.NamedExoticComponent<SchemaFormFieldProps & react.RefAttributes<HTMLDivElement>>;
5161
+ type SchemaFormFieldsProps = HTMLAttributes<HTMLDivElement>;
5162
+ /** Renders every top-level field in the spec, in order. A skeleton while `loading` with no fields. */
5163
+ declare const SchemaFormFields: react.ForwardRefExoticComponent<SchemaFormFieldsProps & react.RefAttributes<HTMLDivElement>>;
5164
+ type SchemaFormErrorProps = HTMLAttributes<HTMLDivElement>;
5165
+ /** A terminal, form-level submission error (e.g. "Couldn't save settings"). Renders nothing when absent. */
5166
+ declare const SchemaFormError: react.ForwardRefExoticComponent<SchemaFormErrorProps & react.RefAttributes<HTMLDivElement>>;
5167
+ interface SchemaFormSubmitProps extends Omit<HTMLAttributes<HTMLButtonElement>, "children"> {
5168
+ /** Submit button label (overrides `spec.submitLabel`). @default "Submit" */
5169
+ label?: string;
5170
+ }
5171
+ /**
5172
+ * The submit affordance. Enabled until the request starts (validation runs on
5173
+ * click), then transiently blocked. `submitting` uses `aria-disabled` + a
5174
+ * click-handler guard — NEVER the native `disabled` attribute — so a focused
5175
+ * button is never dropped from the tab order right after the user activates
5176
+ * it (see the module doc comment / interaction-guidelines.md). The explicit,
5177
+ * caller-set `disabled` (read-only form) stays native: that is a deliberate,
5178
+ * durable state, not a transient auto-flip. A submitted form shows an inert
5179
+ * "Submitted" note instead of a button.
5180
+ */
5181
+ declare const SchemaFormSubmit: react.ForwardRefExoticComponent<SchemaFormSubmitProps & react.RefAttributes<HTMLButtonElement>>;
5182
+ /**
5183
+ * `SchemaFormTestAction`'s lifecycle: `idle` → `pending` while `onTest` is in
5184
+ * flight → `success`/`failure` once it settles. Deliberately local component
5185
+ * state, NOT part of the `SchemaFormStore` — so it can never affect field
5186
+ * validity or gate `submit()` (issue #22 maintainer ruling, 2026-09-01: a
5187
+ * form/group-level test-action slot, kept separate from field validity and
5188
+ * never gating submit — not per-field `validateAsync` in the validation
5189
+ * engine).
5190
+ */
5191
+ type SchemaFormTestActionStatus = "idle" | "pending" | "success" | "failure";
5192
+ interface SchemaFormTestActionProps extends Omit<HTMLAttributes<HTMLDivElement>, "onError"> {
5193
+ /**
5194
+ * Runs the test (e.g. calls an API with the fields typed so far). Receives
5195
+ * the form's CURRENT effective values — the same object `validateForm`
5196
+ * would resolve against — but this call is entirely independent of
5197
+ * validation: a field that is currently invalid, or an unrelated required
5198
+ * field left empty, never blocks a test run. Resolve to signal success;
5199
+ * reject (an `Error`, or throw) to signal failure — a rejected `Error`'s
5200
+ * `message` becomes the shown failure reason.
5201
+ */
5202
+ onTest: (values: FormValues) => void | Promise<void>;
5203
+ /** Button label. @default "Test connection" */
5204
+ label?: string;
5205
+ /** Label shown while pending. @default "Testing…" */
5206
+ pendingLabel?: string;
5207
+ /** Label shown on success. @default "Connected" */
5208
+ successLabel?: string;
5209
+ /** Fallback failure label when the rejection carries no message. @default "Test failed" */
5210
+ failureLabel?: string;
5211
+ }
5212
+ /**
5213
+ * A form- or group-level "Test connection" affordance: an async action the
5214
+ * user can run to verify the values typed so far (e.g. hit a connector's
5215
+ * `/ping` endpoint) BEFORE submitting. Place it anywhere inside a
5216
+ * `SchemaFormProvider` tree — directly under `SchemaFormRoot` for a
5217
+ * form-level test, or beside a `SchemaFormField` inside a `group` branch (a
5218
+ * `TabsContent`/`AdvancedGroup`) for a per-credential-set test. Not part of
5219
+ * `SchemaForm`'s default composition — an opt-in part a consumer places, the
5220
+ * same way a custom layout composes `SchemaFormField` directly.
5221
+ *
5222
+ * Deliberately NOT wired into `errors`/`validateForm`/`submit()` — its
5223
+ * pending/success/failure state is entirely local, so it can never block or
5224
+ * silently gate the form's own submit control.
5225
+ */
5226
+ declare const SchemaFormTestAction: react.ForwardRefExoticComponent<SchemaFormTestActionProps & react.RefAttributes<HTMLDivElement>>;
5227
+ type SchemaFormRootProps = Omit<HTMLAttributes<HTMLFormElement>, "onSubmit">;
5228
+ /**
5229
+ * The `<form>` element wired to the context's `submit`. Never nest inside
5230
+ * another `<form>` — compose it as its own top-level block.
5231
+ */
5232
+ declare const SchemaFormRoot: react.ForwardRefExoticComponent<SchemaFormRootProps & react.RefAttributes<HTMLFormElement>>;
5233
+ type SchemaFormTitleProps = HTMLAttributes<HTMLParagraphElement>;
5234
+ /** The form heading. Its id is the `<form>`'s `aria-labelledby` target. */
5235
+ declare const SchemaFormTitle: react.ForwardRefExoticComponent<SchemaFormTitleProps & react.RefAttributes<HTMLParagraphElement>>;
5236
+ type SchemaFormDescriptionProps = HTMLAttributes<HTMLParagraphElement>;
5237
+ /** Supplemental description under the title. */
5238
+ declare const SchemaFormDescription: react.ForwardRefExoticComponent<SchemaFormDescriptionProps & react.RefAttributes<HTMLParagraphElement>>;
5239
+ interface SchemaFormFallbackProps extends HTMLAttributes<HTMLDivElement> {
5240
+ /** Short human reason the form could not render. */
5241
+ message?: string;
5242
+ }
5243
+ /**
5244
+ * Shown when the spec is unusable. Mirrors `MessageFormFallback`: a calm,
5245
+ * bordered status box with a short reason — never a thrown error.
5246
+ */
5247
+ declare const SchemaFormFallback: react.ForwardRefExoticComponent<SchemaFormFallbackProps & react.RefAttributes<HTMLDivElement>>;
5248
+ interface SchemaFormProps extends Omit<HTMLAttributes<HTMLDivElement>, "onSubmit" | "onChange" | "title"> {
5249
+ /** The serializable form specification. */
5250
+ spec: FormSpec | unknown;
5251
+ /** Controlled values (`{ [fieldName]: value }`). Omit for uncontrolled. */
5252
+ values?: FormValues;
5253
+ /** Called with the next full values object on any change. */
5254
+ onChange?: (values: FormValues) => void;
5255
+ /** Called with `{ formName, values }` on a valid submit. */
5256
+ onSubmit?: (state: FormSubmitState) => void;
5257
+ /** Submit button label (overrides `spec.submitLabel`). */
5258
+ submitLabel?: string;
5259
+ /** Disable every control (the whole form is read-only). */
5260
+ disabled?: boolean;
5261
+ /** Terminal submitted state: inert, values visible, submit replaced. */
5262
+ submitted?: boolean;
5263
+ /** In-flight submit: controls transiently blocked, spinner on submit. */
5264
+ submitting?: boolean;
5265
+ /** No fields to render yet (spec still loading) → skeleton. */
5266
+ loading?: boolean;
5267
+ /** A terminal, form-level submission error rendered above the submit control. */
5268
+ error?: ReactNode;
5269
+ }
5270
+ /**
5271
+ * Convenience composition: `Provider → Root(form) → title/description →
5272
+ * Fields → Error → Submit`. For a custom layout, compose `SchemaFormProvider`
5273
+ * + the parts. A malformed spec renders `SchemaFormFallback` (never throws).
5274
+ */
5275
+ declare const SchemaForm: react.ForwardRefExoticComponent<SchemaFormProps & react.RefAttributes<HTMLDivElement>>;
5276
+
5277
+ /**
5278
+ * from-json-schema.ts — `fromJsonSchema()`: the narrow, documented JSON
5279
+ * Schema → `FormSpec` adapter (issue #22, maintainer ruling 2026-09-01).
5280
+ *
5281
+ * Many consumers already have their config described as JSON Schema (an
5282
+ * OpenAPI request body, a connector manifest). This maps ONLY the common
5283
+ * subset such schemas actually use onto `SchemaForm`'s `FieldSpec`
5284
+ * vocabulary:
5285
+ *
5286
+ * { type: "string" } → StringFieldSpec
5287
+ * { type: "string", enum: [...] } → EnumFieldSpec
5288
+ * { type: "number" | "integer" } → NumberFieldSpec / IntegerFieldSpec
5289
+ * { type: "boolean" } → BooleanFieldSpec
5290
+ * { type: "array", items: { type: "string" } } → ListFieldSpec (free text)
5291
+ * { type: "array",
5292
+ * items: { type: "string", enum: [...] } } → MultiEnumFieldSpec
5293
+ * (a CONSTRAINED array
5294
+ * item schema maps onto
5295
+ * the field type that
5296
+ * actually enforces the
5297
+ * constraint — see
5298
+ * "Constraint keywords"
5299
+ * below for why this
5300
+ * one keyword IS read)
5301
+ * { type: "object", properties: {...} } → GroupFieldSpec
5302
+ * (variant: "advanced",
5303
+ * one always-open branch)
5304
+ *
5305
+ * `title`/`description` map to `label`/`description`; `required` (the
5306
+ * enclosing object schema's array of property names) maps to `required:
5307
+ * true`; `default` maps when it is type-compatible; `minLength`/`maxLength`/
5308
+ * `pattern`/`minimum`/`maximum`/`minItems`/`maxItems` map to their FieldSpec
5309
+ * equivalents. `format` maps only the four values `StringFieldSpec` itself
5310
+ * understands (`email`/`uri`/`date`/`date-time`) — any other `format` value
5311
+ * (`"binary"`, `"password"`, a custom one) is ignored predictably, the same
5312
+ * way an unknown JSON Schema `format` is defined to be advisory, not
5313
+ * validating.
5314
+ *
5315
+ * Deliberately NOT a general draft-07/2020-12 implementation (the maintainer
5316
+ * ruling's explicit narrow option) — this module does not resolve `$ref` and
5317
+ * does not implement the `allOf`/`oneOf`/`anyOf`/`not` combinators. Those
5318
+ * keywords change what a schema actually MEANS, and approximating them would
5319
+ * risk producing a field that looks plausible but is wrong (e.g. rendering a
5320
+ * `$ref`'d object as an empty string field) — silently wrong is exactly what
5321
+ * this adapter must never be. So `fromJsonSchema()` REFUSES: any of those
5322
+ * five keywords, found anywhere in the input (top-level or nested inside a
5323
+ * property/items schema), throws `UnsupportedJsonSchemaError` naming the
5324
+ * keyword and its JSON-Pointer-style path. Pre-resolve/inline that part of
5325
+ * the schema before calling `fromJsonSchema()`, or hand-write the affected
5326
+ * `FieldSpec`.
5327
+ *
5328
+ * A property whose `type` this subset does not cover (e.g. `"null"`, a
5329
+ * JSON-Schema-2020-12 array-of-types, an array of non-string items, an
5330
+ * object schema with no `properties`) is DROPPED from the result —
5331
+ * predictable and non-fatal, the same lenient-parse philosophy
5332
+ * `normalizeFormSpec` already uses for the render path, because omitting one
5333
+ * field is recoverable in a way a mis-mapped `$ref`/combinator is not.
5334
+ *
5335
+ * CONSTRAINT KEYWORDS this subset does not read: `const`, `if`/`then`/`else`,
5336
+ * `dependentSchemas`, `dependentRequired`, `additionalProperties`,
5337
+ * `patternProperties`, `propertyNames`, `contains`, `multipleOf`,
5338
+ * `exclusiveMinimum`/`exclusiveMaximum`, `uniqueItems`. These are
5339
+ * READ-IGNORED, not refused — unlike `$ref`/`allOf`/`oneOf`/`anyOf`/`not`,
5340
+ * none of them changes what TYPE a property maps to, so ignoring one never
5341
+ * produces a wrongly-shaped field. But ignoring one DOES widen what the
5342
+ * rendered form accepts relative to the source schema (a `const`-pinned
5343
+ * property renders as an ordinary editable field, not a fixed one; a
5344
+ * `multipleOf`-constrained number accepts any value in range). This is the
5345
+ * one place `fromJsonSchema()` is honestly silently-permissive rather than
5346
+ * silently-wrong or refusing — call it out in review when a schema leans on
5347
+ * one of these keywords for validation the mapped form will not enforce.
5348
+ * `items.enum` is the one exception among these: a constrained array-item
5349
+ * schema is common enough (and cheap enough to map faithfully) that it reads
5350
+ * `items.enum` and maps onto `MultiEnumFieldSpec` — see the table above —
5351
+ * rather than joining this ignore list and widening into a free-text
5352
+ * `ListFieldSpec`.
5353
+ *
5354
+ * Widening this subset later (more `format`s, `$ref` resolution) is an
5355
+ * additive, non-breaking change to this one function — see issue #22's
5356
+ * "worth having alongside" list.
5357
+ */
5358
+
5359
+ /**
5360
+ * Thrown by `fromJsonSchema()` when the input uses a JSON Schema keyword
5361
+ * outside its documented subset (see this module's doc comment) — never
5362
+ * silently mismapped.
5363
+ */
5364
+ declare class UnsupportedJsonSchemaError extends Error {
5365
+ constructor(keyword: string, path: string);
5366
+ }
5367
+ interface FromJsonSchemaOptions {
5368
+ /** `FormSpec.formName` — required; JSON Schema has no equivalent stable identifier. */
5369
+ formName: string;
5370
+ /** Overrides the mapped `schema.title`. */
5371
+ title?: string;
5372
+ /** Overrides the mapped `schema.description`. */
5373
+ description?: string;
5374
+ /** `FormSpec.submitLabel` — JSON Schema has no equivalent. */
5375
+ submitLabel?: string;
5376
+ }
5377
+ /**
5378
+ * Maps a JSON Schema OBJECT schema (an OpenAPI request body, a connector
5379
+ * manifest) onto a `FormSpec`, using only the documented subset described in
5380
+ * this module's doc comment. Throws `UnsupportedJsonSchemaError` if `schema`
5381
+ * (at any depth) uses `$ref`/`allOf`/`oneOf`/`anyOf`/`not`, or if the
5382
+ * top-level schema is not an object schema — never silently mismapped. A
5383
+ * property whose shape falls outside the subset is dropped, not thrown on.
5384
+ */
5385
+ declare function fromJsonSchema(schema: unknown, options: FromJsonSchemaOptions): FormSpec;
5386
+
3130
5387
  declare const ScrollArea: react.ForwardRefExoticComponent<Omit<ScrollAreaPrimitive.ScrollAreaProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
3131
5388
  declare const ScrollBar: react.ForwardRefExoticComponent<Omit<ScrollAreaPrimitive.ScrollAreaScrollbarProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
3132
5389
 
@@ -3137,10 +5394,20 @@ interface SectionHeaderProps {
3137
5394
  actions?: ReactNode;
3138
5395
  /** Optional element rendered above the title (eyebrow / breadcrumbs). */
3139
5396
  eyebrow?: ReactNode;
5397
+ /**
5398
+ * The heading LEVEL the title contributes to the document outline. The
5399
+ * visual (`text-title`) is identical for every value — pick the level the
5400
+ * page's structure calls for, not the size you want (WCAG 1.3.1).
5401
+ *
5402
+ * Use `as="h1"` when this header titles the PAGE (a screen whose route it
5403
+ * names); leave it at the default when it titles a section INSIDE a page
5404
+ * that already has an `<h1>` elsewhere. @default "h2"
5405
+ */
5406
+ as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
3140
5407
  className?: string;
3141
5408
  }
3142
5409
  /** A consistent page/section heading row with optional actions. */
3143
- declare function SectionHeader({ title, description, actions, eyebrow, className, }: SectionHeaderProps): react.JSX.Element;
5410
+ declare function SectionHeader({ title, description, actions, eyebrow, as: TitleTag, className, }: SectionHeaderProps): react.JSX.Element;
3144
5411
 
3145
5412
  interface SegmentedFieldOption {
3146
5413
  /** The option's value, reported to `onValueChange`. */
@@ -3265,10 +5532,79 @@ declare function SheetFooter({ className, ...props }: HTMLAttributes<HTMLDivElem
3265
5532
  declare const SheetTitle: react.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogTitleProps & react.RefAttributes<HTMLHeadingElement>, "ref"> & react.RefAttributes<HTMLHeadingElement>>;
3266
5533
  declare const SheetDescription: react.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogDescriptionProps & react.RefAttributes<HTMLParagraphElement>, "ref"> & react.RefAttributes<HTMLParagraphElement>>;
3267
5534
 
5535
+ interface SideDockProps extends Omit<ComponentProps<"aside">, "title"> {
5536
+ /**
5537
+ * The dock's name. Rendered as its header heading, and as the `SheetTitle`
5538
+ * of the overlay presentation. REQUIRED: the overlay cannot be accessible
5539
+ * without it, and an optional prop with a generic default would ship a
5540
+ * meaningless announced name into real apps.
5541
+ */
5542
+ title: ReactNode;
5543
+ /**
5544
+ * Optional longer description. Visible under the title in the column
5545
+ * presentation; `sr-only` in the overlay presentation (the compact sheet
5546
+ * header has no room for it, but it still reaches assistive tech).
5547
+ */
5548
+ description?: ReactNode;
5549
+ /** Optional controls placed in the header row beside the built-in close button. */
5550
+ headerActions?: ReactNode;
5551
+ /** Controlled open state. Closed means zero width (content stays mounted, inert). */
5552
+ open?: boolean;
5553
+ /** Uncontrolled initial open state. Default `false` — a dock is summoned. */
5554
+ defaultOpen?: boolean;
5555
+ /** Called with the next open state. */
5556
+ onOpenChange?: (open: boolean) => void;
5557
+ /** Which edge it docks to. Default `"right"`. */
5558
+ side?: "left" | "right";
5559
+ /**
5560
+ * `width`, `defaultWidth`, `minWidth`, `maxWidth`, `minContentWidth` and
5561
+ * `resizable` (below) govern the COLUMN presentation only — viewport at or
5562
+ * above `overlayBreakpoint`. Below that breakpoint the dock renders as an
5563
+ * overlay `Sheet` sized by the viewport (`Sheet`'s own `w-3/4 max-w-sm`),
5564
+ * so none of these props have any effect there.
5565
+ */
5566
+ /** Controlled width in px. */
5567
+ width?: number;
5568
+ /** Uncontrolled initial width in px. Default `400`. */
5569
+ defaultWidth?: number;
5570
+ /** Fires continuously during a resize — drive layout from this. */
5571
+ onWidthChange?: (width: number) => void;
5572
+ /** Fires once when an interaction ends — PERSIST from this. */
5573
+ onWidthCommit?: (width: number) => void;
5574
+ /** Lower bound in px. Default `320`. */
5575
+ minWidth?: number;
5576
+ /** Upper bound in px. Default `640`. */
5577
+ maxWidth?: number;
5578
+ /** Content width preserved when clamping against the live viewport, px. Default `480`. */
5579
+ minContentWidth?: number;
5580
+ /** Whether the resize handle renders. Default `true`. */
5581
+ resizable?: boolean;
5582
+ /**
5583
+ * Viewport width in px below which the dock renders as an overlay `Sheet`
5584
+ * instead of a column. Default `1100`. Deliberately ABOVE the library's
5585
+ * 768px mobile breakpoint: a 400px dock at 768px leaves ~360px of content.
5586
+ * This is the switch point for the column-only sizing props above — the
5587
+ * overlay presentation ignores them entirely.
5588
+ */
5589
+ overlayBreakpoint?: number;
5590
+ }
5591
+ declare const SideDock: react.ForwardRefExoticComponent<Omit<SideDockProps, "ref"> & react.RefAttributes<HTMLElement>>;
5592
+
3268
5593
  type SkeletonProps = HTMLAttributes<HTMLDivElement>;
3269
5594
  /** Loading placeholder. Compose with width/height utilities, e.g. `h-4 w-32`. */
3270
5595
  declare function Skeleton({ className, ...props }: SkeletonProps): react.JSX.Element;
3271
5596
 
5597
+ interface SkipLinkProps extends ComponentProps<"a"> {
5598
+ /** The id of the landmark to jump to. Defaults to "main-content". */
5599
+ targetId?: string;
5600
+ }
5601
+ /**
5602
+ * The first focusable element of an application: invisible until focused, then a
5603
+ * token-styled pill pinned to the top-start corner. Give the target element
5604
+ * `id={targetId}` and `tabIndex={-1}` so focus actually lands there.
5605
+ */
5606
+ declare const SkipLink: react.ForwardRefExoticComponent<Omit<SkipLinkProps, "ref"> & react.RefAttributes<HTMLAnchorElement>>;
5607
+
3272
5608
  /** Props for a single `SliderPrimitive.Thumb` — see `SliderProps["thumbProps"]`. */
3273
5609
  type SliderThumbProps = ComponentPropsWithoutRef<typeof SliderPrimitive.Thumb>;
3274
5610
  type SliderProps = ComponentPropsWithoutRef<typeof SliderPrimitive.Root> & {
@@ -3428,11 +5764,11 @@ type ToasterProps = React.ComponentProps<typeof Toaster$1>;
3428
5764
  declare function Toaster({ className, toastOptions, ...rest }: ToasterProps): react.JSX.Element;
3429
5765
 
3430
5766
  interface SpinnerProps extends React.SVGProps<SVGSVGElement> {
3431
- /** Accessible label; defaults to "Loading". */
5767
+ /** Accessible label; defaults to the localized "Loading" microcopy. */
3432
5768
  label?: string;
3433
5769
  }
3434
5770
  /** Indeterminate spinner with an accessible label. */
3435
- declare function Spinner({ className, label, ...props }: SpinnerProps): react.JSX.Element;
5771
+ declare const Spinner: react.ForwardRefExoticComponent<Omit<SpinnerProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
3436
5772
 
3437
5773
  declare const statePanelVariants: (props?: ({
3438
5774
  kind?: "error" | "loading" | "empty" | null | undefined;
@@ -3450,11 +5786,29 @@ interface StatePanelProps extends VariantProps<typeof statePanelVariants> {
3450
5786
  /** Supporting description below the title. */
3451
5787
  description?: ReactNode;
3452
5788
  /**
3453
- * Icon or illustration shown above the title.
3454
- * For `"error"` defaults to a built-in warning triangle.
3455
- * For `"loading"` defaults to an animated spinner.
5789
+ * Icon shown above the title, clamped to a uniform 40×40 so mismatched
5790
+ * glyphs stay tidy. For `"error"` defaults to a built-in warning triangle.
5791
+ * For `"loading"` defaults to an animated spinner. Ignored when
5792
+ * `illustration` is also provided — see `illustration`.
3456
5793
  */
3457
5794
  icon?: ReactNode;
5795
+ /**
5796
+ * A larger illustration (one of `@elabs-ai/components-ui`'s shipped
5797
+ * `*Illustration` components, or a consumer's own `ReactNode`) shown above
5798
+ * the title instead of `icon`. Unlike `icon`, it is **not** clamped to
5799
+ * 40×40 — an illustration governs its own size (see each illustration's
5800
+ * `size` prop, `rem`-based, ~64px–160px). Takes precedence over `icon`
5801
+ * when both are given.
5802
+ */
5803
+ illustration?: ReactNode;
5804
+ /**
5805
+ * Heading level for the panel's title (#328 convention). Set this to the
5806
+ * level that correctly follows whatever heading precedes this panel in
5807
+ * the document outline — e.g. `"h3"` inside a `ChartCard` whose own title
5808
+ * is an `<h2>`.
5809
+ * @default "h3"
5810
+ */
5811
+ titleAs?: "div" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
3458
5812
  /** Accessible label for the spinner in loading state. @default "Loading…" */
3459
5813
  loadingLabel?: string;
3460
5814
  /** Spinner size (loading kind only). @default "md" */
@@ -3468,113 +5822,28 @@ interface StatePanelProps extends VariantProps<typeof statePanelVariants> {
3468
5822
  * Replaces the three separate `EmptyState` / `ErrorState` / `LoadingState` components
3469
5823
  * while keeping those as back-compat thin wrappers.
3470
5824
  */
3471
- declare function StatePanel({ kind, title, description, icon, loadingLabel, size, actions, className, }: StatePanelProps): react.JSX.Element;
3472
-
3473
- /** The canonical, closed 7-state status enum (research 10 §B.1). */
3474
- declare const STATUSES: readonly ["pending", "running", "complete", "awaiting-approval", "denied", "failed", "skipped"];
3475
- type Status = (typeof STATUSES)[number];
3476
- /** Closed tone set for the out-of-vocabulary escape hatch (CALM treatments only). */
3477
- declare const STATUS_TONES: readonly ["neutral", "info", "success", "warning", "destructive"];
3478
- type StatusTone = (typeof STATUS_TONES)[number];
3479
- /**
3480
- * An out-of-vocabulary status. Prefer the canonical `Status` enum; reach for
3481
- * this only when the domain genuinely has a state the 7 do not express (e.g. a
3482
- * run engine's `stopped_guardrail`). Map it ONCE, near your domain — not per
3483
- * call site.
3484
- */
3485
- interface CustomStatus {
3486
- label: string;
3487
- tone: StatusTone;
3488
- /** Optional Lucide glyph. Omitted → label-only (no default glyph). */
3489
- icon?: LucideIcon;
3490
- }
3491
- /** Narrows `Status | CustomStatus` — the object form is always the escape hatch. */
3492
- declare function isCustomStatus(status: Status | CustomStatus): status is CustomStatus;
3493
- /**
3494
- * The canonical semantic ROLE per status — the single source of truth for
3495
- * status colour (#392). Any other status-keyed colour map in the repo
3496
- * (`Timeline`'s `NODE_STYLE`, or a future one) must be TESTED against this,
3497
- * not hand-authored — a second literal copy is exactly how `NODE_STYLE`
3498
- * drifted (`running` rendered `--primary` while this map said `--info`).
3499
- * Do NOT interpolate `bg-${STATUS_ROLE[status]}` into a class map: Tailwind
3500
- * scans source statically, so a template-literal class emits no CSS. Keep
3501
- * consuming maps as literal class strings, verified against this export by a
3502
- * test.
3503
- */
3504
- declare const STATUS_ROLE: {
3505
- readonly pending: "secondary";
3506
- readonly running: "info";
3507
- readonly complete: "success";
3508
- readonly "awaiting-approval": "warning";
3509
- readonly denied: "muted";
3510
- readonly failed: "destructive";
3511
- readonly skipped: "secondary";
3512
- };
3513
- /** Default human-readable label per status (override via `children`). */
3514
- declare const STATUS_LABELS: Record<Status, string>;
3515
- /**
3516
- * Lucide glyph per out-of-vocabulary TONE — the same five-tone escape hatch
3517
- * `CustomStatus` uses (`STATUS_TONES`). A consumer that encodes a bare TONE
3518
- * with no fuller `Status` semantics (e.g. `@elabs-ai/components-flow`'s `FlowNode.tone`,
3519
- * #387) derives its non-colour cue from here instead of inventing a second
3520
- * icon vocabulary — each entry reuses the SAME icon `STATUS_ICONS` already
3521
- * pairs with that tone's one canonical status (`success`→`complete`'s
3522
- * `CheckCircle2`, `warning`→`awaiting-approval`'s `Clock`,
3523
- * `destructive`→`failed`'s `AlertCircle`). `neutral`/`info` have no entry:
3524
- * nothing consumes them yet, and reaching for a glyph on every neutral/
3525
- * default-toned element would be assistive-tech noise on the common case —
3526
- * extend this map, don't fork a new one, the day something needs them.
3527
- */
3528
- declare const STATUS_TONE_ICONS: Partial<Record<StatusTone, LucideIcon>>;
3529
- interface StatusIconProps extends Omit<LucideProps, "ref"> {
3530
- /** The canonical execution status (closed enum). */
3531
- status: Status;
3532
- }
3533
- /**
3534
- * The icon + status-color atom `StatusBadge` itself composes — for tight rows
3535
- * (test-result rows, timeline/rail nodes) where a full badge is too heavy.
3536
- * Decorative by default (`aria-hidden`); the adjacent row text must carry the
3537
- * status name for AT users.
3538
- */
3539
- declare const StatusIcon: react.ForwardRefExoticComponent<StatusIconProps & react.RefAttributes<SVGSVGElement>>;
3540
- declare const statusBadgeVariants: (props?: ({
3541
- status?: "running" | "pending" | "complete" | "awaiting-approval" | "denied" | "failed" | "skipped" | null | undefined;
3542
- tone?: "success" | "warning" | "destructive" | "info" | "neutral" | null | undefined;
3543
- size?: "md" | "sm" | null | undefined;
3544
- } & class_variance_authority_types.ClassProp) | undefined) => string;
3545
- interface StatusBadgeProps extends HTMLAttributes<HTMLSpanElement>, Omit<VariantProps<typeof statusBadgeVariants>, "status" | "tone"> {
3546
- /** The canonical execution status, or a mapped out-of-vocabulary one (#363). */
3547
- status: Status | CustomStatus;
3548
- /** Render label-only (no status icon). */
3549
- hideIcon?: boolean;
3550
- }
3551
- declare const StatusBadge: react.ForwardRefExoticComponent<StatusBadgeProps & react.RefAttributes<HTMLSpanElement>>;
3552
- /** The editor/markdown `Timeline` 3-state vocabulary (`@elabs-ai/components-editor`). */
3553
- type TimelineStatus = "done" | "active" | "pending";
3554
- /**
3555
- * Map the Timeline `done|active|pending` vocabulary onto the canonical
3556
- * `Status` (research 10 §B.1 mapping b — lossless; the timeline only
3557
- * expresses 3 of the 7 states). The AI-SDK `ToolUIPart` mapper lives in
3558
- * `@elabs-ai/components-ai` (`statusFromToolState`, tool.tsx) so `@elabs-ai/components-ui` stays free of
3559
- * the `ai` dependency (D6).
3560
- */
3561
- declare function fromTimelineStatus(status: TimelineStatus): Status;
5825
+ declare function StatePanel({ kind, title, description, icon, illustration, titleAs: Tag, loadingLabel, size, actions, className, }: StatePanelProps): react.JSX.Element;
3562
5826
 
3563
5827
  /**
3564
5828
  * Per-pane surface tone — the ground-offset tiering axis (research 08 §H, #193).
3565
5829
  * `plain` keeps the ambient ground (default; non-breaking). `card` RAISES the pane as
3566
- * a white `bg-card` + `shadow-sm` and is robust across all three themes — a card is
5830
+ * a white `bg-card` + `shadow-sm` and is robust across every theme — a card is
3567
5831
  * lighter than the page ground in BOTH light and dark, so it always reads as raised.
3568
5832
  * `muted` (`bg-surface-muted`) reads as a recessed well ONLY in light themes; in dark
3569
5833
  * themes `--surface-muted` is lighter than `--card`, so a `muted` pane reads as a faint
3570
5834
  * raised tint, not a recess (dark-mode layering only goes UP — there is no surface below
3571
5835
  * the page ground). For a guaranteed cross-theme raise/recess contrast, raise the focus
3572
5836
  * pane with `card` and leave the other `plain`.
5837
+ *
5838
+ * Exported so the same tone system reaches a `Layout/Resizable` pane — a draggable
5839
+ * `ResizablePanel` composes `splitPaneVariants({ tone })` for the identical ground-offset
5840
+ * tiering `SplitPanel` gives its `startTone`/`endTone`, instead of a hand-rolled second
5841
+ * copy of these three classes. See `Layout/Resizable`'s `Tiered` story.
3573
5842
  */
3574
- declare const paneToneVariants: (props?: ({
3575
- tone?: "card" | "muted" | "plain" | null | undefined;
5843
+ declare const splitPaneVariants: (props?: ({
5844
+ tone?: "muted" | "card" | "plain" | null | undefined;
3576
5845
  } & class_variance_authority_types.ClassProp) | undefined) => string;
3577
- type SplitPanelTone = NonNullable<VariantProps<typeof paneToneVariants>["tone"]>;
5846
+ type SplitPanelTone = NonNullable<VariantProps<typeof splitPaneVariants>["tone"]>;
3578
5847
  interface SplitPanelProps {
3579
5848
  start: ReactNode;
3580
5849
  end: ReactNode;
@@ -3597,8 +5866,12 @@ interface SplitPanelProps {
3597
5866
  }
3598
5867
  /**
3599
5868
  * Two-pane layout for master/detail, editor/preview and inspector workflows.
3600
- * Static sizing by design (predictable in tests/SSR); for drag-to-resize wrap
3601
- * with a resize hook or compose `react-resizable-panels` at the app level.
5869
+ * Static sizing by design (predictable in tests/SSR) `startSize` is a CSS grid
5870
+ * track (`"320px"`, `"40%"`, `"1fr"`), not a percentage. For panes the user can
5871
+ * drag to resize, reach for `Layout/Resizable`'s `ResizablePanelGroup`/
5872
+ * `ResizablePanel`/`ResizableHandle` instead and apply `splitPaneVariants({ tone })`
5873
+ * to a panel for the same ground-offset tiering. See
5874
+ * [Choosing between similar components](?path=/docs/docs-choosing-between-similar-components--docs).
3602
5875
  *
3603
5876
  * For a master/detail surface where the detail should read as a raised card on a
3604
5877
  * recessed list, use `startTone="muted" endTone="card"` (ground-offset tiering).
@@ -3607,6 +5880,33 @@ declare function SplitPanel({ start, end, direction, startSize, divider, startTo
3607
5880
 
3608
5881
  declare const Switch: react.ForwardRefExoticComponent<Omit<SwitchPrimitive.SwitchProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
3609
5882
 
5883
+ /**
5884
+ * `Table`'s own scroll wrapper, gated on MEASURED overflow (#366).
5885
+ *
5886
+ * `className`/`ref`/`...props` all land on the `<table>` — unchanged, no new
5887
+ * prop — so this wrapper is internal plumbing, not a new public surface. It
5888
+ * follows `DataTable`'s non-virtualized branch verbatim
5889
+ * (`packages/data/src/data-table/data-table.tsx:1658-1695`, #330), the
5890
+ * closest precedent: a plain `overflow-auto` box with no pinned columns, no
5891
+ * loading overlay and no edge fade to carry along, just the keyboard
5892
+ * affordance itself.
5893
+ *
5894
+ * A table that FITS must stay a byte-identical no-op: no `tabIndex`, no
5895
+ * `aria-label`, no `role`, no ring — an unconditional stop would announce
5896
+ * "scrollable" on content that never scrolls. Only a table that measurably
5897
+ * overflows gets the tab stop, its accessible name (WCAG 4.1.2) and the
5898
+ * compound focus ring (`focus-ring-inset` — the wrapper's own edge is the
5899
+ * scroll clip, so an outside ring would be cut, `.claude/rules/theming.md`).
5900
+ *
5901
+ * A naming-capable role is REQUIRED alongside that `aria-label`: `aria-label`
5902
+ * on a plain `<div>` (role `generic`) is prohibited by ARIA 1.2 and not
5903
+ * guaranteed to compute into a name, so `tabIndex={0}` alone would make an
5904
+ * UNNAMED stop. That role is `group`, NOT `region`: `region` is a landmark,
5905
+ * and every overflowing table on a page would add one more landmark with the
5906
+ * same name (axe `landmark-unique`) over a real `<table>` that already has
5907
+ * its own semantics. `group` names the stop without joining landmark
5908
+ * navigation — the no-redundant-landmark call `DataTable` made first (#330).
5909
+ */
3610
5910
  declare const Table: react.ForwardRefExoticComponent<HTMLAttributes<HTMLTableElement> & react.RefAttributes<HTMLTableElement>>;
3611
5911
  declare const TableHeader: react.ForwardRefExoticComponent<HTMLAttributes<HTMLTableSectionElement> & react.RefAttributes<HTMLTableSectionElement>>;
3612
5912
  declare const TableBody: react.ForwardRefExoticComponent<HTMLAttributes<HTMLTableSectionElement> & react.RefAttributes<HTMLTableSectionElement>>;
@@ -3627,7 +5927,16 @@ declare const Tabs: react.ForwardRefExoticComponent<TabsPrimitive.TabsProps & re
3627
5927
  * start-alignment on overflow while staying visually identical when the
3628
5928
  * strip fits (see #344).
3629
5929
  */
3630
- declare const TabsList: react.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsListProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
5930
+ declare const tabsListVariants: (props?: ({
5931
+ variant?: "underline" | "segmented" | null | undefined;
5932
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
5933
+ declare const tabsTriggerVariants: (props?: ({
5934
+ variant?: "underline" | "segmented" | null | undefined;
5935
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
5936
+ type TabsVariant = NonNullable<VariantProps<typeof tabsListVariants>["variant"]>;
5937
+ interface TabsListProps extends ComponentPropsWithoutRef<typeof TabsPrimitive.List>, VariantProps<typeof tabsListVariants> {
5938
+ }
5939
+ declare const TabsList: react.ForwardRefExoticComponent<TabsListProps & react.RefAttributes<HTMLDivElement>>;
3631
5940
  declare const TabsTrigger: react.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsTriggerProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
3632
5941
  declare const TabsContent: react.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsContentProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
3633
5942
 
@@ -3704,8 +6013,8 @@ type ThemeTransitionEffect = "polygon" | "circle" | "circle-blur" | "triangle";
3704
6013
  * Transitions API (the chanhdai.com "theme toggle effect", adapted to brand-ui).
3705
6014
  *
3706
6015
  * - Direction-aware: sets `data-vt="to-dark|to-light"` on `<html>` from the
3707
- * target theme's `dark` flag, so the clip-path wipes the right way for ANY of
3708
- * the three themes (not just light/dark).
6016
+ * target theme's `dark` flag, so the clip-path wipes the right way for ANY
6017
+ * theme (not just light/dark).
3709
6018
  * - `data-vt-effect` selects the reveal shape (default "polygon").
3710
6019
  * - Motion-aware: under `useReducedMotion()` (OS or in-app preference) — or when
3711
6020
  * the browser lacks `startViewTransition` — it falls back to an instant,
@@ -4223,7 +6532,7 @@ declare const TEXT_ROLE_REM: {
4223
6532
  type TextRole = keyof typeof TEXT_ROLE_REM;
4224
6533
  declare const textVariants: (props?: ({
4225
6534
  variant?: "body" | "caption" | "meta" | "kpi" | "code" | "lead" | null | undefined;
4226
- tone?: "default" | "primary" | "muted" | null | undefined;
6535
+ tone?: "default" | "muted" | "primary" | null | undefined;
4227
6536
  } & class_variance_authority_types.ClassProp) | undefined) => string;
4228
6537
  type TextVariant = NonNullable<VariantProps<typeof textVariants>["variant"]>;
4229
6538
  type TextTone = NonNullable<VariantProps<typeof textVariants>["tone"]>;
@@ -4334,6 +6643,22 @@ interface FilterChipProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>,
4334
6643
  * as a sentence fragment out of context (and in a screen reader).
4335
6644
  */
4336
6645
  label: string;
6646
+ /**
6647
+ * Short, non-shrinking secondary text — a count, a unit (`"excluded 1,204"`).
6648
+ * A second text slot rather than folding it into `label` (#284): `label` is
6649
+ * the shrinkable, safe-to-truncate part; `trailing` is short and fixed-width
6650
+ * and must never lose characters to the ellipsis. Same shape as
6651
+ * `TurnStatus`'s and `TerminalWorking`'s `trailing` slot — a fixed-width
6652
+ * companion beside a truncating label. Composed into the accessible name
6653
+ * after `label` (`"Remove filter: <label> · <trailing>"`), so the byte-
6654
+ * identical name from before this slot existed is unchanged.
6655
+ *
6656
+ * Trade-off: `trailing` is `shrink-0`, so an extremely narrow container now
6657
+ * truncates `label` down to nothing before it touches `trailing`. That is
6658
+ * the right default — the count is short and fixed, the label is the long,
6659
+ * prose-shaped part — but it is a choice, not a free win.
6660
+ */
6661
+ trailing?: string;
4337
6662
  /** Remove this filter. The WHOLE chip is the remove control — see below. */
4338
6663
  onRemove: () => void;
4339
6664
  }
@@ -4435,6 +6760,90 @@ interface VirtualSelectProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement
4435
6760
  */
4436
6761
  declare const VirtualSelect: react.ForwardRefExoticComponent<VirtualSelectProps & react.RefAttributes<HTMLButtonElement>>;
4437
6762
 
6763
+ /**
6764
+ * `WorkspacePicker`'s pure, directly-testable logic — kept out of the
6765
+ * component for the same reason `../model-picker/model-picker-state.ts` does
6766
+ * (see that file's header comment): an expression buried in JSX cannot be
6767
+ * unit-tested in isolation, and relative-time arithmetic in particular has
6768
+ * edge cases worth locking down on their own.
6769
+ */
6770
+ /**
6771
+ * One recent workspace. Deliberately a strict subset of `ModelPickerItem`'s
6772
+ * shape (`id` / `name` → `label` / `path` → `description` / `lastOpenedAt` →
6773
+ * a formatted `meta` entry) — see the reuse note in `workspace-picker.tsx`.
6774
+ */
6775
+ interface Workspace {
6776
+ id: string;
6777
+ /** Rendered as the row's primary label and, when current, the trigger text. */
6778
+ name: string;
6779
+ /**
6780
+ * The filesystem path. Long, user-supplied content — the row truncates it,
6781
+ * never wraps or overflows.
6782
+ */
6783
+ path: string;
6784
+ /**
6785
+ * When this workspace was last opened. Rendered as a relative time via
6786
+ * `Intl.RelativeTimeFormat` (`formatLastOpened`, below) — never a
6787
+ * pre-formatted string the caller hands over.
6788
+ */
6789
+ lastOpenedAt?: Date;
6790
+ }
6791
+ /**
6792
+ * "2 hours ago" / "in 3 minutes" / "yesterday" — `Intl.RelativeTimeFormat`
6793
+ * picks the coarsest unit (minutes → hours → days) that still reads
6794
+ * naturally, instead of e.g. "127 minutes ago".
6795
+ *
6796
+ * @param now - injection seam for tests; defaults to the real clock.
6797
+ */
6798
+ declare function formatLastOpened(date: Date, locale: string, now?: number): string;
6799
+
6800
+ interface WorkspacePickerProps extends Omit<HTMLAttributes<HTMLDivElement>, "onSelect"> {
6801
+ /** Recent workspaces, most-relevant first — the caller owns ordering. */
6802
+ workspaces: Workspace[];
6803
+ /** The currently open workspace's id. */
6804
+ currentId?: string;
6805
+ /** Fires with the chosen workspace; the popover closes first. */
6806
+ onSelect?: (workspace: Workspace) => void;
6807
+ /**
6808
+ * Free-text path entry, rendered in `ModelPicker`'s `footer` slot below the
6809
+ * list. Fires with the raw string the user typed once it validates as
6810
+ * non-empty — this component performs no filesystem access of any kind
6811
+ * (presentation layer, D5); resolving, normalizing or checking the path is
6812
+ * the caller's job.
6813
+ */
6814
+ onSubmitPath?: (path: string) => void;
6815
+ /**
6816
+ * Drives the same four-body state grid as `ModelPicker` — see
6817
+ * `ModelPickerStatus`. Default `"ready"`, inherited from `ModelPicker`.
6818
+ */
6819
+ status?: ModelPickerStatus;
6820
+ disabled?: boolean;
6821
+ /** Accessible name for the trigger and the popover — what the control is FOR. */
6822
+ "aria-label"?: string;
6823
+ /** Controlled popover open state — see `ModelPicker`'s controlled contract. */
6824
+ open?: boolean;
6825
+ onOpenChange?: (open: boolean) => void;
6826
+ }
6827
+ /**
6828
+ * Recent-workspace switcher — issue #111, decided in
6829
+ * `docs/decisions/2026-09-01-brainless-adoption-architecture.md` § 7.
6830
+ *
6831
+ * A `ModelPicker` PRESET, not a new picker: `ModelPickerItem`'s
6832
+ * `id`/`label`/`description`/`meta` shape is already a superset of what a
6833
+ * workspace needs, so this component only supplies workspace-shaped
6834
+ * defaults — it maps `path` into the truncating `description` slot, formats
6835
+ * `lastOpenedAt` with `Intl.RelativeTimeFormat`, marks the current workspace
6836
+ * in the row's TEXT (never colour alone — `ModelPicker`'s check glyph is
6837
+ * `aria-hidden` and cannot carry that on its own), and renders the free-text
6838
+ * path entry into `ModelPicker`'s `footer` slot so it sits below the list,
6839
+ * un-filtered by the search query.
6840
+ *
6841
+ * Unlike `TeamSwitcher`, this has no `Sidebar` dependency — it works anywhere
6842
+ * a picker is needed (a session launch card, a command palette), not only
6843
+ * inside a sidebar.
6844
+ */
6845
+ declare const WorkspacePicker: react.ForwardRefExoticComponent<WorkspacePickerProps & react.RefAttributes<HTMLDivElement>>;
6846
+
4438
6847
  interface WizardStepMeta {
4439
6848
  /** Stable id for the step. */
4440
6849
  id: string;
@@ -4494,4 +6903,4 @@ interface WizardNavProps extends HTMLAttributes<HTMLDivElement> {
4494
6903
  /** WizardNav — Back / Next (or Finish on the last step) controls. */
4495
6904
  declare const WizardNav: react.ForwardRefExoticComponent<WizardNavProps & react.RefAttributes<HTMLDivElement>>;
4496
6905
 
4497
- export { ATTRIBUTIONS, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AdvancedGroup, type AdvancedGroupProps, Alert, AlertDescription, type AlertDescriptionProps, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, type AlertTitleProps, AppShell, type AppShellProps, AppSidebar, type AppSidebarProps, AspectRatio, type Attribution, type AttributionCategory, AttributionPanel, type AttributionPanelProps, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, BentoGrid, BentoGridItem, type BentoGridItemProps, type BentoGridItemVariants, type BentoGridProps, type BentoGridSize, BoundedNumber, type BoundedNumberProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, type ButtonProps, CATEGORY_LABEL, COLOR_TOKENS, COPY_FEEDBACK_MS, Calendar, type CalendarProps, Card, CardAction, CardContent, CardDescription, type CardDescriptionProps, CardFooter, CardHeader, type CardProps, CardTitle, type CardTitleProps, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, type ChangeHunk, type ChangeHunkStatus, type ChangeProvenance, ChangeReview, type ChangeReviewActions, ChangeReviewHeader, type ChangeReviewHeaderProps, ChangeReviewHunk, type ChangeReviewHunkProps, ChangeReviewList, type ChangeReviewListProps, type ChangeReviewProps, ChangeReviewProvenance, type ChangeReviewProvenanceProps, ChangeReviewProvider, type ChangeReviewProviderProps, type ChangeReviewState, Checkbox, Collapsible, CollapsibleContent, type CollapsiblePanelAttrs, type CollapsiblePanelSide, type CollapsiblePanelState, CollapsibleTrigger, ColorPicker, type ColorPickerProps, type ColorToken, Combobox, type ComboboxOption, type ComboboxProps, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, type CommandProps, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, type CopyToClipboard, CopyableValue, type CopyableValueProps, type CustomStatus, DEFAULT_MESSAGES, DOCUMENT_ADDRESS_KINDS, DatePicker, type DatePickerProps, DateRangePicker, type DateRangePickerProps, type DateRangePreset, Descriptions, DescriptionsItem, type DescriptionsItemProps, type DescriptionsProps, Dialog, DialogBody, type DialogBodyProps, DialogClose, DialogContent, DialogDescription, type DialogDismissGuard, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogSection, type DialogSectionProps, DialogTitle, DialogTrigger, type DocumentAddress, type DocumentAddressKind, type DocumentRect, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, ErrorState, type ErrorStateProps, ExpandDialog, ExpandDialogContent, type ExpandDialogContentProps, ExpandDialogHeader, type ExpandDialogHeaderProps, ExpandDialogPanes, type ExpandDialogPanesProps, type ExpandDialogProps, FILE_CATEGORY_ICONS, FieldRow, type FieldRowProps, type FileCategory, type FileKind, type FileSource, FileUpload, FileUploadDropzone, type FileUploadDropzoneProps, FileUploadItem, type FileUploadItemProps, FileUploadList, type FileUploadListProps, type FileUploadProps, type FileUploadStatus, FilterChip, type FilterChipProps, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Heading, type HeadingLevel, type HeadingProps, type HeadingSize, HoverCard, HoverCardContent, HoverCardTrigger, IconButton, type IconButtonProps, type IconButtonSize, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, type InputGroupProps, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, type InputProps, type InsertMentionResult, Kbd, KeyValueEditor, type KeyValueEditorProps, type KeyValueRow, Label, LinkPreview, LinkPreviewCard, type LinkPreviewCardProps, ListEditor, type ListEditorProps, LoadingState, type LoadingStateProps, type LocaleContextValue, LocaleProvider, type LocaleProviderProps, MatchHighlight, type MatchHighlightProps, type MatchRange, type Mention, MentionInput, MentionInputContent, type MentionInputContentProps, type MentionInputContextValue, MentionInputEmpty, type MentionInputEmptyProps, MentionInputItem, type MentionInputItemProps, MentionInputList, type MentionInputListProps, type MentionInputProps, MentionInputTextarea, type MentionInputTextareaProps, type MentionOption, type MentionValue, Menubar, MenubarCheckboxItem, MenubarContent, MenubarItem, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, type Messages, MetricCard, type MetricCardEmphasis, type MetricCardProps, ModelPicker, type ModelPickerBody, type ModelPickerGroup, type ModelPickerItem, type ModelPickerProps, type ModelPickerStatus, NavMain, type NavMainProps, type NavMainRoute, type NavMainSubItem, type NavNotification, NavNotifications, type NavNotificationsProps, NavUser, type NavUserProps, type NavUserUser, NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, type NormalizedText, NumberInput, type NumberInputProps, PROSE_HEADING_REM, PROSE_HEADING_TRACKING, PROSE_HEADING_WEIGHT, PageShell, type PageShellProps, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, type ProgressProps, ProseBlockquote, ProseHeading, type ProseHeadingLevel, type ProseHeadingProps, ProseInlineCode, ProseLink, type ProseLinkProps, ProseList, ProseListItem, type ProseListProps, ProseText, type ProseTextProps, type QuoteAddress, RadioGroup, RadioGroupItem, type RangeAddress, Rating, type RatingProps, type RectAddress, ResizableHandle, ResizablePanel, ResizablePanelGroup, type ResolvedFileSource, ResultCount, type ResultCountProps, Reveal, RevealGroup, type RevealGroupProps, type RevealProps, type Revision, type RevisionBranch, type RevisionEdge, RevisionTimeline, type RevisionTimelineDensity, type RevisionTimelineProps, STATUSES, STATUS_LABELS, STATUS_ROLE, STATUS_TONES, STATUS_TONE_ICONS, STREAMDOWN_TRANSLATION_KEYS, ScrollArea, ScrollBar, SectionHeader, type SectionHeaderProps, SegmentedField, type SegmentedFieldOption, type SegmentedFieldProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeparatorProps, Sheet, SheetClose, SheetContent, type SheetContentProps, SheetDescription, SheetFooter, SheetHeader, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, type SkeletonProps, Slider, SliderNumber, type SliderNumberProps, type SliderProps, type SliderThumbProps, Spinner, type SpinnerProps, SplitPanel, type SplitPanelProps, type SplitPanelTone, StatePanel, type StatePanelProps, type Status, StatusBadge, type StatusBadgeProps, StatusIcon, type StatusIconProps, type StatusTone, type StreamdownTranslationKey, type StreamdownTranslationMap, Switch, TEXT_ROLE_REM, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TagInput, type TagInputProps, TeamSwitcher, type TeamSwitcherProps, type TeamSwitcherTeam, Text, type TextProps, type TextRole, type TextTone, type TextVariant, Textarea, type TextareaProps, type ThemePreference, ThemeSwitcher, type ThemeSwitcherProps, type ThemeTransitionEffect, Timeline, type TimelineEntry, TimelineItem, type TimelineItemProps, type TimelineProps, TimelineRoot, type TimelineRootProps, type TimelineStatus, Toaster, type ToasterProps, Toggle, ToggleGroup, ToggleGroupItem, Toolbar, ToolbarButton, type ToolbarButtonProps, type ToolbarProps, ToolbarSeparator, type ToolbarSeparatorProps, ToolbarSlot, ToolbarToggleGroup, type ToolbarToggleGroupProps, ToolbarToggleItem, type ToolbarToggleItemProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TopNav, type TopNavProps, Transfer, type TransferItem, type TransferProps, Tree, type TreeNode, type TreeProps, TreeSelect, type TreeSelectProps, type UploadFile, type UseCollapsiblePanelOptions, type UseCollapsiblePanelReturn, type UseCopyToClipboardOptions, type UseDialogDismissGuardOptions, type UseTreeKeyboardOptions, type UseTreeKeyboardResult, ViewToolbar, ViewToolbarFilters, type ViewToolbarFiltersProps, type ViewToolbarProps, VirtualSelect, type VirtualSelectOption, type VirtualSelectProps, Wizard, WizardNav, type WizardNavProps, type WizardProps, WizardStep, type WizardStepMeta, type WizardStepProps, WizardSteps, type WizardStepsProps, type WizardValidator, alertVariants, badgeVariants, bentoGridItemVariants, buttonGroupVariants, buttonVariants, cardVariants, cn, countItems, defaultMentionFilter, dialogContentVariants, downloadBlob, downloadUrl, expandDialogPanesVariants, extensionOf, fileIconFor, fromTimelineStatus, headingVariants, hunkVariants, inputGroupAddonVariants, inputGroupVariants, insertMention, isCustomStatus, laneColor, mediaTypeFromName, mentionAt, mentionEnd, modelPickerBody, navigationMenuTriggerStyle, normalizeFileSource, normalizeQuoteText, normalizeQuoteTextWithOffsets, normalizeRanges, progressIndicatorVariants, queryToRanges, remapMentions, resolveFileKind, revealVariants, revisionTimelineVariants, serializeMentions, showsInlineError, sidebarMenuButtonVariants, statePanelVariants, statusBadgeVariants, textVariants, toggleVariants, toolbarVariants, useCollapsiblePanel, useCommandActiveItemId, useCopyToClipboard, useDialogDismissGuard, useFileUpload, useFormField, useIsMobile, useLocale, useMentionInput, useSidebar, useStreamdownTranslations, useThemeTransition, useTreeKeyboard, useVirtualListbox };
6906
+ export { APPROVAL_SCOPE_DESCRIPTION_KEYS, ATTRIBUTIONS, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AdvancedGroup, type AdvancedGroupProps, type AgentEventOutcome, type AgentEventPhase, Alert, AlertDescription, type AlertDescriptionProps, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, type AlertTitleProps, AppShell, type AppShellProps, AppSidebar, type AppSidebarProps, type ApprovalOption, type ApprovalScope, AspectRatio, type Attribution, type AttributionCategory, AttributionPanel, type AttributionPanelProps, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, BentoGrid, BentoGridItem, type BentoGridItemProps, type BentoGridItemVariants, type BentoGridProps, type BentoGridSize, type BooleanFieldSpec, BoundedNumber, type BoundedNumberProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, type ButtonProps, CATEGORY_LABEL, COLOR_TOKENS, COPY_FEEDBACK_MS, Calendar, type CalendarProps, Card, CardAction, CardContent, CardDescription, type CardDescriptionProps, CardFooter, CardHeader, type CardProps, CardTitle, type CardTitleProps, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, type ChangeHunk, type ChangeHunkStatus, type ChangeProvenance, ChangeReview, type ChangeReviewActions, ChangeReviewHeader, type ChangeReviewHeaderProps, ChangeReviewHunk, type ChangeReviewHunkProps, ChangeReviewList, type ChangeReviewListProps, type ChangeReviewProps, ChangeReviewProvenance, type ChangeReviewProvenanceProps, ChangeReviewProvider, type ChangeReviewProviderProps, type ChangeReviewState, type CheckResult, type CheckSummary, Checkbox, Collapsible, CollapsibleContent, type CollapsiblePanelAttrs, type CollapsiblePanelSide, type CollapsiblePanelState, CollapsibleTrigger, ColorPicker, type ColorPickerProps, type ColorToken, Combobox, type ComboboxOption, type ComboboxProps, Command, CommandDialog, type CommandDialogProps, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, type CommandProps, CommandSeparator, CommandShortcut, CommandTrigger, type CommandTriggerProps, ConfirmDialog, type ConfirmDialogProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, ContextRail, type ContextRailProps, type ContextRailSection, type CopyToClipboard, CopyableValue, type CopyableValueProps, type CustomStatus, DEFAULT_MESSAGES, DOCUMENT_ADDRESS_KINDS, DatePicker, type DatePickerProps, DateRangePicker, type DateRangePickerProps, type DateRangePreset, Descriptions, DescriptionsItem, type DescriptionsItemProps, type DescriptionsProps, Dialog, DialogBody, type DialogBodyProps, DialogClose, DialogContent, DialogDescription, type DialogDismissGuard, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogSection, type DialogSectionProps, DialogTitle, DialogTrigger, type DiffLine, type DiffLineType, type DiffRow, type DocumentAddress, type DocumentAddressKind, type DocumentRect, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, type EffortLevel, EmptyListIllustration, EmptyState, type EmptyStateProps, type EnumFieldSpec, type EnumOption, ErrorIllustration, ErrorState, type ErrorStateProps, ExpandDialog, ExpandDialogContent, type ExpandDialogContentProps, ExpandDialogHeader, type ExpandDialogHeaderProps, ExpandDialogPanes, type ExpandDialogPanesProps, type ExpandDialogProps, FILE_CATEGORY_ICONS, FieldControl, type FieldControlProps, FieldDescription, FieldError, type FieldKeyValueRow, FieldLabel, FieldRoot, type FieldRootProps, FieldRow, type FieldRowProps, type FieldSpec, type FileCategory, type FileFieldSpec, type FileIssue, type FileKind, type FileSource, FileUpload, FileUploadDropzone, type FileUploadDropzoneProps, FileUploadItem, type FileUploadItemProps, FileUploadList, type FileUploadListProps, type FileUploadProps, type FileUploadStatus, FilterChip, type FilterChipProps, type FindTriggerQueryOptions, FirstRunIllustration, type FormSpec, type FormSubmitState, type FormValue, type FormValues, type FromJsonSchemaOptions, type GroupFieldSpec, type GroupItemSpec, Heading, type HeadingLevel, type HeadingProps, type HeadingSize, HoverCard, HoverCardContent, HoverCardTrigger, ILLUSTRATION_ACCENT_VAR, IconButton, type IconButtonProps, type IconButtonSize, type IllustrationProps, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, type InputGroupProps, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, type InputProps, type InsertMentionResult, type IntegerFieldSpec, Kbd, KeyValueEditor, type KeyValueEditorProps, type KeyValueFieldSpec, type KeyValueRow, KeyboardShortcuts, type KeyboardShortcutsProps, Label, LinkPreview, LinkPreviewCard, type LinkPreviewCardProps, ListEditor, type ListEditorProps, type ListFieldSpec, LoadingState, type LoadingStateProps, type LocaleContextValue, LocaleProvider, type LocaleProviderProps, MatchHighlight, type MatchHighlightProps, type MatchRange, type Mention, MentionInput, MentionInputContent, type MentionInputContentProps, type MentionInputContextValue, MentionInputEmpty, type MentionInputEmptyProps, MentionInputItem, type MentionInputItemProps, MentionInputList, type MentionInputListProps, type MentionInputProps, MentionInputTextarea, type MentionInputTextareaProps, type MentionOption, type MentionValue, Menubar, MenubarCheckboxItem, MenubarContent, MenubarItem, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, type MessageValue, type Messages, MetricCard, type MetricCardEmphasis, type MetricCardProps, ModelPicker, type ModelPickerBody, type ModelPickerGroup, type ModelPickerItem, type ModelPickerProps, type ModelPickerStatus, type MultiEnumFieldSpec, NavMain, type NavMainProps, type NavMainRoute, type NavMainSubItem, type NavNotification, NavNotifications, type NavNotificationsProps, NavUser, type NavUserProps, type NavUserUser, NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NoAccessIllustration, NoResultsIllustration, type NormalizedFormSpec, type NormalizedText, type NumberFieldSpec, NumberInput, type NumberInputProps, OfflineIllustration, type OperatingMode, PROSE_HEADING_REM, PROSE_HEADING_TRACKING, PROSE_HEADING_WEIGHT, PageShell, type PageShellProps, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, type PluralCategory, type PluralMessage, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, type ProgressProps, ProseBlockquote, ProseHeading, type ProseHeadingLevel, type ProseHeadingProps, ProseInlineCode, ProseLink, type ProseLinkProps, ProseList, ProseListItem, type ProseListProps, ProseText, type ProseTextProps, type QuoteAddress, RadioGroup, RadioGroupItem, type RangeAddress, Rating, type RatingProps, type RectAddress, ResizableHandle, ResizablePanel, ResizablePanelGroup, type ResolvedFileSource, ResultCount, type ResultCountProps, Reveal, RevealGroup, type RevealGroupProps, type RevealProps, type Revision, type RevisionBranch, type RevisionEdge, RevisionTimeline, type RevisionTimelineDensity, type RevisionTimelineProps, STATUSES, STATUS_LABELS, STATUS_ROLE, STATUS_TONES, STATUS_TONE_ICONS, STREAMDOWN_TRANSLATION_KEYS, SchemaForm, SchemaFormDescription, type SchemaFormDescriptionProps, SchemaFormError, type SchemaFormErrorProps, SchemaFormFallback, type SchemaFormFallbackProps, SchemaFormField, type SchemaFormFieldProps, SchemaFormFields, type SchemaFormFieldsProps, type SchemaFormProps, SchemaFormProvider, type SchemaFormProviderProps, SchemaFormRoot, type SchemaFormRootProps, SchemaFormSubmit, type SchemaFormSubmitProps, SchemaFormTestAction, type SchemaFormTestActionProps, type SchemaFormTestActionStatus, SchemaFormTitle, type SchemaFormTitleProps, ScrollArea, ScrollBar, SectionHeader, type SectionHeaderProps, SegmentedField, type SegmentedFieldOption, type SegmentedFieldProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeparatorProps, type SessionCapability, type SessionQuickAction, type SessionWhatsNewItem, Sheet, SheetClose, SheetContent, type SheetContentProps, SheetDescription, SheetFooter, SheetHeader, SheetPortal, SheetTitle, SheetTrigger, type Shortcut, type ShortcutGroup, SideDock, type SideDockProps, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, type SidebarInsetGutter, type SidebarInsetProps, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, type SkeletonProps, SkipLink, type SkipLinkProps, type SlashCommand, Slider, SliderNumber, type SliderNumberProps, type SliderProps, type SliderThumbProps, Spinner, type SpinnerProps, SplitPanel, type SplitPanelProps, type SplitPanelTone, StatePanel, type StatePanelProps, type Status, StatusBadge, type StatusBadgeProps, StatusIcon, type StatusIconProps, type StatusTone, type StreamdownTranslationKey, type StreamdownTranslationMap, type StringFieldSpec, SuccessIllustration, Switch, TEXT_ROLE_REM, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, type TabsListProps, TabsTrigger, type TabsVariant, TagInput, type TagInputProps, TeamSwitcher, type TeamSwitcherProps, type TeamSwitcherTeam, Text, type TextProps, type TextRole, type TextTone, type TextVariant, Textarea, type TextareaProps, type ThemePreference, ThemeSwitcher, type ThemeSwitcherProps, type ThemeTransitionEffect, Timeline, type TimelineEntry, TimelineItem, type TimelineItemProps, type TimelineProps, TimelineRoot, type TimelineRootProps, type TimelineStatus, Toaster, type ToasterProps, Toggle, ToggleGroup, ToggleGroupItem, Toolbar, ToolbarButton, type ToolbarButtonProps, type ToolbarProps, ToolbarSeparator, type ToolbarSeparatorProps, ToolbarSlot, ToolbarToggleGroup, type ToolbarToggleGroupProps, ToolbarToggleItem, type ToolbarToggleItemProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TopNav, type TopNavProps, Transfer, type TransferItem, type TransferProps, Tree, type TreeNode, type TreeProps, TreeSelect, type TreeSelectProps, type TriggerBoundary, type TriggerQuery, UnsupportedJsonSchemaError, type UploadFile, type UseCollapsiblePanelOptions, type UseCollapsiblePanelReturn, type UseCopyToClipboardOptions, type UseDialogDismissGuardOptions, type UseTreeKeyboardOptions, type UseTreeKeyboardResult, ViewToolbar, ViewToolbarFilters, type ViewToolbarFiltersProps, type ViewToolbarProps, VirtualSelect, type VirtualSelectOption, type VirtualSelectProps, Wizard, WizardNav, type WizardNavProps, type WizardProps, WizardStep, type WizardStepMeta, type WizardStepProps, WizardSteps, type WizardStepsProps, type WizardValidator, type Workspace, WorkspacePicker, type WorkspacePickerProps, agentEventOutcomeStatus, alertVariants, badgeVariants, bentoGridItemVariants, booleanFieldSchema, buttonGroupVariants, buttonVariants, cardVariants, checkFileIssue, cn, collapseDiffRows, collectValidatableFields, countItems, csvQuoteField, csvStringifyValue, defaultMentionFilter, defaultSlashCommandFilter, dialogContentVariants, diffLineAccessibleLabel, diffLineMarker, downloadBlob, downloadUrl, effortRungForIndex, enumFieldSchema, enumOptionSchema, expandDialogPanesVariants, extensionOf, fieldLabel, fieldSpecSchema, fileFieldSchema, fileIconFor, fileMatchesAccept, findFieldByName, findTriggerQuery, formSpecSchema, formatElapsed, formatLastOpened, fromJsonSchema, fromTimelineStatus, groupFieldSchema, groupItemSchema, headingVariants, hunkVariants, illustrationAccent, initialFormValues, inputGroupAddonVariants, inputGroupVariants, insertMention, integerFieldSchema, isCustomStatus, isFieldVisible, isModuleNotFoundMessage, isOptionalPeerMissing, keyValueFieldSchema, keyValueRowSchema, laneColor, listFieldSchema, mediaTypeFromName, mentionAt, mentionEnd, modelPickerBody, multiEnumFieldSchema, navigationMenuTriggerStyle, normalizeFileSource, normalizeFormSpec, normalizeQuoteText, normalizeQuoteTextWithOffsets, normalizeRanges, numberFieldSchema, optionLabel, optionValue, progressIndicatorVariants, queryToRanges, remapMentions, replaceTriggerRun, resolveFileKind, revealVariants, revisionTimelineVariants, serializeMentions, showsInlineError, sidebarMenuButtonVariants, splitPaneVariants, statePanelVariants, statusBadgeVariants, stepIndex, stringFieldSchema, tabsListVariants, tabsTriggerVariants, textVariants, toggleVariants, toolbarVariants, useCollapsiblePanel, useCommandActiveItemId, useCopyToClipboard, useDialogDismissGuard, useDiffRows, useFileUpload, useIsMobile, useLocale, useMentionInput, useSidebar, useStreamdownTranslations, useThemeTransition, useTreeKeyboard, useVirtualListbox, validateField, validateForm };