@astryxdesign/core 0.5.0 → 0.5.1-canary.8359f1a
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/CHANGELOG.md +222 -0
- package/dist/AlertDialog/AlertDialog.d.ts +1 -1
- package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
- package/dist/AlertDialog/AlertDialog.js +45 -20
- package/dist/AspectRatio/AspectRatio.d.ts +6 -6
- package/dist/Avatar/Avatar.d.ts +25 -1
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +43 -9
- package/dist/Avatar/index.d.ts +2 -2
- package/dist/Avatar/index.d.ts.map +1 -1
- package/dist/Avatar/index.js +1 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts +9 -2
- package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroup.js +5 -2
- package/dist/AvatarGroup/AvatarGroupContext.d.ts +2 -1
- package/dist/AvatarGroup/AvatarGroupContext.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +11 -7
- package/dist/Badge/Badge.d.ts.map +1 -1
- package/dist/Badge/Badge.js +26 -2
- package/dist/Banner/Banner.d.ts +10 -1
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +11 -2
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +8 -7
- package/dist/Calendar/Calendar.d.ts +4 -2
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +15 -21
- package/dist/Calendar/hooks/useCalendarDays.js +4 -6
- package/dist/Calendar/hooks/useCalendarNavigation.js +4 -6
- package/dist/Calendar/styles.d.ts +5 -20
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +15 -17
- package/dist/Card/Card.d.ts +12 -12
- package/dist/Card/Card.d.ts.map +1 -1
- package/dist/Card/Card.js +17 -9
- package/dist/Card/index.d.ts +35 -1
- package/dist/Card/index.d.ts.map +1 -1
- package/dist/Card/index.js +21 -1
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +108 -7
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +7 -1
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +15 -4
- package/dist/CodeBlock/highlightRanges.js +1 -1
- package/dist/CodeBlock/highlightStyles.js +13 -13
- package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteItem.js +2 -7
- package/dist/ComplexSelector/ComplexSelector.d.ts +10 -2
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +14 -7
- package/dist/DateInput/DateInput.d.ts +43 -0
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +22 -5
- package/dist/DateInput/MonthScroller.d.ts.map +1 -1
- package/dist/DateInput/MonthScroller.js +5 -3
- package/dist/DateInput/MonthYearWheels.d.ts.map +1 -1
- package/dist/DateInput/MonthYearWheels.js +6 -4
- package/dist/DateInput/NativeDateField.d.ts +10 -0
- package/dist/DateInput/NativeDateField.d.ts.map +1 -0
- package/dist/DateInput/NativeDateField.js +494 -0
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +52 -25
- package/dist/DateInput/Wheel.d.ts.map +1 -1
- package/dist/DateInput/Wheel.js +1 -0
- package/dist/DateInput/index.d.ts +1 -1
- package/dist/DateInput/index.d.ts.map +1 -1
- package/dist/DateInput/nativeDateSegments.d.ts +22 -0
- package/dist/DateInput/nativeDateSegments.d.ts.map +1 -0
- package/dist/DateInput/nativeDateSegments.js +111 -0
- package/dist/DateRangeInput/DateRangeInput.d.ts +4 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +3 -5
- package/dist/DateTimeInput/DateTimeInput.d.ts +23 -24
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +35 -10
- package/dist/DateTimeInput/TouchDateTimeField.d.ts +6 -0
- package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -0
- package/dist/DateTimeInput/TouchDateTimeField.js +1021 -0
- package/dist/Dialog/Dialog.d.ts +16 -2
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +28 -7
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +4 -13
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +9 -1
- package/dist/Field/InputClearButton.d.ts +9 -3
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +14 -3
- package/dist/Heading/Heading.d.ts.map +1 -1
- package/dist/Heading/Heading.js +0 -1
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +104 -3
- package/dist/HoverCard/useHoverCard.d.ts +14 -2
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +7 -1
- package/dist/Icon/Icon.d.ts +4 -2
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/defaultIcons.d.ts +3 -2
- package/dist/Icon/defaultIcons.d.ts.map +1 -1
- package/dist/Icon/defaultIcons.js +7 -0
- package/dist/Icon/globalIconRegistry.d.ts +13 -0
- package/dist/Icon/globalIconRegistry.d.ts.map +1 -1
- package/dist/Icon/globalIconRegistry.js +34 -6
- package/dist/Icon/index.d.ts +1 -1
- package/dist/Icon/index.d.ts.map +1 -1
- package/dist/Icon/useIcon.d.ts +5 -2
- package/dist/Icon/useIcon.d.ts.map +1 -1
- package/dist/Icon/useIcon.js +3 -0
- package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
- package/dist/Indicator/CheckboxIndicator.js +6 -2
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +2 -2
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +2 -26
- package/dist/Layer/gestureCounter.d.ts +8 -0
- package/dist/Layer/gestureCounter.d.ts.map +1 -0
- package/dist/Layer/gestureCounter.js +53 -0
- package/dist/Layer/useLayer.d.ts +23 -13
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +146 -24
- package/dist/List/List.d.ts +1 -1
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +15 -4
- package/dist/Markdown/Markdown.d.ts +1 -1
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +20 -7
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +5 -3
- package/dist/MetadataList/MetadataListItem.d.ts +1 -1
- package/dist/MetadataList/MetadataListItem.d.ts.map +1 -1
- package/dist/MetadataList/MetadataListItem.js +4 -1
- package/dist/MultiSelector/MultiSelector.d.ts +18 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +58 -11
- package/dist/MultiSelector/hooks.d.ts +7 -1
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +3 -2
- package/dist/NavIcon/NavIcon.d.ts.map +1 -1
- package/dist/NavIcon/NavIcon.js +5 -1
- package/dist/NavItem/navItemStyles.stylex.d.ts +0 -8
- package/dist/NavItem/navItemStyles.stylex.d.ts.map +1 -1
- package/dist/NavItem/navItemStyles.stylex.js +0 -2
- package/dist/NavMenu/NavHeadingMenu.d.ts +1 -1
- package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenu.js +7 -4
- package/dist/NumberInput/NumberInput.d.ts +6 -1
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +95 -126
- package/dist/NumberInput/numberInputCommit.d.ts +34 -0
- package/dist/NumberInput/numberInputCommit.d.ts.map +1 -0
- package/dist/NumberInput/numberInputCommit.js +71 -0
- package/dist/NumberInput/numberParser.d.ts +64 -0
- package/dist/NumberInput/numberParser.d.ts.map +1 -0
- package/dist/NumberInput/numberParser.js +350 -0
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +2 -3
- package/dist/OverflowList/OverflowList.d.ts +41 -1
- package/dist/OverflowList/OverflowList.d.ts.map +1 -1
- package/dist/OverflowList/OverflowList.js +43 -2
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +8 -14
- package/dist/Popover/usePopover.d.ts +15 -41
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +26 -7
- package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchValueEditor.js +91 -18
- package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
- package/dist/PowerSearch/formatFilterValue.js +4 -2
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +18 -5
- package/dist/Resizable/useResizable.d.ts +19 -1
- package/dist/Resizable/useResizable.d.ts.map +1 -1
- package/dist/Resizable/useResizable.js +104 -38
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +9 -0
- package/dist/Selector/Selector.d.ts +18 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +92 -21
- package/dist/Selector/hooks.d.ts +7 -1
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +3 -2
- package/dist/SideNav/SideNav.d.ts +6 -1
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +57 -27
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +5 -4
- package/dist/SideNav/SideNavItem.d.ts +29 -4
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +75 -20
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +34 -2
- package/dist/Spinner/Spinner.d.ts +3 -1
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +199 -20
- package/dist/StatusDot/StatusDot.d.ts.map +1 -1
- package/dist/StatusDot/StatusDot.js +6 -1
- package/dist/Stepper/Step.d.ts.map +1 -1
- package/dist/Stepper/Step.js +7 -6
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +5 -1
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +6 -1
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +3 -6
- package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
- package/dist/Table/plugins/filtering/useTableFiltering.js +73 -4
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +26 -0
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +34 -3
- package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
- package/dist/Table/plugins/selection/useTableSelection.js +25 -1
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +3 -4
- package/dist/Text/Text.d.ts.map +1 -1
- package/dist/Text/Text.js +0 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +13 -8
- package/dist/Timestamp/Timestamp.d.ts +1 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +10 -18
- package/dist/Timestamp/formatInstant.d.ts.map +1 -1
- package/dist/Timestamp/formatInstant.js +10 -5
- package/dist/Toast/Toast.d.ts +17 -2
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +77 -11
- package/dist/Toast/ToastViewport.d.ts +1 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +76 -21
- package/dist/Toast/index.d.ts +1 -1
- package/dist/Toast/index.d.ts.map +1 -1
- package/dist/Toast/types.d.ts +38 -0
- package/dist/Toast/types.d.ts.map +1 -1
- package/dist/Toast/useToastGesture.d.ts +26 -0
- package/dist/Toast/useToastGesture.d.ts.map +1 -0
- package/dist/Toast/useToastGesture.js +223 -0
- package/dist/Token/Token.d.ts +1 -1
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +23 -12
- package/dist/Token/TokenLink.d.ts +1 -1
- package/dist/Token/TokenLink.d.ts.map +1 -1
- package/dist/Token/TokenLink.js +5 -2
- package/dist/Tokenizer/Tokenizer.d.ts +12 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +31 -21
- package/dist/TopNav/TopNavHeading.js +2 -2
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +3 -3
- package/dist/TopNav/TopNavMegaMenu.d.ts +1 -1
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +30 -9
- package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuItem.js +3 -3
- package/dist/TopNav/TopNavMenu.d.ts +1 -1
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +21 -6
- package/dist/TreeList/TreeList.d.ts +1 -1
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +7 -2
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +2 -2
- package/dist/Typeahead/BaseTypeahead.d.ts +33 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +51 -8
- package/dist/Typeahead/Typeahead.d.ts +8 -1
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +2 -0
- package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
- package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
- package/dist/Typeahead/TypeaheadItem.js +7 -2
- package/dist/astryx.css +87 -22
- package/dist/hooks/useHotkeys.d.ts.map +1 -1
- package/dist/hooks/useHotkeys.js +3 -25
- package/dist/hooks/useOverflow.d.ts.map +1 -1
- package/dist/hooks/useOverflow.js +14 -4
- package/dist/i18n/InternationalizationContext.d.ts +2 -0
- package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
- package/dist/i18n/InternationalizationContext.js +3 -1
- package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
- package/dist/i18n/InternationalizationProvider.js +3 -1
- package/dist/i18n/resolve.d.ts +1 -1
- package/dist/i18n/resolve.d.ts.map +1 -1
- package/dist/i18n/resolve.js +37 -38
- package/dist/i18n/useTranslator.d.ts.map +1 -1
- package/dist/i18n/useTranslator.js +2 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/theme/Theme.d.ts.map +1 -1
- package/dist/theme/Theme.js +46 -10
- package/dist/theme/defineTheme.d.ts +9 -3
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +5 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +24 -4
- package/dist/theme/generateThemeRules.d.ts +21 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +26 -0
- package/dist/theme/syntax/tokens.d.ts +1 -1
- package/dist/theme/syntax/tokens.d.ts.map +1 -1
- package/dist/theme/syntax/tokens.js +5 -2
- package/dist/theme/useTheme.d.ts.map +1 -1
- package/dist/theme/useTheme.js +6 -7
- package/dist/utils/dateParser.d.ts +5 -8
- package/dist/utils/dateParser.d.ts.map +1 -1
- package/dist/utils/dateParser.js +10 -11
- package/dist/utils/focusOutline.stylex.d.ts +25 -0
- package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
- package/dist/utils/focusOutline.stylex.js +15 -0
- package/dist/utils/interactionOverlay.stylex.d.ts +26 -0
- package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -0
- package/dist/utils/interactionOverlay.stylex.js +42 -0
- package/dist/utils/isApplePlatform.d.ts +18 -0
- package/dist/utils/isApplePlatform.d.ts.map +1 -0
- package/dist/utils/isApplePlatform.js +37 -0
- package/dist/utils/plainDate.d.ts +11 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +20 -4
- package/locales/af-ZA.json +7 -7
- package/locales/ar-SA.json +7 -7
- package/locales/ca-ES.json +6 -6
- package/locales/cs-CZ.json +7 -7
- package/locales/da-DK.json +7 -7
- package/locales/de-DE.json +7 -7
- package/locales/el-GR.json +7 -7
- package/locales/en.json +178 -6
- package/locales/es-ES.json +6 -6
- package/locales/fi-FI.json +7 -7
- package/locales/fr-FR.json +7 -7
- package/locales/he-IL.json +7 -7
- package/locales/hu-HU.json +7 -7
- package/locales/it-IT.json +7 -7
- package/locales/ja-JP.json +7 -7
- package/locales/ko-KR.json +7 -7
- package/locales/nl-NL.json +7 -7
- package/locales/no-NO.json +7 -7
- package/locales/pl-PL.json +7 -7
- package/locales/pseudo.json +130 -1
- package/locales/pt-BR.json +7 -7
- package/locales/pt-PT.json +7 -7
- package/locales/ro-RO.json +7 -7
- package/locales/ru-RU.json +7 -7
- package/locales/sr-SP.json +7 -7
- package/locales/sv-SE.json +7 -7
- package/locales/tr-TR.json +7 -7
- package/locales/uk-UA.json +7 -7
- package/locales/vi-VN.json +7 -7
- package/locales/zh-CN.json +7 -7
- package/locales/zh-TW.json +7 -7
- package/package.json +4 -5
- package/src/AlertDialog/AlertDialog.doc.mjs +114 -30
- package/src/AlertDialog/AlertDialog.test.tsx +211 -2
- package/src/AlertDialog/AlertDialog.tsx +62 -20
- package/src/AspectRatio/AspectRatio.doc.mjs +3 -3
- package/src/AspectRatio/AspectRatio.tsx +6 -6
- package/src/Avatar/Avatar.doc.mjs +12 -2
- package/src/Avatar/Avatar.test.tsx +80 -0
- package/src/Avatar/Avatar.tsx +64 -14
- package/src/Avatar/index.ts +2 -2
- package/src/AvatarGroup/AvatarGroup.doc.mjs +8 -2
- package/src/AvatarGroup/AvatarGroup.test.tsx +24 -0
- package/src/AvatarGroup/AvatarGroup.tsx +12 -4
- package/src/AvatarGroup/AvatarGroupContext.ts +5 -3
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +12 -12
- package/src/Badge/Badge.doc.mjs +3 -2
- package/src/Badge/Badge.test.tsx +32 -3
- package/src/Badge/Badge.tsx +42 -1
- package/src/Banner/Banner.doc.mjs +9 -0
- package/src/Banner/Banner.test.tsx +76 -11
- package/src/Banner/Banner.tsx +21 -2
- package/src/Button/Button.doc.mjs +2 -1
- package/src/Button/Button.test.tsx +19 -4
- package/src/Button/Button.tsx +9 -29
- package/src/ButtonGroup/ButtonGroup.doc.mjs +2 -2
- package/src/ButtonGroup/ButtonGroup.test.tsx +13 -0
- package/src/Calendar/Calendar.doc.mjs +3 -3
- package/src/Calendar/Calendar.test.tsx +112 -0
- package/src/Calendar/Calendar.tsx +18 -16
- package/src/Calendar/hooks/useCalendarDays.ts +4 -4
- package/src/Calendar/hooks/useCalendarNavigation.ts +4 -4
- package/src/Calendar/styles.ts +48 -42
- package/src/Card/Card.doc.mjs +10 -7
- package/src/Card/Card.test.tsx +113 -19
- package/src/Card/Card.tsx +67 -89
- package/src/Card/index.ts +36 -1
- package/src/Carousel/Carousel.doc.mjs +3 -0
- package/src/Carousel/Carousel.test.tsx +360 -0
- package/src/Carousel/Carousel.tsx +116 -15
- package/src/CheckboxInput/CheckboxInput.doc.mjs +2 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +15 -0
- package/src/CheckboxInput/CheckboxInput.tsx +5 -0
- package/src/CodeBlock/CodeBlock.doc.mjs +10 -4
- package/src/CodeBlock/CodeBlock.test.tsx +37 -0
- package/src/CodeBlock/CodeBlock.tsx +20 -4
- package/src/CodeBlock/highlightRanges.ts +1 -1
- package/src/CodeBlock/highlightStyles.ts +13 -13
- package/src/CommandPalette/CommandPaletteItem.tsx +2 -12
- package/src/ComplexSelector/ComplexSelector.doc.mjs +7 -0
- package/src/ComplexSelector/ComplexSelector.test.tsx +183 -0
- package/src/ComplexSelector/ComplexSelector.tsx +22 -12
- package/src/DateInput/DateInput.doc.mjs +16 -0
- package/src/DateInput/DateInput.test.tsx +9 -4
- package/src/DateInput/DateInput.tsx +54 -3
- package/src/DateInput/DateInputTouch.test.tsx +146 -32
- package/src/DateInput/MonthScroller.tsx +5 -1
- package/src/DateInput/MonthYearWheels.tsx +7 -4
- package/src/DateInput/NativeDateField.test.tsx +635 -0
- package/src/DateInput/NativeDateField.tsx +641 -0
- package/src/DateInput/TouchDateField.tsx +83 -33
- package/src/DateInput/Wheel.tsx +1 -0
- package/src/DateInput/index.ts +1 -0
- package/src/DateInput/nativeDateSegments.ts +127 -0
- package/src/DateRangeInput/DateRangeInput.doc.mjs +2 -2
- package/src/DateRangeInput/DateRangeInput.test.tsx +46 -0
- package/src/DateRangeInput/DateRangeInput.tsx +8 -13
- package/src/DateTimeInput/DateTimeInput.doc.mjs +38 -21
- package/src/DateTimeInput/DateTimeInput.test.tsx +76 -0
- package/src/DateTimeInput/DateTimeInput.tsx +54 -20
- package/src/DateTimeInput/DateTimeInputTouch.test.tsx +980 -0
- package/src/DateTimeInput/TouchDateTimeField.tsx +1437 -0
- package/src/Dialog/Dialog.test.tsx +185 -18
- package/src/Dialog/Dialog.tsx +35 -11
- package/src/DropdownMenu/DropdownMenu.test.tsx +44 -10
- package/src/DropdownMenu/DropdownMenu.tsx +4 -13
- package/src/Field/FieldLabel.test.tsx +29 -0
- package/src/Field/FieldLabel.tsx +7 -0
- package/src/Field/InputClearButton.test.tsx +15 -1
- package/src/Field/InputClearButton.tsx +28 -4
- package/src/Heading/Heading.tsx +0 -1
- package/src/HoverCard/HoverCard.doc.mjs +8 -2
- package/src/HoverCard/HoverCard.test.tsx +154 -4
- package/src/HoverCard/HoverCard.tsx +137 -3
- package/src/HoverCard/useHoverCard.tsx +23 -3
- package/src/Icon/Icon.test.tsx +55 -1
- package/src/Icon/Icon.tsx +5 -3
- package/src/Icon/defaultIcons.tsx +11 -2
- package/src/Icon/globalIconRegistry.test.tsx +16 -3
- package/src/Icon/globalIconRegistry.tsx +37 -6
- package/src/Icon/index.ts +1 -0
- package/src/Icon/useIcon.ts +9 -2
- package/src/Indicator/CheckboxIndicator.tsx +14 -8
- package/src/Indicator/Indicator.doc.mjs +2 -0
- package/src/Item/Item.tsx +2 -7
- package/src/Kbd/Kbd.test.tsx +0 -17
- package/src/Kbd/Kbd.tsx +2 -26
- package/src/Layer/gestureCounter.ts +57 -0
- package/src/Layer/useLayer.test.tsx +368 -16
- package/src/Layer/useLayer.tsx +208 -35
- package/src/Layout/__tests__/edgeCompensation.test.tsx +1 -1
- package/src/List/List.test.tsx +38 -0
- package/src/List/List.tsx +8 -1
- package/src/Markdown/Markdown.test.tsx +37 -0
- package/src/Markdown/Markdown.tsx +16 -5
- package/src/Markdown/parser.test.ts +33 -0
- package/src/Markdown/parser.ts +9 -3
- package/src/MetadataList/MetadataList.test.tsx +75 -2
- package/src/MetadataList/MetadataListItem.tsx +5 -2
- package/src/MultiSelector/MultiSelector.doc.mjs +22 -1
- package/src/MultiSelector/MultiSelector.test.tsx +205 -0
- package/src/MultiSelector/MultiSelector.tsx +103 -16
- package/src/MultiSelector/hooks.ts +9 -2
- package/src/NavIcon/NavIcon.doc.mjs +8 -2
- package/src/NavIcon/NavIcon.test.tsx +9 -0
- package/src/NavIcon/NavIcon.tsx +5 -1
- package/src/NavItem/navItemStyles.stylex.ts +0 -8
- package/src/NavMenu/NavHeadingMenu.test.tsx +30 -0
- package/src/NavMenu/NavHeadingMenu.tsx +7 -4
- package/src/NumberInput/NumberInput.doc.mjs +26 -7
- package/src/NumberInput/NumberInput.test.tsx +563 -8
- package/src/NumberInput/NumberInput.tsx +77 -131
- package/src/NumberInput/numberInputCommit.test.ts +72 -0
- package/src/NumberInput/numberInputCommit.ts +103 -0
- package/src/NumberInput/numberParser.docblock.test.ts +234 -0
- package/src/NumberInput/numberParser.test.ts +222 -0
- package/src/NumberInput/numberParser.ts +403 -0
- package/src/Outline/Outline.tsx +2 -4
- package/src/OverflowList/OverflowList.doc.mjs +102 -21
- package/src/OverflowList/OverflowList.test.tsx +550 -4
- package/src/OverflowList/OverflowList.tsx +100 -2
- package/src/Pagination/Pagination.test.tsx +3 -2
- package/src/Popover/Popover.doc.mjs +2 -2
- package/src/Popover/Popover.test.tsx +38 -0
- package/src/Popover/Popover.tsx +28 -66
- package/src/Popover/usePopover.tsx +44 -5
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +87 -0
- package/src/PowerSearch/PowerSearchValueEditor.test.tsx +64 -0
- package/src/PowerSearch/PowerSearchValueEditor.tsx +109 -10
- package/src/PowerSearch/formatFilterValue.test.ts +16 -1
- package/src/PowerSearch/formatFilterValue.ts +2 -0
- package/src/ProgressBar/ProgressBar.doc.mjs +42 -6
- package/src/ProgressBar/ProgressBar.test.tsx +24 -0
- package/src/ProgressBar/ProgressBar.tsx +28 -8
- package/src/Resizable/Resizable.doc.mjs +2 -2
- package/src/Resizable/useResizable.doc.mjs +21 -2
- package/src/Resizable/useResizable.test.ts +421 -0
- package/src/Resizable/useResizable.ts +133 -48
- package/src/SelectableCard/SelectableCard.doc.mjs +3 -0
- package/src/SelectableCard/SelectableCard.tsx +16 -0
- package/src/Selector/Selector.doc.mjs +14 -0
- package/src/Selector/Selector.source-build.test.mjs +65 -0
- package/src/Selector/Selector.test.tsx +301 -0
- package/src/Selector/Selector.tsx +145 -32
- package/src/Selector/hooks.ts +17 -2
- package/src/SideNav/SideNav.doc.mjs +2 -2
- package/src/SideNav/SideNav.test.tsx +1069 -6
- package/src/SideNav/SideNav.tsx +109 -38
- package/src/SideNav/SideNavHeading.tsx +5 -2
- package/src/SideNav/SideNavItem.doc.mjs +24 -3
- package/src/SideNav/SideNavItem.tsx +134 -44
- package/src/Slider/Slider.test.tsx +106 -1
- package/src/Slider/Slider.tsx +52 -1
- package/src/Spinner/Spinner.doc.mjs +17 -5
- package/src/Spinner/Spinner.test.tsx +164 -0
- package/src/Spinner/Spinner.tsx +252 -22
- package/src/StatusDot/StatusDot.doc.mjs +8 -2
- package/src/StatusDot/StatusDot.test.tsx +9 -0
- package/src/StatusDot/StatusDot.tsx +7 -1
- package/src/Stepper/Step.doc.mjs +1 -1
- package/src/Stepper/Step.tsx +7 -14
- package/src/Switch/Switch.doc.mjs +2 -0
- package/src/Switch/Switch.test.tsx +10 -0
- package/src/Switch/Switch.tsx +3 -0
- package/src/Table/BaseTable.tsx +6 -1
- package/src/Table/Table.doc.mjs +5 -3
- package/src/Table/Table.tsx +3 -8
- package/src/Table/TableBody.doc.mjs +2 -2
- package/src/Table/TableFooter.doc.mjs +1 -1
- package/src/Table/TableHeader.doc.mjs +1 -1
- package/src/Table/plugins/filtering/useTableFiltering.test.tsx +44 -6
- package/src/Table/plugins/filtering/useTableFiltering.tsx +100 -4
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +50 -4
- package/src/Table/plugins/selection/useTableSelection.test.tsx +62 -0
- package/src/Table/plugins/selection/useTableSelection.tsx +25 -2
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -2
- package/src/Table/useTableGroupedRows.doc.mjs +3 -3
- package/src/Table/useTablePagination.doc.mjs +1 -1
- package/src/Table/useTableSelection.doc.mjs +1 -1
- package/src/Text/Text.test.tsx +44 -0
- package/src/Text/Text.tsx +0 -1
- package/src/TextArea/TextArea.doc.mjs +12 -2
- package/src/TextArea/TextArea.test.tsx +11 -0
- package/src/TextArea/TextArea.tsx +34 -22
- package/src/Timestamp/Timestamp.test.tsx +89 -0
- package/src/Timestamp/Timestamp.tsx +8 -8
- package/src/Timestamp/formatInstant.ts +5 -0
- package/src/Toast/Toast.doc.mjs +213 -44
- package/src/Toast/Toast.tsx +118 -23
- package/src/Toast/ToastViewport.test.tsx +1434 -8
- package/src/Toast/ToastViewport.tsx +85 -14
- package/src/Toast/index.ts +2 -0
- package/src/Toast/types.ts +43 -5
- package/src/Toast/useToastGesture.ts +361 -0
- package/src/Token/Token.test.tsx +95 -0
- package/src/Token/Token.tsx +19 -17
- package/src/Token/TokenLink.tsx +12 -3
- package/src/Tokenizer/Tokenizer.doc.mjs +16 -3
- package/src/Tokenizer/Tokenizer.test.tsx +161 -0
- package/src/Tokenizer/Tokenizer.tsx +49 -24
- package/src/TopNav/TopNavHeading.tsx +2 -2
- package/src/TopNav/TopNavItem.tsx +3 -7
- package/src/TopNav/TopNavMegaMenu.test.tsx +104 -0
- package/src/TopNav/TopNavMegaMenu.tsx +47 -4
- package/src/TopNav/TopNavMegaMenuItem.tsx +10 -9
- package/src/TopNav/TopNavMenu.test.tsx +133 -1
- package/src/TopNav/TopNavMenu.tsx +38 -5
- package/src/TreeList/TreeList.test.tsx +49 -0
- package/src/TreeList/TreeList.tsx +7 -2
- package/src/TreeList/TreeListItem.tsx +2 -7
- package/src/Typeahead/BaseTypeahead.doc.mjs +13 -0
- package/src/Typeahead/BaseTypeahead.tsx +96 -6
- package/src/Typeahead/Typeahead.doc.mjs +6 -0
- package/src/Typeahead/Typeahead.test.tsx +154 -0
- package/src/Typeahead/Typeahead.tsx +9 -0
- package/src/Typeahead/TypeaheadItem.test.tsx +43 -0
- package/src/Typeahead/TypeaheadItem.tsx +8 -1
- package/src/hooks/useAnnounce.doc.mjs +96 -0
- package/src/hooks/useDevWarning.doc.mjs +96 -0
- package/src/hooks/useHotkeys.test.ts +0 -18
- package/src/hooks/useHotkeys.ts +3 -25
- package/src/hooks/useIndicatorFocusRing.doc.mjs +104 -0
- package/src/hooks/useInputStatusIcon.doc.mjs +142 -0
- package/src/hooks/useInteractiveRole.doc.mjs +119 -0
- package/src/hooks/useLongPress.doc.mjs +123 -0
- package/src/hooks/useOverflow.doc.mjs +58 -17
- package/src/hooks/useOverflow.ts +16 -4
- package/src/hooks/useTypeahead.doc.mjs +153 -0
- package/src/i18n/InternationalizationContext.ts +3 -0
- package/src/i18n/InternationalizationProvider.tsx +8 -1
- package/src/i18n/__tests__/resolve.test.ts +23 -1
- package/src/i18n/resolve.ts +46 -49
- package/src/i18n/useTranslator.ts +2 -7
- package/src/index.ts +2 -0
- package/src/raw-import.d.ts +14 -0
- package/src/theme/Theme.test.tsx +104 -2
- package/src/theme/Theme.tsx +49 -14
- package/src/theme/defineTheme.test.ts +23 -0
- package/src/theme/defineTheme.ts +12 -3
- package/src/theme/derivedVarRegistry.test.ts +87 -3
- package/src/theme/derivedVarRegistry.ts +23 -4
- package/src/theme/generateThemeRules.test.ts +99 -1
- package/src/theme/generateThemeRules.ts +28 -0
- package/src/theme/syntax/tokens.ts +5 -2
- package/src/theme/useTheme.test.tsx +10 -0
- package/src/theme/useTheme.ts +16 -10
- package/src/utils/dateParser.test.ts +34 -2
- package/src/utils/dateParser.ts +11 -14
- package/src/utils/focusOutline.stylex.ts +50 -0
- package/src/utils/interactionOverlay.stylex.ts +74 -0
- package/src/utils/isApplePlatform.test.ts +61 -0
- package/src/utils/isApplePlatform.ts +37 -0
- package/src/utils/plainDate.test.ts +46 -0
- package/src/utils/plainDate.ts +18 -3
package/src/theme/Theme.tsx
CHANGED
|
@@ -42,6 +42,7 @@ import * as stylex from '@stylexjs/stylex';
|
|
|
42
42
|
import type {ThemeMode} from './types';
|
|
43
43
|
import {colorVars, typographyVars} from './tokens.stylex';
|
|
44
44
|
import {generateThemeCSS, type DefinedTheme} from './defineTheme';
|
|
45
|
+
import {generateDataTokenDefaultsCSS} from './generateThemeRules';
|
|
45
46
|
import {registerTheme} from './themeRegistry';
|
|
46
47
|
import {dataAttr} from '../naming';
|
|
47
48
|
import {ThemeContext} from './useTheme';
|
|
@@ -98,6 +99,16 @@ ThemeNestingContext.displayName = 'ThemeNestingContext';
|
|
|
98
99
|
/** Track which themes have already been injected */
|
|
99
100
|
const injectedThemes = new Set<string>();
|
|
100
101
|
|
|
102
|
+
/**
|
|
103
|
+
* How many mounted `Theme`s are relying on the injected data-token defaults.
|
|
104
|
+
*
|
|
105
|
+
* The defaults are one document-wide `:root` block, shared by every theme, so
|
|
106
|
+
* they are injected once and removed only when the last theme that took a
|
|
107
|
+
* reference unmounts — tearing them down with whichever provider happened to
|
|
108
|
+
* inject them would strip the palette from the providers still mounted.
|
|
109
|
+
*/
|
|
110
|
+
let dataTokenDefaultsRefCount = 0;
|
|
111
|
+
|
|
101
112
|
/**
|
|
102
113
|
* Hook to inject theme CSS into the document.
|
|
103
114
|
* Built themes (from `astryx theme build`) skip injection — their CSS
|
|
@@ -112,6 +123,8 @@ function useThemeStyleInjection(theme: DefinedTheme): void {
|
|
|
112
123
|
return;
|
|
113
124
|
}
|
|
114
125
|
|
|
126
|
+
// Second and later `Theme`s using this theme do no work at all —
|
|
127
|
+
// generation included. Its CSS is document-wide and identical for each.
|
|
115
128
|
const themeKey = `astryx-theme-${theme.name}`;
|
|
116
129
|
if (injectedThemes.has(themeKey)) {
|
|
117
130
|
return;
|
|
@@ -130,8 +143,26 @@ function useThemeStyleInjection(theme: DefinedTheme): void {
|
|
|
130
143
|
);
|
|
131
144
|
|
|
132
145
|
const {prose, component} = generateThemeCSS(theme);
|
|
133
|
-
|
|
134
|
-
|
|
146
|
+
const base = generateDataTokenDefaultsCSS();
|
|
147
|
+
injectedThemes.add(themeKey);
|
|
148
|
+
const cleanups: (() => void)[] = [() => injectedThemes.delete(themeKey)];
|
|
149
|
+
|
|
150
|
+
// Data token defaults go into @layer astryx-base, where StyleX puts the
|
|
151
|
+
// core token defaults, so a theme's own `--color-data-*` outranks them by
|
|
152
|
+
// layer. Appended (never prepended) so it cannot register `astryx-base`
|
|
153
|
+
// ahead of `reset` and invert the layer order.
|
|
154
|
+
if (base) {
|
|
155
|
+
if (dataTokenDefaultsRefCount++ === 0) {
|
|
156
|
+
const baseStyle = document.createElement('style');
|
|
157
|
+
baseStyle.setAttribute(dataAttr('theme-base'), '');
|
|
158
|
+
baseStyle.textContent = `@layer astryx-base {\n${base}\n}`;
|
|
159
|
+
document.head.appendChild(baseStyle);
|
|
160
|
+
}
|
|
161
|
+
cleanups.push(() => {
|
|
162
|
+
if (--dataTokenDefaultsRefCount === 0) {
|
|
163
|
+
document.querySelector(`style[${dataAttr('theme-base')}]`)?.remove();
|
|
164
|
+
}
|
|
165
|
+
});
|
|
135
166
|
}
|
|
136
167
|
|
|
137
168
|
// Prose defaults go into @layer reset — lowest priority, scoped to
|
|
@@ -154,20 +185,24 @@ function useThemeStyleInjection(theme: DefinedTheme): void {
|
|
|
154
185
|
document.head.appendChild(compStyle);
|
|
155
186
|
}
|
|
156
187
|
|
|
157
|
-
|
|
188
|
+
if (prose || component) {
|
|
189
|
+
cleanups.push(() => {
|
|
190
|
+
// Matched by the astryx id marker, which is always written above.
|
|
191
|
+
const proseEl = document.querySelector(
|
|
192
|
+
`style[${dataAttr('theme-prose')}="${theme.name}"][${dataAttr('id')}="${id}"]`,
|
|
193
|
+
);
|
|
194
|
+
const compEl = document.querySelector(
|
|
195
|
+
`style[${dataAttr('theme')}="${theme.name}"][${dataAttr('id')}="${id}"]`,
|
|
196
|
+
);
|
|
197
|
+
proseEl?.remove();
|
|
198
|
+
compEl?.remove();
|
|
199
|
+
});
|
|
200
|
+
}
|
|
158
201
|
|
|
159
202
|
return () => {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
`style[${dataAttr('theme-prose')}="${theme.name}"][${dataAttr('id')}="${id}"]`,
|
|
164
|
-
);
|
|
165
|
-
const compEl = document.querySelector(
|
|
166
|
-
`style[${dataAttr('theme')}="${theme.name}"][${dataAttr('id')}="${id}"]`,
|
|
167
|
-
);
|
|
168
|
-
proseEl?.remove();
|
|
169
|
-
compEl?.remove();
|
|
170
|
-
injectedThemes.delete(themeKey);
|
|
203
|
+
for (const cleanup of cleanups) {
|
|
204
|
+
cleanup();
|
|
205
|
+
}
|
|
171
206
|
};
|
|
172
207
|
}, [theme, id]);
|
|
173
208
|
}
|
|
@@ -116,6 +116,29 @@ describe('generateThemeCSS', () => {
|
|
|
116
116
|
expect(css).toContain('font-family: var(--font-family-heading)');
|
|
117
117
|
});
|
|
118
118
|
|
|
119
|
+
it('keeps the data palette out of a theme that never mentions it', () => {
|
|
120
|
+
// That the palette IS declared is covered by `seeds the whole palette
|
|
121
|
+
// once, at :root` in generateThemeRules.test.ts. It is theme-independent,
|
|
122
|
+
// so there is nothing about it a theme can be used to assert.
|
|
123
|
+
const {component} = generateThemeCSS(defineTheme({name: 'chartless'}));
|
|
124
|
+
expect(component).not.toContain('--color-data-');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('puts only the named data token in the theme block, not its siblings', () => {
|
|
128
|
+
const theme = defineTheme({
|
|
129
|
+
name: 'brand-charts',
|
|
130
|
+
tokens: {'--color-data-categorical-blue': '#00A3FF'},
|
|
131
|
+
});
|
|
132
|
+
const {component} = generateThemeCSS(theme);
|
|
133
|
+
expect(component).toContain('--color-data-categorical-blue: #00A3FF;');
|
|
134
|
+
// Leaving the siblings out of the theme's own block is what lets a nested
|
|
135
|
+
// theme inherit a parent's override instead of shadowing it.
|
|
136
|
+
expect(component).not.toContain('--color-data-categorical-orange');
|
|
137
|
+
// Defaults reach the stylesheet without entering the theme's own tokens,
|
|
138
|
+
// which are what `astryx theme build` reports as overrides.
|
|
139
|
+
expect(theme.tokens['--color-data-categorical-orange']).toBeUndefined();
|
|
140
|
+
});
|
|
141
|
+
|
|
119
142
|
it('splits prose into reset layer and components into astryx-theme', () => {
|
|
120
143
|
const theme = defineTheme({
|
|
121
144
|
name: 'split-test',
|
package/src/theme/defineTheme.ts
CHANGED
|
@@ -36,7 +36,16 @@
|
|
|
36
36
|
* - /packages/cli/assets/docs/theme.doc.mjs (`astryx docs theme`)
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
|
-
import type {
|
|
39
|
+
import type {ReactNode} from 'react';
|
|
40
|
+
import type {IconName, NamespacedIconName} from '../Icon/globalIconRegistry';
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Icon overrides a theme may declare: any built-in semantic name, plus the
|
|
44
|
+
* namespaced keys components and libraries own (`'richtext:bold'`).
|
|
45
|
+
*/
|
|
46
|
+
type ThemeIconOverrides = Partial<
|
|
47
|
+
Record<IconName | NamespacedIconName, ReactNode>
|
|
48
|
+
>;
|
|
40
49
|
import type {IndicatorRegistry} from '../Indicator/types';
|
|
41
50
|
import type {TypographyConfig, FontWeight} from './types';
|
|
42
51
|
import {
|
|
@@ -319,7 +328,7 @@ export interface DefineThemeInput {
|
|
|
319
328
|
*/
|
|
320
329
|
components?: ComponentStyleMap;
|
|
321
330
|
/** Icon registry — maps semantic icon names to React nodes */
|
|
322
|
-
icons?:
|
|
331
|
+
icons?: ThemeIconOverrides;
|
|
323
332
|
/**
|
|
324
333
|
* Indicator overrides — replaces the components that draw stateful control
|
|
325
334
|
* visuals with the theme's own, by name.
|
|
@@ -381,7 +390,7 @@ export interface DefinedTheme {
|
|
|
381
390
|
/** Component style overrides */
|
|
382
391
|
components?: ComponentStyleMap;
|
|
383
392
|
/** Icon registry */
|
|
384
|
-
icons?:
|
|
393
|
+
icons?: ThemeIconOverrides;
|
|
385
394
|
/** Indicator overrides for stateful control visuals, keyed by name */
|
|
386
395
|
indicators?: IndicatorRegistry;
|
|
387
396
|
/** Whether this theme has been pre-compiled by theme build CLI */
|
|
@@ -213,6 +213,7 @@ function discoverComponents(): ComponentInfo[] {
|
|
|
213
213
|
// ---------------------------------------------------------------------------
|
|
214
214
|
|
|
215
215
|
const DIR_TO_REGISTRY_KEY: Record<string, string> = {
|
|
216
|
+
Avatar: 'avatar',
|
|
216
217
|
Banner: 'banner',
|
|
217
218
|
Button: 'button',
|
|
218
219
|
Card: 'card',
|
|
@@ -221,13 +222,13 @@ const DIR_TO_REGISTRY_KEY: Record<string, string> = {
|
|
|
221
222
|
Dialog: 'dialog',
|
|
222
223
|
DropdownMenu: 'dropdown-menu',
|
|
223
224
|
Field: 'field',
|
|
224
|
-
HoverCard: '
|
|
225
|
+
HoverCard: 'hover-card',
|
|
225
226
|
NumberInput: 'number-input',
|
|
226
227
|
Popover: 'popover',
|
|
227
|
-
ProgressBar: '
|
|
228
|
+
ProgressBar: 'progress-bar-mark',
|
|
228
229
|
Section: 'section',
|
|
229
230
|
SegmentedControl: 'segmented-control',
|
|
230
|
-
TextArea: '
|
|
231
|
+
TextArea: 'text-area',
|
|
231
232
|
};
|
|
232
233
|
|
|
233
234
|
/**
|
|
@@ -279,6 +280,13 @@ const VARS_WITHOUT_DERIVED_MAPPING = new Set([
|
|
|
279
280
|
'--_thumbnail-hit-inset',
|
|
280
281
|
'--_input-clear-hit-inset',
|
|
281
282
|
'--_input-clear-hit-content',
|
|
283
|
+
// Placement and swipe lifecycle values are private Toast behavior. A theme
|
|
284
|
+
// author controls the surface transform/opacity as a whole, not these values.
|
|
285
|
+
'--_toast-slide-y',
|
|
286
|
+
'--_toast-swipe-y',
|
|
287
|
+
'--_toast-swipe-exit-y',
|
|
288
|
+
'--_toast-swipe-opacity',
|
|
289
|
+
'--_toast-swipe-scale',
|
|
282
290
|
// Indentation and row-spacing metrics: --tree-list-indent is the authorable
|
|
283
291
|
// step, --_tree-indent the per-row distance TreeListItem computes from it.
|
|
284
292
|
// --tree-list-row-gap is applied as half a padding-block on each row wrapper,
|
|
@@ -292,6 +300,19 @@ const VARS_WITHOUT_DERIVED_MAPPING = new Set([
|
|
|
292
300
|
// other.
|
|
293
301
|
'--_card-elevation',
|
|
294
302
|
'--_card-ring',
|
|
303
|
+
// The colour inside that composed ring, for a variant only a theme knows.
|
|
304
|
+
// It is one component of one shadow in the list, so no standard property
|
|
305
|
+
// maps onto it either — a theme sets it beside the fill it has to contrast.
|
|
306
|
+
'--selectable-card-ring-color',
|
|
307
|
+
// The spinner's ring is drawn as an SVG circle, so none of its four vars is
|
|
308
|
+
// a CSS property of the element carrying the theme target: `width` and
|
|
309
|
+
// `borderWidth` would name a box the ring is not, and a `color` mapping
|
|
310
|
+
// would take the label's text color with it. They are public vars a theme
|
|
311
|
+
// sets directly under a size- or shade-variant key.
|
|
312
|
+
'--spinner-diameter',
|
|
313
|
+
'--spinner-stroke-width',
|
|
314
|
+
'--spinner-color',
|
|
315
|
+
'--spinner-track-color',
|
|
295
316
|
]);
|
|
296
317
|
|
|
297
318
|
// ---------------------------------------------------------------------------
|
|
@@ -418,6 +439,21 @@ describe('getDerivedVars', () => {
|
|
|
418
439
|
expect(getDerivedVars('unknown', 'borderRadius')).toEqual([]);
|
|
419
440
|
});
|
|
420
441
|
|
|
442
|
+
it('resolves a deprecated key to the entries of the key that replaced it', () => {
|
|
443
|
+
// A theme written against the old spelling still selects the element (the
|
|
444
|
+
// component emits both classes), so its derived vars must still expand —
|
|
445
|
+
// otherwise the rule lands and the var half of it silently does nothing.
|
|
446
|
+
expect(getDerivedVars('hovercard', 'borderRadius')).toEqual(
|
|
447
|
+
getDerivedVars('hover-card', 'borderRadius'),
|
|
448
|
+
);
|
|
449
|
+
expect(getDerivedVars('textarea', 'paddingInline')).toEqual(
|
|
450
|
+
getDerivedVars('text-area', 'paddingInline'),
|
|
451
|
+
);
|
|
452
|
+
expect(getDerivedVars('progressbar-mark', 'width')).toEqual(
|
|
453
|
+
getDerivedVars('progress-bar-mark', 'width'),
|
|
454
|
+
);
|
|
455
|
+
});
|
|
456
|
+
|
|
421
457
|
it('returns empty for unregistered property', () => {
|
|
422
458
|
expect(getDerivedVars('card', 'color')).toEqual([]);
|
|
423
459
|
});
|
|
@@ -441,3 +477,51 @@ describe('getDerivedVars', () => {
|
|
|
441
477
|
}
|
|
442
478
|
});
|
|
443
479
|
});
|
|
480
|
+
|
|
481
|
+
// ---------------------------------------------------------------------------
|
|
482
|
+
// Read check: a registered var nothing reads is a dead theming knob
|
|
483
|
+
// ---------------------------------------------------------------------------
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Every source file under packages/core/src, concatenated once.
|
|
487
|
+
*
|
|
488
|
+
* `--_popover-radius` shipped documented and registered while `usePopover`
|
|
489
|
+
* hardcoded its radius, so `popover: {borderRadius}` set a var no element ever
|
|
490
|
+
* read. Sync between source, docs and registry cannot catch that: the three
|
|
491
|
+
* agreed with each other, and none of them required a reader.
|
|
492
|
+
*/
|
|
493
|
+
function readAllSource(dir: string): string {
|
|
494
|
+
let out = '';
|
|
495
|
+
for (const entry of readdirSync(dir, {withFileTypes: true})) {
|
|
496
|
+
const path = join(dir, entry.name);
|
|
497
|
+
if (entry.isDirectory()) {
|
|
498
|
+
out += readAllSource(path);
|
|
499
|
+
} else if (
|
|
500
|
+
(entry.name.endsWith('.ts') || entry.name.endsWith('.tsx')) &&
|
|
501
|
+
!entry.name.includes('.test.') &&
|
|
502
|
+
!entry.name.endsWith('.d.ts')
|
|
503
|
+
) {
|
|
504
|
+
out += readFileSync(path, 'utf-8');
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return out;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
describe('registered derived vars are read by component styles', () => {
|
|
511
|
+
const source = readAllSource(SRC_DIR);
|
|
512
|
+
|
|
513
|
+
for (const [component, entries] of Object.entries(derivedVarRegistry)) {
|
|
514
|
+
for (const varName of entries.flatMap(e => e.vars ?? [])) {
|
|
515
|
+
it(`${component}: ${varName} is read via var()`, () => {
|
|
516
|
+
expect(
|
|
517
|
+
source.includes(`var(${varName})`) ||
|
|
518
|
+
source.includes(`var(${varName},`),
|
|
519
|
+
`${varName} is registered as the derived var for a CSS property on ` +
|
|
520
|
+
`\`${component}\`, but no component reads it. A theme setting that ` +
|
|
521
|
+
`property would write a var nothing consumes. Read it in the ` +
|
|
522
|
+
`element's StyleX styles, or drop the derived entry.`,
|
|
523
|
+
).toBe(true);
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
});
|
|
@@ -43,6 +43,7 @@ export interface DerivedVarEntry {
|
|
|
43
43
|
* entries share the same property.
|
|
44
44
|
*/
|
|
45
45
|
export const derivedVarRegistry: Record<string, DerivedVarEntry[]> = {
|
|
46
|
+
avatar: [{property: 'borderRadius', vars: ['--_avatar-radius']}],
|
|
46
47
|
banner: [{property: 'borderRadius', vars: ['--_banner-radius']}],
|
|
47
48
|
button: [{property: 'borderRadius', vars: ['--_button-radius']}],
|
|
48
49
|
card: [
|
|
@@ -66,13 +67,13 @@ export const derivedVarRegistry: Record<string, DerivedVarEntry[]> = {
|
|
|
66
67
|
{property: 'padding', vars: ['--_dropdown-menu-padding']},
|
|
67
68
|
],
|
|
68
69
|
field: [{property: 'borderRadius', vars: ['--_field-radius']}],
|
|
69
|
-
|
|
70
|
+
'hover-card': [{property: 'borderRadius', vars: ['--_hovercard-radius']}],
|
|
70
71
|
'number-input': [
|
|
71
72
|
{property: 'padding', expand: 'container'},
|
|
72
73
|
{property: 'borderRadius', vars: ['--_field-radius']},
|
|
73
74
|
],
|
|
74
75
|
popover: [{property: 'borderRadius', vars: ['--_popover-radius']}],
|
|
75
|
-
'
|
|
76
|
+
'progress-bar-mark': [
|
|
76
77
|
{property: 'width', vars: ['--_progressbar-mark-width'], replaces: true},
|
|
77
78
|
{property: 'height', vars: ['--_progressbar-mark-height'], replaces: true},
|
|
78
79
|
],
|
|
@@ -81,7 +82,7 @@ export const derivedVarRegistry: Record<string, DerivedVarEntry[]> = {
|
|
|
81
82
|
{property: 'borderRadius', vars: ['--_segmented-control-radius']},
|
|
82
83
|
{property: 'padding', vars: ['--_segmented-control-padding']},
|
|
83
84
|
],
|
|
84
|
-
|
|
85
|
+
'text-area': [
|
|
85
86
|
{
|
|
86
87
|
property: 'paddingInline',
|
|
87
88
|
vars: ['--_textarea-inline-padding'],
|
|
@@ -90,6 +91,21 @@ export const derivedVarRegistry: Record<string, DerivedVarEntry[]> = {
|
|
|
90
91
|
],
|
|
91
92
|
};
|
|
92
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Deprecated component keys → the key that superseded them.
|
|
96
|
+
*
|
|
97
|
+
* A renamed target keeps emitting its old class, so a theme written against
|
|
98
|
+
* the old key still selects the element. Without this the rule would land but
|
|
99
|
+
* its derived vars would not expand, and the half that travels through a var
|
|
100
|
+
* (a hover card's radius, a text area's inline padding) would silently do
|
|
101
|
+
* nothing. Drop these with the classes, in the next major.
|
|
102
|
+
*/
|
|
103
|
+
const DEPRECATED_REGISTRY_KEYS: Record<string, string> = {
|
|
104
|
+
hovercard: 'hover-card',
|
|
105
|
+
'progressbar-mark': 'progress-bar-mark',
|
|
106
|
+
textarea: 'text-area',
|
|
107
|
+
};
|
|
108
|
+
|
|
93
109
|
/**
|
|
94
110
|
* Look up derived var entries for a component + CSS property.
|
|
95
111
|
* Returns matching entries in priority order, or empty array if none.
|
|
@@ -98,7 +114,10 @@ export function getDerivedVars(
|
|
|
98
114
|
component: string,
|
|
99
115
|
property: string,
|
|
100
116
|
): DerivedVarEntry[] {
|
|
101
|
-
const
|
|
117
|
+
const renamedTo = DEPRECATED_REGISTRY_KEYS[component];
|
|
118
|
+
const entries =
|
|
119
|
+
derivedVarRegistry[component] ??
|
|
120
|
+
(renamedTo ? derivedVarRegistry[renamedTo] : undefined);
|
|
102
121
|
if (!entries) {
|
|
103
122
|
return [];
|
|
104
123
|
}
|
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import {describe, it, expect} from 'vitest';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
dataTokenDefaults,
|
|
12
|
+
defineTheme,
|
|
13
|
+
generateThemeCSS,
|
|
14
|
+
generateThemeRules,
|
|
15
|
+
} from './index';
|
|
16
|
+
import {generateDataTokenDefaultsCSS} from './generateThemeRules';
|
|
11
17
|
|
|
12
18
|
const defaultInput = {
|
|
13
19
|
name: 'default',
|
|
@@ -702,3 +708,95 @@ describe('physical padding longhands', () => {
|
|
|
702
708
|
expect(rule).not.toContain('--_dropdown-menu-padding');
|
|
703
709
|
});
|
|
704
710
|
});
|
|
711
|
+
|
|
712
|
+
describe('renamed theme targets', () => {
|
|
713
|
+
// The renamed targets emit both classes, so a rule written against either
|
|
714
|
+
// key selects the element. What is easy to miss is the derived-var half: a
|
|
715
|
+
// key the registry does not know still emits a rule, minus every var the
|
|
716
|
+
// component actually reads — the same silent nothing a misspelled key gives.
|
|
717
|
+
it('expands derived vars for a renamed key and its deprecated spelling', () => {
|
|
718
|
+
const rules = (component: string, styles: Record<string, string>) =>
|
|
719
|
+
generateThemeRules(
|
|
720
|
+
defineTheme({
|
|
721
|
+
name: `test-renamed-${component}`,
|
|
722
|
+
components: {[component]: {base: styles}},
|
|
723
|
+
}),
|
|
724
|
+
).join('\n');
|
|
725
|
+
|
|
726
|
+
const hoverCard = rules('hover-card', {borderRadius: '9px'});
|
|
727
|
+
expect(hoverCard).toContain('.astryx-hover-card');
|
|
728
|
+
expect(hoverCard).toContain('--_hovercard-radius: 9px');
|
|
729
|
+
expect(rules('hovercard', {borderRadius: '9px'})).toContain(
|
|
730
|
+
'--_hovercard-radius: 9px',
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
const textArea = rules('text-area', {paddingInline: '11px'});
|
|
734
|
+
expect(textArea).toContain('.astryx-text-area');
|
|
735
|
+
expect(textArea).toContain('--_textarea-inline-padding: 11px');
|
|
736
|
+
expect(rules('textarea', {paddingInline: '11px'})).toContain(
|
|
737
|
+
'--_textarea-inline-padding: 11px',
|
|
738
|
+
);
|
|
739
|
+
|
|
740
|
+
const mark = rules('progress-bar-mark', {width: '3px'});
|
|
741
|
+
expect(mark).toContain('.astryx-progress-bar-mark');
|
|
742
|
+
expect(mark).toContain('--_progressbar-mark-width: 3px');
|
|
743
|
+
expect(rules('progressbar-mark', {width: '3px'})).toContain(
|
|
744
|
+
'--_progressbar-mark-width: 3px',
|
|
745
|
+
);
|
|
746
|
+
});
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
describe('data visualization tokens', () => {
|
|
750
|
+
const scopeBlock = (theme: Parameters<typeof generateThemeRules>[0]) =>
|
|
751
|
+
generateThemeRules(theme).find(r => r.includes(':scope'));
|
|
752
|
+
|
|
753
|
+
it('seeds the whole palette once, at :root', () => {
|
|
754
|
+
const css = generateDataTokenDefaultsCSS();
|
|
755
|
+
|
|
756
|
+
expect(css.startsWith(':root {')).toBe(true);
|
|
757
|
+
for (const [name, value] of Object.entries(dataTokenDefaults)) {
|
|
758
|
+
expect(css).toContain(`${name}: ${value};`);
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
it('leaves the defaults out of a theme scope block', () => {
|
|
763
|
+
// A scope block that re-declared them would shadow a parent theme's
|
|
764
|
+
// override in every nested <Theme>, which no other token family does.
|
|
765
|
+
expect(scopeBlock(defineTheme({name: 'data-bare'}))).toBeUndefined();
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
it("puts only the theme's own data token in its scope block", () => {
|
|
769
|
+
const block = scopeBlock(
|
|
770
|
+
defineTheme({
|
|
771
|
+
name: 'data-override',
|
|
772
|
+
tokens: {'--color-data-categorical-blue': ['#123456', '#654321']},
|
|
773
|
+
}),
|
|
774
|
+
)!;
|
|
775
|
+
|
|
776
|
+
expect(block).toContain(
|
|
777
|
+
'--color-data-categorical-blue: light-dark(#123456, #654321);',
|
|
778
|
+
);
|
|
779
|
+
expect(block.match(/--color-data-/g)).toHaveLength(1);
|
|
780
|
+
expect(block).not.toContain('--color-data-categorical-orange');
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
it('keeps the palette out of the scoped stylesheet', () => {
|
|
784
|
+
// The palette's own contents are asserted once, against
|
|
785
|
+
// `dataTokenDefaults`, in `seeds the whole palette once, at :root` above.
|
|
786
|
+
const {component, prose} = generateThemeCSS(
|
|
787
|
+
defineTheme({name: 'data-css'}),
|
|
788
|
+
);
|
|
789
|
+
|
|
790
|
+
expect(component).not.toContain('--color-data-');
|
|
791
|
+
expect(prose).not.toContain('--color-data-');
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
it('keeps generateThemeCSS to its two scoped blocks', () => {
|
|
795
|
+
// The defaults are theme-independent, so they are not part of the theme
|
|
796
|
+
// CSS contract: `astryx theme build` formats them from the public
|
|
797
|
+
// `dataTokenDefaults` export instead.
|
|
798
|
+
expect(
|
|
799
|
+
Object.keys(generateThemeCSS(defineTheme({name: 'data-shape'}))).sort(),
|
|
800
|
+
).toEqual(['component', 'prose']);
|
|
801
|
+
});
|
|
802
|
+
});
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import type {DefinedTheme} from './defineTheme';
|
|
19
19
|
import {parseStyleKey} from '../utils/parseStyleKey';
|
|
20
20
|
import {getDerivedVars} from './derivedVarRegistry';
|
|
21
|
+
import {dataTokenDefaults} from './domainTokens/dataTokens';
|
|
21
22
|
import {cssVar, classPrefix, dataAttrNamespace} from '../naming';
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -758,6 +759,30 @@ export function generateOnMediaCSS(theme: DefinedTheme): string {
|
|
|
758
759
|
return `@scope (${scopeSelector}) to (${THEME_SCOPE_TO}) {\n${inner}\n}`;
|
|
759
760
|
}
|
|
760
761
|
|
|
762
|
+
/**
|
|
763
|
+
* The `--color-data-*` defaults as one unscoped `:root` block.
|
|
764
|
+
*
|
|
765
|
+
* Core tokens reach CSS once, at `:root`, from StyleX's `defineVars` output in
|
|
766
|
+
* `@layer astryx-base`; a theme's own scope block then carries only the tokens
|
|
767
|
+
* that theme overrides, which is why a nested theme inherits its parent's
|
|
768
|
+
* override instead of shadowing it. Data tokens are not StyleX vars, so nothing
|
|
769
|
+
* declares them — this is their equivalent, and callers put it in
|
|
770
|
+
* `@layer astryx-base` so a theme's override wins by layer rather than by
|
|
771
|
+
* specificity. Seeding it per theme scope instead re-declares the default
|
|
772
|
+
* inside every nested theme, which is the shadowing this shape avoids.
|
|
773
|
+
*
|
|
774
|
+
* @internal Not exported from `@astryxdesign/core/theme`: the `<Theme>`
|
|
775
|
+
* runtime is the only caller. `astryx theme build` formats the same block from
|
|
776
|
+
* the public `dataTokenDefaults` export, and a CLI test asserts the two are
|
|
777
|
+
* byte-identical.
|
|
778
|
+
*/
|
|
779
|
+
export function generateDataTokenDefaultsCSS(): string {
|
|
780
|
+
const declarations = Object.entries(dataTokenDefaults)
|
|
781
|
+
.map(([prop, value]) => ` ${prop}: ${value};`)
|
|
782
|
+
.join('\n');
|
|
783
|
+
return `:root {\n${declarations}\n}`;
|
|
784
|
+
}
|
|
785
|
+
|
|
761
786
|
/**
|
|
762
787
|
* Generate layered CSS for a theme — runtime path.
|
|
763
788
|
*
|
|
@@ -768,6 +793,9 @@ export function generateOnMediaCSS(theme: DefinedTheme): string {
|
|
|
768
793
|
* This separation ensures prose defaults (what bare HTML looks like in a theme)
|
|
769
794
|
* sit at reset-layer priority where any class-based style wins, while component
|
|
770
795
|
* overrides sit above StyleX so themes can restyle components intentionally.
|
|
796
|
+
*
|
|
797
|
+
* The theme-independent `--color-data-*` defaults are not part of this output:
|
|
798
|
+
* see `generateDataTokenDefaultsCSS`.
|
|
771
799
|
*/
|
|
772
800
|
export function generateThemeCSS(theme: DefinedTheme): ThemeCSSOutput {
|
|
773
801
|
const {component, prose} = generateThemeRulesSplit(theme);
|
|
@@ -44,8 +44,11 @@ export const syntaxTokenDefaults = {
|
|
|
44
44
|
'--color-syntax-attribute': 'var(--color-text-teal)',
|
|
45
45
|
// property -> cyan text (object properties)
|
|
46
46
|
'--color-syntax-property': 'var(--color-text-cyan)',
|
|
47
|
-
// punctuation ->
|
|
48
|
-
|
|
47
|
+
// punctuation -> secondary text (brackets, semicolons). Not disabled text:
|
|
48
|
+
// disabled grey is calibrated to fail AA on purpose (WCAG exempts inactive
|
|
49
|
+
// controls), and punctuation in a code sample is normal, always-active
|
|
50
|
+
// text — see #5386.
|
|
51
|
+
'--color-syntax-punctuation': 'var(--color-text-secondary)',
|
|
49
52
|
// background -> muted surface
|
|
50
53
|
'--color-syntax-background': 'var(--color-background-muted)',
|
|
51
54
|
} as const;
|
|
@@ -108,6 +108,16 @@ describe('useTheme', () => {
|
|
|
108
108
|
expect(result.current.token('--color-text-primary')).toBe('#DFE2E5');
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
+
it('keeps the token resolver and return object stable across rerenders', () => {
|
|
112
|
+
const {result, rerender} = renderHook(() => useTheme());
|
|
113
|
+
const first = result.current;
|
|
114
|
+
|
|
115
|
+
rerender();
|
|
116
|
+
|
|
117
|
+
expect(result.current.token).toBe(first.token);
|
|
118
|
+
expect(result.current).toBe(first);
|
|
119
|
+
});
|
|
120
|
+
|
|
111
121
|
it('returns empty string for unknown tokens', () => {
|
|
112
122
|
const {result} = renderHook(() => useTheme(), {
|
|
113
123
|
wrapper: ({children}) => wrapper({children, mode: 'light'}),
|
package/src/theme/useTheme.ts
CHANGED
|
@@ -21,7 +21,13 @@
|
|
|
21
21
|
* - /packages/core/src/theme/index.ts
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
createContext,
|
|
26
|
+
use,
|
|
27
|
+
useCallback,
|
|
28
|
+
useMemo,
|
|
29
|
+
useSyncExternalStore,
|
|
30
|
+
} from 'react';
|
|
25
31
|
import type {ThemeMode} from './types';
|
|
26
32
|
import type {DefinedTheme} from './defineTheme';
|
|
27
33
|
import {resolveThemeTokens} from './tokens';
|
|
@@ -281,14 +287,14 @@ export function useTheme(): UseThemeReturn {
|
|
|
281
287
|
[theme, effectiveMode],
|
|
282
288
|
);
|
|
283
289
|
|
|
284
|
-
const token = (
|
|
285
|
-
|
|
286
|
-
|
|
290
|
+
const token = useCallback(
|
|
291
|
+
(name: string): string => tokens[name] ?? '',
|
|
292
|
+
[tokens],
|
|
293
|
+
);
|
|
294
|
+
const name = theme?.name ?? 'default';
|
|
287
295
|
|
|
288
|
-
return
|
|
289
|
-
name:
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
tokens,
|
|
293
|
-
};
|
|
296
|
+
return useMemo(
|
|
297
|
+
() => ({name, mode: effectiveMode, token, tokens}),
|
|
298
|
+
[name, effectiveMode, token, tokens],
|
|
299
|
+
);
|
|
294
300
|
}
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* SYNC: When dateParser.ts changes, update tests to match new behavior
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {describe, it, expect} from 'vitest';
|
|
13
|
-
import {parseDateInput} from './dateParser';
|
|
12
|
+
import {describe, it, expect, vi} from 'vitest';
|
|
13
|
+
import {isLocaleDayFirst, parseDateInput} from './dateParser';
|
|
14
14
|
|
|
15
15
|
describe('parseDateInput', () => {
|
|
16
16
|
describe('ISO format (YYYY-MM-DD)', () => {
|
|
@@ -280,6 +280,14 @@ describe('parseDateInput', () => {
|
|
|
280
280
|
describe('ambiguous numeric formats follow the passed locale (#5074)', () => {
|
|
281
281
|
// Both numbers are <= 12, so the day/month order is genuinely ambiguous
|
|
282
282
|
// and resolved by isLocaleDayFirst(locale) rather than the host locale.
|
|
283
|
+
it('defaults ambiguous input to English month-first order', () => {
|
|
284
|
+
expect(parseDateInput('3/4/2026')).toEqual({
|
|
285
|
+
year: 2026,
|
|
286
|
+
month: 3,
|
|
287
|
+
day: 4,
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
|
|
283
291
|
it('reads month-first for en-US', () => {
|
|
284
292
|
expect(parseDateInput('3/4/2026', 'en-US')).toEqual({
|
|
285
293
|
year: 2026,
|
|
@@ -297,6 +305,30 @@ describe('parseDateInput', () => {
|
|
|
297
305
|
});
|
|
298
306
|
});
|
|
299
307
|
|
|
308
|
+
describe('isLocaleDayFirst', () => {
|
|
309
|
+
it('defaults to English month-first order', () => {
|
|
310
|
+
expect(isLocaleDayFirst()).toBe(false);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('requests Gregorian calendar data for locale ordering', () => {
|
|
314
|
+
const OriginalDateTimeFormat = globalThis.Intl.DateTimeFormat;
|
|
315
|
+
const dateTimeFormatSpy = vi
|
|
316
|
+
.spyOn(globalThis.Intl, 'DateTimeFormat')
|
|
317
|
+
.mockImplementation(function DateTimeFormat(locale, options) {
|
|
318
|
+
return new OriginalDateTimeFormat(locale, options);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
try {
|
|
322
|
+
isLocaleDayFirst('en-US-u-ca-buddhist');
|
|
323
|
+
expect(dateTimeFormatSpy).toHaveBeenCalledWith('en-US-u-ca-buddhist', {
|
|
324
|
+
calendar: 'gregory',
|
|
325
|
+
});
|
|
326
|
+
} finally {
|
|
327
|
+
dateTimeFormatSpy.mockRestore();
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
|
|
300
332
|
describe('edge cases', () => {
|
|
301
333
|
it('returns null for empty string', () => {
|
|
302
334
|
expect(parseDateInput('')).toBeNull();
|