@astryxdesign/core 0.4.5 → 0.4.6-canary.cea9ecd
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 +134 -0
- package/dist/Avatar/Avatar.d.ts +10 -5
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +139 -30
- package/dist/Avatar/AvatarStatusDot.d.ts +2 -1
- package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
- package/dist/Avatar/AvatarStatusDot.js +30 -4
- package/dist/Avatar/AvatarStatusLabelContext.d.ts +39 -0
- package/dist/Avatar/AvatarStatusLabelContext.d.ts.map +1 -0
- package/dist/Avatar/AvatarStatusLabelContext.js +41 -0
- package/dist/AvatarGroup/AvatarGroup.d.ts +3 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +15 -9
- package/dist/Blockquote/Blockquote.d.ts +4 -3
- package/dist/Blockquote/Blockquote.d.ts.map +1 -1
- package/dist/Blockquote/Blockquote.js +9 -10
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +21 -5
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +47 -34
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +7 -7
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +21 -12
- package/dist/Calendar/hooks/useCalendarNavigation.d.ts.map +1 -1
- package/dist/Calendar/hooks/useCalendarNavigation.js +8 -4
- package/dist/Calendar/styles.d.ts +2 -2
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +5 -5
- package/dist/Center/Center.d.ts +23 -1
- package/dist/Center/Center.d.ts.map +1 -1
- package/dist/Center/Center.js +12 -6
- package/dist/Chat/ChatComposer.d.ts.map +1 -1
- package/dist/Chat/ChatComposer.js +3 -3
- package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
- package/dist/Chat/ChatComposerDrawer.js +2 -2
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +2 -2
- package/dist/Chat/useChatDictation.d.ts +1 -1
- package/dist/Chat/useChatDictation.d.ts.map +1 -1
- package/dist/Chat/useSpeechRecognition.d.ts +1 -1
- package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
- package/dist/Chat/useSpeechRecognition.js +4 -3
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +2 -2
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +2 -2
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +5 -5
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +4 -4
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +1 -1
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +2 -2
- package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteItem.js +3 -3
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +6 -6
- package/dist/DateInput/DateInput.d.ts +31 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +90 -22
- package/dist/DateInput/MonthScroller.d.ts +35 -0
- package/dist/DateInput/MonthScroller.d.ts.map +1 -0
- package/dist/DateInput/MonthScroller.js +658 -0
- package/dist/DateInput/MonthYearWheels.d.ts +24 -0
- package/dist/DateInput/MonthYearWheels.d.ts.map +1 -0
- package/dist/DateInput/MonthYearWheels.js +114 -0
- package/dist/DateInput/TouchDateField.d.ts +10 -0
- package/dist/DateInput/TouchDateField.d.ts.map +1 -0
- package/dist/DateInput/TouchDateField.js +810 -0
- package/dist/DateInput/Wheel.d.ts +41 -0
- package/dist/DateInput/Wheel.d.ts.map +1 -0
- package/dist/DateInput/Wheel.js +315 -0
- package/dist/DateInput/monthGeometry.d.ts +65 -0
- package/dist/DateInput/monthGeometry.d.ts.map +1 -0
- package/dist/DateInput/monthGeometry.js +98 -0
- package/dist/DateInput/tokens.stylex.d.ts +63 -0
- package/dist/DateInput/tokens.stylex.d.ts.map +1 -0
- package/dist/DateInput/tokens.stylex.js +74 -0
- package/dist/DateInput/useOwnScrollGesture.d.ts +41 -0
- package/dist/DateInput/useOwnScrollGesture.d.ts.map +1 -0
- package/dist/DateInput/useOwnScrollGesture.js +202 -0
- package/dist/DateInput/usePointerDragScroll.d.ts +15 -0
- package/dist/DateInput/usePointerDragScroll.d.ts.map +1 -0
- package/dist/DateInput/usePointerDragScroll.js +216 -0
- package/dist/DateInput/useScrollSettle.d.ts +26 -0
- package/dist/DateInput/useScrollSettle.d.ts.map +1 -0
- package/dist/DateInput/useScrollSettle.js +149 -0
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +17 -14
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +17 -14
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +3 -3
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +2 -2
- package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuItem.js +2 -2
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +2 -2
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +2 -2
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +4 -4
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +6 -0
- package/dist/Field/inputStyles.stylex.d.ts +1 -1
- package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
- package/dist/Field/inputStyles.stylex.js +5 -5
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +6 -6
- package/dist/HoverCard/HoverCard.d.ts +13 -3
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +2 -0
- package/dist/HoverCard/index.d.ts +1 -1
- package/dist/HoverCard/index.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.d.ts +17 -2
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +78 -9
- package/dist/InputGroup/InputGroup.js +1 -1
- package/dist/Item/Item.d.ts +9 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +52 -14
- package/dist/Layer/index.d.ts +4 -2
- package/dist/Layer/index.d.ts.map +1 -1
- package/dist/Layer/index.js +2 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +3 -2
- package/dist/Layer/useTouchTrigger.d.ts +113 -0
- package/dist/Layer/useTouchTrigger.d.ts.map +1 -0
- package/dist/Layer/useTouchTrigger.js +241 -0
- package/dist/Layout/container.stylex.d.ts +4 -2
- package/dist/Layout/container.stylex.d.ts.map +1 -1
- package/dist/Layout/container.stylex.js +19 -11
- package/dist/Layout/index.d.ts +1 -0
- package/dist/Layout/index.d.ts.map +1 -1
- package/dist/Layout/index.js +4 -0
- package/dist/Layout/padding.stylex.d.ts +315 -12
- package/dist/Layout/padding.stylex.d.ts.map +1 -1
- package/dist/Layout/padding.stylex.js +389 -12
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +5 -4
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +6 -6
- package/dist/MetadataList/MetadataList.d.ts.map +1 -1
- package/dist/MetadataList/MetadataList.js +1 -1
- package/dist/MobileNav/MobileNav.d.ts +1 -0
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +24 -6
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +8 -8
- package/dist/NavItem/navItemStyles.stylex.d.ts +4 -4
- package/dist/NavItem/navItemStyles.stylex.d.ts.map +1 -1
- package/dist/NavItem/navItemStyles.stylex.js +4 -4
- package/dist/NavMenu/NavHeadingMenuItem.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenuItem.js +3 -3
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +36 -8
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +3 -3
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +2 -2
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +11 -12
- package/dist/PowerSearch/PowerSearchToken.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchToken.js +3 -1
- package/dist/PowerSearch/formatFilterValue.d.ts +11 -2
- package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
- package/dist/PowerSearch/formatFilterValue.js +23 -8
- package/dist/RadioList/RadioListItem.d.ts +2 -2
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +70 -40
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +7 -7
- package/dist/Section/Section.d.ts +36 -1
- package/dist/Section/Section.d.ts.map +1 -1
- package/dist/Section/Section.js +12 -2
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +7 -2
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +3 -3
- package/dist/Selector/Selector.d.ts +26 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +93 -20
- package/dist/Selector/SelectorOption.d.ts +14 -1
- package/dist/Selector/SelectorOption.d.ts.map +1 -1
- package/dist/Selector/SelectorOption.js +6 -0
- package/dist/Selector/SelectorRowLayoutContext.d.ts +8 -0
- package/dist/Selector/SelectorRowLayoutContext.d.ts.map +1 -0
- package/dist/Selector/SelectorRowLayoutContext.js +27 -0
- package/dist/Selector/types.d.ts +1 -0
- package/dist/Selector/types.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +4 -4
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +3 -3
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +7 -7
- package/dist/Stack/Stack.d.ts +23 -1
- package/dist/Stack/Stack.d.ts.map +1 -1
- package/dist/Stack/Stack.js +12 -6
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +2 -2
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +1 -1
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +3 -3
- package/dist/Table/TableRow.js +4 -4
- package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
- package/dist/Table/plugins/columnResize/useTableColumnResize.js +1 -1
- package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
- package/dist/Table/plugins/filtering/useTableFiltering.js +2 -2
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +2 -2
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +2 -2
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +1 -1
- package/dist/Table/plugins/sortable/useTableSortableState.d.ts +5 -3
- package/dist/Table/plugins/sortable/useTableSortableState.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortableState.js +12 -9
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +3 -3
- package/dist/TextArea/TextArea.js +1 -1
- package/dist/TextInput/TextInput.js +1 -1
- package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
- package/dist/Thumbnail/Thumbnail.js +3 -3
- package/dist/TimeInput/TimeInput.js +2 -2
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +6 -4
- package/dist/Timestamp/formatInstant.d.ts +3 -2
- package/dist/Timestamp/formatInstant.d.ts.map +1 -1
- package/dist/Timestamp/formatInstant.js +8 -8
- package/dist/Timestamp/tooltipEntries.d.ts +2 -1
- package/dist/Timestamp/tooltipEntries.d.ts.map +1 -1
- package/dist/Timestamp/tooltipEntries.js +5 -3
- package/dist/Toast/Toast.d.ts +4 -3
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +10 -7
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +6 -6
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +1 -1
- package/dist/Tooltip/Tooltip.d.ts +16 -3
- package/dist/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip/Tooltip.js +2 -0
- package/dist/Tooltip/index.d.ts +1 -1
- package/dist/Tooltip/index.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.d.ts +21 -2
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +71 -13
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +4 -4
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +3 -3
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +2 -2
- package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuItem.js +2 -2
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +4 -4
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +7 -7
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +2 -2
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +1 -1
- package/dist/astryx.css +124 -62
- package/dist/hooks/containerReveal.stylex.d.ts.map +1 -1
- package/dist/hooks/containerReveal.stylex.js +18 -18
- package/dist/hooks/scrollbarGutter.d.ts +28 -0
- package/dist/hooks/scrollbarGutter.d.ts.map +1 -0
- package/dist/hooks/scrollbarGutter.js +103 -0
- package/dist/hooks/useAutoMediaMode.d.ts +31 -0
- package/dist/hooks/useAutoMediaMode.d.ts.map +1 -0
- package/dist/hooks/useAutoMediaMode.js +201 -0
- package/dist/hooks/useInputStatusIcon.d.ts.map +1 -1
- package/dist/hooks/useInputStatusIcon.js +1 -1
- package/dist/hooks/useListFocus.d.ts +5 -2
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +12 -6
- package/dist/hooks/useScrollLock.d.ts +4 -0
- package/dist/hooks/useScrollLock.d.ts.map +1 -1
- package/dist/hooks/useScrollLock.js +13 -1
- package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
- package/dist/i18n/InternationalizationContext.js +2 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +6 -0
- package/dist/i18n/useCollator.d.ts +12 -0
- package/dist/i18n/useCollator.d.ts.map +1 -0
- package/dist/i18n/useCollator.js +40 -0
- package/dist/i18n/useLocale.d.ts +3 -0
- package/dist/i18n/useLocale.d.ts.map +1 -0
- package/dist/i18n/useLocale.js +31 -0
- package/dist/theme/MediaTheme.d.ts +25 -5
- package/dist/theme/MediaTheme.d.ts.map +1 -1
- package/dist/theme/MediaTheme.js +31 -6
- package/dist/theme/defineTheme.d.ts +5 -0
- 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 +7 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +66 -5
- package/dist/theme/index.d.ts +1 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/syntax/index.d.ts +6 -0
- package/dist/theme/syntax/index.d.ts.map +1 -1
- package/dist/theme/syntax/index.js +7 -2
- package/dist/utils/dateParser.d.ts +4 -3
- package/dist/utils/dateParser.d.ts.map +1 -1
- package/dist/utils/dateParser.js +8 -8
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/plainDate.d.ts +5 -2
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +20 -4
- package/locales/en.json +28 -0
- package/locales/pseudo.json +21 -0
- package/package.json +3 -3
- package/src/Avatar/Avatar.doc.mjs +10 -6
- package/src/Avatar/Avatar.test.tsx +219 -1
- package/src/Avatar/Avatar.tsx +179 -37
- package/src/Avatar/AvatarStatusDot.tsx +30 -4
- package/src/Avatar/AvatarStatusLabelContext.ts +47 -0
- package/src/AvatarGroup/AvatarGroup.doc.mjs +10 -6
- package/src/AvatarGroup/AvatarGroup.test.tsx +62 -0
- package/src/AvatarGroup/AvatarGroup.tsx +3 -1
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +31 -8
- package/src/Banner/Banner.doc.mjs +2 -0
- package/src/Blockquote/Blockquote.doc.mjs +30 -7
- package/src/Blockquote/Blockquote.test.tsx +34 -3
- package/src/Blockquote/Blockquote.tsx +11 -9
- package/src/BottomSheet/BottomSheet.doc.mjs +3 -3
- package/src/BottomSheet/BottomSheet.test.tsx +24 -0
- package/src/BottomSheet/BottomSheetPanel.test.tsx +91 -0
- package/src/BottomSheet/BottomSheetPanel.tsx +58 -3
- package/src/Breadcrumbs/BreadcrumbItem.tsx +36 -23
- package/src/Breadcrumbs/Breadcrumbs.doc.mjs +26 -2
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -0
- package/src/Button/Button.tsx +12 -9
- package/src/Calendar/Calendar.tsx +15 -9
- package/src/Calendar/hooks/useCalendarNavigation.ts +6 -4
- package/src/Calendar/styles.ts +8 -5
- package/src/Center/Center.doc.mjs +48 -0
- package/src/Center/Center.test.tsx +158 -0
- package/src/Center/Center.tsx +50 -9
- package/src/Chat/ChatComposer.tsx +11 -5
- package/src/Chat/ChatComposerDrawer.tsx +4 -1
- package/src/Chat/ChatToolCalls.tsx +13 -4
- package/src/Chat/{useChatDictation.test.ts → useChatDictation.test.tsx} +29 -14
- package/src/Chat/useChatDictation.ts +1 -1
- package/src/Chat/useSpeechRecognition.ts +5 -3
- package/src/Chat/useTriggerMenu.tsx +4 -1
- package/src/CheckboxInput/CheckboxInput.tsx +5 -2
- package/src/Citation/Citation.test.tsx +6 -1
- package/src/Citation/Citation.tsx +11 -5
- package/src/ClickableCard/ClickableCard.tsx +7 -4
- package/src/CodeBlock/CodeBlock.tsx +4 -1
- package/src/Collapsible/Collapsible.tsx +5 -2
- package/src/CommandPalette/CommandPaletteItem.tsx +6 -3
- package/src/ComplexSelector/ComplexSelector.doc.mjs +10 -0
- package/src/ComplexSelector/ComplexSelector.tsx +14 -7
- package/src/DateInput/DateInput.test.tsx +17 -1
- package/src/DateInput/DateInput.tsx +93 -21
- package/src/DateInput/DateInputTouch.test.tsx +2582 -0
- package/src/DateInput/MonthScroller.tsx +878 -0
- package/src/DateInput/MonthYearWheels.tsx +147 -0
- package/src/DateInput/TouchDateField.tsx +1223 -0
- package/src/DateInput/Wheel.tsx +473 -0
- package/src/DateInput/monthGeometry.ts +118 -0
- package/src/DateInput/tokens.stylex.ts +99 -0
- package/src/DateInput/useOwnScrollGesture.ts +227 -0
- package/src/DateInput/usePointerDragScroll.ts +220 -0
- package/src/DateInput/useScrollSettle.ts +164 -0
- package/src/DateRangeInput/DateRangeInput.doc.mjs +1 -1
- package/src/DateRangeInput/DateRangeInput.tsx +31 -13
- package/src/DateTimeInput/DateTimeInput.tsx +25 -9
- package/src/Dialog/Dialog.test.tsx +24 -0
- package/src/Dialog/Dialog.tsx +3 -0
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +5 -2
- package/src/DropdownMenu/DropdownMenuItem.tsx +5 -2
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +5 -2
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +5 -2
- package/src/Field/Field.doc.mjs +2 -0
- package/src/Field/FieldLabel.tsx +9 -3
- package/src/Field/InputClearButton.test.tsx +110 -3
- package/src/Field/InputClearButton.tsx +38 -0
- package/src/Field/inputStyles.stylex.ts +17 -13
- package/src/FileInput/FileInput.tsx +15 -8
- package/src/FormLayout/FormLayout.doc.mjs +1 -1
- package/src/HoverCard/HoverCard.doc.mjs +18 -0
- package/src/HoverCard/HoverCard.test.tsx +189 -0
- package/src/HoverCard/HoverCard.tsx +22 -2
- package/src/HoverCard/index.ts +1 -0
- package/src/HoverCard/useHoverCard.doc.mjs +2 -0
- package/src/HoverCard/useHoverCard.tsx +103 -7
- package/src/InputGroup/InputGroup.tsx +1 -1
- package/src/Item/Item.doc.mjs +1 -0
- package/src/Item/Item.test.tsx +50 -0
- package/src/Item/Item.tsx +54 -6
- package/src/Layer/index.ts +10 -0
- package/src/Layer/useLayer.tsx +13 -2
- package/src/Layer/useTouchTrigger.test.ts +70 -0
- package/src/Layer/useTouchTrigger.ts +366 -0
- package/src/Layout/Layout.doc.mjs +18 -0
- package/src/Layout/container.stylex.ts +11 -3
- package/src/Layout/index.ts +4 -0
- package/src/Layout/overlayPaddingReset.test.tsx +222 -0
- package/src/Layout/padding.stylex.ts +192 -12
- package/src/Lightbox/Lightbox.tsx +11 -3
- package/src/Link/Link.tsx +9 -6
- package/src/MetadataList/MetadataList.tsx +4 -1
- package/src/MobileNav/MobileNav.tsx +61 -5
- package/src/MobileNav/MobileNavEntryAnimation.test.tsx +212 -0
- package/src/MobileNav/MobileNavScrollbarGutter.test.tsx +109 -0
- package/src/MultiSelector/MultiSelector.test.tsx +1 -1
- package/src/MultiSelector/MultiSelector.tsx +26 -10
- package/src/NavItem/navItemStyles.stylex.ts +7 -4
- package/src/NavMenu/NavHeadingMenuItem.tsx +6 -3
- package/src/NumberInput/NumberInput.doc.mjs +24 -0
- package/src/NumberInput/NumberInput.test.tsx +138 -0
- package/src/NumberInput/NumberInput.tsx +47 -8
- package/src/Outline/Outline.tsx +5 -2
- package/src/Pagination/Pagination.tsx +5 -2
- package/src/Popover/Popover.test.tsx +27 -1
- package/src/PowerSearch/PowerSearch.tsx +17 -8
- package/src/PowerSearch/PowerSearchToken.tsx +3 -0
- package/src/PowerSearch/formatFilterValue.test.ts +22 -2
- package/src/PowerSearch/formatFilterValue.ts +31 -6
- package/src/RadioList/RadioList.doc.mjs +1 -1
- package/src/RadioList/RadioList.test.tsx +170 -2
- package/src/RadioList/RadioListItem.tsx +88 -53
- package/src/Resizable/ResizeHandle.test.tsx +22 -0
- package/src/Resizable/ResizeHandle.tsx +25 -7
- package/src/Section/Section.doc.mjs +55 -0
- package/src/Section/Section.test.tsx +201 -4
- package/src/Section/Section.tsx +69 -0
- package/src/SegmentedControl/SegmentedControl.test.tsx +31 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +15 -3
- package/src/SelectableCard/SelectableCard.tsx +6 -3
- package/src/Selector/Selector.doc.mjs +16 -2
- package/src/Selector/Selector.test.tsx +525 -1
- package/src/Selector/Selector.tsx +180 -25
- package/src/Selector/SelectorOption.doc.mjs +7 -0
- package/src/Selector/SelectorOption.tsx +21 -0
- package/src/Selector/SelectorRowLayoutContext.ts +32 -0
- package/src/Selector/types.ts +4 -4
- package/src/SideNav/SideNavHeading.tsx +14 -5
- package/src/SideNav/SideNavItem.tsx +9 -3
- package/src/Slider/Slider.tsx +25 -6
- package/src/Stack/Stack.doc.mjs +72 -0
- package/src/Stack/Stack.test.tsx +156 -0
- package/src/Stack/Stack.tsx +50 -8
- package/src/Switch/Switch.tsx +5 -2
- package/src/TabList/Tab.tsx +4 -1
- package/src/TabList/TabMenu.tsx +9 -3
- package/src/Table/TableRow.tsx +4 -4
- package/src/Table/plugins/columnResize/useTableColumnResize.tsx +6 -2
- package/src/Table/plugins/filtering/useTableFiltering.tsx +4 -1
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +10 -3
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +6 -3
- package/src/Table/plugins/sortable/useTableSortable.tsx +4 -1
- package/src/Table/plugins/sortable/useTableSortableState.test.tsx +34 -0
- package/src/Table/plugins/sortable/useTableSortableState.tsx +26 -23
- package/src/Table/plugins/tree/useTableTreeData.tsx +10 -4
- package/src/TextArea/TextArea.doc.mjs +1 -1
- package/src/TextArea/TextArea.tsx +1 -1
- package/src/TextInput/TextInput.tsx +1 -1
- package/src/Thumbnail/Thumbnail.tsx +9 -3
- package/src/TimeInput/TimeInput.tsx +1 -1
- package/src/Timestamp/Timestamp.test.tsx +27 -7
- package/src/Timestamp/Timestamp.tsx +8 -4
- package/src/Timestamp/formatInstant.ts +9 -7
- package/src/Timestamp/tooltipEntries.test.ts +11 -6
- package/src/Timestamp/tooltipEntries.ts +6 -2
- package/src/Toast/Toast.tsx +9 -7
- package/src/Token/Token.tsx +14 -5
- package/src/Tokenizer/Tokenizer.tsx +4 -1
- package/src/Tooltip/Tooltip.doc.mjs +18 -0
- package/src/Tooltip/Tooltip.test.tsx +254 -1
- package/src/Tooltip/Tooltip.tsx +22 -2
- package/src/Tooltip/index.ts +1 -0
- package/src/Tooltip/useTooltip.doc.mjs +2 -0
- package/src/Tooltip/useTooltip.tsx +99 -21
- package/src/TopNav/TopNavHeading.tsx +13 -4
- package/src/TopNav/TopNavItem.tsx +6 -3
- package/src/TopNav/TopNavMegaMenu.tsx +5 -2
- package/src/TopNav/TopNavMegaMenuItem.tsx +5 -2
- package/src/TopNav/TopNavMenu.tsx +10 -4
- package/src/TreeList/TreeListItem.tsx +22 -7
- package/src/Typeahead/BaseTypeahead.tsx +5 -2
- package/src/Typeahead/Typeahead.tsx +4 -1
- package/src/hooks/containerReveal.stylex.ts +54 -18
- package/src/hooks/scrollbarGutter.test.ts +167 -0
- package/src/hooks/scrollbarGutter.ts +121 -0
- package/src/hooks/useAutoMediaMode.test.ts +109 -0
- package/src/hooks/useAutoMediaMode.ts +233 -0
- package/src/hooks/useInputStatusIcon.tsx +4 -1
- package/src/hooks/useListFocus.doc.mjs +2 -2
- package/src/hooks/useListFocus.test.tsx +65 -3
- package/src/hooks/useListFocus.ts +15 -7
- package/src/hooks/useScrollLock.doc.mjs +4 -4
- package/src/hooks/useScrollLock.test.ts +73 -0
- package/src/hooks/useScrollLock.ts +14 -0
- package/src/i18n/InternationalizationContext.ts +2 -0
- package/src/i18n/__tests__/e2e-powersearch.test.tsx +37 -1
- package/src/i18n/__tests__/useCollator.test.tsx +115 -0
- package/src/i18n/__tests__/useLocale.test.tsx +52 -0
- package/src/i18n/index.ts +6 -0
- package/src/i18n/useCollator.doc.mjs +84 -0
- package/src/i18n/useCollator.ts +44 -0
- package/src/i18n/useLocale.doc.mjs +70 -0
- package/src/i18n/useLocale.ts +34 -0
- package/src/i18n/useTranslator.doc.mjs +1 -1
- package/src/reset.css +9 -2
- package/src/reset.test.ts +22 -0
- package/src/theme/MediaTheme.doc.mjs +23 -4
- package/src/theme/MediaTheme.dom.test.tsx +97 -0
- package/src/theme/MediaTheme.tsx +42 -7
- package/src/theme/defineTheme.test.ts +9 -3
- package/src/theme/defineTheme.ts +5 -0
- package/src/theme/derivedVarRegistry.test.ts +19 -5
- package/src/theme/derivedVarRegistry.ts +4 -0
- package/src/theme/generateThemeRules.test.ts +118 -0
- package/src/theme/generateThemeRules.ts +83 -5
- package/src/theme/index.ts +1 -1
- package/src/theme/syntax/index.ts +6 -2
- package/src/theme/syntax/serverSafeSyntax.test.ts +68 -0
- package/src/utils/dateParser.test.ts +20 -0
- package/src/utils/dateParser.ts +14 -7
- package/src/utils/index.ts +2 -0
- package/src/utils/plainDate.test.ts +6 -0
- package/src/utils/plainDate.ts +21 -4
package/src/reset.test.ts
CHANGED
|
@@ -57,4 +57,26 @@ describe('reset.css accessibility invariants', () => {
|
|
|
57
57
|
.not.toMatch(/outline(?:-style|-width)?\s*:\s*(?:none|0)/);
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A disabled control must not answer the pointer with an interactive
|
|
63
|
+
* cursor. The reset is the floor for any element that declares no cursor of
|
|
64
|
+
* its own — components declare theirs under the `disabled-cursor` lint
|
|
65
|
+
* rule, and the Chromium sweep measures the rendered result.
|
|
66
|
+
*/
|
|
67
|
+
it('gives disabled elements the disabled cursor', () => {
|
|
68
|
+
const disabledBlocks = ruleBlocks.filter(
|
|
69
|
+
({selector}) =>
|
|
70
|
+
selector.includes(':disabled') && !selector.includes(':not('),
|
|
71
|
+
);
|
|
72
|
+
expect(disabledBlocks.length).toBeGreaterThan(0);
|
|
73
|
+
for (const {selector, body} of disabledBlocks) {
|
|
74
|
+
expect(body, `disabled rule "${selector}"`).toMatch(/cursor:\s*default/);
|
|
75
|
+
}
|
|
76
|
+
// aria-disabled is how astryx keeps a disabled control focusable, so the
|
|
77
|
+
// reset has to cover it alongside the native state.
|
|
78
|
+
expect(
|
|
79
|
+
disabledBlocks.some(({selector}) => selector.includes('aria-disabled')),
|
|
80
|
+
).toBe(true);
|
|
81
|
+
});
|
|
60
82
|
});
|
|
@@ -21,7 +21,7 @@ export const docs = {
|
|
|
21
21
|
],
|
|
22
22
|
playground: {
|
|
23
23
|
defaults: {
|
|
24
|
-
mode: '
|
|
24
|
+
mode: 'auto',
|
|
25
25
|
children: {
|
|
26
26
|
__element: 'Section',
|
|
27
27
|
props: {
|
|
@@ -65,6 +65,11 @@ export const docs = {
|
|
|
65
65
|
description:
|
|
66
66
|
'Use for any content placed over a dark background (image overlays, video scrims, dark cards) or other inverted surfaces like toasts and tooltips.',
|
|
67
67
|
},
|
|
68
|
+
{
|
|
69
|
+
guidance: true,
|
|
70
|
+
description:
|
|
71
|
+
'Prefer mode="auto" when the surface color comes from a theme token. A token named "inverted" is not guaranteed to be inverted, and auto measures what was actually painted instead of trusting the name — including deciding that a surface needs no media context at all.',
|
|
72
|
+
},
|
|
68
73
|
{
|
|
69
74
|
guidance: true,
|
|
70
75
|
description:
|
|
@@ -85,10 +90,17 @@ export const docs = {
|
|
|
85
90
|
props: [
|
|
86
91
|
{
|
|
87
92
|
name: 'mode',
|
|
88
|
-
type: "'dark' | 'light'",
|
|
93
|
+
type: "'dark' | 'light' | 'auto' | 'off'",
|
|
89
94
|
required: true,
|
|
90
95
|
description:
|
|
91
|
-
'Surface luminance context: dark for content over dark backgrounds (light text, white-tinted interactions), light for content over light backgrounds (dark text, black-tinted interactions).',
|
|
96
|
+
'Surface luminance context: dark for content over dark backgrounds (light text, white-tinted interactions), light for content over light backgrounds (dark text, black-tinted interactions), auto to decide from the painted surface — no media context when the ambient text already reads on the surface (3:1), otherwise the side that reads better — and off to turn it off explicitly. The element renders either way, so a surface can switch contexts without remounting children.',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'fallback',
|
|
100
|
+
type: "'dark' | 'light'",
|
|
101
|
+
default: "'dark'",
|
|
102
|
+
description:
|
|
103
|
+
'Which side auto uses when the surface cannot be measured: during SSR, on the first client frame, and whenever the backdrop is not knowable from CSS — most often a background-image, whose pixels need sampling (useImageMode) rather than a computed style. Ignored unless mode is auto.',
|
|
92
104
|
},
|
|
93
105
|
{
|
|
94
106
|
name: 'children',
|
|
@@ -111,6 +123,11 @@ export const docsDense = {
|
|
|
111
123
|
description:
|
|
112
124
|
'Use for any content over dark background (image overlays, video scrims, dark cards) or other inverted surfaces like toasts/tooltips.',
|
|
113
125
|
},
|
|
126
|
+
{
|
|
127
|
+
guidance: true,
|
|
128
|
+
description:
|
|
129
|
+
'Prefer mode="auto" when surface color comes from a theme token — a token named "inverted" is not guaranteed to be; auto measures what was painted.',
|
|
130
|
+
},
|
|
114
131
|
{
|
|
115
132
|
guidance: true,
|
|
116
133
|
description:
|
|
@@ -129,6 +146,8 @@ export const docsDense = {
|
|
|
129
146
|
],
|
|
130
147
|
},
|
|
131
148
|
propDescriptions: {
|
|
132
|
-
mode: 'surface luminance context: dark for content over dark backgrounds (light text, white-tinted interactions), light for content over light backgrounds (dark text, black-tinted interactions)',
|
|
149
|
+
mode: 'surface luminance context: dark for content over dark backgrounds (light text, white-tinted interactions), light for content over light backgrounds (dark text, black-tinted interactions), auto to decide from painted surface (none if ambient text already reads at 3:1, else better-reading side), off to turn off explicitly (element still renders, so children never remount)',
|
|
150
|
+
fallback:
|
|
151
|
+
'side auto uses when surface is unmeasurable (SSR, first frame, background-image — those need useImageMode sampling); ignored unless mode is auto',
|
|
133
152
|
},
|
|
134
153
|
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file MediaTheme.dom.test.tsx
|
|
5
|
+
* @input MediaTheme rendered in jsdom
|
|
6
|
+
* @output Coverage for mode="auto" and mode="off" DOM behavior
|
|
7
|
+
* @position Companion to useAutoMediaMode.test.ts, which covers the pure pick
|
|
8
|
+
*
|
|
9
|
+
* jsdom applies no stylesheet and resolves no custom properties, so auto
|
|
10
|
+
* cannot measure here — which makes this the right place to pin the fallback
|
|
11
|
+
* behavior that an unmeasurable surface depends on.
|
|
12
|
+
*
|
|
13
|
+
* Named `.dom.test.tsx` rather than `.test.tsx`: a sibling `.test.ts` of the
|
|
14
|
+
* same basename collides in the TypeScript project service, and type-aware
|
|
15
|
+
* lint then cannot resolve either file.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import {describe, it, expect} from 'vitest';
|
|
19
|
+
import {render, screen} from '@testing-library/react';
|
|
20
|
+
import {MediaTheme} from './MediaTheme';
|
|
21
|
+
import type {MediaThemeMode} from './MediaTheme';
|
|
22
|
+
|
|
23
|
+
function renderMode(mode: MediaThemeMode, fallback?: 'dark' | 'light') {
|
|
24
|
+
render(
|
|
25
|
+
<div style={{background: 'rgb(10, 19, 23)'}}>
|
|
26
|
+
<MediaTheme mode={mode} fallback={fallback}>
|
|
27
|
+
<span data-testid="child">content</span>
|
|
28
|
+
</MediaTheme>
|
|
29
|
+
</div>,
|
|
30
|
+
);
|
|
31
|
+
return screen.getByTestId('child').parentElement;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe('MediaTheme', () => {
|
|
35
|
+
it.each(['dark', 'light'] as const)('applies mode=%s verbatim', mode => {
|
|
36
|
+
expect(renderMode(mode)?.getAttribute('data-astryx-media')).toBe(mode);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('renders no media attribute for mode="off"', () => {
|
|
40
|
+
const wrapper = renderMode('off');
|
|
41
|
+
expect(wrapper?.hasAttribute('data-astryx-media')).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('still renders its element for mode="off" so children never remount', () => {
|
|
45
|
+
expect(renderMode('off')?.tagName).toBe('DIV');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('falls back to dark for an unmeasurable auto surface', () => {
|
|
49
|
+
expect(renderMode('auto')?.getAttribute('data-astryx-media')).toBe('dark');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('honors an explicit fallback', () => {
|
|
53
|
+
expect(renderMode('auto', 'light')?.getAttribute('data-astryx-media')).toBe(
|
|
54
|
+
'light',
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('ignores fallback when the mode is explicit', () => {
|
|
59
|
+
expect(renderMode('dark', 'light')?.getAttribute('data-astryx-media')).toBe(
|
|
60
|
+
'dark',
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('leaves no probe element behind', () => {
|
|
65
|
+
const {container} = render(
|
|
66
|
+
<div style={{background: 'rgb(10, 19, 23)'}}>
|
|
67
|
+
<MediaTheme mode="auto">
|
|
68
|
+
<span>content</span>
|
|
69
|
+
</MediaTheme>
|
|
70
|
+
</div>,
|
|
71
|
+
);
|
|
72
|
+
expect(container.querySelectorAll('span')).toHaveLength(1);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Regression: an earlier revision keyed the measurement to a dependency
|
|
76
|
+
// array, so a surface whose color changed by prop kept a stale mode until
|
|
77
|
+
// something unrelated re-ran the effect.
|
|
78
|
+
it('re-measures when the surface changes without the theme changing', () => {
|
|
79
|
+
function Harness({background}: {background: string}) {
|
|
80
|
+
return (
|
|
81
|
+
<div style={{background}}>
|
|
82
|
+
<MediaTheme mode="auto" fallback="dark">
|
|
83
|
+
<span data-testid="child">content</span>
|
|
84
|
+
</MediaTheme>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
// jsdom resolves no custom properties, so the measured pick is always the
|
|
89
|
+
// fallback; what this pins is that the effect RUNS again — a stale
|
|
90
|
+
// implementation skips it entirely.
|
|
91
|
+
const {rerender} = render(<Harness background="rgb(10, 19, 23)" />);
|
|
92
|
+
const first = screen.getByTestId('child').parentElement;
|
|
93
|
+
rerender(<Harness background="rgb(255, 255, 255)" />);
|
|
94
|
+
expect(screen.getByTestId('child').parentElement).toBe(first);
|
|
95
|
+
expect(first?.getAttribute('data-astryx-media')).toBe('dark');
|
|
96
|
+
});
|
|
97
|
+
});
|
package/src/theme/MediaTheme.tsx
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file MediaTheme.tsx
|
|
7
|
-
* @input mode prop ("dark" | "light") + children
|
|
7
|
+
* @input mode prop ("dark" | "light" | "auto" | "off") + children
|
|
8
8
|
* @output Wrapper div that creates an inverted theming context
|
|
9
9
|
* @position Theme system component; sibling to Theme
|
|
10
10
|
*
|
|
11
11
|
* Provides semantic token overrides for content rendered on a surface
|
|
12
12
|
* with a different luminance than the page background. Used by Toast,
|
|
13
|
-
*
|
|
13
|
+
* Overlay, and other components that render on inverted surfaces.
|
|
14
14
|
*
|
|
15
15
|
* How it works:
|
|
16
16
|
* 1. Sets `data-astryx-media="dark|light"` — the theme's generated CSS
|
|
@@ -22,11 +22,14 @@
|
|
|
22
22
|
* `onDark.components` / `onLight.components` in defineTheme().
|
|
23
23
|
* 4. Children (Button, Link, Text, etc.) pick up inverted tokens
|
|
24
24
|
* naturally through CSS custom property inheritance
|
|
25
|
+
* 5. `mode="auto"` measures the painted surface and picks a side — or none;
|
|
26
|
+
* `mode="off"` renders the same element with no media attribute, so
|
|
27
|
+
* either can change without remounting children.
|
|
25
28
|
*
|
|
26
29
|
* @example
|
|
27
30
|
* ```
|
|
28
31
|
* <div style={{ backgroundColor: 'var(--color-background-inverted)' }}>
|
|
29
|
-
* <MediaTheme mode="
|
|
32
|
+
* <MediaTheme mode="auto">
|
|
30
33
|
* <Button label="Undo" variant="ghost" />
|
|
31
34
|
* </MediaTheme>
|
|
32
35
|
* </div>
|
|
@@ -34,24 +37,46 @@
|
|
|
34
37
|
*/
|
|
35
38
|
|
|
36
39
|
import * as React from 'react';
|
|
40
|
+
import {useRef} from 'react';
|
|
37
41
|
import * as stylex from '@stylexjs/stylex';
|
|
38
42
|
import {colorVars} from './tokens.stylex';
|
|
39
43
|
import {dataAttr} from '../naming';
|
|
44
|
+
import {useAutoMediaMode} from '../hooks/useAutoMediaMode';
|
|
40
45
|
|
|
41
46
|
const styles = stylex.create({
|
|
42
47
|
root: {
|
|
43
48
|
display: 'contents',
|
|
49
|
+
},
|
|
50
|
+
active: {
|
|
44
51
|
color: colorVars['--color-text-primary'],
|
|
45
52
|
},
|
|
46
53
|
});
|
|
47
54
|
|
|
55
|
+
/** Surface luminance context, or `"off"` for no media context at all. */
|
|
56
|
+
export type MediaThemeMode = 'dark' | 'light' | 'auto' | 'off';
|
|
57
|
+
|
|
48
58
|
export interface MediaThemeProps {
|
|
49
59
|
/**
|
|
50
60
|
* The surface luminance context for children.
|
|
51
61
|
* - `"dark"` — children are on a dark background (get light text/icons)
|
|
52
62
|
* - `"light"` — children are on a light background (get dark text/icons)
|
|
63
|
+
* - `"auto"` — measure the painted surface and use whichever side reads
|
|
64
|
+
* better on it, or no media context at all when the surface's ambient
|
|
65
|
+
* text already reads better than either
|
|
66
|
+
* - `"off"` — children keep the ambient theme; the surface needs no
|
|
67
|
+
* inversion
|
|
53
68
|
*/
|
|
54
|
-
mode:
|
|
69
|
+
mode: MediaThemeMode;
|
|
70
|
+
/**
|
|
71
|
+
* Which side `mode="auto"` uses when the surface cannot be measured: on the
|
|
72
|
+
* server, on the first client frame, and whenever the backdrop is not
|
|
73
|
+
* knowable from CSS — most often a `background-image`, whose pixels need
|
|
74
|
+
* sampling (see `useImageMode`) rather than a computed style.
|
|
75
|
+
*
|
|
76
|
+
* Ignored unless `mode="auto"`.
|
|
77
|
+
* @default "dark"
|
|
78
|
+
*/
|
|
79
|
+
fallback?: 'dark' | 'light';
|
|
55
80
|
/** Content to render in the media context */
|
|
56
81
|
children: React.ReactNode;
|
|
57
82
|
}
|
|
@@ -65,13 +90,23 @@ export interface MediaThemeProps {
|
|
|
65
90
|
*/
|
|
66
91
|
export function MediaTheme({
|
|
67
92
|
mode,
|
|
93
|
+
fallback = 'dark',
|
|
68
94
|
children,
|
|
69
95
|
}: MediaThemeProps): React.ReactElement {
|
|
96
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
97
|
+
// Measures this element's PARENT — see useAutoMediaMode. `display: contents`
|
|
98
|
+
// means the parent is the element that actually paints the surface.
|
|
99
|
+
const detected = useAutoMediaMode(ref, mode === 'auto');
|
|
100
|
+
const resolved = mode === 'auto' ? (detected ?? fallback) : mode;
|
|
101
|
+
|
|
102
|
+
// "off" keeps the element — and therefore the React tree and the DOM
|
|
103
|
+
// structure — identical, so a surface can switch its media context on and
|
|
104
|
+
// off without remounting its children.
|
|
70
105
|
return (
|
|
71
106
|
<div
|
|
72
|
-
{
|
|
73
|
-
{...
|
|
74
|
-
|
|
107
|
+
ref={ref}
|
|
108
|
+
{...(resolved === 'off' ? null : {[dataAttr('media')]: resolved})}
|
|
109
|
+
{...stylex.props(styles.root, resolved !== 'off' && styles.active)}>
|
|
75
110
|
{children}
|
|
76
111
|
</div>
|
|
77
112
|
);
|
|
@@ -738,7 +738,9 @@ describe('pseudo-class overrides in components', () => {
|
|
|
738
738
|
expect(css).toContain('.astryx-radio {');
|
|
739
739
|
expect(css).toContain('border-color: #8F9296');
|
|
740
740
|
// Pseudo rule — separate selector
|
|
741
|
-
expect(css).toContain(
|
|
741
|
+
expect(css).toContain(
|
|
742
|
+
'.astryx-radio:hover:where(:not(:disabled,[aria-disabled="true"])) {',
|
|
743
|
+
);
|
|
742
744
|
expect(css).toContain(
|
|
743
745
|
'border-color: color-mix(in srgb, #8F9296, black 20%)',
|
|
744
746
|
);
|
|
@@ -764,7 +766,9 @@ describe('pseudo-class overrides in components', () => {
|
|
|
764
766
|
const css = generateThemeTestCSS(theme);
|
|
765
767
|
expect(css).toContain('.astryx-button.primary-muted {');
|
|
766
768
|
expect(css).toContain('background-color: #ECF5FF');
|
|
767
|
-
expect(css).toContain(
|
|
769
|
+
expect(css).toContain(
|
|
770
|
+
'.astryx-button.primary-muted:hover:where(:not(:disabled,[aria-disabled="true"])) {',
|
|
771
|
+
);
|
|
768
772
|
expect(css).toContain('background-color: #D6EBFF');
|
|
769
773
|
expect(css).toContain('.astryx-button.primary-muted:focus-visible {');
|
|
770
774
|
expect(css).toContain('outline: 2px solid var(--color-accent)');
|
|
@@ -787,7 +791,9 @@ describe('pseudo-class overrides in components', () => {
|
|
|
787
791
|
// Should NOT emit an empty base rule
|
|
788
792
|
expect(css).not.toMatch(/\.astryx-switch\s*\{\s*\}/);
|
|
789
793
|
// Should emit the pseudo rule
|
|
790
|
-
expect(css).toContain(
|
|
794
|
+
expect(css).toContain(
|
|
795
|
+
'.astryx-switch:hover:where(:not(:disabled,[aria-disabled="true"])) {',
|
|
796
|
+
);
|
|
791
797
|
});
|
|
792
798
|
|
|
793
799
|
it('keeps non-pseudo string values as regular properties', () => {
|
package/src/theme/defineTheme.ts
CHANGED
|
@@ -113,6 +113,11 @@ export type TokenValue = string | [light: string, dark: string];
|
|
|
113
113
|
* to the component selector. Supported pseudo-classes include `:hover`,
|
|
114
114
|
* `:focus-visible`, `:active`, `:checked`, `:disabled`, etc.
|
|
115
115
|
*
|
|
116
|
+
* A `:hover` override describes the ENABLED control: it is emitted with a
|
|
117
|
+
* guard that keeps it off disabled and `aria-disabled` elements, which
|
|
118
|
+
* `:hover` would otherwise still match. Style the disabled state through
|
|
119
|
+
* `:disabled` instead.
|
|
120
|
+
*
|
|
116
121
|
* @example
|
|
117
122
|
* ```ts
|
|
118
123
|
* {
|
|
@@ -85,6 +85,9 @@ const STRUCTURAL_VARS = new Set([
|
|
|
85
85
|
'--table-row-overlay',
|
|
86
86
|
'--separator-display',
|
|
87
87
|
'--astryx-section-padding',
|
|
88
|
+
// Private counterpart of the public token above: one ancestor Section's
|
|
89
|
+
// padding, propagated down the tree. Structural, never authored by a theme.
|
|
90
|
+
'--_section-padding-propagated',
|
|
88
91
|
]);
|
|
89
92
|
|
|
90
93
|
/**
|
|
@@ -164,9 +167,6 @@ function discoverComponents(): ComponentInfo[] {
|
|
|
164
167
|
allVars.add(v);
|
|
165
168
|
}
|
|
166
169
|
}
|
|
167
|
-
if (allVars.size === 0) {
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
170
|
|
|
171
171
|
// Only check component directories (those with a doc file named after the
|
|
172
172
|
// directory). Match against the on-disk listing rather than existsSync so
|
|
@@ -188,6 +188,16 @@ function discoverComponents(): ComponentInfo[] {
|
|
|
188
188
|
/* skip */
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
// A directory earns a check by declaring a var OR by documenting a
|
|
192
|
+
// derived[] entry. Bailing on the var count alone (as this did) hid every
|
|
193
|
+
// component that is themeable purely through an expansion strategy —
|
|
194
|
+
// `{property: 'padding', expand: 'container'}` names no var, so such a
|
|
195
|
+
// component declares nothing and its registry↔doc consistency check
|
|
196
|
+
// silently never ran.
|
|
197
|
+
if (allVars.size === 0 && docDerived.length === 0) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
|
|
191
201
|
results.push({
|
|
192
202
|
dir,
|
|
193
203
|
sourceVars: [...allVars],
|
|
@@ -212,6 +222,7 @@ const DIR_TO_REGISTRY_KEY: Record<string, string> = {
|
|
|
212
222
|
DropdownMenu: 'dropdown-menu',
|
|
213
223
|
Field: 'field',
|
|
214
224
|
HoverCard: 'hovercard',
|
|
225
|
+
NumberInput: 'number-input',
|
|
215
226
|
Popover: 'popover',
|
|
216
227
|
ProgressBar: 'progressbar-mark',
|
|
217
228
|
Section: 'section',
|
|
@@ -262,9 +273,12 @@ const VARS_WITHOUT_DERIVED_MAPPING = new Set([
|
|
|
262
273
|
'--_avatar-group-overlap',
|
|
263
274
|
'--_codeblock-gutter-width',
|
|
264
275
|
'--_tab-indicator-bottom',
|
|
265
|
-
// Hit-area outset on a ::after overlay
|
|
266
|
-
//
|
|
276
|
+
// Hit-area outset on a ::after overlay, and whether that overlay is
|
|
277
|
+
// generated at all — `inset` and `content` on a pseudo-element are not
|
|
278
|
+
// properties a theme author sets on the component.
|
|
267
279
|
'--_thumbnail-hit-inset',
|
|
280
|
+
'--_input-clear-hit-inset',
|
|
281
|
+
'--_input-clear-hit-content',
|
|
268
282
|
// Indentation and row-spacing metrics: --tree-list-indent is the authorable
|
|
269
283
|
// step, --_tree-indent the per-row distance TreeListItem computes from it.
|
|
270
284
|
// --tree-list-row-gap is applied as half a padding-block on each row wrapper,
|
|
@@ -67,6 +67,10 @@ export const derivedVarRegistry: Record<string, DerivedVarEntry[]> = {
|
|
|
67
67
|
],
|
|
68
68
|
field: [{property: 'borderRadius', vars: ['--_field-radius']}],
|
|
69
69
|
hovercard: [{property: 'borderRadius', vars: ['--_hovercard-radius']}],
|
|
70
|
+
'number-input': [
|
|
71
|
+
{property: 'padding', expand: 'container'},
|
|
72
|
+
{property: 'borderRadius', vars: ['--_field-radius']},
|
|
73
|
+
],
|
|
70
74
|
popover: [{property: 'borderRadius', vars: ['--_popover-radius']}],
|
|
71
75
|
'progressbar-mark': [
|
|
72
76
|
{property: 'width', vars: ['--_progressbar-mark-width'], replaces: true},
|
|
@@ -160,6 +160,45 @@ describe('generateThemeRules', () => {
|
|
|
160
160
|
).toBe(true);
|
|
161
161
|
});
|
|
162
162
|
|
|
163
|
+
// A theme authoring `:hover` is describing the ENABLED control. Without a
|
|
164
|
+
// guard the rule paints a disabled one too, because browsers suppress a
|
|
165
|
+
// disabled control's events, not its hover styling — and a theme override
|
|
166
|
+
// would then reintroduce, on every component at once, the defect the
|
|
167
|
+
// components' own styles were fixed for.
|
|
168
|
+
it('keeps a themed :hover off disabled elements', () => {
|
|
169
|
+
const hoverTheme = defineTheme({
|
|
170
|
+
name: 'hover-guard',
|
|
171
|
+
components: {
|
|
172
|
+
button: {
|
|
173
|
+
base: {
|
|
174
|
+
':hover': {color: 'red'},
|
|
175
|
+
':focus-visible': {outline: '2px solid blue'},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
const hoverRules = generateThemeRules(hoverTheme);
|
|
181
|
+
const hoverRule = hoverRules.find(rule => rule.includes(':hover'));
|
|
182
|
+
expect(hoverRule).toBeDefined();
|
|
183
|
+
expect(hoverRule).toContain(
|
|
184
|
+
'.astryx-button:hover:where(:not(:disabled,[aria-disabled="true"]))',
|
|
185
|
+
);
|
|
186
|
+
// Every selector in a comma-separated list carries its own guard —
|
|
187
|
+
// a trailing pseudo does not distribute over a selector list. (Counted,
|
|
188
|
+
// not split: the guard contains a comma of its own.)
|
|
189
|
+
const selectorText = String(hoverRule).split('{')[0];
|
|
190
|
+
const hovers = selectorText.match(/:hover/g) || [];
|
|
191
|
+
const guards = selectorText.match(/:where\(:not\(:disabled/g) || [];
|
|
192
|
+
expect(hovers.length).toBeGreaterThan(0);
|
|
193
|
+
expect(guards.length).toBe(hovers.length);
|
|
194
|
+
// Other pseudo-classes are untouched: a disabled control can still be
|
|
195
|
+
// focused (that is the point of aria-disabled), and :focus-visible on it
|
|
196
|
+
// is correct.
|
|
197
|
+
const focusRule = hoverRules.find(rule => rule.includes(':focus-visible'));
|
|
198
|
+
expect(focusRule).toContain('.astryx-button:focus-visible {');
|
|
199
|
+
expect(focusRule).not.toContain('aria-disabled');
|
|
200
|
+
});
|
|
201
|
+
|
|
163
202
|
// --- Prose rules ---
|
|
164
203
|
|
|
165
204
|
it('includes prose heading rules with computed values', () => {
|
|
@@ -584,3 +623,82 @@ describe('brutalist-style derived expansion', () => {
|
|
|
584
623
|
expect(rule).toContain('--_dropdown-menu-padding: 4px');
|
|
585
624
|
});
|
|
586
625
|
});
|
|
626
|
+
|
|
627
|
+
describe('physical padding longhands', () => {
|
|
628
|
+
const ruleFor = (
|
|
629
|
+
component: string,
|
|
630
|
+
base: Record<string, string>,
|
|
631
|
+
name = 'test-physical-padding',
|
|
632
|
+
) =>
|
|
633
|
+
generateThemeRules(
|
|
634
|
+
defineTheme({name, components: {[component]: {base}}}),
|
|
635
|
+
).find(r => r.includes(`.astryx-${component}`));
|
|
636
|
+
|
|
637
|
+
// `padding-top`/`padding-bottom` ARE the block edges in every horizontal
|
|
638
|
+
// writing mode, so the expansion can normalize them with no direction
|
|
639
|
+
// assumption. Without that, the padding lands raw on the element and the
|
|
640
|
+
// component's internals — the NumberInput stepper column, container bleed —
|
|
641
|
+
// read the default instead of what the theme set.
|
|
642
|
+
it.each([
|
|
643
|
+
['paddingTop', {paddingTop: '14px'}, 'block-start'],
|
|
644
|
+
['paddingBottom', {paddingBottom: '14px'}, 'block-end'],
|
|
645
|
+
])('routes %s through the container expansion', (_label, base, edge) => {
|
|
646
|
+
const rule = ruleFor('card', base);
|
|
647
|
+
expect(rule).toContain(`--astryx-card-padding-${edge}: 14px`);
|
|
648
|
+
expect(rule).not.toMatch(/[{;]\s*padding-(top|bottom):/);
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
it('normalizes both block edges together, asymmetrically', () => {
|
|
652
|
+
const rule = ruleFor('number-input', {
|
|
653
|
+
paddingTop: '14px',
|
|
654
|
+
paddingBottom: '6px',
|
|
655
|
+
});
|
|
656
|
+
expect(rule).toContain('--astryx-number-input-padding-block-start: 14px');
|
|
657
|
+
expect(rule).toContain('--astryx-number-input-padding-block-end: 6px');
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
it.each(['card', 'dialog', 'section', 'number-input'])(
|
|
661
|
+
'reaches %s, which expands its padding',
|
|
662
|
+
component => {
|
|
663
|
+
expect(ruleFor(component, {paddingTop: '14px'})).toContain(
|
|
664
|
+
`--astryx-${component}-padding-block-start: 14px`,
|
|
665
|
+
);
|
|
666
|
+
},
|
|
667
|
+
);
|
|
668
|
+
|
|
669
|
+
// THE RTL GUARD. `paddingLeft` is inline-start in LTR and inline-end in RTL,
|
|
670
|
+
// and the tokens are consumed by logical properties, so mapping it would
|
|
671
|
+
// silently move the padding to the other edge in RTL. It stays physical —
|
|
672
|
+
// which is what the author wrote — and does not reach the tokens.
|
|
673
|
+
it('leaves the direction-relative inline pair physical', () => {
|
|
674
|
+
const rule = ruleFor('card', {paddingLeft: '20px', paddingRight: '8px'});
|
|
675
|
+
expect(rule).toContain('padding-left: 20px');
|
|
676
|
+
expect(rule).toContain('padding-right: 8px');
|
|
677
|
+
expect(rule).not.toContain('--astryx-card-padding-inline');
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
it('expands the block edges while leaving left physical', () => {
|
|
681
|
+
const rule = ruleFor('card', {paddingTop: '14px', paddingLeft: '20px'});
|
|
682
|
+
expect(rule).toContain('--astryx-card-padding-block-start: 14px');
|
|
683
|
+
expect(rule).toContain('padding-left: 20px');
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
// The shorthand-plus-override case was the worst one: the tokens carried
|
|
687
|
+
// 10px while the element painted 14px on top, so every internal compensated
|
|
688
|
+
// by the wrong amount.
|
|
689
|
+
it('lets a physical longhand override the shorthand per edge', () => {
|
|
690
|
+
const rule = ruleFor('card', {padding: '10px', paddingTop: '14px'});
|
|
691
|
+
expect(rule).toContain('--astryx-card-padding-block-start: 14px');
|
|
692
|
+
expect(rule).toContain('--astryx-card-padding-block-end: 10px');
|
|
693
|
+
expect(rule).toContain('--astryx-card-padding-inline: 10px');
|
|
694
|
+
expect(rule).not.toMatch(/[{;]\s*padding(-top)?:/);
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
// A `vars` entry carries one value for the whole box, so a single physical
|
|
698
|
+
// edge must not feed it — only the container expansion takes these.
|
|
699
|
+
it('does not feed a single edge to a whole-box derived var', () => {
|
|
700
|
+
const rule = ruleFor('dropdown-menu', {paddingTop: '14px'});
|
|
701
|
+
expect(rule).toContain('padding-top: 14px');
|
|
702
|
+
expect(rule).not.toContain('--_dropdown-menu-padding');
|
|
703
|
+
});
|
|
704
|
+
});
|