haze-ui 1.29.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 +58 -0
- 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 +14 -10
- 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 +6 -5
- 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 +11 -8
- 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 +24 -2
- package/dist/components/LocaleProvider/de-de.js +24 -2
- package/dist/components/LocaleProvider/es-es.js +24 -2
- package/dist/components/LocaleProvider/fr-fr.js +24 -2
- package/dist/components/LocaleProvider/it-it.js +24 -2
- package/dist/components/LocaleProvider/ja-jp.js +24 -2
- package/dist/components/LocaleProvider/ko-kr.js +24 -2
- package/dist/components/LocaleProvider/locale.js +24 -2
- package/dist/components/LocaleProvider/pt-br.js +24 -2
- package/dist/components/LocaleProvider/ru-ru.js +24 -2
- package/dist/components/LocaleProvider/zh-cn.js +24 -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 +9 -7
- 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 +5 -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 +44 -34
- package/dist/components/Typography/Typography.js +3 -0
- 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/dialog.css +1 -1
- package/dist/css/drawer.css +1 -1
- package/dist/css/dropdown-menu.css +7 -2
- 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/radio.css +1 -1
- package/dist/css/rating.css +1 -1
- 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 +1 -1
- package/dist/css/tooltip.css +1 -1
- package/dist/css/tree.css +2 -1
- package/dist/css/upload.css +1 -1
- package/dist/css/virtual-list.css +1 -1
- package/dist/css-manifest.json +22 -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/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 +63 -48
- package/dist/index.js +249 -232
- package/dist/mcp-docs.json +1011 -82
- package/dist/registry.json +17 -17
- package/dist/tokens/index.js +7 -7
- package/dist/tokens/motion.js +9 -2
- package/dist/tokens/palette.js +244 -84
- 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 +13 -6
- package/dist/types/components/Chart/chart-elements.d.ts +27 -6
- 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/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/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/locale.d.ts +24 -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/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/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/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 +19 -11
- package/dist/types/tokens/index.d.ts +4 -2
- package/dist/types/tokens/motion.d.ts +16 -0
- package/dist/types/tokens/palette.d.ts +59 -2
- package/dist/types/utils/menuItems.d.ts +126 -0
- package/dist/types/utils/menuRadio.d.ts +21 -0
- 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/package.json +18 -9
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
|
|
@@ -458,6 +476,46 @@ not wrapped.
|
|
|
458
476
|
}
|
|
459
477
|
```
|
|
460
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
|
+
|
|
461
519
|
## Component-level tokens
|
|
462
520
|
|
|
463
521
|
Global `--haze-*` tokens theme the whole system; **component-level tokens**
|
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
|
})]
|
|
@@ -8,6 +8,7 @@ var n = "haze-Affix__affix", r = "haze-Affix__posTop", i = "haze-Affix__posBotto
|
|
|
8
8
|
function a({ position: a = "top", offset: o = 0, children: s, className: c, style: l }) {
|
|
9
9
|
let u = a === "top" ? r : i;
|
|
10
10
|
return /* @__PURE__ */ t("div", {
|
|
11
|
+
"data-slot": "affix",
|
|
11
12
|
style: {
|
|
12
13
|
...a === "top" ? { top: o } : { bottom: o },
|
|
13
14
|
...l
|
|
@@ -16,16 +16,19 @@ function l({ visible: l, onClose: u, variant: d = "info", closable: f = !1, clas
|
|
|
16
16
|
let [h, g] = i(l, !0), _ = t("alert");
|
|
17
17
|
return h ? /* @__PURE__ */ r("div", {
|
|
18
18
|
role: "alert",
|
|
19
|
+
"data-slot": "alert",
|
|
19
20
|
className: e([
|
|
20
21
|
a,
|
|
21
22
|
o[d],
|
|
22
23
|
p
|
|
23
24
|
]),
|
|
24
25
|
children: [/* @__PURE__ */ n("div", {
|
|
26
|
+
"data-slot": "content",
|
|
25
27
|
className: s,
|
|
26
28
|
children: m
|
|
27
29
|
}), f && /* @__PURE__ */ n("button", {
|
|
28
30
|
type: "button",
|
|
31
|
+
"data-slot": "close",
|
|
29
32
|
className: c,
|
|
30
33
|
"aria-label": _.close,
|
|
31
34
|
onClick: () => {
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"use client";
|
|
3
3
|
import { classnames as e } from "../../utils/classnames.js";
|
|
4
4
|
/* empty css */
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { useEffect as t } from "react";
|
|
6
|
+
import { jsx as n } from "react/jsx-runtime";
|
|
7
7
|
import { useControl as r } from "react-use-control";
|
|
8
8
|
//#region src/lib/components/Anchor/Anchor.tsx
|
|
9
9
|
var i = "haze-Anchor__nav", a = "haze-Anchor__list", o = "haze-Anchor__link", s = "haze-Anchor__linkActive";
|
|
@@ -21,7 +21,7 @@ function c({ items: c, activeId: l, onClick: u, offsetTop: d = 0, bounds: f = 5,
|
|
|
21
21
|
behavior: "smooth"
|
|
22
22
|
});
|
|
23
23
|
};
|
|
24
|
-
return
|
|
24
|
+
return t(() => {
|
|
25
25
|
if (typeof IntersectionObserver > "u") return;
|
|
26
26
|
let e = /* @__PURE__ */ new Set(), t = p?.() ?? window, n = new IntersectionObserver((t) => {
|
|
27
27
|
for (let n of t) n.isIntersecting ? e.add(n.target.id) : e.delete(n.target.id);
|
|
@@ -41,7 +41,7 @@ function c({ items: c, activeId: l, onClick: u, offsetTop: d = 0, bounds: f = 5,
|
|
|
41
41
|
d,
|
|
42
42
|
p,
|
|
43
43
|
_
|
|
44
|
-
]),
|
|
44
|
+
]), t(() => {
|
|
45
45
|
if (typeof IntersectionObserver < "u") return;
|
|
46
46
|
let e = p?.() ?? window, t = e instanceof HTMLElement ? e : window, n = e instanceof HTMLElement ? e.getBoundingClientRect().top : 0, r = () => {
|
|
47
47
|
let e;
|
|
@@ -57,20 +57,26 @@ function c({ items: c, activeId: l, onClick: u, offsetTop: d = 0, bounds: f = 5,
|
|
|
57
57
|
f,
|
|
58
58
|
p,
|
|
59
59
|
_
|
|
60
|
-
]), /* @__PURE__ */
|
|
60
|
+
]), /* @__PURE__ */ n("nav", {
|
|
61
|
+
"data-slot": "anchor",
|
|
61
62
|
...h,
|
|
62
63
|
className: e([i, m]),
|
|
63
|
-
children:
|
|
64
|
+
children: n("ul", {
|
|
65
|
+
"data-slot": "list",
|
|
64
66
|
className: e([a]),
|
|
65
|
-
children: c.map((
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
children: c.map((t) => /* @__PURE__ */ n("li", {
|
|
68
|
+
"data-slot": "item",
|
|
69
|
+
children: /* @__PURE__ */ n("a", {
|
|
70
|
+
"data-slot": "link",
|
|
71
|
+
href: `#${t.id}`,
|
|
72
|
+
"aria-current": g === t.id ? "true" : void 0,
|
|
73
|
+
onClick: (e) => {
|
|
74
|
+
e.preventDefault(), _(t.id), u?.(t.id), v(t.id);
|
|
75
|
+
},
|
|
76
|
+
className: e([o, g === t.id && s]),
|
|
77
|
+
children: t.label
|
|
78
|
+
})
|
|
79
|
+
}, t.id))
|
|
74
80
|
})
|
|
75
81
|
});
|
|
76
82
|
}
|
|
@@ -9,6 +9,7 @@ var i = "haze-AppShell__shell", a = "haze-AppShell__withSidebar", o = "haze-AppS
|
|
|
9
9
|
function u({ header: u, sidebar: d, footer: f, sidebarCollapsed: p, sidebarWidth: m = "calc(var(--haze-space-16) * 4)", className: h, style: g, children: _, ...v }) {
|
|
10
10
|
let [y] = r(p, !1);
|
|
11
11
|
return /* @__PURE__ */ n("div", {
|
|
12
|
+
"data-slot": "app-shell",
|
|
12
13
|
style: {
|
|
13
14
|
"--haze-appshell-sidebar-width": m,
|
|
14
15
|
...g
|
|
@@ -21,19 +22,23 @@ function u({ header: u, sidebar: d, footer: f, sidebarCollapsed: p, sidebarWidth
|
|
|
21
22
|
]),
|
|
22
23
|
children: [
|
|
23
24
|
u != null && /* @__PURE__ */ t("header", {
|
|
25
|
+
"data-slot": "header",
|
|
24
26
|
className: e(o),
|
|
25
27
|
children: u
|
|
26
28
|
}),
|
|
27
29
|
d != null && /* @__PURE__ */ t("aside", {
|
|
30
|
+
"data-slot": "aside",
|
|
28
31
|
"data-state": y ? "collapsed" : "expanded",
|
|
29
32
|
className: e(s),
|
|
30
33
|
children: d
|
|
31
34
|
}),
|
|
32
35
|
/* @__PURE__ */ t("main", {
|
|
36
|
+
"data-slot": "main",
|
|
33
37
|
className: e(c),
|
|
34
38
|
children: _
|
|
35
39
|
}),
|
|
36
40
|
f != null && /* @__PURE__ */ t("footer", {
|
|
41
|
+
"data-slot": "footer",
|
|
37
42
|
className: e(l),
|
|
38
43
|
children: f
|
|
39
44
|
})
|