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.
- package/README.md +139 -33
- package/cli/theme.mjs +446 -0
- package/dist/components/Accordion/Accordion.js +1 -0
- package/dist/components/Accordion/AccordionItem.js +3 -0
- package/dist/components/Affix/Affix.js +1 -0
- package/dist/components/Alert/Alert.js +3 -0
- package/dist/components/Anchor/Anchor.js +21 -15
- package/dist/components/AppShell/AppShell.js +5 -0
- package/dist/components/ApprovalCard/ApprovalCard.js +8 -0
- package/dist/components/AspectRatio/AspectRatio.js +2 -0
- package/dist/components/AsyncSection/AsyncSection.js +8 -0
- package/dist/components/Avatar/Avatar.js +11 -6
- package/dist/components/AvatarGroup/AvatarGroup.js +9 -6
- package/dist/components/BackToTop/BackToTop.js +5 -4
- package/dist/components/Badge/Badge.js +1 -0
- package/dist/components/Banner/Banner.js +3 -0
- package/dist/components/BottomSheet/BottomSheet.js +21 -16
- package/dist/components/Breadcrumb/Breadcrumb.js +11 -7
- package/dist/components/Breadcrumb/BreadcrumbItem.js +2 -0
- package/dist/components/Button/Button.js +13 -11
- package/dist/components/Button/ButtonLink.js +15 -13
- package/dist/components/Calendar/Calendar.js +523 -368
- package/dist/components/Calendar/date.js +35 -10
- package/dist/components/Card/Card.js +1 -0
- package/dist/components/Carousel/Carousel.js +157 -60
- package/dist/components/Carousel/CarouselSlide.js +3 -1
- package/dist/components/Cascader/Cascader.js +48 -35
- package/dist/components/Chart/Chart.js +5 -4
- package/dist/components/Chart/chart-elements.js +117 -52
- package/dist/components/ChatContainer/ChatContainer.js +9 -7
- package/dist/components/ChatInput/ChatInput.js +12 -9
- package/dist/components/ChatMessage/ChatMessage.js +83 -44
- package/dist/components/Checkbox/CheckboxCore.js +2 -0
- package/dist/components/Chip/Chip.js +3 -0
- package/dist/components/CodeBlock/CodeBlock.js +18 -9
- package/dist/components/Collapsible/Collapsible.js +24 -21
- package/dist/components/ColorPicker/ColorPicker.js +85 -14
- package/dist/components/ColorPicker/ColorPickerCore.js +6 -0
- package/dist/components/ColorPicker/ColorPickerPanel.js +277 -0
- package/dist/components/ColorPicker/color-math.js +168 -0
- package/dist/components/ColorPicker/color-picker-styles.js +7 -0
- package/dist/components/ColorPicker/index.js +3 -3
- package/dist/components/Combobox/Combobox.js +31 -24
- package/dist/components/Combobox/ComboboxGroup.js +7 -5
- package/dist/components/Combobox/ComboboxOption.js +1 -0
- package/dist/components/Command/Command.js +44 -37
- package/dist/components/Command/CommandDialog.js +8 -8
- package/dist/components/ConfigProvider/ConfigContext.js +30 -0
- package/dist/components/ConfigProvider/ConfigProvider.js +14 -0
- package/dist/components/ConfigProvider/index.js +4 -0
- package/dist/components/ConfigProvider/useConfigDefaults.js +10 -0
- package/dist/components/ConfirmDialog/ConfirmDialog.js +18 -11
- package/dist/components/Container/Container.js +1 -0
- package/dist/components/ContextMenu/ContextMenu.js +7 -6
- package/dist/components/ContextMenu/ContextMenuContent.js +4 -4
- package/dist/components/ContextMenu/ContextMenuItem.js +1 -0
- package/dist/components/ContextMenu/ContextMenuSeparator.js +1 -0
- package/dist/components/ContextMenu/ContextMenuTrigger.js +1 -0
- package/dist/components/ConversationList/ConversationItem.js +4 -0
- package/dist/components/ConversationList/ConversationList.js +1 -0
- package/dist/components/CountUp/CountUp.js +46 -0
- package/dist/components/CountUp/index.js +3 -0
- package/dist/components/DataTable/CellEditor.js +4 -4
- package/dist/components/DataTable/DataTable.js +236 -168
- package/dist/components/DateRangePicker/DateRangePickerCore.js +9 -0
- package/dist/components/Datepicker/Datepicker.js +14 -11
- package/dist/components/Datepicker/DatepickerCore.js +75 -60
- package/dist/components/Datepicker/datetime.js +14 -3
- package/dist/components/Descriptions/Descriptions.js +6 -0
- package/dist/components/Dialog/Dialog.js +13 -11
- package/dist/components/DiffViewer/DiffViewer.js +22 -13
- package/dist/components/Disclosure/Disclosure.js +10 -7
- package/dist/components/Divider/Divider.js +2 -0
- package/dist/components/Drawer/Drawer.js +10 -9
- package/dist/components/DropdownMenu/DropdownMenu.js +58 -35
- package/dist/components/DropdownMenu/DropdownMenuCheckboxItem.js +63 -0
- package/dist/components/DropdownMenu/DropdownMenuContent.js +5 -5
- package/dist/components/DropdownMenu/DropdownMenuGroup.js +26 -0
- package/dist/components/DropdownMenu/DropdownMenuItem.js +29 -10
- package/dist/components/DropdownMenu/DropdownMenuRadioGroup.js +30 -0
- package/dist/components/DropdownMenu/DropdownMenuRadioItem.js +59 -0
- package/dist/components/DropdownMenu/DropdownMenuSeparator.js +1 -0
- package/dist/components/DropdownMenu/DropdownMenuSub.js +1 -0
- package/dist/components/DropdownMenu/DropdownMenuSubTrigger.js +1 -0
- package/dist/components/DropdownMenu/DropdownMenuTrigger.js +1 -0
- package/dist/components/DropdownMenu/dropdown-menu-item-styles.js +7 -0
- package/dist/components/DropdownMenu/index.js +12 -8
- package/dist/components/Ellipsis/Ellipsis.js +56 -0
- package/dist/components/Ellipsis/index.js +3 -0
- package/dist/components/Empty/Empty.js +4 -0
- package/dist/components/FileInput/FileInput.js +7 -5
- package/dist/components/FilePreview/FilePreview.js +19 -1
- package/dist/components/Flex/Flex.js +1 -0
- package/dist/components/FloatButton/FloatButton.js +4 -0
- package/dist/components/FloatButton/FloatButtonGroup.js +18 -13
- package/dist/components/Fullscreen/Fullscreen.js +6 -3
- package/dist/components/Grid/Grid.js +12 -7
- package/dist/components/Grid/GridItem.js +17 -7
- package/dist/components/Grid/grid-item-styles.js +58 -0
- package/dist/components/HoverCard/HoverCard.js +46 -43
- package/dist/components/Icon/Icon.js +1 -0
- package/dist/components/Image/Image.js +10 -7
- package/dist/components/Image/ImagePreview.js +42 -34
- package/dist/components/InlineCompletion/InlineCompletion.js +15 -11
- package/dist/components/InlineEdit/InlineEdit.js +8 -6
- package/dist/components/Input/InputCore.js +1 -0
- package/dist/components/JsonView/JsonView.js +104 -79
- package/dist/components/Kbd/Kbd.js +1 -0
- package/dist/components/List/List.js +1 -0
- package/dist/components/List/ListItem.js +1 -0
- package/dist/components/LocaleProvider/LocaleProvider.js +4 -4
- package/dist/components/LocaleProvider/ar-sa.js +255 -0
- package/dist/components/LocaleProvider/de-de.js +255 -0
- package/dist/components/LocaleProvider/es-es.js +255 -0
- package/dist/components/LocaleProvider/fr-fr.js +255 -0
- package/dist/components/LocaleProvider/index.js +10 -2
- package/dist/components/LocaleProvider/it-it.js +255 -0
- package/dist/components/LocaleProvider/ja-jp.js +35 -2
- package/dist/components/LocaleProvider/ko-kr.js +255 -0
- package/dist/components/LocaleProvider/locale.js +35 -2
- package/dist/components/LocaleProvider/pt-br.js +255 -0
- package/dist/components/LocaleProvider/ru-ru.js +255 -0
- package/dist/components/LocaleProvider/zh-cn.js +35 -2
- package/dist/components/LogViewer/LogViewer.js +25 -14
- package/dist/components/MarkdownRenderer/MarkdownRenderer.js +6 -5
- package/dist/components/MarkdownRenderer/markdown-blocks.js +1 -1
- package/dist/components/Masonry/Masonry.js +13 -10
- package/dist/components/Mentions/MentionsCore.js +15 -11
- package/dist/components/Menu/Menu.js +58 -36
- package/dist/components/Menu/MenuCheckboxItem.js +63 -0
- package/dist/components/Menu/MenuDivider.js +1 -0
- package/dist/components/Menu/MenuGroup.js +26 -0
- package/dist/components/Menu/MenuItem.js +28 -9
- package/dist/components/Menu/MenuRadioGroup.js +30 -0
- package/dist/components/Menu/MenuRadioItem.js +59 -0
- package/dist/components/Menu/MenuSub.js +1 -0
- package/dist/components/Menu/MenuSubTrigger.js +1 -0
- package/dist/components/Menu/index.js +11 -7
- package/dist/components/Menu/menu-item-styles.js +7 -0
- package/dist/components/ModelPicker/ModelPicker.js +3 -0
- package/dist/components/NavigationBar/NavLink.js +7 -6
- package/dist/components/NavigationBar/NavigationBar.js +4 -0
- package/dist/components/NumberInput/NumberInputCore.js +4 -0
- package/dist/components/OTPInput/OTPInputCore.js +9 -7
- package/dist/components/Pagination/Pagination.js +125 -33
- package/dist/components/PasswordInput/PasswordInputCore.js +9 -6
- package/dist/components/Popover/Popover.js +9 -7
- package/dist/components/Progress/Progress.js +5 -0
- package/dist/components/PromptInput/PromptInput.js +49 -41
- package/dist/components/QRCode/QRCode.js +45 -0
- package/dist/components/QRCode/index.js +3 -0
- package/dist/components/Radio/Radio.js +2 -0
- package/dist/components/Radio/RadioGroupCore.js +7 -6
- package/dist/components/Rating/RatingCore.js +18 -15
- package/dist/components/Resizable/Resizable.js +25 -22
- package/dist/components/Result/Result.js +234 -0
- package/dist/components/Result/index.js +3 -0
- package/dist/components/ScrollArea/ScrollArea.js +1 -0
- package/dist/components/Segmented/SegmentedCore.js +9 -7
- package/dist/components/Select/Option.js +1 -0
- package/dist/components/Select/OptionGroup.js +1 -0
- package/dist/components/Select/SelectCore.js +11 -8
- package/dist/components/Select/SelectFloating.js +54 -36
- package/dist/components/Sidebar/Sidebar.js +52 -42
- package/dist/components/Signature/Signature.js +101 -91
- package/dist/components/Skeleton/Skeleton.js +1 -0
- package/dist/components/Slider/SliderCore.js +149 -43
- package/dist/components/Sources/Sources.js +31 -21
- package/dist/components/Spinner/Spinner.js +1 -0
- package/dist/components/Stat/Stat.js +7 -0
- package/dist/components/StepTimeline/StepTimeline.js +6 -0
- package/dist/components/Stepper/Step.js +8 -1
- package/dist/components/Stepper/Stepper.js +7 -6
- package/dist/components/StreamingText/StreamingText.js +62 -29
- package/dist/components/SwipeAction/SwipeAction.js +11 -9
- package/dist/components/Switch/SwitchCore.js +9 -5
- package/dist/components/Table/Table.js +2 -0
- package/dist/components/Table/TableBody.js +1 -0
- package/dist/components/Table/TableCell.js +1 -0
- package/dist/components/Table/TableHead.js +1 -0
- package/dist/components/Table/TableRow.js +1 -0
- package/dist/components/Tabs/Tab.js +1 -0
- package/dist/components/Tabs/TabList.js +5 -4
- package/dist/components/Tabs/TabPanel.js +1 -0
- package/dist/components/Tabs/Tabs.js +1 -0
- package/dist/components/Tag/Tag.js +2 -0
- package/dist/components/TagGroup/SortableTagGroup.js +7 -6
- package/dist/components/TagGroup/TagGroup.js +1 -0
- package/dist/components/TagGroup/TagGroupItem.js +3 -0
- package/dist/components/TagInput/SortableTagInputCore.js +13 -10
- package/dist/components/TagInput/TagInputCore.js +17 -12
- package/dist/components/Textarea/TextareaCore.js +1 -0
- package/dist/components/ThinkingIndicator/ThinkingIndicator.js +18 -4
- package/dist/components/TimePicker/TimePicker.js +30 -14
- package/dist/components/TimePicker/TimePickerCore.js +1 -0
- package/dist/components/TimePicker/TimePickerPanel.js +260 -0
- package/dist/components/TimePicker/time-picker-styles.js +7 -0
- package/dist/components/TimePicker/time.js +51 -0
- package/dist/components/Timeline/Timeline.js +14 -1
- package/dist/components/Toast/Toast.js +94 -48
- package/dist/components/Toast/ToastContainer.js +60 -56
- package/dist/components/Toast/ToastContext.js +3 -1
- package/dist/components/Toast/toast2.js +20 -14
- package/dist/components/Toast/useToast.js +36 -11
- package/dist/components/Toggle/ToggleCore.js +1 -0
- package/dist/components/TokenCounter/TokenCounter.js +8 -1
- package/dist/components/ToolCallCard/ToolCallCard.js +18 -2
- package/dist/components/Toolbar/Toolbar.js +9 -8
- package/dist/components/Toolbar/ToolbarButton.js +1 -0
- package/dist/components/Toolbar/ToolbarSeparator.js +1 -0
- package/dist/components/Toolbar/ToolbarToggle.js +1 -0
- package/dist/components/Tooltip/Tooltip.js +46 -42
- package/dist/components/Tour/Tour.js +76 -65
- package/dist/components/Transfer/TransferCore.js +31 -17
- package/dist/components/Tree/SortableTree.js +151 -0
- package/dist/components/Tree/Tree.js +163 -154
- package/dist/components/Tree/TreeItem.js +52 -39
- package/dist/components/Tree/index.js +2 -1
- package/dist/components/Tree/sortable-tree-styles.js +7 -0
- package/dist/components/Tree/sortable-tree-utils.js +36 -0
- package/dist/components/TreeSelect/TreeSelect.js +240 -0
- package/dist/components/TreeSelect/index.js +3 -0
- package/dist/components/Typography/Typography.js +42 -12
- package/dist/components/Upload/Upload.js +12 -11
- package/dist/components/Upload/UploadCore.js +92 -65
- package/dist/components/Upload/UploadList.js +177 -105
- package/dist/components/VirtualList/VirtualList.js +229 -124
- package/dist/components/Watermark/Watermark.js +8 -6
- package/dist/css/accordion.css +1 -1
- package/dist/css/alert.css +1 -1
- package/dist/css/async-section.css +1 -1
- package/dist/css/banner.css +1 -1
- package/dist/css/bottom-sheet.css +1 -1
- package/dist/css/button.css +2 -2
- package/dist/css/calendar.css +1 -1
- package/dist/css/carousel.css +1 -1
- package/dist/css/chat-message.css +1 -1
- package/dist/css/checkbox.css +1 -1
- package/dist/css/color-picker.css +2 -0
- package/dist/css/combobox.css +2 -2
- package/dist/css/context-menu.css +1 -1
- package/dist/css/count-up.css +2 -0
- package/dist/css/dialog.css +1 -1
- package/dist/css/drawer.css +1 -1
- package/dist/css/dropdown-menu.css +7 -2
- package/dist/css/ellipsis.css +2 -0
- package/dist/css/form.css +1 -1
- package/dist/css/grid.css +2 -1
- package/dist/css/hover-card.css +1 -1
- package/dist/css/input.css +1 -1
- package/dist/css/menu.css +9 -4
- package/dist/css/pagination.css +1 -1
- package/dist/css/popover.css +1 -1
- package/dist/css/progress.css +1 -1
- package/dist/css/qr-code.css +2 -0
- package/dist/css/radio.css +1 -1
- package/dist/css/rating.css +1 -1
- package/dist/css/result.css +2 -0
- package/dist/css/segmented.css +1 -1
- package/dist/css/skeleton.css +1 -1
- package/dist/css/slider.css +1 -1
- package/dist/css/spinner.css +1 -1
- package/dist/css/stepper.css +1 -1
- package/dist/css/streaming-text.css +1 -1
- package/dist/css/switch.css +1 -1
- package/dist/css/tabs.css +1 -1
- package/dist/css/textarea.css +1 -1
- package/dist/css/thinking-indicator.css +1 -1
- package/dist/css/time-picker.css +1 -0
- package/dist/css/toast.css +1 -1
- package/dist/css/toggle.css +1 -1
- package/dist/css/tokens.css +4 -2
- package/dist/css/tooltip.css +1 -1
- package/dist/css/tree-select.css +3 -0
- package/dist/css/tree.css +2 -1
- package/dist/css/typography.css +1 -1
- package/dist/css/upload.css +1 -1
- package/dist/css/virtual-list.css +1 -1
- package/dist/css-manifest.json +41 -0
- package/dist/dates/adapter.js +13 -0
- package/dist/dates/gregory.js +44 -0
- package/dist/dates/islamic.js +87 -0
- package/dist/dates/registry.js +13 -0
- package/dist/dates/timezone.js +29 -0
- package/dist/design-tokens/cyan-dark.json +355 -0
- package/dist/design-tokens/cyan-light.json +355 -0
- package/dist/design-tokens/dark.json +355 -0
- package/dist/design-tokens/light.json +355 -0
- package/dist/design-tokens/orange-dark.json +355 -0
- package/dist/design-tokens/orange-light.json +355 -0
- package/dist/design-tokens/rose-dark.json +355 -0
- package/dist/design-tokens/rose-light.json +355 -0
- package/dist/design-tokens/teal-dark.json +355 -0
- package/dist/design-tokens/teal-light.json +355 -0
- package/dist/design-tokens/violet-dark.json +355 -0
- package/dist/design-tokens/violet-light.json +355 -0
- package/dist/form/FormItem.js +71 -63
- package/dist/form/FormList.js +6 -6
- package/dist/form/form-item-styles.js +7 -0
- package/dist/haze-ui.css +73 -50
- package/dist/index.js +250 -218
- package/dist/mcp-docs.json +10312 -0
- package/dist/registry.json +144 -42
- package/dist/tokens/brands.js +21 -0
- package/dist/tokens/density.js +6 -0
- package/dist/tokens/index.js +7 -6
- package/dist/tokens/motion.js +9 -2
- package/dist/tokens/palette.js +256 -88
- package/dist/tokens/registry.js +18 -22
- package/dist/types/components/Button/Button.d.ts +1 -1
- package/dist/types/components/Calendar/Calendar.d.ts +39 -14
- package/dist/types/components/Calendar/date.d.ts +51 -0
- package/dist/types/components/Calendar/index.d.ts +1 -1
- package/dist/types/components/Carousel/Carousel.d.ts +5 -1
- package/dist/types/components/Carousel/CarouselSlide.d.ts +3 -3
- package/dist/types/components/Chart/Chart.d.ts +24 -13
- package/dist/types/components/Chart/chart-elements.d.ts +39 -10
- package/dist/types/components/ChatMessage/ChatMessage.d.ts +10 -1
- package/dist/types/components/ColorPicker/ColorPicker.d.ts +44 -5
- package/dist/types/components/ColorPicker/ColorPickerPanel.d.ts +28 -0
- package/dist/types/components/ColorPicker/color-math.d.ts +63 -0
- package/dist/types/components/ColorPicker/color-picker-styles.d.ts +50 -0
- package/dist/types/components/ConfigProvider/ConfigContext.d.ts +67 -0
- package/dist/types/components/ConfigProvider/ConfigProvider.d.ts +25 -0
- package/dist/types/components/ConfigProvider/index.d.ts +4 -0
- package/dist/types/components/ConfigProvider/useConfigDefaults.d.ts +28 -0
- package/dist/types/components/CountUp/CountUp.d.ts +20 -0
- package/dist/types/components/CountUp/index.d.ts +2 -0
- package/dist/types/components/Datepicker/Datepicker.d.ts +23 -10
- package/dist/types/components/Datepicker/DatepickerCore.d.ts +40 -10
- package/dist/types/components/Datepicker/datetime.d.ts +33 -11
- package/dist/types/components/DropdownMenu/DropdownMenu.d.ts +12 -2
- package/dist/types/components/DropdownMenu/DropdownMenuCheckboxItem.d.ts +26 -0
- package/dist/types/components/DropdownMenu/DropdownMenuGroup.d.ts +16 -0
- package/dist/types/components/DropdownMenu/DropdownMenuItem.d.ts +7 -1
- package/dist/types/components/DropdownMenu/DropdownMenuRadioGroup.d.ts +21 -0
- package/dist/types/components/DropdownMenu/DropdownMenuRadioItem.d.ts +22 -0
- package/dist/types/components/DropdownMenu/dropdown-menu-item-styles.d.ts +29 -0
- package/dist/types/components/DropdownMenu/index.d.ts +9 -1
- package/dist/types/components/Ellipsis/Ellipsis.d.ts +19 -0
- package/dist/types/components/Ellipsis/index.d.ts +2 -0
- package/dist/types/components/Fullscreen/Fullscreen.d.ts +1 -0
- package/dist/types/components/Grid/Grid.d.ts +8 -1
- package/dist/types/components/Grid/GridItem.d.ts +24 -1
- package/dist/types/components/Grid/grid-item-styles.d.ts +57 -0
- package/dist/types/components/HoverCard/HoverCard.d.ts +1 -1
- package/dist/types/components/LocaleProvider/ar-sa.d.ts +22 -0
- package/dist/types/components/LocaleProvider/de-de.d.ts +15 -0
- package/dist/types/components/LocaleProvider/es-es.d.ts +15 -0
- package/dist/types/components/LocaleProvider/fr-fr.d.ts +15 -0
- package/dist/types/components/LocaleProvider/index.d.ts +8 -0
- package/dist/types/components/LocaleProvider/it-it.d.ts +15 -0
- package/dist/types/components/LocaleProvider/ko-kr.d.ts +15 -0
- package/dist/types/components/LocaleProvider/locale.d.ts +35 -0
- package/dist/types/components/LocaleProvider/pt-br.d.ts +16 -0
- package/dist/types/components/LocaleProvider/ru-ru.d.ts +15 -0
- package/dist/types/components/Menu/Menu.d.ts +11 -2
- package/dist/types/components/Menu/MenuCheckboxItem.d.ts +25 -0
- package/dist/types/components/Menu/MenuGroup.d.ts +16 -0
- package/dist/types/components/Menu/MenuItem.d.ts +7 -1
- package/dist/types/components/Menu/MenuRadioGroup.d.ts +20 -0
- package/dist/types/components/Menu/MenuRadioItem.d.ts +22 -0
- package/dist/types/components/Menu/index.d.ts +9 -1
- package/dist/types/components/Menu/menu-item-styles.d.ts +28 -0
- package/dist/types/components/NavigationBar/NavLink.d.ts +1 -1
- package/dist/types/components/Pagination/Pagination.d.ts +17 -3
- package/dist/types/components/QRCode/QRCode.d.ts +33 -0
- package/dist/types/components/QRCode/index.d.ts +2 -0
- package/dist/types/components/Result/Result.d.ts +16 -0
- package/dist/types/components/Result/index.d.ts +2 -0
- package/dist/types/components/Sidebar/Sidebar.d.ts +1 -1
- package/dist/types/components/Slider/Slider.d.ts +24 -2
- package/dist/types/components/Slider/SliderCore.d.ts +41 -3
- package/dist/types/components/StreamingText/StreamingText.d.ts +8 -1
- package/dist/types/components/TagGroup/SortableTagGroup.d.ts +3 -2
- package/dist/types/components/TagGroup/TagGroup.d.ts +1 -1
- package/dist/types/components/TagInput/SortableTagInput.d.ts +2 -3
- package/dist/types/components/TagInput/SortableTagInputCore.d.ts +3 -3
- package/dist/types/components/TimePicker/TimePicker.d.ts +36 -4
- package/dist/types/components/TimePicker/TimePickerPanel.d.ts +26 -0
- package/dist/types/components/TimePicker/index.d.ts +1 -0
- package/dist/types/components/TimePicker/time-picker-styles.d.ts +30 -0
- package/dist/types/components/TimePicker/time.d.ts +49 -0
- package/dist/types/components/Toast/Toast.d.ts +19 -6
- package/dist/types/components/Toast/ToastContainer.d.ts +1 -1
- package/dist/types/components/Toast/ToastContext.d.ts +22 -2
- package/dist/types/components/Toast/index.d.ts +1 -1
- package/dist/types/components/Toast/toast.d.ts +20 -14
- package/dist/types/components/Toast/useToast.d.ts +14 -4
- package/dist/types/components/Tooltip/Tooltip.d.ts +1 -1
- package/dist/types/components/Tree/SortableTree.d.ts +38 -0
- package/dist/types/components/Tree/Tree.d.ts +1 -1
- package/dist/types/components/Tree/index.d.ts +2 -0
- package/dist/types/components/Tree/sortable-tree-styles.d.ts +36 -0
- package/dist/types/components/Tree/sortable-tree-utils.d.ts +40 -0
- package/dist/types/components/TreeSelect/TreeSelect.d.ts +93 -0
- package/dist/types/components/TreeSelect/index.d.ts +2 -0
- package/dist/types/components/Typography/Typography.d.ts +12 -3
- package/dist/types/components/Typography/index.d.ts +1 -1
- package/dist/types/components/Upload/Upload.d.ts +17 -10
- package/dist/types/components/Upload/UploadCore.d.ts +26 -12
- package/dist/types/components/Upload/UploadList.d.ts +10 -7
- package/dist/types/components/Upload/index.d.ts +1 -1
- package/dist/types/components/Upload/types.d.ts +33 -7
- package/dist/types/components/VirtualList/VirtualList.d.ts +79 -26
- package/dist/types/components/VirtualList/index.d.ts +1 -1
- package/dist/types/dates/adapter.d.ts +74 -0
- package/dist/types/dates/gregory.d.ts +10 -0
- package/dist/types/dates/index.d.ts +6 -0
- package/dist/types/dates/islamic.d.ts +17 -0
- package/dist/types/dates/registry.d.ts +13 -0
- package/dist/types/dates/timezone.d.ts +36 -0
- package/dist/types/form/FormItem.d.ts +31 -1
- package/dist/types/form/form-item-styles.d.ts +24 -0
- package/dist/types/index.d.ts +34 -13
- package/dist/types/tokens/brands.d.ts +28 -0
- package/dist/types/tokens/density.d.ts +3 -0
- package/dist/types/tokens/index.d.ts +5 -2
- package/dist/types/tokens/motion.d.ts +16 -0
- package/dist/types/tokens/palette.d.ts +95 -1
- package/dist/types/tokens/spacing.d.ts +13 -0
- package/dist/types/utils/menuItems.d.ts +126 -0
- package/dist/types/utils/menuRadio.d.ts +21 -0
- package/dist/types/utils/sortable-shared.d.ts +4 -4
- package/dist/utils/floating.js +45 -44
- package/dist/utils/menuItems.js +55 -0
- package/dist/utils/menuKeyboard.js +31 -31
- package/dist/utils/menuRadio.js +28 -0
- package/dist/utils/sortable-shared.js +3 -3
- package/dist/utils/sortable.js +12 -11
- package/mcp/index.mjs +64 -0
- package/mcp/server.mjs +89 -0
- package/mcp/server.test.mjs +281 -0
- package/mcp/tools.mjs +240 -0
- 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
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
Vite, webpack, Turbopack, Rollup)
|
|
150
|
-
|
|
151
|
-
'haze-ui'`
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
`haze-ui/components/DataTable` and
|
|
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
|
|
414
|
+
## Sortable tags and chips
|
|
397
415
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
`@dnd-kit/
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
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,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
|
})]
|