@cube-dev/ui-kit 0.149.2 → 0.150.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/dist/CHANGELOG.md +28 -0
- package/dist/_internal/hooks/use-chained-callback.js +1 -1
- package/dist/_internal/hooks/use-debounced-value.js +1 -1
- package/dist/_internal/hooks/use-deprecation-warning.js +1 -1
- package/dist/_internal/hooks/use-event.js +1 -1
- package/dist/_internal/hooks/use-is-first-render.js +1 -1
- package/dist/_internal/hooks/use-sync-ref.js +1 -1
- package/dist/_internal/hooks/use-timer/timer.js +1 -1
- package/dist/_internal/hooks/use-timer/use-timer.js +1 -1
- package/dist/_internal/hooks/use-warn.js +1 -1
- package/dist/components/Block.js +1 -1
- package/dist/components/CollectionItem.js +1 -1
- package/dist/components/GlobalStyles.js +7 -7
- package/dist/components/GlobalStyles.js.map +1 -1
- package/dist/components/GridProvider.js +1 -1
- package/dist/components/HiddenInput.js +1 -1
- package/dist/components/Root.js +1 -1
- package/dist/components/actions/Action/Action.js +1 -1
- package/dist/components/actions/Banner/Banner.js +1 -1
- package/dist/components/actions/Button/Button.js +1 -1
- package/dist/components/actions/ButtonGroup/ButtonGroup.js +1 -1
- package/dist/components/actions/ButtonSplit/ButtonSplit.js +1 -1
- package/dist/components/actions/ButtonSplit/context.js +1 -1
- package/dist/components/actions/CommandMenu/CommandMenu.js +1 -1
- package/dist/components/actions/CommandMenu/styled.js +1 -1
- package/dist/components/actions/ItemAction/ItemAction.js +1 -1
- package/dist/components/actions/ItemActionContext.js +1 -1
- package/dist/components/actions/ItemButton/ItemButton.js +1 -1
- package/dist/components/actions/Link/Link.js +1 -1
- package/dist/components/actions/Menu/Menu.js +1 -1
- package/dist/components/actions/Menu/MenuItem.js +1 -1
- package/dist/components/actions/Menu/MenuSection.js +1 -1
- package/dist/components/actions/Menu/MenuTrigger.js +1 -1
- package/dist/components/actions/Menu/SubMenuTrigger.js +1 -1
- package/dist/components/actions/Menu/SubmenuTriggerContext.js +1 -1
- package/dist/components/actions/Menu/context.js +1 -1
- package/dist/components/actions/Menu/styled.js +1 -1
- package/dist/components/actions/index.js +1 -1
- package/dist/components/actions/use-action.js +1 -1
- package/dist/components/actions/use-action.js.map +1 -1
- package/dist/components/actions/use-anchored-menu.js +1 -1
- package/dist/components/actions/use-context-menu.js +1 -1
- package/dist/components/content/ActiveZone/ActiveZone.js +1 -1
- package/dist/components/content/Alert/Alert.js +1 -1
- package/dist/components/content/Alert/use-alert.js +1 -1
- package/dist/components/content/Avatar/Avatar.js +1 -1
- package/dist/components/content/Badge/Badge.js +1 -1
- package/dist/components/content/Card/Card.js +1 -1
- package/dist/components/content/Content.js +1 -1
- package/dist/components/content/CopyPasteBlock/CopyPasteBlock.js +1 -1
- package/dist/components/content/CopySnippet/CopySnippet.js +5 -1
- package/dist/components/content/CopySnippet/CopySnippet.js.map +1 -1
- package/dist/components/content/Disclosure/Disclosure.js +1 -1
- package/dist/components/content/Divider.js +1 -1
- package/dist/components/content/Footer.js +1 -1
- package/dist/components/content/Header.js +1 -1
- package/dist/components/content/HotKeys/HotKeys.js +1 -1
- package/dist/components/content/InfoBadge/InfoBadge.js +1 -1
- package/dist/components/content/InlineInput/InlineInput.js +1 -1
- package/dist/components/content/Item/Item.js +1 -1
- package/dist/components/content/ItemBadge/ItemBadge.js +1 -1
- package/dist/components/content/ItemCard/ItemCard.js +1 -1
- package/dist/components/content/Layout/GridLayout.js +1 -1
- package/dist/components/content/Layout/Layout.js +1 -1
- package/dist/components/content/Layout/LayoutBlock.js +1 -1
- package/dist/components/content/Layout/LayoutCenter.js +1 -1
- package/dist/components/content/Layout/LayoutContainer.js +1 -1
- package/dist/components/content/Layout/LayoutContent.js +1 -1
- package/dist/components/content/Layout/LayoutContext.js +1 -1
- package/dist/components/content/Layout/LayoutFlex.js +1 -1
- package/dist/components/content/Layout/LayoutFooter.js +1 -1
- package/dist/components/content/Layout/LayoutGrid.js +1 -1
- package/dist/components/content/Layout/LayoutHeader.js +1 -1
- package/dist/components/content/Layout/LayoutPane.js +1 -1
- package/dist/components/content/Layout/LayoutPanel.js +1 -1
- package/dist/components/content/Layout/LayoutPanelHeader.js +1 -1
- package/dist/components/content/Layout/LayoutToolbar.js +1 -1
- package/dist/components/content/Layout/hooks/useTinyScrollbar.js +1 -1
- package/dist/components/content/Layout/index.js +1 -1
- package/dist/components/content/Layout/utils.js +1 -1
- package/dist/components/content/Paragraph.js +1 -1
- package/dist/components/content/Placeholder/Placeholder.js +1 -1
- package/dist/components/content/PrismCode/PrismCode.js +6 -2
- package/dist/components/content/PrismCode/PrismCode.js.map +1 -1
- package/dist/components/content/PrismCode/prismSetup.js +1 -1
- package/dist/components/content/PrismDiffCode/PrismDiffCode.js +1 -1
- package/dist/components/content/Result/Result.js +1 -1
- package/dist/components/content/Skeleton/Skeleton.js +1 -1
- package/dist/components/content/Tag/Tag.js +1 -1
- package/dist/components/content/Text.d.ts +7 -7
- package/dist/components/content/Text.js +1 -1
- package/dist/components/content/TextItem/TextItem.js +1 -1
- package/dist/components/content/Title.js +1 -1
- package/dist/components/content/Tree/Tree.js +1 -1
- package/dist/components/content/Tree/TreeNode.js +1 -1
- package/dist/components/content/Tree/styled.js +1 -1
- package/dist/components/content/Tree/tree-index.js +1 -1
- package/dist/components/content/Tree/use-checkbox-tree.js +1 -1
- package/dist/components/content/Tree/use-load-data.js +1 -1
- package/dist/components/content/highlightText.js +1 -1
- package/dist/components/content/use-auto-tooltip.js +1 -1
- package/dist/components/fields/Checkbox/Checkbox.js +1 -1
- package/dist/components/fields/Checkbox/CheckboxGroup.js +1 -1
- package/dist/components/fields/Checkbox/context.js +1 -1
- package/dist/components/fields/ComboBox/ComboBox.js +1 -1
- package/dist/components/fields/CommandTextArea/CommandTextArea.js +1 -1
- package/dist/components/fields/CommandTextArea/caretPosition.js +1 -1
- package/dist/components/fields/CommandTextArea/useCaretAnchor.js +1 -1
- package/dist/components/fields/DatePicker/DateInput.js +1 -1
- package/dist/components/fields/DatePicker/DateInputBase.js +1 -1
- package/dist/components/fields/DatePicker/DatePicker.js +1 -1
- package/dist/components/fields/DatePicker/DatePickerButton.js +1 -1
- package/dist/components/fields/DatePicker/DatePickerElement.js +1 -1
- package/dist/components/fields/DatePicker/DatePickerInput.js +1 -1
- package/dist/components/fields/DatePicker/DatePickerSegment.js +1 -1
- package/dist/components/fields/DatePicker/DateRangePicker.js +1 -1
- package/dist/components/fields/DatePicker/DateRangeSeparatedPicker.js +1 -1
- package/dist/components/fields/DatePicker/TimeInput.js +1 -1
- package/dist/components/fields/DatePicker/parseDate.js +1 -1
- package/dist/components/fields/DatePicker/props.js +1 -1
- package/dist/components/fields/DatePicker/utils.js +1 -1
- package/dist/components/fields/FileInput/FileInput.js +1 -1
- package/dist/components/fields/FilterListBox/FilterListBox.js +1 -1
- package/dist/components/fields/FilterPicker/FilterPicker.js +1 -1
- package/dist/components/fields/Input/Input.js +1 -1
- package/dist/components/fields/ListBox/DraggableListBox.js +1 -1
- package/dist/components/fields/ListBox/ListBox.js +1 -1
- package/dist/components/fields/ListBoxPopover/ListBoxPopover.js +1 -1
- package/dist/components/fields/ListBoxPopover/listNavigation.js +1 -1
- package/dist/components/fields/ListBoxPopover/useCompositeFocus.js +1 -1
- package/dist/components/fields/NumberInput/NumberInput.js +1 -1
- package/dist/components/fields/NumberInput/StepButton.js +1 -1
- package/dist/components/fields/PasswordInput/PasswordInput.js +1 -1
- package/dist/components/fields/Picker/Picker.js +1 -1
- package/dist/components/fields/RadioGroup/Radio.js +1 -1
- package/dist/components/fields/RadioGroup/RadioGroup.js +1 -1
- package/dist/components/fields/RadioGroup/context.js +1 -1
- package/dist/components/fields/SearchComboBox/SearchComboBox.js +1 -1
- package/dist/components/fields/SearchInput/SearchInput.js +1 -1
- package/dist/components/fields/Select/Select.js +1 -1
- package/dist/components/fields/Slider/Gradation.js +1 -1
- package/dist/components/fields/Slider/HueSlider.js +1 -1
- package/dist/components/fields/Slider/RangeSlider.js +1 -1
- package/dist/components/fields/Slider/Slider.js +1 -1
- package/dist/components/fields/Slider/SliderBase.js +1 -1
- package/dist/components/fields/Slider/SliderThumb.js +1 -1
- package/dist/components/fields/Slider/SliderTrack.js +1 -1
- package/dist/components/fields/Slider/elements.js +1 -1
- package/dist/components/fields/Slider/index.js +1 -1
- package/dist/components/fields/Switch/Switch.js +1 -1
- package/dist/components/fields/TextArea/TextArea.js +1 -1
- package/dist/components/fields/TextInput/TextInput.js +1 -1
- package/dist/components/fields/TextInput/TextInputBase.js +1 -1
- package/dist/components/fields/TextInputMapper/TextInputMapper.js +1 -1
- package/dist/components/form/FieldWrapper/FieldWrapper.js +1 -1
- package/dist/components/form/Form/Field.js +1 -1
- package/dist/components/form/Form/Form.js +1 -1
- package/dist/components/form/Form/ResetButton/ResetButton.js +1 -1
- package/dist/components/form/Form/SubmitButton/SubmitButton.js +1 -1
- package/dist/components/form/Form/SubmitError.js +1 -1
- package/dist/components/form/Form/index.js +1 -1
- package/dist/components/form/Form/use-field/use-field-props.js +1 -1
- package/dist/components/form/Form/use-field/use-field.js +1 -1
- package/dist/components/form/Form/use-form.js +1 -1
- package/dist/components/form/Form/validation.js +1 -1
- package/dist/components/form/Label.js +1 -1
- package/dist/components/form/validation/ValidationIndicator.js +1 -1
- package/dist/components/form/validation/resolve-validation-props.js +1 -1
- package/dist/components/form/validation/use-validation-props.js +1 -1
- package/dist/components/form/wrapper.js +1 -1
- package/dist/components/helpers/DisplayTransition/DisplayTransition.js +1 -1
- package/dist/components/helpers/IconSwitch/IconSwitch.js +1 -1
- package/dist/components/layout/Board/Board.js +1 -1
- package/dist/components/layout/Board/BoardProvider.js +1 -1
- package/dist/components/layout/Board/BoardResponsive.js +1 -1
- package/dist/components/layout/Board/Widget.js +1 -1
- package/dist/components/layout/Board/WidgetHost.js +1 -1
- package/dist/components/layout/Board/board-context.js +1 -1
- package/dist/components/layout/Board/board-store.js +1 -1
- package/dist/components/layout/Board/grid-core/calculate.js +1 -1
- package/dist/components/layout/Board/grid-core/collision.js +1 -1
- package/dist/components/layout/Board/grid-core/compactors.js +1 -1
- package/dist/components/layout/Board/grid-core/constraints.js +1 -1
- package/dist/components/layout/Board/grid-core/layout.js +1 -1
- package/dist/components/layout/Board/grid-core/sort.js +1 -1
- package/dist/components/layout/Board/index.js +1 -1
- package/dist/components/layout/Board/responsive-utils.js +1 -1
- package/dist/components/layout/Board/use-board-layout.js +1 -1
- package/dist/components/layout/Board/use-board-registry.js +1 -1
- package/dist/components/layout/Flex.js +1 -1
- package/dist/components/layout/Flow.js +1 -1
- package/dist/components/layout/Grid.js +1 -1
- package/dist/components/layout/Panel.js +1 -1
- package/dist/components/layout/Prefix.js +1 -1
- package/dist/components/layout/ResizablePanel.js +1 -1
- package/dist/components/layout/Space.js +1 -1
- package/dist/components/layout/Suffix.js +1 -1
- package/dist/components/navigation/Tabs/DraggableTabList.js +1 -1
- package/dist/components/navigation/Tabs/TabButton.js +1 -1
- package/dist/components/navigation/Tabs/TabDropIndicator.js +1 -1
- package/dist/components/navigation/Tabs/TabPanel.js +1 -1
- package/dist/components/navigation/Tabs/TabPicker.js +1 -1
- package/dist/components/navigation/Tabs/Tabs.js +1 -1
- package/dist/components/navigation/Tabs/TabsAction.js +1 -1
- package/dist/components/navigation/Tabs/TabsContext.js +1 -1
- package/dist/components/navigation/Tabs/popover-placement.js +1 -1
- package/dist/components/navigation/Tabs/styled.js +1 -1
- package/dist/components/navigation/Tabs/types.js +1 -1
- package/dist/components/navigation/Tabs/use-tab-editing.js +1 -1
- package/dist/components/navigation/Tabs/use-tab-indicator.js +1 -1
- package/dist/components/organisms/FileTabs/FileTabs.js +1 -1
- package/dist/components/organisms/StatsCard/StatsCard.js +1 -1
- package/dist/components/other/Calendar/Calendar.js +1 -1
- package/dist/components/other/Calendar/CalendarCell.js +1 -1
- package/dist/components/other/Calendar/CalendarGrid.js +1 -1
- package/dist/components/other/Calendar/RangeCalendar.js +1 -1
- package/dist/components/other/CloudLogo/CloudLogo.js +1 -1
- package/dist/components/overlays/AlertDialog/AlertDialog.js +1 -1
- package/dist/components/overlays/AlertDialog/AlertDialogApiProvider.js +1 -1
- package/dist/components/overlays/AlertDialog/AlertDialogZone.js +1 -1
- package/dist/components/overlays/Dialog/Dialog.js +1 -1
- package/dist/components/overlays/Dialog/DialogContainer.js +1 -1
- package/dist/components/overlays/Dialog/DialogForm.js +1 -1
- package/dist/components/overlays/Dialog/DialogTrigger.js +1 -1
- package/dist/components/overlays/Dialog/context.js +1 -1
- package/dist/components/overlays/Dialog/use-dialog-container.js +1 -1
- package/dist/components/overlays/Modal/Modal.js +1 -1
- package/dist/components/overlays/Modal/OpenTransitionContext.js +1 -1
- package/dist/components/overlays/Modal/Overlay.js +1 -1
- package/dist/components/overlays/Modal/Popover.js +1 -1
- package/dist/components/overlays/Modal/Tray.js +1 -1
- package/dist/components/overlays/Modal/Underlay.js +1 -1
- package/dist/components/overlays/Notifications/Notification.js +1 -1
- package/dist/components/overlays/Notifications/NotificationAction.js +1 -1
- package/dist/components/overlays/Notifications/NotificationCard.js +1 -1
- package/dist/components/overlays/Notifications/NotificationContext.js +1 -1
- package/dist/components/overlays/Notifications/NotificationItem.js +1 -1
- package/dist/components/overlays/Notifications/OverlayContainer.js +1 -1
- package/dist/components/overlays/Notifications/OverlayProvider.js +1 -1
- package/dist/components/overlays/Notifications/PersistentNotificationsList.js +1 -1
- package/dist/components/overlays/Notifications/dismissed-storage.js +1 -1
- package/dist/components/overlays/Notifications/format-relative-time.js +1 -1
- package/dist/components/overlays/Notifications/index.js +1 -1
- package/dist/components/overlays/Notifications/use-notification-state.js +1 -1
- package/dist/components/overlays/Notifications/use-notifications.js +1 -1
- package/dist/components/overlays/Notifications/use-overlay-timers.js +1 -1
- package/dist/components/overlays/Notifications/use-persistent-notifications.js +1 -1
- package/dist/components/overlays/Notifications/use-persistent-state.js +1 -1
- package/dist/components/overlays/Notifications/use-toast-state.js +1 -1
- package/dist/components/overlays/Toast/ToastItem.js +1 -1
- package/dist/components/overlays/Toast/index.js +1 -1
- package/dist/components/overlays/Toast/useProgressToast.js +1 -1
- package/dist/components/overlays/Toast/useToast.js +1 -1
- package/dist/components/overlays/Tooltip/Tooltip.js +1 -1
- package/dist/components/overlays/Tooltip/TooltipProvider.js +1 -1
- package/dist/components/overlays/Tooltip/TooltipTrigger.js +1 -1
- package/dist/components/overlays/Tooltip/context.js +1 -1
- package/dist/components/portal/Portal.js +1 -1
- package/dist/components/portal/PortalProvider.js +1 -1
- package/dist/components/portal/usePortal.js +1 -1
- package/dist/components/shared/DraggableCollection.js +1 -1
- package/dist/components/shared/InvalidIcon.js +1 -1
- package/dist/components/shared/ValidIcon.js +1 -1
- package/dist/components/status/LoadingAnimation/LoadingAnimation.js +1 -1
- package/dist/components/status/Spin/Cube.js +1 -1
- package/dist/components/status/Spin/InternalSpinner.js +1 -1
- package/dist/components/status/Spin/Spin.js +1 -1
- package/dist/components/status/Spin/SpinsContainer.js +1 -1
- package/dist/data/item-themes.js +5 -3
- package/dist/data/item-themes.js.map +1 -1
- package/dist/data/themes.js +1 -1
- package/dist/i18n/I18nProvider.js +1 -1
- package/dist/i18n/createFormatter.js +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/instance.js +1 -1
- package/dist/i18n/locales/de-DE/uikit.js +1 -1
- package/dist/i18n/locales/en-US/uikit.js +1 -1
- package/dist/i18n/locales/es-ES/uikit.js +1 -1
- package/dist/i18n/locales/es-MX/uikit.js +1 -1
- package/dist/i18n/locales/fr-FR/uikit.js +1 -1
- package/dist/i18n/locales/it-IT/uikit.js +1 -1
- package/dist/i18n/locales/ja-JP/uikit.js +1 -1
- package/dist/i18n/locales/nb-NO/uikit.js +1 -1
- package/dist/i18n/locales/pt-BR/uikit.js +1 -1
- package/dist/i18n/locales/pt-PT/uikit.js +1 -1
- package/dist/i18n/locales/sv-SE/uikit.js +1 -1
- package/dist/i18n/locales/vi-VN/uikit.js +1 -1
- package/dist/i18n/locales.js +1 -1
- package/dist/i18n/useFormatter.js +1 -1
- package/dist/i18n/useI18n.js +1 -1
- package/dist/icons/AdjustmentsHorizontalIcon.js +1 -1
- package/dist/icons/AdjustmentsIcon.js +1 -1
- package/dist/icons/AiIcon.js +1 -1
- package/dist/icons/AreaChartIcon.js +1 -1
- package/dist/icons/BackwardIcon.js +1 -1
- package/dist/icons/BarChartIcon.js +1 -1
- package/dist/icons/BellFilledIcon.js +1 -1
- package/dist/icons/BellIcon.js +1 -1
- package/dist/icons/BooleanIcon.js +1 -1
- package/dist/icons/CalendarEditIcon.js +1 -1
- package/dist/icons/CalendarIcon.js +1 -1
- package/dist/icons/CaretDownIcon.js +1 -1
- package/dist/icons/CaretUpIcon.js +1 -1
- package/dist/icons/ChartAreaStackedIcon.js +1 -1
- package/dist/icons/ChartAreaStackedPercentageIcon.js +1 -1
- package/dist/icons/ChartBarGroupedHorizontalIcon.js +1 -1
- package/dist/icons/ChartBarGroupedIcon.js +1 -1
- package/dist/icons/ChartBarHorizontalIcon.js +1 -1
- package/dist/icons/ChartBarLineIcon.js +1 -1
- package/dist/icons/ChartBarStackedHorizontalIcon.js +1 -1
- package/dist/icons/ChartBarStackedIcon.js +1 -1
- package/dist/icons/ChartBarStackedPercentageHorizontalIcon.js +1 -1
- package/dist/icons/ChartBarStackedPercentageIcon.js +1 -1
- package/dist/icons/ChartBoxPlot2Icon.js +1 -1
- package/dist/icons/ChartBoxPlotIcon.js +1 -1
- package/dist/icons/ChartBubbleIcon.js +1 -1
- package/dist/icons/ChartDonut2Icon.js +1 -1
- package/dist/icons/ChartFunnelIcon.js +1 -1
- package/dist/icons/ChartHeatmapIcon.js +1 -1
- package/dist/icons/ChartKPIIcon.js +1 -1
- package/dist/icons/ChartPie2Icon.js +1 -1
- package/dist/icons/ChartScatterIcon.js +1 -1
- package/dist/icons/CheckCircleFilledIcon.js +1 -1
- package/dist/icons/CheckCircleIcon.js +1 -1
- package/dist/icons/CheckIcon.js +1 -1
- package/dist/icons/CircleFilledIcon.js +1 -1
- package/dist/icons/ClearIcon.js +1 -1
- package/dist/icons/CloseCircleFilledIcon.js +1 -1
- package/dist/icons/CloseCircleIcon.js +1 -1
- package/dist/icons/CloseIcon.js +1 -1
- package/dist/icons/CodeIcon.js +1 -1
- package/dist/icons/ColumnTotalIcon.js +1 -1
- package/dist/icons/CopyIcon.js +1 -1
- package/dist/icons/CountIcon.js +1 -1
- package/dist/icons/CubeIcon.js +1 -1
- package/dist/icons/CubePauseIcon.js +1 -1
- package/dist/icons/CubePlayIcon.js +1 -1
- package/dist/icons/CurrencyDollarIcon.js +1 -1
- package/dist/icons/DangerIcon.js +1 -1
- package/dist/icons/DashboardIcon.js +1 -1
- package/dist/icons/DatabaseIcon.js +1 -1
- package/dist/icons/DecimalDecreaseIcon.js +1 -1
- package/dist/icons/DecimalIncreaseIcon.js +1 -1
- package/dist/icons/DirectionIcon.js +1 -1
- package/dist/icons/DonutIcon.js +1 -1
- package/dist/icons/DownIcon.js +1 -1
- package/dist/icons/EditIcon.js +1 -1
- package/dist/icons/ExclamationCircleFilledIcon.js +1 -1
- package/dist/icons/ExclamationCircleIcon.js +1 -1
- package/dist/icons/ExclamationIcon.js +1 -1
- package/dist/icons/EyeIcon.js +1 -1
- package/dist/icons/EyeInvisibleIcon.js +1 -1
- package/dist/icons/FilterIcon.js +1 -1
- package/dist/icons/FolderFilledIcon.js +1 -1
- package/dist/icons/FolderIcon.js +1 -1
- package/dist/icons/FolderOpenFilledIcon.js +1 -1
- package/dist/icons/FolderOpenIcon.js +1 -1
- package/dist/icons/ForwardIcon.js +1 -1
- package/dist/icons/GripVerticalIcon.js +1 -1
- package/dist/icons/HierarchyIcon.js +1 -1
- package/dist/icons/HierarchyOpenIcon.js +1 -1
- package/dist/icons/Icon.js +1 -1
- package/dist/icons/InfoCircleIcon.js +1 -1
- package/dist/icons/InfoIcon.js +1 -1
- package/dist/icons/KeyIcon.js +1 -1
- package/dist/icons/LeftIcon.js +1 -1
- package/dist/icons/LineChartIcon.js +1 -1
- package/dist/icons/LoadingIcon.js +1 -1
- package/dist/icons/LockFilledIcon.js +1 -1
- package/dist/icons/LockIcon.js +1 -1
- package/dist/icons/MoreIcon.js +1 -1
- package/dist/icons/NotAllowedIcon.js +1 -1
- package/dist/icons/Number123Icon.js +1 -1
- package/dist/icons/NumberIcon.js +1 -1
- package/dist/icons/PauseCircleFilledIcon.js +1 -1
- package/dist/icons/PauseCircleIcon.js +1 -1
- package/dist/icons/PauseIcon.js +1 -1
- package/dist/icons/PercentageIcon.js +1 -1
- package/dist/icons/PieChartIcon.js +1 -1
- package/dist/icons/PlayCircleIcon.js +1 -1
- package/dist/icons/PlayIcon.js +1 -1
- package/dist/icons/PlusIcon.js +1 -1
- package/dist/icons/ProgressBarIcon.js +1 -1
- package/dist/icons/ReloadIcon.js +1 -1
- package/dist/icons/ReportIcon.js +1 -1
- package/dist/icons/ReturnIcon.js +1 -1
- package/dist/icons/RightIcon.js +1 -1
- package/dist/icons/RowTotalsIcon.js +1 -1
- package/dist/icons/SchemeIcon.js +1 -1
- package/dist/icons/SearchIcon.js +1 -1
- package/dist/icons/SemanticQueryIcon.js +1 -1
- package/dist/icons/SettingsIcon.js +1 -1
- package/dist/icons/ShieldFilledIcon.js +1 -1
- package/dist/icons/ShieldIcon.js +1 -1
- package/dist/icons/SlashIcon.js +1 -1
- package/dist/icons/SparklesIcon.js +1 -1
- package/dist/icons/SqlIcon.js +1 -1
- package/dist/icons/StatsIcon.js +1 -1
- package/dist/icons/StopIcon.js +1 -1
- package/dist/icons/StringIcon.js +1 -1
- package/dist/icons/SubtotalsIcon.js +1 -1
- package/dist/icons/SwitchIcon.js +1 -1
- package/dist/icons/TableIcon.js +1 -1
- package/dist/icons/ThumbsDownIcon.js +1 -1
- package/dist/icons/ThumbsUpIcon.js +1 -1
- package/dist/icons/ThunderboltCrossedIcon.js +1 -1
- package/dist/icons/ThunderboltFilledIcon.js +1 -1
- package/dist/icons/ThunderboltIcon.js +1 -1
- package/dist/icons/TimeIcon.js +1 -1
- package/dist/icons/TrashIcon.js +1 -1
- package/dist/icons/UnlockIcon.js +1 -1
- package/dist/icons/UpIcon.js +1 -1
- package/dist/icons/UserGroupIcon.js +1 -1
- package/dist/icons/UserIcon.js +1 -1
- package/dist/icons/UserLockIcon.js +1 -1
- package/dist/icons/ViewIcon.js +1 -1
- package/dist/icons/WarningFilledIcon.js +1 -1
- package/dist/icons/WarningIcon.js +1 -1
- package/dist/icons/wrap-icon.js +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/provider.js +1 -1
- package/dist/providers/TrackingProvider.js +1 -1
- package/dist/providers/navigationAdapter.default.js +1 -1
- package/dist/tokens/base.js +1 -1
- package/dist/tokens/colors.d.ts +2 -7
- package/dist/tokens/colors.js +16 -7
- package/dist/tokens/colors.js.map +1 -1
- package/dist/tokens/index.d.ts +5 -17
- package/dist/tokens/index.js +23 -13
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/layout.js +1 -1
- package/dist/tokens/lazy-styles.js +33 -0
- package/dist/tokens/lazy-styles.js.map +1 -0
- package/dist/tokens/palette.d.ts +15 -0
- package/dist/tokens/palette.js +166 -123
- package/dist/tokens/palette.js.map +1 -1
- package/dist/tokens/shadows.js +1 -1
- package/dist/tokens/sizes.js +1 -1
- package/dist/tokens/spacing.js +1 -1
- package/dist/tokens/typography.d.ts +1 -0
- package/dist/tokens/typography.js +29 -1
- package/dist/tokens/typography.js.map +1 -1
- package/dist/utils/ResizeSensor.js +1 -1
- package/dist/utils/is-dev-env.js +1 -1
- package/dist/utils/modules.js +1 -1
- package/dist/utils/promise.js +1 -1
- package/dist/utils/raf.js +1 -1
- package/dist/utils/random.js +1 -1
- package/dist/utils/range.js +1 -1
- package/dist/utils/react/RenderCache.js +1 -1
- package/dist/utils/react/Slots.js +1 -1
- package/dist/utils/react/chain.js +1 -1
- package/dist/utils/react/forwardRefWithGenerics.js +1 -1
- package/dist/utils/react/index.js +1 -1
- package/dist/utils/react/interactions.js +1 -1
- package/dist/utils/react/isTextOnly.js +1 -1
- package/dist/utils/react/mapProps.js +1 -1
- package/dist/utils/react/mergeProps.js +1 -1
- package/dist/utils/react/nullableValue.js +1 -1
- package/dist/utils/react/resolveIcon.js +1 -1
- package/dist/utils/react/sharedStore.js +1 -1
- package/dist/utils/react/useCombinedRefs.js +1 -1
- package/dist/utils/react/useControlledFocusVisible.js +1 -1
- package/dist/utils/react/useEventBus.js +1 -1
- package/dist/utils/react/useId.js +1 -1
- package/dist/utils/react/useIsDarwin.js +1 -1
- package/dist/utils/react/useKeySymbols.js +1 -1
- package/dist/utils/react/useLayoutEffect.js +1 -1
- package/dist/utils/react/useLocalStorage.js +1 -1
- package/dist/utils/react/useMergeStyles.js +1 -1
- package/dist/utils/react/usePopoverSync.js +1 -1
- package/dist/utils/react/useQaProps.js +1 -1
- package/dist/utils/react/useViewportSize.js +1 -1
- package/dist/utils/react/wrapNodeIfPlain.js +1 -1
- package/dist/utils/selection.js +1 -1
- package/dist/utils/styles.js +1 -1
- package/dist/utils/tree.js +1 -1
- package/dist/utils/warnings.js +1 -1
- package/dist/version.js +2 -2
- package/docs/Colors.md +77 -0
- package/docs/Typography.md +1 -1
- package/docs/Usage.md +10 -0
- package/docs/components/content/CopySnippet.md +1 -1
- package/docs/components/content/PrismCode.md +1 -0
- package/docs/glaze/api.md +1033 -414
- package/docs/glaze/methodology.md +536 -208
- package/docs/glaze/migration.md +127 -49
- package/docs/glaze/okhst.md +190 -0
- package/package.json +2 -2
package/docs/glaze/api.md
CHANGED
|
@@ -6,12 +6,18 @@ Full reference for every public method, option, and type exported by `@tenphi/gl
|
|
|
6
6
|
|
|
7
7
|
- [Theme creation](#theme-creation)
|
|
8
8
|
- [Theme methods](#theme-methods)
|
|
9
|
+
- [DTCG](#themedtcgoptions)
|
|
10
|
+
- [DTCG Resolver-Module](#themedtcgresolveroptions)
|
|
11
|
+
- [Tailwind CSS](#themetailwindoptions)
|
|
12
|
+
- [High-contrast pairs](#high-contrast-pairs)
|
|
9
13
|
- [Color definitions](#color-definitions)
|
|
14
|
+
- [Dark seed](#dark-seed-darkhue--darksaturation)
|
|
10
15
|
- [Standalone color tokens](#standalone-color-tokens)
|
|
11
16
|
- [Shadows](#shadows)
|
|
12
17
|
- [Mix colors](#mix-colors)
|
|
13
18
|
- [Palette](#palette)
|
|
14
19
|
- [Output formats](#output-formats)
|
|
20
|
+
- [Hue channel splitting](#hue-channel-splitting-splithue)
|
|
15
21
|
- [Adaptation modes](#adaptation-modes)
|
|
16
22
|
- [Light / dark scheme mapping](#light--dark-scheme-mapping)
|
|
17
23
|
- [Configuration](#configuration)
|
|
@@ -23,25 +29,42 @@ Full reference for every public method, option, and type exported by `@tenphi/gl
|
|
|
23
29
|
|
|
24
30
|
## Theme creation
|
|
25
31
|
|
|
26
|
-
| Method
|
|
27
|
-
|
|
28
|
-
| `glaze(hue, saturation?, config?)`
|
|
29
|
-
| `glaze({ hue, saturation }, config?)` | Create a theme from an options object, with optional per-theme config override. |
|
|
30
|
-
| `glaze.
|
|
31
|
-
| `glaze.
|
|
32
|
-
| `glaze.
|
|
32
|
+
| Method | Description |
|
|
33
|
+
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
34
|
+
| `glaze(hue, saturation?, config?)` | Create a theme from hue (0–360) and saturation (0–100). Optional `config` overrides the global config for this theme. |
|
|
35
|
+
| `glaze({ hue, saturation, darkHue?, darkSaturation? }, config?)` | Create a theme from an options object, with optional per-theme config override. `darkHue` / `darkSaturation` seed the dark schemes — see [Dark seed](#dark-seed-darkhue--darksaturation). |
|
|
36
|
+
| `glaze.themeFrom(data)` | Create a theme from a `theme.export()` snapshot (`kind: 'theme'`). |
|
|
37
|
+
| `glaze.from(data)` | Compat alias for `glaze.themeFrom`. |
|
|
38
|
+
| `glaze.fromHex(hex)` | Create a theme from a hex color (`#rgb` or `#rrggbb`). Extracts hue and saturation. |
|
|
39
|
+
| `glaze.fromRgb(r, g, b)` | Create a theme from RGB values (0–255). Extracts hue and saturation. |
|
|
40
|
+
| `glaze.paletteFrom(data)` | Create a palette from a `palette.export()` snapshot (`kind: 'palette'`). |
|
|
41
|
+
| `glaze.colorFrom(data)` | Create a color token from a `token.export()` snapshot (`kind: 'color'`). |
|
|
42
|
+
| `glaze.isThemeExport(data)` | Type guard for theme authoring snapshots. |
|
|
43
|
+
| `glaze.isColorTokenExport(data)` | Type guard for color-token authoring snapshots. |
|
|
44
|
+
| `glaze.isPaletteExport(data)` | Type guard for palette authoring snapshots. |
|
|
33
45
|
|
|
34
46
|
```ts
|
|
35
47
|
const a = glaze(280, 80);
|
|
36
48
|
const b = glaze({ hue: 280, saturation: 80 });
|
|
49
|
+
const bDark = glaze({ hue: 280, saturation: 80, darkHue: 268, darkSaturation: 65 });
|
|
37
50
|
const c = glaze.fromHex('#7a4dbf');
|
|
38
51
|
const d = glaze.fromRgb(122, 77, 191);
|
|
39
|
-
const e = glaze.
|
|
52
|
+
const e = glaze.themeFrom(a.export());
|
|
40
53
|
|
|
41
54
|
// Per-theme config override:
|
|
42
|
-
const rawTheme = glaze(280, 80, {
|
|
55
|
+
const rawTheme = glaze(280, 80, { lightTone: false, darkTone: false });
|
|
43
56
|
```
|
|
44
57
|
|
|
58
|
+
Authoring restore triad (parallel to `.export()` on each instance):
|
|
59
|
+
|
|
60
|
+
| Export | Restore |
|
|
61
|
+
| ------ | ------- |
|
|
62
|
+
| `theme.export()` | `glaze.themeFrom()` |
|
|
63
|
+
| `token.export()` | `glaze.colorFrom()` |
|
|
64
|
+
| `palette.export()` | `glaze.paletteFrom()` |
|
|
65
|
+
|
|
66
|
+
Every snapshot includes `kind` + `version` (`GLAZE_EXPORT_VERSION`, currently `1`). Legacy snapshots without those fields still restore. Wrong `kind`, or a `version` outside `1..=GLAZE_EXPORT_VERSION`, throws.
|
|
67
|
+
|
|
45
68
|
The optional `config` parameter is a `GlazeConfigOverride` — see [Per-instance config override](#per-instance-config-override).
|
|
46
69
|
|
|
47
70
|
---
|
|
@@ -50,38 +73,43 @@ The optional `config` parameter is a `GlazeConfigOverride` — see [Per-instance
|
|
|
50
73
|
|
|
51
74
|
A `GlazeTheme` exposes:
|
|
52
75
|
|
|
53
|
-
| Method
|
|
54
|
-
|
|
55
|
-
| `theme.hue` (readonly)
|
|
56
|
-
| `theme.saturation` (readonly)
|
|
57
|
-
| `theme.
|
|
58
|
-
| `theme.
|
|
59
|
-
| `theme.
|
|
60
|
-
| `theme.
|
|
61
|
-
| `theme.
|
|
62
|
-
| `theme.
|
|
63
|
-
| `theme.
|
|
64
|
-
| `theme.
|
|
65
|
-
| `theme.
|
|
66
|
-
| `theme.
|
|
67
|
-
| `theme.
|
|
68
|
-
| `theme.
|
|
69
|
-
| `theme.
|
|
70
|
-
| `theme.
|
|
76
|
+
| Method | Description |
|
|
77
|
+
| ------------------------------- | --------------------------------------------------------------------------------------------------- |
|
|
78
|
+
| `theme.hue` (readonly) | The hue seed (0–360). |
|
|
79
|
+
| `theme.saturation` (readonly) | The saturation seed (0–100). |
|
|
80
|
+
| `theme.darkHue` (readonly) | The dark-scheme hue seed (0–360), or `undefined` when `hue` is reused. |
|
|
81
|
+
| `theme.darkSaturation` (readonly) | The dark-scheme saturation seed (0–100), or `undefined` when `saturation` is reused. |
|
|
82
|
+
| `theme.colors(defs)` | Add/replace colors (additive merge — adds new, overwrites existing by name, doesn't remove others). |
|
|
83
|
+
| `theme.color(name)` | Get a color definition by name. |
|
|
84
|
+
| `theme.color(name, def)` | Set a single color definition. |
|
|
85
|
+
| `theme.remove(name \| names[])` | Remove one or more color definitions. |
|
|
86
|
+
| `theme.has(name)` | Check if a color is defined. |
|
|
87
|
+
| `theme.list()` | List all defined color names. |
|
|
88
|
+
| `theme.reset()` | Clear all color definitions. |
|
|
89
|
+
| `theme.export(override?)` | Export the theme configuration as a JSON-safe object (optional config override at export time). |
|
|
90
|
+
| `theme.extend(options)` | Create a child theme inheriting all color definitions (see [`extend`](#themeextendoptions) below). |
|
|
91
|
+
| `theme.resolve()` | Resolve all colors and return a `Map<string, ResolvedColor>`. |
|
|
92
|
+
| `theme.tokens(options?)` | Export as a flat token map grouped by scheme variant. |
|
|
93
|
+
| `theme.tasty(options?)` | Export as [Tasty](https://tasty.style) style-to-state bindings. |
|
|
94
|
+
| `theme.json(options?)` | Export as plain JSON. |
|
|
95
|
+
| `theme.css(options?)` | Export as CSS custom property declarations. |
|
|
96
|
+
| `theme.dtcg(options?)` | Export one W3C DTCG token tree per scheme. |
|
|
97
|
+
| `theme.dtcgResolver(options?)` | Export one DTCG Resolver-Module document containing every scheme. |
|
|
98
|
+
| `theme.tailwind(options?)` | Export a Tailwind CSS v4 theme and scheme overrides. |
|
|
71
99
|
|
|
72
100
|
### `theme.colors(defs)`
|
|
73
101
|
|
|
74
102
|
```ts
|
|
75
|
-
theme.colors({ surface: {
|
|
76
|
-
theme.colors({ text: {
|
|
103
|
+
theme.colors({ surface: { tone: 97 } });
|
|
104
|
+
theme.colors({ text: { tone: 30 } });
|
|
77
105
|
// Both 'surface' and 'text' are now defined.
|
|
78
106
|
```
|
|
79
107
|
|
|
80
108
|
### `theme.color(name) / theme.color(name, def)`
|
|
81
109
|
|
|
82
110
|
```ts
|
|
83
|
-
theme.color('surface', {
|
|
84
|
-
const def = theme.color('surface');
|
|
111
|
+
theme.color('surface', { tone: 97, saturation: 0.75 }); // set
|
|
112
|
+
const def = theme.color('surface'); // get
|
|
85
113
|
```
|
|
86
114
|
|
|
87
115
|
### `theme.extend(options)`
|
|
@@ -91,73 +119,89 @@ Creates a new theme inheriting all color definitions, optionally replacing the h
|
|
|
91
119
|
```ts
|
|
92
120
|
const danger = primary.extend({
|
|
93
121
|
hue: 23,
|
|
94
|
-
colors: { 'accent-fill': {
|
|
122
|
+
colors: { 'accent-fill': { tone: 48, mode: 'fixed' } },
|
|
95
123
|
});
|
|
96
124
|
|
|
97
|
-
// Inherit parent's config override and
|
|
98
|
-
const highSat = base.extend({ config: {
|
|
125
|
+
// Inherit parent's config override and widen the dark window further:
|
|
126
|
+
const highSat = base.extend({ config: { darkTone: [10, 100] } });
|
|
99
127
|
```
|
|
100
128
|
|
|
101
129
|
`GlazeExtendOptions`:
|
|
102
130
|
|
|
103
|
-
| Field
|
|
104
|
-
|
|
105
|
-
| `hue`
|
|
106
|
-
| `saturation` | `number`
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
131
|
+
| Field | Type | Description |
|
|
132
|
+
| ------------ | --------------------- | -------------------------------------------------------------------------------------------- |
|
|
133
|
+
| `hue` | `number` | Replace the hue seed. Defaults to the parent's hue. |
|
|
134
|
+
| `saturation` | `number` | Replace the saturation seed. Defaults to the parent's saturation. |
|
|
135
|
+
| `darkHue` | `number` | Replace the dark hue seed. Defaults to the parent's `darkHue`. |
|
|
136
|
+
| `darkSaturation` | `number` | Replace the dark saturation seed. Defaults to the parent's `darkSaturation`. |
|
|
137
|
+
| `colors` | `ColorMap` | Per-theme overrides (additive merge over the inherited map). |
|
|
138
|
+
| `config` | `GlazeConfigOverride` | Config override for the child. Shallow-merged with the parent's override — child fields win. |
|
|
109
139
|
|
|
110
140
|
Colors marked with `inherit: false` on the parent are **not** copied into the child.
|
|
111
141
|
|
|
142
|
+
### `theme.resolve()`
|
|
143
|
+
|
|
144
|
+
Resolves the dependency graph and returns a
|
|
145
|
+
`Map<string, ResolvedColor>`. Export methods call it automatically; use it
|
|
146
|
+
directly for tests, diagnostics, or a custom output pipeline.
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
const resolved = theme.resolve();
|
|
150
|
+
const surface = resolved.get('surface');
|
|
151
|
+
// surface?.light.t is canonical tone on 0–1.
|
|
152
|
+
```
|
|
153
|
+
|
|
112
154
|
### `theme.tokens(options?)`
|
|
113
155
|
|
|
114
156
|
Flat token map grouped by scheme variant.
|
|
115
157
|
|
|
116
158
|
```ts
|
|
117
|
-
theme.tokens()
|
|
118
|
-
// → { light: { surface: '
|
|
159
|
+
theme.tokens();
|
|
160
|
+
// → { light: { surface: 'oklch(...)' }, dark: { surface: 'oklch(...)' } }
|
|
119
161
|
```
|
|
120
162
|
|
|
121
163
|
`GlazeJsonOptions`:
|
|
122
164
|
|
|
123
|
-
| Option
|
|
124
|
-
|
|
125
|
-
| `format` | `'
|
|
126
|
-
| `modes`
|
|
165
|
+
| Option | Default | Description |
|
|
166
|
+
| -------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
167
|
+
| `format` | `'oklch'` | Output color format. One of `'rgb' \| 'hsl' \| 'oklch'`. `'okhsl'` and `'okhst'` throw — use `tasty()` for those. |
|
|
168
|
+
| `modes` | `{ dark: true, highContrast: false }` (or global config) | Which scheme variants to include. |
|
|
127
169
|
|
|
128
170
|
### `theme.tasty(options?)`
|
|
129
171
|
|
|
130
|
-
|
|
172
|
+
Style-to-state bindings for the [Tasty](https://tasty.style) style system. Uses `#name` color token keys and state aliases. By default the dark and high-contrast variants are keyed by media-query states (`'@media(prefers-color-scheme: dark)'`, `'@media(prefers-contrast: more)'`) so tokens work without registering custom states.
|
|
131
173
|
|
|
132
174
|
```ts
|
|
133
|
-
theme.tasty()
|
|
175
|
+
theme.tasty();
|
|
134
176
|
// → {
|
|
135
|
-
// '#surface': { '': '
|
|
177
|
+
// '#surface': { '': 'oklch(...)', '@media(prefers-color-scheme: dark)': 'oklch(...)' },
|
|
136
178
|
// ...
|
|
137
179
|
// }
|
|
138
180
|
```
|
|
139
181
|
|
|
140
182
|
`GlazeTokenOptions`:
|
|
141
183
|
|
|
142
|
-
| Option
|
|
143
|
-
|
|
144
|
-
| `format`
|
|
145
|
-
| `modes`
|
|
146
|
-
| `states.dark`
|
|
147
|
-
| `states.highContrast` | `'@
|
|
148
|
-
| `
|
|
184
|
+
| Option | Default | Description |
|
|
185
|
+
| --------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
186
|
+
| `format` | `'oklch'` | Output color format. `'okhsl'` and `'okhst'` are also supported here ([Tasty](https://tasty.style)-only spaces). |
|
|
187
|
+
| `modes` | global config | Which scheme variants to include. |
|
|
188
|
+
| `states.dark` | `'@media(prefers-color-scheme: dark)'` (or global config) | State alias for dark mode tokens. |
|
|
189
|
+
| `states.highContrast` | `'@media(prefers-contrast: more)'` (or global config) | State alias for high-contrast tokens. |
|
|
190
|
+
| `splitHue` | `false` | Emit hue as a separate custom property (`$name-hue` token + `var()` in `oklch` values). Requires `format: 'oklch'` and every color to be pastel. |
|
|
191
|
+
| `name` | `'theme'` | Base name for the theme-level hue var (`$theme-hue` / `--theme-hue`). Palette export auto-derives this from the theme name. |
|
|
192
|
+
| `prefix` | (palette only) | See [Palette](#palette). |
|
|
149
193
|
|
|
150
|
-
When both `dark` and `highContrast` modes are enabled, dark high-contrast variants are emitted under the combined key `<dark> & <highContrast>` (e.g. `'@dark & @
|
|
194
|
+
When both `dark` and `highContrast` modes are enabled, dark high-contrast variants are emitted under the combined key `<dark> & <highContrast>` (e.g. `'@media(prefers-color-scheme: dark) & @media(prefers-contrast: more)'`).
|
|
151
195
|
|
|
152
196
|
### `theme.json(options?)`
|
|
153
197
|
|
|
154
198
|
Per-color JSON map.
|
|
155
199
|
|
|
156
200
|
```ts
|
|
157
|
-
theme.json()
|
|
201
|
+
theme.json();
|
|
158
202
|
// → {
|
|
159
|
-
// surface: { light: '
|
|
160
|
-
// text: { light: '
|
|
203
|
+
// surface: { light: 'oklch(...)', dark: 'oklch(...)' },
|
|
204
|
+
// text: { light: 'oklch(...)', dark: 'oklch(...)' },
|
|
161
205
|
// }
|
|
162
206
|
```
|
|
163
207
|
|
|
@@ -170,8 +214,8 @@ CSS custom property declaration strings, grouped by scheme variant.
|
|
|
170
214
|
```ts
|
|
171
215
|
theme.css();
|
|
172
216
|
// → {
|
|
173
|
-
// light: '--surface-color:
|
|
174
|
-
// dark: '--surface-color:
|
|
217
|
+
// light: '--surface-color: oklch(...);\n--text-color: oklch(...);',
|
|
218
|
+
// dark: '--surface-color: oklch(...);\n--text-color: oklch(...);',
|
|
175
219
|
// lightContrast: '...',
|
|
176
220
|
// darkContrast: '...',
|
|
177
221
|
// }
|
|
@@ -179,23 +223,188 @@ theme.css();
|
|
|
179
223
|
|
|
180
224
|
`GlazeCssOptions`:
|
|
181
225
|
|
|
182
|
-
| Option
|
|
183
|
-
|
|
184
|
-
| `format`
|
|
185
|
-
| `suffix`
|
|
226
|
+
| Option | Default | Description |
|
|
227
|
+
| ---------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
228
|
+
| `format` | `'oklch'` | Output color format. One of `'rgb' \| 'hsl' \| 'oklch'`. `'okhsl'` and `'okhst'` throw — use `tasty()` for those. |
|
|
229
|
+
| `suffix` | `'-color'` | Suffix appended to each CSS property name. Pass `''` for bare property names. |
|
|
230
|
+
| `splitHue` | `false` | Emit hue as a separate `--*-hue` custom property referenced via `var()` in `oklch` color values. Requires `format: 'oklch'` and every color to be pastel. Shadow/mix colors stay inline (blended hue; they do not follow `--hue` rotation). |
|
|
231
|
+
| `name` | `'theme'` | Base name for the theme-level hue var (`--theme-hue`). Palette export auto-derives this from the theme name. |
|
|
186
232
|
|
|
187
233
|
`GlazeCssResult` always contains all four keys (`light`, `dark`, `lightContrast`, `darkContrast`); empty if no colors are defined for that variant.
|
|
188
234
|
|
|
189
|
-
### `theme.
|
|
235
|
+
### `theme.dtcg(options?)`
|
|
236
|
+
|
|
237
|
+
W3C [Design Tokens Format Module (2025.10)](https://www.designtokens.org/) documents — the vendor-neutral JSON format consumed by Figma, Tokens Studio, Style Dictionary v4+, Terrazzo, Penpot, and every DTCG-compatible tool. Returns one spec-conformant token tree per scheme variant.
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
theme.dtcg();
|
|
241
|
+
// → {
|
|
242
|
+
// light: {
|
|
243
|
+
// surface: {
|
|
244
|
+
// $type: 'color',
|
|
245
|
+
// $value: { colorSpace: 'srgb', components: [0.96, 0.94, 0.98], hex: '#f5f0fa' },
|
|
246
|
+
// },
|
|
247
|
+
// },
|
|
248
|
+
// dark: {
|
|
249
|
+
// surface: {
|
|
250
|
+
// $type: 'color',
|
|
251
|
+
// $value: { colorSpace: 'srgb', components: [0.16, 0.14, 0.2], hex: '#292333' },
|
|
252
|
+
// },
|
|
253
|
+
// },
|
|
254
|
+
// }
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Write each document to its own `.tokens.json` file — one file per scheme is the most tool-compatible convention (one per Style Dictionary theme / Tokens Studio set / Figma variable mode).
|
|
258
|
+
|
|
259
|
+
`GlazeDtcgOptions`:
|
|
260
|
+
|
|
261
|
+
| Option | Default | Description |
|
|
262
|
+
| ------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
263
|
+
| `colorSpace` | `'srgb'` | Color space for `$value`. `'srgb'` emits gamma sRGB `components` (0–1) plus a `hex` hint — universally understood. `'oklch'` emits `[L, C, H]` components with no hex — Glaze-native, wide-gamut. |
|
|
264
|
+
| `modes` | global config | Which scheme variants to include. `light` is always present. |
|
|
265
|
+
|
|
266
|
+
`alpha` is included on `$value` only when the color's opacity is below 1. `$type` is always `'color'`.
|
|
267
|
+
|
|
268
|
+
### `theme.dtcgResolver(options?)`
|
|
269
|
+
|
|
270
|
+
A single W3C [DTCG Resolver-Module](https://www.designtokens.org/) document describing **every scheme variant in one file** — an alternative to `dtcg()`'s per-scheme files for tools that resolve sets + modifiers (e.g. Dispersa). The light document becomes `sets.base.sources[0]` (the default context); each other variant becomes a context override on a single `scheme` modifier.
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
theme.dtcgResolver({ modes: { highContrast: true } });
|
|
274
|
+
// → {
|
|
275
|
+
// version: '2025.10',
|
|
276
|
+
// sets: {
|
|
277
|
+
// base: {
|
|
278
|
+
// sources: [
|
|
279
|
+
// {
|
|
280
|
+
// surface: {
|
|
281
|
+
// $type: 'color',
|
|
282
|
+
// $value: { colorSpace: 'srgb', components: [0.96, 0.94, 0.98], hex: '#f5f0fa' },
|
|
283
|
+
// },
|
|
284
|
+
// },
|
|
285
|
+
// ],
|
|
286
|
+
// },
|
|
287
|
+
// },
|
|
288
|
+
// modifiers: {
|
|
289
|
+
// scheme: {
|
|
290
|
+
// default: 'light',
|
|
291
|
+
// contexts: {
|
|
292
|
+
// light: [],
|
|
293
|
+
// dark: [
|
|
294
|
+
// {
|
|
295
|
+
// surface: {
|
|
296
|
+
// $type: 'color',
|
|
297
|
+
// $value: { colorSpace: 'srgb', components: [0.16, 0.14, 0.2], hex: '#292333' },
|
|
298
|
+
// },
|
|
299
|
+
// },
|
|
300
|
+
// ],
|
|
301
|
+
// lightContrast: [ /* … */ ],
|
|
302
|
+
// darkContrast: [ /* … */ ],
|
|
303
|
+
// },
|
|
304
|
+
// },
|
|
305
|
+
// },
|
|
306
|
+
// resolutionOrder: [
|
|
307
|
+
// { $ref: '#/sets/base' },
|
|
308
|
+
// { $ref: '#/modifiers/scheme' },
|
|
309
|
+
// ],
|
|
310
|
+
// }
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
**Why one modifier with four contexts.** Glaze resolves `darkContrast` independently — it is not `dark` + `lightContrast` layered. The resolver model composes modifiers additively (last in `resolutionOrder` wins on conflict), so two independent modifiers (`scheme` × `contrast`) would produce wrong values for the dark + high-contrast permutation. One `scheme` modifier with a context per variant keeps every resolved value exact. Choose `dtcgResolver()` when you want single-file theming and feed it to a resolver tool; choose `dtcg()` for maximum per-file tool compatibility.
|
|
314
|
+
|
|
315
|
+
`GlazeDtcgResolverOptions` (extends `GlazeDtcgOptions`, so `modes` and `colorSpace` pass through):
|
|
316
|
+
|
|
317
|
+
| Option | Default | Description |
|
|
318
|
+
| -------------- | ------------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
319
|
+
| `colorSpace` | `'srgb'` | Same as `dtcg()` — flows through to every source and context. |
|
|
320
|
+
| `modes` | global config | Which scheme variants to emit as contexts. `light` is always present (the default); absent variants are omitted. |
|
|
321
|
+
| `setName` | `'base'` | Name of the single set holding the default (light) token tree. |
|
|
322
|
+
| `modifierName` | `'scheme'` | Name of the modifier describing the scheme axis. |
|
|
323
|
+
| `contextNames` | identity | Override the four context names (`light` / `dark` / `lightContrast` / `darkContrast`) — e.g. `{ dark: 'night' }`. |
|
|
324
|
+
| `version` | `'2025.10'` | Resolver document version. |
|
|
325
|
+
|
|
326
|
+
### `theme.tailwind(options?)`
|
|
327
|
+
|
|
328
|
+
A Tailwind CSS v4 `@theme` block (light baseline) plus dark / high-contrast overrides under configurable selectors. Returns a single ready-to-paste CSS string. The `--color-*` namespace auto-generates `bg-*` / `text-*` / `border-*` utilities.
|
|
329
|
+
|
|
330
|
+
```css
|
|
331
|
+
@theme {
|
|
332
|
+
--color-surface: oklch(0.96 0.01 280);
|
|
333
|
+
--color-text: oklch(0.3 0.05 280);
|
|
334
|
+
}
|
|
335
|
+
.dark {
|
|
336
|
+
--color-surface: oklch(0.16 0.01 280);
|
|
337
|
+
--color-text: oklch(0.85 0.05 280);
|
|
338
|
+
}
|
|
339
|
+
.high-contrast {
|
|
340
|
+
--color-surface: oklch(0.98 0.01 280);
|
|
341
|
+
--color-text: oklch(0.1 0.05 280);
|
|
342
|
+
}
|
|
343
|
+
.dark.high-contrast {
|
|
344
|
+
--color-surface: oklch(0.05 0.01 280);
|
|
345
|
+
--color-text: oklch(0.95 0.05 280);
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
`GlazeTailwindOptions`:
|
|
350
|
+
|
|
351
|
+
| Option | Default | Description |
|
|
352
|
+
| ---------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
353
|
+
| `format` | `'oklch'` | Output color format for the values. |
|
|
354
|
+
| `namespace` | `'color-'` | CSS custom property namespace, forming `--<namespace><name>` (e.g. `--color-surface`). Named `namespace` to avoid clashing with the palette theme-prefix option. |
|
|
355
|
+
| `darkSelector` | `'.dark'` | Selector wrapping the dark overrides. Pass an at-rule like `'@media (prefers-color-scheme: dark)'` to drive dark mode from the OS preference (it nests `:root` automatically). |
|
|
356
|
+
| `highContrastSelector` | `'.high-contrast'` | Selector wrapping the light high-contrast overrides. The combined dark + high-contrast block uses `${darkSelector}${highContrastSelector}` (e.g. `.dark.high-contrast`). |
|
|
357
|
+
| `modes` | global config | Which scheme variants to include. The `@theme` block (light) is always emitted when colors exist. |
|
|
358
|
+
|
|
359
|
+
### `theme.export(override?)`
|
|
190
360
|
|
|
191
361
|
```ts
|
|
192
362
|
const snapshot = theme.export();
|
|
193
|
-
// → {
|
|
363
|
+
// → {
|
|
364
|
+
// kind: 'theme',
|
|
365
|
+
// version: 1,
|
|
366
|
+
// hue: 280,
|
|
367
|
+
// saturation: 80,
|
|
368
|
+
// colors: { surface: { ... }, ... },
|
|
369
|
+
// config: { lightTone: {...}, darkTone: {...}, pastel: false, ... },
|
|
370
|
+
// }
|
|
371
|
+
|
|
372
|
+
const restored = glaze.themeFrom(snapshot);
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Returns a deep-cloned, JSON-safe authoring snapshot (definitions + frozen
|
|
376
|
+
effective config — not resolved color strings). Freezes
|
|
377
|
+
`getConfig() ∪ instance local ∪ override` at call time. Restored themes pin
|
|
378
|
+
that freeze as their local override. Distinct from `theme.json()`, which
|
|
379
|
+
emits resolved color strings.
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## High-contrast pairs
|
|
384
|
+
|
|
385
|
+
`HCPair<T>` means either one value used in both ordinary and high-contrast
|
|
386
|
+
schemes, or an explicit `[normal, highContrast]` pair:
|
|
194
387
|
|
|
195
|
-
|
|
388
|
+
```ts
|
|
389
|
+
type HCPair<T> = T | [T, T];
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
It is used by `tone`, `contrast`, shadow `intensity`, and mix `value`:
|
|
393
|
+
|
|
394
|
+
```ts
|
|
395
|
+
tone: '-8'; // -8 in normal and HC
|
|
396
|
+
tone: ['-8', '-16']; // -8 normal, -16 HC
|
|
397
|
+
contrast: {
|
|
398
|
+
apca: 'content';
|
|
399
|
+
} // preset with automatic HC enhancement
|
|
400
|
+
contrast: {
|
|
401
|
+
apca: ['content', 'body'];
|
|
402
|
+
} // explicit normal/HC targets
|
|
196
403
|
```
|
|
197
404
|
|
|
198
|
-
|
|
405
|
+
For `contrast`, the pair may wrap the whole spec or live inside the selected
|
|
406
|
+
metric. An explicit HC value disables automatic APCA enhancement or WCAG preset
|
|
407
|
+
promotion for that color.
|
|
199
408
|
|
|
200
409
|
---
|
|
201
410
|
|
|
@@ -209,88 +418,288 @@ type ColorDef = RegularColorDef | ShadowColorDef | MixColorDef;
|
|
|
209
418
|
|
|
210
419
|
### `RegularColorDef`
|
|
211
420
|
|
|
212
|
-
| Field
|
|
213
|
-
|
|
214
|
-
| `
|
|
215
|
-
| `saturation` | `number`
|
|
216
|
-
| `hue`
|
|
217
|
-
| `
|
|
218
|
-
| `
|
|
219
|
-
| `
|
|
220
|
-
| `
|
|
221
|
-
| `
|
|
421
|
+
| Field | Type | Description |
|
|
422
|
+
| ------------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
423
|
+
| `tone` | `HCPair<ToneValue>` | Number = absolute (0–100). `'+N'`/`'-N'` = a signed **tone delta** from the base (requires `base`). `'max'`/`'min'` = forced to the scheme's tone extreme (no `base`). Optional HC pair `[normal, hc]`. |
|
|
424
|
+
| `saturation` | `number` | Saturation factor applied to the seed saturation (0–1). Default: `1`. |
|
|
425
|
+
| `hue` | `number \| RelativeValue` | Number = absolute (0–360). String (`'+N'`/`'-N'`) = relative to the **theme seed hue** (never to a base color). |
|
|
426
|
+
| `darkHue` | `number \| RelativeValue` | Dark-scheme hue. Number = absolute (0–360). String = relative to the **theme dark seed hue**. Falls back to `hue`. See [Dark seed](#dark-seed-darkhue--darksaturation). |
|
|
427
|
+
| `darkSaturation` | `number` | Dark-scheme saturation factor (0–1) over the dark seed saturation. Falls back to `saturation`. When set, the global `darkDesaturation` reduction is **not** applied on top. |
|
|
428
|
+
| `base` | `string` | Name of another color in the same theme — makes this a _dependent_ color. |
|
|
429
|
+
| `contrast` | `HCPair<ContrastSpec>` | Contrast floor against `base`. Requires `base`. See [`contrast`](#contrast-floor). |
|
|
430
|
+
| `mode` | `'auto' \| 'fixed' \| 'static'` | Adaptation mode. Default: `'auto'`. See [Adaptation modes](#adaptation-modes). |
|
|
431
|
+
| `autoFlip` | `boolean` | Flip out-of-bounds results (relative `tone` overshoot / unmet `contrast`) to the opposite side instead of clamping. Default: the global `autoFlip` (`true`). See [`autoFlip`](#autoflip). |
|
|
432
|
+
| `opacity` | `number` | Fixed alpha 0–1. Output includes alpha in the CSS value. Combining with `contrast` is not recommended (a `console.warn` is emitted). |
|
|
433
|
+
| `pastel` | `boolean` | Per-color override for the hue-independent "safe" chroma limit used in OKHSL↔sRGB conversions (luminance, contrast solving, output formatting). Falls through to the per-theme / per-token `pastel` override when omitted. Default: unset. See [Per-color `pastel`](#per-color-pastel). |
|
|
434
|
+
| `role` | `RoleInput` | Semantic role against `base` (`'text'` / `'surface'` / `'border'` or an alias). Fixes APCA contrast polarity. Resolved via: explicit `role` → name inference → opposite of the base's role → `'text'`. See [Roles](#roles). |
|
|
435
|
+
| `inherit` | `boolean` | Whether this color is inherited by child themes via `extend()`. Default: `true`. Set to `false` to make the color local to the current theme. |
|
|
436
|
+
|
|
437
|
+
#### Tone values
|
|
438
|
+
|
|
439
|
+
`tone` (0–100) replaces authored OKHSL lightness with a contrast-shaped axis.
|
|
440
|
+
Equal tone differences give equal WCAG contrast for neutrals; chromatic results
|
|
441
|
+
can drift in measured luminance. See [OKHST in Glaze](okhst.md). To port old
|
|
442
|
+
`lightness` values, see [migration.md](migration.md).
|
|
443
|
+
|
|
444
|
+
| Form | Example | Meaning |
|
|
445
|
+
| ------------------- | ----------------------- | --------------------------------------------------------------------------------------------- |
|
|
446
|
+
| Number (absolute) | `tone: 45` | Absolute tone 0–100. |
|
|
447
|
+
| String (tone delta) | `tone: '-52'` | Signed difference from the base color's resolved tone (requires `base`). |
|
|
448
|
+
| Extreme | `tone: 'max'` / `'min'` | Force to the scheme's highest (`'max'` = 100) or lowest (`'min'` = 0) tone. With a `base`, the light-scheme shift is replayed in dark. No `base` needed. |
|
|
449
|
+
| HC pair | `tone: ['-7', '-20']` | `[normal, high-contrast]`. A single value applies to both. |
|
|
450
|
+
|
|
451
|
+
**Absolute tone** on a dependent color (`base` set) positions the color independently. In dark mode it is tone-mapped (inverted + windowed) on its own. The `contrast` solver acts as a safety net.
|
|
452
|
+
|
|
453
|
+
**A tone delta** applies a signed difference to the base color's resolved tone.
|
|
454
|
+
It gives an exact contrast step for neutrals and a stable visual progression for
|
|
455
|
+
chromatic colors. In dark mode with `mode: 'auto'`, it is anchored to the
|
|
456
|
+
base's per-scheme tone. If `base + delta` falls outside `[0, 100]`, the result
|
|
457
|
+
is clamped to the boundary, or — with `autoFlip` (default on) — mirrored to the
|
|
458
|
+
other side of the base. If the mirrored target is also out of range, the original
|
|
459
|
+
delta is kept and clamped on the authored side.
|
|
460
|
+
|
|
461
|
+
**Extreme tone** (`'max'` / `'min'`) forces the color to the scheme's tone extreme without a contrast hack or a magic number. `'max'` resolves to author tone 100 and `'min'` to 0. Without a `base`, both flow through scheme mapping like an absolute tone, so under `mode: 'auto'` they invert in dark (`'max'` is lightest in light, darkest in dark). Use `mode: 'static'` to pin the same extreme across schemes, or `mode: 'fixed'` to keep the same end without inverting. No `base` required.
|
|
462
|
+
|
|
463
|
+
**Extreme tone with a `base`** keeps the pair's contrast across schemes. The tone windows are asymmetric by default (`lightTone: [10, 100]`, `darkTone: [15, 95]`), so re-mapping the extreme through the dark window would squeeze the base-to-extreme span and cost contrast. Instead Glaze measures the tone shift the light scheme applied between the base and the extreme, then replays it against the base's resolved dark tone — mirrored under `mode: 'auto'` (both ends invert), same-signed under `'fixed'`. The result is clamped to `[0, 100]` only, so it may cross the `darkTone` window edge; that is intentional, since the author asked for the extreme. When the shift does not fit above or below the dark base, the color pins at tone 100 / 0. `mode: 'static'` is unaffected, and high-contrast variants already use the full range.
|
|
222
464
|
|
|
223
|
-
|
|
465
|
+
```ts
|
|
466
|
+
theme.colors({
|
|
467
|
+
bg: { tone: 60 },
|
|
468
|
+
fg: { base: 'bg', tone: 'max' },
|
|
469
|
+
});
|
|
470
|
+
// light: bg 62.0, fg 100.0 — shift +38.0, contrast 3.18:1
|
|
471
|
+
// dark: bg 43.9, fg 5.9 — shift -38.0, contrast 3.18:1
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
A dependent color with `base` but no `tone` inherits the base's tone (equivalent to a delta of 0).
|
|
224
475
|
|
|
225
|
-
|
|
226
|
-
|---|---|---|
|
|
227
|
-
| Number (absolute) | `lightness: 45` | Absolute lightness 0–100. |
|
|
228
|
-
| String (relative) | `lightness: '-52'` | Relative to base color's lightness (requires `base`). |
|
|
229
|
-
| HC pair | `lightness: ['-7', '-20']` | `[normal, high-contrast]`. A single value applies to both. |
|
|
476
|
+
#### `autoFlip`
|
|
230
477
|
|
|
231
|
-
|
|
478
|
+
`autoFlip` governs what happens when a result would fall outside its valid range:
|
|
232
479
|
|
|
233
|
-
**Relative
|
|
480
|
+
- **Relative `tone` overshoot:** when `base ± delta` exceeds `[0, 100]`, `autoFlip` mirrors the delta to the other side of the base (e.g. `'+30'` becomes `'-30'`) instead of clamping to the boundary. If the mirrored target is also outside `[0, 100]`, the original delta is kept and clamped on the authored side.
|
|
481
|
+
- **`contrast` direction:** when the requested tone direction can't meet the floor, `autoFlip` lets the solver try the opposite side (the same behavior as the global `autoFlip`).
|
|
234
482
|
|
|
235
|
-
|
|
483
|
+
`autoFlip` defaults to the global `autoFlip` (`true`). Set `autoFlip: false` on a color to clamp instead of mirror — useful when you want a relative offset to stay on the authored side of the base, or to keep an unmet contrast pinned to one direction's extreme.
|
|
236
484
|
|
|
237
|
-
#### `contrast` (
|
|
485
|
+
#### `contrast` (floor)
|
|
238
486
|
|
|
239
487
|
```ts
|
|
240
|
-
type
|
|
488
|
+
type ContrastPreset = 'AA' | 'AAA' | 'AA-large' | 'AAA-large';
|
|
489
|
+
type ContrastSpec =
|
|
490
|
+
| number // bare WCAG ratio
|
|
491
|
+
| ContrastPreset // named WCAG preset
|
|
492
|
+
| { wcag: HCPair<number | ContrastPreset> }
|
|
493
|
+
| { apca: HCPair<number> }; // APCA Lc target
|
|
241
494
|
```
|
|
242
495
|
|
|
243
|
-
| Preset
|
|
244
|
-
|
|
245
|
-
| `'AA-large'`
|
|
246
|
-
| `'AA'`
|
|
247
|
-
| `'AAA-large'` | 4.5
|
|
248
|
-
| `'AAA'`
|
|
496
|
+
| Preset | WCAG ratio |
|
|
497
|
+
| ------------- | ---------- |
|
|
498
|
+
| `'AA-large'` | 3 |
|
|
499
|
+
| `'AA'` | 4.5 |
|
|
500
|
+
| `'AAA-large'` | 4.5 |
|
|
501
|
+
| `'AAA'` | 7 |
|
|
502
|
+
|
|
503
|
+
A bare number or preset means **WCAG**. Use `{ wcag }` / `{ apca }` to pick the metric explicitly. The `[normal, highContrast]` pair may live at the outer level (`[4.5, 7]`, `[{ wcag: 4.5 }, { wcag: 7 }]`) or inside the metric (`{ wcag: [4.5, 7] }`, `{ apca: [45, 60] }`).
|
|
504
|
+
|
|
505
|
+
```ts
|
|
506
|
+
contrast: 4.5; // WCAG 4.5
|
|
507
|
+
contrast: 'AAA'; // WCAG 7
|
|
508
|
+
contrast: {
|
|
509
|
+
wcag: 6;
|
|
510
|
+
} // WCAG 6
|
|
511
|
+
contrast: {
|
|
512
|
+
wcag: [4.5, 7];
|
|
513
|
+
} // WCAG 4.5 normal / 7 high-contrast (explicit)
|
|
514
|
+
contrast: {
|
|
515
|
+
apca: 60;
|
|
516
|
+
} // APCA Lc 60 normal / 75 high-contrast (auto)
|
|
517
|
+
contrast: {
|
|
518
|
+
apca: [45, 60];
|
|
519
|
+
} // APCA Lc 45 normal / 60 high-contrast (explicit)
|
|
520
|
+
contrast: {
|
|
521
|
+
apca: 'content';
|
|
522
|
+
} // APCA preset -> Lc 60 normal / 75 high-contrast (auto)
|
|
523
|
+
contrast: {
|
|
524
|
+
apca: ['content', 'body'];
|
|
525
|
+
} // Lc 60 normal / 75 high-contrast (explicit)
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
**WCAG HC auto-promotion:** a bare WCAG preset (no `[normal, hc]` pair at either
|
|
529
|
+
the outer `contrast` or inner `wcag` level) is automatically promoted to its
|
|
530
|
+
spec-defined "Enhanced" successor in high-contrast mode — `AA` → `AAA` (4.5 → 7)
|
|
531
|
+
and `AA-large` → `AAA-large` (3 → 4.5), per WCAG SC 1.4.3 → 1.4.6. `AAA` and
|
|
532
|
+
`AAA-large` are already the top WCAG tier and are left unchanged; bare numeric
|
|
533
|
+
targets have no successor tier and are also left unchanged. An explicit HC value
|
|
534
|
+
via either pair overrides and skips the promotion.
|
|
535
|
+
|
|
536
|
+
**APCA Enhanced Level (HC auto-boost):** a bare APCA scalar (no `[normal, hc]`
|
|
537
|
+
pair at either the outer `contrast` or inner `apca` level) is automatically
|
|
538
|
+
boosted by **+15 Lc** in high-contrast mode, the APCA analog of WCAG's
|
|
539
|
+
AAA-over-AA step. On by default; an explicit HC value via either pair
|
|
540
|
+
overrides it and skips the boost. The enhanced target is clamped to 106 Lc.
|
|
541
|
+
For large/bold text (where APCA caps contrast at Lc 90 to avoid glare), pass
|
|
542
|
+
an explicit HC pair to hold that ceiling.
|
|
249
543
|
|
|
250
|
-
|
|
544
|
+
APCA preset keywords (Bronze Simple Mode conformance levels, role-independent):
|
|
545
|
+
`'preferred'` (Lc 90), `'body'` (75), `'content'` (60, ~AA), `'large'` (45, ~3:1),
|
|
546
|
+
`'non-text'` (30), `'min'` (15, point of invisibility).
|
|
251
547
|
|
|
252
|
-
|
|
548
|
+
The floor is applied independently per scheme. If the preferred `tone` already
|
|
549
|
+
satisfies it, the tone is kept; otherwise the solver uses the tone-shaped scale
|
|
550
|
+
for a closed-form WCAG seed and fast search until the target is met.
|
|
253
551
|
|
|
254
|
-
|
|
552
|
+
By default, the solver crosses to the opposite side of the base color when the requested tone direction cannot satisfy the floor. This is controlled per-color by [`autoFlip`](#autoflip) (which defaults to the global `autoFlip`). Set `glaze.configure({ autoFlip: false })` — or `autoFlip: false` on a single color — to keep strict directionality: unmet colors pin to that direction's 0 or 100 tone extreme instead of falling back to the original requested value.
|
|
553
|
+
|
|
554
|
+
**Full tone spectrum in HC mode:** in high-contrast variants the `lightTone` and `darkTone` window constraints are bypassed entirely (the window is forced to `[0, 100]`). Colors can reach the full range, maximizing perceivable contrast.
|
|
555
|
+
|
|
556
|
+
**Chromatic drift (verification):** tone is contrast-uniform for grays. A chromatic swatch at a given tone shares its OKHSL lightness with the equivalent gray but drifts in real luminance, so a contrast-floored color may land slightly under its gray-tone expectation. Glaze measures the resolved result against the base and emits a deduped advisory `console.warn` when it drifts below the target. See [Contrast verification](okhst.md#contrast-verification).
|
|
255
557
|
|
|
256
558
|
#### Per-color hue override
|
|
257
559
|
|
|
258
560
|
```ts
|
|
259
561
|
const theme = glaze(280, 80);
|
|
260
562
|
theme.colors({
|
|
261
|
-
surface:
|
|
262
|
-
gradientEnd: {
|
|
263
|
-
warning:
|
|
563
|
+
surface: { tone: 97 },
|
|
564
|
+
gradientEnd: { tone: 90, hue: '+20' }, // 280 + 20 = 300
|
|
565
|
+
warning: { tone: 60, hue: 40 }, // absolute
|
|
264
566
|
});
|
|
265
567
|
```
|
|
266
568
|
|
|
267
569
|
Relative hue is always relative to the **theme seed hue**, not to a base color.
|
|
268
570
|
|
|
571
|
+
#### Dark seed (`darkHue` / `darkSaturation`)
|
|
572
|
+
|
|
573
|
+
Tone inverts automatically between light and dark, but hue and saturation do
|
|
574
|
+
not — by default every scheme reuses the one seed, with dark getting a flat
|
|
575
|
+
`darkDesaturation` haircut. When a palette needs a genuinely different chroma in
|
|
576
|
+
dark (a cooler accent, a calmer surface tint), author a second seed:
|
|
577
|
+
|
|
578
|
+
```ts
|
|
579
|
+
const theme = glaze({
|
|
580
|
+
hue: 280,
|
|
581
|
+
saturation: 80,
|
|
582
|
+
darkHue: 268, // dark schemes seed from 268 instead of 280
|
|
583
|
+
darkSaturation: 65, // and from 65 instead of 80
|
|
584
|
+
});
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
Individual colors can override either channel for dark on their own:
|
|
588
|
+
|
|
589
|
+
```ts
|
|
590
|
+
theme.colors({
|
|
591
|
+
surface: { tone: 97 },
|
|
592
|
+
accent: { tone: 55, hue: '+20', darkHue: '+35' },
|
|
593
|
+
warning: { tone: 60, saturation: 0.9, darkSaturation: 0.6 },
|
|
594
|
+
});
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
Both apply to the `dark` **and** `darkContrast` variants. The rules:
|
|
598
|
+
|
|
599
|
+
| Rule | Behavior |
|
|
600
|
+
| ---- | -------- |
|
|
601
|
+
| Units | Seed-level `darkSaturation` is `0–100` (like `saturation` on the theme). Def-level `darkSaturation` is a `0–1` factor (like `saturation` on a color def). |
|
|
602
|
+
| Fallback | `darkHue` falls back to `hue`, `darkSaturation` to `saturation`, and the def falls back to the seed. Omitting everything reproduces the previous behavior exactly. |
|
|
603
|
+
| Relative hue | `darkHue: '+N'` anchors to the theme's **dark** seed hue. A plain `hue: '+N'` with no `darkHue` also re-anchors to the dark seed, so a whole palette rotates together. |
|
|
604
|
+
| Absolute hue | An absolute `hue` (no `darkHue`) is used verbatim in dark — absolute means absolute in every scheme. |
|
|
605
|
+
| `darkDesaturation` | Bypassed as soon as any explicit dark saturation is authored, at either level. The value you write is the value you get. |
|
|
606
|
+
| `mode: 'static'` | Ignores both. A static color is pinned to one hue and saturation across every scheme. |
|
|
607
|
+
| Shadows and mixes | Have no channels of their own — they derive hue and saturation from their `bg` / `fg` / `target`, so they inherit dark overrides automatically. |
|
|
608
|
+
|
|
609
|
+
With [`splitHue`](#hue-channel-splitting-splithue), a dark seed makes the hue
|
|
610
|
+
custom properties scheme-dependent; Glaze re-declares them in the dark block
|
|
611
|
+
automatically.
|
|
612
|
+
|
|
613
|
+
#### Per-color `pastel`
|
|
614
|
+
|
|
615
|
+
`pastel: true` on a single color def overrides the per-theme / per-token `pastel` override for that color only. It toggles the hue-independent "safe" chroma limit used in every OKHSL↔sRGB conversion that touches this color: luminance calculations during contrast solving, gamut clamping during sRGB blend / mix edges, and output formatting. The effective flag is carried on the resolved variant (`ResolvedColorVariant.pastel`) so formatting matches the gamut mapping applied during resolution.
|
|
616
|
+
|
|
617
|
+
```ts
|
|
618
|
+
const theme = glaze(280, 80);
|
|
619
|
+
theme.colors({
|
|
620
|
+
plain: { tone: 50, saturation: 1 },
|
|
621
|
+
soft: { tone: 50, saturation: 1, pastel: true },
|
|
622
|
+
});
|
|
623
|
+
// theme.resolve().get('soft')!.light.pastel === true
|
|
624
|
+
// theme.css().light contains different rgb() triples for `--plain` and `--soft`
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
Omit the field to inherit the theme/token `pastel` override (default `false`) — useful for keeping the default behavior while opting a single accent into the pastel gamut.
|
|
628
|
+
|
|
629
|
+
The flag is part of the def object, so `extend()` copies it through to child themes alongside the rest of the def. Override it again on the child to flip a single color back:
|
|
630
|
+
|
|
631
|
+
```ts
|
|
632
|
+
const parent = glaze(280, 80);
|
|
633
|
+
parent.colors({ soft: { tone: 50, saturation: 1, pastel: true } });
|
|
634
|
+
|
|
635
|
+
const child = parent.extend({
|
|
636
|
+
colors: { soft: { tone: 50, saturation: 1, pastel: false } },
|
|
637
|
+
});
|
|
638
|
+
// child.resolve().get('soft')!.light.pastel === false
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
> **Note:** Per-color `pastel` is also supported on `ShadowColorDef` and `MixColorDef` (see the tables above). For shadows the math itself happens in OKHSL space, so the flag mainly controls the gamut-mapped output formatting and any luminance verification for that variant.
|
|
642
|
+
>
|
|
643
|
+
> Standalone `glaze.color()` tokens accept the same `pastel` field on both the structured (`GlazeColorInput`) and value-shorthand (`GlazeColorOverrides`) forms, and it survives the `export()` / `glaze.colorFrom()` round-trip.
|
|
644
|
+
|
|
645
|
+
#### Roles
|
|
646
|
+
|
|
647
|
+
A color's `role` describes how it is used against its `base` and fixes **APCA contrast polarity** — which side is the foreground vs the background. APCA is asymmetric (`|apca(a,b)| ≠ |apca(b,a)|`), so the role picks the correct argument order; WCAG is symmetric and unaffected.
|
|
648
|
+
|
|
649
|
+
| Role | Polarity | Use | Aliases (name inference) |
|
|
650
|
+
| ----------- | -------- | ---------------------------------------------------- | ----------------------------------------------------------------- |
|
|
651
|
+
| `'text'` | fg | Text / icons / foreground content | `text`, `fg`, `foreground`, `content`, `ink`, `label`, `stroke` |
|
|
652
|
+
| `'border'` | fg | Non-text spot elements (borders, dividers, outlines) | `border`, `divider`, `outline`, `separator`, `hairline`, `rule` |
|
|
653
|
+
| `'surface'` | bg | Backgrounds / fills | `surface`, `bg`, `background`, `fill`, `canvas`, `paper`, `layer` |
|
|
654
|
+
|
|
655
|
+
Resolution chain (per color):
|
|
656
|
+
|
|
657
|
+
1. Explicit `role` (normalized from an alias) wins.
|
|
658
|
+
2. Else, when `inferRole` is enabled (default), infer from the color name — the **last** recognized token wins (`button-text` → `text`, `input-bg` → `surface`, `card-outline` → `border`).
|
|
659
|
+
3. Else, the opposite of the base's role (a `surface` base ⇒ this is `text`).
|
|
660
|
+
4. Else, `'text'` (foreground) — i.e. the base is treated as the background.
|
|
661
|
+
|
|
662
|
+
```ts
|
|
663
|
+
const theme = glaze(280, 60);
|
|
664
|
+
theme.colors({
|
|
665
|
+
surface: { tone: 90 },
|
|
666
|
+
text: { base: 'surface', contrast: { apca: 'content' } }, // inferred text
|
|
667
|
+
border: { base: 'surface', tone: '-10' }, // inferred border
|
|
668
|
+
});
|
|
669
|
+
// role fixes APCA polarity; set `pastel: true` explicitly if a border
|
|
670
|
+
// needs the hue-independent safe chroma limit.
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
Disable name inference with `glaze.configure({ inferRole: false })` (the base-opposite and foreground-default fallbacks still apply).
|
|
674
|
+
|
|
269
675
|
### `ShadowColorDef`
|
|
270
676
|
|
|
271
|
-
| Field
|
|
272
|
-
|
|
273
|
-
| `type`
|
|
274
|
-
| `bg`
|
|
275
|
-
| `fg`
|
|
276
|
-
| `intensity` | `HCPair<number>` | Shadow intensity, 0–100. Supports HC pairs.
|
|
277
|
-
| `tuning`
|
|
278
|
-
| `
|
|
677
|
+
| Field | Type | Description |
|
|
678
|
+
| ----------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
679
|
+
| `type` | `'shadow'` | Discriminator. |
|
|
680
|
+
| `bg` | `string` | Background color name — must reference a non-shadow color in the same theme. |
|
|
681
|
+
| `fg` | `string` | Optional foreground color name for tinting and intensity modulation. Must reference a non-shadow color. Omit for an achromatic shadow at full user-specified intensity. |
|
|
682
|
+
| `intensity` | `HCPair<number>` | Shadow intensity, 0–100. Supports HC pairs. |
|
|
683
|
+
| `tuning` | `ShadowTuning` | Per-color tuning overrides. Merged field-by-field with the global `shadowTuning`. |
|
|
684
|
+
| `pastel` | `boolean` | Per-color `pastel` override. See [Per-color `pastel`](#per-color-pastel). |
|
|
685
|
+
| `inherit` | `boolean` | Inheritance flag, default `true`. |
|
|
279
686
|
|
|
280
687
|
See [Shadows](#shadows) below for the algorithm and tuning details.
|
|
281
688
|
|
|
282
689
|
### `MixColorDef`
|
|
283
690
|
|
|
284
|
-
| Field
|
|
285
|
-
|
|
286
|
-
| `type`
|
|
287
|
-
| `base`
|
|
288
|
-
| `target`
|
|
289
|
-
| `value`
|
|
290
|
-
| `blend`
|
|
291
|
-
| `space`
|
|
292
|
-
| `contrast` | `HCPair<
|
|
293
|
-
| `
|
|
691
|
+
| Field | Type | Description |
|
|
692
|
+
| ---------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
693
|
+
| `type` | `'mix'` | Discriminator. |
|
|
694
|
+
| `base` | `string` | "From" color name. |
|
|
695
|
+
| `target` | `string` | "To" color name. |
|
|
696
|
+
| `value` | `HCPair<number>` | Mix ratio 0–100 (0 = pure base, 100 = pure target). In `'transparent'` blend, this becomes the target's opacity. Supports HC pairs. |
|
|
697
|
+
| `blend` | `'opaque' \| 'transparent'` | Default `'opaque'`. |
|
|
698
|
+
| `space` | `'okhsl' \| 'srgb'` | Interpolation space for opaque blending. Default `'okhsl'`. Ignored for `'transparent'` (always composites in linear sRGB). |
|
|
699
|
+
| `contrast` | `HCPair<ContrastSpec>` | Optional contrast floor against `base` (WCAG or APCA — see [`contrast`](#contrast-floor)). The solver adjusts the mix ratio (opaque) or opacity (transparent). |
|
|
700
|
+
| `pastel` | `boolean` | Per-color `pastel` override. See [Per-color `pastel`](#per-color-pastel). |
|
|
701
|
+
| `role` | `RoleInput` | Semantic role of the mixed result against `base`. Same semantics as `RegularColorDef.role` (see [Roles](#roles)). |
|
|
702
|
+
| `inherit` | `boolean` | Inheritance flag, default `true`. |
|
|
294
703
|
|
|
295
704
|
See [Mix colors](#mix-colors) below.
|
|
296
705
|
|
|
@@ -310,130 +719,155 @@ glaze.color(color: GlazeFromInput | GlazeColorInput | GlazeColorValue, config?:
|
|
|
310
719
|
|
|
311
720
|
`glaze.color()` accepts **four input shapes**, discriminated by structure:
|
|
312
721
|
|
|
313
|
-
| Shape
|
|
314
|
-
|
|
315
|
-
| **Bare string**
|
|
316
|
-
| **Value object**
|
|
317
|
-
| **`{ from, ...overrides }`** | `{ from: '#1a1a2e', base: bg, contrast: 'AA' }` | Value + color overrides in one object.
|
|
318
|
-
| **Structured**
|
|
722
|
+
| Shape | Example | Notes |
|
|
723
|
+
| ---------------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------- |
|
|
724
|
+
| **Bare string** | `'#26fcb2'` | Hex or CSS color function (`rgb()`, `hsl()`, `okhsl()`, `okhst()`, `oklch()`). |
|
|
725
|
+
| **Value object** | `{ h: 152, s: 0.95, l: 0.74 }` | OKHSL, OKHST (`{ h, s, t }`), `{ r, g, b }` (sRGB 0–255), or `{ l, c, h }` (OKLCh). |
|
|
726
|
+
| **`{ from, ...overrides }`** | `{ from: '#1a1a2e', base: bg, contrast: 'AA' }` | Value + color overrides in one object. |
|
|
727
|
+
| **Structured** | `{ hue: 152, saturation: 95, tone: 74 }` | Full theme-style token (hue/saturation in 0–100, tone in 0–100). |
|
|
319
728
|
|
|
320
729
|
`GlazeColorValue` (bare string or value-object forms) accepts:
|
|
321
730
|
|
|
322
|
-
| Form
|
|
323
|
-
|
|
324
|
-
| Hex
|
|
325
|
-
| `rgb()`
|
|
326
|
-
| `hsl()`
|
|
327
|
-
| `okhsl()`
|
|
328
|
-
| `
|
|
329
|
-
| `
|
|
330
|
-
| `
|
|
331
|
-
| `
|
|
332
|
-
|
|
333
|
-
`
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
|
338
|
-
|
|
|
339
|
-
| `
|
|
340
|
-
| `
|
|
341
|
-
| `
|
|
342
|
-
| `
|
|
343
|
-
| `
|
|
344
|
-
| `
|
|
345
|
-
| `
|
|
731
|
+
| Form | Example | Notes |
|
|
732
|
+
| ------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
733
|
+
| Hex | `'#26fcb2'`, `'#26fcb2ff'`, `'#abc'` | 3, 6, or 8 digits. Alpha is dropped with a `console.warn` — use `opacity` instead. |
|
|
734
|
+
| `rgb()` | `'rgb(38 252 178)'`, `'rgb(38 252 178 / 0.8)'` | Modern space syntax. Alpha dropped with warning. |
|
|
735
|
+
| `hsl()` | `'hsl(152 97% 57%)'` | Modern space syntax. Alpha dropped with warning. |
|
|
736
|
+
| `okhsl()` | `'okhsl(152 95% 74%)'` | Glaze's own emit format. Alpha dropped with warning. |
|
|
737
|
+
| `okhst()` | `'okhst(152 95% 70%)'` | OKHST tone input (third value is tone 0–100). Not native CSS; it can also be serialized by [Tasty](https://tasty.style) exports. Alpha dropped with warning. |
|
|
738
|
+
| `oklch()` | `'oklch(0.85 0.18 152)'` | Glaze's own emit format. Alpha dropped with warning. |
|
|
739
|
+
| `OkhslColor` object | `{ h: 152, s: 0.95, l: 0.74 }` | OKHSL shape (h: 0–360, s/l: 0–1). Passing 0–100 for `s`/`l` throws with a hint to use the structured form. |
|
|
740
|
+
| `OkhstColor` object | `{ h: 152, s: 0.95, t: 0.70 }` | Direct OKHST input shape (h: 0–360, s/t: 0–1). The `t` key disambiguates it from `{ h, s, l }`. |
|
|
741
|
+
| `RgbColor` object | `{ r: 38, g: 252, b: 178 }` | sRGB 0–255. RGB tuple `[r, g, b]` is not supported — use this object form. |
|
|
742
|
+
| `OklchColor` object | `{ l: 0.85, c: 0.18, h: 152 }` | OKLCh (L/C: 0–1, H: degrees), same semantics as `oklch()` strings. |
|
|
743
|
+
|
|
744
|
+
`GlazeColorInput` (structured form) is `{ hue, saturation, tone, ... }`:
|
|
745
|
+
|
|
746
|
+
| Field | Type | Description |
|
|
747
|
+
| ------------------ | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
748
|
+
| `hue` | `number` | 0–360. |
|
|
749
|
+
| `saturation` | `number` | 0–100. |
|
|
750
|
+
| `tone` | `HCPair<number \| ExtremeValue>` | 0–100 (contrast-shaped) or `'max'`/`'min'`, optional HC pair. |
|
|
751
|
+
| `saturationFactor` | `number` | Multiplier on the seed (0–1). Default: `1`. |
|
|
752
|
+
| `darkHue` | `number \| RelativeValue` | Dark-scheme hue. Absolute (0–360) or `'+N'`/`'-N'` relative to the dark seed hue (which defaults to `hue`). Falls back to `hue`. |
|
|
753
|
+
| `darkSaturation` | `number` | Dark-scheme seed saturation (0–100). Falls back to `saturation`. |
|
|
754
|
+
| `darkSaturationFactor` | `number` | Dark-scheme multiplier on the dark seed (0–1). Falls back to `saturationFactor`. |
|
|
755
|
+
| `mode` | `AdaptationMode` | Default: `'auto'`. |
|
|
756
|
+
| `autoFlip` | `boolean` | Flip out-of-bounds results instead of clamping. Default: global `autoFlip`. |
|
|
757
|
+
| `opacity` | `number` | Fixed alpha 0–1. |
|
|
758
|
+
| `base` | `GlazeColorToken \| GlazeColorValue` | Optional dependency. See [Pairing colors](#pairing-colors). |
|
|
759
|
+
| `contrast` | `HCPair<ContrastSpec>` | Contrast floor against `base` (WCAG or APCA). Without `base`, anchored to the literal seed. |
|
|
760
|
+
| `pastel` | `boolean` | Per-color `pastel` override. Falls through to the per-theme / per-token `pastel` override when omitted. See [Per-color `pastel`](#per-color-pastel). |
|
|
761
|
+
| `role` | `RoleInput` | Semantic role against `base` / the seed (see [Roles](#roles)). Fixes APCA polarity. |
|
|
762
|
+
| `name` | `string` | Debug label for warnings; doesn't change output keys. Reserved names (`'value'`, `'seed'`, `'externalBase'`) are rejected. |
|
|
346
763
|
|
|
347
764
|
`GlazeFromInput` (from form) is `{ from: GlazeColorValue, ...colorOverrides }`:
|
|
348
765
|
|
|
349
|
-
| Field
|
|
350
|
-
|
|
351
|
-
| `from`
|
|
352
|
-
| `hue`
|
|
353
|
-
| `saturation`
|
|
354
|
-
| `
|
|
355
|
-
| `saturationFactor` | Multiplier on the seed (0–1).
|
|
356
|
-
| `
|
|
357
|
-
| `
|
|
358
|
-
| `
|
|
359
|
-
| `
|
|
360
|
-
| `
|
|
766
|
+
| Field | Notes |
|
|
767
|
+
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
768
|
+
| `from` | **Required.** The source color value — same forms as `GlazeColorValue`. |
|
|
769
|
+
| `hue` | Number (absolute 0–360) or `'+N'`/`'-N'` (relative to seed, never to `base`). |
|
|
770
|
+
| `saturation` | Override seed saturation (0–100). |
|
|
771
|
+
| `tone` | Number (absolute 0–100), `'+N'`/`'-N'`, or `'max'`/`'min'`. Without `base`, relative anchors to the seed; with `base`, anchors to `base`'s tone per scheme. |
|
|
772
|
+
| `saturationFactor` | Multiplier on the seed (0–1). |
|
|
773
|
+
| `darkHue` | Dark-scheme hue: absolute (0–360) or `'+N'`/`'-N'` relative to the dark seed hue. Falls back to `hue`. |
|
|
774
|
+
| `darkSaturation` | Dark-scheme seed saturation (0–100). Falls back to `saturation`. |
|
|
775
|
+
| `darkSaturationFactor` | Dark-scheme multiplier on the dark seed (0–1). Falls back to `saturationFactor`. |
|
|
776
|
+
| `mode` | `'auto'` (default) / `'fixed'` / `'static'`. |
|
|
777
|
+
| `autoFlip` | Flip out-of-bounds results instead of clamping. Default: global `autoFlip`. |
|
|
778
|
+
| `contrast` | Contrast floor (WCAG or APCA). Without `base`, anchored to the literal seed; with `base`, solved per scheme. |
|
|
779
|
+
| `base` | `GlazeColorToken` or raw `GlazeColorValue`. See [Pairing colors](#pairing-colors). |
|
|
780
|
+
| `opacity` | Fixed alpha 0–1. Combining with `contrast` is not recommended — `console.warn` is emitted. |
|
|
781
|
+
| `pastel` | Per-color `pastel` override. Falls through to the per-theme / per-token `pastel` override when omitted. See [Per-color `pastel`](#per-color-pastel). |
|
|
782
|
+
| `role` | Semantic role against `base` / the seed (see [Roles](#roles)). Fixes APCA polarity. |
|
|
783
|
+
| `name` | Debug label only — surfaces in warnings/errors. Does not change output keys. |
|
|
361
784
|
|
|
362
785
|
Named CSS colors (`'red'`, `'blueviolet'`) are not supported.
|
|
363
786
|
|
|
364
787
|
### Defaults
|
|
365
788
|
|
|
366
|
-
Every input form defaults to `mode: 'auto'` so the resolved token adapts between light and dark like an ordinary theme color.
|
|
789
|
+
Every input form defaults to `mode: 'auto'` so the resolved token adapts between light and dark like an ordinary theme color. Tokens store a **sparse local** config override; omitted fields fall through to the live global at resolve time (same as themes). Authoring `.export(override?)` freezes `getConfig() ∪ local ∪ override` at call time.
|
|
367
790
|
|
|
368
791
|
- **Value-shorthand** (bare strings, value objects, and `{ from, ...overrides }`):
|
|
369
|
-
- Light variant preserves the input
|
|
370
|
-
-
|
|
371
|
-
- **Structured input** (`{ hue, saturation,
|
|
372
|
-
-
|
|
373
|
-
-
|
|
792
|
+
- Light variant preserves the input tone exactly (`lightTone: false` as a local default).
|
|
793
|
+
- Other omitted fields track the live global config.
|
|
794
|
+
- **Structured input** (`{ hue, saturation, tone, ... }`):
|
|
795
|
+
- Omitted tone windows and other fields track the live global config (same as a theme color).
|
|
796
|
+
- `pastel` is instance-only — set via the config override or per-color `pastel`, not `glaze.configure()`.
|
|
374
797
|
|
|
375
798
|
```ts
|
|
376
799
|
// Bare string — adapts automatically
|
|
377
|
-
glaze.color('#26fcb2')
|
|
800
|
+
glaze.color('#26fcb2');
|
|
378
801
|
|
|
379
802
|
// Value-object — same behavior
|
|
380
|
-
glaze.color({ h: 152, s: 0.95, l: 0.74 })
|
|
803
|
+
glaze.color({ h: 152, s: 0.95, l: 0.74 });
|
|
804
|
+
|
|
805
|
+
// OKHST value-object — tone axis
|
|
806
|
+
glaze.color({ h: 152, s: 0.95, t: 0.7 });
|
|
381
807
|
|
|
382
808
|
// From form — value + color overrides
|
|
383
|
-
glaze.color({ from: '#1a1a2e', hue: '+20', contrast: 'AA' })
|
|
809
|
+
glaze.color({ from: '#1a1a2e', hue: '+20', contrast: 'AA' });
|
|
384
810
|
|
|
385
|
-
// Structured form — explicit hue/saturation/
|
|
386
|
-
glaze.color({ hue: 152, saturation: 95,
|
|
811
|
+
// Structured form — explicit hue/saturation/tone (0–100)
|
|
812
|
+
glaze.color({ hue: 152, saturation: 95, tone: 74 });
|
|
387
813
|
```
|
|
388
814
|
|
|
389
815
|
### Token methods
|
|
390
816
|
|
|
391
817
|
A `GlazeColorToken` exposes:
|
|
392
818
|
|
|
393
|
-
| Method
|
|
394
|
-
|
|
395
|
-
| `token.resolve()`
|
|
396
|
-
| `token.token(options?)`
|
|
397
|
-
| `token.tasty(options?)`
|
|
398
|
-
| `token.json(options?)`
|
|
819
|
+
| Method | Description |
|
|
820
|
+
| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
821
|
+
| `token.resolve()` | Resolve as a `ResolvedColor` (light/dark/lightContrast/darkContrast variants). |
|
|
822
|
+
| `token.token(options?)` | Flat token map (no color-name key). Options: `format`, `modes`, `states`. |
|
|
823
|
+
| `token.tasty(options?)` | [Tasty](https://tasty.style) state map (no color-name key). Same options as `token.token`. |
|
|
824
|
+
| `token.json(options?)` | JSON map (no color-name key). Options: `format`, `modes`. |
|
|
399
825
|
| `token.css({ name, format?, suffix? })` | CSS custom property declarations grouped by scheme variant. `name` is **required** and becomes the variable identifier (`'brand'` → `--brand-color`). Defaults: `format: 'rgb'`, `suffix: '-color'` (matches `theme.css`). |
|
|
400
|
-
| `token.
|
|
826
|
+
| `token.dtcg(options?)` | DTCG color tokens, one per scheme variant (no color-name key). Each entry is a full `{ $type: 'color', $value }` token. Options: `colorSpace` (`'srgb'` \| `'oklch'`), `modes`. |
|
|
827
|
+
| `token.dtcgResolver({ name, ... })` | A single DTCG Resolver-Module document for this color, keyed by `name` across all scheme variants. `name` is **required**. Same options as `theme.dtcgResolver()` plus `name`. |
|
|
828
|
+
| `token.tailwind({ name, ... })` | Tailwind v4 `@theme` block + dark / high-contrast overrides for this color. `name` is **required** (forms `--color-<name>`). Same options as `theme.tailwind()` plus `name`. |
|
|
829
|
+
| `token.export(override?)` | JSON-safe snapshot — freezes effective config at call time; pass to `glaze.colorFrom(...)` to rehydrate. Optional `override` merges over the instance local (and nested `base` exports). |
|
|
401
830
|
|
|
402
831
|
### Per-instance config override
|
|
403
832
|
|
|
404
|
-
The optional `config`
|
|
833
|
+
The optional `config` argument (`GlazeConfigOverride`) overrides
|
|
834
|
+
resolve-relevant fields for a token or theme. A tone window can be
|
|
835
|
+
`[lo, hi]`, `{ lo, hi, eps }`, or `false` (full range). Both themes and
|
|
836
|
+
standalone tokens keep a sparse local override — omitted fields (except
|
|
837
|
+
instance-only `pastel`) fall through to the live global at resolve time.
|
|
405
838
|
|
|
406
839
|
`GlazeConfigOverride`:
|
|
407
840
|
|
|
408
|
-
| Field
|
|
409
|
-
|
|
410
|
-
| `
|
|
411
|
-
| `
|
|
412
|
-
| `darkDesaturation` | `0.1`
|
|
413
|
-
| `
|
|
414
|
-
| `
|
|
415
|
-
| `
|
|
841
|
+
| Field | Default (from global / fixed) | Description |
|
|
842
|
+
| ------------------ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
843
|
+
| `lightTone` | `[10, 100]` | Light tone window: `[lo, hi]`, `{ lo, hi, eps }`, or `false` (disable clamping). |
|
|
844
|
+
| `darkTone` | `[15, 95]` | Dark tone window: `[lo, hi]`, `{ lo, hi, eps }`, or `false` (disable clamping). |
|
|
845
|
+
| `darkDesaturation` | `0.1` | Saturation reduction in dark scheme (0–1). |
|
|
846
|
+
| `autoFlip` | `true` | Default for each color's `autoFlip`: when solving `contrast` (or applying a relative `tone` that overshoots), allow crossing to the opposite side instead of clamping. |
|
|
847
|
+
| `pastel` | `false` (instance-only) | Theme/token-level pastel default for colors that omit per-color `pastel`. Not available on `glaze.configure()`. |
|
|
848
|
+
| `inferRole` | `true` | Infer color `role` from the name when unset. |
|
|
849
|
+
| `shadowTuning` | `undefined` | Default shadow tuning (meaningful for themes; harmless on color tokens). |
|
|
416
850
|
|
|
417
851
|
Config overrides apply to both `glaze.color()` tokens and `glaze()` themes:
|
|
418
852
|
|
|
419
853
|
```ts
|
|
420
|
-
// Standalone color — preserve raw
|
|
421
|
-
glaze.color('#26fcb2', {
|
|
854
|
+
// Standalone color — preserve raw tone in both schemes
|
|
855
|
+
glaze.color('#26fcb2', { darkTone: false });
|
|
422
856
|
|
|
423
857
|
// Restore the #000 → white dark flip (full dark range)
|
|
424
858
|
glaze.color('#000000', {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
})
|
|
859
|
+
lightTone: false,
|
|
860
|
+
darkTone: [15, 100],
|
|
861
|
+
});
|
|
428
862
|
|
|
429
863
|
// Structured form with config override
|
|
430
|
-
glaze.color({ hue: 152, saturation: 95,
|
|
864
|
+
glaze.color({ hue: 152, saturation: 95, tone: 74 }, { darkTone: false, pastel: true });
|
|
431
865
|
|
|
432
866
|
// Theme with config override
|
|
433
|
-
const rawTheme = glaze(280, 80, {
|
|
867
|
+
const rawTheme = glaze(280, 80, { lightTone: false, pastel: true });
|
|
434
868
|
```
|
|
435
869
|
|
|
436
|
-
|
|
870
|
+
See [Theme config override](#theme-config-override).
|
|
437
871
|
|
|
438
872
|
### Theme config override
|
|
439
873
|
|
|
@@ -443,24 +877,31 @@ When a theme is created with a `GlazeConfigOverride`, the override is **merged o
|
|
|
443
877
|
- Fields you didn't override still react to later `glaze.configure()` calls.
|
|
444
878
|
|
|
445
879
|
```ts
|
|
446
|
-
const t = glaze(280, 80, {
|
|
447
|
-
t.colors({ text: {
|
|
448
|
-
// text.light
|
|
880
|
+
const t = glaze(280, 80, { lightTone: [0, 50] });
|
|
881
|
+
t.colors({ text: { tone: 50, saturation: 1 } });
|
|
882
|
+
// text.light lands inside the [0, 50] window — always, regardless of
|
|
883
|
+
// global lightTone changes.
|
|
449
884
|
// text.dark.s reacts to glaze.configure({ darkDesaturation }) since it's not overridden.
|
|
450
885
|
```
|
|
451
886
|
|
|
452
887
|
`extend` inherits the parent's override and shallow-merges the child's:
|
|
453
888
|
|
|
454
889
|
```ts
|
|
455
|
-
const child = t.extend({ config: {
|
|
456
|
-
// child:
|
|
890
|
+
const child = t.extend({ config: { darkTone: false } });
|
|
891
|
+
// child: lightTone { lo: 0, hi: 50 } (inherited) + darkTone: false (added)
|
|
457
892
|
```
|
|
458
893
|
|
|
459
|
-
`theme.export()`
|
|
894
|
+
`theme.export(override?)` freezes `getConfig() ∪ instance local ∪ override` at
|
|
895
|
+
call time. Restoring via `glaze.themeFrom(data)` (or the compat alias
|
|
896
|
+
`glaze.from`) pins that freeze as the restored theme's local override — matching
|
|
897
|
+
standalone color-token behavior.
|
|
460
898
|
|
|
461
899
|
### `glaze.colorFrom(data)`
|
|
462
900
|
|
|
463
|
-
Inverse of `token.export()`. The exported snapshot includes the original input,
|
|
901
|
+
Inverse of `token.export()`. The exported snapshot includes the original input,
|
|
902
|
+
all overrides (with any `base` token recursively serialized), and the effective
|
|
903
|
+
config freeze from export time — so later `glaze.configure()` calls don't change
|
|
904
|
+
rehydrated tokens.
|
|
464
905
|
|
|
465
906
|
```ts
|
|
466
907
|
const text = glaze.color({ from: '#1a1a1a', contrast: 'AA' });
|
|
@@ -473,7 +914,7 @@ Both value-form and structured-form tokens round-trip.
|
|
|
473
914
|
|
|
474
915
|
### Pairing colors
|
|
475
916
|
|
|
476
|
-
Set `base` to anchor a standalone color to another standalone color or raw value. The
|
|
917
|
+
Set `base` to anchor a standalone color to another standalone color or raw value. The contrast solver and relative `tone` offsets switch their anchor from the literal seed to the base's resolved variant per scheme — so the same text color automatically lands at AA against its background in light, dark, and high-contrast modes.
|
|
477
918
|
|
|
478
919
|
```ts
|
|
479
920
|
const bg = glaze.color('#1a1a2e');
|
|
@@ -481,10 +922,11 @@ const bg = glaze.color('#1a1a2e');
|
|
|
481
922
|
// Text guaranteed AA against `bg` in every scheme.
|
|
482
923
|
const text = glaze.color({ from: '#ffffff', base: bg, contrast: 'AA' });
|
|
483
924
|
|
|
484
|
-
// Border 8
|
|
485
|
-
const border = glaze.color({
|
|
925
|
+
// Border 8 tone units lighter than `bg` in each scheme.
|
|
926
|
+
const border = glaze.color({
|
|
927
|
+
from: '#000000',
|
|
486
928
|
base: bg,
|
|
487
|
-
|
|
929
|
+
tone: '+8',
|
|
488
930
|
mode: 'fixed',
|
|
489
931
|
});
|
|
490
932
|
|
|
@@ -495,11 +937,11 @@ const text2 = glaze.color({ from: '#ffffff', base: '#1a1a2e', contrast: 'AA' });
|
|
|
495
937
|
Behavior with `base`:
|
|
496
938
|
|
|
497
939
|
- `contrast` is solved per scheme against `base`'s resolved variant (light / dark / lightContrast / darkContrast).
|
|
498
|
-
- Relative `
|
|
940
|
+
- Relative `tone: '+N'` / `'-N'` is anchored to `base`'s tone per scheme (matches theme behavior).
|
|
499
941
|
- Relative `hue: '+N'` / `'-N'` still anchors to the **seed** (the value passed to `glaze.color()`), not the base.
|
|
500
942
|
- `mode` works as a per-pair knob.
|
|
501
943
|
- The base token's `.resolve()` is called lazily on the first resolve of the dependent and the result is captured by reference; later mutations to the base don't apply.
|
|
502
|
-
- **Structured bases are resolved at full range for linking math**: when a value/`from` color links to a base created via the structured form, the contrast/
|
|
944
|
+
- **Structured bases are resolved at full range for linking math**: when a value/`from` color links to a base created via the structured form, the contrast/tone anchor uses the raw input tone (not the windowed output). This ensures the anchor matches what you intended, not what the light window remapped it to. The base's own `.resolve()` output is unaffected.
|
|
503
945
|
- When the contrast target is physically unreachable, `glaze` emits a single `console.warn` per `(name, scheme, target)` triple and returns the closest passing variant. Use the `name` override to make the warning identifiable.
|
|
504
946
|
|
|
505
947
|
Chains compose:
|
|
@@ -522,8 +964,8 @@ The `name` override appears in `console.warn` / Error messages but **does not**
|
|
|
522
964
|
|
|
523
965
|
```ts
|
|
524
966
|
theme.colors({
|
|
525
|
-
surface: {
|
|
526
|
-
text:
|
|
967
|
+
surface: { tone: 95 },
|
|
968
|
+
text: { base: 'surface', tone: '-52', contrast: 'AAA' },
|
|
527
969
|
|
|
528
970
|
'shadow-sm': { type: 'shadow', bg: 'surface', fg: 'text', intensity: 5 },
|
|
529
971
|
'shadow-md': { type: 'shadow', bg: 'surface', fg: 'text', intensity: 10 },
|
|
@@ -562,20 +1004,22 @@ theme.colors({
|
|
|
562
1004
|
|
|
563
1005
|
Fine-tune behavior per-color or globally via `glaze.configure({ shadowTuning })`. Per-color `tuning` is merged field-by-field with the global one.
|
|
564
1006
|
|
|
565
|
-
| Parameter
|
|
566
|
-
|
|
567
|
-
| `saturationFactor` | `0.18`
|
|
568
|
-
| `maxSaturation`
|
|
569
|
-
| `lightnessFactor`
|
|
570
|
-
| `lightnessBounds`
|
|
571
|
-
| `minGapTarget`
|
|
572
|
-
| `alphaMax`
|
|
573
|
-
| `bgHueBlend`
|
|
1007
|
+
| Parameter | Default | Description |
|
|
1008
|
+
| ------------------ | -------------- | ------------------------------------------------------------------------------------- |
|
|
1009
|
+
| `saturationFactor` | `0.18` | Fraction of fg saturation kept in pigment. |
|
|
1010
|
+
| `maxSaturation` | `0.25` | Upper clamp on pigment saturation. |
|
|
1011
|
+
| `lightnessFactor` | `0.25` | Multiplier for bg lightness → pigment lightness. |
|
|
1012
|
+
| `lightnessBounds` | `[0.05, 0.20]` | Clamp range for pigment lightness. |
|
|
1013
|
+
| `minGapTarget` | `0.05` | Target minimum gap between pigment and bg lightness. |
|
|
1014
|
+
| `alphaMax` | `1.0` | Asymptotic maximum alpha. |
|
|
1015
|
+
| `bgHueBlend` | `0.2` | Blend weight pulling pigment hue toward bg hue. `0` = pure fg hue, `1` = pure bg hue. |
|
|
574
1016
|
|
|
575
1017
|
```ts
|
|
576
1018
|
theme.colors({
|
|
577
1019
|
'shadow-soft': {
|
|
578
|
-
type: 'shadow',
|
|
1020
|
+
type: 'shadow',
|
|
1021
|
+
bg: 'surface',
|
|
1022
|
+
intensity: 10,
|
|
579
1023
|
tuning: { alphaMax: 0.3, saturationFactor: 0.1 },
|
|
580
1024
|
},
|
|
581
1025
|
});
|
|
@@ -603,12 +1047,12 @@ const css = glaze.format(v, 'oklch');
|
|
|
603
1047
|
|
|
604
1048
|
`GlazeShadowInput`:
|
|
605
1049
|
|
|
606
|
-
| Field
|
|
607
|
-
|
|
608
|
-
| `bg`
|
|
609
|
-
| `fg`
|
|
610
|
-
| `intensity` | `number`
|
|
611
|
-
| `tuning`
|
|
1050
|
+
| Field | Type | Description |
|
|
1051
|
+
| ----------- | ----------------- | ------------------------------------------------------------------------------ |
|
|
1052
|
+
| `bg` | `GlazeColorValue` | Background. Any `GlazeColorValue` form. Alpha components dropped with warning. |
|
|
1053
|
+
| `fg` | `GlazeColorValue` | Optional foreground. Same forms as `bg`. |
|
|
1054
|
+
| `intensity` | `number` | 0–100. |
|
|
1055
|
+
| `tuning` | `ShadowTuning` | Optional. |
|
|
612
1056
|
|
|
613
1057
|
### Fixed opacity (regular colors)
|
|
614
1058
|
|
|
@@ -616,7 +1060,7 @@ For a simple fixed-alpha color (no shadow algorithm), use `opacity` on a regular
|
|
|
616
1060
|
|
|
617
1061
|
```ts
|
|
618
1062
|
theme.colors({
|
|
619
|
-
overlay: {
|
|
1063
|
+
overlay: { tone: 0, opacity: 0.5 },
|
|
620
1064
|
});
|
|
621
1065
|
// → 'oklch(0 0 0 / 0.5)'
|
|
622
1066
|
```
|
|
@@ -631,9 +1075,9 @@ Produces a solid color by interpolating between `base` and `target`:
|
|
|
631
1075
|
|
|
632
1076
|
```ts
|
|
633
1077
|
theme.colors({
|
|
634
|
-
surface: {
|
|
635
|
-
accent:
|
|
636
|
-
tint:
|
|
1078
|
+
surface: { tone: 95 },
|
|
1079
|
+
accent: { tone: 30 },
|
|
1080
|
+
tint: { type: 'mix', base: 'surface', target: 'accent', value: 30 },
|
|
637
1081
|
});
|
|
638
1082
|
```
|
|
639
1083
|
|
|
@@ -647,11 +1091,14 @@ Produces the target color with controlled opacity — useful for hover overlays:
|
|
|
647
1091
|
|
|
648
1092
|
```ts
|
|
649
1093
|
theme.colors({
|
|
650
|
-
surface: {
|
|
651
|
-
black:
|
|
1094
|
+
surface: { tone: 95 },
|
|
1095
|
+
black: { tone: 0, saturation: 0 },
|
|
652
1096
|
hover: {
|
|
653
|
-
type: 'mix',
|
|
654
|
-
|
|
1097
|
+
type: 'mix',
|
|
1098
|
+
base: 'surface',
|
|
1099
|
+
target: 'black',
|
|
1100
|
+
value: 8,
|
|
1101
|
+
blend: 'transparent',
|
|
655
1102
|
},
|
|
656
1103
|
});
|
|
657
1104
|
// hover → black with alpha = 0.08
|
|
@@ -661,10 +1108,10 @@ The output color has `h`, `s`, `l` from the target and `alpha = value / 100`.
|
|
|
661
1108
|
|
|
662
1109
|
### Blend space (opaque only)
|
|
663
1110
|
|
|
664
|
-
| `space`
|
|
665
|
-
|
|
666
|
-
| `'okhsl'` (default) | Perceptually uniform OKHSL interpolation. | Design token derivation.
|
|
667
|
-
| `'srgb'`
|
|
1111
|
+
| `space` | Behavior | Best for |
|
|
1112
|
+
| ------------------- | ----------------------------------------- | -------------------------------------------------------- |
|
|
1113
|
+
| `'okhsl'` (default) | Perceptually uniform OKHSL interpolation. | Design token derivation. |
|
|
1114
|
+
| `'srgb'` | Linear sRGB channel interpolation. | Matching browser compositing of CSS color-mix / overlay. |
|
|
668
1115
|
|
|
669
1116
|
Transparent blending always composites in linear sRGB (matches browser alpha compositing).
|
|
670
1117
|
|
|
@@ -695,10 +1142,22 @@ Mix colors can reference other mix colors:
|
|
|
695
1142
|
|
|
696
1143
|
```ts
|
|
697
1144
|
theme.colors({
|
|
698
|
-
white: {
|
|
699
|
-
black: {
|
|
700
|
-
gray:
|
|
701
|
-
|
|
1145
|
+
white: { tone: 100, saturation: 0 },
|
|
1146
|
+
black: { tone: 0, saturation: 0 },
|
|
1147
|
+
gray: {
|
|
1148
|
+
type: 'mix',
|
|
1149
|
+
base: 'white',
|
|
1150
|
+
target: 'black',
|
|
1151
|
+
value: 50,
|
|
1152
|
+
space: 'srgb',
|
|
1153
|
+
},
|
|
1154
|
+
lightGray: {
|
|
1155
|
+
type: 'mix',
|
|
1156
|
+
base: 'white',
|
|
1157
|
+
target: 'gray',
|
|
1158
|
+
value: 50,
|
|
1159
|
+
space: 'srgb',
|
|
1160
|
+
},
|
|
702
1161
|
});
|
|
703
1162
|
```
|
|
704
1163
|
|
|
@@ -720,35 +1179,67 @@ const palette = glaze.palette(
|
|
|
720
1179
|
|
|
721
1180
|
`GlazePaletteOptions`:
|
|
722
1181
|
|
|
723
|
-
| Option
|
|
724
|
-
|
|
1182
|
+
| Option | Description |
|
|
1183
|
+
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
725
1184
|
| `primary` | Name of the primary theme. The primary's tokens are duplicated **without** prefix in all exports, providing convenient short aliases alongside the prefixed versions. Throws if the name doesn't match any theme. |
|
|
726
1185
|
|
|
727
1186
|
A `GlazePalette` exposes:
|
|
728
1187
|
|
|
729
|
-
| Method
|
|
730
|
-
|
|
731
|
-
| `palette.
|
|
732
|
-
| `palette.
|
|
733
|
-
| `palette.
|
|
734
|
-
| `palette.
|
|
1188
|
+
| Method | Description |
|
|
1189
|
+
| -------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
1190
|
+
| `palette.list()` | Theme names in insertion order. |
|
|
1191
|
+
| `palette.primary` | Primary theme name, if set. |
|
|
1192
|
+
| `palette.theme(name)` | Get a live theme instance by name. |
|
|
1193
|
+
| `palette.themes()` | Shallow copy of the theme map (same instances the palette holds). |
|
|
1194
|
+
| `palette.export(override?)` | Authoring snapshot — restorable via `glaze.paletteFrom()`. Optional override forwarded to themes. |
|
|
1195
|
+
| `palette.tokens(options?)` | Flat token map grouped by scheme variant. |
|
|
1196
|
+
| `palette.tasty(options?)` | [Tasty](https://tasty.style) style-to-state bindings. |
|
|
1197
|
+
| `palette.json(options?)` | Per-theme **resolved** color JSON (not restorable as authoring config). |
|
|
1198
|
+
| `palette.css(options?)` | CSS custom property declaration strings. |
|
|
1199
|
+
| `palette.dtcg(options?)` | Per-scheme W3C DTCG token trees. |
|
|
1200
|
+
| `palette.dtcgResolver(options?)` | One DTCG Resolver-Module document for every scheme. |
|
|
1201
|
+
| `palette.tailwind(options?)` | One Tailwind CSS v4 theme with scheme overrides. |
|
|
1202
|
+
|
|
1203
|
+
### `palette.export(override?)` / `glaze.paletteFrom()`
|
|
1204
|
+
|
|
1205
|
+
```ts
|
|
1206
|
+
const snapshot = palette.export();
|
|
1207
|
+
// → {
|
|
1208
|
+
// kind: 'palette',
|
|
1209
|
+
// version: 1,
|
|
1210
|
+
// primary: 'brand',
|
|
1211
|
+
// themes: { brand: { kind: 'theme', ... }, danger: { ... } },
|
|
1212
|
+
// }
|
|
1213
|
+
|
|
1214
|
+
const restored = glaze.paletteFrom(JSON.parse(JSON.stringify(snapshot)));
|
|
1215
|
+
const brand = restored.theme('brand')!;
|
|
1216
|
+
```
|
|
1217
|
+
|
|
1218
|
+
Optional `override` is forwarded to each nested `theme.export(override)`.
|
|
1219
|
+
Config snapshot vs resolved output: use `export()` / `paletteFrom()` to
|
|
1220
|
+
persist and restore the authoring graph (themes, color defs, relations). Use
|
|
1221
|
+
`json()` / `tokens()` / `css()` / … to emit resolved color strings for apps
|
|
1222
|
+
and design tools.
|
|
735
1223
|
|
|
736
1224
|
### `GlazePaletteExportOptions`
|
|
737
1225
|
|
|
738
1226
|
Shared by `tokens`, `tasty`, and `css`:
|
|
739
1227
|
|
|
740
|
-
| Option
|
|
741
|
-
|
|
742
|
-
| `prefix`
|
|
743
|
-
| `primary` | inherits from palette creation | `string` to override, `false` to disable for this call.
|
|
1228
|
+
| Option | Default | Description |
|
|
1229
|
+
| --------- | ------------------------------ | -------------------------------------------------------------------------------------------- |
|
|
1230
|
+
| `prefix` | `true` (= `"<themeName>-"`) | `false` disables prefixing. Or pass a custom map: `{ primary: 'brand-', danger: 'error-' }`. |
|
|
1231
|
+
| `primary` | inherits from palette creation | `string` to override, `false` to disable for this call. |
|
|
744
1232
|
|
|
745
1233
|
Each export method also accepts its own format/options shape:
|
|
746
1234
|
|
|
747
|
-
| Method
|
|
748
|
-
|
|
749
|
-
| `palette.tokens(options?)`
|
|
750
|
-
| `palette.tasty(options?)`
|
|
751
|
-
| `palette.css(options?)`
|
|
1235
|
+
| Method | Additional options |
|
|
1236
|
+
| -------------------------------- | ----------------------------------------- |
|
|
1237
|
+
| `palette.tokens(options?)` | `format`, `modes` |
|
|
1238
|
+
| `palette.tasty(options?)` | `format`, `modes`, `states` |
|
|
1239
|
+
| `palette.css(options?)` | `format`, `suffix` |
|
|
1240
|
+
| `palette.dtcg(options?)` | `colorSpace`, `modes` |
|
|
1241
|
+
| `palette.dtcgResolver(options?)` | `colorSpace`, `modes`, resolver names |
|
|
1242
|
+
| `palette.tailwind(options?)` | `format`, `modes`, selectors, `namespace` |
|
|
752
1243
|
|
|
753
1244
|
`palette.css()` does not accept `modes`; it always returns all four CSS strings (`light`, `dark`, `lightContrast`, `darkContrast`).
|
|
754
1245
|
|
|
@@ -759,8 +1250,8 @@ By default all palette tokens are prefixed:
|
|
|
759
1250
|
```ts
|
|
760
1251
|
palette.tokens();
|
|
761
1252
|
// → {
|
|
762
|
-
// light: { 'primary-surface': '
|
|
763
|
-
// dark: { 'primary-surface': '
|
|
1253
|
+
// light: { 'primary-surface': 'oklch(...)', 'danger-surface': 'oklch(...)' },
|
|
1254
|
+
// dark: { 'primary-surface': 'oklch(...)', 'danger-surface': 'oklch(...)' },
|
|
764
1255
|
// }
|
|
765
1256
|
```
|
|
766
1257
|
|
|
@@ -796,10 +1287,10 @@ const palette = glaze.palette(
|
|
|
796
1287
|
palette.tokens();
|
|
797
1288
|
// → {
|
|
798
1289
|
// light: {
|
|
799
|
-
// 'primary-surface': '
|
|
800
|
-
// 'danger-surface': '
|
|
801
|
-
// 'success-surface': '
|
|
802
|
-
// 'surface': '
|
|
1290
|
+
// 'primary-surface': 'oklch(...)',
|
|
1291
|
+
// 'danger-surface': 'oklch(...)',
|
|
1292
|
+
// 'success-surface': 'oklch(...)',
|
|
1293
|
+
// 'surface': 'oklch(...)', // unprefixed alias
|
|
803
1294
|
// },
|
|
804
1295
|
// }
|
|
805
1296
|
```
|
|
@@ -825,8 +1316,8 @@ JSON export groups by theme name (no prefix needed):
|
|
|
825
1316
|
```ts
|
|
826
1317
|
palette.json();
|
|
827
1318
|
// → {
|
|
828
|
-
// primary: { surface: { light: '
|
|
829
|
-
// danger: { surface: { light: '
|
|
1319
|
+
// primary: { surface: { light: 'oklch(...)', dark: 'oklch(...)' } },
|
|
1320
|
+
// danger: { surface: { light: 'oklch(...)', dark: 'oklch(...)' } },
|
|
830
1321
|
// }
|
|
831
1322
|
```
|
|
832
1323
|
|
|
@@ -845,29 +1336,113 @@ const stylesheet = `
|
|
|
845
1336
|
`palette.css()` accepts the same `GlazeCssOptions` as `theme.css()` plus `GlazePaletteExportOptions`.
|
|
846
1337
|
It does not accept `modes`; all four result fields are always returned.
|
|
847
1338
|
|
|
1339
|
+
### `palette.dtcg()`
|
|
1340
|
+
|
|
1341
|
+
DTCG export for a palette. Prefix defaults to `true` and the palette-level `primary` is honored (the primary theme's tokens are duplicated without prefix as aliases).
|
|
1342
|
+
|
|
1343
|
+
```ts
|
|
1344
|
+
palette.dtcg();
|
|
1345
|
+
// → {
|
|
1346
|
+
// light: {
|
|
1347
|
+
// 'primary-surface': { $type: 'color', $value: { ... } },
|
|
1348
|
+
// 'surface': { $type: 'color', $value: { ... } }, // unprefixed alias
|
|
1349
|
+
// 'danger-surface': { $type: 'color', $value: { ... } },
|
|
1350
|
+
// },
|
|
1351
|
+
// dark: { ... },
|
|
1352
|
+
// }
|
|
1353
|
+
```
|
|
1354
|
+
|
|
1355
|
+
Accepts `GlazeDtcgOptions` plus `GlazePaletteExportOptions`.
|
|
1356
|
+
|
|
1357
|
+
### `palette.dtcgResolver()`
|
|
1358
|
+
|
|
1359
|
+
Resolver-Module export for a palette. Same as `theme.dtcgResolver()` but merges every theme (with prefix / `primary` aliasing) into the single `sets.base` source and each `scheme` context. Prefix defaults to `true`; the palette-level `primary` is honored.
|
|
1360
|
+
|
|
1361
|
+
```ts
|
|
1362
|
+
palette.dtcgResolver();
|
|
1363
|
+
// → {
|
|
1364
|
+
// version: '2025.10',
|
|
1365
|
+
// sets: { base: { sources: [ { 'primary-surface': {…}, 'surface': {…}, 'danger-surface': {…} } ] } },
|
|
1366
|
+
// modifiers: { scheme: { default: 'light', contexts: { light: [], dark: [ {…} ] } } },
|
|
1367
|
+
// resolutionOrder: [ { $ref: '#/sets/base' }, { $ref: '#/modifiers/scheme' } ],
|
|
1368
|
+
// }
|
|
1369
|
+
```
|
|
1370
|
+
|
|
1371
|
+
Accepts `GlazeDtcgResolverOptions` plus `GlazePaletteExportOptions`.
|
|
1372
|
+
|
|
1373
|
+
### `palette.tailwind()`
|
|
1374
|
+
|
|
1375
|
+
Tailwind export for a palette. All themes are merged into a single `@theme` block (plus dark / high-contrast overrides), so each color is reachable as a Tailwind utility. Prefix defaults to `true`.
|
|
1376
|
+
|
|
1377
|
+
```ts
|
|
1378
|
+
const css = palette.tailwind();
|
|
1379
|
+
// @theme {
|
|
1380
|
+
// --color-primary-surface: oklch(...);
|
|
1381
|
+
// --color-surface: oklch(...); /* unprefixed alias */
|
|
1382
|
+
// --color-danger-surface: oklch(...);
|
|
1383
|
+
// }
|
|
1384
|
+
// .dark { ... }
|
|
1385
|
+
```
|
|
1386
|
+
|
|
1387
|
+
Accepts `GlazeTailwindOptions` plus `GlazePaletteExportOptions`. The palette `prefix` option (theme prefixing) is separate from `GlazeTailwindOptions.namespace` (the `--color-*` CSS namespace).
|
|
1388
|
+
|
|
848
1389
|
---
|
|
849
1390
|
|
|
850
1391
|
## Output formats
|
|
851
1392
|
|
|
852
1393
|
Control the color format with the `format` option on any export method:
|
|
853
1394
|
|
|
854
|
-
| Format
|
|
855
|
-
|
|
856
|
-
| `'
|
|
857
|
-
| `'rgb'`
|
|
858
|
-
| `'hsl'`
|
|
859
|
-
| `'
|
|
1395
|
+
| Format | Output (alpha = 1) | Output (alpha < 1) | Notes |
|
|
1396
|
+
| --------------------------------------------- | ------------------ | -------------------- | --------------------------------------------------------------------------------------------- |
|
|
1397
|
+
| `'oklch'` (default for CSS-string exports) | `oklch(L C H)` | `oklch(L C H / A)` | OKLab-based LCH. Native CSS. Required for `splitHue`. |
|
|
1398
|
+
| `'rgb'` | `rgb(R G B)` | `rgb(R G B / A)` | Rounded integers, modern space syntax. |
|
|
1399
|
+
| `'hsl'` | `hsl(H S% L%)` | `hsl(H S% L% / A)` | Modern space syntax. |
|
|
1400
|
+
| `'okhsl'` | `okhsl(H S% L%)` | `okhsl(H S% L% / A)` | Glaze's native format, not a CSS function. **[Tasty](https://tasty.style)-only** (`tasty()`, `token()`, `.tasty()`). |
|
|
1401
|
+
| `'okhst'` | `okhst(H S% T%)` | `okhst(H S% T% / A)` | OKHST tone axis. **[Tasty](https://tasty.style)-only** — same restriction as `okhsl`. |
|
|
860
1402
|
|
|
861
1403
|
```ts
|
|
862
|
-
theme.tokens();
|
|
863
|
-
theme.tokens({ format: 'rgb' });
|
|
864
|
-
theme.
|
|
865
|
-
theme.
|
|
1404
|
+
theme.tokens(); // 'oklch(0.965 0.0123 280)' (default)
|
|
1405
|
+
theme.tokens({ format: 'rgb' }); // 'rgb(244 240 250)'
|
|
1406
|
+
theme.tasty(); // 'oklch(0.965 0.0123 280)' (default)
|
|
1407
|
+
theme.tasty({ format: 'okhst' }); // 'okhst(280 60% 97%)'
|
|
866
1408
|
```
|
|
867
1409
|
|
|
868
1410
|
All numeric output strips trailing zeros for cleaner CSS (e.g. `95` not `95.0`).
|
|
869
1411
|
|
|
870
|
-
The `format` option works on
|
|
1412
|
+
The `format` option works on CSS-string exports: `theme.tokens()`, `theme.tasty()`, `theme.json()`, `theme.css()`, `theme.tailwind()`, the same on `palette`, and on `token.token()` / `.tasty()` / `.json()` / `.css()` / `.tailwind()`. **`okhsl` and `okhst` throw on non-[Tasty](https://tasty.style) exports** (`tokens`, `json`, `css`, `tailwind`) — they are not native CSS color spaces.
|
|
1413
|
+
|
|
1414
|
+
### Hue channel splitting (`splitHue`)
|
|
1415
|
+
|
|
1416
|
+
On `theme.css()`, `theme.tasty()`, `palette.css()`, `palette.tasty()`, and standalone `color.css()` with `format: 'oklch'`, set `splitHue: true` to emit hue as its own custom property so consumers can re-skin at runtime:
|
|
1417
|
+
|
|
1418
|
+
```css
|
|
1419
|
+
/* theme.css({ format: 'oklch', splitHue: true, name: 'brand' }) */
|
|
1420
|
+
--brand-hue: 240;
|
|
1421
|
+
--accent-hue: calc(var(--brand-hue) + 20);
|
|
1422
|
+
--surface-color: oklch(0.52 0.06 var(--brand-hue));
|
|
1423
|
+
--accent-color: oklch(0.62 0.03 var(--accent-hue));
|
|
1424
|
+
```
|
|
1425
|
+
|
|
1426
|
+
**Requirements:** every exported color must be pastel (`pastel: true` on the theme/token override or per-color). Pastel mode bounds chroma by the hue-independent safe chroma at each lightness, so emitted `C` stays in sRGB for any rotated hue. Non-pastel palettes throw rather than emit values that would clip under rotation.
|
|
1427
|
+
|
|
1428
|
+
**Dark hues:** hue vars are scheme-independent unless the theme or a color authors a [dark hue](#dark-seed-darkhue--darksaturation). When one does, the whole hue set is re-declared in the dark block (and in the Tasty dark state, gated by `modes.dark`):
|
|
1429
|
+
|
|
1430
|
+
```css
|
|
1431
|
+
/* glaze({ hue: 240, saturation: 18, darkHue: 200 }) */
|
|
1432
|
+
:root {
|
|
1433
|
+
--brand-hue: 240;
|
|
1434
|
+
--accent-hue: calc(var(--brand-hue) + 20);
|
|
1435
|
+
}
|
|
1436
|
+
/* dark */
|
|
1437
|
+
--brand-hue: 200;
|
|
1438
|
+
--accent-hue: calc(var(--brand-hue) + 20);
|
|
1439
|
+
```
|
|
1440
|
+
|
|
1441
|
+
`--accent-hue` repeats verbatim on purpose: a custom property substitutes `var()` at computed-value time on the element that declares it, so it has to be re-declared to pick up the new `--brand-hue`. Colors with `mode: 'static'` are pinned to an absolute hue instead, so they don't drift with the dark seed.
|
|
1442
|
+
|
|
1443
|
+
**Limitations:** `oklch` only (native CSS `var()` in the hue slot). Shadow and mix colors stay inline (blended hue). Standalone `.token()` / `.tasty()` do not support `splitHue` (return shape cannot carry the `$name-hue` declaration).
|
|
1444
|
+
|
|
1445
|
+
`theme.dtcg()` / `theme.dtcgResolver()` / `palette.dtcg()` / `palette.dtcgResolver()` ignore `format` — DTCG emits structured `$value` objects, not CSS strings. Use the `colorSpace` option (`'srgb'` or `'oklch'`) to pick the color representation instead.
|
|
871
1446
|
|
|
872
1447
|
---
|
|
873
1448
|
|
|
@@ -875,87 +1450,84 @@ The `format` option works on every export: `theme.tokens()`, `theme.tasty()`, `t
|
|
|
875
1450
|
|
|
876
1451
|
`mode` controls how a color adapts across schemes:
|
|
877
1452
|
|
|
878
|
-
| Mode
|
|
879
|
-
|
|
880
|
-
| `'auto'` (default) | Full adaptation.
|
|
881
|
-
| `'fixed'`
|
|
882
|
-
| `'static'`
|
|
1453
|
+
| Mode | Behavior |
|
|
1454
|
+
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1455
|
+
| `'auto'` (default) | Full adaptation. Dark uses **dark tone inversion** (`100 − t`) and then remaps into the dark tone window. High-contrast uses the full range. |
|
|
1456
|
+
| `'fixed'` | Color stays recognizable. Tone is _mapped_ (not inverted) into the dark window. Use for brand buttons, CTAs, status banners. |
|
|
1457
|
+
| `'static'` | No adaptation. Same tone in every scheme. |
|
|
883
1458
|
|
|
884
|
-
### How relative
|
|
1459
|
+
### How relative tone adapts
|
|
885
1460
|
|
|
886
|
-
**`auto`** —
|
|
1461
|
+
**`auto`** — the offset is anchored to the base's per-scheme tone:
|
|
887
1462
|
|
|
888
1463
|
```
|
|
889
|
-
Light: surface
|
|
890
|
-
Dark: surface inverts to
|
|
891
|
-
|
|
1464
|
+
Light: surface tone=97, text tone='-52' → tone 45 (dark text on light bg)
|
|
1465
|
+
Dark: surface inverts to a low tone; the '-52' offset re-anchors to the
|
|
1466
|
+
base's light tone and maps into the dark window (light text on dark bg)
|
|
892
1467
|
```
|
|
893
1468
|
|
|
894
|
-
**`fixed`** —
|
|
1469
|
+
**`fixed`** — tone is mapped (not inverted), relative sign preserved:
|
|
895
1470
|
|
|
896
1471
|
```
|
|
897
|
-
Light: accent-fill
|
|
898
|
-
Dark: accent-fill maps
|
|
1472
|
+
Light: accent-fill tone=52, accent-text tone='+20' → lighter than the fill
|
|
1473
|
+
Dark: accent-fill maps into the dark window, sign preserved
|
|
899
1474
|
```
|
|
900
1475
|
|
|
901
|
-
|
|
1476
|
+
Offsets that would push past `[0, 100]` clamp to the boundary, or — with `autoFlip` (default on) — mirror to the other side of the base. If the mirror also overshoots, the original side is kept and clamped. Set `autoFlip: false` to keep the authored side and clamp instead.
|
|
1477
|
+
|
|
1478
|
+
**`static`** — no adaptation, same tone in every scheme.
|
|
902
1479
|
|
|
903
1480
|
---
|
|
904
1481
|
|
|
905
1482
|
## Light / dark scheme mapping
|
|
906
1483
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1484
|
+
The mapping is a single tone pipeline; there is no Möbius curve. See
|
|
1485
|
+
[Scheme adaptation](okhst.md#scheme-adaptation) for the product-level model and
|
|
1486
|
+
the [canonical OKHST specification](https://github.com/tenphi/okhst) for the
|
|
1487
|
+
transfer math.
|
|
910
1488
|
|
|
911
|
-
|
|
912
|
-
const [lo, hi] = lightLightness; // default: [10, 100]
|
|
913
|
-
const mappedL = (lightness * (hi - lo)) / 100 + lo;
|
|
914
|
-
```
|
|
1489
|
+
### Light scheme
|
|
915
1490
|
|
|
916
|
-
|
|
1491
|
+
An authored tone (0–100) is remapped into the `lightTone` **tone window**.
|
|
1492
|
+
The window's `lo`/`hi` are OKHSL-lightness boundaries (0–100); authored tone is
|
|
1493
|
+
positioned within the corresponding tone interval and converted to final OKHSL
|
|
1494
|
+
lightness. `static` mode and HC variants use the full range.
|
|
917
1495
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
1496
|
+
```
|
|
1497
|
+
window = lightTone // default [10, 100]
|
|
1498
|
+
finalTone = remap(authorTone, window)
|
|
1499
|
+
finalL = fromTone(finalTone) // OKHSL lightness
|
|
1500
|
+
```
|
|
923
1501
|
|
|
924
|
-
### Dark scheme
|
|
1502
|
+
### Dark scheme
|
|
925
1503
|
|
|
926
|
-
**`auto`** —
|
|
1504
|
+
**`auto`** — invert the tone, then remap into the dark window:
|
|
927
1505
|
|
|
928
|
-
```
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
// darkCurve default: 0.5
|
|
1506
|
+
```
|
|
1507
|
+
window = darkTone // default [15, 95]
|
|
1508
|
+
inverted = 100 - authorTone
|
|
1509
|
+
finalTone = remap(inverted, window)
|
|
933
1510
|
```
|
|
934
1511
|
|
|
935
|
-
The
|
|
936
|
-
|
|
937
|
-
|
|
1512
|
+
The inversion preserves authored tone spacing without a fitted curve. This is
|
|
1513
|
+
exactly contrast-even for neutrals and approximate for chromatic colors. The
|
|
1514
|
+
ordinary light/dark asymmetry lives in the two windows' `(lo, hi, eps)` values
|
|
1515
|
+
(`eps` defaults to the reference `0.05`).
|
|
938
1516
|
|
|
939
|
-
**`fixed`** —
|
|
1517
|
+
**`fixed`** — remap into the dark window without inversion:
|
|
940
1518
|
|
|
941
|
-
```
|
|
942
|
-
|
|
1519
|
+
```
|
|
1520
|
+
finalTone = remap(authorTone, darkTone)
|
|
943
1521
|
```
|
|
944
1522
|
|
|
945
|
-
|
|
946
|
-
|---|---|---|---|---|
|
|
947
|
-
| surface (L=97) | 97 | 19.7 | 17.4 | 92.6 |
|
|
948
|
-
| accent-fill (L=52) | 52 | 66.9 | 53.4 | 56.6 |
|
|
949
|
-
| accent-text (L=100) | 100 | 15 | 15 | 95 |
|
|
950
|
-
|
|
951
|
-
In high-contrast variants the `darkLightness` window is bypassed — `auto` uses the Möbius curve over the full `[0, 100]` range, `fixed` uses identity.
|
|
1523
|
+
In high-contrast variants both windows are bypassed (forced to the full `[0, 100]` range): `auto` still inverts, `fixed`/`static` do not.
|
|
952
1524
|
|
|
953
1525
|
### Dark scheme — saturation
|
|
954
1526
|
|
|
955
1527
|
`darkDesaturation` reduces saturation for all colors in dark scheme:
|
|
956
1528
|
|
|
957
1529
|
```ts
|
|
958
|
-
S_dark = S_light * (1 - darkDesaturation) // default: 0.1
|
|
1530
|
+
S_dark = S_light * (1 - darkDesaturation); // default: 0.1
|
|
959
1531
|
```
|
|
960
1532
|
|
|
961
1533
|
`static` mode skips desaturation.
|
|
@@ -966,13 +1538,12 @@ S_dark = S_light * (1 - darkDesaturation) // default: 0.1
|
|
|
966
1538
|
|
|
967
1539
|
```ts
|
|
968
1540
|
glaze.configure({
|
|
969
|
-
|
|
970
|
-
|
|
1541
|
+
lightTone: [10, 100], // [lo, hi]; or { lo, hi, eps } / false to disable clamping
|
|
1542
|
+
darkTone: [15, 95], // [lo, hi]; or { lo, hi, eps } / false to disable clamping
|
|
971
1543
|
darkDesaturation: 0.1,
|
|
972
|
-
darkCurve: 0.5, // or [normal, hc] pair
|
|
973
1544
|
states: {
|
|
974
|
-
dark: '@dark',
|
|
975
|
-
highContrast: '@
|
|
1545
|
+
dark: '@media(prefers-color-scheme: dark)',
|
|
1546
|
+
highContrast: '@media(prefers-contrast: more)',
|
|
976
1547
|
},
|
|
977
1548
|
modes: {
|
|
978
1549
|
dark: true,
|
|
@@ -985,28 +1556,33 @@ glaze.configure({
|
|
|
985
1556
|
});
|
|
986
1557
|
```
|
|
987
1558
|
|
|
1559
|
+
A `ToneWindow` is `[lo, hi]` (OKHSL-lightness boundaries, reference eps — the
|
|
1560
|
+
common form), `{ lo, hi, eps }` (advanced: explicit per-scheme render eps), or
|
|
1561
|
+
`false` for the full range `[0, 100]` at the reference eps. `false` removes the
|
|
1562
|
+
boundaries, not the tone transfer.
|
|
1563
|
+
|
|
988
1564
|
`GlazeConfig`:
|
|
989
1565
|
|
|
990
|
-
| Field
|
|
991
|
-
|
|
992
|
-
| `
|
|
993
|
-
| `
|
|
994
|
-
| `darkDesaturation`
|
|
995
|
-
| `
|
|
996
|
-
| `states.
|
|
997
|
-
| `
|
|
998
|
-
| `modes.
|
|
999
|
-
| `
|
|
1000
|
-
| `
|
|
1001
|
-
| `
|
|
1002
|
-
|
|
1003
|
-
| Method
|
|
1004
|
-
|
|
1566
|
+
| Field | Default | Description |
|
|
1567
|
+
| --------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1568
|
+
| `lightTone` | `[10, 100]` | Light scheme tone window: `[lo, hi]`, `{ lo, hi, eps }`, or `false` to disable clamping. Bypassed in HC. |
|
|
1569
|
+
| `darkTone` | `[15, 95]` | Dark scheme tone window: `[lo, hi]`, `{ lo, hi, eps }`, or `false` to disable clamping. Bypassed in HC. |
|
|
1570
|
+
| `darkDesaturation` | `0.1` | Saturation reduction in dark scheme (0–1). |
|
|
1571
|
+
| `states.dark` | `'@media(prefers-color-scheme: dark)'` | State alias for dark mode tokens ([Tasty](https://tasty.style) export). Defaults to a media query so tokens react to the OS preference without registering custom states. |
|
|
1572
|
+
| `states.highContrast` | `'@media(prefers-contrast: more)'` | State alias for HC tokens ([Tasty](https://tasty.style) export). |
|
|
1573
|
+
| `modes.dark` | `true` | Include dark variants in exports. |
|
|
1574
|
+
| `modes.highContrast` | `false` | Include HC variants. |
|
|
1575
|
+
| `shadowTuning` | `undefined` | Default tuning for all shadow colors. Per-color tuning merges field-by-field. |
|
|
1576
|
+
| `autoFlip` | `true` | Default for each color's `autoFlip`. When solving `contrast` (or applying a relative `tone` that overshoots `[0, 100]`), allow crossing to the opposite side instead of clamping. With `false`, only the requested direction is considered; unmet contrasts pin the tone to that direction's extreme (and emit a warning) and overshooting offsets clamp to the boundary. Override per color via [`autoFlip`](#autoflip). |
|
|
1577
|
+
| `inferRole` | `true` | Infer each color's [`role`](#roles) from its name when no explicit `role` is set. Set to `false` to opt out of name-based inference (the base-opposite and foreground-default fallbacks still apply). |
|
|
1578
|
+
|
|
1579
|
+
| Method | Description |
|
|
1580
|
+
| ------------------------- | ----------------------------------------------------------------------------------- |
|
|
1005
1581
|
| `glaze.configure(config)` | Merge into the global config. Bumps a config version that invalidates theme caches. |
|
|
1006
|
-
| `glaze.getConfig()`
|
|
1007
|
-
| `glaze.resetConfig()`
|
|
1582
|
+
| `glaze.getConfig()` | Snapshot the current resolved config (shallow copy). |
|
|
1583
|
+
| `glaze.resetConfig()` | Reset to defaults (also bumps the version counter). |
|
|
1008
1584
|
|
|
1009
|
-
|
|
1585
|
+
Themes and standalone color tokens keep a sparse local `GlazeConfigOverride` and merge the live global at resolve time for omitted fields. Authoring `.export(override?)` freezes the effective merge at call time; restored instances pin that freeze. `pastel` is instance-only (theme/token override or per-color) — not set via `configure()`.
|
|
1010
1586
|
|
|
1011
1587
|
---
|
|
1012
1588
|
|
|
@@ -1036,30 +1612,38 @@ Resolution priority (highest first):
|
|
|
1036
1612
|
|
|
1037
1613
|
## Validation
|
|
1038
1614
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
|
1046
|
-
|
|
|
1047
|
-
|
|
|
1048
|
-
| `base`
|
|
1049
|
-
|
|
|
1050
|
-
|
|
|
1051
|
-
|
|
|
1052
|
-
|
|
|
1053
|
-
|
|
|
1054
|
-
|
|
|
1055
|
-
|
|
|
1056
|
-
|
|
|
1057
|
-
|
|
|
1058
|
-
|
|
|
1059
|
-
|
|
|
1060
|
-
|
|
|
1061
|
-
|
|
|
1062
|
-
|
|
|
1615
|
+
Invalid definitions throw before resolution when Glaze cannot produce a
|
|
1616
|
+
well-defined dependency graph. Recoverable numeric bounds are clamped. A
|
|
1617
|
+
physically unreachable contrast floor or a potentially misleading
|
|
1618
|
+
contrast/opacity combination emits `console.warn` and returns the closest
|
|
1619
|
+
available result.
|
|
1620
|
+
|
|
1621
|
+
| Condition | Behavior |
|
|
1622
|
+
| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
1623
|
+
| `contrast` without `base` in a **theme** color | Validation error |
|
|
1624
|
+
| Relative `tone` without `base` in a **theme** color | Validation error |
|
|
1625
|
+
| `contrast` without `base` in `glaze.color()` | Anchors against the literal seed (no error) |
|
|
1626
|
+
| Relative `tone` without `base` in `glaze.color()` | Anchors against the literal seed (no error) |
|
|
1627
|
+
| Relative `tone` overshoots `[0, 100]` | Mirror to the other side of the base (`autoFlip` on, default), or clamp to the boundary (`autoFlip` off). If the mirror also overshoots, clamp on the authored side. |
|
|
1628
|
+
| `tone` resolves outside 0–100 | Clamp silently |
|
|
1629
|
+
| `'max'` / `'min'` without `base` | Allowed — resolves to the scheme's tone extreme (root color) |
|
|
1630
|
+
| `saturation` outside 0–1 | Clamp silently |
|
|
1631
|
+
| Circular `base` references | Validation error |
|
|
1632
|
+
| `base` references non-existent name | Validation error |
|
|
1633
|
+
| Shadow `bg` references non-existent color | Validation error |
|
|
1634
|
+
| Shadow `fg` references non-existent color | Validation error |
|
|
1635
|
+
| Shadow `bg` references another shadow color | Validation error |
|
|
1636
|
+
| Shadow `fg` references another shadow color | Validation error |
|
|
1637
|
+
| Regular color `base` references a shadow color | Validation error |
|
|
1638
|
+
| Shadow `intensity` outside 0–100 | Clamp silently |
|
|
1639
|
+
| `contrast` + `opacity` combined | `console.warn` |
|
|
1640
|
+
| Mix `base` references non-existent color | Validation error |
|
|
1641
|
+
| Mix `target` references non-existent color | Validation error |
|
|
1642
|
+
| Mix `base` references a shadow color | Validation error |
|
|
1643
|
+
| Mix `target` references a shadow color | Validation error |
|
|
1644
|
+
| Mix `value` outside 0–100 | Clamp silently |
|
|
1645
|
+
| Circular references involving mix colors | Validation error |
|
|
1646
|
+
| Contrast target physically unreachable | `console.warn` (deduped per `(name, scheme, target)`); closest passing variant returned |
|
|
1063
1647
|
|
|
1064
1648
|
---
|
|
1065
1649
|
|
|
@@ -1085,19 +1669,19 @@ import {
|
|
|
1085
1669
|
} from '@tenphi/glaze';
|
|
1086
1670
|
```
|
|
1087
1671
|
|
|
1088
|
-
| Function
|
|
1089
|
-
|
|
1090
|
-
| `okhslToLinearSrgb(h, s, l)`
|
|
1091
|
-
| `okhslToSrgb(h, s, l)`
|
|
1092
|
-
| `okhslToOklab([h, s, l])`
|
|
1093
|
-
| `oklabToOkhsl([L, a, b])`
|
|
1094
|
-
| `srgbToOkhsl([r, g, b])`
|
|
1095
|
-
| `hslToSrgb(h, s, l)`
|
|
1096
|
-
| `parseHex(hex)`
|
|
1097
|
-
| `parseHexAlpha(hex)`
|
|
1098
|
-
| `relativeLuminanceFromLinearRgb(rgb)` | WCAG relative luminance from linear sRGB.
|
|
1099
|
-
| `contrastRatioFromLuminance(yA, yB)`
|
|
1100
|
-
| `gamutClampedLuminance(linearRgb)`
|
|
1672
|
+
| Function | Description |
|
|
1673
|
+
| ------------------------------------- | ------------------------------------------------------------------------ |
|
|
1674
|
+
| `okhslToLinearSrgb(h, s, l)` | OKHSL (h: 0–360, s/l: 0–1) → linear sRGB tuple. |
|
|
1675
|
+
| `okhslToSrgb(h, s, l)` | OKHSL → gamma-encoded sRGB tuple (0–1 per channel). |
|
|
1676
|
+
| `okhslToOklab([h, s, l])` | OKHSL → OKLab `[L, a, b]`. |
|
|
1677
|
+
| `oklabToOkhsl([L, a, b])` | OKLab → OKHSL. |
|
|
1678
|
+
| `srgbToOkhsl([r, g, b])` | Gamma sRGB (0–1) → OKHSL. |
|
|
1679
|
+
| `hslToSrgb(h, s, l)` | CSS HSL → sRGB tuple. |
|
|
1680
|
+
| `parseHex(hex)` | Parse `#rgb` / `#rrggbb` to sRGB tuple. Returns `null` on invalid input. |
|
|
1681
|
+
| `parseHexAlpha(hex)` | Parse `#rgb` / `#rrggbb` / `#rrggbbaa`; returns `[r, g, b, a?]`. |
|
|
1682
|
+
| `relativeLuminanceFromLinearRgb(rgb)` | WCAG relative luminance from linear sRGB. |
|
|
1683
|
+
| `contrastRatioFromLuminance(yA, yB)` | WCAG contrast ratio from two luminances. |
|
|
1684
|
+
| `gamutClampedLuminance(linearRgb)` | Relative luminance with channel clamping for out-of-gamut colors. |
|
|
1101
1685
|
|
|
1102
1686
|
### Format writers
|
|
1103
1687
|
|
|
@@ -1105,42 +1689,77 @@ import {
|
|
|
1105
1689
|
import { formatOkhsl, formatRgb, formatHsl, formatOklch } from '@tenphi/glaze';
|
|
1106
1690
|
|
|
1107
1691
|
formatOkhsl(280, 60, 95); // 'okhsl(280 60% 95%)'
|
|
1108
|
-
formatRgb(280, 60, 95);
|
|
1109
|
-
formatHsl(280, 60, 95);
|
|
1692
|
+
formatRgb(280, 60, 95); // 'rgb(244 240 250)'
|
|
1693
|
+
formatHsl(280, 60, 95); // 'hsl(280 60% 95%)'
|
|
1110
1694
|
formatOklch(280, 60, 95); // 'oklch(0.95 ... 280)'
|
|
1111
1695
|
```
|
|
1112
1696
|
|
|
1113
1697
|
To attach an alpha component, use `glaze.format(variant, format)` on a `ResolvedColorVariant` (which carries the `alpha` channel) instead of these raw writers.
|
|
1114
1698
|
|
|
1699
|
+
### OKHST tone utilities
|
|
1700
|
+
|
|
1701
|
+
```ts
|
|
1702
|
+
import {
|
|
1703
|
+
toTone,
|
|
1704
|
+
fromTone,
|
|
1705
|
+
toneFromY,
|
|
1706
|
+
yFromTone,
|
|
1707
|
+
okhstToOkhsl,
|
|
1708
|
+
okhslToOkhst,
|
|
1709
|
+
variantToOkhsl,
|
|
1710
|
+
REF_EPS,
|
|
1711
|
+
} from '@tenphi/glaze';
|
|
1712
|
+
```
|
|
1713
|
+
|
|
1714
|
+
| Function | Description |
|
|
1715
|
+
| ------------------------------------------- | ------------------------------------------------------------------------- |
|
|
1716
|
+
| `toTone(l, eps?)` | OKHSL lightness (0–1) → tone (0–100). Defaults to `REF_EPS`. |
|
|
1717
|
+
| `fromTone(t, eps?)` | Tone (0–100) → OKHSL lightness (0–1). Inverse of `toTone`. |
|
|
1718
|
+
| `toneFromY(y, eps?)` / `yFromTone(t, eps?)` | Same transfer in luminance space (0–1). |
|
|
1719
|
+
| `okhstToOkhsl({ h, s, t })` | OKHST → OKHSL (`{ h, s, l }`). |
|
|
1720
|
+
| `okhslToOkhst({ h, s, l })` | OKHSL → OKHST (`{ h, s, t }`). |
|
|
1721
|
+
| `variantToOkhsl(variant)` | `ResolvedColorVariant` (stores `t`) → `{ h, s, l, alpha }` for rendering. |
|
|
1722
|
+
| `REF_EPS` | Reference epsilon (`0.05`) for the canonical tone axis. |
|
|
1723
|
+
|
|
1724
|
+
`ResolvedColorVariant` stores `{ h, s, t, alpha }` (tone, not lightness). Use
|
|
1725
|
+
`variantToOkhsl(variant).l` to recover OKHSL lightness. See
|
|
1726
|
+
[OKHST in Glaze](okhst.md) for the model.
|
|
1727
|
+
|
|
1115
1728
|
### Contrast solver
|
|
1116
1729
|
|
|
1117
1730
|
```ts
|
|
1118
1731
|
import {
|
|
1119
|
-
|
|
1732
|
+
findToneForContrast,
|
|
1120
1733
|
findValueForMixContrast,
|
|
1734
|
+
resolveContrastForMode,
|
|
1121
1735
|
resolveMinContrast,
|
|
1736
|
+
apcaContrast,
|
|
1122
1737
|
} from '@tenphi/glaze';
|
|
1123
1738
|
```
|
|
1124
1739
|
|
|
1125
|
-
| Function
|
|
1126
|
-
|
|
1127
|
-
| `
|
|
1128
|
-
| `findValueForMixContrast(opts)`
|
|
1129
|
-
| `
|
|
1130
|
-
|
|
1131
|
-
`
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
|
1138
|
-
|
|
|
1139
|
-
| `
|
|
1140
|
-
| `
|
|
1141
|
-
| `
|
|
1142
|
-
| `
|
|
1143
|
-
| `
|
|
1144
|
-
| `
|
|
1145
|
-
|
|
1146
|
-
|
|
1740
|
+
| Function | Description |
|
|
1741
|
+
| ----------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1742
|
+
| `findToneForContrast(opts)` | Binary-search for the tone (0–1) that meets a contrast floor (WCAG or APCA) against a base color. Returns `{ tone, contrast, met, branch, flipped? }`. |
|
|
1743
|
+
| `findValueForMixContrast(opts)` | Same, but searches for a mix `value` (0–1) that meets a contrast floor between a base and a target. |
|
|
1744
|
+
| `resolveContrastForMode(spec, isHC, polarity?, outerExplicitHC?)` | Resolves a `ContrastSpec` to `{ metric: 'wcag' \| 'apca', target }` for the requested mode (picks the normal or HC entry of any pair). In HC, applies the metric's auto-enhancement unless `outerExplicitHC` is set or the inner metric pair carries an explicit HC value: APCA +15 Lc (clamped to 106); WCAG AA → AAA / AA-large → AAA-large (AAA-family and bare numbers unchanged). |
|
|
1745
|
+
| `resolveMinContrast(value)` | Resolves a `MinContrast` (WCAG preset or number) to a numeric ratio. |
|
|
1746
|
+
| `apcaContrast(yText, yBg)` | APCA Lc magnitude (0–106) for two relative luminances. |
|
|
1747
|
+
|
|
1748
|
+
Exported constants: `APCA_PRESETS`, `APCA_HC_ENHANCEMENT` (`15`, the Enhanced Level delta), `APCA_MAX_LC` (`106`).
|
|
1749
|
+
|
|
1750
|
+
`findToneForContrast` options:
|
|
1751
|
+
|
|
1752
|
+
| Option | Default | Description |
|
|
1753
|
+
| ------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
1754
|
+
| `hue` | — | Candidate hue (0–360). |
|
|
1755
|
+
| `saturation` | — | Candidate saturation (0–1). |
|
|
1756
|
+
| `preferredTone` | — | Preferred candidate tone (0–1). Kept if it already meets the target. |
|
|
1757
|
+
| `baseLinearRgb` | — | Base color as linear sRGB tuple. |
|
|
1758
|
+
| `contrast` | — | `ResolvedContrast` (`{ metric, target }`). |
|
|
1759
|
+
| `toneRange` | `[0, 1]` | Search bounds in tone. |
|
|
1760
|
+
| `epsilon` | `1e-4` | Convergence threshold. |
|
|
1761
|
+
| `maxIterations` | `18` | Max binary-search iterations per branch. |
|
|
1762
|
+
| `initialDirection` | higher-contrast side | Direction to search first (`'lighter'` or `'darker'`). |
|
|
1763
|
+
| `flip` | `false` | When `true`, try the opposite direction if the initial one doesn't meet the target. When `false`, only the initial direction is searched — unmet contrasts pin the result to that direction's extreme. |
|
|
1764
|
+
|
|
1765
|
+
Result: `{ tone, contrast, met, branch: 'lighter' | 'darker' | 'preferred', flipped? }`. `flipped: true` indicates the initial direction failed and the opposite direction satisfied the target.
|