haze-ui 1.28.0 → 1.30.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 (435) hide show
  1. package/README.md +139 -33
  2. package/cli/theme.mjs +446 -0
  3. package/dist/components/Accordion/Accordion.js +1 -0
  4. package/dist/components/Accordion/AccordionItem.js +3 -0
  5. package/dist/components/Affix/Affix.js +1 -0
  6. package/dist/components/Alert/Alert.js +3 -0
  7. package/dist/components/Anchor/Anchor.js +21 -15
  8. package/dist/components/AppShell/AppShell.js +5 -0
  9. package/dist/components/ApprovalCard/ApprovalCard.js +8 -0
  10. package/dist/components/AspectRatio/AspectRatio.js +2 -0
  11. package/dist/components/AsyncSection/AsyncSection.js +8 -0
  12. package/dist/components/Avatar/Avatar.js +11 -6
  13. package/dist/components/AvatarGroup/AvatarGroup.js +9 -6
  14. package/dist/components/BackToTop/BackToTop.js +5 -4
  15. package/dist/components/Badge/Badge.js +1 -0
  16. package/dist/components/Banner/Banner.js +3 -0
  17. package/dist/components/BottomSheet/BottomSheet.js +21 -16
  18. package/dist/components/Breadcrumb/Breadcrumb.js +11 -7
  19. package/dist/components/Breadcrumb/BreadcrumbItem.js +2 -0
  20. package/dist/components/Button/Button.js +13 -11
  21. package/dist/components/Button/ButtonLink.js +15 -13
  22. package/dist/components/Calendar/Calendar.js +523 -368
  23. package/dist/components/Calendar/date.js +35 -10
  24. package/dist/components/Card/Card.js +1 -0
  25. package/dist/components/Carousel/Carousel.js +157 -60
  26. package/dist/components/Carousel/CarouselSlide.js +3 -1
  27. package/dist/components/Cascader/Cascader.js +48 -35
  28. package/dist/components/Chart/Chart.js +5 -4
  29. package/dist/components/Chart/chart-elements.js +117 -52
  30. package/dist/components/ChatContainer/ChatContainer.js +9 -7
  31. package/dist/components/ChatInput/ChatInput.js +12 -9
  32. package/dist/components/ChatMessage/ChatMessage.js +83 -44
  33. package/dist/components/Checkbox/CheckboxCore.js +2 -0
  34. package/dist/components/Chip/Chip.js +3 -0
  35. package/dist/components/CodeBlock/CodeBlock.js +18 -9
  36. package/dist/components/Collapsible/Collapsible.js +24 -21
  37. package/dist/components/ColorPicker/ColorPicker.js +85 -14
  38. package/dist/components/ColorPicker/ColorPickerCore.js +6 -0
  39. package/dist/components/ColorPicker/ColorPickerPanel.js +277 -0
  40. package/dist/components/ColorPicker/color-math.js +168 -0
  41. package/dist/components/ColorPicker/color-picker-styles.js +7 -0
  42. package/dist/components/ColorPicker/index.js +3 -3
  43. package/dist/components/Combobox/Combobox.js +31 -24
  44. package/dist/components/Combobox/ComboboxGroup.js +7 -5
  45. package/dist/components/Combobox/ComboboxOption.js +1 -0
  46. package/dist/components/Command/Command.js +44 -37
  47. package/dist/components/Command/CommandDialog.js +8 -8
  48. package/dist/components/ConfigProvider/ConfigContext.js +30 -0
  49. package/dist/components/ConfigProvider/ConfigProvider.js +14 -0
  50. package/dist/components/ConfigProvider/index.js +4 -0
  51. package/dist/components/ConfigProvider/useConfigDefaults.js +10 -0
  52. package/dist/components/ConfirmDialog/ConfirmDialog.js +18 -11
  53. package/dist/components/Container/Container.js +1 -0
  54. package/dist/components/ContextMenu/ContextMenu.js +7 -6
  55. package/dist/components/ContextMenu/ContextMenuContent.js +4 -4
  56. package/dist/components/ContextMenu/ContextMenuItem.js +1 -0
  57. package/dist/components/ContextMenu/ContextMenuSeparator.js +1 -0
  58. package/dist/components/ContextMenu/ContextMenuTrigger.js +1 -0
  59. package/dist/components/ConversationList/ConversationItem.js +4 -0
  60. package/dist/components/ConversationList/ConversationList.js +1 -0
  61. package/dist/components/CountUp/CountUp.js +46 -0
  62. package/dist/components/CountUp/index.js +3 -0
  63. package/dist/components/DataTable/CellEditor.js +4 -4
  64. package/dist/components/DataTable/DataTable.js +236 -168
  65. package/dist/components/DateRangePicker/DateRangePickerCore.js +9 -0
  66. package/dist/components/Datepicker/Datepicker.js +14 -11
  67. package/dist/components/Datepicker/DatepickerCore.js +75 -60
  68. package/dist/components/Datepicker/datetime.js +14 -3
  69. package/dist/components/Descriptions/Descriptions.js +6 -0
  70. package/dist/components/Dialog/Dialog.js +13 -11
  71. package/dist/components/DiffViewer/DiffViewer.js +22 -13
  72. package/dist/components/Disclosure/Disclosure.js +10 -7
  73. package/dist/components/Divider/Divider.js +2 -0
  74. package/dist/components/Drawer/Drawer.js +10 -9
  75. package/dist/components/DropdownMenu/DropdownMenu.js +58 -35
  76. package/dist/components/DropdownMenu/DropdownMenuCheckboxItem.js +63 -0
  77. package/dist/components/DropdownMenu/DropdownMenuContent.js +5 -5
  78. package/dist/components/DropdownMenu/DropdownMenuGroup.js +26 -0
  79. package/dist/components/DropdownMenu/DropdownMenuItem.js +29 -10
  80. package/dist/components/DropdownMenu/DropdownMenuRadioGroup.js +30 -0
  81. package/dist/components/DropdownMenu/DropdownMenuRadioItem.js +59 -0
  82. package/dist/components/DropdownMenu/DropdownMenuSeparator.js +1 -0
  83. package/dist/components/DropdownMenu/DropdownMenuSub.js +1 -0
  84. package/dist/components/DropdownMenu/DropdownMenuSubTrigger.js +1 -0
  85. package/dist/components/DropdownMenu/DropdownMenuTrigger.js +1 -0
  86. package/dist/components/DropdownMenu/dropdown-menu-item-styles.js +7 -0
  87. package/dist/components/DropdownMenu/index.js +12 -8
  88. package/dist/components/Ellipsis/Ellipsis.js +56 -0
  89. package/dist/components/Ellipsis/index.js +3 -0
  90. package/dist/components/Empty/Empty.js +4 -0
  91. package/dist/components/FileInput/FileInput.js +7 -5
  92. package/dist/components/FilePreview/FilePreview.js +19 -1
  93. package/dist/components/Flex/Flex.js +1 -0
  94. package/dist/components/FloatButton/FloatButton.js +4 -0
  95. package/dist/components/FloatButton/FloatButtonGroup.js +18 -13
  96. package/dist/components/Fullscreen/Fullscreen.js +6 -3
  97. package/dist/components/Grid/Grid.js +12 -7
  98. package/dist/components/Grid/GridItem.js +17 -7
  99. package/dist/components/Grid/grid-item-styles.js +58 -0
  100. package/dist/components/HoverCard/HoverCard.js +46 -43
  101. package/dist/components/Icon/Icon.js +1 -0
  102. package/dist/components/Image/Image.js +10 -7
  103. package/dist/components/Image/ImagePreview.js +42 -34
  104. package/dist/components/InlineCompletion/InlineCompletion.js +15 -11
  105. package/dist/components/InlineEdit/InlineEdit.js +8 -6
  106. package/dist/components/Input/InputCore.js +1 -0
  107. package/dist/components/JsonView/JsonView.js +104 -79
  108. package/dist/components/Kbd/Kbd.js +1 -0
  109. package/dist/components/List/List.js +1 -0
  110. package/dist/components/List/ListItem.js +1 -0
  111. package/dist/components/LocaleProvider/LocaleProvider.js +4 -4
  112. package/dist/components/LocaleProvider/ar-sa.js +255 -0
  113. package/dist/components/LocaleProvider/de-de.js +255 -0
  114. package/dist/components/LocaleProvider/es-es.js +255 -0
  115. package/dist/components/LocaleProvider/fr-fr.js +255 -0
  116. package/dist/components/LocaleProvider/index.js +10 -2
  117. package/dist/components/LocaleProvider/it-it.js +255 -0
  118. package/dist/components/LocaleProvider/ja-jp.js +35 -2
  119. package/dist/components/LocaleProvider/ko-kr.js +255 -0
  120. package/dist/components/LocaleProvider/locale.js +35 -2
  121. package/dist/components/LocaleProvider/pt-br.js +255 -0
  122. package/dist/components/LocaleProvider/ru-ru.js +255 -0
  123. package/dist/components/LocaleProvider/zh-cn.js +35 -2
  124. package/dist/components/LogViewer/LogViewer.js +25 -14
  125. package/dist/components/MarkdownRenderer/MarkdownRenderer.js +6 -5
  126. package/dist/components/MarkdownRenderer/markdown-blocks.js +1 -1
  127. package/dist/components/Masonry/Masonry.js +13 -10
  128. package/dist/components/Mentions/MentionsCore.js +15 -11
  129. package/dist/components/Menu/Menu.js +58 -36
  130. package/dist/components/Menu/MenuCheckboxItem.js +63 -0
  131. package/dist/components/Menu/MenuDivider.js +1 -0
  132. package/dist/components/Menu/MenuGroup.js +26 -0
  133. package/dist/components/Menu/MenuItem.js +28 -9
  134. package/dist/components/Menu/MenuRadioGroup.js +30 -0
  135. package/dist/components/Menu/MenuRadioItem.js +59 -0
  136. package/dist/components/Menu/MenuSub.js +1 -0
  137. package/dist/components/Menu/MenuSubTrigger.js +1 -0
  138. package/dist/components/Menu/index.js +11 -7
  139. package/dist/components/Menu/menu-item-styles.js +7 -0
  140. package/dist/components/ModelPicker/ModelPicker.js +3 -0
  141. package/dist/components/NavigationBar/NavLink.js +7 -6
  142. package/dist/components/NavigationBar/NavigationBar.js +4 -0
  143. package/dist/components/NumberInput/NumberInputCore.js +4 -0
  144. package/dist/components/OTPInput/OTPInputCore.js +9 -7
  145. package/dist/components/Pagination/Pagination.js +125 -33
  146. package/dist/components/PasswordInput/PasswordInputCore.js +9 -6
  147. package/dist/components/Popover/Popover.js +9 -7
  148. package/dist/components/Progress/Progress.js +5 -0
  149. package/dist/components/PromptInput/PromptInput.js +49 -41
  150. package/dist/components/QRCode/QRCode.js +45 -0
  151. package/dist/components/QRCode/index.js +3 -0
  152. package/dist/components/Radio/Radio.js +2 -0
  153. package/dist/components/Radio/RadioGroupCore.js +7 -6
  154. package/dist/components/Rating/RatingCore.js +18 -15
  155. package/dist/components/Resizable/Resizable.js +25 -22
  156. package/dist/components/Result/Result.js +234 -0
  157. package/dist/components/Result/index.js +3 -0
  158. package/dist/components/ScrollArea/ScrollArea.js +1 -0
  159. package/dist/components/Segmented/SegmentedCore.js +9 -7
  160. package/dist/components/Select/Option.js +1 -0
  161. package/dist/components/Select/OptionGroup.js +1 -0
  162. package/dist/components/Select/SelectCore.js +11 -8
  163. package/dist/components/Select/SelectFloating.js +54 -36
  164. package/dist/components/Sidebar/Sidebar.js +52 -42
  165. package/dist/components/Signature/Signature.js +101 -91
  166. package/dist/components/Skeleton/Skeleton.js +1 -0
  167. package/dist/components/Slider/SliderCore.js +149 -43
  168. package/dist/components/Sources/Sources.js +31 -21
  169. package/dist/components/Spinner/Spinner.js +1 -0
  170. package/dist/components/Stat/Stat.js +7 -0
  171. package/dist/components/StepTimeline/StepTimeline.js +6 -0
  172. package/dist/components/Stepper/Step.js +8 -1
  173. package/dist/components/Stepper/Stepper.js +7 -6
  174. package/dist/components/StreamingText/StreamingText.js +62 -29
  175. package/dist/components/SwipeAction/SwipeAction.js +11 -9
  176. package/dist/components/Switch/SwitchCore.js +9 -5
  177. package/dist/components/Table/Table.js +2 -0
  178. package/dist/components/Table/TableBody.js +1 -0
  179. package/dist/components/Table/TableCell.js +1 -0
  180. package/dist/components/Table/TableHead.js +1 -0
  181. package/dist/components/Table/TableRow.js +1 -0
  182. package/dist/components/Tabs/Tab.js +1 -0
  183. package/dist/components/Tabs/TabList.js +5 -4
  184. package/dist/components/Tabs/TabPanel.js +1 -0
  185. package/dist/components/Tabs/Tabs.js +1 -0
  186. package/dist/components/Tag/Tag.js +2 -0
  187. package/dist/components/TagGroup/SortableTagGroup.js +7 -6
  188. package/dist/components/TagGroup/TagGroup.js +1 -0
  189. package/dist/components/TagGroup/TagGroupItem.js +3 -0
  190. package/dist/components/TagInput/SortableTagInputCore.js +13 -10
  191. package/dist/components/TagInput/TagInputCore.js +17 -12
  192. package/dist/components/Textarea/TextareaCore.js +1 -0
  193. package/dist/components/ThinkingIndicator/ThinkingIndicator.js +18 -4
  194. package/dist/components/TimePicker/TimePicker.js +30 -14
  195. package/dist/components/TimePicker/TimePickerCore.js +1 -0
  196. package/dist/components/TimePicker/TimePickerPanel.js +260 -0
  197. package/dist/components/TimePicker/time-picker-styles.js +7 -0
  198. package/dist/components/TimePicker/time.js +51 -0
  199. package/dist/components/Timeline/Timeline.js +14 -1
  200. package/dist/components/Toast/Toast.js +94 -48
  201. package/dist/components/Toast/ToastContainer.js +60 -56
  202. package/dist/components/Toast/ToastContext.js +3 -1
  203. package/dist/components/Toast/toast2.js +20 -14
  204. package/dist/components/Toast/useToast.js +36 -11
  205. package/dist/components/Toggle/ToggleCore.js +1 -0
  206. package/dist/components/TokenCounter/TokenCounter.js +8 -1
  207. package/dist/components/ToolCallCard/ToolCallCard.js +18 -2
  208. package/dist/components/Toolbar/Toolbar.js +9 -8
  209. package/dist/components/Toolbar/ToolbarButton.js +1 -0
  210. package/dist/components/Toolbar/ToolbarSeparator.js +1 -0
  211. package/dist/components/Toolbar/ToolbarToggle.js +1 -0
  212. package/dist/components/Tooltip/Tooltip.js +46 -42
  213. package/dist/components/Tour/Tour.js +76 -65
  214. package/dist/components/Transfer/TransferCore.js +31 -17
  215. package/dist/components/Tree/SortableTree.js +151 -0
  216. package/dist/components/Tree/Tree.js +163 -154
  217. package/dist/components/Tree/TreeItem.js +52 -39
  218. package/dist/components/Tree/index.js +2 -1
  219. package/dist/components/Tree/sortable-tree-styles.js +7 -0
  220. package/dist/components/Tree/sortable-tree-utils.js +36 -0
  221. package/dist/components/TreeSelect/TreeSelect.js +240 -0
  222. package/dist/components/TreeSelect/index.js +3 -0
  223. package/dist/components/Typography/Typography.js +42 -12
  224. package/dist/components/Upload/Upload.js +12 -11
  225. package/dist/components/Upload/UploadCore.js +92 -65
  226. package/dist/components/Upload/UploadList.js +177 -105
  227. package/dist/components/VirtualList/VirtualList.js +229 -124
  228. package/dist/components/Watermark/Watermark.js +8 -6
  229. package/dist/css/accordion.css +1 -1
  230. package/dist/css/alert.css +1 -1
  231. package/dist/css/async-section.css +1 -1
  232. package/dist/css/banner.css +1 -1
  233. package/dist/css/bottom-sheet.css +1 -1
  234. package/dist/css/button.css +2 -2
  235. package/dist/css/calendar.css +1 -1
  236. package/dist/css/carousel.css +1 -1
  237. package/dist/css/chat-message.css +1 -1
  238. package/dist/css/checkbox.css +1 -1
  239. package/dist/css/color-picker.css +2 -0
  240. package/dist/css/combobox.css +2 -2
  241. package/dist/css/context-menu.css +1 -1
  242. package/dist/css/count-up.css +2 -0
  243. package/dist/css/dialog.css +1 -1
  244. package/dist/css/drawer.css +1 -1
  245. package/dist/css/dropdown-menu.css +7 -2
  246. package/dist/css/ellipsis.css +2 -0
  247. package/dist/css/form.css +1 -1
  248. package/dist/css/grid.css +2 -1
  249. package/dist/css/hover-card.css +1 -1
  250. package/dist/css/input.css +1 -1
  251. package/dist/css/menu.css +9 -4
  252. package/dist/css/pagination.css +1 -1
  253. package/dist/css/popover.css +1 -1
  254. package/dist/css/progress.css +1 -1
  255. package/dist/css/qr-code.css +2 -0
  256. package/dist/css/radio.css +1 -1
  257. package/dist/css/rating.css +1 -1
  258. package/dist/css/result.css +2 -0
  259. package/dist/css/segmented.css +1 -1
  260. package/dist/css/skeleton.css +1 -1
  261. package/dist/css/slider.css +1 -1
  262. package/dist/css/spinner.css +1 -1
  263. package/dist/css/stepper.css +1 -1
  264. package/dist/css/streaming-text.css +1 -1
  265. package/dist/css/switch.css +1 -1
  266. package/dist/css/tabs.css +1 -1
  267. package/dist/css/textarea.css +1 -1
  268. package/dist/css/thinking-indicator.css +1 -1
  269. package/dist/css/time-picker.css +1 -0
  270. package/dist/css/toast.css +1 -1
  271. package/dist/css/toggle.css +1 -1
  272. package/dist/css/tokens.css +4 -2
  273. package/dist/css/tooltip.css +1 -1
  274. package/dist/css/tree-select.css +3 -0
  275. package/dist/css/tree.css +2 -1
  276. package/dist/css/typography.css +1 -1
  277. package/dist/css/upload.css +1 -1
  278. package/dist/css/virtual-list.css +1 -1
  279. package/dist/css-manifest.json +41 -0
  280. package/dist/dates/adapter.js +13 -0
  281. package/dist/dates/gregory.js +44 -0
  282. package/dist/dates/islamic.js +87 -0
  283. package/dist/dates/registry.js +13 -0
  284. package/dist/dates/timezone.js +29 -0
  285. package/dist/design-tokens/cyan-dark.json +355 -0
  286. package/dist/design-tokens/cyan-light.json +355 -0
  287. package/dist/design-tokens/dark.json +355 -0
  288. package/dist/design-tokens/light.json +355 -0
  289. package/dist/design-tokens/orange-dark.json +355 -0
  290. package/dist/design-tokens/orange-light.json +355 -0
  291. package/dist/design-tokens/rose-dark.json +355 -0
  292. package/dist/design-tokens/rose-light.json +355 -0
  293. package/dist/design-tokens/teal-dark.json +355 -0
  294. package/dist/design-tokens/teal-light.json +355 -0
  295. package/dist/design-tokens/violet-dark.json +355 -0
  296. package/dist/design-tokens/violet-light.json +355 -0
  297. package/dist/form/FormItem.js +71 -63
  298. package/dist/form/FormList.js +6 -6
  299. package/dist/form/form-item-styles.js +7 -0
  300. package/dist/haze-ui.css +73 -50
  301. package/dist/index.js +250 -218
  302. package/dist/mcp-docs.json +10312 -0
  303. package/dist/registry.json +144 -42
  304. package/dist/tokens/brands.js +21 -0
  305. package/dist/tokens/density.js +6 -0
  306. package/dist/tokens/index.js +7 -6
  307. package/dist/tokens/motion.js +9 -2
  308. package/dist/tokens/palette.js +256 -88
  309. package/dist/tokens/registry.js +18 -22
  310. package/dist/types/components/Button/Button.d.ts +1 -1
  311. package/dist/types/components/Calendar/Calendar.d.ts +39 -14
  312. package/dist/types/components/Calendar/date.d.ts +51 -0
  313. package/dist/types/components/Calendar/index.d.ts +1 -1
  314. package/dist/types/components/Carousel/Carousel.d.ts +5 -1
  315. package/dist/types/components/Carousel/CarouselSlide.d.ts +3 -3
  316. package/dist/types/components/Chart/Chart.d.ts +24 -13
  317. package/dist/types/components/Chart/chart-elements.d.ts +39 -10
  318. package/dist/types/components/ChatMessage/ChatMessage.d.ts +10 -1
  319. package/dist/types/components/ColorPicker/ColorPicker.d.ts +44 -5
  320. package/dist/types/components/ColorPicker/ColorPickerPanel.d.ts +28 -0
  321. package/dist/types/components/ColorPicker/color-math.d.ts +63 -0
  322. package/dist/types/components/ColorPicker/color-picker-styles.d.ts +50 -0
  323. package/dist/types/components/ConfigProvider/ConfigContext.d.ts +67 -0
  324. package/dist/types/components/ConfigProvider/ConfigProvider.d.ts +25 -0
  325. package/dist/types/components/ConfigProvider/index.d.ts +4 -0
  326. package/dist/types/components/ConfigProvider/useConfigDefaults.d.ts +28 -0
  327. package/dist/types/components/CountUp/CountUp.d.ts +20 -0
  328. package/dist/types/components/CountUp/index.d.ts +2 -0
  329. package/dist/types/components/Datepicker/Datepicker.d.ts +23 -10
  330. package/dist/types/components/Datepicker/DatepickerCore.d.ts +40 -10
  331. package/dist/types/components/Datepicker/datetime.d.ts +33 -11
  332. package/dist/types/components/DropdownMenu/DropdownMenu.d.ts +12 -2
  333. package/dist/types/components/DropdownMenu/DropdownMenuCheckboxItem.d.ts +26 -0
  334. package/dist/types/components/DropdownMenu/DropdownMenuGroup.d.ts +16 -0
  335. package/dist/types/components/DropdownMenu/DropdownMenuItem.d.ts +7 -1
  336. package/dist/types/components/DropdownMenu/DropdownMenuRadioGroup.d.ts +21 -0
  337. package/dist/types/components/DropdownMenu/DropdownMenuRadioItem.d.ts +22 -0
  338. package/dist/types/components/DropdownMenu/dropdown-menu-item-styles.d.ts +29 -0
  339. package/dist/types/components/DropdownMenu/index.d.ts +9 -1
  340. package/dist/types/components/Ellipsis/Ellipsis.d.ts +19 -0
  341. package/dist/types/components/Ellipsis/index.d.ts +2 -0
  342. package/dist/types/components/Fullscreen/Fullscreen.d.ts +1 -0
  343. package/dist/types/components/Grid/Grid.d.ts +8 -1
  344. package/dist/types/components/Grid/GridItem.d.ts +24 -1
  345. package/dist/types/components/Grid/grid-item-styles.d.ts +57 -0
  346. package/dist/types/components/HoverCard/HoverCard.d.ts +1 -1
  347. package/dist/types/components/LocaleProvider/ar-sa.d.ts +22 -0
  348. package/dist/types/components/LocaleProvider/de-de.d.ts +15 -0
  349. package/dist/types/components/LocaleProvider/es-es.d.ts +15 -0
  350. package/dist/types/components/LocaleProvider/fr-fr.d.ts +15 -0
  351. package/dist/types/components/LocaleProvider/index.d.ts +8 -0
  352. package/dist/types/components/LocaleProvider/it-it.d.ts +15 -0
  353. package/dist/types/components/LocaleProvider/ko-kr.d.ts +15 -0
  354. package/dist/types/components/LocaleProvider/locale.d.ts +35 -0
  355. package/dist/types/components/LocaleProvider/pt-br.d.ts +16 -0
  356. package/dist/types/components/LocaleProvider/ru-ru.d.ts +15 -0
  357. package/dist/types/components/Menu/Menu.d.ts +11 -2
  358. package/dist/types/components/Menu/MenuCheckboxItem.d.ts +25 -0
  359. package/dist/types/components/Menu/MenuGroup.d.ts +16 -0
  360. package/dist/types/components/Menu/MenuItem.d.ts +7 -1
  361. package/dist/types/components/Menu/MenuRadioGroup.d.ts +20 -0
  362. package/dist/types/components/Menu/MenuRadioItem.d.ts +22 -0
  363. package/dist/types/components/Menu/index.d.ts +9 -1
  364. package/dist/types/components/Menu/menu-item-styles.d.ts +28 -0
  365. package/dist/types/components/NavigationBar/NavLink.d.ts +1 -1
  366. package/dist/types/components/Pagination/Pagination.d.ts +17 -3
  367. package/dist/types/components/QRCode/QRCode.d.ts +33 -0
  368. package/dist/types/components/QRCode/index.d.ts +2 -0
  369. package/dist/types/components/Result/Result.d.ts +16 -0
  370. package/dist/types/components/Result/index.d.ts +2 -0
  371. package/dist/types/components/Sidebar/Sidebar.d.ts +1 -1
  372. package/dist/types/components/Slider/Slider.d.ts +24 -2
  373. package/dist/types/components/Slider/SliderCore.d.ts +41 -3
  374. package/dist/types/components/StreamingText/StreamingText.d.ts +8 -1
  375. package/dist/types/components/TagGroup/SortableTagGroup.d.ts +3 -2
  376. package/dist/types/components/TagGroup/TagGroup.d.ts +1 -1
  377. package/dist/types/components/TagInput/SortableTagInput.d.ts +2 -3
  378. package/dist/types/components/TagInput/SortableTagInputCore.d.ts +3 -3
  379. package/dist/types/components/TimePicker/TimePicker.d.ts +36 -4
  380. package/dist/types/components/TimePicker/TimePickerPanel.d.ts +26 -0
  381. package/dist/types/components/TimePicker/index.d.ts +1 -0
  382. package/dist/types/components/TimePicker/time-picker-styles.d.ts +30 -0
  383. package/dist/types/components/TimePicker/time.d.ts +49 -0
  384. package/dist/types/components/Toast/Toast.d.ts +19 -6
  385. package/dist/types/components/Toast/ToastContainer.d.ts +1 -1
  386. package/dist/types/components/Toast/ToastContext.d.ts +22 -2
  387. package/dist/types/components/Toast/index.d.ts +1 -1
  388. package/dist/types/components/Toast/toast.d.ts +20 -14
  389. package/dist/types/components/Toast/useToast.d.ts +14 -4
  390. package/dist/types/components/Tooltip/Tooltip.d.ts +1 -1
  391. package/dist/types/components/Tree/SortableTree.d.ts +38 -0
  392. package/dist/types/components/Tree/Tree.d.ts +1 -1
  393. package/dist/types/components/Tree/index.d.ts +2 -0
  394. package/dist/types/components/Tree/sortable-tree-styles.d.ts +36 -0
  395. package/dist/types/components/Tree/sortable-tree-utils.d.ts +40 -0
  396. package/dist/types/components/TreeSelect/TreeSelect.d.ts +93 -0
  397. package/dist/types/components/TreeSelect/index.d.ts +2 -0
  398. package/dist/types/components/Typography/Typography.d.ts +12 -3
  399. package/dist/types/components/Typography/index.d.ts +1 -1
  400. package/dist/types/components/Upload/Upload.d.ts +17 -10
  401. package/dist/types/components/Upload/UploadCore.d.ts +26 -12
  402. package/dist/types/components/Upload/UploadList.d.ts +10 -7
  403. package/dist/types/components/Upload/index.d.ts +1 -1
  404. package/dist/types/components/Upload/types.d.ts +33 -7
  405. package/dist/types/components/VirtualList/VirtualList.d.ts +79 -26
  406. package/dist/types/components/VirtualList/index.d.ts +1 -1
  407. package/dist/types/dates/adapter.d.ts +74 -0
  408. package/dist/types/dates/gregory.d.ts +10 -0
  409. package/dist/types/dates/index.d.ts +6 -0
  410. package/dist/types/dates/islamic.d.ts +17 -0
  411. package/dist/types/dates/registry.d.ts +13 -0
  412. package/dist/types/dates/timezone.d.ts +36 -0
  413. package/dist/types/form/FormItem.d.ts +31 -1
  414. package/dist/types/form/form-item-styles.d.ts +24 -0
  415. package/dist/types/index.d.ts +34 -13
  416. package/dist/types/tokens/brands.d.ts +28 -0
  417. package/dist/types/tokens/density.d.ts +3 -0
  418. package/dist/types/tokens/index.d.ts +5 -2
  419. package/dist/types/tokens/motion.d.ts +16 -0
  420. package/dist/types/tokens/palette.d.ts +95 -1
  421. package/dist/types/tokens/spacing.d.ts +13 -0
  422. package/dist/types/utils/menuItems.d.ts +126 -0
  423. package/dist/types/utils/menuRadio.d.ts +21 -0
  424. package/dist/types/utils/sortable-shared.d.ts +4 -4
  425. package/dist/utils/floating.js +45 -44
  426. package/dist/utils/menuItems.js +55 -0
  427. package/dist/utils/menuKeyboard.js +31 -31
  428. package/dist/utils/menuRadio.js +28 -0
  429. package/dist/utils/sortable-shared.js +3 -3
  430. package/dist/utils/sortable.js +12 -11
  431. package/mcp/index.mjs +64 -0
  432. package/mcp/server.mjs +89 -0
  433. package/mcp/server.test.mjs +281 -0
  434. package/mcp/tools.mjs +240 -0
  435. package/package.json +74 -47
package/README.md CHANGED
@@ -35,6 +35,24 @@ English | [简体中文](./README-zh_CN.md)
35
35
 
36
36
  ## Getting Started
37
37
 
38
+ ### Quickstart via create-haze-ui
39
+
40
+ Scaffold a ready-to-run app with the official templates — the CLI has zero
41
+ runtime dependencies and needs no network access beyond dependency install:
42
+
43
+ ```sh
44
+ pnpm create haze-ui my-app # vite template (default)
45
+ pnpm create haze-ui my-app --template nextjs # or: npm create haze-ui@latest my-app --
46
+ ```
47
+
48
+ The **vite** template is a React 19 + Vite + TypeScript single-page demo
49
+ (`Button` / `Input` / `Dialog` / `Toast`) with the theme classes mounted on
50
+ the page root; the **nextjs** template is a Next.js 15 App Router starter
51
+ whose home page renders the RSC-safe static subset (`Badge` / `Card` /
52
+ `Typography`) as a server component, with a client island for the
53
+ interactive pieces. Prefer wiring an existing project by hand? Continue
54
+ with Installation below.
55
+
38
56
  ### Installation
39
57
 
40
58
  ```sh
@@ -129,30 +147,30 @@ checklist:
129
147
 
130
148
  ### Dependencies
131
149
 
132
- haze-ui ships two runtime dependencies — `react-use-control`, the engine
133
- behind `ControlOrValue<T>`, and `react-f0rm` (^1.3), the form engine
134
- behind `FormItem`/`FormList` (the same author's headless form store).
135
- Five integrations remain optional peers, installed only when you use the
136
- components that need them:
137
-
138
- ```sh
139
- npm i @tanstack/react-table # DataTable (peer range ^9.2.4)
140
- npm i recharts # Chart (peer range ^3.10.1)
141
- npm i @dnd-kit/core @dnd-kit/sortable \
142
- @dnd-kit/utilities # TagInput/TagGroup sortable
143
- # (^6.3.1 / ^10.0.0 / ^3.2.2)
144
- ```
145
-
146
- Everything else — `Button`, `Input`, `Dialog`, `Select`, … — runs with
147
- nothing beyond `react` and the two runtime dependencies. The dist is ESM
148
- with `preserveModules` and side-effect-free JS, so bundlers (Next.js,
149
- Vite, webpack, Turbopack, Rollup) tree-shake the unused re-export chains
150
- and never resolve peers you haven't installed: `import { Button } from
151
- 'haze-ui'` works without `@tanstack/react-table`. Only bundler-less
152
- consumers (bare Node ESM importing the barrel, which links the module
153
- graph eagerly) must install the optional peers; the
154
- `haze-ui/components/DataTable` and `haze-ui/components/Chart` subpaths
155
- bypass the barrel entirely.
150
+ haze-ui declares only the host environment as peers: `react` and
151
+ `react-dom` (^19). Everything else is a regular dependency — one
152
+ `npm i haze-ui` and every component works:
153
+
154
+ - `react-use-control` — the engine behind `ControlOrValue<T>`
155
+ - `react-f0rm` (^1.3) — the form engine behind `FormItem`/`FormList`
156
+ (the same author's headless form store)
157
+ - `@tanstack/react-table` — DataTable
158
+ - `recharts` — Chart
159
+ - `@dnd-kit/core` / `@dnd-kit/sortable` / `@dnd-kit/utilities` — the
160
+ sortable TagInput/TagGroup variants
161
+ - `qrcode` — QRCode
162
+
163
+ Swapping any of these engines for another library is invisible to your
164
+ code (the one deliberate exception: DataTable's column API exposes
165
+ TanStack's `ColumnDef` types). The dist is ESM with `preserveModules`
166
+ and side-effect-free JS, and engines are imported only by the components
167
+ that need them, so bundlers (Next.js, Vite, webpack, Turbopack, Rollup)
168
+ tree-shake the unused re-export chains: `import { Button } from
169
+ 'haze-ui'` never pulls `@tanstack/react-table` into the bundle. Engines
170
+ install as regular dependencies, so even bundler-less consumers (bare
171
+ Node ESM importing the barrel, which links the module graph eagerly)
172
+ work with zero manual installs; the `haze-ui/components/DataTable` and
173
+ `haze-ui/components/Chart` subpaths bypass the barrel entirely.
156
174
 
157
175
  ### Browser support
158
176
 
@@ -393,16 +411,18 @@ user-controllable, SSR/jsdom-safe when the underlying API is missing.
393
411
  | `useTitle(title)` | — | Document title while mounted |
394
412
  | `useToast()` | toast API | Requires a `ToastContainer` ancestor |
395
413
 
396
- ## Sortable tags and chips (optional dnd-kit peers)
414
+ ## Sortable tags and chips
397
415
 
398
- `TagInput` and `TagGroup` accept `sortable?: boolean` — opt-in drag
399
- reordering powered by `@dnd-kit/core` / `@dnd-kit/sortable` /
400
- `@dnd-kit/utilities` (optional peers, same tree-shaking contract as
401
- recharts and TanStack Table). `TagInput` writes the new array through
402
- `onChange`; `TagGroup` reports `onReorder(nextOrder)` (the new
403
- arrangement of original child indexes) and leaves re-rendering to the
404
- parent. Sorting is keyboard-complete: focus a tag, `Space` to lift,
405
- arrows to move, `Space` to drop, `Escape` to cancel.
416
+ Drag reordering is an opt-in variant: `SortableTagInput` /
417
+ `SortableTagInputCore` and `SortableTagGroup` statically import
418
+ `@dnd-kit/core` / `@dnd-kit/sortable` / `@dnd-kit/utilities` (regular
419
+ dependencies — the plain `TagInput`/`TagGroup` never touch them, so they
420
+ stay out of every bundle that doesn't import a Sortable variant).
421
+ `SortableTagInput` writes the new array through `onChange`;
422
+ `SortableTagGroup` reports `onReorder(nextOrder)` (the new arrangement of
423
+ original child indexes) and leaves re-rendering to the parent. Sorting is
424
+ keyboard-complete: focus a tag, `Space` to lift, arrows to move, `Space`
425
+ to drop, `Escape` to cancel.
406
426
 
407
427
  ## Imperative overlay handles
408
428
 
@@ -456,6 +476,46 @@ not wrapped.
456
476
  }
457
477
  ```
458
478
 
479
+ ## Brand themes: presets, runtime generation, CLI
480
+
481
+ Five preset brand themes ship as complete theme classes — `violetTheme`,
482
+ `tealTheme`, `cyanTheme`, `orangeTheme`, `roseTheme` — each a drop-in
483
+ replacement for `lightTheme`/`darkTheme` with primary/info/focus-ring
484
+ rerouted to the brand's scale.
485
+
486
+ **Runtime custom brands.** `createBrandTheme` (from `haze-ui` or
487
+ `haze-ui/tokens`) runs the exact preset pipeline from your own seed hex:
488
+
489
+ ```ts
490
+ import { createBrandTheme } from 'haze-ui/tokens';
491
+
492
+ const brand = createBrandTheme({
493
+ name: 'acme', // → --haze-acme-1…12 (lowercase kebab; not gray/green/amber/red)
494
+ light: '#0066ff', // light-mode primary seed (scale step 9)
495
+ dark: '#0a3d99', // optional — derived from light (oklch l +0.2) when omitted
496
+ overrides: { light: { 10: '#0052cc' } }, // optional extra anchors
497
+ });
498
+ // brand.light / brand.dark: bare declaration blocks — wrap in classes once:
499
+ // styleEl.textContent = `.acme-light { ${brand.light} }\n.acme-dark { ${brand.dark} }`;
500
+ ```
501
+
502
+ The blocks are theme *replacements* (never stack on `lightTheme`), and you
503
+ own contrast: pick a light seed dark enough for white text — the presets'
504
+ step-9 anchors sit near Tailwind's 600/700 range for that reason.
505
+
506
+ **CLI.** Zero Node dependencies, identical output:
507
+
508
+ ```bash
509
+ npx haze-ui-theme --primary '#0066ff' [--dark '#0a3d99'] [--name brand] [--out brand.css]
510
+ ```
511
+
512
+ **W3C design-token archives.** Every preset is also exported per mode as
513
+ W3C DTF JSON:
514
+
515
+ ```js
516
+ import violetLight from 'haze-ui/design-tokens/violet/light.json';
517
+ ```
518
+
459
519
  ## Component-level tokens
460
520
 
461
521
  Global `--haze-*` tokens theme the whole system; **component-level tokens**
@@ -544,6 +604,52 @@ own css manifest. The same items are also installable straight from this
544
604
  GitHub repository — see
545
605
  [Install via shadcn CLI (GitHub registry)](#install-via-shadcn-cli-github-registry).
546
606
 
607
+ ## AI / MCP
608
+
609
+ **`haze-ui-mcp`** — an [MCP server](https://modelcontextprotocol.io) that puts the
610
+ whole component reference in your AI coding agent's tool belt. It serves the
611
+ same docs the site renders (props tables with types/defaults/descriptions,
612
+ import statements, CSS paths, peer deps, the full token registry), so the
613
+ agent never guesses a prop name or a stylesheet path again:
614
+
615
+ | Tool | What it returns |
616
+ | --- | --- |
617
+ | `haze_list_components` | Every component with its css family |
618
+ | `haze_get_component` | One component's full reference — props tables, import statement, CSS imports. Name matching is case-insensitive and accepts kebab-case (`data-table`) or PascalCase (`DataTable`) |
619
+ | `haze_get_tokens` | The `--haze-*` token registry with light and dark values, optionally filtered by category (`color`, `typography`, `spacing`, `radius`, `shadow`) |
620
+ | `haze_search_docs` | Top-10 ranked matches across component names, css families, prop names and descriptions |
621
+
622
+ **Claude Code**:
623
+
624
+ ```sh
625
+ claude mcp add haze-ui -- npx haze-ui-mcp
626
+ ```
627
+
628
+ **Cursor** (`.cursor/mcp.json`):
629
+
630
+ ```json
631
+ {
632
+ "mcpServers": {
633
+ "haze-ui": {
634
+ "command": "npx",
635
+ "args": ["haze-ui-mcp"]
636
+ }
637
+ }
638
+ }
639
+ ```
640
+
641
+ The server speaks stdio JSON-RPC and ships its own docs snapshot
642
+ (`dist/mcp-docs.json`, regenerated on every build by
643
+ `scripts/generate-mcp-docs.mjs`) — no project access, no indexing on startup.
644
+ In this repository you can run it directly against the local snapshot:
645
+
646
+ ```sh
647
+ node scripts/generate-mcp-docs.mjs
648
+ node mcp/index.mjs
649
+ ```
650
+
651
+ Point it at a custom snapshot with `HAZE_UI_MCP_DOCS=/path/to/mcp-docs.json`.
652
+
547
653
  ## AI runtime integration (Vercel AI SDK `useChat`)
548
654
 
549
655
  haze-ui ships the agent chat surface as **presentational** components —
package/cli/theme.mjs ADDED
@@ -0,0 +1,446 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * haze-ui-theme — generate a complete haze-ui brand theme CSS file from one
4
+ * or two seed hexes, no Node dependencies.
5
+ *
6
+ * node cli/theme.mjs --primary '#0066ff' [--dark '#0a3d99'] [--name brand] [--out brand.css]
7
+ * npx haze-ui-theme --primary '#7c3aed' --name acme
8
+ *
9
+ * The emitted classes (.haze-{name}-light / .haze-{name}-dark) are theme
10
+ * REPLACEMENTS for lightTheme/darkTheme — apply one per subtree, never stack
11
+ * on top of the default theme classes.
12
+ *
13
+ * The color math below is a dependency-free port of src/lib/tokens/oklch.ts
14
+ * + the scale/semantic pipeline of src/lib/tokens/palette.ts (the library
15
+ * source cannot be imported here: this file must also run from an
16
+ * as-yet-unbuilt checkout, and dist/ is not guaranteed to exist). Drift is
17
+ * pinned by src/lib/tokens/brand-theme.test.ts, which asserts this module's
18
+ * output is byte-identical to createBrandTheme() for every preset seed set.
19
+ */
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // OKLCH math — ported from src/lib/tokens/oklch.ts
23
+ // ---------------------------------------------------------------------------
24
+
25
+ const SRGB_LINEAR_CUTOFF = 0.04045;
26
+ const LINEAR_SRGB_CUTOFF = 0.0031308;
27
+ const GAMUT_EPSILON = 1e-5;
28
+
29
+ const srgbToLinear = (channel) =>
30
+ channel <= SRGB_LINEAR_CUTOFF ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);
31
+
32
+ const linearToSrgb = (channel) =>
33
+ channel <= LINEAR_SRGB_CUTOFF ? 12.92 * channel : 1.055 * Math.pow(channel, 1 / 2.4) - 0.055;
34
+
35
+ function linearRgbToOklab({r, g, b}) {
36
+ const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
37
+ const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
38
+ const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
39
+ return {
40
+ L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
41
+ a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
42
+ b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,
43
+ };
44
+ }
45
+
46
+ function oklabToLinearRgb({L, a, b}) {
47
+ const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
48
+ const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
49
+ const s_ = L - 0.0894841775 * a - 1.291485548 * b;
50
+ const l = l_ * l_ * l_;
51
+ const m = m_ * m_ * m_;
52
+ const s = s_ * s_ * s_;
53
+ return {
54
+ r: 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
55
+ g: -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
56
+ b: -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,
57
+ };
58
+ }
59
+
60
+ const lchToLab = ({l, c, h}) => {
61
+ const hue = (h * Math.PI) / 180;
62
+ return {L: l, a: c * Math.cos(hue), b: c * Math.sin(hue)};
63
+ };
64
+
65
+ const labToLch = ({L, a, b}) => {
66
+ const hue = (Math.atan2(b, a) * 180) / Math.PI;
67
+ return {l: L, c: Math.sqrt(a * a + b * b), h: hue < 0 ? hue + 360 : hue};
68
+ };
69
+
70
+ const inGamut = (rgb) =>
71
+ rgb.r >= -GAMUT_EPSILON && rgb.r <= 1 + GAMUT_EPSILON &&
72
+ rgb.g >= -GAMUT_EPSILON && rgb.g <= 1 + GAMUT_EPSILON &&
73
+ rgb.b >= -GAMUT_EPSILON && rgb.b <= 1 + GAMUT_EPSILON;
74
+
75
+ /** Reduce chroma until the color fits the sRGB gamut, preserving lightness and hue exactly. */
76
+ function clampChroma(color) {
77
+ const l = Math.min(1, Math.max(0, color.l));
78
+ const hue = (color.h * Math.PI) / 180;
79
+ let low = 0;
80
+ let high = Math.max(color.c, 0);
81
+ for (let i = 0; i < 20; i++) {
82
+ const mid = (low + high) / 2;
83
+ if (inGamut(oklabToLinearRgb({L: l, a: mid * Math.cos(hue), b: mid * Math.sin(hue)}))) {
84
+ low = mid;
85
+ } else {
86
+ high = mid;
87
+ }
88
+ }
89
+ return color.alpha === undefined ? {l, c: low, h: color.h} : {l, c: low, h: color.h, alpha: color.alpha};
90
+ }
91
+
92
+ /** Parse `#rgb`, `#rgba`, `#rrggbb` or `#rrggbbaa` into OKLCH. */
93
+ function parseHex(hex) {
94
+ const match = /^#([0-9a-f]{3,8})$/i.exec(hex.trim());
95
+ const digits = match?.[1];
96
+ if (digits === undefined || (digits.length !== 3 && digits.length !== 4 && digits.length !== 6 && digits.length !== 8)) {
97
+ throw new Error(`Invalid hex color: ${hex}`);
98
+ }
99
+ const expanded =
100
+ digits.length === 3 || digits.length === 4 ? digits.split('').map((d) => d + d).join('') : digits;
101
+ const alpha = expanded.length === 8 ? parseInt(expanded.slice(6, 8), 16) / 255 : undefined;
102
+ const lch = labToLch(
103
+ linearRgbToOklab({
104
+ r: srgbToLinear(parseInt(expanded.slice(0, 2), 16) / 255),
105
+ g: srgbToLinear(parseInt(expanded.slice(2, 4), 16) / 255),
106
+ b: srgbToLinear(parseInt(expanded.slice(4, 6), 16) / 255),
107
+ }),
108
+ );
109
+ return alpha === undefined ? lch : {...lch, alpha};
110
+ }
111
+
112
+ /** Format as a CSS `oklch()` string: l/c to 3 decimals, h to 1 decimal. */
113
+ const formatOklch = (color) =>
114
+ `oklch(${color.l.toFixed(3)} ${color.c.toFixed(3)} ${color.h.toFixed(1)})`;
115
+
116
+ // ---------------------------------------------------------------------------
117
+ // Palette pipeline — ported from src/lib/tokens/palette.ts
118
+ // ---------------------------------------------------------------------------
119
+
120
+ const MODES = ['light', 'dark'];
121
+
122
+ /** Gray seeds and the text-muted nudge — mirror of SEEDS.gray / TEXT_MUTED_ADJUST. */
123
+ const GRAY_SEEDS = {
124
+ light: {1: '#ffffff', 2: '#f7f8fa', 3: '#eef0f4', 4: '#e0e0e0', 9: '#8a8a8a', 11: '#4a4a4a', 12: '#1a1a1a'},
125
+ dark: {1: '#121212', 2: '#1e1e1e', 3: '#2a2a2a', 4: '#333333', 9: '#707070', 11: '#b0b0b0', 12: '#e8e8e8'},
126
+ };
127
+ /** Success/warning/danger seeds — mirror of SEEDS.green/amber/red (fixed in every theme). */
128
+ const STATUS_SEEDS = {
129
+ green: {light: {9: '#15803d'}, dark: {8: '#22c55e'}},
130
+ amber: {light: {9: '#f59e0b'}, dark: {8: '#fbbf24'}},
131
+ red: {light: {9: '#dc2626'}, dark: {8: '#ef4444'}},
132
+ };
133
+ const TEXT_MUTED_ADJUST = {light: -0.008, dark: 0.014};
134
+
135
+ const CHROMATIC_ENDPOINTS = {
136
+ light: {l1: 0.982, l12: 0.16, c1: 0.018, c12: 0.045},
137
+ dark: {l1: 0.155, l12: 0.982, c1: 0.03, c12: 0.012},
138
+ };
139
+
140
+ /** Piecewise-linear interpolation over sorted points (clamped at both ends). */
141
+ function interpolateAt(points, x) {
142
+ const first = points[0];
143
+ if (x <= first.x) return first.y;
144
+ for (let i = 1; i < points.length; i++) {
145
+ const point = points[i];
146
+ if (x <= point.x) {
147
+ const previous = points[i - 1];
148
+ const t = (x - previous.x) / (point.x - previous.x);
149
+ return previous.y + t * (point.y - previous.y);
150
+ }
151
+ }
152
+ return points[points.length - 1].y;
153
+ }
154
+
155
+ function formatSteps(luminancePoints, chromaAt, hueAt) {
156
+ const steps = [];
157
+ for (let step = 1; step <= 12; step++) {
158
+ steps.push(formatOklch(clampChroma({l: interpolateAt(luminancePoints, step), c: chromaAt(step), h: hueAt(step)})));
159
+ }
160
+ return steps;
161
+ }
162
+
163
+ function grayAnchors(seed, mode) {
164
+ return Object.entries(seed)
165
+ .map(([step, hex]) => {
166
+ const parsed = parseHex(hex);
167
+ const l = Number(step) === 9 ? parsed.l + TEXT_MUTED_ADJUST[mode] : parsed.l;
168
+ return {step: Number(step), color: {l, c: 0, h: 0}};
169
+ })
170
+ .sort((a, b) => a.step - b.step);
171
+ }
172
+
173
+ /** The fixed neutral scales — identical to the default themes' gray family. */
174
+ const GRAY_SCALE = Object.fromEntries(
175
+ MODES.map((mode) => [
176
+ mode,
177
+ formatSteps(grayAnchors(GRAY_SEEDS[mode], mode).map((a) => ({x: a.step, y: a.color.l})), () => 0, () => 0),
178
+ ]),
179
+ );
180
+
181
+ /** The fixed success/warning/danger scales — identical to the default themes'. */
182
+ const STATUS_SCALE = Object.fromEntries(
183
+ ['green', 'amber', 'red'].map((family) => [
184
+ family,
185
+ Object.fromEntries(
186
+ MODES.map((mode) => [
187
+ mode,
188
+ chromaticScaleFromAnchors(
189
+ Object.entries(STATUS_SEEDS[family][mode]).map(([step, hex]) => ({step: Number(step), color: parseHex(hex)})),
190
+ mode,
191
+ ),
192
+ ]),
193
+ ),
194
+ ]),
195
+ );
196
+
197
+ function chromaticScaleFromAnchors(anchors, mode) {
198
+ const endpoints = CHROMATIC_ENDPOINTS[mode];
199
+ const luminancePoints = [{x: 1, y: endpoints.l1}, ...anchors.map((a) => ({x: a.step, y: a.color.l})), {x: 12, y: endpoints.l12}];
200
+ const chromaPoints = [{x: 1, y: endpoints.c1}, ...anchors.map((a) => ({x: a.step, y: a.color.c})), {x: 12, y: endpoints.c12}];
201
+ const huePoints = [
202
+ {x: 1, y: anchors[0].color.h},
203
+ ...anchors.map((a) => ({x: a.step, y: a.color.h})),
204
+ {x: 12, y: anchors[anchors.length - 1].color.h},
205
+ ];
206
+ return formatSteps(luminancePoints, (step) => interpolateAt(chromaPoints, step), (step) => interpolateAt(huePoints, step));
207
+ }
208
+
209
+ // Semantic rerouting — mirror of DEFAULT_STATUS_FAMILY / STATUS_STEP / NEUTRAL_STEP.
210
+ const DEFAULT_STATUS_FAMILY = {primary: 'blue', success: 'green', warning: 'amber', danger: 'red', info: 'blue'};
211
+ const STATUS_STEP = {
212
+ light: {primary: 9, success: 9, warning: 9, danger: 9, info: 10},
213
+ dark: {primary: 9, success: 8, warning: 8, danger: 8, info: 8},
214
+ };
215
+ const NEUTRAL_STEP = {
216
+ bg: 1,
217
+ 'bg-subtle': 2,
218
+ 'bg-muted': 3,
219
+ text: 12,
220
+ 'text-secondary': 11,
221
+ 'text-muted': 9,
222
+ border: 4,
223
+ };
224
+
225
+ // Interaction-state parameters — mirror of DERIVED_PARAMS / FOCUS_RING_ALPHA.
226
+ const DERIVED_PARAMS = {
227
+ light: {hover: -0.045, active: -0.09, borderHover: -0.09, subtleL: 0.945, subtleC: 0.2},
228
+ dark: {hover: 0.05, active: 0.09, borderHover: 0.08, subtleL: 0.26, subtleC: 0.35},
229
+ };
230
+ const FOCUS_RING_ALPHA = 0.4;
231
+
232
+ const primitiveVar = (family, step) => `var(--haze-${family}-${step})`;
233
+ const lightnessCalc = (delta) => `calc(l ${delta < 0 ? '-' : '+'} ${Math.abs(delta)})`;
234
+
235
+ function derivedCss(mode, baseVar, kind) {
236
+ const params = DERIVED_PARAMS[mode];
237
+ switch (kind) {
238
+ case 'hover':
239
+ return `oklch(from ${baseVar} ${lightnessCalc(params.hover)} c h)`;
240
+ case 'active':
241
+ return `oklch(from ${baseVar} ${lightnessCalc(params.active)} c h)`;
242
+ case 'subtle':
243
+ return `oklch(from ${baseVar} ${params.subtleL} calc(c * ${params.subtleC}) h)`;
244
+ case 'border-hover':
245
+ return `oklch(from ${baseVar} ${lightnessCalc(params.borderHover)} c h)`;
246
+ case 'focus-ring':
247
+ return `oklch(from ${baseVar} l c h / ${FOCUS_RING_ALPHA})`;
248
+ }
249
+ }
250
+
251
+ /**
252
+ * The full declaration block one mode of a brand theme carries: primitive
253
+ * scales first (gray/{name}/green/amber/red), then the semantic aliases
254
+ * with primary/info/focus-ring rerouted to the brand family.
255
+ */
256
+ function themeDeclarations(mode, name, brandScale) {
257
+ const primitives = [
258
+ ['gray', GRAY_SCALE[mode]],
259
+ [name, brandScale],
260
+ ['green', STATUS_SCALE.green[mode]],
261
+ ['amber', STATUS_SCALE.amber[mode]],
262
+ ['red', STATUS_SCALE.red[mode]],
263
+ ]
264
+ .map(([family, steps]) => steps.map((value, index) => `--haze-${family}-${index + 1}: ${value};`).join('\n'))
265
+ .join('\n');
266
+ const statusFamily = {...DEFAULT_STATUS_FAMILY, primary: name, info: name};
267
+ const lines = [];
268
+ const statusGroup = (key) => {
269
+ const base = `--haze-color-${key}`;
270
+ const family = statusFamily[key];
271
+ lines.push(`${base}: ${primitiveVar(family, STATUS_STEP[mode][key])};`);
272
+ const baseVar = `var(${base})`;
273
+ lines.push(`${base}-hover: ${derivedCss(mode, baseVar, 'hover')};`);
274
+ lines.push(`${base}-active: ${derivedCss(mode, baseVar, 'active')};`);
275
+ lines.push(`${base}-subtle: ${derivedCss(mode, baseVar, 'subtle')};`);
276
+ };
277
+ const neutral = (key) => lines.push(`--haze-color-${key}: ${primitiveVar('gray', NEUTRAL_STEP[key])};`);
278
+ statusGroup('primary');
279
+ neutral('bg');
280
+ neutral('bg-subtle');
281
+ neutral('bg-muted');
282
+ neutral('text');
283
+ neutral('text-secondary');
284
+ neutral('text-muted');
285
+ lines.push(`--haze-color-text-inverse: ${mode === 'light' ? 'oklch(1 0 0)' : GRAY_SCALE.light[11]};`);
286
+ neutral('border');
287
+ lines.push(`--haze-color-border-hover: ${derivedCss(mode, 'var(--haze-color-border)', 'border-hover')};`);
288
+ statusGroup('success');
289
+ statusGroup('warning');
290
+ statusGroup('danger');
291
+ statusGroup('info');
292
+ lines.push(`--haze-color-focus-ring: ${derivedCss(mode, 'var(--haze-color-primary)', 'focus-ring')};`);
293
+ return `${primitives}\n\n${lines.join('\n')}`;
294
+ }
295
+
296
+ // ---------------------------------------------------------------------------
297
+ // createBrandTheme mirror — identical options/semantics to palette.ts
298
+ // ---------------------------------------------------------------------------
299
+
300
+ const NEUTRAL_FAMILIES = new Set(['gray', 'green', 'amber', 'red']);
301
+ const FAMILY_NAME_RE = /^[a-z][a-z0-9-]*$/;
302
+ const DERIVED_SEED_OFFSETS = {infoStep: -0.07, darkPrimary: 0.2};
303
+
304
+ const clampLightness = (l) => Math.min(1, Math.max(0, l));
305
+ const shiftLightness = (color, delta) => clampChroma({l: clampLightness(color.l + delta), c: color.c, h: color.h});
306
+
307
+ function mergeAnchors(base, seed) {
308
+ const byStep = new Map(base.map((anchor) => [anchor.step, anchor.color]));
309
+ for (const [step, hex] of Object.entries(seed ?? {})) {
310
+ if (Number(step) < 1 || Number(step) > 12) {
311
+ throw new Error(`Seed anchor step ${step} is outside the 1–12 scale`);
312
+ }
313
+ byStep.set(Number(step), parseHex(hex));
314
+ }
315
+ return [...byStep.entries()].map(([step, color]) => ({step, color})).sort((a, b) => a.step - b.step);
316
+ }
317
+
318
+ /**
319
+ * Build a complete brand theme at runtime — mirror of palette.ts's
320
+ * createBrandTheme (byte-identical output; enforced by brand-theme.test.ts).
321
+ *
322
+ * @param {{name?: string, light: string, dark?: string, overrides?: {light?: Record<number, string>, dark?: Record<number, string>}}} options
323
+ * @returns {{name: string, light: string, dark: string}} bare declaration blocks per mode
324
+ */
325
+ export function createBrandThemeCss({name = 'brand', light, dark, overrides} = {}) {
326
+ if (!FAMILY_NAME_RE.test(name)) {
327
+ throw new Error(`Invalid brand name "${name}" — use a lowercase kebab identifier (letters, digits, hyphens)`);
328
+ }
329
+ if (NEUTRAL_FAMILIES.has(name)) {
330
+ throw new Error(`Brand name "${name}" collides with a fixed neutral family (gray/green/amber/red)`);
331
+ }
332
+ const lightPrimary = parseHex(light);
333
+ const darkPrimary = dark === undefined ? shiftLightness(lightPrimary, DERIVED_SEED_OFFSETS.darkPrimary) : parseHex(dark);
334
+ const anchors = {
335
+ light: mergeAnchors(
336
+ [
337
+ {step: 9, color: lightPrimary},
338
+ {step: 10, color: shiftLightness(lightPrimary, DERIVED_SEED_OFFSETS.infoStep)},
339
+ ],
340
+ overrides?.light,
341
+ ),
342
+ dark: mergeAnchors(
343
+ [
344
+ {step: 9, color: darkPrimary},
345
+ {step: 8, color: shiftLightness(darkPrimary, DERIVED_SEED_OFFSETS.infoStep)},
346
+ ],
347
+ overrides?.dark,
348
+ ),
349
+ };
350
+ return {
351
+ name,
352
+ light: themeDeclarations('light', name, chromaticScaleFromAnchors(anchors.light, 'light')),
353
+ dark: themeDeclarations('dark', name, chromaticScaleFromAnchors(anchors.dark, 'dark')),
354
+ };
355
+ }
356
+
357
+ /** Wrap the two declaration blocks into a standalone stylesheet. */
358
+ export function renderStylesheet(theme, {lightSeed, darkSeed}) {
359
+ const header = [
360
+ `/* haze-ui brand theme "${theme.name}" — generated by haze-ui-theme.`,
361
+ ` light seed: ${lightSeed} · dark seed: ${darkSeed}`,
362
+ ' Apply ONE class per subtree as a replacement for lightTheme/darkTheme. */',
363
+ ].join('\n');
364
+ const block = (mode) => `.haze-${theme.name}-${mode} {\n${theme[mode]}\n}`;
365
+ return `${header}\n\n${block('light')}\n\n${block('dark')}\n`;
366
+ }
367
+
368
+ // ---------------------------------------------------------------------------
369
+ // CLI entry
370
+ // ---------------------------------------------------------------------------
371
+
372
+ import {writeFileSync} from 'node:fs';
373
+ import {pathToFileURL} from 'node:url';
374
+
375
+ const USAGE = `Usage: haze-ui-theme --primary <hex> [--dark <hex>] [--name <kebab>] [--out <file>]
376
+
377
+ --primary <hex> Light-mode primary seed, e.g. '#0066ff' (required).
378
+ --dark <hex> Dark-mode primary seed. Omit to derive it from --primary
379
+ (OKLCH lightness +0.2, chroma/hue preserved).
380
+ --name <kebab> Brand family name for the custom properties (default:
381
+ 'brand'). Becomes --haze-<name>-1…12; may not be
382
+ gray/green/amber/red.
383
+ --out <file> Write the stylesheet to <file> instead of stdout.
384
+
385
+ Outputs .haze-<name>-light / .haze-<name>-dark classes carrying the complete
386
+ token set (primitive scales + semantic aliases + relative-color interaction
387
+ states) — use them as replacements for lightTheme/darkTheme.`;
388
+
389
+ function parseArgs(argv) {
390
+ const options = {primary: undefined, dark: undefined, name: 'brand', out: undefined};
391
+ for (let i = 0; i < argv.length; i++) {
392
+ const arg = argv[i];
393
+ const flag = arg.includes('=') ? arg.slice(0, arg.indexOf('=')) : arg;
394
+ const inline = arg.includes('=') ? arg.slice(arg.indexOf('=') + 1) : undefined;
395
+ const value = inline ?? argv[++i];
396
+ if (flag === '--help' || flag === '-h') {
397
+ options.help = true;
398
+ } else if (flag === '--primary') {
399
+ options.primary = value;
400
+ } else if (flag === '--dark') {
401
+ options.dark = value;
402
+ } else if (flag === '--name') {
403
+ options.name = value;
404
+ } else if (flag === '--out') {
405
+ options.out = value;
406
+ } else {
407
+ throw new Error(`Unknown argument: ${arg}\n\n${USAGE}`);
408
+ }
409
+ if (value === undefined && !options.help) {
410
+ throw new Error(`Missing value for ${flag}\n\n${USAGE}`);
411
+ }
412
+ }
413
+ return options;
414
+ }
415
+
416
+ function main(argv) {
417
+ const options = parseArgs(argv);
418
+ if (options.help) {
419
+ process.stdout.write(`${USAGE}\n`);
420
+ return 0;
421
+ }
422
+ if (options.primary === undefined) {
423
+ process.stderr.write(`haze-ui-theme: --primary is required\n\n${USAGE}\n`);
424
+ return 1;
425
+ }
426
+ let theme;
427
+ try {
428
+ theme = createBrandThemeCss({name: options.name, light: options.primary, dark: options.dark});
429
+ } catch (error) {
430
+ process.stderr.write(`haze-ui-theme: ${error instanceof Error ? error.message : error}\n`);
431
+ return 1;
432
+ }
433
+ const css = renderStylesheet(theme, {lightSeed: options.primary, darkSeed: options.dark ?? 'derived (oklch l +0.2)'});
434
+ if (options.out === undefined) {
435
+ process.stdout.write(css);
436
+ return 0;
437
+ }
438
+ writeFileSync(options.out, css);
439
+ process.stdout.write(`haze-ui-theme: wrote ${options.out} (.haze-${options.name}-light / .haze-${options.name}-dark)\n`);
440
+ return 0;
441
+ }
442
+
443
+ // Run as a script; importable as a module when executed by the parity test.
444
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
445
+ process.exit(main(process.argv.slice(2)));
446
+ }
@@ -7,6 +7,7 @@ import { jsx as t } from "react/jsx-runtime";
7
7
  var n = "haze-Accordion__base";
8
8
  function r({ className: r, children: i }) {
9
9
  return /* @__PURE__ */ t("div", {
10
+ "data-slot": "accordion",
10
11
  className: e([n, r]),
11
12
  children: i
12
13
  });
@@ -7,12 +7,15 @@ import { jsx as t, jsxs as n } from "react/jsx-runtime";
7
7
  var r = "haze-AccordionItem__item", i = "haze-AccordionItem__summary", a = "haze-AccordionItem__content";
8
8
  function o({ title: o, className: s, children: c }) {
9
9
  return /* @__PURE__ */ n("details", {
10
+ "data-slot": "accordion-item",
10
11
  name: "accordion",
11
12
  className: e([r, s]),
12
13
  children: [/* @__PURE__ */ t("summary", {
14
+ "data-slot": "header",
13
15
  className: i,
14
16
  children: o
15
17
  }), /* @__PURE__ */ t("div", {
18
+ "data-slot": "content",
16
19
  className: a,
17
20
  children: c
18
21
  })]