@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
|
@@ -131,6 +131,8 @@ export interface TopNavItemProps extends BaseProps<HTMLAnchorElement> {
|
|
|
131
131
|
isSelected?: boolean;
|
|
132
132
|
/**
|
|
133
133
|
* Whether the nav item is disabled.
|
|
134
|
+
* A disabled item renders as a plain anchor without an href (and without
|
|
135
|
+
* target), so it cannot navigate and is removed from the tab order.
|
|
134
136
|
* @default false
|
|
135
137
|
*/
|
|
136
138
|
isDisabled?: boolean;
|
|
@@ -157,6 +159,15 @@ export interface TopNavItemProps extends BaseProps<HTMLAnchorElement> {
|
|
|
157
159
|
size?: NavItemSize;
|
|
158
160
|
}
|
|
159
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Click handler for disabled items. The disabled anchor renders without an
|
|
164
|
+
* href, so there is no navigation to block in practice; preventDefault is a
|
|
165
|
+
* defensive guard against synthetic/programmatic clicks.
|
|
166
|
+
*/
|
|
167
|
+
function preventDefaultClick(event: React.MouseEvent<HTMLAnchorElement>): void {
|
|
168
|
+
event.preventDefault();
|
|
169
|
+
}
|
|
170
|
+
|
|
160
171
|
/**
|
|
161
172
|
* A navigation item for use within TopNav startContent.
|
|
162
173
|
*
|
|
@@ -178,6 +189,9 @@ export interface TopNavItemProps extends BaseProps<HTMLAnchorElement> {
|
|
|
178
189
|
*/
|
|
179
190
|
export function TopNavItem({
|
|
180
191
|
as,
|
|
192
|
+
href,
|
|
193
|
+
target,
|
|
194
|
+
onClick,
|
|
181
195
|
label,
|
|
182
196
|
isSelected = false,
|
|
183
197
|
isDisabled = false,
|
|
@@ -195,22 +209,34 @@ export function TopNavItem({
|
|
|
195
209
|
const renderMode = useTopNavRenderMode();
|
|
196
210
|
const {closeMobileNav} = useAppShellMobile();
|
|
197
211
|
|
|
212
|
+
// A disabled item renders as a plain <a> with no href: an href-less anchor
|
|
213
|
+
// is not focusable and exposes no link affordance, so programmatic focus +
|
|
214
|
+
// Enter, AT activation commands, and middle-click cannot navigate or fire
|
|
215
|
+
// the consumer onClick. The router LinkComponent is deliberately skipped —
|
|
216
|
+
// a disabled item performs no navigation, and custom router links may
|
|
217
|
+
// require a live href. target is omitted with the href. (Mirrors the
|
|
218
|
+
// disabled paths of Link and SideNavItem.)
|
|
219
|
+
const Root = isDisabled ? 'a' : LinkComponent;
|
|
220
|
+
|
|
198
221
|
// =========================================================================
|
|
199
222
|
// Drawer mode — render as a SideNavItem-style vertical list element
|
|
200
223
|
// =========================================================================
|
|
201
224
|
if (renderMode === 'drawer') {
|
|
202
|
-
const handleDrawerClick = (e: React.MouseEvent) => {
|
|
225
|
+
const handleDrawerClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
203
226
|
if (isDisabled) {
|
|
227
|
+
preventDefaultClick(e);
|
|
204
228
|
return;
|
|
205
229
|
}
|
|
206
230
|
// Forward the original onClick if present
|
|
207
|
-
|
|
231
|
+
onClick?.(e);
|
|
208
232
|
closeMobileNav();
|
|
209
233
|
};
|
|
210
234
|
|
|
211
235
|
return (
|
|
212
|
-
<
|
|
236
|
+
<Root
|
|
213
237
|
ref={ref}
|
|
238
|
+
href={isDisabled ? undefined : href}
|
|
239
|
+
target={isDisabled ? undefined : target}
|
|
214
240
|
aria-label={isIconOnly ? label : undefined}
|
|
215
241
|
aria-current={isSelected ? 'page' : undefined}
|
|
216
242
|
aria-disabled={isDisabled || undefined}
|
|
@@ -235,7 +261,7 @@ export function TopNavItem({
|
|
|
235
261
|
onClick={handleDrawerClick}>
|
|
236
262
|
{icon}
|
|
237
263
|
{!isIconOnly && (children ?? label)}
|
|
238
|
-
</
|
|
264
|
+
</Root>
|
|
239
265
|
);
|
|
240
266
|
}
|
|
241
267
|
|
|
@@ -244,8 +270,11 @@ export function TopNavItem({
|
|
|
244
270
|
// =========================================================================
|
|
245
271
|
|
|
246
272
|
return (
|
|
247
|
-
<
|
|
273
|
+
<Root
|
|
248
274
|
ref={ref}
|
|
275
|
+
href={isDisabled ? undefined : href}
|
|
276
|
+
target={isDisabled ? undefined : target}
|
|
277
|
+
onClick={isDisabled ? preventDefaultClick : onClick}
|
|
249
278
|
aria-label={isIconOnly ? label : undefined}
|
|
250
279
|
aria-current={isSelected ? 'page' : undefined}
|
|
251
280
|
aria-disabled={isDisabled || undefined}
|
|
@@ -267,7 +296,7 @@ export function TopNavItem({
|
|
|
267
296
|
{...props}>
|
|
268
297
|
{icon}
|
|
269
298
|
{!isIconOnly && (children ?? label)}
|
|
270
|
-
</
|
|
299
|
+
</Root>
|
|
271
300
|
);
|
|
272
301
|
}
|
|
273
302
|
|
|
@@ -27,7 +27,7 @@ export const docs = {
|
|
|
27
27
|
{
|
|
28
28
|
name: 'imageAlt',
|
|
29
29
|
type: 'string',
|
|
30
|
-
description: 'Alt text for the image. When omitted, the image is explicitly decorative (alt="", role="presentation", aria-hidden)
|
|
30
|
+
description: 'Alt text for the image. When omitted, the image is explicitly decorative (alt="", role="presentation", aria-hidden), usually correct since the card already has a visible title. Provide it only when the image conveys information beyond the title and description.',
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
name: 'linkLabel',
|
|
@@ -30,6 +30,9 @@ export const docs = {
|
|
|
30
30
|
{className: 'astryx-tree-list-item-label', states: ['selected']},
|
|
31
31
|
{className: 'astryx-tree-list-guide'},
|
|
32
32
|
],
|
|
33
|
+
vars: [
|
|
34
|
+
{name: '--tree-list-indent', description: 'Per-level indentation step. Each nesting level indents its rows by this distance, and the guide lines follow it so they stay aligned. Set it on the `tree-list` target to retune the metric (e.g. `var(--spacing-5)` for a wider indent).', default: 'var(--spacing-4)'},
|
|
35
|
+
],
|
|
33
36
|
},
|
|
34
37
|
components: [
|
|
35
38
|
{
|
|
@@ -104,6 +107,9 @@ export const docsZh = {
|
|
|
104
107
|
{className: 'astryx-tree-list-item-label', states: ['selected']},
|
|
105
108
|
{className: 'astryx-tree-list-guide'},
|
|
106
109
|
],
|
|
110
|
+
vars: [
|
|
111
|
+
{name: '--tree-list-indent', description: '每级缩进步长。每个嵌套层级的行按此距离缩进,引导线随之对齐。在 `tree-list` 目标上设置以调整该度量(例如用 `var(--spacing-5)` 获得更宽的缩进)。', default: 'var(--spacing-4)'},
|
|
112
|
+
],
|
|
107
113
|
},
|
|
108
114
|
components: [
|
|
109
115
|
{
|
|
@@ -432,25 +432,28 @@ describe('TreeList', () => {
|
|
|
432
432
|
|
|
433
433
|
it("variant='noGuides' preserves per-level indentation on the rows", () => {
|
|
434
434
|
// Indentation lives on the row's margin-inline-start (not the guide
|
|
435
|
-
// element), so it must survive when the connectors are suppressed.
|
|
436
|
-
//
|
|
435
|
+
// element), so it must survive when the connectors are suppressed. The
|
|
436
|
+
// per-row distance is published as the `--_tree-indent` custom property
|
|
437
|
+
// (not an inline longhand — see #4308), so the theme layer can override
|
|
438
|
+
// the `margin-inline-start` declaration. A deeper row is indented more
|
|
439
|
+
// than a shallower one.
|
|
437
440
|
const {container} = render(
|
|
438
441
|
<TreeList items={deepItems} variant="noGuides" />,
|
|
439
442
|
);
|
|
440
|
-
const
|
|
443
|
+
const indentOf = (text: string): string => {
|
|
441
444
|
const li = screen.getByText(text).closest('li')!;
|
|
442
|
-
const styled = li.querySelector('[style*="
|
|
445
|
+
const styled = li.querySelector('[style*="--_tree-indent"]');
|
|
443
446
|
return styled?.getAttribute('style') ?? '';
|
|
444
447
|
};
|
|
445
448
|
// Guides are gone…
|
|
446
449
|
expect(container.querySelector('.astryx-tree-list-guide')).toBeNull();
|
|
447
|
-
// …but each level still
|
|
448
|
-
//
|
|
449
|
-
expect(
|
|
450
|
-
expect(
|
|
451
|
-
expect(
|
|
450
|
+
// …but each level still publishes an indent distance, and the level
|
|
451
|
+
// multiplier grows with depth (0, 1, 2).
|
|
452
|
+
expect(indentOf('Root')).toContain('--_tree-indent');
|
|
453
|
+
expect(indentOf('Mid')).toContain('--_tree-indent');
|
|
454
|
+
expect(indentOf('Leaf')).toContain('--_tree-indent');
|
|
452
455
|
const level = (text: string): number => {
|
|
453
|
-
const m = /calc\((\d+)/.exec(
|
|
456
|
+
const m = /calc\((\d+)/.exec(indentOf(text));
|
|
454
457
|
return m ? Number(m[1]) : NaN;
|
|
455
458
|
};
|
|
456
459
|
expect(level('Mid')).toBeGreaterThan(level('Root'));
|
|
@@ -504,6 +507,43 @@ describe('TreeList', () => {
|
|
|
504
507
|
});
|
|
505
508
|
});
|
|
506
509
|
|
|
510
|
+
// ===========================================================================
|
|
511
|
+
// Indent lever (--tree-list-indent)
|
|
512
|
+
// ===========================================================================
|
|
513
|
+
|
|
514
|
+
describe('indent lever', () => {
|
|
515
|
+
it('lets a theme retune the indent step via the tree-list target', () => {
|
|
516
|
+
// The per-level step is a public, themeable var (default --spacing-4) set
|
|
517
|
+
// on the tree-list root, so a theme can retune the indent metric (e.g. to
|
|
518
|
+
// --spacing-5) via defineTheme. jsdom cannot resolve the @layer cascade,
|
|
519
|
+
// so the generated CSS is what proves the override reaches the lever.
|
|
520
|
+
const theme = defineTheme({
|
|
521
|
+
name: 'tree-list-indent-test',
|
|
522
|
+
components: {
|
|
523
|
+
'tree-list': {
|
|
524
|
+
base: {'--tree-list-indent': 'var(--spacing-5)'},
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
});
|
|
528
|
+
const css = generateThemeCSSFlat(theme);
|
|
529
|
+
expect(css).toContain('.astryx-tree-list {');
|
|
530
|
+
expect(css).toContain('--tree-list-indent: var(--spacing-5)');
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
it('rows consume the indent step in their published indent distance', () => {
|
|
534
|
+
// Each row's --_tree-indent is calc(level * var(--tree-list-indent)),
|
|
535
|
+
// so retuning the step scales every level uniformly.
|
|
536
|
+
render(<TreeList items={deepItems} variant="noGuides" />);
|
|
537
|
+
const indentOf = (text: string): string => {
|
|
538
|
+
const li = screen.getByText(text).closest('li')!;
|
|
539
|
+
const styled = li.querySelector('[style*="--_tree-indent"]');
|
|
540
|
+
return styled?.getAttribute('style') ?? '';
|
|
541
|
+
};
|
|
542
|
+
expect(indentOf('Mid')).toContain('var(--tree-list-indent)');
|
|
543
|
+
expect(indentOf('Leaf')).toContain('var(--tree-list-indent)');
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
|
|
507
547
|
// ===========================================================================
|
|
508
548
|
// xds class name
|
|
509
549
|
// ===========================================================================
|
|
@@ -83,6 +83,11 @@ export interface TreeListProps extends BaseProps<HTMLDivElement> {
|
|
|
83
83
|
const styles = stylex.create({
|
|
84
84
|
root: {
|
|
85
85
|
position: 'relative',
|
|
86
|
+
// Per-level indentation step. Public, themeable lever: a theme can retune
|
|
87
|
+
// the tree's indent metric (e.g. to `var(--spacing-5)`) via `defineTheme`
|
|
88
|
+
// on the `tree-list` target, and both the row margins (TreeListItem) and
|
|
89
|
+
// the guide-line offsets (TreeListBranches) read it so they stay aligned.
|
|
90
|
+
'--tree-list-indent': spacingVars['--spacing-4'],
|
|
86
91
|
},
|
|
87
92
|
list: {
|
|
88
93
|
margin: 0,
|
|
@@ -26,8 +26,10 @@ const LINE_WIDTH = 1;
|
|
|
26
26
|
*/
|
|
27
27
|
const BRANCH_MARGIN = `calc(${spacingVars['--spacing-2']} + ${spacingVars['--spacing-0-5']})`;
|
|
28
28
|
|
|
29
|
-
/** Per-level indent width,
|
|
30
|
-
|
|
29
|
+
/** Per-level indent width. Reads the public, themeable `--tree-list-indent`
|
|
30
|
+
* lever set on the tree-list root (default `--spacing-4`, 16px), so the guide
|
|
31
|
+
* lines stay aligned with the row indent when a theme retunes the step. */
|
|
32
|
+
const LEVEL_INDENT = 'var(--tree-list-indent)';
|
|
31
33
|
|
|
32
34
|
const styles = stylex.create({
|
|
33
35
|
container: {
|
|
@@ -37,10 +39,10 @@ const styles = stylex.create({
|
|
|
37
39
|
},
|
|
38
40
|
verticalLine: {
|
|
39
41
|
borderRadius: 1,
|
|
40
|
-
|
|
42
|
+
insetInlineStart: 0,
|
|
41
43
|
margin: 'auto',
|
|
42
44
|
position: 'absolute',
|
|
43
|
-
|
|
45
|
+
insetInlineEnd: 0,
|
|
44
46
|
width: LINE_WIDTH,
|
|
45
47
|
backgroundColor: colorVars['--color-border-emphasized'],
|
|
46
48
|
},
|
|
@@ -92,7 +94,7 @@ export function TreeListBranches({
|
|
|
92
94
|
key={level}
|
|
93
95
|
{...mergeProps(stylex.props(styles.container), {
|
|
94
96
|
style: {
|
|
95
|
-
|
|
97
|
+
insetInlineStart: branchOffset,
|
|
96
98
|
},
|
|
97
99
|
})}>
|
|
98
100
|
<div
|
|
@@ -109,7 +111,7 @@ export function TreeListBranches({
|
|
|
109
111
|
<div
|
|
110
112
|
{...mergeProps(stylex.props(styles.container), {
|
|
111
113
|
style: {
|
|
112
|
-
|
|
114
|
+
insetInlineStart: `calc(${BRANCH_MARGIN} + ${nestedLevel - 1} * ${LEVEL_INDENT})`,
|
|
113
115
|
},
|
|
114
116
|
})}>
|
|
115
117
|
<div
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
typeScaleVars,
|
|
26
26
|
} from '../theme/tokens.stylex';
|
|
27
27
|
import {getIcon} from '../Icon/globalIconRegistry';
|
|
28
|
-
import {mergeProps} from '../utils';
|
|
28
|
+
import {mergeProps, rtlStyles} from '../utils';
|
|
29
29
|
import {useLinkComponent} from '../Link/useLinkComponent';
|
|
30
30
|
import {TreeListBranches} from './TreeListBranches';
|
|
31
31
|
import type {TreeListDensity, TreeListVariant} from './TreeListTypes';
|
|
@@ -82,6 +82,12 @@ const styles = stylex.create({
|
|
|
82
82
|
position: 'relative',
|
|
83
83
|
boxSizing: 'border-box',
|
|
84
84
|
textAlign: 'start',
|
|
85
|
+
// Per-level indent. Declared here (not inline) so it lives in
|
|
86
|
+
// `@layer astryx-base` and the theme layer can override it in normal
|
|
87
|
+
// cascade order — an inline longhand would outrank every layer. The row
|
|
88
|
+
// publishes only the computed distance as `--_tree-indent`; the per-level
|
|
89
|
+
// step is the public `--tree-list-indent` lever (see TreeList `root`).
|
|
90
|
+
marginInlineStart: 'var(--_tree-indent, 0px)',
|
|
85
91
|
},
|
|
86
92
|
interactive: {
|
|
87
93
|
cursor: 'pointer',
|
|
@@ -246,6 +252,11 @@ const descriptionSizeStyles = stylex.create({
|
|
|
246
252
|
},
|
|
247
253
|
});
|
|
248
254
|
|
|
255
|
+
// `CSSProperties` has no index signature for custom properties, so the row's
|
|
256
|
+
// inline style — which publishes the computed indent distance as the private
|
|
257
|
+
// `--_tree-indent` — needs this augmentation to typecheck.
|
|
258
|
+
type IndentStyle = React.CSSProperties & Record<'--_tree-indent', string>;
|
|
259
|
+
|
|
249
260
|
// =============================================================================
|
|
250
261
|
// Types
|
|
251
262
|
// =============================================================================
|
|
@@ -353,9 +364,18 @@ export function TreeListItem({
|
|
|
353
364
|
return undefined;
|
|
354
365
|
}, [onClick, hasChildren, onToggle, id, isDisabled]);
|
|
355
366
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
367
|
+
// Per-level indent distance. The per-level step is the public, themeable
|
|
368
|
+
// `--tree-list-indent` lever (default `--spacing-4`, set on the tree-list
|
|
369
|
+
// root). Leaves add a fixed chevron-column offset (chevron width + gap) so
|
|
370
|
+
// their labels line up with sibling parents' labels; that offset is tied to
|
|
371
|
+
// the chevron's own dimensions, not the indent step, so it does not scale
|
|
372
|
+
// with the lever. Published as the private `--_tree-indent` and consumed by
|
|
373
|
+
// `contentWrapper`'s stylesheet `margin-inline-start` (kept out of the inline
|
|
374
|
+
// style so the theme layer can override it — see #4308).
|
|
375
|
+
const indentDistance = hasChildren
|
|
376
|
+
? `calc(${nestedLevel} * var(--tree-list-indent))`
|
|
377
|
+
: `calc(${nestedLevel} * var(--tree-list-indent) + ${spacingVars['--spacing-4']} + ${spacingVars['--spacing-2']})`;
|
|
378
|
+
const indentStyle: IndentStyle = {'--_tree-indent': indentDistance};
|
|
359
379
|
|
|
360
380
|
const labelAndDescription = (
|
|
361
381
|
<>
|
|
@@ -386,12 +406,14 @@ export function TreeListItem({
|
|
|
386
406
|
);
|
|
387
407
|
|
|
388
408
|
const chevronIcon = (
|
|
389
|
-
<span
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
409
|
+
<span {...stylex.props(rtlStyles.mirror)}>
|
|
410
|
+
<span
|
|
411
|
+
{...stylex.props(
|
|
412
|
+
styles.chevronSvg,
|
|
413
|
+
isExpanded ? styles.chevronExpanded : styles.chevronCollapsed,
|
|
414
|
+
)}>
|
|
415
|
+
{getIcon('chevronRight')}
|
|
416
|
+
</span>
|
|
395
417
|
</span>
|
|
396
418
|
);
|
|
397
419
|
|
|
@@ -527,7 +549,7 @@ export function TreeListItem({
|
|
|
527
549
|
isSelected && styles.selected,
|
|
528
550
|
),
|
|
529
551
|
)}
|
|
530
|
-
style={
|
|
552
|
+
style={indentStyle}
|
|
531
553
|
onClick={handleClick}>
|
|
532
554
|
{innerContent}
|
|
533
555
|
</div>
|
|
@@ -431,7 +431,7 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
431
431
|
resultsGenRef.current = gen;
|
|
432
432
|
const shown = searchResults.slice(0, maxMenuItems);
|
|
433
433
|
setResults(shown);
|
|
434
|
-
setHighlightedIndex(
|
|
434
|
+
setHighlightedIndex(shown.length > 0 ? 0 : -1);
|
|
435
435
|
if (searchResults.length > 0 || searchQuery.length > 0) {
|
|
436
436
|
showLayer();
|
|
437
437
|
}
|
|
@@ -469,8 +469,9 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
469
469
|
return;
|
|
470
470
|
}
|
|
471
471
|
resultsGenRef.current = gen;
|
|
472
|
-
|
|
473
|
-
|
|
472
|
+
const shown = bootstrapResults.slice(0, maxMenuItems);
|
|
473
|
+
setResults(shown);
|
|
474
|
+
setHighlightedIndex(shown.length > 0 ? 0 : -1);
|
|
474
475
|
if (bootstrapResults.length > 0) {
|
|
475
476
|
showLayer();
|
|
476
477
|
}
|
|
@@ -637,15 +638,19 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
637
638
|
switch (e.key) {
|
|
638
639
|
case 'ArrowDown':
|
|
639
640
|
e.preventDefault();
|
|
640
|
-
|
|
641
|
-
prev
|
|
642
|
-
|
|
641
|
+
if (results.length > 0) {
|
|
642
|
+
setHighlightedIndex(prev =>
|
|
643
|
+
prev < results.length - 1 ? prev + 1 : 0,
|
|
644
|
+
);
|
|
645
|
+
}
|
|
643
646
|
break;
|
|
644
647
|
case 'ArrowUp':
|
|
645
648
|
e.preventDefault();
|
|
646
|
-
|
|
647
|
-
prev
|
|
648
|
-
|
|
649
|
+
if (results.length > 0) {
|
|
650
|
+
setHighlightedIndex(prev =>
|
|
651
|
+
prev > 0 ? prev - 1 : results.length - 1,
|
|
652
|
+
);
|
|
653
|
+
}
|
|
649
654
|
break;
|
|
650
655
|
case 'Enter':
|
|
651
656
|
e.preventDefault();
|
|
@@ -660,13 +665,17 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
660
665
|
case 'Home':
|
|
661
666
|
if (popover.isOpen) {
|
|
662
667
|
e.preventDefault();
|
|
663
|
-
|
|
668
|
+
if (results.length > 0) {
|
|
669
|
+
setHighlightedIndex(0);
|
|
670
|
+
}
|
|
664
671
|
}
|
|
665
672
|
break;
|
|
666
673
|
case 'End':
|
|
667
674
|
if (popover.isOpen) {
|
|
668
675
|
e.preventDefault();
|
|
669
|
-
|
|
676
|
+
if (results.length > 0) {
|
|
677
|
+
setHighlightedIndex(results.length - 1);
|
|
678
|
+
}
|
|
670
679
|
}
|
|
671
680
|
break;
|
|
672
681
|
}
|
|
@@ -694,13 +703,17 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
694
703
|
// cursor walks off-screen once navigation passes the visible window. Mirrors
|
|
695
704
|
// CommandPaletteItem's scrollIntoView({block: 'nearest'}) behavior.
|
|
696
705
|
useEffect(() => {
|
|
697
|
-
if (
|
|
706
|
+
if (
|
|
707
|
+
!popover.isOpen ||
|
|
708
|
+
highlightedIndex < 0 ||
|
|
709
|
+
highlightedIndex >= results.length
|
|
710
|
+
) {
|
|
698
711
|
return;
|
|
699
712
|
}
|
|
700
713
|
document
|
|
701
714
|
.getElementById(getItemId(highlightedIndex))
|
|
702
715
|
?.scrollIntoView?.({block: 'nearest'});
|
|
703
|
-
}, [popover.isOpen, highlightedIndex, getItemId]);
|
|
716
|
+
}, [popover.isOpen, highlightedIndex, getItemId, results.length]);
|
|
704
717
|
|
|
705
718
|
const selectedKey =
|
|
706
719
|
value == null ? null : getKey(value.id, () => results.indexOf(value));
|
|
@@ -725,7 +738,9 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
725
738
|
aria-expanded={popover.isOpen}
|
|
726
739
|
aria-controls={listboxId}
|
|
727
740
|
aria-activedescendant={
|
|
728
|
-
popover.isOpen &&
|
|
741
|
+
popover.isOpen &&
|
|
742
|
+
highlightedIndex >= 0 &&
|
|
743
|
+
highlightedIndex < results.length
|
|
729
744
|
? getItemId(highlightedIndex)
|
|
730
745
|
: undefined
|
|
731
746
|
}
|
|
@@ -165,6 +165,12 @@ export const docs = {
|
|
|
165
165
|
type: '(isOpen: boolean) => void',
|
|
166
166
|
description: 'Callback when the dropdown opens or closes.',
|
|
167
167
|
},
|
|
168
|
+
{
|
|
169
|
+
name: 'width',
|
|
170
|
+
type: 'SizeValue',
|
|
171
|
+
description:
|
|
172
|
+
'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.',
|
|
173
|
+
},
|
|
168
174
|
{
|
|
169
175
|
name: 'xstyle',
|
|
170
176
|
type: 'StyleXStyles',
|
|
@@ -171,6 +171,33 @@ describe('BaseTypeahead', () => {
|
|
|
171
171
|
});
|
|
172
172
|
});
|
|
173
173
|
|
|
174
|
+
describe('empty results active descendant (#4059)', () => {
|
|
175
|
+
it('does not set aria-activedescendant when search has 0 results', async () => {
|
|
176
|
+
render(
|
|
177
|
+
<BaseTypeahead
|
|
178
|
+
searchSource={fruitSource}
|
|
179
|
+
value={null}
|
|
180
|
+
onChange={() => {}}
|
|
181
|
+
debounceMs={0}
|
|
182
|
+
/>,
|
|
183
|
+
);
|
|
184
|
+
const input = screen.getByRole('combobox');
|
|
185
|
+
fireEvent.change(input, {target: {value: 'zzzzz'}});
|
|
186
|
+
|
|
187
|
+
await waitFor(() => {
|
|
188
|
+
expect(input).not.toHaveAttribute('aria-activedescendant');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Press ArrowDown — should NOT set aria-activedescendant to option-0
|
|
192
|
+
fireEvent.keyDown(input, {key: 'ArrowDown'});
|
|
193
|
+
expect(input).not.toHaveAttribute('aria-activedescendant');
|
|
194
|
+
|
|
195
|
+
// Press Home — should NOT set aria-activedescendant
|
|
196
|
+
fireEvent.keyDown(input, {key: 'Home'});
|
|
197
|
+
expect(input).not.toHaveAttribute('aria-activedescendant');
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
174
201
|
it('disables input when isDisabled', () => {
|
|
175
202
|
render(
|
|
176
203
|
<BaseTypeahead
|
|
@@ -421,7 +421,7 @@ export function Typeahead<T extends SearchableItem>({
|
|
|
421
421
|
styles.wrapper,
|
|
422
422
|
sizeStyle,
|
|
423
423
|
status && inputStatusBorderStyles[status.type],
|
|
424
|
-
status && inputStatusHoverShadowStyles[status.type],
|
|
424
|
+
status && !isDisabled && inputStatusHoverShadowStyles[status.type],
|
|
425
425
|
status && inputStatusFocusWithinStyles[status.type],
|
|
426
426
|
isDisabled && inputWrapperStyles.disabled,
|
|
427
427
|
inputGroup && groupStyles.inGroup,
|
|
@@ -132,6 +132,7 @@ export function TypeaheadItem<T extends SearchableItem>({
|
|
|
132
132
|
icon,
|
|
133
133
|
description,
|
|
134
134
|
isDisabled = false,
|
|
135
|
+
xstyle,
|
|
135
136
|
}: TypeaheadItemProps<T>) {
|
|
136
137
|
// If item has a pre-rendered element, use it
|
|
137
138
|
if (item.element) {
|
|
@@ -143,7 +144,7 @@ export function TypeaheadItem<T extends SearchableItem>({
|
|
|
143
144
|
ref={ref}
|
|
144
145
|
{...mergeProps(
|
|
145
146
|
themeProps('typeahead-item'),
|
|
146
|
-
stylex.props(styles.container, isDisabled && styles.disabled),
|
|
147
|
+
stylex.props(styles.container, isDisabled && styles.disabled, xstyle),
|
|
147
148
|
)}>
|
|
148
149
|
{icon}
|
|
149
150
|
<div {...stylex.props(styles.content)}>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
import {describe, it, expect} from 'vitest';
|
|
4
|
+
|
|
5
|
+
import {docs as CheckboxInputDocs} from '../CheckboxInput/CheckboxInput.doc.mjs';
|
|
6
|
+
import {docs as CheckboxListDocs} from '../CheckboxList/CheckboxList.doc.mjs';
|
|
7
|
+
import {docs as DateInputDocs} from '../DateInput/DateInput.doc.mjs';
|
|
8
|
+
import {docs as DateRangeInputDocs} from '../DateRangeInput/DateRangeInput.doc.mjs';
|
|
9
|
+
import {docs as DateTimeInputDocs} from '../DateTimeInput/DateTimeInput.doc.mjs';
|
|
10
|
+
import {docs as FileInputDocs} from '../FileInput/FileInput.doc.mjs';
|
|
11
|
+
import {docs as MultiSelectorDocs} from '../MultiSelector/MultiSelector.doc.mjs';
|
|
12
|
+
import {docs as NumberInputDocs} from '../NumberInput/NumberInput.doc.mjs';
|
|
13
|
+
import {docs as RadioListDocs} from '../RadioList/RadioList.doc.mjs';
|
|
14
|
+
import {docs as SelectorDocs} from '../Selector/Selector.doc.mjs';
|
|
15
|
+
import {docs as SliderDocs} from '../Slider/Slider.doc.mjs';
|
|
16
|
+
import {docs as SwitchDocs} from '../Switch/Switch.doc.mjs';
|
|
17
|
+
import {docs as TextAreaDocs} from '../TextArea/TextArea.doc.mjs';
|
|
18
|
+
import {docs as TextInputDocs} from '../TextInput/TextInput.doc.mjs';
|
|
19
|
+
import {docs as TimeInputDocs} from '../TimeInput/TimeInput.doc.mjs';
|
|
20
|
+
import {docs as TokenizerDocs} from '../Tokenizer/Tokenizer.doc.mjs';
|
|
21
|
+
import {docs as TypeaheadDocs} from '../Typeahead/Typeahead.doc.mjs';
|
|
22
|
+
|
|
23
|
+
const inputDocsSuite = [
|
|
24
|
+
{name: 'CheckboxInput', docs: CheckboxInputDocs},
|
|
25
|
+
{name: 'CheckboxList', docs: CheckboxListDocs},
|
|
26
|
+
{name: 'DateInput', docs: DateInputDocs},
|
|
27
|
+
{name: 'DateRangeInput', docs: DateRangeInputDocs},
|
|
28
|
+
{name: 'DateTimeInput', docs: DateTimeInputDocs},
|
|
29
|
+
{name: 'FileInput', docs: FileInputDocs},
|
|
30
|
+
{name: 'MultiSelector', docs: MultiSelectorDocs},
|
|
31
|
+
{name: 'NumberInput', docs: NumberInputDocs},
|
|
32
|
+
{name: 'RadioList', docs: RadioListDocs},
|
|
33
|
+
{name: 'Selector', docs: SelectorDocs},
|
|
34
|
+
{name: 'Slider', docs: SliderDocs},
|
|
35
|
+
{name: 'Switch', docs: SwitchDocs},
|
|
36
|
+
{name: 'TextArea', docs: TextAreaDocs},
|
|
37
|
+
{name: 'TextInput', docs: TextInputDocs},
|
|
38
|
+
{name: 'TimeInput', docs: TimeInputDocs},
|
|
39
|
+
{name: 'Tokenizer', docs: TokenizerDocs},
|
|
40
|
+
{name: 'Typeahead', docs: TypeaheadDocs},
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
describe('Input Family width Prop Contract (#4163)', () => {
|
|
44
|
+
inputDocsSuite.forEach(({name, docs}) => {
|
|
45
|
+
it(`documents the width prop for ${name}`, () => {
|
|
46
|
+
const propsList = (docs.props || docs.components?.[0]?.props) as {
|
|
47
|
+
name: string;
|
|
48
|
+
type: string;
|
|
49
|
+
}[];
|
|
50
|
+
expect(
|
|
51
|
+
propsList,
|
|
52
|
+
`${name}.doc.mjs must expose a props array`,
|
|
53
|
+
).toBeDefined();
|
|
54
|
+
const widthProp = propsList.find(p => p.name === 'width');
|
|
55
|
+
expect(
|
|
56
|
+
widthProp,
|
|
57
|
+
`${name}.doc.mjs must document the width prop`,
|
|
58
|
+
).toBeDefined();
|
|
59
|
+
expect(widthProp?.type).toBe('SizeValue');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
package/src/doc-mjs.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Ambient module declaration for `*.doc.mjs` imports.
|
|
5
|
+
*
|
|
6
|
+
* Component contract tests (packages/core/src/__tests__/*Contract.test.tsx)
|
|
7
|
+
* import `{Name}.doc.mjs` files directly to assert their documented props
|
|
8
|
+
* stay in sync with the component's real API. Without this declaration,
|
|
9
|
+
* TypeScript has no way to type a `.mjs` import and fails with
|
|
10
|
+
* TS7016 ("Could not find a declaration file for module").
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
declare module '*.doc.mjs' {
|
|
14
|
+
import type {ComponentDoc, TranslationDoc} from './docs-types';
|
|
15
|
+
|
|
16
|
+
export const docs: ComponentDoc;
|
|
17
|
+
export const docsZh: ComponentDoc;
|
|
18
|
+
export const docsDense: TranslationDoc;
|
|
19
|
+
}
|
package/src/hooks/index.ts
CHANGED
|
@@ -76,6 +76,12 @@ export type {
|
|
|
76
76
|
export {useInputContainer} from './useInputContainer';
|
|
77
77
|
export type {UseInputContainerOptions} from './useInputContainer';
|
|
78
78
|
|
|
79
|
+
export {useInputStatusIcon} from './useInputStatusIcon';
|
|
80
|
+
export type {
|
|
81
|
+
UseInputStatusIconOptions,
|
|
82
|
+
UseInputStatusIconReturn,
|
|
83
|
+
} from './useInputStatusIcon';
|
|
84
|
+
|
|
79
85
|
export {useInteractiveRole} from './useInteractiveRole';
|
|
80
86
|
export type {
|
|
81
87
|
InteractiveRole,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file isRtlElement.ts
|
|
7
|
+
* @input DOM element (nullable)
|
|
8
|
+
* @output Exports isRtlElement helper resolving an element's computed text
|
|
9
|
+
* direction
|
|
10
|
+
* @position Internal hook utility; used by useListFocus and useGridFocus to
|
|
11
|
+
* auto-detect RTL for arrow-key navigation (same getComputedStyle precedent
|
|
12
|
+
* as Resizable's ResizeHandle drag deltas).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Whether `el` renders right-to-left, per its computed `direction`.
|
|
17
|
+
*
|
|
18
|
+
* SSR-safe: returns false when `el` is null or no DOM is available. Callers
|
|
19
|
+
* should invoke this lazily (on keydown, not on render) so getComputedStyle
|
|
20
|
+
* runs only when a horizontal arrow key is actually handled.
|
|
21
|
+
*/
|
|
22
|
+
export function isRtlElement(el: HTMLElement | null): boolean {
|
|
23
|
+
if (!el || typeof window === 'undefined') {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
return window.getComputedStyle(el).direction === 'rtl';
|
|
27
|
+
}
|