@cube-dev/ui-kit 0.154.1 → 0.155.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 +35 -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 +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-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 +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.d.ts +2 -1
- package/dist/components/content/Item/Item.js +1 -1
- package/dist/components/content/Item/Item.js.map +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 +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 +21 -42
- package/dist/components/content/Text.js +4 -5
- package/dist/components/content/Text.js.map +1 -1
- package/dist/components/content/TextItem/TextItem.js +1 -1
- package/dist/components/content/Title.js +2 -3
- package/dist/components/content/Title.js.map +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.d.ts +0 -1
- package/dist/components/content/use-auto-tooltip.js +1 -1
- package/dist/components/content/use-auto-tooltip.js.map +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/DateInputBase.js.map +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/MonthPicker.js +1 -1
- package/dist/components/fields/DatePicker/PeriodPicker.js +1 -1
- package/dist/components/fields/DatePicker/QuarterPicker.js +1 -1
- package/dist/components/fields/DatePicker/TimeInput.js +1 -1
- package/dist/components/fields/DatePicker/WeekPicker.js +1 -1
- package/dist/components/fields/DatePicker/YearPicker.js +1 -1
- package/dist/components/fields/DatePicker/parseDate.js +1 -1
- package/dist/components/fields/DatePicker/period.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.d.ts +2 -1
- package/dist/components/fields/FileInput/FileInput.js +1 -1
- package/dist/components/fields/FileInput/FileInput.js.map +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.d.ts +2 -1
- package/dist/components/fields/Select/Select.js +1 -1
- package/dist/components/fields/Select/Select.js.map +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.d.ts +2 -1
- package/dist/components/fields/TextInput/TextInputBase.js +1 -1
- package/dist/components/fields/TextInput/TextInputBase.js.map +1 -1
- package/dist/components/fields/TextInputMapper/TextInputMapper.js +1 -1
- package/dist/components/form/FieldWrapper/FieldWrapper.d.ts +2 -1
- package/dist/components/form/FieldWrapper/FieldWrapper.js +1 -1
- package/dist/components/form/FieldWrapper/types.d.ts +2 -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/PeriodCalendar.js +1 -1
- package/dist/components/other/Calendar/RangeCalendar.js +1 -1
- package/dist/components/other/CubeLogo/CubeLogo.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/Modal.js.map +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/Overlay.js.map +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/Tray.js.map +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/overlays/Tooltip/context.js.map +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 +1 -1
- package/dist/data/themes.js +1 -1
- package/dist/eslint-plugin/defaults.generated.js +1 -1
- package/dist/eslint-plugin/index.js +1 -1
- package/dist/eslint-plugin/rules/no-redundant-default-prop.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 +2 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/props.d.ts +13 -0
- package/dist/provider.d.ts +1 -1
- package/dist/provider.js +1 -1
- package/dist/provider.js.map +1 -1
- package/dist/providers/TrackingProvider.js +1 -1
- package/dist/providers/navigationAdapter.default.js +1 -1
- package/dist/shared/form.d.ts +2 -1
- package/dist/tokens/base.js +1 -1
- package/dist/tokens/colors.js +1 -1
- package/dist/tokens/index.js +1 -1
- package/dist/tokens/layout.js +1 -1
- package/dist/tokens/lazy-styles.js +1 -1
- package/dist/tokens/palette-config.js +1 -1
- package/dist/tokens/palette.js +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.js +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.d.ts +1 -1
- package/dist/utils/react/mergeProps.js +1 -1
- package/dist/utils/react/mergeProps.js.map +1 -1
- package/dist/utils/react/nullableValue.d.ts +1 -1
- package/dist/utils/react/nullableValue.js +1 -1
- package/dist/utils/react/nullableValue.js.map +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 +3 -3
- package/docs/components/content/Text.md +1 -2
- package/docs/tasty/README.md +3 -1
- package/docs/tasty/ai-agents.md +21 -7
- package/docs/tasty/configuration.md +220 -30
- package/docs/tasty/debug.md +7 -7
- package/docs/tasty/design-system.md +2 -2
- package/docs/tasty/dsl.md +68 -8
- package/docs/tasty/injector.md +31 -4
- package/docs/tasty/methodology.md +1 -1
- package/docs/tasty/migration-v3.md +285 -0
- package/docs/tasty/pipeline.md +3 -3
- package/docs/tasty/plugins.md +349 -0
- package/docs/tasty/react-api.md +61 -1
- package/docs/tasty/ssr.md +41 -33
- package/docs/tasty/styles.md +27 -9
- package/docs/tasty/tasty-static.md +8 -6
- package/package.json +3 -3
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# Plugins & Extension Points
|
|
2
|
+
|
|
3
|
+
How to extend Tasty: new value syntax, new units, new states, new style properties, new component props, and how to package any of it as a plugin.
|
|
4
|
+
|
|
5
|
+
- [What a plugin is](#what-a-plugin-is)
|
|
6
|
+
- [Choosing an extension point](#choosing-an-extension-point)
|
|
7
|
+
- [Custom style handlers](#custom-style-handlers)
|
|
8
|
+
- [Props middleware](#props-middleware)
|
|
9
|
+
- [Base style props](#base-style-props)
|
|
10
|
+
- [Typing your extension](#typing-your-extension)
|
|
11
|
+
- [Worked example: a `glaze` plugin](#worked-example-a-glaze-plugin)
|
|
12
|
+
- [Rendering modes and caveats](#rendering-modes-and-caveats)
|
|
13
|
+
- [Testing a plugin](#testing-a-plugin)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## What a plugin is
|
|
18
|
+
|
|
19
|
+
A plugin is a plain object with a `name` and any subset of the `configure()` options it is allowed to supply. There is no lifecycle and no init hook — a plugin is just pre-packaged configuration.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { configure } from '@tenphi/tasty';
|
|
23
|
+
import type { TastyPluginFactory } from '@tenphi/tasty';
|
|
24
|
+
|
|
25
|
+
const spacingPlugin: TastyPluginFactory = () => ({
|
|
26
|
+
name: 'spacing',
|
|
27
|
+
units: { gu: (n) => `calc(${n} * var(--grid-unit))` },
|
|
28
|
+
tokens: { '$grid-unit': '4px' },
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
configure({ plugins: [spacingPlugin()] });
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`TastyPluginFactory<TOptions>` types a factory that takes options; with no type argument it types a zero-argument factory.
|
|
35
|
+
|
|
36
|
+
**Ordering.** Plugins are applied in array order and merged key by key, so a later plugin overrides an earlier one for the same key. Options passed directly to `configure()` are applied last and win over every plugin.
|
|
37
|
+
|
|
38
|
+
**Configuration is locked after the first render.** `configure()` warns and does nothing once any style has been generated, so it must run before your first component renders — at module scope in your entry file, or in a design-system module every component imports. `resetConfig()` reopens it, but it exists for tests.
|
|
39
|
+
|
|
40
|
+
**Repeated `configure()` calls merge** for `tokens` and `globalStyles` (per selector). See [Configuration](configuration.md) for the current per-key semantics.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Choosing an extension point
|
|
45
|
+
|
|
46
|
+
| You want to add | Use | Runs | Zero-runtime |
|
|
47
|
+
|---|---|---|---|
|
|
48
|
+
| New value syntax — `okhsl(…)`, `double(2x)` | `functions` (bare key) | parse time, per value | ✅ |
|
|
49
|
+
| A reusable CSS `@function` | `functions` (`$$name` key) | injected once, globally | ✅ |
|
|
50
|
+
| A new unit — `2gu` | `units` | parse time, per value | ✅ |
|
|
51
|
+
| A new state alias — `@mobile` | `states` | state-key parse | ✅ |
|
|
52
|
+
| A style property → **CSS declarations** | `handlers` | pipeline, per state snapshot | ✅ |
|
|
53
|
+
| A style property on every component | `baseStyleProps` | prop harvest | ✅ (styles only) |
|
|
54
|
+
| A **component prop** → anything | `propHandlers` | render, per component | ❌ (no props to run on) |
|
|
55
|
+
| A named bundle of styles | `recipes` | before chunking | ✅ |
|
|
56
|
+
| Typography scale tokens | `presets` | inject time | ✅ |
|
|
57
|
+
| `:root` variables | `tokens`, `replaceTokens` | inject time | ✅ |
|
|
58
|
+
| Global selector styles | `globalStyles` | inject time | ✅ |
|
|
59
|
+
|
|
60
|
+
Two distinctions do most of the work:
|
|
61
|
+
|
|
62
|
+
- **`handlers` vs `propHandlers`.** A handler turns a *style property* into CSS declarations and knows nothing about components. A prop handler turns a *component prop* into other props — including `styles`, which then flow through the normal handlers. Reach for `propHandlers` when the input isn't a style value (an options object, a domain concept) or when it should affect more than styles.
|
|
63
|
+
- **`recipes` vs `propHandlers`.** A recipe is a static named bundle. A prop handler computes its styles from a value.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Custom style handlers
|
|
68
|
+
|
|
69
|
+
A handler receives a map of the style properties it declared and returns CSS declarations. See [Configuration → Custom Style Handlers](configuration.md#custom-style-handlers) for the definition forms, return shape, the shared-handler groups you must be careful of, and chunk membership. The essentials:
|
|
70
|
+
|
|
71
|
+
- Values arrive **state-resolved but unparsed** — the raw authored DSL string (`'2x'`, `'#purple.5'`, `true`, `4`). Call the exported `parseStyle()` / `parseColor()` yourself.
|
|
72
|
+
- Return a `CSSMap` with **kebab-case** keys, an array of them, or nothing. `$` is a selector suffix, not a property.
|
|
73
|
+
- Handlers must be pure and synchronous. They are called once per state combination and the results are cached.
|
|
74
|
+
- Use `defineHandler(deps, fn)` for multi-dependency handlers so the dependency types are inferred.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { configure, defineHandler, parseStyle } from '@tenphi/tasty';
|
|
78
|
+
|
|
79
|
+
configure({
|
|
80
|
+
handlers: {
|
|
81
|
+
// Every declaration set the handler returns can target its own selector.
|
|
82
|
+
stripe: defineHandler(['stripe'], ({ stripe }) => {
|
|
83
|
+
if (!stripe) return;
|
|
84
|
+
|
|
85
|
+
const { values } = parseStyle(String(stripe)).groups[0];
|
|
86
|
+
|
|
87
|
+
return [
|
|
88
|
+
{ position: 'relative' },
|
|
89
|
+
{
|
|
90
|
+
$: '&::before',
|
|
91
|
+
content: '""',
|
|
92
|
+
position: 'absolute',
|
|
93
|
+
inset: '0 auto 0 0',
|
|
94
|
+
width: values[0],
|
|
95
|
+
background: 'var(--purple-color)',
|
|
96
|
+
},
|
|
97
|
+
];
|
|
98
|
+
}),
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Props middleware
|
|
106
|
+
|
|
107
|
+
`propHandlers` are middleware over a component's props: props in, props out. They run at the very top of every tasty component's render, before any prop is destructured, so a handler can read and rewrite `styles`, `mods`, `tokens`, `variant`, `as`, `element`, and `qa`, and can strip its own props so they never reach the DOM.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { configure, mergeStyles } from '@tenphi/tasty';
|
|
111
|
+
|
|
112
|
+
configure({
|
|
113
|
+
propHandlers: {
|
|
114
|
+
glaze: (props) => {
|
|
115
|
+
const { glaze, ...rest } = props;
|
|
116
|
+
if (!glaze) return rest;
|
|
117
|
+
|
|
118
|
+
return { ...rest, styles: mergeStyles(glazeStyles(glaze), rest.styles) };
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**The key is the trigger.** By default a handler runs only when a prop matching its key is present, so an absent prop costs one property check rather than a call. Override that with a tuple:
|
|
125
|
+
|
|
126
|
+
| Definition | Runs when |
|
|
127
|
+
|---|---|
|
|
128
|
+
| `fn` | a prop named after the key is present |
|
|
129
|
+
| `['glaze', fn]` | `glaze` is present |
|
|
130
|
+
| `[['glaze', 'tint'], fn]` | either is present |
|
|
131
|
+
| `['*', fn]` | always |
|
|
132
|
+
|
|
133
|
+
**Chaining.** Handlers run in registration order — plugins first, then direct `configure()` — and each receives the previous one's output. Registering the same key twice replaces the handler in place, keeping its position.
|
|
134
|
+
|
|
135
|
+
**Returning nothing means unchanged**, with a development-mode warning, because that is almost always a forgotten `return props`. A non-object return is ignored with a warning.
|
|
136
|
+
|
|
137
|
+
### Rules
|
|
138
|
+
|
|
139
|
+
- **Be pure. Never mutate the input.** Style values are cached by object identity, so mutating a value object in place yields a stale class name *and* stale CSS. Return fresh objects.
|
|
140
|
+
- **Memoize the styles you build, per input value.** A reference-stable (ideally frozen) styles object lets the cache key reuse its serialization instead of recomputing it on every render. This is the single highest-leverage thing you can do for performance.
|
|
141
|
+
- **Precedence is fixed** and not adjustable from a handler. Styles are merged as `factory defaults → styles → harvested style props`, and injected styles occupy the `styles` slot: they beat a component's own default styles and lose to a style prop passed at the call site. This matches how `recipe` already behaves.
|
|
142
|
+
- **Prefer returning `styles` over bare style props.** Returning `{ fill: '#red' }` only works if `fill` is harvestable on *that* component (in its `styleProps`, or promoted via `baseStyleProps`); otherwise it leaks to the DOM.
|
|
143
|
+
|
|
144
|
+
### What it cannot do
|
|
145
|
+
|
|
146
|
+
- **`ref`** — `forwardRef` separates it from props, so it is out of reach.
|
|
147
|
+
- **Sub-elements** (`Card.Title`) — they have no `styles` prop and no style-prop harvest, so middleware does not run on them.
|
|
148
|
+
- **Zero-runtime mode** — see [Rendering modes](#rendering-modes-and-caveats).
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Base style props
|
|
153
|
+
|
|
154
|
+
A small set of style properties — `display`, `font`, `preset`, `hide`, `whiteSpace`, `opacity`, `transition` — are harvested as props on every `tasty()` component. `baseStyleProps` adds to that set globally:
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
configure({ baseStyleProps: ['radius', 'shadow'] });
|
|
158
|
+
|
|
159
|
+
<Card radius="1r" shadow />
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Names must be real style properties, must start with a lowercase letter, and must not collide with a prop `tasty()` consumes itself (`as`, `styles`, `variant`, `mods`, `tokens`, …); invalid entries are dropped with a development warning.
|
|
163
|
+
|
|
164
|
+
`configure()` may run *after* your components are defined — each factory resolves its prop list lazily and refreshes when the registry changes.
|
|
165
|
+
|
|
166
|
+
**Costs and caveats.** Each name adds one property check per render of every component, forever, so keep the list short. The effect is app-global and cannot be scoped to a subtree — use a factory's own `styleProps` for that. Be wary of names that collide with real DOM or component props (`width`, `size`, `color`): promoting one means every component swallows it as a style, including when rendering `as={SomeThirdPartyComponent}`.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Typing your extension
|
|
171
|
+
|
|
172
|
+
Four augmentation points, each matching a runtime registry:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
// tasty.d.ts
|
|
176
|
+
import type { StylePropValue } from '@tenphi/tasty';
|
|
177
|
+
|
|
178
|
+
declare module '@tenphi/tasty' {
|
|
179
|
+
// configure({ handlers }) — a new style property
|
|
180
|
+
interface StylesInterface {
|
|
181
|
+
stripe?: StylePropValue<string>;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// configure({ propHandlers }) — a new component prop
|
|
185
|
+
interface TastyCustomProps {
|
|
186
|
+
glaze: 'soft' | 'strong' | { tone: string; intensity?: number };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// configure({ baseStyleProps }) — promoted style names, typed like the style
|
|
190
|
+
interface TastyBaseStylePropNames {
|
|
191
|
+
radius: true;
|
|
192
|
+
shadow: true;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// configure({ tokens }) / recipes / presets — autocomplete for names
|
|
196
|
+
interface TastyNamedColors {
|
|
197
|
+
'glaze-bg': true;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
`TastyCustomProps` keys become optional props on every component. `TastyBaseStylePropNames` entries are typed exactly like the style they name, so `radius="1r"` accepts the same values as `styles={{ radius: '1r' }}`.
|
|
203
|
+
|
|
204
|
+
**Also update `tasty.config.ts`.** The ESLint plugin and VS Code extension validate style and token names against it, and neither is derived from the runtime registries:
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
// tasty.config.ts
|
|
208
|
+
export default {
|
|
209
|
+
styles: ['stripe'],
|
|
210
|
+
tokens: ['#glaze-bg'],
|
|
211
|
+
};
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
`propHandlers` keys are JSX props rather than style keys, so they need no entry — but any *style* name or token a handler expands into does.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Worked example: a `glaze` plugin
|
|
219
|
+
|
|
220
|
+
A `glaze` prop on every component that takes a configuration object and expands into color token declarations. This is the case `propHandlers` exists for: the value is an options object, not a style value, so it cannot be a style property.
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
// glaze-plugin.ts
|
|
224
|
+
import { mergeStyles } from '@tenphi/tasty';
|
|
225
|
+
import type { Styles, TastyPluginFactory } from '@tenphi/tasty';
|
|
226
|
+
|
|
227
|
+
export interface GlazeConfig {
|
|
228
|
+
tone: string;
|
|
229
|
+
/** 0–100. Default 10. */
|
|
230
|
+
intensity?: number;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
type GlazeValue = string | GlazeConfig;
|
|
234
|
+
|
|
235
|
+
// Memoized per value so the styles object is reference-stable across renders.
|
|
236
|
+
const cache = new Map<string, Styles>();
|
|
237
|
+
|
|
238
|
+
function glazeStyles(value: GlazeValue): Styles {
|
|
239
|
+
const { tone, intensity = 10 } =
|
|
240
|
+
typeof value === 'string' ? { tone: value } : value;
|
|
241
|
+
const key = `${tone}:${intensity}`;
|
|
242
|
+
|
|
243
|
+
let styles = cache.get(key);
|
|
244
|
+
|
|
245
|
+
if (!styles) {
|
|
246
|
+
styles = Object.freeze({
|
|
247
|
+
'#glaze-bg': `#${tone}.${intensity}`,
|
|
248
|
+
fill: '#glaze-bg',
|
|
249
|
+
transition: 'fill 0.2s',
|
|
250
|
+
}) as Styles;
|
|
251
|
+
cache.set(key, styles);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return styles;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export const glazePlugin: TastyPluginFactory = () => ({
|
|
258
|
+
name: 'glaze',
|
|
259
|
+
|
|
260
|
+
propHandlers: {
|
|
261
|
+
glaze: (props) => {
|
|
262
|
+
const { glaze, ...rest } = props;
|
|
263
|
+
if (!glaze) return rest;
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
...rest,
|
|
267
|
+
styles: mergeStyles(
|
|
268
|
+
glazeStyles(glaze as GlazeValue),
|
|
269
|
+
rest.styles as Styles,
|
|
270
|
+
),
|
|
271
|
+
};
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
// Typed so `#glaze-bg` animates smoothly instead of snapping.
|
|
276
|
+
properties: {
|
|
277
|
+
'#glaze-bg': { syntax: '<color>', inherits: false, initialValue: 'transparent' },
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
// app entry, before the first render
|
|
284
|
+
import { configure } from '@tenphi/tasty';
|
|
285
|
+
|
|
286
|
+
import { glazePlugin } from './glaze-plugin';
|
|
287
|
+
|
|
288
|
+
configure({ plugins: [glazePlugin()] });
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
```tsx
|
|
292
|
+
<Element glaze="purple" />
|
|
293
|
+
<Element glaze={{ tone: 'success', intensity: 30 }} />
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
// tasty.d.ts
|
|
298
|
+
declare module '@tenphi/tasty' {
|
|
299
|
+
interface TastyCustomProps {
|
|
300
|
+
glaze: import('./glaze-plugin').GlazeConfig | string;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
The object value is unambiguous here precisely because `glaze` is a **prop**. A style *value* of the same shape would be indistinguishable from a state map (`{ tone: … }` looks exactly like `{ hovered: … }`), which is why this belongs in `propHandlers` rather than `handlers`.
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Rendering modes and caveats
|
|
310
|
+
|
|
311
|
+
| Mode | `functions` / `units` / `states` / `handlers` / `recipes` / `tokens` | `propHandlers` |
|
|
312
|
+
|---|---|---|
|
|
313
|
+
| Client | ✅ | ✅ |
|
|
314
|
+
| SSR / RSC | ✅ | ✅ |
|
|
315
|
+
| Zero-runtime (`tastyStatic`) | ✅ at build time | not applicable |
|
|
316
|
+
|
|
317
|
+
**Zero-runtime.** The Babel plugin transforms `tastyStatic()` calls, which take styles objects — there are no props in that pipeline, so there is nothing for props middleware to run on. Components you render through `tasty()` are untouched by the plugin and keep the runtime injector, so `propHandlers` work there exactly as in any client app; their CSS simply comes from the injector rather than the extracted stylesheet. Everything else runs at build time, which is why handlers, functions, and units must be pure functions of their input.
|
|
318
|
+
|
|
319
|
+
**Server and client must configure identically.** Class names are derived from resolved styles, so a handler or promoted prop registered on one side and not the other produces a hydration mismatch. This is the same requirement as `namePrefix` — see [SSR → Hydration mismatch warnings](ssr.md#hydration-mismatch-warnings).
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Testing a plugin
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
import { configure, resetConfig, renderStyles } from '@tenphi/tasty';
|
|
327
|
+
|
|
328
|
+
describe('glaze plugin', () => {
|
|
329
|
+
beforeEach(() => resetConfig());
|
|
330
|
+
afterEach(() => resetConfig());
|
|
331
|
+
|
|
332
|
+
it('expands into a color token declaration', () => {
|
|
333
|
+
configure({ plugins: [glazePlugin()] });
|
|
334
|
+
|
|
335
|
+
const rules = renderStyles({ '#glaze-bg': '#purple.10' }, '.test');
|
|
336
|
+
|
|
337
|
+
expect(rules[0].declarations).toContain('--glaze-bg-color');
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Two things to know:
|
|
343
|
+
|
|
344
|
+
- **Create components inside each test.** `resetConfig()` does not clear the per-factory class-name cache or prop-list memo, so a module-scope component created in one test carries state into the next.
|
|
345
|
+
- **Dev-mode warnings may not fire.** `isDevEnv()` reports `false` for `NODE_ENV=test`. Warnings that check it lazily can be enabled with `vi.stubEnv('NODE_ENV', 'development')`; some older ones capture it at module load and cannot be triggered from a test at all.
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
See [Configuration](configuration.md) for every option in detail, [Style DSL](dsl.md) for the value syntax your extensions produce, and [React API](react-api.md) for `tasty()`, `styleProps`, `modProps`, and `tokenProps`.
|
package/docs/tasty/react-api.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# React API
|
|
2
2
|
|
|
3
|
-
The React-specific `tasty()` component factory, component props, and style functions. All Tasty style functions — `tasty()` components, `useStyles()`, `useGlobalStyles()`, `useRawCSS()`, `useKeyframes()`, `useProperty()`, `useFontFace()`, and `
|
|
3
|
+
The React-specific `tasty()` component factory, component props, and style functions. All Tasty style functions — `tasty()` components, `useStyles()`, `useGlobalStyles()`, `useRawCSS()`, `useKeyframes()`, `useProperty()`, `useFontFace()`, `useCounterStyle()`, and `useFunction()` — are hook-free and compatible with React Server Components. No `'use client'` directive needed. For the shared style language (state maps, tokens, units, extending semantics), see [Style DSL](dsl.md). For global configuration, see [Configuration](configuration.md). For the broader docs map, see the [Docs Hub](README.md).
|
|
4
4
|
|
|
5
5
|
> **Note:** This file was previously named `runtime.md`. All functionality documented here works in both server and client contexts — "runtime" referred to style computation during React rendering, not to client-side JavaScript.
|
|
6
6
|
|
|
@@ -98,6 +98,26 @@ Style props accept state maps, so responsive values work through the same API:
|
|
|
98
98
|
|
|
99
99
|
For predefined style prop lists (`FLOW_STYLES`, `POSITION_STYLES`, `DIMENSION_STYLES`, etc.) and guidance on which props to expose per component category, see [Methodology — styleProps as the public API](methodology.md#styleprops-as-the-public-api).
|
|
100
100
|
|
|
101
|
+
### Always-available style props
|
|
102
|
+
|
|
103
|
+
A small set of style properties — `display`, `font`, `preset`, `hide`, `whiteSpace`, `opacity`, and `transition` — are always harvested as style props on every `tasty()` component, even when `styleProps` is omitted. This means you can pass `<Card display="grid" />` or `<Text preset="h1" />` without declaring them. When you do declare `styleProps`, these base props are unioned with your list (not replaced).
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## `Element`
|
|
108
|
+
|
|
109
|
+
`Element` is the unstyled base component exported from the main entry — equivalent to `tasty({})` (a `div` with no default styles). It accepts all Tasty props (`styles`, `styleProps`, `mods`, `tokens`, `as`, `qa`, `theme`, the `is*` props, etc.) and is useful as a generic styled box or as a building block for layout primitives.
|
|
110
|
+
|
|
111
|
+
```jsx
|
|
112
|
+
import { Element } from '@tenphi/tasty';
|
|
113
|
+
|
|
114
|
+
<Element as="section" padding="4x" fill="#surface">
|
|
115
|
+
Content
|
|
116
|
+
</Element>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
> Note: `Element` shadows the global DOM `Element` type when imported from `@tenphi/tasty`. In files that need the DOM type, alias the import: `import { Element as TastyElement } from '@tenphi/tasty'`.
|
|
120
|
+
|
|
101
121
|
---
|
|
102
122
|
|
|
103
123
|
## Mod Props
|
|
@@ -579,6 +599,46 @@ function useCounterStyle(
|
|
|
579
599
|
): string;
|
|
580
600
|
```
|
|
581
601
|
|
|
602
|
+
### useFunction
|
|
603
|
+
|
|
604
|
+
Register a CSS `@function` (custom function). Permanent — no cleanup on unmount. Deduplicates by function name. The function name accepts `$$name` (matching the call site `$$name(...)`), `$name`, or `--name`.
|
|
605
|
+
|
|
606
|
+
```tsx
|
|
607
|
+
import { tasty, useFunction } from '@tenphi/tasty';
|
|
608
|
+
|
|
609
|
+
const Box = tasty({ styles: { marginTop: '$$negative(10px)' } });
|
|
610
|
+
|
|
611
|
+
function Layout() {
|
|
612
|
+
useFunction('$$negative', { args: ['$value'], result: '(-1 * $value)' });
|
|
613
|
+
return <Box />;
|
|
614
|
+
}
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
Call the function through the Tasty DSL rather than a raw `style` prop. An inline `style` value reaches the browser unparsed, so the `$$name(...)` sugar is never expanded — and under `configure({ polyfills: { functions: true } })` it silently does nothing, because the polyfill rewrites calls at parse time.
|
|
618
|
+
|
|
619
|
+
Inside a `tasty()` component you call functions with the same `$$name(...)` sugar:
|
|
620
|
+
|
|
621
|
+
```tsx
|
|
622
|
+
const Box = tasty({
|
|
623
|
+
styles: {
|
|
624
|
+
'@function': { '$$negative': { args: ['$value'], result: '(-1 * $value)' } },
|
|
625
|
+
marginTop: '$$negative(10px)',
|
|
626
|
+
},
|
|
627
|
+
});
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
Signature:
|
|
631
|
+
|
|
632
|
+
```ts
|
|
633
|
+
function useFunction(
|
|
634
|
+
name: string,
|
|
635
|
+
definition: FunctionDefinition,
|
|
636
|
+
options?: { root?: Document | ShadowRoot },
|
|
637
|
+
): void;
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
See the [Functions section of the DSL reference](dsl.md#functions-function) for the full descriptor shape, token conventions, and value-sugar support. `@function` is an experimental CSS feature — unsupported browsers safely ignore the native rule, or enable the [`polyfills.functions`](configuration.md#polyfills) inline polyfill for full cross-browser support.
|
|
641
|
+
|
|
582
642
|
### Troubleshooting
|
|
583
643
|
|
|
584
644
|
- Styles are not updating: make sure `configure()` runs before first render, and verify the generated class name or global rule with [Debug Utilities](debug.md).
|
package/docs/tasty/ssr.md
CHANGED
|
@@ -18,18 +18,18 @@ The Astro integration (`@tenphi/tasty/ssr/astro`) has no additional dependencies
|
|
|
18
18
|
|
|
19
19
|
## How It Works
|
|
20
20
|
|
|
21
|
-
`tasty()` components are hook-free and use `computeStyles()` internally — a synchronous, framework-agnostic function. On the server, `computeStyles()` discovers a `ServerStyleCollector` via a registered getter (module-level for Next.js, `globalThis` for Astro/generic frameworks using `AsyncLocalStorage`) and collects CSS into it instead of trying to access the DOM. On the client, CSS is injected synchronously into the DOM during render; the injector's content-based cache makes this idempotent. The collector accumulates all styles
|
|
21
|
+
`tasty()` components are hook-free and use `computeStyles()` internally — a synchronous, framework-agnostic function. On the server, `computeStyles()` discovers a `ServerStyleCollector` via a registered getter (module-level for Next.js, `globalThis` for Astro/generic frameworks using `AsyncLocalStorage`) and collects CSS into it instead of trying to access the DOM. On the client, CSS is injected synchronously into the DOM during render; the injector's content-based cache makes this idempotent. The collector accumulates all styles and serializes them as `<style>` tags plus a class-list script in the HTML. On the client, `hydrateTastyClasses()` pre-populates the injector's rules map with the rendered class names so that `computeStyles()` skips the rendering pipeline entirely during hydration.
|
|
22
22
|
|
|
23
23
|
```
|
|
24
24
|
Server Client
|
|
25
25
|
────── ──────
|
|
26
|
-
tasty() renders
|
|
27
|
-
└─ computeStyles() └─
|
|
26
|
+
tasty() renders hydrateTastyClasses() reads window.__TASTY__
|
|
27
|
+
└─ computeStyles() └─ marks rendered class names as already-in-DOM
|
|
28
28
|
└─ collector.collect()
|
|
29
29
|
tasty() renders
|
|
30
30
|
After render: └─ computeStyles()
|
|
31
|
-
<style data-tasty-ssr>
|
|
32
|
-
<script
|
|
31
|
+
<style data-tasty-ssr> └─ class name known → skip pipeline
|
|
32
|
+
<script> (pushes to __TASTY__) └─ no CSS re-injection
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
---
|
|
@@ -85,8 +85,8 @@ That's it. All `tasty()` components inside the tree automatically get SSR suppor
|
|
|
85
85
|
- `TastyRegistry` is a `'use client'` component, but Next.js still server-renders it on initial page load. The `'use client'` boundary is required solely to access `useServerInsertedHTML` — **not** because `tasty()` components need the client.
|
|
86
86
|
- During SSR, `TastyRegistry` creates a `ServerStyleCollector` and registers it via a module-level getter (not `globalThis` — this avoids leaking between Next.js's separate RSC and SSR module graphs). It also wraps children in a React context provider so that hooks inside the SSR tree can discover the collector. All style functions — `tasty()` components, `computeStyles()`, `useStyles()`, `useGlobalStyles()`, `useRawCSS()`, `useKeyframes()`, `useProperty()`, `useFontFace()`, and `useCounterStyle()` — discover the collector through the module-level getter or context provider.
|
|
87
87
|
- `TastyRegistry` uses `useServerInsertedHTML` to flush collected CSS into the HTML stream as `<style data-tasty-ssr>` tags. This is fully streaming-compatible — styles are injected alongside each Suspense boundary as it resolves.
|
|
88
|
-
- A companion inline `<script>` tag
|
|
89
|
-
- When the `@tenphi/tasty/ssr/next` module loads on the client, `
|
|
88
|
+
- A companion inline `<script>` tag pushes the rendered class names into `window.__TASTY__` for each flush. This streaming-friendly approach accumulates the class list incrementally as Suspense boundaries resolve.
|
|
89
|
+
- When the `@tenphi/tasty/ssr/next` module loads on the client, `hydrateTastyClasses()` runs automatically from `window.__TASTY__` and pre-populates the injector's rules map. During hydration, `computeStyles()` sees the class name is already registered and skips the entire pipeline.
|
|
90
90
|
|
|
91
91
|
### Using Tasty in Server Components
|
|
92
92
|
|
|
@@ -188,7 +188,7 @@ This gives you:
|
|
|
188
188
|
|
|
189
189
|
- A `ServerStyleCollector` per request via `AsyncLocalStorage`, deduplicating CSS across all React trees on the page
|
|
190
190
|
- A single consolidated `<style data-tasty-ssr>` injected into `</head>`
|
|
191
|
-
- A `<script
|
|
191
|
+
- A `<script>` tag pushing the rendered class names into `window.__TASTY__` for client hydration
|
|
192
192
|
- Auto-injected client hydration script (via `injectScript('before-hydration')`) so islands skip the style pipeline during hydration -- no need to import anything manually in each island component
|
|
193
193
|
|
|
194
194
|
All style functions (`useGlobalStyles`, `useRawCSS`, `useKeyframes`, `useProperty`, `useFontFace`, `useCounterStyle`) work on the server.
|
|
@@ -223,7 +223,7 @@ export default defineConfig({
|
|
|
223
223
|
});
|
|
224
224
|
```
|
|
225
225
|
|
|
226
|
-
This gives the same middleware deduplication and hook support, but ships zero client-side JavaScript. No `<script
|
|
226
|
+
This gives the same middleware deduplication and hook support, but ships zero client-side JavaScript. No class-list `<script>` is emitted.
|
|
227
227
|
|
|
228
228
|
### Manual middleware (advanced)
|
|
229
229
|
|
|
@@ -258,7 +258,7 @@ export const onRequest = tastyMiddleware({ transferCache: false });
|
|
|
258
258
|
Astro's `@astrojs/react` renderer calls `renderToString()` for each React component without wrapping the tree in a provider. The middleware creates a `ServerStyleCollector` and binds it via `AsyncLocalStorage`. All `computeStyles()` calls within the request discover this collector automatically.
|
|
259
259
|
|
|
260
260
|
- **Static components** (no `client:*`): Styles are collected during `renderToString` and injected into `</head>` as a single `<style>` tag. No JavaScript is shipped.
|
|
261
|
-
- **Islands** (`client:load`, `client:visible`, etc.): Styles are collected during SSR the same way. On the client, the hydration script (auto-injected by `tastyIntegration()` or manually via `@tenphi/tasty/ssr/astro-client`) reads the
|
|
261
|
+
- **Islands** (`client:load`, `client:visible`, etc.): Styles are collected during SSR the same way. On the client, the hydration script (auto-injected by `tastyIntegration()` or manually via `@tenphi/tasty/ssr/astro-client`) reads the class list from `window.__TASTY__` and pre-populates the injector's rules map. The island's `computeStyles()` calls see the class names as already registered and skip the pipeline during hydration.
|
|
262
262
|
- The middleware reads the full response body, then injects the collected CSS into `</head>` before sending the final HTML.
|
|
263
263
|
|
|
264
264
|
### CSP nonce
|
|
@@ -274,31 +274,30 @@ Any React-based framework can integrate using `runWithCollector`, which binds a
|
|
|
274
274
|
```tsx
|
|
275
275
|
import {
|
|
276
276
|
ServerStyleCollector,
|
|
277
|
+
createServerStyleCollector,
|
|
277
278
|
runWithCollector,
|
|
278
|
-
|
|
279
|
+
hydrateTastyClasses,
|
|
279
280
|
} from '@tenphi/tasty/ssr';
|
|
280
281
|
import { renderToString } from 'react-dom/server';
|
|
281
282
|
import { hydrateRoot } from 'react-dom/client';
|
|
282
283
|
|
|
283
284
|
// ── Server ──────────────────────────────────────────────
|
|
284
285
|
|
|
285
|
-
const collector =
|
|
286
|
+
const collector = createServerStyleCollector();
|
|
286
287
|
|
|
287
288
|
const html = await runWithCollector(collector, () =>
|
|
288
289
|
renderToString(<App />)
|
|
289
290
|
);
|
|
290
291
|
|
|
291
292
|
const css = collector.getCSS();
|
|
292
|
-
const
|
|
293
|
+
const classNames = collector.getRenderedClassNames();
|
|
293
294
|
|
|
294
295
|
// Embed in your HTML template:
|
|
295
296
|
const fullHtml = `
|
|
296
297
|
<html>
|
|
297
298
|
<head>
|
|
298
299
|
<style data-tasty-ssr>${css}</style>
|
|
299
|
-
<script
|
|
300
|
-
${JSON.stringify(cacheState)}
|
|
301
|
-
</script>
|
|
300
|
+
<script>(window.__TASTY__=window.__TASTY__||[]).push(${JSON.stringify(classNames)})</script>
|
|
302
301
|
</head>
|
|
303
302
|
<body>
|
|
304
303
|
<div id="root">${html}</div>
|
|
@@ -309,7 +308,7 @@ const fullHtml = `
|
|
|
309
308
|
// ── Client ──────────────────────────────────────────────
|
|
310
309
|
|
|
311
310
|
// Before hydration:
|
|
312
|
-
|
|
311
|
+
hydrateTastyClasses(); // reads from window.__TASTY__
|
|
313
312
|
|
|
314
313
|
hydrateRoot(document.getElementById('root'), <App />);
|
|
315
314
|
```
|
|
@@ -319,7 +318,7 @@ hydrateRoot(document.getElementById('root'), <App />);
|
|
|
319
318
|
For streaming with `renderToPipeableStream`, use `flushCSS()` instead of `getCSS()`:
|
|
320
319
|
|
|
321
320
|
```tsx
|
|
322
|
-
const collector =
|
|
321
|
+
const collector = createServerStyleCollector();
|
|
323
322
|
|
|
324
323
|
const stream = await runWithCollector(collector, () =>
|
|
325
324
|
renderToPipeableStream(<App />, {
|
|
@@ -330,12 +329,14 @@ const stream = await runWithCollector(collector, () =>
|
|
|
330
329
|
stream.pipe(res);
|
|
331
330
|
},
|
|
332
331
|
onAllReady() {
|
|
333
|
-
// Flush any remaining styles +
|
|
332
|
+
// Flush any remaining styles + class list
|
|
334
333
|
const css = collector.flushCSS();
|
|
335
334
|
if (css) res.write(`<style data-tasty-ssr>${css}</style>`);
|
|
336
335
|
|
|
337
|
-
const
|
|
338
|
-
res.write(
|
|
336
|
+
const classNames = collector.getRenderedClassNames();
|
|
337
|
+
res.write(
|
|
338
|
+
`<script>(window.__TASTY__=window.__TASTY__||[]).push(${JSON.stringify(classNames)})</script>`,
|
|
339
|
+
);
|
|
339
340
|
},
|
|
340
341
|
})
|
|
341
342
|
);
|
|
@@ -349,16 +350,17 @@ const stream = await runWithCollector(collector, () =>
|
|
|
349
350
|
|
|
350
351
|
| Import path | Description |
|
|
351
352
|
|---|---|
|
|
352
|
-
| `@tenphi/tasty/ssr` | Core SSR API: `ServerStyleCollector`, `runWithCollector`, `
|
|
353
|
+
| `@tenphi/tasty/ssr` | Core SSR API: `ServerStyleCollector`, `createServerStyleCollector`, `runWithCollector`, `hydrateTastyClasses` |
|
|
353
354
|
| `@tenphi/tasty/ssr/next` | Next.js App Router: `TastyRegistry` component |
|
|
354
355
|
| `@tenphi/tasty/ssr/astro` | Astro: `tastyIntegration`, `tastyMiddleware` |
|
|
355
356
|
| `@tenphi/tasty/ssr/astro-client` | Astro: client-side cache hydration (auto-injected by integration, or import manually) |
|
|
357
|
+
| `@tenphi/tasty/ssr/astro-middleware`<br>`@tenphi/tasty/ssr/astro-middleware-static` | Astro: the middleware entrypoints `tastyIntegration()` registers via `addMiddleware()`. Exported so Astro can resolve them by specifier; you should not import them. For manual setups use `tastyMiddleware()`. |
|
|
356
358
|
|
|
357
359
|
### `ServerStyleCollector`
|
|
358
360
|
|
|
359
361
|
Server-safe style collector. One instance per request.
|
|
360
362
|
|
|
361
|
-
Constructor: `new ServerStyleCollector(namePrefix?)
|
|
363
|
+
Constructor: `new ServerStyleCollector(namePrefix?)`, or use the `createServerStyleCollector(namePrefix?)` factory. The optional `namePrefix` overrides the value from `configure({ namePrefix })`; in normal usage you pass nothing and let the global config drive it. See [Configuration: Name prefix](configuration.md#name-prefix).
|
|
362
364
|
|
|
363
365
|
| Method | Description |
|
|
364
366
|
|---|---|
|
|
@@ -375,7 +377,7 @@ Constructor: `new ServerStyleCollector(namePrefix?)`. The optional `namePrefix`
|
|
|
375
377
|
| `collectInternals()` | Collect internal `@property` rules, `:root` token defaults, `@font-face`, and `@counter-style` rules from the global config. Called automatically on first chunk collection; idempotent. |
|
|
376
378
|
| `getCSS()` | Get all collected CSS as a single string. For non-streaming SSR. |
|
|
377
379
|
| `flushCSS()` | Get only CSS collected since the last flush. For streaming SSR. |
|
|
378
|
-
| `
|
|
380
|
+
| `getRenderedClassNames()` | Get the list of class names rendered so far. Serialized to `window.__TASTY__` for client hydration via `hydrateTastyClasses()`. |
|
|
379
381
|
|
|
380
382
|
### `TastyRegistry`
|
|
381
383
|
|
|
@@ -402,9 +404,9 @@ Astro middleware factory. Use for manual middleware composition.
|
|
|
402
404
|
|---|---|---|---|
|
|
403
405
|
| `transferCache` | `boolean` | `true` | Embed cache state script for island hydration |
|
|
404
406
|
|
|
405
|
-
### `
|
|
407
|
+
### `hydrateTastyClasses(classes?)`
|
|
406
408
|
|
|
407
|
-
Pre-populate the client injector
|
|
409
|
+
Pre-populate the client injector's rules map with class names rendered on the server, marking them as already present in the DOM so `computeStyles()` skips re-injection during hydration. When called without arguments, reads the class list from `window.__TASTY__` (populated by the streaming `<script>` tags emitted during SSR).
|
|
408
410
|
|
|
409
411
|
### `runWithCollector(collector, fn)`
|
|
410
412
|
|
|
@@ -420,23 +422,29 @@ The `TastyRegistry` or `tastyIntegration` is missing. Ensure your layout wraps t
|
|
|
420
422
|
|
|
421
423
|
### Hydration mismatch warnings
|
|
422
424
|
|
|
423
|
-
Class names are deterministic for the same render order. If you see mismatches, ensure `
|
|
425
|
+
Class names are deterministic for the same render order. If you see mismatches, ensure `hydrateTastyClasses()` runs before React hydration. For Next.js, this is automatic. For Astro with `tastyIntegration()`, this is also automatic. For manual Astro middleware setups, import `@tenphi/tasty/ssr/astro-client` in your island components. For custom setups, call `hydrateTastyClasses()` before `hydrateRoot()`.
|
|
426
|
+
|
|
427
|
+
Class names are also derived from the *resolved* styles, so the server and the client must configure Tasty identically. Anything that changes what a component's styles resolve to will produce a mismatch if it is registered on only one side — `namePrefix`, `recipes`, `handlers`, and the `propHandlers` / `baseStyleProps` extension points described in [Plugins](plugins.md). Call the same `configure()` on both; global CSS is deduplicated automatically, so no `typeof window` guard is needed.
|
|
424
428
|
|
|
425
429
|
### Styles duplicated after hydration
|
|
426
430
|
|
|
427
431
|
**Global CSS** (`:root` tokens, `@property`, `globalStyles`, `@font-face`, `@counter-style`) configured via `configure()` is automatically deduplicated. When Tasty detects `<style data-tasty-ssr>` in the document, it skips client-side injection of globals that were already rendered by the SSR collector. This means `configure()` can be called with the full config on both server and client — no `typeof window === 'undefined'` guard is needed.
|
|
428
432
|
|
|
429
|
-
**Component CSS**: SSR `<style data-tasty-ssr>` tags remain in the DOM. The client injector creates separate `<style>` elements for any new styles. SSR styles are never modified or removed by the client. If this is a concern for very large apps,
|
|
433
|
+
**Component CSS**: SSR `<style data-tasty-ssr>` tags remain in the DOM. The client injector creates separate `<style>` elements for any new styles. SSR styles are never modified or removed by the client. If this is a concern for very large apps, you can remove the SSR style tags and hydration scripts manually after hydration:
|
|
430
434
|
|
|
431
435
|
```tsx
|
|
432
|
-
import {
|
|
436
|
+
import { hydrateTastyClasses } from '@tenphi/tasty/ssr';
|
|
433
437
|
|
|
434
|
-
|
|
438
|
+
hydrateTastyClasses();
|
|
435
439
|
hydrateRoot(root, <App />);
|
|
436
440
|
|
|
437
|
-
// Optional: remove SSR style tags after hydration
|
|
438
|
-
document.querySelectorAll('style[data-tasty-ssr]').forEach(el => el.remove());
|
|
439
|
-
document
|
|
441
|
+
// Optional: remove SSR style tags and class-list scripts after hydration
|
|
442
|
+
document.querySelectorAll('style[data-tasty-ssr]').forEach((el) => el.remove());
|
|
443
|
+
document
|
|
444
|
+
.querySelectorAll('script')
|
|
445
|
+
.forEach((el) => {
|
|
446
|
+
if (el.textContent?.includes('__TASTY__')) el.remove();
|
|
447
|
+
});
|
|
440
448
|
```
|
|
441
449
|
|
|
442
450
|
### `AsyncLocalStorage` not available
|