@astryxdesign/core 0.1.9 → 0.2.0-canary.136a00f
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 +107 -0
- package/dist/Avatar/Avatar.d.ts +42 -3
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +190 -59
- package/dist/Avatar/AvatarStatusDot.d.ts +6 -4
- package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts +7 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroup.js +58 -6
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +7 -2
- package/dist/Banner/Banner.js +2 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +11 -4
- package/dist/Breadcrumbs/index.d.ts +1 -0
- package/dist/Breadcrumbs/index.d.ts.map +1 -1
- package/dist/Breadcrumbs/index.js +2 -1
- package/dist/Button/Button.d.ts +1 -1
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +6 -4
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +50 -9
- package/dist/Calendar/dayCellUtils.d.ts +4 -4
- package/dist/Calendar/dayCellUtils.js +2 -2
- package/dist/Calendar/styles.d.ts +30 -31
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +30 -31
- package/dist/Card/Card.js +1 -1
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +22 -12
- package/dist/Chat/ChatComposerInput.js +1 -1
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +3 -1
- package/dist/Chat/ChatLayout.js +4 -4
- package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
- package/dist/Chat/ChatMessageBubble.js +8 -8
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +10 -3
- package/dist/Chat/useTriggerMenu.js +2 -2
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +6 -6
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +19 -4
- package/dist/Citation/Citation.d.ts +22 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +20 -6
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +16 -10
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +3 -1
- package/dist/CommandPalette/CommandPalette.d.ts +1 -1
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +42 -3
- package/dist/CommandPalette/CommandPaletteItem.js +1 -1
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +23 -5
- package/dist/ContextMenu/index.d.ts +1 -0
- package/dist/ContextMenu/index.d.ts.map +1 -1
- package/dist/ContextMenu/index.js +3 -1
- package/dist/DateInput/DateInput.d.ts +10 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +33 -19
- package/dist/DateRangeInput/DateRangeInput.d.ts +10 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +23 -20
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +23 -18
- package/dist/Divider/Divider.d.ts +2 -2
- package/dist/Divider/Divider.d.ts.map +1 -1
- package/dist/Divider/Divider.js +13 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts +6 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +22 -5
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +4 -1
- package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuItem.js +5 -2
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +8 -11
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioGroup.js +3 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +5 -2
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +104 -0
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -0
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +427 -0
- package/dist/DropdownMenu/index.d.ts +10 -0
- package/dist/DropdownMenu/index.d.ts.map +1 -1
- package/dist/DropdownMenu/index.js +13 -0
- package/dist/DropdownMenu/menuItemHover.d.ts +23 -0
- package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -0
- package/dist/DropdownMenu/menuItemHover.js +33 -0
- package/dist/DropdownMenu/menuItemRoles.d.ts +8 -0
- package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -1
- package/dist/DropdownMenu/menuItemRoles.js +10 -1
- package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
- package/dist/DropdownMenu/renderDropdownItems.js +21 -6
- package/dist/Field/Field.d.ts +3 -1
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +4 -1
- package/dist/Field/FieldLabel.d.ts +2 -1
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +9 -5
- package/dist/Field/inputStyles.stylex.d.ts +1 -0
- package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
- package/dist/Field/inputStyles.stylex.js +1 -0
- package/dist/FieldStatus/FieldStatus.d.ts +10 -0
- package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
- package/dist/FieldStatus/FieldStatus.js +39 -3
- package/dist/FileInput/FileInput.d.ts +10 -2
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +93 -65
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +10 -4
- package/dist/Icon/Icon.d.ts +15 -1
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +19 -3
- package/dist/Item/Item.d.ts +16 -3
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +31 -6
- package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
- package/dist/Layer/layerAnimations.stylex.js +10 -2
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +19 -13
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +6 -3
- package/dist/List/ListItem.d.ts +11 -1
- package/dist/List/ListItem.d.ts.map +1 -1
- package/dist/List/ListItem.js +2 -0
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +7 -0
- package/dist/MetadataList/MetadataList.d.ts +1 -1
- package/dist/MetadataList/MetadataList.d.ts.map +1 -1
- package/dist/MetadataList/MetadataList.js +4 -2
- package/dist/MultiSelector/MultiSelector.d.ts +9 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +80 -42
- package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
- package/dist/NumberInput/NumberInput.d.ts +10 -2
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +22 -17
- package/dist/Outline/Outline.js +2 -2
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +11 -3
- package/dist/PowerSearch/PowerSearch.d.ts +9 -2
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +2 -0
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +6 -1
- package/dist/RadioList/RadioList.d.ts +2 -2
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +5 -5
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +49 -19
- package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +5 -3
- package/dist/Selector/Selector.d.ts +8 -0
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +66 -17
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +5 -5
- package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
- package/dist/SideNav/SideNavCollapseButton.js +13 -10
- package/dist/SideNav/SideNavItem.d.ts +1 -1
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +12 -10
- package/dist/Skeleton/Skeleton.d.ts.map +1 -1
- package/dist/Skeleton/Skeleton.js +2 -2
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +87 -34
- package/dist/Spinner/Spinner.d.ts +3 -2
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +11 -2
- package/dist/Switch/Switch.d.ts +8 -1
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +171 -91
- package/dist/TabList/Tab.js +2 -2
- package/dist/TabList/TabList.d.ts +2 -11
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +5 -9
- package/dist/TabList/TabListContext.d.ts +0 -5
- package/dist/TabList/TabListContext.d.ts.map +1 -1
- package/dist/TabList/TabListContext.js +0 -5
- package/dist/TabList/TabMenu.js +1 -1
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +30 -4
- package/dist/Table/TableCell.js +3 -3
- package/dist/Table/TableHeaderCell.js +3 -3
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +15 -11
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +37 -27
- package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
- package/dist/Table/plugins/selection/useTableSelection.js +3 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +15 -7
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +29 -23
- package/dist/Table/types.d.ts +32 -0
- package/dist/Table/types.d.ts.map +1 -1
- package/dist/TextArea/TextArea.d.ts +10 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +18 -19
- package/dist/TextInput/TextInput.d.ts +10 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +20 -17
- package/dist/Thumbnail/Thumbnail.js +2 -2
- package/dist/TimeInput/TimeInput.d.ts +10 -2
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +17 -17
- package/dist/Timestamp/Timestamp.d.ts +31 -3
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +47 -76
- package/dist/Timestamp/formatInstant.d.ts +41 -0
- package/dist/Timestamp/formatInstant.d.ts.map +1 -0
- package/dist/Timestamp/formatInstant.js +177 -0
- package/dist/Timestamp/index.d.ts +1 -0
- package/dist/Timestamp/index.d.ts.map +1 -1
- package/dist/Timestamp/tooltipEntries.d.ts +56 -0
- package/dist/Timestamp/tooltipEntries.d.ts.map +1 -0
- package/dist/Timestamp/tooltipEntries.js +163 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +61 -9
- package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButton.js +3 -1
- package/dist/Token/Token.d.ts +34 -4
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +85 -45
- package/dist/Token/TokenLink.d.ts +62 -0
- package/dist/Token/TokenLink.d.ts.map +1 -0
- package/dist/Token/TokenLink.js +76 -0
- package/dist/Token/index.d.ts +1 -1
- package/dist/Token/index.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.d.ts +9 -2
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +4 -2
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +17 -1
- package/dist/TopNav/TopNavItem.d.ts +3 -1
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +30 -3
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +1 -0
- package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
- package/dist/TreeList/TreeListBranches.js +8 -6
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +32 -14
- package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +22 -11
- package/dist/Typeahead/Typeahead.d.ts +9 -2
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +11 -2
- package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
- package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
- package/dist/Typeahead/TypeaheadItem.js +20 -10
- package/dist/astryx.css +70 -30
- package/dist/astryx.umd.js +51 -51
- package/dist/astryx.umd.js.map +4 -4
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/isRtlElement.d.ts +18 -0
- package/dist/hooks/isRtlElement.d.ts.map +1 -0
- package/dist/hooks/isRtlElement.js +27 -0
- package/dist/hooks/useAnnounce.d.ts +3 -0
- package/dist/hooks/useAnnounce.d.ts.map +1 -1
- package/dist/hooks/useAnnounce.js +39 -1
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +52 -11
- package/dist/hooks/useGridFocus.d.ts +6 -1
- package/dist/hooks/useGridFocus.d.ts.map +1 -1
- package/dist/hooks/useGridFocus.js +12 -9
- package/dist/hooks/useHotkeys.d.ts +9 -0
- package/dist/hooks/useHotkeys.d.ts.map +1 -1
- package/dist/hooks/useHotkeys.js +9 -0
- package/dist/hooks/useInputStatusIcon.d.ts +38 -0
- package/dist/hooks/useInputStatusIcon.d.ts.map +1 -0
- package/dist/hooks/useInputStatusIcon.js +158 -0
- package/dist/hooks/useKeyboardHint.d.ts +1 -1
- package/dist/hooks/useKeyboardHint.d.ts.map +1 -1
- package/dist/hooks/useKeyboardHint.js +4 -2
- package/dist/hooks/useListFocus.d.ts +39 -1
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +54 -9
- package/dist/i18n/InternationalizationContext.d.ts +1 -0
- package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
- package/dist/i18n/InternationalizationContext.js +3 -0
- package/dist/i18n/InternationalizationProvider.d.ts +8 -1
- package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
- package/dist/i18n/InternationalizationProvider.js +5 -1
- package/dist/i18n/getLocaleDirection.d.ts +18 -0
- package/dist/i18n/getLocaleDirection.d.ts.map +1 -0
- package/dist/i18n/getLocaleDirection.js +29 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +7 -1
- package/dist/i18n/useDirection.d.ts +2 -0
- package/dist/i18n/useDirection.d.ts.map +1 -0
- package/dist/i18n/useDirection.js +27 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +13 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -1
- package/dist/utils/plainDate.d.ts +17 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +23 -4
- package/dist/utils/rtlStyles.d.ts +24 -0
- package/dist/utils/rtlStyles.d.ts.map +1 -0
- package/dist/utils/rtlStyles.js +27 -0
- package/locales/en.json +112 -0
- package/locales/pseudo.json +84 -0
- package/package.json +6 -1
- package/src/Avatar/Avatar.doc.mjs +50 -3
- package/src/Avatar/Avatar.test.tsx +218 -0
- package/src/Avatar/Avatar.tsx +285 -79
- package/src/Avatar/AvatarStatusDot.doc.mjs +4 -4
- package/src/Avatar/AvatarStatusDot.tsx +6 -4
- package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
- package/src/AvatarGroup/AvatarGroup.test.tsx +162 -2
- package/src/AvatarGroup/AvatarGroup.tsx +58 -3
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +5 -2
- package/src/Banner/Banner.tsx +6 -6
- package/src/Breadcrumbs/BreadcrumbItem.tsx +10 -10
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +52 -1
- package/src/Breadcrumbs/index.ts +4 -0
- package/src/Button/Button.doc.mjs +0 -4
- package/src/Button/Button.test.tsx +16 -0
- package/src/Button/Button.tsx +6 -4
- package/src/Calendar/Calendar.test.tsx +170 -20
- package/src/Calendar/Calendar.tsx +73 -16
- package/src/Calendar/dayCellUtils.test.ts +18 -18
- package/src/Calendar/dayCellUtils.ts +2 -2
- package/src/Calendar/styles.ts +33 -39
- package/src/Card/Card.tsx +1 -1
- package/src/Carousel/Carousel.tsx +25 -6
- package/src/Chat/ChatComposer.doc.mjs +2 -2
- package/src/Chat/ChatComposerInput.doc.mjs +1 -1
- package/src/Chat/ChatComposerInput.tsx +2 -2
- package/src/Chat/ChatDictationButton.tsx +7 -1
- package/src/Chat/ChatLayout.tsx +4 -4
- package/src/Chat/ChatMessageBubble.tsx +15 -10
- package/src/Chat/ChatSystemMessage.test.tsx +5 -0
- package/src/Chat/ChatToolCalls.tsx +9 -2
- package/src/Chat/useTriggerMenu.tsx +1 -1
- package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +23 -0
- package/src/CheckboxInput/CheckboxInput.tsx +21 -6
- package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
- package/src/CheckboxList/CheckboxList.test.tsx +94 -3
- package/src/CheckboxList/CheckboxListItem.tsx +17 -10
- package/src/Citation/Citation.doc.mjs +4 -3
- package/src/Citation/Citation.test.tsx +97 -0
- package/src/Citation/Citation.tsx +43 -11
- package/src/CodeBlock/CodeBlock.test.tsx +17 -0
- package/src/CodeBlock/CodeBlock.tsx +38 -11
- package/src/Collapsible/Collapsible.doc.mjs +1 -0
- package/src/Collapsible/Collapsible.test.tsx +7 -0
- package/src/Collapsible/Collapsible.tsx +16 -6
- package/src/CommandPalette/CommandPalette.test.tsx +95 -1
- package/src/CommandPalette/CommandPalette.tsx +41 -2
- package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
- package/src/ContextMenu/ContextMenu.test.tsx +59 -2
- package/src/ContextMenu/ContextMenu.tsx +22 -11
- package/src/ContextMenu/index.ts +5 -0
- package/src/DateInput/DateInput.doc.mjs +25 -0
- package/src/DateInput/DateInput.test.tsx +230 -0
- package/src/DateInput/DateInput.tsx +51 -29
- package/src/DateRangeInput/DateRangeInput.doc.mjs +16 -0
- package/src/DateRangeInput/DateRangeInput.test.tsx +140 -0
- package/src/DateRangeInput/DateRangeInput.tsx +42 -30
- package/src/DateTimeInput/DateTimeInput.doc.mjs +22 -1
- package/src/DateTimeInput/DateTimeInput.test.tsx +112 -0
- package/src/DateTimeInput/DateTimeInput.tsx +44 -39
- package/src/Divider/Divider.test.tsx +32 -8
- package/src/Divider/Divider.tsx +14 -1
- package/src/DropdownMenu/DropdownMenu.test.tsx +60 -0
- package/src/DropdownMenu/DropdownMenu.tsx +31 -12
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +8 -2
- package/src/DropdownMenu/DropdownMenuItem.tsx +9 -3
- package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +4 -12
- package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +9 -10
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +9 -3
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +20 -2
- package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +88 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +635 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +553 -0
- package/src/DropdownMenu/index.ts +16 -0
- package/src/DropdownMenu/menuItemHover.ts +39 -0
- package/src/DropdownMenu/menuItemRoles.ts +9 -0
- package/src/DropdownMenu/renderDropdownItems.tsx +29 -15
- package/src/Field/Field.tsx +14 -9
- package/src/Field/FieldLabel.test.tsx +25 -0
- package/src/Field/FieldLabel.tsx +12 -3
- package/src/Field/inputStyles.stylex.ts +2 -0
- package/src/FieldStatus/FieldStatus.test.tsx +72 -0
- package/src/FieldStatus/FieldStatus.tsx +48 -2
- package/src/FileInput/FileInput.doc.mjs +23 -2
- package/src/FileInput/FileInput.test.tsx +104 -13
- package/src/FileInput/FileInput.tsx +106 -79
- package/src/HoverCard/useHoverCard.tsx +15 -3
- package/src/Icon/Icon.doc.mjs +13 -0
- package/src/Icon/Icon.test.tsx +89 -0
- package/src/Icon/Icon.tsx +51 -3
- package/src/Item/Item.doc.mjs +5 -0
- package/src/Item/Item.test.tsx +88 -0
- package/src/Item/Item.tsx +57 -11
- package/src/Layer/layerAnimations.stylex.ts +23 -0
- package/src/Lightbox/Lightbox.tsx +15 -7
- package/src/List/List.test.tsx +17 -29
- package/src/List/List.tsx +6 -1
- package/src/List/ListItem.doc.mjs +12 -0
- package/src/List/ListItem.tsx +13 -0
- package/src/Markdown/Markdown.test.tsx +21 -0
- package/src/Markdown/Markdown.tsx +4 -0
- package/src/MetadataList/MetadataList.test.tsx +24 -0
- package/src/MetadataList/MetadataList.tsx +6 -2
- package/src/MultiSelector/MultiSelector.doc.mjs +20 -0
- package/src/MultiSelector/MultiSelector.test.tsx +402 -0
- package/src/MultiSelector/MultiSelector.tsx +120 -59
- package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
- package/src/NumberInput/NumberInput.doc.mjs +21 -0
- package/src/NumberInput/NumberInput.test.tsx +71 -0
- package/src/NumberInput/NumberInput.tsx +35 -26
- package/src/Outline/Outline.test.tsx +12 -12
- package/src/Outline/Outline.tsx +2 -2
- package/src/Pagination/Pagination.tsx +11 -3
- package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
- package/src/PowerSearch/PowerSearch.test.tsx +23 -0
- package/src/PowerSearch/PowerSearch.tsx +10 -1
- package/src/ProgressBar/ProgressBar.test.tsx +34 -0
- package/src/ProgressBar/ProgressBar.tsx +16 -1
- package/src/RadioList/RadioList.doc.mjs +6 -0
- package/src/RadioList/RadioList.test.tsx +26 -4
- package/src/RadioList/RadioList.tsx +2 -2
- package/src/RadioList/RadioListItem.tsx +12 -5
- package/src/Resizable/ResizeHandle.test.tsx +94 -0
- package/src/Resizable/ResizeHandle.tsx +70 -20
- package/src/SegmentedControl/SegmentedControl.test.tsx +28 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +22 -2
- package/src/Selector/Selector.doc.mjs +15 -0
- package/src/Selector/Selector.test.tsx +370 -0
- package/src/Selector/Selector.tsx +88 -20
- package/src/SideNav/SideNav.tsx +1 -8
- package/src/SideNav/SideNavCollapseButton.tsx +9 -7
- package/src/SideNav/SideNavItem.tsx +5 -3
- package/src/Skeleton/Skeleton.test.tsx +16 -0
- package/src/Skeleton/Skeleton.tsx +13 -1
- package/src/Slider/Slider.doc.mjs +6 -0
- package/src/Slider/Slider.test.tsx +240 -12
- package/src/Slider/Slider.tsx +96 -23
- package/src/Spinner/Spinner.test.tsx +10 -8
- package/src/Spinner/Spinner.tsx +15 -5
- package/src/Switch/Switch.doc.mjs +142 -42
- package/src/Switch/Switch.test.tsx +111 -0
- package/src/Switch/Switch.tsx +149 -32
- package/src/TabList/Tab.tsx +2 -2
- package/src/TabList/TabList.doc.mjs +0 -6
- package/src/TabList/TabList.test.tsx +3 -15
- package/src/TabList/TabList.tsx +6 -17
- package/src/TabList/TabListContext.ts +0 -6
- package/src/TabList/TabMenu.tsx +2 -2
- package/src/Table/BaseTable.tsx +34 -2
- package/src/Table/Table.doc.mjs +11 -0
- package/src/Table/Table.test.tsx +85 -0
- package/src/Table/TableCell.tsx +3 -3
- package/src/Table/TableHeaderCell.tsx +3 -3
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +9 -6
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +19 -0
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +27 -18
- package/src/Table/plugins/selection/useTableSelection.test.tsx +61 -3
- package/src/Table/plugins/selection/useTableSelection.tsx +3 -0
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +38 -9
- package/src/Table/plugins/tree/useTableTreeData.tsx +17 -13
- package/src/Table/types.ts +33 -0
- package/src/Table/useTableRowStatus.doc.mjs +1 -1
- package/src/TextArea/TextArea.doc.mjs +21 -0
- package/src/TextArea/TextArea.test.tsx +23 -0
- package/src/TextArea/TextArea.tsx +27 -26
- package/src/TextInput/TextInput.doc.mjs +21 -0
- package/src/TextInput/TextInput.test.tsx +150 -0
- package/src/TextInput/TextInput.tsx +28 -25
- package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
- package/src/Thumbnail/Thumbnail.tsx +1 -1
- package/src/TimeInput/TimeInput.doc.mjs +21 -0
- package/src/TimeInput/TimeInput.test.tsx +23 -0
- package/src/TimeInput/TimeInput.tsx +24 -25
- package/src/Timestamp/Timestamp.doc.mjs +32 -6
- package/src/Timestamp/Timestamp.test.tsx +371 -0
- package/src/Timestamp/Timestamp.tsx +96 -93
- package/src/Timestamp/formatInstant.ts +218 -0
- package/src/Timestamp/index.ts +4 -0
- package/src/Timestamp/tooltipEntries.test.ts +552 -0
- package/src/Timestamp/tooltipEntries.ts +210 -0
- package/src/Toast/ToastViewport.test.tsx +218 -8
- package/src/Toast/ToastViewport.tsx +71 -12
- package/src/ToggleButton/ToggleButton.test.tsx +24 -0
- package/src/ToggleButton/ToggleButton.tsx +19 -1
- package/src/Token/Token.test.tsx +166 -15
- package/src/Token/Token.tsx +104 -47
- package/src/Token/TokenLink.tsx +107 -0
- package/src/Token/index.ts +1 -1
- package/src/Tokenizer/Tokenizer.doc.mjs +23 -1
- package/src/Tokenizer/Tokenizer.test.tsx +23 -0
- package/src/Tokenizer/Tokenizer.tsx +14 -2
- package/src/Tooltip/Tooltip.test.tsx +46 -0
- package/src/Tooltip/useTooltip.tsx +20 -0
- package/src/TopNav/TopNav.test.tsx +93 -2
- package/src/TopNav/TopNavItem.doc.mjs +3 -3
- package/src/TopNav/TopNavItem.tsx +35 -6
- package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +1 -1
- package/src/TreeList/TreeList.doc.mjs +6 -0
- package/src/TreeList/TreeList.test.tsx +50 -10
- package/src/TreeList/TreeList.tsx +5 -0
- package/src/TreeList/TreeListBranches.tsx +8 -6
- package/src/TreeList/TreeListItem.tsx +33 -11
- package/src/Typeahead/BaseTypeahead.tsx +42 -15
- package/src/Typeahead/Typeahead.doc.mjs +13 -0
- package/src/Typeahead/Typeahead.test.tsx +112 -0
- package/src/Typeahead/Typeahead.tsx +17 -1
- package/src/Typeahead/TypeaheadItem.tsx +2 -1
- package/src/__tests__/forcedColors.ts +60 -0
- package/src/__tests__/inputWidthContract.test.tsx +62 -0
- package/src/doc-mjs.d.ts +19 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/isRtlElement.ts +27 -0
- package/src/hooks/useAnnounce.test.tsx +75 -2
- package/src/hooks/useAnnounce.ts +47 -1
- package/src/hooks/useFocusTrap.test.tsx +104 -0
- package/src/hooks/useFocusTrap.ts +61 -12
- package/src/hooks/useGridFocus.doc.mjs +3 -3
- package/src/hooks/useGridFocus.test.tsx +41 -0
- package/src/hooks/useGridFocus.ts +21 -10
- package/src/hooks/useHotkeys.ts +9 -0
- package/src/hooks/useInputStatusIcon.test.tsx +162 -0
- package/src/hooks/useInputStatusIcon.tsx +224 -0
- package/src/hooks/useKeyboardHint.test.tsx +22 -0
- package/src/hooks/useKeyboardHint.tsx +6 -2
- package/src/hooks/useListFocus.doc.mjs +25 -3
- package/src/hooks/useListFocus.test.tsx +153 -1
- package/src/hooks/useListFocus.ts +102 -9
- package/src/i18n/InternationalizationContext.ts +4 -0
- package/src/i18n/InternationalizationProvider.tsx +12 -2
- package/src/i18n/__tests__/getLocaleDirection.test.ts +40 -0
- package/src/i18n/__tests__/useDirection.test.tsx +66 -0
- package/src/i18n/getLocaleDirection.ts +29 -0
- package/src/i18n/index.ts +6 -0
- package/src/i18n/useDirection.ts +29 -0
- package/src/reset.css +0 -26
- package/src/reset.test.ts +60 -0
- package/src/theme/derivedVarRegistry.test.ts +1 -0
- package/src/theme/derivedVarRegistry.ts +6 -0
- package/src/theme/generateThemeRules.test.ts +42 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/plainDate.test.ts +24 -6
- package/src/utils/plainDate.ts +18 -4
- package/src/utils/rtlStyles.ts +27 -0
|
@@ -56,14 +56,27 @@ function resolveEffectiveSide(
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
|
-
* Hit
|
|
60
|
-
*
|
|
59
|
+
* Hit-area inline bias, expressed as a fraction of the pill's per-side offset.
|
|
60
|
+
*
|
|
61
|
+
* The visible pill is placed by `pillOffsetX`/`pillOffsetY`: anchored at the
|
|
62
|
+
* divider's inline-start edge and pushed one grip-width-plus-gap toward the
|
|
63
|
+
* panel side via a PHYSICAL translate (dir −1 = start, +1 = end). Because that
|
|
64
|
+
* offset is physical, the pill sits on the same physical side of the divider in
|
|
65
|
+
* both LTR and RTL. The grab zone must sit OVER that pill, so it has to use the
|
|
66
|
+
* exact same anchor + physical-offset construction as the pill (just wider) —
|
|
67
|
+
* anchoring the hit area at the divider centre (`insetInlineStart: 50%`) and
|
|
68
|
+
* biasing with a percentage translate mixes a logical anchor (which flips under
|
|
69
|
+
* RTL) with a physical translate (which doesn't), leaving the grab zone stranded
|
|
70
|
+
* to one side under RTL. Returning the pill's `dir` here lets the hit area reuse
|
|
71
|
+
* `pillOffsetX`/`pillOffsetY` so the two elements are positioned identically.
|
|
61
72
|
*/
|
|
62
|
-
function
|
|
73
|
+
function hitAreaBiasDir(
|
|
74
|
+
effectiveSide: 'start' | 'end' | 'center',
|
|
75
|
+
): number | null {
|
|
63
76
|
if (effectiveSide === 'center') {
|
|
64
|
-
return
|
|
77
|
+
return null;
|
|
65
78
|
}
|
|
66
|
-
return effectiveSide === 'start' ?
|
|
79
|
+
return effectiveSide === 'start' ? -1 : 1;
|
|
67
80
|
}
|
|
68
81
|
|
|
69
82
|
const styles = stylex.create({
|
|
@@ -102,8 +115,8 @@ const styles = stylex.create({
|
|
|
102
115
|
},
|
|
103
116
|
overlayVertical: {
|
|
104
117
|
insetBlockEnd: 0,
|
|
105
|
-
|
|
106
|
-
|
|
118
|
+
insetInlineStart: 0,
|
|
119
|
+
insetInlineEnd: 0,
|
|
107
120
|
height: 'var(--resize-handle-hit-area, 16px)',
|
|
108
121
|
},
|
|
109
122
|
horizontal: {
|
|
@@ -145,16 +158,24 @@ const styles = stylex.create({
|
|
|
145
158
|
width: spacingVars['--spacing-4'],
|
|
146
159
|
top: 0,
|
|
147
160
|
bottom: 0,
|
|
148
|
-
left: '50%',
|
|
149
161
|
cursor: 'col-resize',
|
|
150
162
|
},
|
|
151
163
|
hitAreaVertical: {
|
|
152
164
|
height: spacingVars['--spacing-4'],
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
top: '50%',
|
|
165
|
+
insetInlineStart: 0,
|
|
166
|
+
insetInlineEnd: 0,
|
|
156
167
|
cursor: 'row-resize',
|
|
157
168
|
},
|
|
169
|
+
// Centered grab zone (pillPlacement 'center' / no bias): sit the hit area on
|
|
170
|
+
// the divider itself. Anchored logically so it centers in both directions.
|
|
171
|
+
hitAreaCenteredX: {
|
|
172
|
+
insetInlineStart: '50%',
|
|
173
|
+
transform: 'translateX(-50%)',
|
|
174
|
+
},
|
|
175
|
+
hitAreaCenteredY: {
|
|
176
|
+
insetBlockStart: '50%',
|
|
177
|
+
transform: 'translateY(-50%)',
|
|
178
|
+
},
|
|
158
179
|
|
|
159
180
|
// Pill base — themes target .astryx-resize-handle-pill for size/shape.
|
|
160
181
|
pill: {
|
|
@@ -167,7 +188,7 @@ const styles = stylex.create({
|
|
|
167
188
|
transitionDuration: durationVars['--duration-fast'],
|
|
168
189
|
transitionTimingFunction: easeVars['--ease-standard'],
|
|
169
190
|
top: '50%',
|
|
170
|
-
|
|
191
|
+
insetInlineStart: '50%',
|
|
171
192
|
transform: 'translate(-50%, -50%)',
|
|
172
193
|
},
|
|
173
194
|
pillHorizontal: {
|
|
@@ -193,14 +214,32 @@ const styles = stylex.create({
|
|
|
193
214
|
// Dynamic styles — avoids inline style overrides.
|
|
194
215
|
// Each axis gets its own function since StyleX requires static structure.
|
|
195
216
|
const dynamicStyles = stylex.create({
|
|
196
|
-
|
|
197
|
-
|
|
217
|
+
// Hit-area inline offset — mirrors the pill's `pillOffsetX`/`pillOffsetY`
|
|
218
|
+
// construction so the grab zone sits centred on the visible pill in BOTH
|
|
219
|
+
// directions. Both anchor at the divider's inline-start edge
|
|
220
|
+
// (`insetInlineStart: 0`) and travel toward the panel side with the SAME
|
|
221
|
+
// physical translate `dir * (gripWidth + gap)`, so they share the pill's
|
|
222
|
+
// near edge. The hit area is wider, so it also shifts by half the width
|
|
223
|
+
// difference `(16px − 3px) / 2 = 6.5px` to align the two CENTRES. That
|
|
224
|
+
// centring shift is along the inline axis (a box grows from its inline-start
|
|
225
|
+
// edge toward inline-end), so it must flip physical sign under RTL — unlike
|
|
226
|
+
// the `dir * (...)` travel, which is physical and identical in both
|
|
227
|
+
// directions because the pill's own offset is physical. Mixing the previous
|
|
228
|
+
// divider-relative `50%` anchor with a percentage translate stranded the grab
|
|
229
|
+
// zone to one side under RTL; this construction keeps it on the pill.
|
|
230
|
+
hitAreaOffsetX: (dir: number) => ({
|
|
231
|
+
insetInlineStart: 0,
|
|
232
|
+
transform: {
|
|
233
|
+
default: `translate(calc(${dir} * (3px + ${spacingVars['--spacing-1']}) - 6.5px), -50%)`,
|
|
234
|
+
':is([dir="rtl"] *)': `translate(calc(${dir} * (3px + ${spacingVars['--spacing-1']}) + 6.5px), -50%)`,
|
|
235
|
+
},
|
|
198
236
|
}),
|
|
199
|
-
|
|
200
|
-
|
|
237
|
+
hitAreaOffsetY: (dir: number) => ({
|
|
238
|
+
insetBlockStart: 0,
|
|
239
|
+
transform: `translate(-50%, calc(${dir} * (3px + ${spacingVars['--spacing-1']}) - 6.5px))`,
|
|
201
240
|
}),
|
|
202
241
|
pillOffsetX: (dir: number) => ({
|
|
203
|
-
|
|
242
|
+
insetInlineStart: 0,
|
|
204
243
|
transform: `translate(calc(${dir} * (100% + ${spacingVars['--spacing-1']})), -50%)`,
|
|
205
244
|
}),
|
|
206
245
|
// Vertical offset: no rotation — use explicit landscape dimensions.
|
|
@@ -333,6 +372,9 @@ export function ResizeHandle({
|
|
|
333
372
|
isReversed,
|
|
334
373
|
resizable?._isCollapsed ?? false,
|
|
335
374
|
);
|
|
375
|
+
// Physical offset direction shared by the pill and the grab zone (null =
|
|
376
|
+
// centered / no bias). Keeps the two positioned identically in LTR and RTL.
|
|
377
|
+
const hitBiasDir = hitAreaBiasDir(effectiveSide);
|
|
336
378
|
|
|
337
379
|
const getRTLMultiplier = useCallback((): number => {
|
|
338
380
|
const el = handleRef.current;
|
|
@@ -538,9 +580,17 @@ export function ResizeHandle({
|
|
|
538
580
|
{...stylex.props(
|
|
539
581
|
styles.hitArea,
|
|
540
582
|
isHorizontal ? styles.hitAreaHorizontal : styles.hitAreaVertical,
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
583
|
+
// Bias the grab zone to sit over the visible pill. When the pill is
|
|
584
|
+
// centered (no bias) just center the hit area on the divider; when
|
|
585
|
+
// it's offset to a panel side, reuse the pill's physical-offset
|
|
586
|
+
// construction so the two stay aligned in LTR and RTL alike.
|
|
587
|
+
hitBiasDir == null
|
|
588
|
+
? isHorizontal
|
|
589
|
+
? styles.hitAreaCenteredX
|
|
590
|
+
: styles.hitAreaCenteredY
|
|
591
|
+
: isHorizontal
|
|
592
|
+
? dynamicStyles.hitAreaOffsetX(hitBiasDir)
|
|
593
|
+
: dynamicStyles.hitAreaOffsetY(hitBiasDir),
|
|
544
594
|
isDisabled && styles.disabled,
|
|
545
595
|
)}
|
|
546
596
|
onPointerDown={handlePointerDown}
|
|
@@ -14,6 +14,10 @@ import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
15
|
import {SegmentedControl} from './SegmentedControl';
|
|
16
16
|
import {SegmentedControlItem} from './SegmentedControlItem';
|
|
17
|
+
import {
|
|
18
|
+
getAllInjectedCss,
|
|
19
|
+
getForcedColorsRules,
|
|
20
|
+
} from '../__tests__/forcedColors';
|
|
17
21
|
|
|
18
22
|
// Mock showPopover/hidePopover (not implemented in jsdom) so the tooltip layer
|
|
19
23
|
// reflects its open state via a `popover-open` attribute the tests can assert.
|
|
@@ -780,3 +784,27 @@ describe('SegmentedControl container handler forwarding', () => {
|
|
|
780
784
|
expect(onChange).not.toHaveBeenCalled();
|
|
781
785
|
});
|
|
782
786
|
});
|
|
787
|
+
|
|
788
|
+
// jsdom cannot emulate forced-colors rendering, so these assert that the
|
|
789
|
+
// compiled output includes the forced-colors rules; visual behavior needs
|
|
790
|
+
// manual verification under Windows High Contrast.
|
|
791
|
+
describe('forced colors (WCAG 1.4.11)', () => {
|
|
792
|
+
it('compiles forced-colors overrides so the selected segment survives Windows High Contrast', () => {
|
|
793
|
+
render(
|
|
794
|
+
<SegmentedControl value="grid" onChange={() => {}} label="View mode">
|
|
795
|
+
<SegmentedControlItem value="grid" label="Grid" />
|
|
796
|
+
<SegmentedControlItem value="list" label="List" />
|
|
797
|
+
</SegmentedControl>,
|
|
798
|
+
);
|
|
799
|
+
const css = getForcedColorsRules();
|
|
800
|
+
// The painted surface fill and shadow are stripped; Highlight/
|
|
801
|
+
// HighlightText marks the selected segment.
|
|
802
|
+
expect(css).toContain('background-color: highlight;');
|
|
803
|
+
expect(css).toContain('color: highlighttext;');
|
|
804
|
+
// The segment is a <button>; without opting out of UA remapping it keeps
|
|
805
|
+
// the native ButtonFace surface and ignores the Highlight fill, leaving
|
|
806
|
+
// HighlightText text on a white surface. forced-color-adjust: none makes
|
|
807
|
+
// both render as authored.
|
|
808
|
+
expect(getAllInjectedCss()).toContain('forced-color-adjust: none;');
|
|
809
|
+
});
|
|
810
|
+
});
|
|
@@ -103,9 +103,27 @@ const styles = stylex.create({
|
|
|
103
103
|
},
|
|
104
104
|
},
|
|
105
105
|
selected: {
|
|
106
|
-
|
|
106
|
+
// Forced colors (Windows High Contrast) strips the painted surface fill
|
|
107
|
+
// and box shadow, which would leave the selected segment with no state
|
|
108
|
+
// indication beyond font weight. Highlight/HighlightText is the platform
|
|
109
|
+
// convention for a selected item (WCAG 1.4.11).
|
|
110
|
+
//
|
|
111
|
+
// forced-color-adjust must be `none` here: the segment is a <button>, and
|
|
112
|
+
// the UA keeps native form-control colors (ButtonFace surface) for it under
|
|
113
|
+
// forced colors, ignoring the authored Highlight fill — the label kept its
|
|
114
|
+
// HighlightText color, giving white text on a white surface. Opting the
|
|
115
|
+
// selected segment out of UA remapping makes both the Highlight surface and
|
|
116
|
+
// the HighlightText label render as authored, restoring figure-ground.
|
|
117
|
+
forcedColorAdjust: 'none',
|
|
118
|
+
color: {
|
|
119
|
+
default: colorVars['--color-text-primary'],
|
|
120
|
+
'@media (forced-colors: active)': 'HighlightText',
|
|
121
|
+
},
|
|
107
122
|
fontWeight: fontWeightVars['--font-weight-semibold'],
|
|
108
|
-
backgroundColor:
|
|
123
|
+
backgroundColor: {
|
|
124
|
+
default: colorVars['--color-background-surface'],
|
|
125
|
+
'@media (forced-colors: active)': 'Highlight',
|
|
126
|
+
},
|
|
109
127
|
boxShadow: shadowVars['--shadow-low'],
|
|
110
128
|
},
|
|
111
129
|
disabled: {
|
|
@@ -169,6 +187,7 @@ export function SegmentedControlItem({
|
|
|
169
187
|
icon,
|
|
170
188
|
isDisabled = false,
|
|
171
189
|
onClick: onClickProp,
|
|
190
|
+
xstyle,
|
|
172
191
|
...rest
|
|
173
192
|
}: SegmentedControlItemProps) {
|
|
174
193
|
const ctx = useSegmentedControlContext();
|
|
@@ -228,6 +247,7 @@ export function SegmentedControlItem({
|
|
|
228
247
|
isSelected && styles.selected,
|
|
229
248
|
!isSelected && !isItemDisabled && styles.hover,
|
|
230
249
|
isItemDisabled && styles.disabled,
|
|
250
|
+
xstyle,
|
|
231
251
|
),
|
|
232
252
|
)}>
|
|
233
253
|
{iconElement}
|
|
@@ -23,6 +23,8 @@ export const docs = {
|
|
|
23
23
|
targets: [
|
|
24
24
|
{className: 'astryx-selector', visualProps: ['size', 'status']},
|
|
25
25
|
{className: 'astryx-selector-option'},
|
|
26
|
+
{className: 'astryx-selector-clear-icon'},
|
|
27
|
+
{className: 'astryx-selector-indicator-icon', states: ['state']},
|
|
26
28
|
],
|
|
27
29
|
},
|
|
28
30
|
description: 'Dropdown selector for choosing from a list of options.',
|
|
@@ -128,12 +130,25 @@ export const docs = {
|
|
|
128
130
|
type: "{type: 'error' | 'warning' | 'success', message?: string}",
|
|
129
131
|
description: 'Validation status with an optional message.',
|
|
130
132
|
},
|
|
133
|
+
{
|
|
134
|
+
name: 'statusVariant',
|
|
135
|
+
type: "'attached' | 'detached'",
|
|
136
|
+
description:
|
|
137
|
+
'How the status message is placed relative to the input. attached overlaps directly below the input (bordered treatment); detached floats below as a separate element with spacing.',
|
|
138
|
+
default: "'attached'",
|
|
139
|
+
},
|
|
131
140
|
{
|
|
132
141
|
name: 'renderOption',
|
|
133
142
|
type: '(option: SelectorOptionData) => ReactNode',
|
|
134
143
|
description:
|
|
135
144
|
'Custom render function for each selectable option in the dropdown. Use this instead of JSX children; dividers and sections are rendered by the selector.',
|
|
136
145
|
},
|
|
146
|
+
{
|
|
147
|
+
name: 'width',
|
|
148
|
+
type: 'SizeValue',
|
|
149
|
+
description:
|
|
150
|
+
'Width of the field (number = pixels, string used as-is, e.g. "100%"). Sizes the whole field (label, control, and status) so they stay aligned.',
|
|
151
|
+
},
|
|
137
152
|
{
|
|
138
153
|
name: 'xstyle',
|
|
139
154
|
type: 'StyleXStyles',
|
|
@@ -20,8 +20,11 @@ import {
|
|
|
20
20
|
import userEvent from '@testing-library/user-event';
|
|
21
21
|
import {Selector} from './Selector';
|
|
22
22
|
import {SelectorOption} from './SelectorOption';
|
|
23
|
+
import {Icon} from '../Icon';
|
|
23
24
|
import {InputGroup, InputGroupText} from '../InputGroup';
|
|
24
25
|
import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
|
|
26
|
+
import {defineTheme} from '../theme/defineTheme';
|
|
27
|
+
import {generateThemeCSSFlat} from '../theme/generateThemeRules';
|
|
25
28
|
|
|
26
29
|
function politeRegion(): HTMLElement | null {
|
|
27
30
|
return document.querySelector('[data-astryx-live-region="polite"]');
|
|
@@ -610,6 +613,28 @@ describe('Selector', () => {
|
|
|
610
613
|
expect(within(listbox).getByText('No results found')).toBeInTheDocument();
|
|
611
614
|
});
|
|
612
615
|
|
|
616
|
+
it('empty-state message is not exposed as a listbox child', async () => {
|
|
617
|
+
const user = userEvent.setup();
|
|
618
|
+
render(
|
|
619
|
+
<Selector
|
|
620
|
+
label="Fruit"
|
|
621
|
+
options={OPTIONS}
|
|
622
|
+
value="Apple"
|
|
623
|
+
onChange={() => {}}
|
|
624
|
+
hasSearch
|
|
625
|
+
/>,
|
|
626
|
+
);
|
|
627
|
+
await user.click(screen.getByRole('button', {name: 'Fruit'}));
|
|
628
|
+
await user.type(screen.getByRole('combobox', h), 'xyz');
|
|
629
|
+
|
|
630
|
+
// role="listbox" only permits option/group children — the visual
|
|
631
|
+
// empty-state message must be presentational (it is announced through
|
|
632
|
+
// the result-count live region instead).
|
|
633
|
+
const listbox = screen.getByRole('listbox', h);
|
|
634
|
+
const empty = within(listbox).getByText('No results found');
|
|
635
|
+
expect(empty).toHaveAttribute('role', 'presentation');
|
|
636
|
+
});
|
|
637
|
+
|
|
613
638
|
it('calls onChange when selecting a filtered option', async () => {
|
|
614
639
|
const user = userEvent.setup();
|
|
615
640
|
const onChange = vi.fn();
|
|
@@ -746,6 +771,119 @@ describe('Selector', () => {
|
|
|
746
771
|
expect(politeRegion()?.textContent ?? '').toBe('');
|
|
747
772
|
});
|
|
748
773
|
});
|
|
774
|
+
|
|
775
|
+
describe('grouped search', () => {
|
|
776
|
+
const GROUPED = [
|
|
777
|
+
{
|
|
778
|
+
type: 'section' as const,
|
|
779
|
+
title: 'Citrus',
|
|
780
|
+
options: [
|
|
781
|
+
{value: 'orange', label: 'Orange'},
|
|
782
|
+
{value: 'lemon', label: 'Lemon'},
|
|
783
|
+
],
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
type: 'section' as const,
|
|
787
|
+
title: 'Berries',
|
|
788
|
+
options: [
|
|
789
|
+
{value: 'strawberry', label: 'Strawberry'},
|
|
790
|
+
{value: 'blueberry', label: 'Blueberry'},
|
|
791
|
+
],
|
|
792
|
+
},
|
|
793
|
+
];
|
|
794
|
+
|
|
795
|
+
it('keeps the group header above matching items while searching', async () => {
|
|
796
|
+
const user = userEvent.setup();
|
|
797
|
+
render(
|
|
798
|
+
<Selector
|
|
799
|
+
label="Fruit"
|
|
800
|
+
options={GROUPED}
|
|
801
|
+
onChange={() => {}}
|
|
802
|
+
hasSearch
|
|
803
|
+
/>,
|
|
804
|
+
);
|
|
805
|
+
await user.click(screen.getByRole('button', {name: 'Fruit'}));
|
|
806
|
+
// "orange" only matches within the Citrus group.
|
|
807
|
+
await user.type(screen.getByRole('combobox', h), 'orange');
|
|
808
|
+
|
|
809
|
+
expect(
|
|
810
|
+
screen.getByRole('group', {name: 'Citrus', ...h}),
|
|
811
|
+
).toBeInTheDocument();
|
|
812
|
+
const options = screen.getAllByRole('option', h);
|
|
813
|
+
expect(options).toHaveLength(1);
|
|
814
|
+
expect(options[0]).toHaveTextContent('Orange');
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
it('hides a group whose items have no match', async () => {
|
|
818
|
+
const user = userEvent.setup();
|
|
819
|
+
render(
|
|
820
|
+
<Selector
|
|
821
|
+
label="Fruit"
|
|
822
|
+
options={GROUPED}
|
|
823
|
+
onChange={() => {}}
|
|
824
|
+
hasSearch
|
|
825
|
+
/>,
|
|
826
|
+
);
|
|
827
|
+
await user.click(screen.getByRole('button', {name: 'Fruit'}));
|
|
828
|
+
// "berry" only matches items inside the Berries group.
|
|
829
|
+
await user.type(screen.getByRole('combobox', h), 'berry');
|
|
830
|
+
|
|
831
|
+
expect(
|
|
832
|
+
screen.getByRole('group', {name: 'Berries', ...h}),
|
|
833
|
+
).toBeInTheDocument();
|
|
834
|
+
expect(
|
|
835
|
+
screen.queryByRole('group', {name: 'Citrus', ...h}),
|
|
836
|
+
).not.toBeInTheDocument();
|
|
837
|
+
expect(screen.getAllByRole('option', h)).toHaveLength(2);
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
it('lands keyboard focus on the correct option after filtering', async () => {
|
|
841
|
+
const user = userEvent.setup();
|
|
842
|
+
render(
|
|
843
|
+
<Selector
|
|
844
|
+
label="Fruit"
|
|
845
|
+
options={GROUPED}
|
|
846
|
+
onChange={() => {}}
|
|
847
|
+
hasSearch
|
|
848
|
+
/>,
|
|
849
|
+
);
|
|
850
|
+
await user.click(screen.getByRole('button', {name: 'Fruit'}));
|
|
851
|
+
const search = screen.getByRole('combobox', h);
|
|
852
|
+
// "berry" leaves Strawberry, Blueberry (in that document order).
|
|
853
|
+
await user.type(search, 'berry');
|
|
854
|
+
const options = screen.getAllByRole('option', h);
|
|
855
|
+
expect(options.map(o => o.textContent)).toEqual([
|
|
856
|
+
'Strawberry',
|
|
857
|
+
'Blueberry',
|
|
858
|
+
]);
|
|
859
|
+
await user.keyboard('{ArrowDown}');
|
|
860
|
+
expect(search).toHaveAttribute('aria-activedescendant', options[0].id);
|
|
861
|
+
await user.keyboard('{ArrowDown}');
|
|
862
|
+
expect(search).toHaveAttribute('aria-activedescendant', options[1].id);
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
it('shows the empty state when no group has a match', async () => {
|
|
866
|
+
const user = userEvent.setup();
|
|
867
|
+
render(
|
|
868
|
+
<Selector
|
|
869
|
+
label="Fruit"
|
|
870
|
+
options={GROUPED}
|
|
871
|
+
onChange={() => {}}
|
|
872
|
+
hasSearch
|
|
873
|
+
/>,
|
|
874
|
+
);
|
|
875
|
+
await user.click(screen.getByRole('button', {name: 'Fruit'}));
|
|
876
|
+
await user.type(screen.getByRole('combobox', h), 'zzz');
|
|
877
|
+
expect(screen.queryAllByRole('option', h)).toHaveLength(0);
|
|
878
|
+
expect(
|
|
879
|
+
screen.queryByRole('group', {name: 'Citrus', ...h}),
|
|
880
|
+
).not.toBeInTheDocument();
|
|
881
|
+
const listbox = screen.getByRole('listbox', h);
|
|
882
|
+
expect(
|
|
883
|
+
within(listbox).getByText('No results found'),
|
|
884
|
+
).toBeInTheDocument();
|
|
885
|
+
});
|
|
886
|
+
});
|
|
749
887
|
});
|
|
750
888
|
|
|
751
889
|
describe('keyboard accessibility', () => {
|
|
@@ -1073,3 +1211,235 @@ describe('Selector', () => {
|
|
|
1073
1211
|
});
|
|
1074
1212
|
});
|
|
1075
1213
|
});
|
|
1214
|
+
|
|
1215
|
+
describe('Selector statusVariant forwarding', () => {
|
|
1216
|
+
it('defaults to attached (status renders with data-variant="attached")', () => {
|
|
1217
|
+
const {container} = render(
|
|
1218
|
+
<Selector
|
|
1219
|
+
label="Fruit"
|
|
1220
|
+
options={['Apple', 'Banana']}
|
|
1221
|
+
status={{type: 'error', message: 'Required'}}
|
|
1222
|
+
/>,
|
|
1223
|
+
);
|
|
1224
|
+
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
1225
|
+
'data-variant',
|
|
1226
|
+
'attached',
|
|
1227
|
+
);
|
|
1228
|
+
});
|
|
1229
|
+
|
|
1230
|
+
it('forwards statusVariant="detached" to the underlying Field status', () => {
|
|
1231
|
+
const {container} = render(
|
|
1232
|
+
<Selector
|
|
1233
|
+
label="Fruit"
|
|
1234
|
+
options={['Apple', 'Banana']}
|
|
1235
|
+
status={{type: 'error', message: 'Required'}}
|
|
1236
|
+
statusVariant="detached"
|
|
1237
|
+
/>,
|
|
1238
|
+
);
|
|
1239
|
+
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
1240
|
+
'data-variant',
|
|
1241
|
+
'detached',
|
|
1242
|
+
);
|
|
1243
|
+
});
|
|
1244
|
+
});
|
|
1245
|
+
|
|
1246
|
+
describe('Selector clear icon theme target', () => {
|
|
1247
|
+
// Resolve the clear glyph span (the astryx-icon element inside the clear
|
|
1248
|
+
// button), independent of the theme target class.
|
|
1249
|
+
const getClearIcon = (): HTMLElement => {
|
|
1250
|
+
const button = screen.getByRole('button', {name: 'Clear Fruit'});
|
|
1251
|
+
const icon = button.querySelector('.astryx-icon');
|
|
1252
|
+
if (icon == null) {
|
|
1253
|
+
throw new Error('clear icon not found');
|
|
1254
|
+
}
|
|
1255
|
+
return icon as HTMLElement;
|
|
1256
|
+
};
|
|
1257
|
+
|
|
1258
|
+
it('renders the astryx-selector-clear-icon target on the clear glyph', () => {
|
|
1259
|
+
render(
|
|
1260
|
+
<Selector
|
|
1261
|
+
label="Fruit"
|
|
1262
|
+
options={OPTIONS}
|
|
1263
|
+
value="Banana"
|
|
1264
|
+
onChange={() => {}}
|
|
1265
|
+
hasClear
|
|
1266
|
+
/>,
|
|
1267
|
+
);
|
|
1268
|
+
// The stable theme target lands on the icon element itself (not the
|
|
1269
|
+
// button), so a theme can restyle just this glyph (color, size, hover)
|
|
1270
|
+
// via `defineTheme` — a button-level target could not reach the icon's
|
|
1271
|
+
// own color/size.
|
|
1272
|
+
const icon = getClearIcon();
|
|
1273
|
+
expect(icon).toHaveClass('astryx-selector-clear-icon');
|
|
1274
|
+
expect(icon).toHaveClass('astryx-icon');
|
|
1275
|
+
});
|
|
1276
|
+
|
|
1277
|
+
it('keeps the clear button functional alongside the target', () => {
|
|
1278
|
+
const onChange = vi.fn();
|
|
1279
|
+
render(
|
|
1280
|
+
<Selector
|
|
1281
|
+
label="Fruit"
|
|
1282
|
+
options={OPTIONS}
|
|
1283
|
+
value="Banana"
|
|
1284
|
+
onChange={onChange}
|
|
1285
|
+
hasClear
|
|
1286
|
+
/>,
|
|
1287
|
+
);
|
|
1288
|
+
const clear = screen.getByRole('button', {name: 'Clear Fruit'});
|
|
1289
|
+
expect(clear.tagName).toBe('BUTTON');
|
|
1290
|
+
fireEvent.click(clear);
|
|
1291
|
+
expect(onChange).toHaveBeenCalledWith(null);
|
|
1292
|
+
});
|
|
1293
|
+
|
|
1294
|
+
it('renders the default icon (secondary color, sm size) byte-identically', () => {
|
|
1295
|
+
// Pixel-identical default guard: the clear glyph must carry the exact same
|
|
1296
|
+
// StyleX color/size classes as a standalone secondary/sm icon. The added
|
|
1297
|
+
// target class is purely additive — it changes nothing until a theme
|
|
1298
|
+
// targets it.
|
|
1299
|
+
render(
|
|
1300
|
+
<Selector
|
|
1301
|
+
label="Fruit"
|
|
1302
|
+
options={OPTIONS}
|
|
1303
|
+
value="Banana"
|
|
1304
|
+
onChange={() => {}}
|
|
1305
|
+
hasClear
|
|
1306
|
+
/>,
|
|
1307
|
+
);
|
|
1308
|
+
const icon = getClearIcon();
|
|
1309
|
+
|
|
1310
|
+
const {container: refContainer} = render(
|
|
1311
|
+
<Icon icon="close" size="sm" color="secondary" />,
|
|
1312
|
+
);
|
|
1313
|
+
const refIcon = refContainer.querySelector('.astryx-icon') as HTMLElement;
|
|
1314
|
+
|
|
1315
|
+
const styleClasses = (el: HTMLElement) =>
|
|
1316
|
+
el.className
|
|
1317
|
+
.split(' ')
|
|
1318
|
+
.filter(c => c !== 'astryx-selector-clear-icon')
|
|
1319
|
+
.sort();
|
|
1320
|
+
|
|
1321
|
+
expect(styleClasses(icon)).toEqual(styleClasses(refIcon));
|
|
1322
|
+
});
|
|
1323
|
+
|
|
1324
|
+
it('exposes selector-clear-icon so a theme reaches the icon color, size, and hover', () => {
|
|
1325
|
+
// jsdom cannot resolve the @layer cascade, so the DOM-class assertion above
|
|
1326
|
+
// (target lands on the icon element) plus this generation assertion (the
|
|
1327
|
+
// theme emits same-element icon rules in @layer astryx-theme) together
|
|
1328
|
+
// prove the seam: a same-element theme rule wins over the icon's own
|
|
1329
|
+
// base-layer color/size.
|
|
1330
|
+
const theme = defineTheme({
|
|
1331
|
+
name: 'selector-clear-icon-test',
|
|
1332
|
+
components: {
|
|
1333
|
+
'selector-clear-icon': {
|
|
1334
|
+
base: {
|
|
1335
|
+
width: '12px',
|
|
1336
|
+
height: '12px',
|
|
1337
|
+
fontSize: '12px',
|
|
1338
|
+
color: 'var(--color-icon-secondary)',
|
|
1339
|
+
':hover': {color: 'var(--color-icon-primary)'},
|
|
1340
|
+
},
|
|
1341
|
+
},
|
|
1342
|
+
},
|
|
1343
|
+
});
|
|
1344
|
+
const css = generateThemeCSSFlat(theme);
|
|
1345
|
+
expect(css).toContain('.astryx-selector-clear-icon {');
|
|
1346
|
+
expect(css).toContain('width: 12px');
|
|
1347
|
+
expect(css).toContain('height: 12px');
|
|
1348
|
+
expect(css).toContain('.astryx-selector-clear-icon:hover {');
|
|
1349
|
+
expect(css).toContain('color: var(--color-icon-primary)');
|
|
1350
|
+
});
|
|
1351
|
+
});
|
|
1352
|
+
|
|
1353
|
+
describe('Selector indicator (chevron) icon theme target', () => {
|
|
1354
|
+
const getIndicatorIcon = (container: HTMLElement): HTMLElement => {
|
|
1355
|
+
// The chevron is the only glyph carrying the indicator target class.
|
|
1356
|
+
const icon = container.querySelector('.astryx-selector-indicator-icon');
|
|
1357
|
+
if (icon == null) {
|
|
1358
|
+
throw new Error('indicator icon not found');
|
|
1359
|
+
}
|
|
1360
|
+
return icon as HTMLElement;
|
|
1361
|
+
};
|
|
1362
|
+
|
|
1363
|
+
it('renders the astryx-selector-indicator-icon target on the chevron glyph', () => {
|
|
1364
|
+
const {container} = render(
|
|
1365
|
+
<Selector label="Fruit" options={OPTIONS} onChange={() => {}} />,
|
|
1366
|
+
);
|
|
1367
|
+
// The stable theme target lands on the icon element itself (not the trigger
|
|
1368
|
+
// button), so a theme can restyle just this glyph (color, size, hover) —
|
|
1369
|
+
// and each open/closed state — via `defineTheme`. A button-level target
|
|
1370
|
+
// could not reach the icon's own color/size.
|
|
1371
|
+
const icon = getIndicatorIcon(container);
|
|
1372
|
+
expect(icon).toHaveClass('astryx-selector-indicator-icon');
|
|
1373
|
+
expect(icon).toHaveClass('astryx-icon');
|
|
1374
|
+
// Open/closed state is reflected so a theme can target each state alone.
|
|
1375
|
+
expect(icon).toHaveAttribute('data-state', 'collapsed');
|
|
1376
|
+
});
|
|
1377
|
+
|
|
1378
|
+
it('reflects the expanded state on the chevron when the popover is open', async () => {
|
|
1379
|
+
const user = userEvent.setup();
|
|
1380
|
+
const {container} = render(
|
|
1381
|
+
<Selector label="Fruit" options={OPTIONS} onChange={() => {}} />,
|
|
1382
|
+
);
|
|
1383
|
+
await user.click(screen.getByRole('combobox'));
|
|
1384
|
+
await waitFor(() => {
|
|
1385
|
+
expect(getIndicatorIcon(container)).toHaveAttribute(
|
|
1386
|
+
'data-state',
|
|
1387
|
+
'expanded',
|
|
1388
|
+
);
|
|
1389
|
+
});
|
|
1390
|
+
});
|
|
1391
|
+
|
|
1392
|
+
it('renders the default icon (inherit color, sm size) byte-identically', () => {
|
|
1393
|
+
// Pixel-identical default guard: the chevron glyph must carry the exact
|
|
1394
|
+
// same StyleX color/size classes as a standalone inherit/sm icon. The added
|
|
1395
|
+
// target class + data-state are purely additive — they change nothing until
|
|
1396
|
+
// a theme targets them.
|
|
1397
|
+
const {container} = render(
|
|
1398
|
+
<Selector label="Fruit" options={OPTIONS} onChange={() => {}} />,
|
|
1399
|
+
);
|
|
1400
|
+
const icon = getIndicatorIcon(container);
|
|
1401
|
+
|
|
1402
|
+
const {container: refContainer} = render(
|
|
1403
|
+
<Icon icon="chevronDown" size="sm" color="inherit" />,
|
|
1404
|
+
);
|
|
1405
|
+
const refIcon = refContainer.querySelector('.astryx-icon') as HTMLElement;
|
|
1406
|
+
|
|
1407
|
+
// Exclude the additive theme-target classes (the stable target + its
|
|
1408
|
+
// reflected state class) so only the StyleX color/size classes remain.
|
|
1409
|
+
const themeTargetClasses = new Set([
|
|
1410
|
+
'astryx-selector-indicator-icon',
|
|
1411
|
+
'collapsed',
|
|
1412
|
+
'expanded',
|
|
1413
|
+
]);
|
|
1414
|
+
const styleClasses = (el: HTMLElement) =>
|
|
1415
|
+
el.className
|
|
1416
|
+
.split(' ')
|
|
1417
|
+
.filter(c => !themeTargetClasses.has(c))
|
|
1418
|
+
.sort();
|
|
1419
|
+
|
|
1420
|
+
expect(styleClasses(icon)).toEqual(styleClasses(refIcon));
|
|
1421
|
+
});
|
|
1422
|
+
|
|
1423
|
+
it('exposes selector-indicator-icon so a theme reaches the icon size and per-state color', () => {
|
|
1424
|
+
// jsdom cannot resolve the @layer cascade, so the DOM-class assertions
|
|
1425
|
+
// above (target lands on the icon element) plus this generation assertion
|
|
1426
|
+
// (the theme emits same-element icon rules in @layer astryx-theme) together
|
|
1427
|
+
// prove the seam: a same-element theme rule wins over the icon's own
|
|
1428
|
+
// base-layer color/size.
|
|
1429
|
+
const theme = defineTheme({
|
|
1430
|
+
name: 'selector-indicator-icon-test',
|
|
1431
|
+
components: {
|
|
1432
|
+
'selector-indicator-icon': {
|
|
1433
|
+
base: {width: '14px', height: '14px', fontSize: '14px'},
|
|
1434
|
+
'state:expanded': {color: 'var(--color-icon-primary)'},
|
|
1435
|
+
},
|
|
1436
|
+
},
|
|
1437
|
+
});
|
|
1438
|
+
const css = generateThemeCSSFlat(theme);
|
|
1439
|
+
expect(css).toContain('.astryx-selector-indicator-icon {');
|
|
1440
|
+
expect(css).toContain('width: 14px');
|
|
1441
|
+
expect(css).toContain('height: 14px');
|
|
1442
|
+
expect(css).toContain('.astryx-selector-indicator-icon.expanded');
|
|
1443
|
+
expect(css).toContain('color: var(--color-icon-primary)');
|
|
1444
|
+
});
|
|
1445
|
+
});
|