@astryxdesign/core 0.1.1 → 0.1.2-canary.04e71b2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +105 -0
- package/README.md +131 -13
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +11 -5
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +4 -1
- package/dist/Banner/Banner.d.ts +7 -0
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +9 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +24 -5
- package/dist/Button/Button.d.ts +12 -2
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +53 -17
- package/dist/Calendar/Calendar.d.ts +5 -4
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +82 -43
- package/dist/Calendar/hooks/index.d.ts +0 -2
- package/dist/Calendar/hooks/index.d.ts.map +1 -1
- package/dist/Calendar/hooks/index.js +1 -2
- package/dist/Calendar/index.d.ts +3 -3
- package/dist/Calendar/index.d.ts.map +1 -1
- package/dist/Calendar/index.js +1 -1
- package/dist/Calendar/styles.d.ts +3 -9
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +3 -11
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +17 -3
- package/dist/Center/Center.d.ts +11 -1
- package/dist/Center/Center.d.ts.map +1 -1
- package/dist/Center/Center.js +9 -3
- package/dist/Chat/ChatMessageList.d.ts +14 -1
- package/dist/Chat/ChatMessageList.d.ts.map +1 -1
- package/dist/Chat/ChatMessageList.js +2 -0
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +4 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts +23 -2
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +51 -9
- package/dist/CheckboxList/CheckboxList.d.ts +13 -1
- package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxList.js +39 -9
- package/dist/CheckboxList/CheckboxListContext.d.ts +7 -0
- package/dist/CheckboxList/CheckboxListContext.d.ts.map +1 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +3 -3
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +49 -37
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +5 -5
- package/dist/ContextMenu/ContextMenu.d.ts +4 -5
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +93 -11
- package/dist/DateInput/DateInput.d.ts +23 -1
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +59 -8
- package/dist/DateRangeInput/DateRangeInput.d.ts +23 -1
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +42 -9
- package/dist/DateTimeInput/DateTimeInput.d.ts +35 -2
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +78 -15
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +12 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts +1 -8
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +42 -14
- package/dist/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/EmptyState/EmptyState.js +7 -1
- package/dist/Field/Field.d.ts +19 -2
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +4 -0
- package/dist/Field/FieldLabel.d.ts +21 -2
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +41 -26
- package/dist/FileInput/FileInput.d.ts +22 -1
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +56 -10
- package/dist/Grid/Grid.d.ts +11 -1
- package/dist/Grid/Grid.d.ts.map +1 -1
- package/dist/Grid/Grid.js +8 -0
- package/dist/HoverCard/HoverCard.d.ts +2 -2
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +18 -6
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +7 -3
- package/dist/InputGroup/InputGroup.d.ts +2 -2
- package/dist/InputGroup/InputGroup.d.ts.map +1 -1
- package/dist/InputGroup/InputGroup.js +14 -5
- package/dist/InputGroup/InputGroupContext.d.ts +4 -0
- package/dist/InputGroup/InputGroupContext.d.ts.map +1 -1
- package/dist/InputGroup/InputGroupContext.js +2 -2
- package/dist/InputGroup/index.d.ts +1 -0
- package/dist/InputGroup/index.d.ts.map +1 -1
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +34 -2
- package/dist/Layer/anchorName.d.ts +20 -0
- package/dist/Layer/anchorName.d.ts.map +1 -0
- package/dist/Layer/anchorName.js +36 -0
- package/dist/Layer/layerAnimations.stylex.d.ts +4 -0
- package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
- package/dist/Layer/layerAnimations.stylex.js +8 -4
- package/dist/Layer/useLayer.d.ts +29 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +55 -11
- package/dist/Layout/Layout.d.ts +4 -11
- package/dist/Layout/Layout.d.ts.map +1 -1
- package/dist/Layout/Layout.js +10 -11
- package/dist/Layout/LayoutFooter.d.ts +2 -2
- package/dist/Layout/LayoutFooter.d.ts.map +1 -1
- package/dist/Layout/LayoutHeader.d.ts +2 -2
- package/dist/Layout/LayoutHeader.d.ts.map +1 -1
- package/dist/Layout/LayoutPanel.d.ts +2 -2
- package/dist/Layout/LayoutPanel.d.ts.map +1 -1
- package/dist/Layout/padding.stylex.d.ts +51 -0
- package/dist/Layout/padding.stylex.d.ts.map +1 -1
- package/dist/Layout/padding.stylex.js +63 -0
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +4 -2
- package/dist/Link/Link.d.ts +17 -2
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +20 -9
- package/dist/Link/LinkProvider.d.ts +1 -0
- package/dist/Link/LinkProvider.d.ts.map +1 -1
- package/dist/Link/LinkProvider.js +1 -0
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +18 -3
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +13 -0
- package/dist/MoreMenu/MoreMenu.d.ts +1 -7
- package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
- package/dist/MoreMenu/MoreMenu.js +0 -2
- package/dist/MultiSelector/MultiSelector.d.ts +25 -2
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +103 -22
- package/dist/MultiSelector/hooks.d.ts +12 -1
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +14 -1
- package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenu.js +34 -3
- package/dist/NumberInput/NumberInput.d.ts +23 -2
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +62 -12
- package/dist/Pagination/Pagination.d.ts +1 -1
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +46 -28
- package/dist/Popover/usePopover.d.ts +25 -2
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +18 -6
- package/dist/PowerSearch/PowerSearch.d.ts +11 -1
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +6 -1
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +3 -5
- package/dist/RadioList/RadioList.d.ts +20 -2
- package/dist/RadioList/RadioList.d.ts.map +1 -1
- package/dist/RadioList/RadioList.js +105 -9
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +13 -2
- package/dist/SegmentedControl/SegmentedControl.d.ts +13 -2
- package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControl.js +78 -44
- package/dist/SegmentedControl/SegmentedControlContext.d.ts +7 -0
- package/dist/SegmentedControl/SegmentedControlContext.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +13 -2
- package/dist/Selector/Selector.d.ts +22 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +84 -23
- package/dist/Selector/hooks.d.ts +8 -1
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +14 -1
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +1 -1
- package/dist/Skeleton/Skeleton.d.ts.map +1 -1
- package/dist/Skeleton/Skeleton.js +8 -2
- package/dist/Slider/Slider.d.ts +21 -0
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +38 -11
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +1 -1
- package/dist/Stack/Stack.d.ts +38 -23
- package/dist/Stack/Stack.d.ts.map +1 -1
- package/dist/Stack/Stack.js +25 -1
- package/dist/Stack/StackItem.d.ts +12 -23
- package/dist/Stack/StackItem.d.ts.map +1 -1
- package/dist/Stack/StackItem.js +8 -1
- package/dist/Switch/Switch.d.ts +23 -2
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +41 -11
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +6 -0
- package/dist/TabList/TabList.d.ts +16 -4
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +86 -10
- package/dist/TabList/TabListContext.d.ts +5 -0
- package/dist/TabList/TabListContext.d.ts.map +1 -1
- package/dist/TabList/TabListContext.js +5 -0
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +6 -1
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +38 -16
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +36 -7
- package/dist/Table/TableCell.d.ts +8 -1
- package/dist/Table/TableCell.d.ts.map +1 -1
- package/dist/Table/TableCell.js +10 -10
- package/dist/Table/TableHeaderCell.d.ts +8 -1
- package/dist/Table/TableHeaderCell.d.ts.map +1 -1
- package/dist/Table/TableHeaderCell.js +16 -16
- package/dist/Table/TableRow.d.ts +6 -1
- package/dist/Table/TableRow.d.ts.map +1 -1
- package/dist/Table/TableRow.js +15 -7
- package/dist/Table/index.d.ts +4 -1
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +3 -2
- package/dist/Table/plugins/pagination/paginateData.d.ts +2 -1
- package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
- package/dist/Table/plugins/pagination/paginateData.js +8 -3
- package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
- package/dist/Table/plugins/pagination/useTablePagination.js +6 -1
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +59 -3
- package/dist/Table/plugins/stickyColumns/index.d.ts +3 -0
- package/dist/Table/plugins/stickyColumns/index.d.ts.map +1 -0
- package/dist/Table/plugins/stickyColumns/index.js +3 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts +25 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +369 -0
- package/dist/Table/tableContextMenu.d.ts +33 -0
- package/dist/Table/tableContextMenu.d.ts.map +1 -0
- package/dist/Table/tableContextMenu.js +133 -0
- package/dist/Table/types.d.ts +161 -5
- package/dist/Table/types.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.js +1 -1
- package/dist/Text/text.stylex.d.ts +2 -2
- package/dist/Text/text.stylex.js +2 -2
- package/dist/TextArea/TextArea.d.ts +22 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +41 -9
- package/dist/TextInput/TextInput.d.ts +23 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +55 -10
- package/dist/TimeInput/TimeInput.d.ts +23 -1
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +53 -10
- package/dist/Timestamp/Timestamp.d.ts +1 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +28 -3
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +14 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +132 -3
- package/dist/ToggleButton/ToggleButton.d.ts +7 -9
- package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButton.js +34 -57
- package/dist/Tokenizer/Tokenizer.d.ts +12 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +27 -5
- package/dist/Toolbar/Toolbar.d.ts +3 -3
- package/dist/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/Toolbar/Toolbar.js +51 -7
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +57 -9
- package/dist/TreeList/TreeList.d.ts +1 -1
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +72 -2
- package/dist/TreeList/TreeListItem.d.ts +11 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +51 -12
- package/dist/TreeList/treeListItem.markers.stylex.d.ts +16 -0
- package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +1 -0
- package/dist/TreeList/treeListItem.markers.stylex.js +22 -0
- package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +67 -6
- package/dist/Typeahead/Typeahead.d.ts +24 -1
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +29 -5
- package/dist/VisuallyHidden/VisuallyHidden.d.ts +61 -0
- package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
- package/dist/VisuallyHidden/VisuallyHidden.js +65 -0
- package/dist/VisuallyHidden/index.d.ts +11 -0
- package/dist/VisuallyHidden/index.d.ts.map +1 -0
- package/dist/VisuallyHidden/index.js +13 -0
- package/dist/astryx.css +40 -1
- package/dist/astryx.umd.js +147 -0
- package/dist/astryx.umd.js.map +7 -0
- package/dist/hooks/focusableSelector.d.ts +22 -0
- package/dist/hooks/focusableSelector.d.ts.map +1 -0
- package/dist/hooks/focusableSelector.js +24 -0
- package/dist/hooks/index.d.ts +12 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +7 -2
- package/dist/hooks/useAnnounce.d.ts +40 -0
- package/dist/hooks/useAnnounce.d.ts.map +1 -0
- package/dist/hooks/useAnnounce.js +142 -0
- package/dist/hooks/useClickableContainer.d.ts +16 -1
- package/dist/hooks/useClickableContainer.d.ts.map +1 -1
- package/dist/hooks/useClickableContainer.js +16 -4
- package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
- package/dist/hooks/useEntryAnimation.js +4 -4
- package/dist/hooks/useFocusTrap.d.ts +18 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +87 -3
- package/dist/hooks/useGridFocus.d.ts +88 -1
- package/dist/hooks/useGridFocus.d.ts.map +1 -1
- package/dist/hooks/useGridFocus.js +261 -62
- package/dist/hooks/useKeyboardHint.d.ts +82 -0
- package/dist/hooks/useKeyboardHint.d.ts.map +1 -0
- package/dist/hooks/useKeyboardHint.js +220 -0
- package/dist/hooks/useListFocus.d.ts +78 -7
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +305 -52
- package/dist/hooks/useLongPress.d.ts +21 -0
- package/dist/hooks/useLongPress.d.ts.map +1 -0
- package/dist/hooks/useLongPress.js +89 -0
- package/dist/hooks/useTreeFocus.d.ts +157 -0
- package/dist/hooks/useTreeFocus.d.ts.map +1 -0
- package/dist/hooks/useTreeFocus.js +337 -0
- package/dist/hooks/useTypeahead.d.ts +63 -0
- package/dist/hooks/useTypeahead.d.ts.map +1 -0
- package/dist/hooks/useTypeahead.js +117 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/generateThemeRules.js +1 -1
- package/dist/theme/syntax/SyntaxTheme.d.ts +1 -1
- package/dist/theme/syntax/SyntaxTheme.js +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.js +2 -2
- package/dist/theme/syntax/presets.d.ts +1 -1
- package/dist/theme/syntax/presets.d.ts.map +1 -1
- package/dist/theme/syntax/presets.js +1 -1
- package/dist/theme/syntax/tokens.d.ts +1 -1
- package/dist/theme/syntax/tokens.js +1 -1
- package/dist/theme/types.d.ts +1 -1
- package/dist/utils/dateTypes.d.ts +12 -0
- package/dist/utils/dateTypes.d.ts.map +1 -1
- package/dist/utils/dateTypes.js +41 -1
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/inputAria.d.ts +29 -0
- package/dist/utils/inputAria.d.ts.map +1 -0
- package/dist/utils/inputAria.js +30 -0
- package/dist/utils/timeParser.d.ts.map +1 -1
- package/dist/utils/timeParser.js +5 -2
- package/package.json +15 -5
- package/src/Avatar/Avatar.test.tsx +37 -0
- package/src/Avatar/Avatar.tsx +10 -5
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +3 -0
- package/src/Banner/Banner.doc.mjs +8 -0
- package/src/Banner/Banner.test.tsx +16 -7
- package/src/Banner/Banner.tsx +9 -2
- package/src/Breadcrumbs/BreadcrumbItem.tsx +25 -7
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -10
- package/src/Button/Button.doc.mjs +6 -0
- package/src/Button/Button.test.tsx +105 -11
- package/src/Button/Button.tsx +76 -21
- package/src/Calendar/Calendar.doc.mjs +4 -4
- package/src/Calendar/Calendar.test.tsx +168 -30
- package/src/Calendar/Calendar.tsx +121 -66
- package/src/Calendar/hooks/index.ts +0 -6
- package/src/Calendar/index.ts +1 -3
- package/src/Calendar/styles.ts +4 -9
- package/src/Carousel/Carousel.doc.mjs +7 -1
- package/src/Carousel/Carousel.test.tsx +20 -0
- package/src/Carousel/Carousel.tsx +16 -1
- package/src/Center/Center.doc.mjs +12 -2
- package/src/Center/Center.tsx +28 -3
- package/src/Chat/ChatComposer.doc.mjs +3 -0
- package/src/Chat/ChatComposerDrawer.doc.mjs +12 -0
- package/src/Chat/ChatMessageList.doc.mjs +8 -0
- package/src/Chat/ChatMessageList.test.tsx +18 -0
- package/src/Chat/ChatMessageList.tsx +16 -0
- package/src/Chat/useTriggerMenu.tsx +3 -0
- package/src/CheckboxInput/CheckboxInput.doc.mjs +18 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +172 -27
- package/src/CheckboxInput/CheckboxInput.tsx +78 -6
- package/src/CheckboxList/CheckboxList.doc.mjs +9 -0
- package/src/CheckboxList/CheckboxList.test.tsx +169 -16
- package/src/CheckboxList/CheckboxList.tsx +56 -3
- package/src/CheckboxList/CheckboxListContext.tsx +7 -0
- package/src/Citation/Citation.doc.mjs +10 -0
- package/src/Citation/Citation.test.tsx +117 -0
- package/src/Citation/Citation.tsx +9 -1
- package/src/ClickableCard/ClickableCard.doc.mjs +15 -0
- package/src/CodeBlock/CodeBlock.test.tsx +115 -0
- package/src/CodeBlock/CodeBlock.tsx +61 -33
- package/src/CommandPalette/CommandPalette.test.tsx +47 -1
- package/src/CommandPalette/CommandPalette.tsx +9 -21
- package/src/ContextMenu/ContextMenu.doc.mjs +4 -4
- package/src/ContextMenu/ContextMenu.test.tsx +155 -1
- package/src/ContextMenu/ContextMenu.tsx +113 -16
- package/src/DateInput/DateInput.doc.mjs +281 -56
- package/src/DateInput/DateInput.test.tsx +188 -2
- package/src/DateInput/DateInput.tsx +89 -10
- package/src/DateRangeInput/DateRangeInput.doc.mjs +251 -46
- package/src/DateRangeInput/DateRangeInput.test.tsx +182 -20
- package/src/DateRangeInput/DateRangeInput.tsx +63 -5
- package/src/DateTimeInput/DateTimeInput.doc.mjs +368 -67
- package/src/DateTimeInput/DateTimeInput.test.tsx +279 -11
- package/src/DateTimeInput/DateTimeInput.tsx +125 -17
- package/src/Dialog/Dialog.doc.mjs +2 -2
- package/src/Dialog/Dialog.tsx +12 -0
- package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -8
- package/src/DropdownMenu/DropdownMenu.test.tsx +56 -42
- package/src/DropdownMenu/DropdownMenu.tsx +52 -18
- package/src/EmptyState/EmptyState.test.tsx +4 -2
- package/src/EmptyState/EmptyState.tsx +6 -2
- package/src/Field/Field.test.tsx +32 -0
- package/src/Field/Field.tsx +23 -5
- package/src/Field/FieldLabel.tsx +55 -17
- package/src/FileInput/FileInput.doc.mjs +17 -0
- package/src/FileInput/FileInput.test.tsx +283 -49
- package/src/FileInput/FileInput.tsx +76 -4
- package/src/Grid/Grid.doc.mjs +14 -4
- package/src/Grid/Grid.tsx +20 -0
- package/src/HoverCard/HoverCard.doc.mjs +3 -0
- package/src/HoverCard/HoverCard.test.tsx +189 -2
- package/src/HoverCard/HoverCard.tsx +20 -16
- package/src/HoverCard/useHoverCard.tsx +13 -10
- package/src/Icon/Icon.doc.mjs +8 -0
- package/src/InputGroup/InputGroup.doc.mjs +2 -2
- package/src/InputGroup/InputGroup.test.tsx +98 -60
- package/src/InputGroup/InputGroup.tsx +21 -4
- package/src/InputGroup/InputGroupContext.ts +9 -4
- package/src/InputGroup/index.ts +1 -0
- package/src/Kbd/Kbd.test.tsx +22 -4
- package/src/Kbd/Kbd.tsx +37 -12
- package/src/Layer/anchorName.test.ts +146 -0
- package/src/Layer/anchorName.ts +46 -0
- package/src/Layer/layerAnimations.stylex.ts +20 -4
- package/src/Layer/useLayer.doc.mjs +12 -2
- package/src/Layer/useLayer.tsx +100 -15
- package/src/Layout/Layout.doc.mjs +1 -1
- package/src/Layout/Layout.tsx +8 -16
- package/src/Layout/LayoutFooter.doc.mjs +4 -4
- package/src/Layout/LayoutFooter.tsx +3 -3
- package/src/Layout/LayoutHeader.doc.mjs +4 -4
- package/src/Layout/LayoutHeader.tsx +3 -3
- package/src/Layout/LayoutPanel.tsx +3 -3
- package/src/Layout/padding.stylex.ts +52 -0
- package/src/Lightbox/Lightbox.doc.mjs +9 -2
- package/src/Lightbox/Lightbox.test.tsx +53 -5
- package/src/Lightbox/Lightbox.tsx +9 -4
- package/src/Link/Link.doc.mjs +14 -0
- package/src/Link/Link.test.tsx +52 -2
- package/src/Link/Link.tsx +42 -7
- package/src/Link/LinkProvider.tsx +1 -0
- package/src/List/List.doc.mjs +7 -0
- package/src/Markdown/Markdown.doc.mjs +2 -0
- package/src/Markdown/Markdown.test.tsx +28 -26
- package/src/Markdown/Markdown.tsx +21 -6
- package/src/MetadataList/MetadataListItem.doc.mjs +4 -0
- package/src/MobileNav/MobileNav.doc.mjs +8 -8
- package/src/MobileNav/MobileNav.tsx +13 -0
- package/src/MobileNav/MobileNavReopen.test.tsx +118 -0
- package/src/MoreMenu/MoreMenu.doc.mjs +2 -17
- package/src/MoreMenu/MoreMenu.tsx +0 -9
- package/src/MultiSelector/MultiSelector.doc.mjs +25 -0
- package/src/MultiSelector/MultiSelector.test.tsx +375 -8
- package/src/MultiSelector/MultiSelector.tsx +145 -21
- package/src/MultiSelector/hooks.ts +27 -0
- package/src/NavMenu/NavHeadingMenu.test.tsx +77 -1
- package/src/NavMenu/NavHeadingMenu.tsx +50 -3
- package/src/NumberInput/NumberInput.doc.mjs +17 -0
- package/src/NumberInput/NumberInput.test.tsx +242 -40
- package/src/NumberInput/NumberInput.tsx +89 -11
- package/src/OverflowList/OverflowList.doc.mjs +17 -0
- package/src/Pagination/Pagination.doc.mjs +3 -3
- package/src/Pagination/Pagination.test.tsx +250 -14
- package/src/Pagination/Pagination.tsx +54 -29
- package/src/Popover/usePopover.doc.mjs +7 -3
- package/src/Popover/usePopover.tsx +49 -6
- package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
- package/src/PowerSearch/PowerSearch.test.tsx +97 -1
- package/src/PowerSearch/PowerSearch.tsx +16 -3
- package/src/ProgressBar/ProgressBar.test.tsx +45 -27
- package/src/ProgressBar/ProgressBar.tsx +3 -4
- package/src/RadioList/RadioList.doc.mjs +9 -0
- package/src/RadioList/RadioList.test.tsx +252 -16
- package/src/RadioList/RadioList.tsx +166 -10
- package/src/RadioList/RadioListItem.tsx +14 -2
- package/src/Resizable/Resizable.doc.mjs +1 -1
- package/src/Section/Section.doc.mjs +11 -0
- package/src/SegmentedControl/SegmentedControl.doc.mjs +9 -0
- package/src/SegmentedControl/SegmentedControl.test.tsx +214 -42
- package/src/SegmentedControl/SegmentedControl.tsx +102 -54
- package/src/SegmentedControl/SegmentedControlContext.ts +7 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +14 -1
- package/src/SelectableCard/SelectableCard.doc.mjs +15 -0
- package/src/Selector/Selector.doc.mjs +25 -0
- package/src/Selector/Selector.test.tsx +322 -15
- package/src/Selector/Selector.tsx +126 -40
- package/src/Selector/hooks.ts +23 -0
- package/src/SideNav/SideNav.test.tsx +16 -0
- package/src/SideNav/SideNavItem.tsx +2 -4
- package/src/Skeleton/Skeleton.doc.mjs +11 -1
- package/src/Skeleton/Skeleton.test.tsx +25 -0
- package/src/Skeleton/Skeleton.tsx +11 -1
- package/src/Slider/Slider.doc.mjs +19 -0
- package/src/Slider/Slider.test.tsx +158 -18
- package/src/Slider/Slider.tsx +54 -6
- package/src/Spinner/Spinner.tsx +7 -1
- package/src/Stack/Stack.doc.mjs +77 -0
- package/src/Stack/Stack.test.tsx +55 -5
- package/src/Stack/Stack.tsx +73 -24
- package/src/Stack/StackItem.test.tsx +23 -0
- package/src/Stack/StackItem.tsx +20 -23
- package/src/Switch/Switch.doc.mjs +15 -0
- package/src/Switch/Switch.test.tsx +162 -27
- package/src/Switch/Switch.tsx +61 -21
- package/src/TabList/Tab.tsx +6 -0
- package/src/TabList/TabList.doc.mjs +12 -0
- package/src/TabList/TabList.test.tsx +208 -0
- package/src/TabList/TabList.tsx +102 -12
- package/src/TabList/TabListContext.ts +7 -3
- package/src/TabList/TabMenu.tsx +6 -3
- package/src/Table/BaseTable.tsx +72 -41
- package/src/Table/Table.doc.mjs +14 -0
- package/src/Table/Table.test.tsx +39 -30
- package/src/Table/Table.tsx +27 -1
- package/src/Table/TableCell.tsx +25 -23
- package/src/Table/TableHeaderCell.tsx +28 -29
- package/src/Table/TableRow.tsx +37 -7
- package/src/Table/index.ts +6 -2
- package/src/Table/plugins/pagination/paginateData.ts +10 -3
- package/src/Table/plugins/pagination/useTablePagination.test.tsx +16 -0
- package/src/Table/plugins/pagination/useTablePagination.tsx +8 -1
- package/src/Table/plugins/sortable/useTableSortable.test.tsx +91 -2
- package/src/Table/plugins/sortable/useTableSortable.tsx +53 -1
- package/src/Table/plugins/stickyColumns/index.ts +4 -0
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.test.tsx +163 -0
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +407 -0
- package/src/Table/tableContextMenu.test.tsx +157 -0
- package/src/Table/tableContextMenu.tsx +142 -0
- package/src/Table/types.ts +175 -4
- package/src/Table/useBaseTablePlugins.ts +1 -0
- package/src/Table/useTableColumnResize.doc.mjs +96 -0
- package/src/Table/useTableStickyColumns.doc.mjs +59 -0
- package/src/Text/Heading.doc.mjs +15 -2
- package/src/Text/Text.doc.mjs +7 -1
- package/src/Text/text.stylex.ts +2 -2
- package/src/TextArea/TextArea.doc.mjs +17 -0
- package/src/TextArea/TextArea.test.tsx +167 -35
- package/src/TextArea/TextArea.tsx +62 -15
- package/src/TextInput/TextInput.doc.mjs +17 -0
- package/src/TextInput/TextInput.test.tsx +168 -34
- package/src/TextInput/TextInput.tsx +77 -9
- package/src/TimeInput/TimeInput.doc.mjs +335 -60
- package/src/TimeInput/TimeInput.test.tsx +144 -7
- package/src/TimeInput/TimeInput.tsx +74 -5
- package/src/Timestamp/Timestamp.doc.mjs +9 -0
- package/src/Timestamp/Timestamp.test.tsx +44 -18
- package/src/Timestamp/Timestamp.tsx +30 -10
- package/src/Toast/Toast.tsx +14 -0
- package/src/Toast/ToastViewport.test.tsx +204 -0
- package/src/Toast/ToastViewport.tsx +167 -21
- package/src/ToggleButton/ToggleButton.doc.mjs +9 -3
- package/src/ToggleButton/ToggleButton.test.tsx +39 -18
- package/src/ToggleButton/ToggleButton.tsx +46 -83
- package/src/Tokenizer/Tokenizer.doc.mjs +15 -0
- package/src/Tokenizer/Tokenizer.test.tsx +105 -1
- package/src/Tokenizer/Tokenizer.tsx +41 -2
- package/src/Toolbar/Toolbar.doc.mjs +65 -5
- package/src/Toolbar/Toolbar.test.tsx +109 -6
- package/src/Toolbar/Toolbar.tsx +59 -5
- package/src/Tooltip/Tooltip.test.tsx +81 -0
- package/src/Tooltip/useTooltip.tsx +57 -11
- package/src/TreeList/TreeList.test.tsx +295 -6
- package/src/TreeList/TreeList.tsx +73 -1
- package/src/TreeList/TreeListItem.tsx +51 -5
- package/src/TreeList/treeListItem.markers.stylex.ts +20 -0
- package/src/Typeahead/BaseTypeahead.tsx +86 -9
- package/src/Typeahead/Typeahead.doc.mjs +136 -30
- package/src/Typeahead/Typeahead.test.tsx +331 -1
- package/src/Typeahead/Typeahead.tsx +52 -1
- package/src/VisuallyHidden/VisuallyHidden.doc.mjs +80 -0
- package/src/VisuallyHidden/VisuallyHidden.test.tsx +76 -0
- package/src/VisuallyHidden/VisuallyHidden.tsx +113 -0
- package/src/VisuallyHidden/index.ts +15 -0
- package/src/hooks/focusableSelector.ts +25 -0
- package/src/hooks/index.ts +28 -2
- package/src/hooks/useAnnounce.test.tsx +101 -0
- package/src/hooks/useAnnounce.ts +168 -0
- package/src/hooks/useClickableContainer.ts +16 -4
- package/src/hooks/useEntryAnimation.ts +16 -4
- package/src/hooks/useFocusTrap.test.tsx +132 -0
- package/src/hooks/useFocusTrap.ts +98 -4
- package/src/hooks/useGridFocus.doc.mjs +40 -2
- package/src/hooks/useGridFocus.test.tsx +132 -0
- package/src/hooks/useGridFocus.ts +343 -67
- package/src/hooks/useImageMode.test.ts +133 -0
- package/src/hooks/useKeyboardHint.doc.mjs +101 -0
- package/src/hooks/useKeyboardHint.test.tsx +70 -0
- package/src/hooks/useKeyboardHint.tsx +332 -0
- package/src/hooks/useListFocus.doc.mjs +50 -10
- package/src/hooks/useListFocus.test.tsx +375 -0
- package/src/hooks/useListFocus.ts +395 -57
- package/src/hooks/useLongPress.test.tsx +134 -0
- package/src/hooks/useLongPress.ts +119 -0
- package/src/hooks/useTreeFocus.doc.mjs +140 -0
- package/src/hooks/useTreeFocus.test.tsx +214 -0
- package/src/hooks/useTreeFocus.ts +559 -0
- package/src/hooks/useTypeahead.test.tsx +109 -0
- package/src/hooks/useTypeahead.ts +183 -0
- package/src/index.ts +1 -0
- package/src/theme/derivedVarRegistry.test.ts +4 -0
- package/src/theme/generateThemeRules.test.ts +7 -8
- package/src/theme/generateThemeRules.ts +1 -1
- package/src/theme/syntax/SyntaxTheme.tsx +1 -1
- package/src/theme/syntax/defineSyntaxTheme.ts +20 -11
- package/src/theme/syntax/presets.ts +5 -2
- package/src/theme/syntax/tokens.ts +1 -1
- package/src/theme/types.ts +1 -1
- package/src/utils/dateTypes.test.ts +40 -0
- package/src/utils/dateTypes.ts +40 -0
- package/src/utils/index.ts +9 -0
- package/src/utils/inputAria.test.ts +39 -0
- package/src/utils/inputAria.ts +58 -0
- package/src/utils/timeParser.test.ts +10 -0
- package/src/utils/timeParser.ts +5 -2
- package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts +0 -57
- package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts.map +0 -1
- package/dist/Calendar/hooks/useCalendarRovingTabindex.js +0 -96
- package/src/Calendar/hooks/useCalendarRovingTabindex.ts +0 -118
|
@@ -179,11 +179,16 @@ export function BreadcrumbItem({
|
|
|
179
179
|
className,
|
|
180
180
|
style,
|
|
181
181
|
'data-testid': testId,
|
|
182
|
+
...rest
|
|
182
183
|
}: BreadcrumbItemProps) {
|
|
183
184
|
const ctx = use(BreadcrumbContext);
|
|
184
185
|
const LinkComponent = useLinkComponent(as);
|
|
185
186
|
const isSupporting = ctx.variant === 'supporting';
|
|
186
187
|
const liRef = useRef<HTMLLIElement>(null);
|
|
188
|
+
// Points at the element we render to hold the item's content (the
|
|
189
|
+
// link/button/span in the auto-candidate path). Auto-current detection sets
|
|
190
|
+
// aria-current on this instead of guessing the <li>'s last child.
|
|
191
|
+
const contentRef = useRef<HTMLElement>(null);
|
|
187
192
|
|
|
188
193
|
const isCurrent = isCurrentProp === true;
|
|
189
194
|
const isAutoCandidate = isCurrentProp == null;
|
|
@@ -191,6 +196,10 @@ export function BreadcrumbItem({
|
|
|
191
196
|
// Auto-detect: if no sibling has aria-current="page" and this is the last
|
|
192
197
|
// non-separator item, set aria-current on our content element.
|
|
193
198
|
// Runs as useEffect (not layout) — only sets an aria attribute, no visual change.
|
|
199
|
+
// Placed on the item's content element (the link/button/span after the
|
|
200
|
+
// separator), matching where the explicit `isCurrent` path sets it, so
|
|
201
|
+
// aria-current lands on the actual interactive element — including when the
|
|
202
|
+
// last item is a link — rather than on the outer <li> (navigation-11).
|
|
194
203
|
useEffect(() => {
|
|
195
204
|
if (!isAutoCandidate) {
|
|
196
205
|
return;
|
|
@@ -211,12 +220,16 @@ export function BreadcrumbItem({
|
|
|
211
220
|
const hasExplicit = ol.querySelector('[aria-current="page"]');
|
|
212
221
|
|
|
213
222
|
if (isLast && !hasExplicit) {
|
|
214
|
-
|
|
223
|
+
// We control the element that holds the content (see the auto-candidate
|
|
224
|
+
// render path below), so set aria-current on that ref rather than
|
|
225
|
+
// assuming a positional last child. Fall back to the <li> only if the
|
|
226
|
+
// ref is somehow unresolved.
|
|
227
|
+
const target = contentRef.current ?? li;
|
|
228
|
+
target.setAttribute('aria-current', 'page');
|
|
229
|
+
return () => {
|
|
230
|
+
target.removeAttribute('aria-current');
|
|
231
|
+
};
|
|
215
232
|
}
|
|
216
|
-
|
|
217
|
-
return () => {
|
|
218
|
-
li.removeAttribute('aria-current');
|
|
219
|
-
};
|
|
220
233
|
});
|
|
221
234
|
|
|
222
235
|
const content = (
|
|
@@ -240,7 +253,8 @@ export function BreadcrumbItem({
|
|
|
240
253
|
className,
|
|
241
254
|
style,
|
|
242
255
|
)}
|
|
243
|
-
data-testid={testId}
|
|
256
|
+
data-testid={testId}
|
|
257
|
+
{...rest}>
|
|
244
258
|
<span aria-hidden="true" {...stylex.props(itemStyles.separator)}>
|
|
245
259
|
{ctx.separator}
|
|
246
260
|
</span>
|
|
@@ -274,12 +288,14 @@ export function BreadcrumbItem({
|
|
|
274
288
|
className,
|
|
275
289
|
style,
|
|
276
290
|
)}
|
|
277
|
-
data-testid={testId}
|
|
291
|
+
data-testid={testId}
|
|
292
|
+
{...rest}>
|
|
278
293
|
<span aria-hidden="true" {...stylex.props(itemStyles.separator)}>
|
|
279
294
|
{ctx.separator}
|
|
280
295
|
</span>
|
|
281
296
|
{href != null ? (
|
|
282
297
|
<LinkComponent
|
|
298
|
+
ref={contentRef}
|
|
283
299
|
href={href}
|
|
284
300
|
onClick={onClick}
|
|
285
301
|
{...stylex.props(
|
|
@@ -290,6 +306,7 @@ export function BreadcrumbItem({
|
|
|
290
306
|
</LinkComponent>
|
|
291
307
|
) : onClick != null ? (
|
|
292
308
|
<button
|
|
309
|
+
ref={contentRef as React.RefObject<HTMLButtonElement | null>}
|
|
293
310
|
type="button"
|
|
294
311
|
onClick={onClick}
|
|
295
312
|
{...stylex.props(
|
|
@@ -301,6 +318,7 @@ export function BreadcrumbItem({
|
|
|
301
318
|
</button>
|
|
302
319
|
) : (
|
|
303
320
|
<span
|
|
321
|
+
ref={contentRef}
|
|
304
322
|
{...stylex.props(
|
|
305
323
|
itemStyles.contentWrapper,
|
|
306
324
|
itemStyles.current,
|
|
@@ -180,12 +180,31 @@ describe('BreadcrumbItem', () => {
|
|
|
180
180
|
<BreadcrumbItem>Last Item</BreadcrumbItem>
|
|
181
181
|
</Breadcrumbs>,
|
|
182
182
|
);
|
|
183
|
-
// aria-current is set via useEffect
|
|
184
|
-
|
|
183
|
+
// aria-current is set via useEffect on the content element (matching the
|
|
184
|
+
// explicit isCurrent path), not the outer <li>.
|
|
185
|
+
const lastContent = screen.getByText('Last Item');
|
|
185
186
|
await waitFor(() => {
|
|
186
|
-
expect(
|
|
187
|
+
expect(lastContent).toHaveAttribute('aria-current', 'page');
|
|
187
188
|
});
|
|
188
|
-
expect(
|
|
189
|
+
expect(lastContent.tagName).toBe('SPAN');
|
|
190
|
+
// The <li> wrapper must NOT carry aria-current.
|
|
191
|
+
expect(lastContent.closest('li')).not.toHaveAttribute('aria-current');
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('auto-detects aria-current on the anchor when the last item is a link', async () => {
|
|
195
|
+
render(
|
|
196
|
+
<Breadcrumbs>
|
|
197
|
+
<BreadcrumbItem href="/">Home</BreadcrumbItem>
|
|
198
|
+
<BreadcrumbItem href="/projects/current">Current</BreadcrumbItem>
|
|
199
|
+
</Breadcrumbs>,
|
|
200
|
+
);
|
|
201
|
+
const lastLink = screen.getByText('Current');
|
|
202
|
+
await waitFor(() => {
|
|
203
|
+
expect(lastLink).toHaveAttribute('aria-current', 'page');
|
|
204
|
+
});
|
|
205
|
+
// aria-current is on the anchor itself, not the <li>.
|
|
206
|
+
expect(lastLink.tagName).toBe('A');
|
|
207
|
+
expect(lastLink.closest('li')).not.toHaveAttribute('aria-current');
|
|
189
208
|
});
|
|
190
209
|
|
|
191
210
|
it('does not auto-detect when isCurrent is explicitly set', async () => {
|
|
@@ -270,11 +289,12 @@ describe('BreadcrumbItem', () => {
|
|
|
270
289
|
<BreadcrumbItem>Only Item</BreadcrumbItem>
|
|
271
290
|
</Breadcrumbs>,
|
|
272
291
|
);
|
|
273
|
-
const
|
|
292
|
+
const content = screen.getByText('Only Item');
|
|
274
293
|
await waitFor(() => {
|
|
275
|
-
expect(
|
|
294
|
+
expect(content).toHaveAttribute('aria-current', 'page');
|
|
276
295
|
});
|
|
277
|
-
expect(
|
|
296
|
+
expect(content.tagName).toBe('SPAN');
|
|
297
|
+
expect(content.closest('li')).not.toHaveAttribute('aria-current');
|
|
278
298
|
});
|
|
279
299
|
|
|
280
300
|
it('auto-detects last child as current with supporting variant', async () => {
|
|
@@ -284,11 +304,12 @@ describe('BreadcrumbItem', () => {
|
|
|
284
304
|
<BreadcrumbItem>Last</BreadcrumbItem>
|
|
285
305
|
</Breadcrumbs>,
|
|
286
306
|
);
|
|
287
|
-
const
|
|
307
|
+
const content = screen.getByText('Last');
|
|
288
308
|
await waitFor(() => {
|
|
289
|
-
expect(
|
|
309
|
+
expect(content).toHaveAttribute('aria-current', 'page');
|
|
290
310
|
});
|
|
291
|
-
expect(
|
|
311
|
+
expect(content.tagName).toBe('SPAN');
|
|
312
|
+
expect(content.closest('li')).not.toHaveAttribute('aria-current');
|
|
292
313
|
});
|
|
293
314
|
|
|
294
315
|
it('renders custom component for non-current items when as is provided', () => {
|
|
@@ -78,6 +78,12 @@ export const docs = {
|
|
|
78
78
|
description: 'Shows a loading spinner and disables interaction. Announces "Loading" via a live region.',
|
|
79
79
|
default: 'false',
|
|
80
80
|
},
|
|
81
|
+
{
|
|
82
|
+
name: 'isInterruptible',
|
|
83
|
+
type: 'boolean',
|
|
84
|
+
description: 'Keep the button clickable while a clickAction is pending: the spinner and aria-busy still show, but the button is not disabled and the action is not deduped, so a re-click lands and interrupts the in-flight action with a fresh one.',
|
|
85
|
+
default: 'false',
|
|
86
|
+
},
|
|
81
87
|
{
|
|
82
88
|
name: 'isDisabled',
|
|
83
89
|
type: 'boolean',
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import {describe, it, expect, vi} from 'vitest';
|
|
13
|
-
import {render, screen} from '@testing-library/react';
|
|
13
|
+
import {render, screen, fireEvent, act} from '@testing-library/react';
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
15
|
import {Button} from './Button';
|
|
16
16
|
import {Badge} from '../Badge/Badge';
|
|
@@ -71,6 +71,32 @@ describe('Button', () => {
|
|
|
71
71
|
expect(button).toBeDisabled();
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
+
it('sets aria-busy synchronously while clickAction is pending', async () => {
|
|
75
|
+
// The spinner reveal is visually delayed (CSS animation-delay), but the
|
|
76
|
+
// loading DOM state — aria-busy and disabled — must not be delayed.
|
|
77
|
+
const user = userEvent.setup();
|
|
78
|
+
let resolveAction: (() => void) | undefined;
|
|
79
|
+
const clickAction = vi.fn(
|
|
80
|
+
async () =>
|
|
81
|
+
new Promise<void>(resolve => {
|
|
82
|
+
resolveAction = resolve;
|
|
83
|
+
}),
|
|
84
|
+
);
|
|
85
|
+
render(<Button label="Save" clickAction={clickAction} />);
|
|
86
|
+
const button = screen.getByRole('button');
|
|
87
|
+
|
|
88
|
+
await user.click(button);
|
|
89
|
+
expect(button).toHaveAttribute('aria-busy', 'true');
|
|
90
|
+
expect(button).toBeDisabled();
|
|
91
|
+
|
|
92
|
+
await act(async () => {
|
|
93
|
+
resolveAction?.();
|
|
94
|
+
await Promise.resolve();
|
|
95
|
+
});
|
|
96
|
+
expect(button).not.toHaveAttribute('aria-busy', 'true');
|
|
97
|
+
expect(button).not.toBeDisabled();
|
|
98
|
+
});
|
|
99
|
+
|
|
74
100
|
it('renders the loading spinner with the inherit shade for every variant (#2717)', () => {
|
|
75
101
|
// The spinner must follow the button's resolved foreground color rather
|
|
76
102
|
// than a hardcoded white, so it keeps contrast on themed variants like the
|
|
@@ -228,11 +254,7 @@ describe('Button', () => {
|
|
|
228
254
|
order.push('clickAction');
|
|
229
255
|
});
|
|
230
256
|
render(
|
|
231
|
-
<Button
|
|
232
|
-
label="Test"
|
|
233
|
-
onClick={handleClick}
|
|
234
|
-
clickAction={handleAction}
|
|
235
|
-
/>,
|
|
257
|
+
<Button label="Test" onClick={handleClick} clickAction={handleAction} />,
|
|
236
258
|
);
|
|
237
259
|
|
|
238
260
|
await user.click(screen.getByRole('button'));
|
|
@@ -246,11 +268,7 @@ describe('Button', () => {
|
|
|
246
268
|
const handleClick = vi.fn((e: React.MouseEvent) => e.preventDefault());
|
|
247
269
|
const handleAction = vi.fn();
|
|
248
270
|
render(
|
|
249
|
-
<Button
|
|
250
|
-
label="Test"
|
|
251
|
-
onClick={handleClick}
|
|
252
|
-
clickAction={handleAction}
|
|
253
|
-
/>,
|
|
271
|
+
<Button label="Test" onClick={handleClick} clickAction={handleAction} />,
|
|
254
272
|
);
|
|
255
273
|
|
|
256
274
|
await user.click(screen.getByRole('button'));
|
|
@@ -258,6 +276,82 @@ describe('Button', () => {
|
|
|
258
276
|
expect(handleAction).not.toHaveBeenCalled();
|
|
259
277
|
});
|
|
260
278
|
|
|
279
|
+
it('fires clickAction once on a fast double-click (no double-submit)', async () => {
|
|
280
|
+
let resolveAction: (() => void) | undefined;
|
|
281
|
+
const handleAction = vi.fn(
|
|
282
|
+
async () =>
|
|
283
|
+
new Promise<void>(resolve => {
|
|
284
|
+
resolveAction = resolve;
|
|
285
|
+
}),
|
|
286
|
+
);
|
|
287
|
+
render(<Button label="Pay" clickAction={handleAction} />);
|
|
288
|
+
|
|
289
|
+
const button = screen.getByRole('button');
|
|
290
|
+
await act(async () => {
|
|
291
|
+
fireEvent.click(button);
|
|
292
|
+
fireEvent.click(button);
|
|
293
|
+
});
|
|
294
|
+
expect(handleAction).toHaveBeenCalledTimes(1);
|
|
295
|
+
|
|
296
|
+
await act(async () => {
|
|
297
|
+
resolveAction?.();
|
|
298
|
+
await Promise.resolve();
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('stays clickable (not disabled) while a clickAction is pending when isInterruptible', async () => {
|
|
303
|
+
const user = userEvent.setup();
|
|
304
|
+
let resolveAction: (() => void) | undefined;
|
|
305
|
+
const clickAction = vi.fn(
|
|
306
|
+
async () =>
|
|
307
|
+
new Promise<void>(resolve => {
|
|
308
|
+
resolveAction = resolve;
|
|
309
|
+
}),
|
|
310
|
+
);
|
|
311
|
+
render(<Button label="Toggle" isInterruptible clickAction={clickAction} />);
|
|
312
|
+
const button = screen.getByRole('button');
|
|
313
|
+
|
|
314
|
+
await user.click(button);
|
|
315
|
+
// Loading is announced via aria-busy, but the button is not disabled so it
|
|
316
|
+
// can be re-clicked to interrupt the in-flight action.
|
|
317
|
+
expect(button).toHaveAttribute('aria-busy', 'true');
|
|
318
|
+
expect(button).not.toBeDisabled();
|
|
319
|
+
|
|
320
|
+
await act(async () => {
|
|
321
|
+
resolveAction?.();
|
|
322
|
+
await Promise.resolve();
|
|
323
|
+
});
|
|
324
|
+
expect(button).not.toHaveAttribute('aria-busy', 'true');
|
|
325
|
+
expect(button).not.toBeDisabled();
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('re-fires clickAction on re-click while pending when isInterruptible (no dedupe)', async () => {
|
|
329
|
+
// Unlike the fire-once default, an interruptible action is not deduped: a
|
|
330
|
+
// re-click while pending starts a fresh action that interrupts the prior.
|
|
331
|
+
const resolvers: (() => void)[] = [];
|
|
332
|
+
const clickAction = vi.fn(
|
|
333
|
+
async () =>
|
|
334
|
+
new Promise<void>(resolve => {
|
|
335
|
+
resolvers.push(resolve);
|
|
336
|
+
}),
|
|
337
|
+
);
|
|
338
|
+
render(<Button label="Toggle" isInterruptible clickAction={clickAction} />);
|
|
339
|
+
|
|
340
|
+
const button = screen.getByRole('button');
|
|
341
|
+
await act(async () => {
|
|
342
|
+
fireEvent.click(button);
|
|
343
|
+
});
|
|
344
|
+
await act(async () => {
|
|
345
|
+
fireEvent.click(button);
|
|
346
|
+
});
|
|
347
|
+
expect(clickAction).toHaveBeenCalledTimes(2);
|
|
348
|
+
|
|
349
|
+
await act(async () => {
|
|
350
|
+
resolvers.forEach(resolve => resolve());
|
|
351
|
+
await Promise.resolve();
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
|
|
261
355
|
// type/name/value/form props
|
|
262
356
|
it('defaults type to button', () => {
|
|
263
357
|
render(<Button label="Test" />);
|
package/src/Button/Button.tsx
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* - /apps/storybook/stories/Button.stories.tsx (storybook stories)
|
|
16
16
|
* - /packages/cli/templates/blocks/components/Button/ (showcase blocks)
|
|
17
17
|
*
|
|
18
|
-
* Last synced props: label, variant, size, isDisabled, isLoading, clickAction, icon, isIconOnly, children, tooltip, endContent, href, as, target, rel
|
|
18
|
+
* Last synced props: label, variant, size, isDisabled, isLoading, isInterruptible, clickAction, icon, isIconOnly, children, tooltip, endContent, href, as, target, rel
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import {useRef, useTransition, type ReactNode} from 'react';
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
} from '../theme/tokens.stylex';
|
|
35
35
|
import {Tooltip} from '../Tooltip/Tooltip';
|
|
36
36
|
import {Spinner} from '../Spinner';
|
|
37
|
+
import {VisuallyHidden} from '../VisuallyHidden';
|
|
37
38
|
|
|
38
39
|
import {EDGE_COMP_ATTR} from '../Layout/edgeCompensation.stylex';
|
|
39
40
|
import {useSize} from '../SizeContext/SizeContext';
|
|
@@ -124,17 +125,6 @@ const styles = stylex.create({
|
|
|
124
125
|
textOverflow: 'ellipsis',
|
|
125
126
|
minWidth: 0,
|
|
126
127
|
},
|
|
127
|
-
visuallyHidden: {
|
|
128
|
-
position: 'absolute',
|
|
129
|
-
width: '1px',
|
|
130
|
-
height: '1px',
|
|
131
|
-
padding: 0,
|
|
132
|
-
margin: '-1px',
|
|
133
|
-
overflow: 'hidden',
|
|
134
|
-
clip: 'rect(0, 0, 0, 0)',
|
|
135
|
-
whiteSpace: 'nowrap',
|
|
136
|
-
borderWidth: 0,
|
|
137
|
-
},
|
|
138
128
|
link: {
|
|
139
129
|
textDecoration: 'none',
|
|
140
130
|
},
|
|
@@ -320,6 +310,16 @@ export interface ButtonProps extends BaseProps<HTMLButtonElement> {
|
|
|
320
310
|
* @default false
|
|
321
311
|
*/
|
|
322
312
|
isLoading?: boolean;
|
|
313
|
+
/**
|
|
314
|
+
* Keep the button interactive while a `clickAction` is pending. The loading
|
|
315
|
+
* state still renders the spinner and `aria-busy`, but the button is not
|
|
316
|
+
* disabled and the in-flight action is not deduped — so a re-click lands and
|
|
317
|
+
* interrupts the previous action with a fresh one. Use for interruptible
|
|
318
|
+
* actions (e.g. a toggle whose action can be re-triggered before the previous
|
|
319
|
+
* one settles), not fire-once actions (submit/save/pay).
|
|
320
|
+
* @default false
|
|
321
|
+
*/
|
|
322
|
+
isInterruptible?: boolean;
|
|
323
323
|
/**
|
|
324
324
|
* Click handler. For async actions that should show a loading state,
|
|
325
325
|
* use `clickAction` instead.
|
|
@@ -380,6 +380,22 @@ export interface ButtonProps extends BaseProps<HTMLButtonElement> {
|
|
|
380
380
|
rel?: string;
|
|
381
381
|
}
|
|
382
382
|
|
|
383
|
+
const spinnerReveal = stylex.keyframes({
|
|
384
|
+
from: {opacity: 0},
|
|
385
|
+
to: {opacity: 1},
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
const contentHide = stylex.keyframes({
|
|
389
|
+
from: {color: 'inherit'},
|
|
390
|
+
to: {color: 'transparent'},
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Hold the loading swap for a short delay so a fast action (e.g. clickAction)
|
|
394
|
+
// that settles within the delay never flashes a spinner. The spinner fade-in
|
|
395
|
+
// and the content hide share the same delay so the button never shows an empty
|
|
396
|
+
// frame in between. Reduced motion is instant.
|
|
397
|
+
const SPINNER_DELAY = durationVars['--duration-medium-min'];
|
|
398
|
+
|
|
383
399
|
const loadingStyles = stylex.create({
|
|
384
400
|
// Hide the button's own content while the spinner overlay is shown. Applied
|
|
385
401
|
// to the content wrapper (not the button) so the button keeps its variant
|
|
@@ -387,6 +403,17 @@ const loadingStyles = stylex.create({
|
|
|
387
403
|
hiddenContent: {
|
|
388
404
|
color: 'transparent',
|
|
389
405
|
},
|
|
406
|
+
// Delayed variant: keep content visible, then hide it in lockstep with the
|
|
407
|
+
// spinner reveal once the delay elapses.
|
|
408
|
+
hiddenContentDelayed: {
|
|
409
|
+
animationName: contentHide,
|
|
410
|
+
animationDuration: '1ms',
|
|
411
|
+
animationFillMode: 'forwards',
|
|
412
|
+
animationDelay: {
|
|
413
|
+
default: SPINNER_DELAY,
|
|
414
|
+
'@media (prefers-reduced-motion: reduce)': '0s',
|
|
415
|
+
},
|
|
416
|
+
},
|
|
390
417
|
spinnerOverlay: {
|
|
391
418
|
position: 'absolute',
|
|
392
419
|
top: 0,
|
|
@@ -396,6 +423,15 @@ const loadingStyles = stylex.create({
|
|
|
396
423
|
display: 'grid',
|
|
397
424
|
placeItems: 'center',
|
|
398
425
|
},
|
|
426
|
+
spinnerDelayed: {
|
|
427
|
+
animationName: spinnerReveal,
|
|
428
|
+
animationDuration: durationVars['--duration-fast'],
|
|
429
|
+
animationFillMode: 'backwards',
|
|
430
|
+
animationDelay: {
|
|
431
|
+
default: SPINNER_DELAY,
|
|
432
|
+
'@media (prefers-reduced-motion: reduce)': '0s',
|
|
433
|
+
},
|
|
434
|
+
},
|
|
399
435
|
});
|
|
400
436
|
|
|
401
437
|
const groupStyles = stylex.create({
|
|
@@ -493,6 +529,7 @@ export function Button({
|
|
|
493
529
|
type = 'button',
|
|
494
530
|
isDisabled = false,
|
|
495
531
|
isLoading = false,
|
|
532
|
+
isInterruptible = false,
|
|
496
533
|
clickAction,
|
|
497
534
|
icon,
|
|
498
535
|
isIconOnly = false,
|
|
@@ -513,10 +550,23 @@ export function Button({
|
|
|
513
550
|
const buttonGroup = useButtonGroup();
|
|
514
551
|
|
|
515
552
|
const [isPending, startTransition] = useTransition();
|
|
553
|
+
// clickAction is normally fire-once (submit/save/pay), so a same-tick
|
|
554
|
+
// double-click must dedupe — which neither isPending nor useOptimistic do.
|
|
555
|
+
// Hence the ref guard. Interruptible callers (e.g. ToggleButton) opt out so a
|
|
556
|
+
// re-click can land and interrupt the in-flight action with a fresh one.
|
|
516
557
|
const actionInFlightRef = useRef(false);
|
|
517
558
|
const isLoadingState = isLoading || isPending;
|
|
559
|
+
// Delay the spinner reveal for action-driven loading (clickAction's own
|
|
560
|
+
// transition) so a fast action that settles within the delay does not flash
|
|
561
|
+
// a spinner. Interruptible loading is delayed too, so rapid re-clicks settle
|
|
562
|
+
// before any spinner shows. Explicit isLoading-only stays immediate, since
|
|
563
|
+
// the consumer is deliberately showing it.
|
|
564
|
+
const delaySpinner = isPending || isInterruptible;
|
|
518
565
|
const groupDisabled = buttonGroup?.isDisabled ?? false;
|
|
519
|
-
|
|
566
|
+
// When interruptible, the loading state drives the spinner and aria-busy but
|
|
567
|
+
// not disabled, so clicks keep landing and can interrupt the in-flight action.
|
|
568
|
+
const buttonDisabled =
|
|
569
|
+
isDisabled || groupDisabled || (isLoadingState && !isInterruptible);
|
|
520
570
|
// isIconOnly prop is the source of truth for icon-only rendering.
|
|
521
571
|
// When false (default), label is always rendered as visible text.
|
|
522
572
|
|
|
@@ -531,7 +581,9 @@ export function Button({
|
|
|
531
581
|
const useAriaDisabled = tooltip != null && buttonDisabled;
|
|
532
582
|
|
|
533
583
|
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
534
|
-
|
|
584
|
+
// The ref guard dedupes fire-once actions. Interruptible callers skip it so
|
|
585
|
+
// a re-click while pending starts a fresh action that interrupts the prior.
|
|
586
|
+
if (buttonDisabled || (actionInFlightRef.current && !isInterruptible)) {
|
|
535
587
|
e.preventDefault();
|
|
536
588
|
return;
|
|
537
589
|
}
|
|
@@ -598,7 +650,10 @@ export function Button({
|
|
|
598
650
|
<>
|
|
599
651
|
{isLoadingState && (
|
|
600
652
|
<span
|
|
601
|
-
{...stylex.props(
|
|
653
|
+
{...stylex.props(
|
|
654
|
+
loadingStyles.spinnerOverlay,
|
|
655
|
+
delaySpinner && loadingStyles.spinnerDelayed,
|
|
656
|
+
)}
|
|
602
657
|
aria-hidden="true">
|
|
603
658
|
<Spinner size="sm" shade="inherit" />
|
|
604
659
|
</span>
|
|
@@ -606,7 +661,10 @@ export function Button({
|
|
|
606
661
|
<span
|
|
607
662
|
{...stylex.props(
|
|
608
663
|
styles.contentWrapper,
|
|
609
|
-
isLoadingState &&
|
|
664
|
+
isLoadingState &&
|
|
665
|
+
(delaySpinner
|
|
666
|
+
? loadingStyles.hiddenContentDelayed
|
|
667
|
+
: loadingStyles.hiddenContent),
|
|
610
668
|
)}
|
|
611
669
|
aria-hidden={isLoadingState || undefined}>
|
|
612
670
|
{icon && (
|
|
@@ -622,12 +680,9 @@ export function Button({
|
|
|
622
680
|
)}
|
|
623
681
|
</span>
|
|
624
682
|
{/* Live region for loading state announcements */}
|
|
625
|
-
<
|
|
626
|
-
{...stylex.props(styles.visuallyHidden)}
|
|
627
|
-
role="status"
|
|
628
|
-
aria-live="polite">
|
|
683
|
+
<VisuallyHidden role="status" aria-live="polite">
|
|
629
684
|
{isLoadingState ? 'Loading' : ''}
|
|
630
|
-
</
|
|
685
|
+
</VisuallyHidden>
|
|
631
686
|
</>
|
|
632
687
|
);
|
|
633
688
|
|
|
@@ -103,8 +103,8 @@ export const docs = {
|
|
|
103
103
|
},
|
|
104
104
|
{
|
|
105
105
|
name: 'weekStartsOn',
|
|
106
|
-
type:
|
|
107
|
-
description: 'First day of week (0=Sunday).',
|
|
106
|
+
type: "0 | 1 | 2 | 3 | 4 | 5 | 6 | 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat'",
|
|
107
|
+
description: 'First day of week. Accepts a number (0=Sunday) or a three-letter day name (e.g. "mon").',
|
|
108
108
|
default: '0',
|
|
109
109
|
},
|
|
110
110
|
],
|
|
@@ -147,7 +147,7 @@ export const docsZh = {
|
|
|
147
147
|
{name: 'hasOutsideDays', type: 'boolean', description: '显示相邻月份的日期。', default: 'true'},
|
|
148
148
|
{name: 'hasWeekNumbers', type: 'boolean', description: '显示 ISO 周数。', default: 'false'},
|
|
149
149
|
{name: 'hasVariableRowCount', type: 'boolean', description: '可变行数与固定 6 行网格。', default: 'false'},
|
|
150
|
-
{name: 'weekStartsOn', type:
|
|
150
|
+
{name: 'weekStartsOn', type: "0 | 1 | 2 | 3 | 4 | 5 | 6 | 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat'", description: '每周起始日。可为数字(0=周日)或三字母星期缩写(如 "mon")。', default: '0'},
|
|
151
151
|
],
|
|
152
152
|
theming: {
|
|
153
153
|
targets: [
|
|
@@ -200,6 +200,6 @@ export const docsDense = {
|
|
|
200
200
|
hasOutsideDays: 'show days from adjacent months',
|
|
201
201
|
hasWeekNumbers: 'show ISO week numbers',
|
|
202
202
|
hasVariableRowCount: 'variable vs fixed 6-row grid',
|
|
203
|
-
weekStartsOn: 'first day of week (0=Sunday)',
|
|
203
|
+
weekStartsOn: 'first day of week (0=Sunday, or name e.g. "mon")',
|
|
204
204
|
},
|
|
205
205
|
};
|