@astryxdesign/core 0.1.2 → 0.1.3
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 +165 -0
- package/README.md +12 -12
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +11 -5
- 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.map +1 -1
- package/dist/Button/Button.js +2 -4
- package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
- package/dist/ButtonGroup/ButtonGroup.js +0 -1
- 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/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +0 -1
- 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 +8 -1
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +15 -3
- 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/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +0 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +9 -5
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +51 -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 +167 -99
- 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/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 +32 -6
- package/dist/InputGroup/InputGroup.d.ts +4 -3
- package/dist/InputGroup/InputGroup.d.ts.map +1 -1
- package/dist/InputGroup/InputGroup.js +16 -6
- 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/groupStyles.d.ts +1 -1
- package/dist/InputGroup/groupStyles.d.ts.map +1 -1
- package/dist/InputGroup/groupStyles.js +3 -3
- 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 +33 -1
- 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 +10 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +64 -9
- 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 +16 -1
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +18 -7
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +7 -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 +27 -2
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +141 -42
- 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 +15 -1
- package/dist/Popover/Popover.d.ts +18 -2
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +5 -2
- package/dist/Popover/usePopover.d.ts +38 -3
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +24 -9
- 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 +24 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +122 -43
- 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/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +2 -0
- 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 +36 -9
- 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 +87 -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 +11 -8
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +10 -1
- 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/index.d.ts +2 -1
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +2 -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/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 +66 -0
- package/dist/Table/types.d.ts.map +1 -1
- 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 +147 -76
- 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 +131 -3
- package/dist/Tokenizer/Tokenizer.d.ts +12 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +26 -4
- 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 +56 -9
- package/dist/TopNav/TopNavHeading.d.ts +7 -1
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +8 -0
- 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 +13 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +69 -6
- package/dist/Typeahead/Typeahead.d.ts +26 -3
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +65 -29
- 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 +18 -0
- package/dist/astryx.umd.js +55 -55
- package/dist/astryx.umd.js.map +4 -4
- 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/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/docs.mjs +2 -2
- package/package.json +12 -8
- package/src/Avatar/Avatar.test.tsx +37 -0
- package/src/Avatar/Avatar.tsx +10 -5
- package/src/Breadcrumbs/BreadcrumbItem.tsx +25 -7
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -10
- package/src/Button/Button.tsx +3 -16
- package/src/ButtonGroup/ButtonGroup.test.tsx +9 -9
- package/src/ButtonGroup/ButtonGroup.tsx +0 -1
- 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/ChatComposerInput.test.tsx +26 -7
- package/src/Chat/ChatComposerInput.tsx +0 -1
- package/src/Chat/ChatDictationButton.doc.mjs +1 -1
- 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 +22 -4
- package/src/CheckboxInput/CheckboxInput.doc.mjs +10 -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 +192 -26
- package/src/CheckboxList/CheckboxList.tsx +56 -3
- package/src/CheckboxList/CheckboxListContext.tsx +7 -0
- package/src/CheckboxList/CheckboxListItem.tsx +0 -3
- package/src/Citation/Citation.doc.mjs +10 -0
- package/src/Citation/Citation.test.tsx +121 -0
- package/src/Citation/Citation.tsx +15 -3
- package/src/CodeBlock/CodeBlock.test.tsx +115 -0
- package/src/CodeBlock/CodeBlock.tsx +63 -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 +286 -56
- package/src/DateInput/DateInput.test.tsx +248 -2
- package/src/DateInput/DateInput.tsx +196 -100
- 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/Field/Field.doc.mjs +59 -18
- 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 +17 -4
- package/src/Grid/Grid.test.tsx +43 -30
- package/src/Grid/Grid.tsx +38 -3
- package/src/Icon/Icon.doc.mjs +3 -3
- package/src/InputGroup/InputGroup.doc.mjs +111 -23
- package/src/InputGroup/InputGroup.test.tsx +257 -60
- package/src/InputGroup/InputGroup.tsx +23 -5
- package/src/InputGroup/InputGroupContext.ts +9 -4
- package/src/InputGroup/groupStyles.ts +7 -1
- package/src/InputGroup/index.ts +1 -0
- package/src/Kbd/Kbd.test.tsx +22 -4
- package/src/Kbd/Kbd.tsx +35 -3
- package/src/Layer/layerAnimations.stylex.ts +20 -4
- package/src/Layer/useLayer.doc.mjs +5 -0
- package/src/Layer/useLayer.test.tsx +111 -0
- package/src/Layer/useLayer.tsx +90 -9
- 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 -0
- 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 +50 -0
- package/src/Link/Link.tsx +39 -4
- package/src/Markdown/Markdown.test.tsx +11 -0
- package/src/Markdown/Markdown.tsx +7 -0
- package/src/MetadataList/MetadataListItem.doc.mjs +4 -0
- package/src/MoreMenu/MoreMenu.doc.mjs +2 -17
- package/src/MoreMenu/MoreMenu.tsx +0 -9
- package/src/MultiSelector/MultiSelector.doc.mjs +30 -0
- package/src/MultiSelector/MultiSelector.test.tsx +375 -8
- package/src/MultiSelector/MultiSelector.tsx +194 -48
- 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/Pagination/Pagination.doc.mjs +3 -3
- package/src/Pagination/Pagination.test.tsx +117 -5
- package/src/Pagination/Pagination.tsx +21 -1
- package/src/Popover/Popover.doc.mjs +26 -0
- package/src/Popover/Popover.test.tsx +121 -0
- package/src/Popover/Popover.tsx +23 -2
- package/src/Popover/usePopover.doc.mjs +9 -3
- package/src/Popover/usePopover.tsx +70 -12
- 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 +34 -26
- 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/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 +1 -1
- package/src/Selector/Selector.doc.mjs +26 -0
- package/src/Selector/Selector.test.tsx +387 -15
- package/src/Selector/Selector.tsx +175 -67
- package/src/Selector/hooks.ts +23 -0
- package/src/SideNav/SideNav.test.tsx +48 -0
- package/src/SideNav/SideNavHeading.tsx +8 -2
- package/src/SideNav/SideNavItem.tsx +2 -4
- package/src/Skeleton/Skeleton.test.tsx +25 -0
- package/src/Skeleton/Skeleton.tsx +11 -1
- package/src/Slider/Slider.doc.mjs +15 -0
- package/src/Slider/Slider.test.tsx +155 -2
- package/src/Slider/Slider.tsx +53 -5
- 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 +6 -0
- package/src/TabList/TabList.test.tsx +251 -0
- package/src/TabList/TabList.tsx +103 -12
- package/src/TabList/TabListContext.ts +7 -3
- package/src/TabList/TabMenu.tsx +6 -3
- package/src/Table/BaseTable.tsx +21 -17
- package/src/Table/Table.doc.mjs +2 -0
- package/src/Table/Table.test.tsx +10 -0
- package/src/Table/Table.tsx +8 -0
- package/src/Table/TableCell.tsx +25 -23
- package/src/Table/TableHeaderCell.tsx +28 -29
- package/src/Table/index.ts +3 -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/tableContextMenu.test.tsx +157 -0
- package/src/Table/tableContextMenu.tsx +142 -0
- package/src/Table/types.ts +74 -0
- package/src/Table/useTableColumnResize.doc.mjs +3 -3
- package/src/Table/useTableStickyColumns.doc.mjs +2 -2
- package/src/Text/Text.doc.mjs +18 -18
- 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/Thumbnail/Thumbnail.doc.mjs +4 -4
- package/src/TimeInput/TimeInput.doc.mjs +340 -60
- package/src/TimeInput/TimeInput.test.tsx +255 -7
- package/src/TimeInput/TimeInput.tsx +176 -70
- package/src/Timestamp/Timestamp.doc.mjs +19 -19
- package/src/Toast/Toast.tsx +14 -0
- package/src/Toast/ToastViewport.test.tsx +214 -0
- package/src/Toast/ToastViewport.tsx +167 -21
- package/src/Tokenizer/Tokenizer.doc.mjs +29 -14
- package/src/Tokenizer/Tokenizer.test.tsx +105 -1
- package/src/Tokenizer/Tokenizer.tsx +37 -1
- package/src/Toolbar/Toolbar.test.tsx +109 -6
- package/src/Toolbar/Toolbar.tsx +59 -5
- package/src/Tooltip/Tooltip.test.tsx +68 -0
- package/src/Tooltip/useTooltip.tsx +55 -8
- package/src/TopNav/TopNav.test.tsx +50 -0
- package/src/TopNav/TopNavHeading.tsx +17 -1
- 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 +93 -9
- package/src/Typeahead/Typeahead.doc.mjs +141 -30
- package/src/Typeahead/Typeahead.test.tsx +331 -1
- package/src/Typeahead/Typeahead.tsx +105 -33
- 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/docs-script.test.mjs +50 -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/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 +10 -5
- 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
|
@@ -9,13 +9,46 @@
|
|
|
9
9
|
* SYNC: When CheckboxList.tsx or CheckboxListItem.tsx changes, update tests to match new behavior
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {describe, it, expect, vi} from 'vitest';
|
|
13
|
-
import {
|
|
12
|
+
import {describe, it, expect, vi, beforeEach} from 'vitest';
|
|
13
|
+
import {
|
|
14
|
+
render,
|
|
15
|
+
screen,
|
|
16
|
+
fireEvent,
|
|
17
|
+
within,
|
|
18
|
+
waitFor,
|
|
19
|
+
} from '@testing-library/react';
|
|
14
20
|
import userEvent from '@testing-library/user-event';
|
|
15
21
|
import {CheckboxList} from './CheckboxList';
|
|
16
22
|
import {CheckboxListItem} from './CheckboxListItem';
|
|
17
23
|
import {List} from '../List/List';
|
|
18
24
|
|
|
25
|
+
// Mock showPopover/hidePopover (not implemented in jsdom) so the tooltip layer
|
|
26
|
+
// reflects its open state via a `popover-open` attribute the tests can assert.
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
HTMLElement.prototype.showPopover = vi.fn(function (this: HTMLElement) {
|
|
29
|
+
this.setAttribute('popover-open', '');
|
|
30
|
+
const event = new Event('toggle', {bubbles: false});
|
|
31
|
+
Object.defineProperty(event, 'newState', {value: 'open'});
|
|
32
|
+
this.dispatchEvent(event);
|
|
33
|
+
});
|
|
34
|
+
HTMLElement.prototype.hidePopover = vi.fn(function (this: HTMLElement) {
|
|
35
|
+
this.removeAttribute('popover-open');
|
|
36
|
+
const event = new Event('toggle', {bubbles: false});
|
|
37
|
+
Object.defineProperty(event, 'newState', {value: 'closed'});
|
|
38
|
+
this.dispatchEvent(event);
|
|
39
|
+
});
|
|
40
|
+
const originalMatches = HTMLElement.prototype.matches;
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
(HTMLElement.prototype as any).matches = function (
|
|
43
|
+
selector: string,
|
|
44
|
+
): boolean {
|
|
45
|
+
if (selector === ':popover-open') {
|
|
46
|
+
return this.hasAttribute('popover-open');
|
|
47
|
+
}
|
|
48
|
+
return originalMatches.call(this, selector);
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
|
|
19
52
|
describe('CheckboxList', () => {
|
|
20
53
|
it('renders with label', () => {
|
|
21
54
|
render(
|
|
@@ -26,6 +59,25 @@ describe('CheckboxList', () => {
|
|
|
26
59
|
expect(screen.getByText('Preferences')).toBeInTheDocument();
|
|
27
60
|
});
|
|
28
61
|
|
|
62
|
+
it('wraps items in a group named by the label (forms audit: group role)', () => {
|
|
63
|
+
render(
|
|
64
|
+
<CheckboxList label="Preferences" value={[]} onChange={() => {}}>
|
|
65
|
+
<CheckboxListItem label="Option A" value="a" />
|
|
66
|
+
</CheckboxList>,
|
|
67
|
+
);
|
|
68
|
+
// The checkboxes are wrapped in a role="group" whose accessible name comes
|
|
69
|
+
// from the field label (via aria-labelledby). The label is rendered as a
|
|
70
|
+
// <span> (not a literal <label>, which can't name a group) with no
|
|
71
|
+
// orphaned htmlFor.
|
|
72
|
+
const group = screen.getByRole('group', {name: 'Preferences'});
|
|
73
|
+
expect(group).toBeInTheDocument();
|
|
74
|
+
const label = screen.getByText('Preferences');
|
|
75
|
+
expect(label.tagName).toBe('SPAN');
|
|
76
|
+
expect(label.closest('label')).toBeNull();
|
|
77
|
+
expect(label).not.toHaveAttribute('for');
|
|
78
|
+
expect(group.getAttribute('aria-labelledby')).toBe(label.id);
|
|
79
|
+
});
|
|
80
|
+
|
|
29
81
|
it('renders checkbox items', () => {
|
|
30
82
|
render(
|
|
31
83
|
<CheckboxList label="Preferences" value={[]} onChange={() => {}}>
|
|
@@ -39,10 +91,7 @@ describe('CheckboxList', () => {
|
|
|
39
91
|
|
|
40
92
|
it('checks the correct items based on value prop', () => {
|
|
41
93
|
render(
|
|
42
|
-
<CheckboxList
|
|
43
|
-
label="Preferences"
|
|
44
|
-
value={['a', 'c']}
|
|
45
|
-
onChange={() => {}}>
|
|
94
|
+
<CheckboxList label="Preferences" value={['a', 'c']} onChange={() => {}}>
|
|
46
95
|
<CheckboxListItem label="Option A" value="a" />
|
|
47
96
|
<CheckboxListItem label="Option B" value="b" />
|
|
48
97
|
<CheckboxListItem label="Option C" value="c" />
|
|
@@ -58,10 +107,7 @@ describe('CheckboxList', () => {
|
|
|
58
107
|
const user = userEvent.setup();
|
|
59
108
|
const handleChange = vi.fn();
|
|
60
109
|
render(
|
|
61
|
-
<CheckboxList
|
|
62
|
-
label="Preferences"
|
|
63
|
-
value={['a']}
|
|
64
|
-
onChange={handleChange}>
|
|
110
|
+
<CheckboxList label="Preferences" value={['a']} onChange={handleChange}>
|
|
65
111
|
<CheckboxListItem label="Option A" value="a" />
|
|
66
112
|
<CheckboxListItem label="Option B" value="b" />
|
|
67
113
|
</CheckboxList>,
|
|
@@ -272,11 +318,7 @@ describe('CheckboxList', () => {
|
|
|
272
318
|
isChecked={false}
|
|
273
319
|
onCheck={handleSelectAll}
|
|
274
320
|
/>
|
|
275
|
-
<CheckboxListItem
|
|
276
|
-
label="Name"
|
|
277
|
-
isChecked={true}
|
|
278
|
-
onCheck={handleCheck}
|
|
279
|
-
/>
|
|
321
|
+
<CheckboxListItem label="Name" isChecked={true} onCheck={handleCheck} />
|
|
280
322
|
<CheckboxListItem
|
|
281
323
|
label="Email"
|
|
282
324
|
isChecked={false}
|
|
@@ -347,8 +389,15 @@ describe('CheckboxListItem standalone mode', () => {
|
|
|
347
389
|
<CheckboxListItem label="Partial" isChecked="indeterminate" />
|
|
348
390
|
</List>,
|
|
349
391
|
);
|
|
392
|
+
// The inner native checkbox exposes mixed state via the indeterminate DOM
|
|
393
|
+
// property (not a redundant aria-checked, forms-16). The list row is a
|
|
394
|
+
// plain listitem and must not carry aria-checked (aria-allowed-attr).
|
|
350
395
|
const checkbox = screen.getByRole('checkbox');
|
|
351
|
-
expect(checkbox).
|
|
396
|
+
expect(checkbox).toBeInstanceOf(HTMLInputElement);
|
|
397
|
+
if (checkbox instanceof HTMLInputElement) {
|
|
398
|
+
expect(checkbox.indeterminate).toBe(true);
|
|
399
|
+
}
|
|
400
|
+
expect(checkbox).not.toHaveAttribute('aria-checked');
|
|
352
401
|
});
|
|
353
402
|
|
|
354
403
|
it('calls onCheck with true when clicking indeterminate item', async () => {
|
|
@@ -370,21 +419,26 @@ describe('CheckboxListItem standalone mode', () => {
|
|
|
370
419
|
});
|
|
371
420
|
|
|
372
421
|
describe('CheckboxListItem ARIA props', () => {
|
|
373
|
-
it('
|
|
422
|
+
it('conveys checked state via the inner checkbox, not aria-checked on the listitem', () => {
|
|
374
423
|
render(
|
|
375
424
|
<CheckboxList label="Prefs" value={['a']} onChange={() => {}}>
|
|
376
425
|
<CheckboxListItem label="Option A" value="a" />
|
|
377
426
|
<CheckboxListItem label="Option B" value="b" />
|
|
378
427
|
</CheckboxList>,
|
|
379
428
|
);
|
|
429
|
+
// The listitem row must not carry aria-checked (not a valid attribute on
|
|
430
|
+
// role="listitem" — axe: aria-allowed-attr). Checked state is exposed by
|
|
431
|
+
// the inner native checkbox instead.
|
|
380
432
|
const items = screen.getAllByRole('listitem');
|
|
381
|
-
|
|
382
|
-
expect(items[
|
|
383
|
-
|
|
384
|
-
|
|
433
|
+
expect(items[0]).not.toHaveAttribute('aria-checked');
|
|
434
|
+
expect(items[1]).not.toHaveAttribute('aria-checked');
|
|
435
|
+
|
|
436
|
+
const checkboxes = screen.getAllByRole('checkbox');
|
|
437
|
+
expect(checkboxes[0]).toBeChecked();
|
|
438
|
+
expect(checkboxes[1]).not.toBeChecked();
|
|
385
439
|
});
|
|
386
440
|
|
|
387
|
-
it('
|
|
441
|
+
it('does not put aria-checked on the listitem in standalone mode', () => {
|
|
388
442
|
render(
|
|
389
443
|
<List>
|
|
390
444
|
<CheckboxListItem label="Done" isChecked={true} />
|
|
@@ -392,18 +446,26 @@ describe('CheckboxListItem ARIA props', () => {
|
|
|
392
446
|
</List>,
|
|
393
447
|
);
|
|
394
448
|
const items = screen.getAllByRole('listitem');
|
|
395
|
-
expect(items[0]).toHaveAttribute('aria-checked'
|
|
396
|
-
expect(items[1]).toHaveAttribute('aria-checked'
|
|
449
|
+
expect(items[0]).not.toHaveAttribute('aria-checked');
|
|
450
|
+
expect(items[1]).not.toHaveAttribute('aria-checked');
|
|
451
|
+
|
|
452
|
+
const checkboxes = screen.getAllByRole('checkbox');
|
|
453
|
+
expect(checkboxes[0]).toBeChecked();
|
|
454
|
+
expect(checkboxes[1]).not.toBeChecked();
|
|
397
455
|
});
|
|
398
456
|
|
|
399
|
-
it('
|
|
457
|
+
it('exposes indeterminate state via the checkbox, not aria-checked on the listitem', () => {
|
|
400
458
|
render(
|
|
401
459
|
<List>
|
|
402
460
|
<CheckboxListItem label="Partial" isChecked="indeterminate" />
|
|
403
461
|
</List>,
|
|
404
462
|
);
|
|
405
463
|
const item = screen.getByRole('listitem');
|
|
406
|
-
expect(item).toHaveAttribute('aria-checked'
|
|
464
|
+
expect(item).not.toHaveAttribute('aria-checked');
|
|
465
|
+
const checkbox = screen.getByRole('checkbox');
|
|
466
|
+
if (checkbox instanceof HTMLInputElement) {
|
|
467
|
+
expect(checkbox.indeterminate).toBe(true);
|
|
468
|
+
}
|
|
407
469
|
});
|
|
408
470
|
|
|
409
471
|
it('does not mark items aria-busy when idle', () => {
|
|
@@ -500,4 +562,108 @@ describe('CheckboxListItem ARIA props', () => {
|
|
|
500
562
|
expect(item).toHaveAttribute('aria-describedby', 'help-text');
|
|
501
563
|
expect(item).toHaveAttribute('aria-label', 'custom label');
|
|
502
564
|
});
|
|
565
|
+
|
|
566
|
+
describe('disabledMessage', () => {
|
|
567
|
+
const h = {hidden: true} as const;
|
|
568
|
+
|
|
569
|
+
function renderGroup(props?: {onChange?: (v: string[]) => void}) {
|
|
570
|
+
return render(
|
|
571
|
+
<CheckboxList
|
|
572
|
+
label="Notifications"
|
|
573
|
+
value={['email']}
|
|
574
|
+
onChange={props?.onChange ?? (() => {})}
|
|
575
|
+
isDisabled
|
|
576
|
+
disabledMessage="Notifications are managed by your administrator">
|
|
577
|
+
<CheckboxListItem label="Email" value="email" />
|
|
578
|
+
<CheckboxListItem label="SMS" value="sms" />
|
|
579
|
+
</CheckboxList>,
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
it('shows the reason tooltip on hover when the group is disabled with a reason', async () => {
|
|
584
|
+
renderGroup();
|
|
585
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
586
|
+
expect(tooltip).toHaveTextContent(
|
|
587
|
+
'Notifications are managed by your administrator',
|
|
588
|
+
);
|
|
589
|
+
const group = screen.getByRole('group');
|
|
590
|
+
fireEvent.mouseEnter(group);
|
|
591
|
+
await waitFor(() => expect(tooltip).toHaveAttribute('popover-open'));
|
|
592
|
+
fireEvent.mouseLeave(group);
|
|
593
|
+
await waitFor(() => expect(tooltip).not.toHaveAttribute('popover-open'));
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
it('shows the reason tooltip on keyboard focus', async () => {
|
|
597
|
+
const user = userEvent.setup();
|
|
598
|
+
renderGroup();
|
|
599
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
600
|
+
await user.tab();
|
|
601
|
+
await waitFor(() => expect(tooltip).toHaveAttribute('popover-open'));
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
it('does not render a tooltip when not disabled', () => {
|
|
605
|
+
render(
|
|
606
|
+
<CheckboxList
|
|
607
|
+
label="Notifications"
|
|
608
|
+
value={['email']}
|
|
609
|
+
onChange={() => {}}
|
|
610
|
+
disabledMessage="Notifications are managed by your administrator">
|
|
611
|
+
<CheckboxListItem label="Email" value="email" />
|
|
612
|
+
</CheckboxList>,
|
|
613
|
+
);
|
|
614
|
+
expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
it('does not render a tooltip when disabled without a reason', () => {
|
|
618
|
+
render(
|
|
619
|
+
<CheckboxList
|
|
620
|
+
label="Notifications"
|
|
621
|
+
value={['email']}
|
|
622
|
+
onChange={() => {}}
|
|
623
|
+
isDisabled>
|
|
624
|
+
<CheckboxListItem label="Email" value="email" />
|
|
625
|
+
</CheckboxList>,
|
|
626
|
+
);
|
|
627
|
+
expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
it('keeps checkboxes focusable via aria-disabled when a reason is provided', () => {
|
|
631
|
+
renderGroup();
|
|
632
|
+
for (const checkbox of screen.getAllByRole('checkbox', h)) {
|
|
633
|
+
expect(checkbox).not.toBeDisabled();
|
|
634
|
+
expect(checkbox).toHaveAttribute('aria-disabled', 'true');
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
it('links the reason tooltip from the group via aria-describedby', () => {
|
|
639
|
+
renderGroup();
|
|
640
|
+
const group = screen.getByRole('group');
|
|
641
|
+
const tooltip = screen.getByRole('tooltip', h);
|
|
642
|
+
expect(group.getAttribute('aria-describedby')).toContain(tooltip.id);
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
it('blocks toggling while focusable-disabled', () => {
|
|
646
|
+
const onChange = vi.fn();
|
|
647
|
+
renderGroup({onChange});
|
|
648
|
+
const sms = screen.getByRole('checkbox', {name: 'SMS', hidden: true});
|
|
649
|
+
fireEvent.click(sms);
|
|
650
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
it('keeps checkboxes natively disabled when disabled without a reason', () => {
|
|
654
|
+
render(
|
|
655
|
+
<CheckboxList
|
|
656
|
+
label="Notifications"
|
|
657
|
+
value={['email']}
|
|
658
|
+
onChange={() => {}}
|
|
659
|
+
isDisabled>
|
|
660
|
+
<CheckboxListItem label="Email" value="email" />
|
|
661
|
+
<CheckboxListItem label="SMS" value="sms" />
|
|
662
|
+
</CheckboxList>,
|
|
663
|
+
);
|
|
664
|
+
for (const checkbox of screen.getAllByRole('checkbox', h)) {
|
|
665
|
+
expect(checkbox).toBeDisabled();
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
});
|
|
503
669
|
});
|
|
@@ -30,6 +30,7 @@ import {Field} from '../Field/Field';
|
|
|
30
30
|
import type {InputStatus} from '../Field/types';
|
|
31
31
|
import {List} from '../List/List';
|
|
32
32
|
import type {ListDensity} from '../List/ListContext';
|
|
33
|
+
import {useTooltip} from '../Tooltip';
|
|
33
34
|
import {mergeProps} from '../utils';
|
|
34
35
|
import {themeProps} from '../utils/themeProps';
|
|
35
36
|
import {
|
|
@@ -93,6 +94,18 @@ export interface CheckboxListProps extends Omit<
|
|
|
93
94
|
* @default false
|
|
94
95
|
*/
|
|
95
96
|
isDisabled?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Explains why the checkbox group is disabled. Applies to the whole-group
|
|
99
|
+
* disabled state (`isDisabled`), not individual items. When set together with
|
|
100
|
+
* `isDisabled`, the group shows a tooltip with this text on hover and keyboard
|
|
101
|
+
* focus, and its checkboxes stay focusable (via `aria-disabled`) so the reason
|
|
102
|
+
* is discoverable by keyboard and assistive technology. Toggling stays
|
|
103
|
+
* blocked.
|
|
104
|
+
*
|
|
105
|
+
* Use this instead of wrapping a disabled group in `Tooltip` — disabled
|
|
106
|
+
* controls don't emit the pointer events an external tooltip needs.
|
|
107
|
+
*/
|
|
108
|
+
disabledMessage?: string;
|
|
96
109
|
/**
|
|
97
110
|
* Whether all checkbox items are read-only.
|
|
98
111
|
* Displays the current state at full opacity but prevents interaction.
|
|
@@ -141,6 +154,7 @@ export function CheckboxList({
|
|
|
141
154
|
density = 'balanced',
|
|
142
155
|
hasDividers = false,
|
|
143
156
|
isDisabled = false,
|
|
157
|
+
disabledMessage,
|
|
144
158
|
isReadOnly = false,
|
|
145
159
|
children,
|
|
146
160
|
ref,
|
|
@@ -151,6 +165,7 @@ export function CheckboxList({
|
|
|
151
165
|
'data-testid': dataTestId,
|
|
152
166
|
}: CheckboxListProps) {
|
|
153
167
|
const inputID = useId();
|
|
168
|
+
const labelID = useId();
|
|
154
169
|
const descriptionID = useId();
|
|
155
170
|
const statusMessageID = useId();
|
|
156
171
|
|
|
@@ -162,6 +177,19 @@ export function CheckboxList({
|
|
|
162
177
|
// the transition settles, so the spinner clears without manual cleanup.
|
|
163
178
|
const [loadingValue, setLoadingValue] = useOptimistic<string | null>(null);
|
|
164
179
|
|
|
180
|
+
// Disabled-reason tooltip. Applies to the whole-group disabled state. Disabled
|
|
181
|
+
// controls swallow pointer events, so the tooltip listeners attach to the
|
|
182
|
+
// group container and the checkboxes stay perceivable via aria-disabled
|
|
183
|
+
// instead of the disabled attribute. Toggling is blocked in the item.
|
|
184
|
+
const showsDisabledMessage = isDisabled && !!disabledMessage;
|
|
185
|
+
const disabledMessageTooltip = useTooltip({
|
|
186
|
+
placement: 'above',
|
|
187
|
+
// The group container is not naturally focusable; focusin bubbles up from
|
|
188
|
+
// the checkboxes, so always attach focus listeners.
|
|
189
|
+
focusTrigger: 'always',
|
|
190
|
+
isEnabled: showsDisabledMessage,
|
|
191
|
+
});
|
|
192
|
+
|
|
165
193
|
const handleChange = useCallback(
|
|
166
194
|
(newValues: string[], toggledValue?: string) => {
|
|
167
195
|
onChange?.(newValues);
|
|
@@ -189,6 +217,7 @@ export function CheckboxList({
|
|
|
189
217
|
value: isCollectionMode ? optimisticValue : undefined,
|
|
190
218
|
onChange: isCollectionMode ? handleChange : undefined,
|
|
191
219
|
isDisabled,
|
|
220
|
+
hasDisabledMessage: showsDisabledMessage,
|
|
192
221
|
isReadOnly,
|
|
193
222
|
loadingValue,
|
|
194
223
|
}),
|
|
@@ -197,6 +226,7 @@ export function CheckboxList({
|
|
|
197
226
|
optimisticValue,
|
|
198
227
|
handleChange,
|
|
199
228
|
isDisabled,
|
|
229
|
+
showsDisabledMessage,
|
|
200
230
|
isReadOnly,
|
|
201
231
|
loadingValue,
|
|
202
232
|
],
|
|
@@ -210,6 +240,8 @@ export function CheckboxList({
|
|
|
210
240
|
isLabelHidden={isLabelHidden}
|
|
211
241
|
description={description}
|
|
212
242
|
inputID={inputID}
|
|
243
|
+
labelID={labelID}
|
|
244
|
+
isGroupLabel
|
|
213
245
|
descriptionID={description ? descriptionID : undefined}
|
|
214
246
|
isDisabled={isDisabled}
|
|
215
247
|
status={
|
|
@@ -226,10 +258,31 @@ export function CheckboxList({
|
|
|
226
258
|
xstyle={xstyle}
|
|
227
259
|
{...mergeProps(themeProps('checkbox-list'), {className, style})}>
|
|
228
260
|
<CheckboxListContext value={contextValue}>
|
|
229
|
-
<
|
|
230
|
-
{
|
|
231
|
-
|
|
261
|
+
<div
|
|
262
|
+
ref={el => {
|
|
263
|
+
// Anchor + hover/focus listeners for the disabled-message tooltip.
|
|
264
|
+
// Handlers are gated internally by isEnabled, so attaching
|
|
265
|
+
// unconditionally is safe.
|
|
266
|
+
disabledMessageTooltip.ref(el);
|
|
267
|
+
}}
|
|
268
|
+
role="group"
|
|
269
|
+
aria-labelledby={labelID}
|
|
270
|
+
aria-describedby={
|
|
271
|
+
[
|
|
272
|
+
description ? descriptionID : null,
|
|
273
|
+
status?.message ? statusMessageID : null,
|
|
274
|
+
showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
|
|
275
|
+
]
|
|
276
|
+
.filter(Boolean)
|
|
277
|
+
.join(' ') || undefined
|
|
278
|
+
}>
|
|
279
|
+
<List density={density} hasDividers={hasDividers}>
|
|
280
|
+
{children}
|
|
281
|
+
</List>
|
|
282
|
+
</div>
|
|
232
283
|
</CheckboxListContext>
|
|
284
|
+
{showsDisabledMessage &&
|
|
285
|
+
disabledMessageTooltip.renderTooltip(disabledMessage)}
|
|
233
286
|
</Field>
|
|
234
287
|
);
|
|
235
288
|
}
|
|
@@ -21,6 +21,13 @@ export interface CheckboxListContextValue {
|
|
|
21
21
|
*/
|
|
22
22
|
onChange?: (values: string[], toggledValue?: string) => void;
|
|
23
23
|
isDisabled: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* True when the whole group is disabled *and* a `disabledMessage` is set. In
|
|
26
|
+
* that mode items stay focusable via `aria-disabled` (instead of the native
|
|
27
|
+
* `disabled` attribute) so the group's disabled-reason tooltip is keyboard-
|
|
28
|
+
* and AT-discoverable; toggling is still blocked.
|
|
29
|
+
*/
|
|
30
|
+
hasDisabledMessage?: boolean;
|
|
24
31
|
isReadOnly: boolean;
|
|
25
32
|
/**
|
|
26
33
|
* The value of the item with a pending `changeAction`, or null when idle.
|
|
@@ -201,9 +201,6 @@ export function CheckboxListItem({
|
|
|
201
201
|
endContent={endContent}
|
|
202
202
|
isDisabled={effectiveDisabled}
|
|
203
203
|
onClick={isInteractive ? handleToggle : undefined}
|
|
204
|
-
aria-checked={
|
|
205
|
-
resolvedChecked === 'indeterminate' ? 'mixed' : resolvedChecked
|
|
206
|
-
}
|
|
207
204
|
aria-busy={isBusy || undefined}
|
|
208
205
|
xstyle={
|
|
209
206
|
[
|
|
@@ -56,6 +56,16 @@ export const docs = {
|
|
|
56
56
|
],
|
|
57
57
|
},
|
|
58
58
|
|
|
59
|
+
// `source` is a custom object type the docsite preview cannot generate
|
|
60
|
+
// automatically; without these defaults the properties tab shows the
|
|
61
|
+
// missing-required-props placeholder instead of an interactive preview.
|
|
62
|
+
playground: {
|
|
63
|
+
defaults: {
|
|
64
|
+
source: {title: 'Astryx Design', url: 'https://example.com'},
|
|
65
|
+
number: 1,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
|
|
59
69
|
props: [
|
|
60
70
|
{
|
|
61
71
|
name: 'source',
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Citation.test.tsx
|
|
5
|
+
* @input Uses React Testing Library, Citation, theme tokens
|
|
6
|
+
* @output Tests for Citation component
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {render, screen} from '@testing-library/react';
|
|
10
|
+
import {describe, it, expect} from 'vitest';
|
|
11
|
+
import * as stylex from '@stylexjs/stylex';
|
|
12
|
+
import {colorVars} from '../theme/tokens.stylex';
|
|
13
|
+
import {Citation} from './Citation';
|
|
14
|
+
|
|
15
|
+
// StyleX emits one deterministic atomic class per property/value pair, so an
|
|
16
|
+
// element carries a probe's class exactly when it has the same declaration.
|
|
17
|
+
// The dev-mode debug class (contains "__") varies by source location and is
|
|
18
|
+
// excluded from the comparison.
|
|
19
|
+
const probe = stylex.create({
|
|
20
|
+
secondaryText: {color: colorVars['--color-text-secondary']},
|
|
21
|
+
accentText: {color: colorVars['--color-text-accent']},
|
|
22
|
+
badgeBackground: {backgroundColor: colorVars['--color-accent-muted']},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
function atomicClasses(style: (typeof probe)[keyof typeof probe]): string[] {
|
|
26
|
+
const {className = ''} = stylex.props(style);
|
|
27
|
+
return className.split(' ').filter(c => c !== '' && !c.includes('__'));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe('Citation', () => {
|
|
31
|
+
const source = {title: 'Example Source', url: 'https://example.com'};
|
|
32
|
+
|
|
33
|
+
it('renders the source title as a link in the label variant', () => {
|
|
34
|
+
render(<Citation source={source} number={1} data-testid="citation" />);
|
|
35
|
+
const el = screen.getByTestId('citation');
|
|
36
|
+
expect(el.tagName).toBe('A');
|
|
37
|
+
expect(el).toHaveAttribute('href', 'https://example.com');
|
|
38
|
+
expect(el).toHaveTextContent('Example Source');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('renders the index as a badge in the number variant', () => {
|
|
42
|
+
render(
|
|
43
|
+
<Citation
|
|
44
|
+
source={source}
|
|
45
|
+
number={3}
|
|
46
|
+
variant="number"
|
|
47
|
+
data-testid="citation"
|
|
48
|
+
/>,
|
|
49
|
+
);
|
|
50
|
+
const el = screen.getByTestId('citation');
|
|
51
|
+
expect(el).toHaveTextContent('3');
|
|
52
|
+
expect(el).toHaveAttribute('role', 'doc-noteref');
|
|
53
|
+
expect(el).toHaveAttribute('aria-label', 'Citation 3: Example Source');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('renders as a span when the source has no url', () => {
|
|
57
|
+
render(
|
|
58
|
+
<Citation
|
|
59
|
+
source={{title: 'No link'}}
|
|
60
|
+
number={1}
|
|
61
|
+
data-testid="citation"
|
|
62
|
+
/>,
|
|
63
|
+
);
|
|
64
|
+
const el = screen.getByTestId('citation');
|
|
65
|
+
expect(el.tagName).toBe('SPAN');
|
|
66
|
+
// doc-noteref is a reference role that is not permitted on a plain
|
|
67
|
+
// (unlinked) span (axe: aria-allowed-role), so it must be omitted here.
|
|
68
|
+
expect(el).not.toHaveAttribute('role');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('renders astryx-* class names for theme targeting', () => {
|
|
72
|
+
render(<Citation source={source} number={1} data-testid="citation" />);
|
|
73
|
+
expect(screen.getByTestId('citation').className).toContain(
|
|
74
|
+
'astryx-citation',
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('uses the secondary text color in the label variant', () => {
|
|
79
|
+
render(<Citation source={source} number={1} data-testid="citation" />);
|
|
80
|
+
const el = screen.getByTestId('citation');
|
|
81
|
+
for (const cls of atomicClasses(probe.secondaryText)) {
|
|
82
|
+
expect(el.classList.contains(cls)).toBe(true);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('uses the secondary text color, not accent, in the number variant', () => {
|
|
87
|
+
render(
|
|
88
|
+
<Citation
|
|
89
|
+
source={source}
|
|
90
|
+
number={1}
|
|
91
|
+
variant="number"
|
|
92
|
+
data-testid="citation"
|
|
93
|
+
/>,
|
|
94
|
+
);
|
|
95
|
+
const el = screen.getByTestId('citation');
|
|
96
|
+
for (const cls of atomicClasses(probe.secondaryText)) {
|
|
97
|
+
expect(el.classList.contains(cls)).toBe(true);
|
|
98
|
+
}
|
|
99
|
+
for (const cls of atomicClasses(probe.accentText)) {
|
|
100
|
+
expect(el.classList.contains(cls)).toBe(false);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('keeps the accent-muted badge background when the source has a url', () => {
|
|
105
|
+
// `numberHover` must not clobber the base background: a hover-only
|
|
106
|
+
// conditional without a default replaces the whole property on merge,
|
|
107
|
+
// leaving linked badges with a transparent pill.
|
|
108
|
+
render(
|
|
109
|
+
<Citation
|
|
110
|
+
source={source}
|
|
111
|
+
number={1}
|
|
112
|
+
variant="number"
|
|
113
|
+
data-testid="citation"
|
|
114
|
+
/>,
|
|
115
|
+
);
|
|
116
|
+
const el = screen.getByTestId('citation');
|
|
117
|
+
for (const cls of atomicClasses(probe.badgeBackground)) {
|
|
118
|
+
expect(el.classList.contains(cls)).toBe(true);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -83,6 +83,10 @@ const styles = stylex.create({
|
|
|
83
83
|
},
|
|
84
84
|
},
|
|
85
85
|
color: {
|
|
86
|
+
// Explicit default: without it, this hover-only conditional replaces
|
|
87
|
+
// the base secondary color from `label` (last-wins property merge),
|
|
88
|
+
// leaving linked citations to inherit the surrounding text color.
|
|
89
|
+
default: colorVars['--color-text-secondary'],
|
|
86
90
|
':hover': {
|
|
87
91
|
'@media (hover: hover)': colorVars['--color-text-primary'],
|
|
88
92
|
},
|
|
@@ -96,7 +100,7 @@ const styles = stylex.create({
|
|
|
96
100
|
fontSize: typeScaleVars['--text-supporting-size'],
|
|
97
101
|
fontWeight: fontWeightVars['--font-weight-semibold'],
|
|
98
102
|
lineHeight: typeScaleVars['--text-supporting-leading'],
|
|
99
|
-
color: colorVars['--color-text-
|
|
103
|
+
color: colorVars['--color-text-secondary'],
|
|
100
104
|
backgroundColor: colorVars['--color-accent-muted'],
|
|
101
105
|
borderRadius: radiusVars['--radius-full'],
|
|
102
106
|
minWidth: spacingVars['--spacing-5'],
|
|
@@ -110,6 +114,10 @@ const styles = stylex.create({
|
|
|
110
114
|
},
|
|
111
115
|
numberHover: {
|
|
112
116
|
backgroundColor: {
|
|
117
|
+
// Explicit default for the same reason as labelHover's color: a
|
|
118
|
+
// hover-only conditional replaces the base accent-muted pill from
|
|
119
|
+
// `number` on merge, leaving linked badges transparent.
|
|
120
|
+
default: colorVars['--color-accent-muted'],
|
|
113
121
|
':hover': {
|
|
114
122
|
'@media (hover: hover)': colorVars['--color-overlay-hover'],
|
|
115
123
|
},
|
|
@@ -150,6 +158,10 @@ export function Citation({
|
|
|
150
158
|
const href = source.url;
|
|
151
159
|
const icon = source.icon;
|
|
152
160
|
const Tag = href ? 'a' : 'span';
|
|
161
|
+
// `doc-noteref` is a reference role — only appropriate on the interactive
|
|
162
|
+
// link form. On a plain (unlinked) span it is not a permitted role
|
|
163
|
+
// (axe: aria-allowed-role), so omit it there; the aria-label still names it.
|
|
164
|
+
const noteRole = href ? ('doc-noteref' as const) : undefined;
|
|
153
165
|
const linkProps = href
|
|
154
166
|
? {
|
|
155
167
|
href,
|
|
@@ -168,7 +180,7 @@ export function Citation({
|
|
|
168
180
|
<Tag
|
|
169
181
|
{...rest}
|
|
170
182
|
ref={elementRef}
|
|
171
|
-
role=
|
|
183
|
+
role={noteRole}
|
|
172
184
|
aria-label={`Citation ${number}: ${title}`}
|
|
173
185
|
data-testid={testId}
|
|
174
186
|
{...linkProps}
|
|
@@ -191,7 +203,7 @@ export function Citation({
|
|
|
191
203
|
<Tag
|
|
192
204
|
{...rest}
|
|
193
205
|
ref={elementRef}
|
|
194
|
-
role=
|
|
206
|
+
role={noteRole}
|
|
195
207
|
aria-label={`Citation ${number}: ${title}`}
|
|
196
208
|
data-testid={testId}
|
|
197
209
|
{...linkProps}
|