@astryxdesign/core 0.1.9-canary.d2d84f8 → 0.1.9-canary.e00a241
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Avatar/Avatar.d.ts +6 -1
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +46 -12
- package/dist/Avatar/AvatarStatusDot.d.ts +6 -4
- package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
- 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/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/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +3 -1
- 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/CheckboxInput/CheckboxInput.js +4 -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 +13 -7
- 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/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +14 -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 +1 -0
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +31 -19
- package/dist/DateRangeInput/DateRangeInput.d.ts +1 -0
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +20 -19
- 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 +4 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +4 -1
- 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/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 +4 -1
- package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
- package/dist/FieldStatus/FieldStatus.js +4 -2
- package/dist/FileInput/FileInput.d.ts +1 -0
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +91 -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/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +15 -9
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +6 -3
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +7 -0
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +65 -40
- package/dist/NumberInput/NumberInput.d.ts +1 -0
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +20 -17
- package/dist/Outline/Outline.js +2 -2
- package/dist/RadioList/RadioList.d.ts +2 -2
- package/dist/RadioList/RadioListItem.js +4 -4
- 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 +2 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +58 -16
- 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/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 +160 -91
- 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/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +30 -4
- 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 +36 -26
- 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 +14 -6
- 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 +1 -0
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +16 -19
- package/dist/TextInput/TextInput.d.ts +1 -0
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +18 -17
- package/dist/TimeInput/TimeInput.d.ts +1 -0
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +15 -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/Token/Token.d.ts +30 -3
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +17 -2
- package/dist/Token/index.d.ts +1 -1
- package/dist/Token/index.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +2 -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.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +19 -10
- package/dist/Typeahead/Typeahead.js +1 -1
- 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 +38 -14
- package/dist/astryx.umd.js +52 -52
- 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/useListFocus.d.ts +39 -1
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +54 -9
- 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 +76 -0
- package/locales/pseudo.json +57 -0
- package/package.json +6 -1
- package/src/Avatar/Avatar.doc.mjs +18 -4
- package/src/Avatar/Avatar.test.tsx +106 -0
- package/src/Avatar/Avatar.tsx +62 -10
- package/src/Avatar/AvatarStatusDot.doc.mjs +4 -4
- package/src/Avatar/AvatarStatusDot.tsx +6 -4
- package/src/AvatarGroup/AvatarGroup.test.tsx +16 -1
- package/src/Breadcrumbs/BreadcrumbItem.tsx +10 -10
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +51 -0
- package/src/Breadcrumbs/index.ts +4 -0
- package/src/Button/Button.doc.mjs +0 -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/ChatDictationButton.tsx +7 -1
- package/src/Chat/ChatMessageBubble.tsx +15 -10
- package/src/Chat/ChatSystemMessage.test.tsx +5 -0
- package/src/Chat/ChatToolCalls.tsx +9 -2
- package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
- package/src/CheckboxInput/CheckboxInput.tsx +4 -4
- package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
- 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.tsx +35 -8
- 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/ContextMenu/ContextMenu.test.tsx +42 -0
- package/src/ContextMenu/ContextMenu.tsx +13 -11
- package/src/ContextMenu/index.ts +5 -0
- package/src/DateInput/DateInput.doc.mjs +15 -5
- package/src/DateInput/DateInput.test.tsx +210 -3
- package/src/DateInput/DateInput.tsx +41 -29
- package/src/DateRangeInput/DateRangeInput.doc.mjs +11 -3
- package/src/DateRangeInput/DateRangeInput.test.tsx +120 -3
- package/src/DateRangeInput/DateRangeInput.tsx +29 -27
- 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 +8 -2
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +8 -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/inputStyles.stylex.ts +2 -0
- package/src/FieldStatus/FieldStatus.tsx +10 -4
- package/src/FileInput/FileInput.doc.mjs +13 -7
- package/src/FileInput/FileInput.test.tsx +84 -16
- package/src/FileInput/FileInput.tsx +96 -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/Lightbox/Lightbox.tsx +11 -3
- package/src/List/List.test.tsx +17 -29
- package/src/List/List.tsx +6 -1
- package/src/Markdown/Markdown.test.tsx +21 -0
- package/src/Markdown/Markdown.tsx +4 -0
- package/src/MultiSelector/MultiSelector.doc.mjs +11 -0
- package/src/MultiSelector/MultiSelector.test.tsx +306 -3
- package/src/MultiSelector/MultiSelector.tsx +88 -57
- package/src/NumberInput/NumberInput.doc.mjs +11 -5
- package/src/NumberInput/NumberInput.test.tsx +48 -0
- package/src/NumberInput/NumberInput.tsx +25 -26
- package/src/Outline/Outline.test.tsx +12 -12
- package/src/Outline/Outline.tsx +2 -2
- package/src/RadioList/RadioList.doc.mjs +6 -0
- package/src/RadioList/RadioList.tsx +2 -2
- package/src/RadioList/RadioListItem.tsx +4 -4
- package/src/Resizable/ResizeHandle.test.tsx +94 -0
- package/src/Resizable/ResizeHandle.tsx +70 -20
- package/src/SegmentedControl/SegmentedControlItem.tsx +2 -0
- package/src/Selector/Selector.doc.mjs +8 -0
- package/src/Selector/Selector.test.tsx +328 -3
- package/src/Selector/Selector.tsx +70 -19
- package/src/SideNav/SideNav.tsx +1 -8
- package/src/SideNav/SideNavCollapseButton.tsx +9 -7
- package/src/SideNav/SideNavItem.tsx +5 -3
- 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 +22 -0
- package/src/Switch/Switch.tsx +90 -33
- 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/Table/BaseTable.tsx +34 -2
- package/src/Table/Table.doc.mjs +11 -0
- package/src/Table/Table.test.tsx +85 -0
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +9 -6
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +24 -17
- 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 +37 -8
- 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 +11 -5
- package/src/TextArea/TextArea.tsx +17 -26
- package/src/TextInput/TextInput.doc.mjs +11 -5
- package/src/TextInput/TextInput.test.tsx +130 -3
- package/src/TextInput/TextInput.tsx +18 -25
- package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
- package/src/TimeInput/TimeInput.doc.mjs +11 -5
- package/src/TimeInput/TimeInput.tsx +14 -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/Token/Token.test.tsx +21 -15
- package/src/Token/Token.tsx +31 -14
- package/src/Token/index.ts +1 -1
- package/src/Tokenizer/Tokenizer.doc.mjs +8 -1
- package/src/Tokenizer/Tokenizer.tsx +4 -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 +29 -14
- package/src/Typeahead/Typeahead.doc.mjs +6 -0
- package/src/Typeahead/Typeahead.test.tsx +27 -0
- package/src/Typeahead/Typeahead.tsx +1 -1
- package/src/Typeahead/TypeaheadItem.tsx +2 -1
- 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/useListFocus.doc.mjs +25 -3
- package/src/hooks/useListFocus.test.tsx +153 -1
- package/src/hooks/useListFocus.ts +102 -9
- 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
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
type KeyboardEvent,
|
|
28
28
|
} from 'react';
|
|
29
29
|
import * as stylex from '@stylexjs/stylex';
|
|
30
|
-
import type {IconName} from '../Icon';
|
|
31
30
|
import {
|
|
32
31
|
colorVars,
|
|
33
32
|
sizeVars,
|
|
@@ -40,7 +39,6 @@ import {
|
|
|
40
39
|
import {
|
|
41
40
|
Field,
|
|
42
41
|
type InputStatus,
|
|
43
|
-
type InputStatusType,
|
|
44
42
|
inputWrapperStyles,
|
|
45
43
|
inputStatusBorderStyles,
|
|
46
44
|
inputStatusHoverShadowStyles,
|
|
@@ -54,6 +52,7 @@ import {useCalendarConstraints} from '../Calendar/hooks';
|
|
|
54
52
|
import {usePopover} from '../Popover';
|
|
55
53
|
import {useTooltip} from '../Tooltip';
|
|
56
54
|
import {useInputContainer} from '../hooks/useInputContainer';
|
|
55
|
+
import {useInputStatusIcon} from '../hooks/useInputStatusIcon';
|
|
57
56
|
import {
|
|
58
57
|
type ISOTimeString,
|
|
59
58
|
parseDateInput,
|
|
@@ -470,25 +469,21 @@ export function DateTimeInput({
|
|
|
470
469
|
isEnabled: showsDisabledMessage,
|
|
471
470
|
});
|
|
472
471
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
> = {
|
|
483
|
-
warning: 'warning',
|
|
484
|
-
error: 'error',
|
|
485
|
-
success: 'success',
|
|
486
|
-
};
|
|
472
|
+
// DateTimeInput fixes its status presentation to the detached message box,
|
|
473
|
+
// so the shared helper suppresses the on-field icon (the message box carries
|
|
474
|
+
// its own leading glyph). Routed through the helper for consistency with the
|
|
475
|
+
// rest of the bordered input family.
|
|
476
|
+
const {statusIcon, describedBy: statusTooltipDescribedBy} =
|
|
477
|
+
useInputStatusIcon({
|
|
478
|
+
status,
|
|
479
|
+
statusVariant: 'detached',
|
|
480
|
+
});
|
|
487
481
|
|
|
488
482
|
const ariaDescribedBy =
|
|
489
483
|
[
|
|
490
484
|
description ? descriptionID : null,
|
|
491
485
|
status?.message ? statusMessageID : null,
|
|
486
|
+
statusTooltipDescribedBy,
|
|
492
487
|
showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
|
|
493
488
|
]
|
|
494
489
|
.filter(Boolean)
|
|
@@ -890,14 +885,22 @@ export function DateTimeInput({
|
|
|
890
885
|
{/* Date input */}
|
|
891
886
|
<div
|
|
892
887
|
ref={popover.triggerRef}
|
|
893
|
-
{...
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
888
|
+
{...mergeProps(
|
|
889
|
+
themeProps('date-time-input-date-segment', {
|
|
890
|
+
size,
|
|
891
|
+
status: status?.type ?? null,
|
|
892
|
+
}),
|
|
893
|
+
stylex.props(
|
|
894
|
+
inputWrapperStyles.base,
|
|
895
|
+
sizeStyles[size],
|
|
896
|
+
styles.dateWrapper,
|
|
897
|
+
isEffectivelyDisabled && inputWrapperStyles.disabled,
|
|
898
|
+
status && inputStatusBorderStyles[status.type],
|
|
899
|
+
status &&
|
|
900
|
+
!isEffectivelyDisabled &&
|
|
901
|
+
inputStatusHoverShadowStyles[status.type],
|
|
902
|
+
status && inputStatusFocusWithinStyles[status.type],
|
|
903
|
+
),
|
|
901
904
|
)}>
|
|
902
905
|
<button
|
|
903
906
|
type="button"
|
|
@@ -968,13 +971,7 @@ export function DateTimeInput({
|
|
|
968
971
|
</button>
|
|
969
972
|
)}
|
|
970
973
|
{isBusy && <Spinner size="sm" />}
|
|
971
|
-
{
|
|
972
|
-
<Icon
|
|
973
|
-
icon={statusIconMap[status.type]}
|
|
974
|
-
size="md"
|
|
975
|
-
color={statusIconColorMap[status.type]}
|
|
976
|
-
/>
|
|
977
|
-
)}
|
|
974
|
+
{statusIcon}
|
|
978
975
|
</div>
|
|
979
976
|
|
|
980
977
|
{/* Time input */}
|
|
@@ -982,14 +979,22 @@ export function DateTimeInput({
|
|
|
982
979
|
ref={timeContainerRef}
|
|
983
980
|
onClick={handleTimeWrapperClick}
|
|
984
981
|
onMouseUp={handleTimeWrapperMouseUp}
|
|
985
|
-
{...
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
982
|
+
{...mergeProps(
|
|
983
|
+
themeProps('date-time-input-time-segment', {
|
|
984
|
+
size,
|
|
985
|
+
status: status?.type ?? null,
|
|
986
|
+
}),
|
|
987
|
+
stylex.props(
|
|
988
|
+
inputWrapperStyles.base,
|
|
989
|
+
sizeStyles[size],
|
|
990
|
+
styles.timeWrapper,
|
|
991
|
+
isEffectivelyDisabled && inputWrapperStyles.disabled,
|
|
992
|
+
status && inputStatusBorderStyles[status.type],
|
|
993
|
+
status &&
|
|
994
|
+
!isEffectivelyDisabled &&
|
|
995
|
+
inputStatusHoverShadowStyles[status.type],
|
|
996
|
+
status && inputStatusFocusWithinStyles[status.type],
|
|
997
|
+
),
|
|
993
998
|
)}>
|
|
994
999
|
<div {...stylex.props(styles.icon)}>
|
|
995
1000
|
<Icon icon="clock" size="sm" color="secondary" />
|
|
@@ -89,25 +89,49 @@ describe('Divider', () => {
|
|
|
89
89
|
|
|
90
90
|
it('renders vertical divider with label', () => {
|
|
91
91
|
render(
|
|
92
|
-
<Divider
|
|
93
|
-
orientation="vertical"
|
|
94
|
-
label="Vertical"
|
|
95
|
-
data-testid="divider"
|
|
96
|
-
/>,
|
|
92
|
+
<Divider orientation="vertical" label="Vertical" data-testid="divider" />,
|
|
97
93
|
);
|
|
98
94
|
const divider = screen.getByTestId('divider');
|
|
99
95
|
expect(divider).toHaveAttribute('aria-orientation', 'vertical');
|
|
100
96
|
expect(screen.getByText('Vertical')).toBeInTheDocument();
|
|
101
97
|
});
|
|
102
98
|
|
|
103
|
-
it('
|
|
99
|
+
it('exposes the label as the accessible name of the separator', () => {
|
|
100
|
+
render(<Divider label="Section" data-testid="divider" />);
|
|
101
|
+
const divider = screen.getByTestId('divider');
|
|
102
|
+
expect(divider).toHaveAttribute('aria-labelledby');
|
|
103
|
+
expect(divider).toHaveAccessibleName('Section');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('names the separator from a ReactNode label via aria-labelledby', () => {
|
|
107
|
+
render(<Divider label={<span>Custom</span>} data-testid="divider" />);
|
|
108
|
+
expect(screen.getByTestId('divider')).toHaveAccessibleName('Custom');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('does not set aria-labelledby without a label', () => {
|
|
112
|
+
render(<Divider data-testid="divider" />);
|
|
113
|
+
expect(screen.getByTestId('divider')).not.toHaveAttribute(
|
|
114
|
+
'aria-labelledby',
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('prefers an explicit aria-label over the rendered label', () => {
|
|
104
119
|
render(
|
|
105
120
|
<Divider
|
|
106
|
-
|
|
107
|
-
|
|
121
|
+
label="Section"
|
|
122
|
+
aria-label="Custom name"
|
|
108
123
|
data-testid="divider"
|
|
109
124
|
/>,
|
|
110
125
|
);
|
|
126
|
+
const divider = screen.getByTestId('divider');
|
|
127
|
+
expect(divider).toHaveAccessibleName('Custom name');
|
|
128
|
+
expect(divider).not.toHaveAttribute('aria-labelledby');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('renders astryx-* class names for theme targeting', () => {
|
|
132
|
+
render(
|
|
133
|
+
<Divider variant="strong" orientation="vertical" data-testid="divider" />,
|
|
134
|
+
);
|
|
111
135
|
const root = screen.getByTestId('divider');
|
|
112
136
|
expect(root.className).toContain('astryx-divider');
|
|
113
137
|
expect(root.className).toContain('strong');
|
package/src/Divider/Divider.tsx
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* - /packages/cli/templates/blocks/components/Divider/ (showcase blocks)
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import type
|
|
18
|
+
import {useId, type ReactNode} from 'react';
|
|
19
19
|
import type {BaseProps} from '../BaseProps';
|
|
20
20
|
import * as stylex from '@stylexjs/stylex';
|
|
21
21
|
|
|
@@ -165,9 +165,19 @@ export function Divider({
|
|
|
165
165
|
className,
|
|
166
166
|
style,
|
|
167
167
|
ref,
|
|
168
|
+
'aria-label': ariaLabel,
|
|
169
|
+
'aria-labelledby': ariaLabelledBy,
|
|
168
170
|
...props
|
|
169
171
|
}: DividerProps) {
|
|
170
172
|
const isHorizontal = orientation === 'horizontal';
|
|
173
|
+
const labelId = useId();
|
|
174
|
+
|
|
175
|
+
// A separator does not derive its accessible name from its content, so the
|
|
176
|
+
// rendered label must be referenced explicitly via aria-labelledby to be
|
|
177
|
+
// exposed as the separator's name (WCAG 1.3.1). An explicit aria-label or
|
|
178
|
+
// aria-labelledby from the consumer takes precedence.
|
|
179
|
+
const resolvedLabelledBy =
|
|
180
|
+
ariaLabelledBy ?? (label && ariaLabel == null ? labelId : undefined);
|
|
171
181
|
|
|
172
182
|
return (
|
|
173
183
|
<div
|
|
@@ -175,6 +185,8 @@ export function Divider({
|
|
|
175
185
|
{...props}
|
|
176
186
|
role="separator"
|
|
177
187
|
aria-orientation={orientation}
|
|
188
|
+
aria-label={ariaLabel}
|
|
189
|
+
aria-labelledby={resolvedLabelledBy}
|
|
178
190
|
{...mergeProps(
|
|
179
191
|
themeProps('divider', {variant, orientation}),
|
|
180
192
|
stylex.props(
|
|
@@ -196,6 +208,7 @@ export function Divider({
|
|
|
196
208
|
/>
|
|
197
209
|
{label && (
|
|
198
210
|
<div
|
|
211
|
+
id={labelId}
|
|
199
212
|
{...stylex.props(
|
|
200
213
|
labelStyles.label,
|
|
201
214
|
!isHorizontal && labelStyles.verticalLabel,
|
|
@@ -781,4 +781,64 @@ describe('DropdownMenu keyboard access for menuitemradio/menuitemcheckbox (#3829
|
|
|
781
781
|
screen.getByRole('menuitemradio', {name: 'Oldest', hidden: true}),
|
|
782
782
|
).toHaveFocus();
|
|
783
783
|
});
|
|
784
|
+
|
|
785
|
+
it('moves focus to the item the mouse hovers, keeping a single highlight', async () => {
|
|
786
|
+
const user = userEvent.setup();
|
|
787
|
+
render(
|
|
788
|
+
<DropdownMenu button={{label: 'Actions'}}>
|
|
789
|
+
<DropdownMenuItem label="Edit" onClick={() => {}} />
|
|
790
|
+
<DropdownMenuItem label="Duplicate" onClick={() => {}} />
|
|
791
|
+
<DropdownMenuItem label="Delete" onClick={() => {}} />
|
|
792
|
+
</DropdownMenu>,
|
|
793
|
+
);
|
|
794
|
+
|
|
795
|
+
await user.click(screen.getByRole('button', {name: /Actions/}));
|
|
796
|
+
// Keyboard focus starts on the first item.
|
|
797
|
+
const edit = screen.getByRole('menuitem', {name: 'Edit', hidden: true});
|
|
798
|
+
const del = screen.getByRole('menuitem', {name: 'Delete', hidden: true});
|
|
799
|
+
edit.focus();
|
|
800
|
+
expect(edit).toHaveFocus();
|
|
801
|
+
|
|
802
|
+
// A mouse hover over another item moves focus to it, so the single
|
|
803
|
+
// focus-driven highlight follows the pointer instead of leaving two.
|
|
804
|
+
fireEvent.pointerMove(del, {pointerType: 'mouse'});
|
|
805
|
+
expect(del).toHaveFocus();
|
|
806
|
+
expect(edit).not.toHaveFocus();
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
it('does not move focus on hover for a disabled item', async () => {
|
|
810
|
+
const user = userEvent.setup();
|
|
811
|
+
render(
|
|
812
|
+
<DropdownMenu button={{label: 'Actions'}}>
|
|
813
|
+
<DropdownMenuItem label="Edit" onClick={() => {}} />
|
|
814
|
+
<DropdownMenuItem label="Delete" isDisabled onClick={() => {}} />
|
|
815
|
+
</DropdownMenu>,
|
|
816
|
+
);
|
|
817
|
+
|
|
818
|
+
await user.click(screen.getByRole('button', {name: /Actions/}));
|
|
819
|
+
const edit = screen.getByRole('menuitem', {name: 'Edit', hidden: true});
|
|
820
|
+
const del = screen.getByRole('menuitem', {name: 'Delete', hidden: true});
|
|
821
|
+
edit.focus();
|
|
822
|
+
|
|
823
|
+
fireEvent.pointerMove(del, {pointerType: 'mouse'});
|
|
824
|
+
expect(edit).toHaveFocus();
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
it('does not move focus for a non-mouse (touch) pointer', async () => {
|
|
828
|
+
const user = userEvent.setup();
|
|
829
|
+
render(
|
|
830
|
+
<DropdownMenu button={{label: 'Actions'}}>
|
|
831
|
+
<DropdownMenuItem label="Edit" onClick={() => {}} />
|
|
832
|
+
<DropdownMenuItem label="Delete" onClick={() => {}} />
|
|
833
|
+
</DropdownMenu>,
|
|
834
|
+
);
|
|
835
|
+
|
|
836
|
+
await user.click(screen.getByRole('button', {name: /Actions/}));
|
|
837
|
+
const edit = screen.getByRole('menuitem', {name: 'Edit', hidden: true});
|
|
838
|
+
const del = screen.getByRole('menuitem', {name: 'Delete', hidden: true});
|
|
839
|
+
edit.focus();
|
|
840
|
+
|
|
841
|
+
fireEvent.pointerMove(del, {pointerType: 'touch'});
|
|
842
|
+
expect(edit).toHaveFocus();
|
|
843
|
+
});
|
|
784
844
|
});
|
|
@@ -38,7 +38,11 @@ import {Icon} from '../Icon';
|
|
|
38
38
|
import type {IconType} from '../Icon';
|
|
39
39
|
|
|
40
40
|
import {renderDropdownItems} from './renderDropdownItems';
|
|
41
|
-
import {
|
|
41
|
+
import {
|
|
42
|
+
MENU_ITEM_ROLES,
|
|
43
|
+
MENU_ITEM_SELECTOR,
|
|
44
|
+
MENU_BOUNDARY_SELECTOR,
|
|
45
|
+
} from './menuItemRoles';
|
|
42
46
|
import {
|
|
43
47
|
DropdownMenuContext,
|
|
44
48
|
type DropdownMenuContextValue,
|
|
@@ -100,6 +104,12 @@ export interface DropdownMenuItemData {
|
|
|
100
104
|
onClick?: () => void;
|
|
101
105
|
isDisabled?: boolean;
|
|
102
106
|
icon?: ReactNode | IconType;
|
|
107
|
+
/**
|
|
108
|
+
* Nested submenu entries. When present, this row becomes a submenu (a
|
|
109
|
+
* flyout revealing `items`) instead of a leaf action — no separate item
|
|
110
|
+
* "type" is needed. Data-mode parity for the compound DropdownMenuSubMenu API.
|
|
111
|
+
*/
|
|
112
|
+
items?: DropdownMenuOption[];
|
|
103
113
|
}
|
|
104
114
|
|
|
105
115
|
export interface DropdownMenuDivider {
|
|
@@ -200,6 +210,14 @@ export function DropdownMenu({
|
|
|
200
210
|
const items = ('items' in props ? props.items : undefined) ?? [];
|
|
201
211
|
const children = props.children;
|
|
202
212
|
|
|
213
|
+
// Extract BaseProps pass-throughs (aria-*, id, event handlers) from the
|
|
214
|
+
// discriminated-union rest bag so they can be forwarded to the menu element.
|
|
215
|
+
const {
|
|
216
|
+
items: _items,
|
|
217
|
+
children: _children,
|
|
218
|
+
...rest
|
|
219
|
+
} = props as Record<string, unknown>;
|
|
220
|
+
|
|
203
221
|
const menuId = useId();
|
|
204
222
|
const menuSize = button.size ?? 'md';
|
|
205
223
|
const buttonRef = useRef<HTMLButtonElement>(null);
|
|
@@ -265,23 +283,18 @@ export function DropdownMenu({
|
|
|
265
283
|
handleKeyDown: listNavKeyDown,
|
|
266
284
|
focusFirst,
|
|
267
285
|
focusItem,
|
|
286
|
+
ownsEvent,
|
|
287
|
+
getItems: getMenuItems,
|
|
268
288
|
} = useListFocus<HTMLDivElement>({
|
|
269
289
|
itemSelector: MENU_ITEM_SELECTOR,
|
|
290
|
+
boundarySelector: MENU_BOUNDARY_SELECTOR,
|
|
270
291
|
wrap: false,
|
|
271
292
|
onEscape: closeMenu,
|
|
272
293
|
});
|
|
273
294
|
|
|
274
295
|
// First-character typeahead over the (enabled) menu items — jump to the next
|
|
275
|
-
// item whose label starts with the typed text (menus-11).
|
|
276
|
-
|
|
277
|
-
(): HTMLElement[] =>
|
|
278
|
-
listRef.current
|
|
279
|
-
? Array.from(
|
|
280
|
-
listRef.current.querySelectorAll<HTMLElement>(MENU_ITEM_SELECTOR),
|
|
281
|
-
)
|
|
282
|
-
: [],
|
|
283
|
-
[listRef],
|
|
284
|
-
);
|
|
296
|
+
// item whose label starts with the typed text (menus-11). Reuses the hook's
|
|
297
|
+
// scoped item collection so an inline submenu flyout's items aren't swept in.
|
|
285
298
|
const typeahead = useTypeahead({
|
|
286
299
|
getItemLabels: () => getMenuItems().map(el => el.textContent),
|
|
287
300
|
onMatch: focusItem,
|
|
@@ -307,6 +320,11 @@ export function DropdownMenu({
|
|
|
307
320
|
// Extend useListFocus with Enter/Space activation + typeahead
|
|
308
321
|
const listKeyDown = useCallback(
|
|
309
322
|
(e: React.KeyboardEvent) => {
|
|
323
|
+
// A submenu flyout renders inline inside this menu; its key events bubble
|
|
324
|
+
// up here. Let that level own them — only handle events from this level.
|
|
325
|
+
if (!ownsEvent(e)) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
310
328
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
311
329
|
e.preventDefault();
|
|
312
330
|
const focused = document.activeElement as HTMLElement | null;
|
|
@@ -334,7 +352,7 @@ export function DropdownMenu({
|
|
|
334
352
|
}
|
|
335
353
|
listNavKeyDown(e);
|
|
336
354
|
},
|
|
337
|
-
[listNavKeyDown, closeMenu, typeahead],
|
|
355
|
+
[listNavKeyDown, closeMenu, typeahead, ownsEvent],
|
|
338
356
|
);
|
|
339
357
|
|
|
340
358
|
const openAndFocus = useCallback(() => {
|
|
@@ -435,6 +453,7 @@ export function DropdownMenu({
|
|
|
435
453
|
|
|
436
454
|
{popover.render(
|
|
437
455
|
<div
|
|
456
|
+
{...rest}
|
|
438
457
|
ref={listRef}
|
|
439
458
|
id={menuId}
|
|
440
459
|
role="menu"
|
|
@@ -23,11 +23,12 @@
|
|
|
23
23
|
* checkmark uses the `check` icon from the active theme's icon registry.
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import {useCallback, type ReactNode} from 'react';
|
|
26
|
+
import {useCallback, type PointerEvent, type ReactNode} from 'react';
|
|
27
27
|
import * as stylex from '@stylexjs/stylex';
|
|
28
28
|
import {Icon, renderIconSlot, type IconType} from '../Icon';
|
|
29
29
|
import {Item} from '../Item';
|
|
30
30
|
import {useDropdownMenuContext} from './DropdownMenuContext';
|
|
31
|
+
import {focusMenuItemOnHover} from './menuItemHover';
|
|
31
32
|
import {
|
|
32
33
|
colorVars,
|
|
33
34
|
spacingVars,
|
|
@@ -47,7 +48,6 @@ const styles = stylex.create({
|
|
|
47
48
|
backgroundColor: {
|
|
48
49
|
default: 'transparent',
|
|
49
50
|
':focus': colorVars['--color-overlay-hover'],
|
|
50
|
-
':hover': colorVars['--color-overlay-hover'],
|
|
51
51
|
},
|
|
52
52
|
cursor: 'pointer',
|
|
53
53
|
outline: 'none',
|
|
@@ -190,12 +190,18 @@ export function DropdownMenuCheckboxItem({
|
|
|
190
190
|
}
|
|
191
191
|
}, [isDisabled, onChange, value, hasCloseOnSelect, ctx]);
|
|
192
192
|
|
|
193
|
+
const handlePointerMove = useCallback(
|
|
194
|
+
(e: PointerEvent<HTMLElement>) => focusMenuItemOnHover(e, isDisabled),
|
|
195
|
+
[isDisabled],
|
|
196
|
+
);
|
|
197
|
+
|
|
193
198
|
return (
|
|
194
199
|
<Item
|
|
195
200
|
{...rest}
|
|
196
201
|
role="menuitemcheckbox"
|
|
197
202
|
aria-checked={value}
|
|
198
203
|
tabIndex={isDisabled ? undefined : -1}
|
|
204
|
+
onPointerMove={handlePointerMove}
|
|
199
205
|
marker={
|
|
200
206
|
<span
|
|
201
207
|
aria-hidden="true"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* - /packages/cli/templates/blocks/components/DropdownMenu/ (showcase blocks)
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import {useCallback, type ReactNode} from 'react';
|
|
26
|
+
import {useCallback, type PointerEvent, type ReactNode} from 'react';
|
|
27
27
|
import * as stylex from '@stylexjs/stylex';
|
|
28
28
|
import {renderIconSlot, type IconType} from '../Icon';
|
|
29
29
|
import {Item} from '../Item';
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
import {mergeProps} from '../utils';
|
|
37
37
|
import type {BaseProps} from '../BaseProps';
|
|
38
38
|
import {useDropdownMenuContext} from './DropdownMenuContext';
|
|
39
|
+
import {focusMenuItemOnHover} from './menuItemHover';
|
|
39
40
|
import {themeProps} from '../utils/themeProps';
|
|
40
41
|
|
|
41
42
|
const menuItemStyles = stylex.create({
|
|
@@ -51,7 +52,6 @@ const menuItemStyles = stylex.create({
|
|
|
51
52
|
backgroundColor: {
|
|
52
53
|
default: 'transparent',
|
|
53
54
|
':focus': colorVars['--color-overlay-hover'],
|
|
54
|
-
':hover': colorVars['--color-overlay-hover'],
|
|
55
55
|
},
|
|
56
56
|
border: 'none',
|
|
57
57
|
cursor: 'pointer',
|
|
@@ -129,10 +129,16 @@ export function DropdownMenuItem({
|
|
|
129
129
|
ctx?.closeMenu();
|
|
130
130
|
}, [isDisabled, onClick, ctx]);
|
|
131
131
|
|
|
132
|
+
const handlePointerMove = useCallback(
|
|
133
|
+
(e: PointerEvent<HTMLElement>) => focusMenuItemOnHover(e, isDisabled),
|
|
134
|
+
[isDisabled],
|
|
135
|
+
);
|
|
136
|
+
|
|
132
137
|
return (
|
|
133
138
|
<Item
|
|
134
139
|
role="menuitem"
|
|
135
140
|
tabIndex={isDisabled ? undefined : -1}
|
|
141
|
+
onPointerMove={handlePointerMove}
|
|
136
142
|
startContent={
|
|
137
143
|
icon
|
|
138
144
|
? renderIconSlot(icon, {size: 'sm', color: 'secondary'})
|
|
@@ -21,11 +21,12 @@
|
|
|
21
21
|
* has no registry glyph).
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import {useCallback, type ReactNode} from 'react';
|
|
24
|
+
import {useCallback, type PointerEvent, type ReactNode} from 'react';
|
|
25
25
|
import * as stylex from '@stylexjs/stylex';
|
|
26
26
|
import {renderIconSlot, type IconType} from '../Icon';
|
|
27
27
|
import {Item} from '../Item';
|
|
28
28
|
import {useDropdownMenuContext} from './DropdownMenuContext';
|
|
29
|
+
import {focusMenuItemOnHover} from './menuItemHover';
|
|
29
30
|
import {
|
|
30
31
|
colorVars,
|
|
31
32
|
spacingVars,
|
|
@@ -45,7 +46,6 @@ const styles = stylex.create({
|
|
|
45
46
|
backgroundColor: {
|
|
46
47
|
default: 'transparent',
|
|
47
48
|
':focus': colorVars['--color-overlay-hover'],
|
|
48
|
-
':hover': colorVars['--color-overlay-hover'],
|
|
49
49
|
},
|
|
50
50
|
cursor: 'pointer',
|
|
51
51
|
outline: 'none',
|
|
@@ -184,12 +184,18 @@ export function DropdownMenuRadioItem({
|
|
|
184
184
|
}
|
|
185
185
|
}, [isDisabled, groupCtx, value, menuCtx]);
|
|
186
186
|
|
|
187
|
+
const handlePointerMove = useCallback(
|
|
188
|
+
(e: PointerEvent<HTMLElement>) => focusMenuItemOnHover(e, isDisabled),
|
|
189
|
+
[isDisabled],
|
|
190
|
+
);
|
|
191
|
+
|
|
187
192
|
return (
|
|
188
193
|
<Item
|
|
189
194
|
{...rest}
|
|
190
195
|
role="menuitemradio"
|
|
191
196
|
aria-checked={isChecked}
|
|
192
197
|
tabIndex={isDisabled ? undefined : -1}
|
|
198
|
+
onPointerMove={handlePointerMove}
|
|
193
199
|
marker={
|
|
194
200
|
<span
|
|
195
201
|
aria-hidden="true"
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** @type {import('../docs-types').ComponentDoc} */
|
|
4
|
+
|
|
5
|
+
export const docs = {
|
|
6
|
+
name: 'DropdownMenuSubMenu',
|
|
7
|
+
subComponentOf: 'DropdownMenu',
|
|
8
|
+
displayName: 'Dropdown Menu Submenu',
|
|
9
|
+
isHiddenFromOverview: true,
|
|
10
|
+
description:
|
|
11
|
+
'A single menu row that reveals a nested flyout of its own items. The row adopts DropdownMenuItem semantics (label / icon / description / isDisabled); its children become the flyout content. Opens inline-end with viewport auto-flip; Right/Enter/Space opens and focuses the first item, Left/Escape closes and returns focus to the trigger (Right/Left swap in RTL). For data-driven menus, give a menu item a nested `items` array instead of using this component directly.',
|
|
12
|
+
playground: {
|
|
13
|
+
defaults: {label: 'Move to'},
|
|
14
|
+
},
|
|
15
|
+
props: [
|
|
16
|
+
{
|
|
17
|
+
name: 'label',
|
|
18
|
+
type: 'ReactNode',
|
|
19
|
+
description: 'Primary label text for the trigger row.',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'icon',
|
|
23
|
+
type: 'IconType',
|
|
24
|
+
description:
|
|
25
|
+
'Icon to display before the label. See `astryx docs icons` for valid semantic names.',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'description',
|
|
29
|
+
type: 'ReactNode',
|
|
30
|
+
description: 'Secondary description text displayed below the label.',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'children',
|
|
34
|
+
type: 'ReactNode',
|
|
35
|
+
description:
|
|
36
|
+
'The flyout menu items: the same components used at the top level (DropdownMenuItem, nested DropdownMenuSubMenu, selectable items).',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'isDisabled',
|
|
40
|
+
type: 'boolean',
|
|
41
|
+
default: 'false',
|
|
42
|
+
description:
|
|
43
|
+
'A disabled submenu renders its trigger row but never opens the flyout.',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'hasSpinner',
|
|
47
|
+
type: 'boolean',
|
|
48
|
+
default: 'false',
|
|
49
|
+
description:
|
|
50
|
+
'Show a spinner in place of the caret, e.g. while a lazy submenu\'s children are loading.',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'menuWidth',
|
|
54
|
+
type: 'number | string',
|
|
55
|
+
description: 'Fixed flyout width. Defaults to sizing to its content (min 160px).',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'onOpenChange',
|
|
59
|
+
type: '(isOpen: boolean) => void',
|
|
60
|
+
description: 'Called when the flyout opens or closes.',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'xstyle',
|
|
64
|
+
type: 'StyleXStyles',
|
|
65
|
+
description:
|
|
66
|
+
'StyleX styles for the trigger row. Must be a stylex.create() value: not an inline style object like style={{}}.',
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const docsDense = {
|
|
72
|
+
name: 'DropdownMenuSubMenu',
|
|
73
|
+
isHiddenFromOverview: true,
|
|
74
|
+
displayName: 'Dropdown Menu Submenu',
|
|
75
|
+
description:
|
|
76
|
+
'menu row that reveals a nested flyout of its own children/items (single component, not Sub/SubTrigger/SubContent)',
|
|
77
|
+
propDescriptions: {
|
|
78
|
+
label: 'primary label text for the trigger row',
|
|
79
|
+
icon: 'icon before label',
|
|
80
|
+
description: 'secondary text below label',
|
|
81
|
+
children: 'flyout menu items (same components as top level)',
|
|
82
|
+
isDisabled: 'renders trigger but never opens',
|
|
83
|
+
hasSpinner: 'spinner instead of caret for async children',
|
|
84
|
+
menuWidth: 'fixed flyout width (default: content, min 160px)',
|
|
85
|
+
onOpenChange: 'called when flyout opens/closes',
|
|
86
|
+
xstyle: 'StyleX styles for the trigger row',
|
|
87
|
+
},
|
|
88
|
+
};
|