@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
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
inputStatusBorderStyles,
|
|
38
38
|
inputStatusHoverShadowStyles,
|
|
39
39
|
inputWrapperStyles,
|
|
40
|
+
type FieldStatusVariant,
|
|
40
41
|
} from '../Field';
|
|
41
42
|
import {Divider} from '../Divider';
|
|
42
43
|
import {layerAnimations} from '../Layer/layerAnimations.stylex';
|
|
@@ -253,7 +254,7 @@ const styles = stylex.create({
|
|
|
253
254
|
backgroundColor: 'transparent',
|
|
254
255
|
border: 'none',
|
|
255
256
|
cursor: 'pointer',
|
|
256
|
-
textAlign: '
|
|
257
|
+
textAlign: 'start',
|
|
257
258
|
outline: 'none',
|
|
258
259
|
},
|
|
259
260
|
itemContent: {
|
|
@@ -433,6 +434,13 @@ interface SelectorPropsBase<
|
|
|
433
434
|
* If message is provided, displays a message box below the selector.
|
|
434
435
|
*/
|
|
435
436
|
status?: SelectorStatus;
|
|
437
|
+
/**
|
|
438
|
+
* How the status message is placed relative to the input.
|
|
439
|
+
* - 'attached': message overlaps directly below the input (bordered treatment)
|
|
440
|
+
* - 'detached': message floats below as a separate element with spacing
|
|
441
|
+
* @default 'attached'
|
|
442
|
+
*/
|
|
443
|
+
statusVariant?: FieldStatusVariant;
|
|
436
444
|
|
|
437
445
|
/**
|
|
438
446
|
* Width of the field. Numbers are treated as pixels, strings are used as-is
|
|
@@ -537,6 +545,21 @@ function DefaultOption({option}: {option: SelectorOptionData}) {
|
|
|
537
545
|
);
|
|
538
546
|
}
|
|
539
547
|
|
|
548
|
+
// Case-insensitive substring match for a single option. The one predicate used
|
|
549
|
+
// by both the flat filter (count + keyboard nav) and the grouped renderer, so
|
|
550
|
+
// what is shown while searching stays in lockstep with the announced count.
|
|
551
|
+
function optionMatchesQuery(
|
|
552
|
+
option: SelectorOptionData,
|
|
553
|
+
query: string,
|
|
554
|
+
): boolean {
|
|
555
|
+
if (!query) {
|
|
556
|
+
return true;
|
|
557
|
+
}
|
|
558
|
+
return (option.label ?? option.value)
|
|
559
|
+
.toLowerCase()
|
|
560
|
+
.includes(query.toLowerCase());
|
|
561
|
+
}
|
|
562
|
+
|
|
540
563
|
// Case-insensitive substring filter over the selectable options. Shared by the
|
|
541
564
|
// `filteredItems` memo (rendering) and the search-change handler, which needs
|
|
542
565
|
// the count for the *next* query synchronously to announce it exactly once per
|
|
@@ -548,10 +571,7 @@ function filterOptionsByQuery(
|
|
|
548
571
|
if (!query) {
|
|
549
572
|
return items;
|
|
550
573
|
}
|
|
551
|
-
|
|
552
|
-
return items.filter(item =>
|
|
553
|
-
(item.label ?? item.value).toLowerCase().includes(q),
|
|
554
|
-
);
|
|
574
|
+
return items.filter(item => optionMatchesQuery(item, query));
|
|
555
575
|
}
|
|
556
576
|
|
|
557
577
|
/**
|
|
@@ -588,6 +608,7 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
588
608
|
placeholder: placeholderFromProps,
|
|
589
609
|
size: sizeProp,
|
|
590
610
|
status,
|
|
611
|
+
statusVariant = 'attached',
|
|
591
612
|
labelTooltip,
|
|
592
613
|
startIcon,
|
|
593
614
|
htmlName,
|
|
@@ -938,16 +959,22 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
938
959
|
|
|
939
960
|
// Render all options (handling sections/dividers)
|
|
940
961
|
const renderOptions = useCallback(() => {
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
962
|
+
const isSearching = hasSearch && Boolean(searchQuery);
|
|
963
|
+
|
|
964
|
+
// Nothing matched across every group/option: show the empty state.
|
|
965
|
+
if (isSearching && filteredItems.length === 0) {
|
|
966
|
+
// role="presentation" keeps the message out of the listbox's
|
|
967
|
+
// accessibility tree (role="listbox" only permits option/group
|
|
968
|
+
// children); the no-results outcome is announced via the
|
|
969
|
+
// result-count live region instead.
|
|
970
|
+
return [
|
|
971
|
+
<div
|
|
972
|
+
key="empty"
|
|
973
|
+
role="presentation"
|
|
974
|
+
{...stylex.props(styles.emptyState)}>
|
|
975
|
+
No results found
|
|
976
|
+
</div>,
|
|
977
|
+
];
|
|
951
978
|
}
|
|
952
979
|
|
|
953
980
|
let flatIndex = 0;
|
|
@@ -957,13 +984,27 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
957
984
|
const option = options[i];
|
|
958
985
|
|
|
959
986
|
if (isDivider(option)) {
|
|
987
|
+
// While searching, a standalone divider between groups would orphan
|
|
988
|
+
// itself once its neighbors are filtered out, so skip it.
|
|
989
|
+
if (isSearching) {
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
960
992
|
elements.push(<Divider key={`divider-${i}`} xstyle={styles.divider} />);
|
|
961
993
|
} else if (isSection(option)) {
|
|
962
994
|
const sectionItems: ReactNode[] = [];
|
|
963
995
|
for (const opt of option.options) {
|
|
964
|
-
|
|
996
|
+
const normalized = normalizeOption(opt);
|
|
997
|
+
if (isSearching && !optionMatchesQuery(normalized, searchQuery)) {
|
|
998
|
+
continue;
|
|
999
|
+
}
|
|
1000
|
+
sectionItems.push(renderItem(normalized, flatIndex));
|
|
965
1001
|
flatIndex++;
|
|
966
1002
|
}
|
|
1003
|
+
// Hide a group entirely (header + wrapper) when none of its items
|
|
1004
|
+
// match the query, so no header is left standing over nothing.
|
|
1005
|
+
if (sectionItems.length === 0) {
|
|
1006
|
+
continue;
|
|
1007
|
+
}
|
|
967
1008
|
if (option.title) {
|
|
968
1009
|
elements.push(
|
|
969
1010
|
<Divider
|
|
@@ -979,7 +1020,11 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
979
1020
|
</div>,
|
|
980
1021
|
);
|
|
981
1022
|
} else if (isOptionData(option)) {
|
|
982
|
-
|
|
1023
|
+
const normalized = normalizeOption(option);
|
|
1024
|
+
if (isSearching && !optionMatchesQuery(normalized, searchQuery)) {
|
|
1025
|
+
continue;
|
|
1026
|
+
}
|
|
1027
|
+
elements.push(renderItem(normalized, flatIndex));
|
|
983
1028
|
flatIndex++;
|
|
984
1029
|
}
|
|
985
1030
|
}
|
|
@@ -1008,7 +1053,7 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
1008
1053
|
isDisabled && inputWrapperStyles.disabled,
|
|
1009
1054
|
!selectedItem && styles.triggerPlaceholder,
|
|
1010
1055
|
status && inputStatusBorderStyles[status.type],
|
|
1011
|
-
status && inputStatusHoverShadowStyles[status.type],
|
|
1056
|
+
status && !isDisabled && inputStatusHoverShadowStyles[status.type],
|
|
1012
1057
|
inputGroup && groupStyles.inGroup,
|
|
1013
1058
|
xstyle,
|
|
1014
1059
|
),
|
|
@@ -1071,7 +1116,17 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
1071
1116
|
onClick={handleClear}
|
|
1072
1117
|
aria-label={t('@astryx.selector.clearLabel', {label})}
|
|
1073
1118
|
{...stylex.props(styles.clearButton)}>
|
|
1074
|
-
<Icon
|
|
1119
|
+
<Icon
|
|
1120
|
+
icon="close"
|
|
1121
|
+
size="sm"
|
|
1122
|
+
color="secondary"
|
|
1123
|
+
// Stable theme target on the clear glyph itself, so a theme can
|
|
1124
|
+
// restyle just this icon (color, size, hover) via `defineTheme`.
|
|
1125
|
+
// Same-element rules in @layer astryx-theme win over the icon's
|
|
1126
|
+
// own base color/size, which a button-level target could not
|
|
1127
|
+
// reach.
|
|
1128
|
+
{...themeProps('selector-clear-icon')}
|
|
1129
|
+
/>
|
|
1075
1130
|
</button>
|
|
1076
1131
|
)}
|
|
1077
1132
|
<span
|
|
@@ -1087,7 +1142,19 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
1087
1142
|
color={STATUS_ICON_COLOR_MAP[status.type]}
|
|
1088
1143
|
/>
|
|
1089
1144
|
) : (
|
|
1090
|
-
<Icon
|
|
1145
|
+
<Icon
|
|
1146
|
+
icon="chevronDown"
|
|
1147
|
+
size="sm"
|
|
1148
|
+
color="inherit"
|
|
1149
|
+
// Stable theme target on the chevron glyph itself, so a theme can
|
|
1150
|
+
// restyle just this icon (color, size, hover) — and its
|
|
1151
|
+
// open/closed state — via `defineTheme`. Same-element rules in
|
|
1152
|
+
// @layer astryx-theme win over the icon's own base color/size,
|
|
1153
|
+
// which a button-level target could not reach.
|
|
1154
|
+
{...themeProps('selector-indicator-icon', {
|
|
1155
|
+
state: popover.isOpen ? 'expanded' : 'collapsed',
|
|
1156
|
+
})}
|
|
1157
|
+
/>
|
|
1091
1158
|
)}
|
|
1092
1159
|
</span>
|
|
1093
1160
|
</div>
|
|
@@ -1154,6 +1221,7 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
1154
1221
|
}
|
|
1155
1222
|
: undefined
|
|
1156
1223
|
}
|
|
1224
|
+
statusVariant={statusVariant}
|
|
1157
1225
|
labelTooltip={labelTooltip}
|
|
1158
1226
|
width={width}>
|
|
1159
1227
|
{selectorContent}
|
package/src/SideNav/SideNav.tsx
CHANGED
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
import type {BaseProps} from '../BaseProps';
|
|
32
32
|
import * as stylex from '@stylexjs/stylex';
|
|
33
33
|
import type {StyleXStyles} from '@stylexjs/stylex';
|
|
34
|
-
import {
|
|
34
|
+
import {spacingVars} from '../theme/tokens.stylex';
|
|
35
35
|
import {mergeProps, mergeRefs} from '../utils';
|
|
36
36
|
import {
|
|
37
37
|
SideNavCollapseContext,
|
|
@@ -123,9 +123,6 @@ const styles = stylex.create({
|
|
|
123
123
|
paddingInline: spacingVars['--spacing-2'],
|
|
124
124
|
paddingBlockStart: spacingVars['--spacing-1'],
|
|
125
125
|
paddingBlockEnd: spacingVars['--spacing-2'],
|
|
126
|
-
borderBlockStartWidth: borderVars['--border-width'],
|
|
127
|
-
borderBlockStartStyle: 'solid',
|
|
128
|
-
borderBlockStartColor: colorVars['--color-border'],
|
|
129
126
|
},
|
|
130
127
|
footerRow: {
|
|
131
128
|
display: 'flex',
|
|
@@ -145,7 +142,6 @@ const styles = stylex.create({
|
|
|
145
142
|
alignItems: 'center',
|
|
146
143
|
},
|
|
147
144
|
stickyBottomCollapsed: {
|
|
148
|
-
borderBlockStart: 'none',
|
|
149
145
|
paddingBlockStart: 0,
|
|
150
146
|
},
|
|
151
147
|
// Drawer footer — pushed to bottom of the scrollable content area
|
|
@@ -155,9 +151,6 @@ const styles = stylex.create({
|
|
|
155
151
|
marginBlockStart: 'auto',
|
|
156
152
|
gap: spacingVars['--spacing-2'],
|
|
157
153
|
paddingBlockStart: spacingVars['--spacing-2'],
|
|
158
|
-
borderBlockStartWidth: borderVars['--border-width'],
|
|
159
|
-
borderBlockStartStyle: 'solid',
|
|
160
|
-
borderBlockStartColor: colorVars['--color-border'],
|
|
161
154
|
},
|
|
162
155
|
drawerFooterIcons: {
|
|
163
156
|
display: 'flex',
|
|
@@ -23,7 +23,7 @@ import {durationVars, easeVars} from '../theme/tokens.stylex';
|
|
|
23
23
|
import {getIcon} from '../Icon/globalIconRegistry';
|
|
24
24
|
import {Button} from '../Button';
|
|
25
25
|
import type {BaseProps} from '../BaseProps';
|
|
26
|
-
import {composeEventHandlers} from '../utils';
|
|
26
|
+
import {composeEventHandlers, rtlStyles} from '../utils';
|
|
27
27
|
import {
|
|
28
28
|
useSideNavCollapse,
|
|
29
29
|
type SideNavCollapseState,
|
|
@@ -131,12 +131,14 @@ export function SideNavCollapseButton({
|
|
|
131
131
|
onClick={composeEventHandlers(onClickProp, toggle)}
|
|
132
132
|
icon={
|
|
133
133
|
children ?? (
|
|
134
|
-
<span
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
134
|
+
<span {...stylex.props(rtlStyles.mirror)}>
|
|
135
|
+
<span
|
|
136
|
+
{...stylex.props(
|
|
137
|
+
styles.chevron,
|
|
138
|
+
isCollapsed && styles.chevronCollapsed,
|
|
139
|
+
)}>
|
|
140
|
+
{getIcon('chevronLeft')}
|
|
141
|
+
</span>
|
|
140
142
|
</span>
|
|
141
143
|
)
|
|
142
144
|
}
|
|
@@ -356,6 +356,8 @@ export function SideNavItem({
|
|
|
356
356
|
size = 'md',
|
|
357
357
|
'data-testid': testId,
|
|
358
358
|
ref,
|
|
359
|
+
xstyle,
|
|
360
|
+
...rest
|
|
359
361
|
}: SideNavItemProps) {
|
|
360
362
|
const t = useTranslator();
|
|
361
363
|
const {isCollapsed} = useSideNavCollapse();
|
|
@@ -502,7 +504,7 @@ export function SideNavItem({
|
|
|
502
504
|
// Items with children: popover trigger + popover
|
|
503
505
|
if (hasChildren) {
|
|
504
506
|
return (
|
|
505
|
-
<div {...stylex.props(styles.root)}>
|
|
507
|
+
<div {...stylex.props(styles.root, xstyle)}>
|
|
506
508
|
<button
|
|
507
509
|
ref={mergeRefs(ref, popover.triggerRef)}
|
|
508
510
|
type="button"
|
|
@@ -554,7 +556,7 @@ export function SideNavItem({
|
|
|
554
556
|
);
|
|
555
557
|
|
|
556
558
|
return (
|
|
557
|
-
<div ref={itemRef} {...stylex.props(styles.root)}>
|
|
559
|
+
<div ref={itemRef} {...stylex.props(styles.root, xstyle)}>
|
|
558
560
|
{collapsedElement}
|
|
559
561
|
<Tooltip content={label} placement="end" anchorRef={itemRef} />
|
|
560
562
|
</div>
|
|
@@ -670,7 +672,7 @@ export function SideNavItem({
|
|
|
670
672
|
}
|
|
671
673
|
|
|
672
674
|
const item = (
|
|
673
|
-
<div ref={itemRef} {...stylex.props(styles.root)}>
|
|
675
|
+
<div ref={itemRef} {...stylex.props(styles.root, xstyle)}>
|
|
674
676
|
{itemElement}
|
|
675
677
|
{hasChildren && !isCollapsed && (
|
|
676
678
|
<div
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import {describe, it, expect} from 'vitest';
|
|
4
4
|
import {render, screen} from '@testing-library/react';
|
|
5
5
|
import {Skeleton} from './Skeleton';
|
|
6
|
+
import {getForcedColorsRules} from '../__tests__/forcedColors';
|
|
6
7
|
|
|
7
8
|
describe('Skeleton', () => {
|
|
8
9
|
it('renders a placeholder element', () => {
|
|
@@ -23,3 +24,18 @@ describe('Skeleton', () => {
|
|
|
23
24
|
expect(screen.getByTestId('sk')).toHaveAttribute('aria-hidden', 'false');
|
|
24
25
|
});
|
|
25
26
|
});
|
|
27
|
+
|
|
28
|
+
// jsdom cannot emulate forced-colors rendering, so these assert that the
|
|
29
|
+
// compiled output includes the forced-colors rules; visual behavior needs
|
|
30
|
+
// manual verification under Windows High Contrast.
|
|
31
|
+
describe('forced colors (WCAG 1.4.11)', () => {
|
|
32
|
+
it('compiles forced-colors overrides so the placeholder stays visible under Windows High Contrast', () => {
|
|
33
|
+
render(<Skeleton width={200} height={20} data-testid="sk" />);
|
|
34
|
+
const css = getForcedColorsRules();
|
|
35
|
+
// The painted fill is stripped to Canvas (invisible); GrayText is a
|
|
36
|
+
// system color, so it survives forcing.
|
|
37
|
+
expect(css).toContain('background-color: graytext;');
|
|
38
|
+
// The resting 0.25 opacity is lifted so the static placeholder reads.
|
|
39
|
+
expect(css).toContain('opacity: 1;');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -55,8 +55,20 @@ const styles = stylex.create({
|
|
|
55
55
|
backgroundColor: {
|
|
56
56
|
default: colorVars['--color-skeleton'],
|
|
57
57
|
'@media (prefers-contrast: more)': `color-mix(in srgb, ${colorVars['--color-skeleton']}, ${colorVars['--color-text-primary']} 30%)`,
|
|
58
|
+
// Forced colors (Windows High Contrast) strips painted backgrounds,
|
|
59
|
+
// which would make the placeholder invisible. GrayText is a system
|
|
60
|
+
// color, so it survives forcing and keeps the placeholder visible
|
|
61
|
+
// (WCAG 1.4.11). Listed after prefers-contrast so it wins when both
|
|
62
|
+
// media features are active.
|
|
63
|
+
'@media (forced-colors: active)': 'GrayText',
|
|
64
|
+
},
|
|
65
|
+
opacity: {
|
|
66
|
+
default: 0.25,
|
|
67
|
+
// The resting 0.25 opacity would render GrayText nearly invisible on
|
|
68
|
+
// Canvas; full opacity keeps the static placeholder perceivable (the
|
|
69
|
+
// fade animation still pulses when motion is allowed).
|
|
70
|
+
'@media (forced-colors: active)': 1,
|
|
58
71
|
},
|
|
59
|
-
opacity: 0.25,
|
|
60
72
|
},
|
|
61
73
|
animate: {
|
|
62
74
|
animationDirection: 'alternate',
|
|
@@ -141,6 +141,12 @@ export const docs = {
|
|
|
141
141
|
type: 'string',
|
|
142
142
|
description: 'Tooltip text for an info icon displayed next to the label.',
|
|
143
143
|
},
|
|
144
|
+
{
|
|
145
|
+
name: 'width',
|
|
146
|
+
type: 'SizeValue',
|
|
147
|
+
description:
|
|
148
|
+
'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.',
|
|
149
|
+
},
|
|
144
150
|
{
|
|
145
151
|
name: 'xstyle',
|
|
146
152
|
type: 'StyleXStyles',
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* SYNC: When Slider.tsx changes, update tests to match new behavior
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import {useState} from 'react';
|
|
12
13
|
import {describe, it, expect, vi, beforeEach} from 'vitest';
|
|
13
14
|
import {render, screen, act, fireEvent, waitFor} from '@testing-library/react';
|
|
14
15
|
import userEvent from '@testing-library/user-event';
|
|
@@ -50,23 +51,17 @@ beforeEach(() => {
|
|
|
50
51
|
describe('Slider', () => {
|
|
51
52
|
// --- Aria labels ---
|
|
52
53
|
|
|
53
|
-
it('single thumb
|
|
54
|
+
it('single thumb takes its accessible name from the label', () => {
|
|
54
55
|
render(<Slider label="Volume" value={50} />);
|
|
55
56
|
const slider = screen.getByRole('slider');
|
|
56
|
-
expect(slider).
|
|
57
|
+
expect(slider).toHaveAccessibleName('Volume');
|
|
57
58
|
});
|
|
58
59
|
|
|
59
|
-
it('range thumbs have
|
|
60
|
+
it('range thumbs have individual names composing with the group label', () => {
|
|
60
61
|
render(<Slider label="Price range" value={[20, 80] as [number, number]} />);
|
|
61
62
|
const sliders = screen.getAllByRole('slider');
|
|
62
|
-
expect(sliders[0]).
|
|
63
|
-
|
|
64
|
-
'Price range, minimum value',
|
|
65
|
-
);
|
|
66
|
-
expect(sliders[1]).toHaveAttribute(
|
|
67
|
-
'aria-label',
|
|
68
|
-
'Price range, maximum value',
|
|
69
|
-
);
|
|
63
|
+
expect(sliders[0]).toHaveAccessibleName('Minimum value');
|
|
64
|
+
expect(sliders[1]).toHaveAccessibleName('Maximum value');
|
|
70
65
|
});
|
|
71
66
|
|
|
72
67
|
it('sets aria-valuetext with formatValue', () => {
|
|
@@ -94,7 +89,9 @@ describe('Slider', () => {
|
|
|
94
89
|
render(<Slider label="Volume" value={value} min={0} max={100} />);
|
|
95
90
|
const slider = screen.getByRole('slider');
|
|
96
91
|
expect(slider).toHaveAttribute('aria-valuenow', String(expectedValue));
|
|
97
|
-
|
|
92
|
+
// Thumb positions via the logical `inset-inline-start` so it mirrors
|
|
93
|
+
// under RTL (see RTL Phase 4). In LTR this resolves to the left edge.
|
|
94
|
+
expect(slider).toHaveStyle({insetInlineStart: expectedPosition});
|
|
98
95
|
},
|
|
99
96
|
);
|
|
100
97
|
|
|
@@ -110,6 +107,102 @@ describe('Slider', () => {
|
|
|
110
107
|
const sliders = screen.getAllByRole('slider');
|
|
111
108
|
expect(sliders[0]).toHaveAttribute('aria-valuenow', '25');
|
|
112
109
|
expect(sliders[1]).toHaveAttribute('aria-valuenow', '75');
|
|
110
|
+
// Per the APG multi-thumb pattern, each thumb's bounds are constrained by
|
|
111
|
+
// its sibling: the lower thumb can't exceed the upper thumb's value and
|
|
112
|
+
// the upper thumb can't go below the lower thumb's value.
|
|
113
|
+
expect(sliders[0]).toHaveAttribute('aria-valuemin', '0');
|
|
114
|
+
expect(sliders[0]).toHaveAttribute('aria-valuemax', '75');
|
|
115
|
+
expect(sliders[1]).toHaveAttribute('aria-valuemin', '25');
|
|
116
|
+
expect(sliders[1]).toHaveAttribute('aria-valuemax', '100');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('range thumb bounds update after moving a thumb', async () => {
|
|
120
|
+
const user = userEvent.setup();
|
|
121
|
+
function ControlledRange() {
|
|
122
|
+
const [value, setValue] = useState<[number, number]>([25, 75]);
|
|
123
|
+
return (
|
|
124
|
+
<Slider
|
|
125
|
+
label="Range"
|
|
126
|
+
value={value}
|
|
127
|
+
onChange={setValue}
|
|
128
|
+
min={0}
|
|
129
|
+
max={100}
|
|
130
|
+
/>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
render(<ControlledRange />);
|
|
134
|
+
const sliders = screen.getAllByRole('slider');
|
|
135
|
+
act(() => {
|
|
136
|
+
sliders[0].focus();
|
|
137
|
+
});
|
|
138
|
+
await user.keyboard('{ArrowRight}');
|
|
139
|
+
expect(sliders[0]).toHaveAttribute('aria-valuenow', '26');
|
|
140
|
+
// The upper thumb's floor tracks the lower thumb's new value.
|
|
141
|
+
expect(sliders[1]).toHaveAttribute('aria-valuemin', '26');
|
|
142
|
+
expect(sliders[0]).toHaveAttribute('aria-valuemax', '75');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('range thumb bounds include the minStepsBetweenThumbs gap', () => {
|
|
146
|
+
render(
|
|
147
|
+
<Slider
|
|
148
|
+
label="Range"
|
|
149
|
+
value={[20, 80] as [number, number]}
|
|
150
|
+
min={0}
|
|
151
|
+
max={100}
|
|
152
|
+
step={5}
|
|
153
|
+
minStepsBetweenThumbs={2}
|
|
154
|
+
/>,
|
|
155
|
+
);
|
|
156
|
+
const sliders = screen.getAllByRole('slider');
|
|
157
|
+
// minGap = 2 steps * 5 = 10
|
|
158
|
+
expect(sliders[0]).toHaveAttribute('aria-valuemax', '70');
|
|
159
|
+
expect(sliders[1]).toHaveAttribute('aria-valuemin', '30');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// --- Label association ---
|
|
163
|
+
|
|
164
|
+
// A <label htmlFor> must point at an existing form-associated element;
|
|
165
|
+
// div[role="slider"] is not labelable, so the Slider label must render as a
|
|
166
|
+
// group label instead (WCAG 1.3.1).
|
|
167
|
+
const LABELABLE_TAGS = new Set([
|
|
168
|
+
'BUTTON',
|
|
169
|
+
'INPUT',
|
|
170
|
+
'METER',
|
|
171
|
+
'OUTPUT',
|
|
172
|
+
'PROGRESS',
|
|
173
|
+
'SELECT',
|
|
174
|
+
'TEXTAREA',
|
|
175
|
+
]);
|
|
176
|
+
|
|
177
|
+
function expectNoOrphanedLabels(container: HTMLElement) {
|
|
178
|
+
for (const labelEl of container.querySelectorAll('label[for]')) {
|
|
179
|
+
const target = document.getElementById(labelEl.getAttribute('for')!);
|
|
180
|
+
expect(target).not.toBeNull();
|
|
181
|
+
expect(LABELABLE_TAGS.has(target!.tagName)).toBe(true);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
it('single mode renders the label as a group label naming the thumb', () => {
|
|
186
|
+
const {container} = render(<Slider label="Volume" value={50} />);
|
|
187
|
+
expectNoOrphanedLabels(container);
|
|
188
|
+
const slider = screen.getByRole('slider');
|
|
189
|
+
const labelledBy = slider.getAttribute('aria-labelledby');
|
|
190
|
+
expect(labelledBy).toBeTruthy();
|
|
191
|
+
expect(document.getElementById(labelledBy!)).toHaveTextContent('Volume');
|
|
192
|
+
expect(slider).toHaveAccessibleName('Volume');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('range mode labels the slider group via aria-labelledby', () => {
|
|
196
|
+
const {container} = render(
|
|
197
|
+
<Slider label="Price range" value={[20, 80] as [number, number]} />,
|
|
198
|
+
);
|
|
199
|
+
expectNoOrphanedLabels(container);
|
|
200
|
+
const group = screen.getByRole('group', {name: 'Price range'});
|
|
201
|
+
const labelledBy = group.getAttribute('aria-labelledby');
|
|
202
|
+
expect(labelledBy).toBeTruthy();
|
|
203
|
+
expect(document.getElementById(labelledBy!)).toHaveTextContent(
|
|
204
|
+
'Price range',
|
|
205
|
+
);
|
|
113
206
|
});
|
|
114
207
|
|
|
115
208
|
it('sets aria-orientation for vertical', () => {
|
|
@@ -301,6 +394,58 @@ describe('Slider', () => {
|
|
|
301
394
|
expect(handleChangeEnd).toHaveBeenCalledWith(55);
|
|
302
395
|
});
|
|
303
396
|
|
|
397
|
+
// --- Fractional step precision ---
|
|
398
|
+
|
|
399
|
+
it('emits exact decimal values for fractional steps on keyboard', async () => {
|
|
400
|
+
const user = userEvent.setup();
|
|
401
|
+
const handleChange = vi.fn();
|
|
402
|
+
const handleChangeEnd = vi.fn();
|
|
403
|
+
render(
|
|
404
|
+
<Slider
|
|
405
|
+
label="Opacity"
|
|
406
|
+
value={0.2}
|
|
407
|
+
min={0}
|
|
408
|
+
max={1}
|
|
409
|
+
step={0.1}
|
|
410
|
+
onChange={handleChange}
|
|
411
|
+
onChangeEnd={handleChangeEnd}
|
|
412
|
+
/>,
|
|
413
|
+
);
|
|
414
|
+
const slider = screen.getByRole('slider');
|
|
415
|
+
act(() => {
|
|
416
|
+
slider.focus();
|
|
417
|
+
});
|
|
418
|
+
await user.keyboard('{ArrowRight}');
|
|
419
|
+
// 0.2 + 0.1 must not surface binary float error (0.30000000000000004)
|
|
420
|
+
expect(handleChange).toHaveBeenCalledWith(0.3);
|
|
421
|
+
expect(handleChangeEnd).toHaveBeenCalledWith(0.3);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it('emits exact decimal values for fractional steps in range mode', async () => {
|
|
425
|
+
const user = userEvent.setup();
|
|
426
|
+
const handleChange = vi.fn();
|
|
427
|
+
const handleChangeEnd = vi.fn();
|
|
428
|
+
render(
|
|
429
|
+
<Slider
|
|
430
|
+
label="Range"
|
|
431
|
+
value={[0.2, 0.6] as [number, number]}
|
|
432
|
+
min={0}
|
|
433
|
+
max={1}
|
|
434
|
+
step={0.1}
|
|
435
|
+
onChange={handleChange}
|
|
436
|
+
onChangeEnd={handleChangeEnd}
|
|
437
|
+
/>,
|
|
438
|
+
);
|
|
439
|
+
const sliders = screen.getAllByRole('slider');
|
|
440
|
+
act(() => {
|
|
441
|
+
sliders[1].focus();
|
|
442
|
+
});
|
|
443
|
+
await user.keyboard('{ArrowRight}');
|
|
444
|
+
// 0.6 + 0.1 snaps to 7 * 0.1, which is 0.7000000000000001 without rounding
|
|
445
|
+
expect(handleChange).toHaveBeenCalledWith([0.2, 0.7]);
|
|
446
|
+
expect(handleChangeEnd).toHaveBeenCalledWith([0.2, 0.7]);
|
|
447
|
+
});
|
|
448
|
+
|
|
304
449
|
it('fires onChangeEnd on keyboard Home/End with correct value', async () => {
|
|
305
450
|
const user = userEvent.setup();
|
|
306
451
|
const handleChangeEnd = vi.fn();
|
|
@@ -416,6 +561,89 @@ describe('Slider', () => {
|
|
|
416
561
|
expect(document.activeElement).toBe(slider);
|
|
417
562
|
});
|
|
418
563
|
|
|
564
|
+
// --- RTL pointer value mapping (RTL Phase 4) ---
|
|
565
|
+
// Contract: the inline-start edge (value = min) is the RIGHT edge under RTL,
|
|
566
|
+
// so the same physical click maps to the mirrored value relative to LTR.
|
|
567
|
+
// `valueDisplay="none"` keeps the thumb a direct child of the track element
|
|
568
|
+
// (no Tooltip wrapper) so the mocked rect lands on trackRef.
|
|
569
|
+
|
|
570
|
+
it('maps a track click to the LTR value in the default direction', () => {
|
|
571
|
+
const handleChange = vi.fn();
|
|
572
|
+
render(
|
|
573
|
+
<Slider
|
|
574
|
+
label="Volume"
|
|
575
|
+
value={0}
|
|
576
|
+
min={0}
|
|
577
|
+
max={100}
|
|
578
|
+
valueDisplay="none"
|
|
579
|
+
onChange={handleChange}
|
|
580
|
+
/>,
|
|
581
|
+
);
|
|
582
|
+
const track = screen.getByRole('slider').parentElement!;
|
|
583
|
+
track.getBoundingClientRect = () =>
|
|
584
|
+
({
|
|
585
|
+
left: 0,
|
|
586
|
+
top: 0,
|
|
587
|
+
right: 200,
|
|
588
|
+
bottom: 20,
|
|
589
|
+
width: 200,
|
|
590
|
+
height: 20,
|
|
591
|
+
x: 0,
|
|
592
|
+
y: 0,
|
|
593
|
+
toJSON: () => {},
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
// Click at 25% of the track from the left (x=50 of 200) → value 25 in LTR.
|
|
597
|
+
fireEvent.pointerDown(track, {clientX: 50, clientY: 10, pointerId: 1});
|
|
598
|
+
expect(handleChange).toHaveBeenLastCalledWith(25);
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
it('mirrors a track click to the RTL value when the track is rtl', () => {
|
|
602
|
+
const handleChange = vi.fn();
|
|
603
|
+
render(
|
|
604
|
+
<Slider
|
|
605
|
+
label="Volume"
|
|
606
|
+
value={0}
|
|
607
|
+
min={0}
|
|
608
|
+
max={100}
|
|
609
|
+
valueDisplay="none"
|
|
610
|
+
onChange={handleChange}
|
|
611
|
+
/>,
|
|
612
|
+
);
|
|
613
|
+
const track = screen.getByRole('slider').parentElement!;
|
|
614
|
+
track.getBoundingClientRect = () =>
|
|
615
|
+
({
|
|
616
|
+
left: 0,
|
|
617
|
+
top: 0,
|
|
618
|
+
right: 200,
|
|
619
|
+
bottom: 20,
|
|
620
|
+
width: 200,
|
|
621
|
+
height: 20,
|
|
622
|
+
x: 0,
|
|
623
|
+
y: 0,
|
|
624
|
+
toJSON: () => {},
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
// Force the track's computed direction to rtl (isRtlElement reads this).
|
|
628
|
+
const realGetComputedStyle = window.getComputedStyle;
|
|
629
|
+
const gcsSpy = vi
|
|
630
|
+
.spyOn(window, 'getComputedStyle')
|
|
631
|
+
.mockImplementation((el: Element, pseudo?: string | null) => {
|
|
632
|
+
if (el === track) {
|
|
633
|
+
return {direction: 'rtl'} as CSSStyleDeclaration;
|
|
634
|
+
}
|
|
635
|
+
return realGetComputedStyle(el, pseudo ?? undefined);
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
// Same physical click at 25% from the left (x=50). Under RTL the inline
|
|
639
|
+
// start is the right edge, so fraction = (right - x)/width = 150/200 = 0.75
|
|
640
|
+
// → value 75 (the mirror of the LTR value 25).
|
|
641
|
+
fireEvent.pointerDown(track, {clientX: 50, clientY: 10, pointerId: 1});
|
|
642
|
+
expect(handleChange).toHaveBeenLastCalledWith(75);
|
|
643
|
+
|
|
644
|
+
gcsSpy.mockRestore();
|
|
645
|
+
});
|
|
646
|
+
|
|
419
647
|
// --- Mark label click snapping ---
|
|
420
648
|
|
|
421
649
|
it('clicking a mark label snaps to that mark value, not pointer position', () => {
|