@astryxdesign/core 0.1.2 → 0.1.3-canary.102854d
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 +31 -12
- 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 +124 -61
- package/dist/Calendar/dayCellUtils.d.ts +67 -5
- package/dist/Calendar/dayCellUtils.d.ts.map +1 -1
- package/dist/Calendar/dayCellUtils.js +139 -18
- 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 +12 -5
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +96 -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 +13 -9
- 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 +79 -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 +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/rowExpansion/index.d.ts +3 -0
- package/dist/Table/plugins/rowExpansion/index.d.ts.map +1 -0
- package/dist/Table/plugins/rowExpansion/index.js +3 -0
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +90 -0
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -0
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +398 -0
- 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 +37 -0
- package/dist/Table/tableContextMenu.d.ts.map +1 -0
- package/dist/Table/tableContextMenu.js +140 -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 +22 -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.doc.mjs +2 -2
- 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 +42 -22
- 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 +247 -30
- package/src/Calendar/Calendar.tsx +173 -86
- package/src/Calendar/dayCellUtils.test.ts +306 -1
- package/src/Calendar/dayCellUtils.ts +206 -13
- 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 +129 -16
- package/src/DateInput/DateInput.doc.mjs +291 -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/__tests__/edgeCompensation.test.tsx +72 -0
- 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 +35 -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 +31 -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 +9 -3
- 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 +24 -18
- 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 +105 -24
- package/src/Table/TableHeaderCell.tsx +28 -29
- package/src/Table/index.ts +8 -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/rowExpansion/index.ts +7 -0
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +155 -0
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +590 -0
- 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 +181 -0
- package/src/Table/tableContextMenu.tsx +160 -0
- package/src/Table/types.ts +74 -0
- package/src/Table/useTableColumnResize.doc.mjs +3 -3
- package/src/Table/useTablePagination.doc.mjs +4 -1
- package/src/Table/useTableRowExpansion.doc.mjs +63 -0
- package/src/Table/useTableSortable.doc.mjs +4 -1
- 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 +345 -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 +146 -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
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file useTableRowExpansion.tsx
|
|
7
|
+
* @input React, StyleX, Icon, Table types
|
|
8
|
+
* @output Exports useTableRowExpansion hook + config/state types
|
|
9
|
+
* @position Row-expansion plugin; consumed by Table via plugins prop
|
|
10
|
+
*
|
|
11
|
+
* SYNC: When modified, update these files to stay in sync:
|
|
12
|
+
* - /packages/core/src/Table/index.ts (exports)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {useCallback, useMemo, useRef, type ReactNode} from 'react';
|
|
16
|
+
import * as stylex from '@stylexjs/stylex';
|
|
17
|
+
import {spacingVars, colorVars, radiusVars} from '../../../theme/tokens.stylex';
|
|
18
|
+
import {Icon} from '../../../Icon';
|
|
19
|
+
import {resolveContextActions} from '../../tableContextMenu';
|
|
20
|
+
import type {
|
|
21
|
+
TablePlugin,
|
|
22
|
+
TableColumn,
|
|
23
|
+
BodyCellRenderProps,
|
|
24
|
+
BodyRowRenderProps,
|
|
25
|
+
HeaderCellRenderProps,
|
|
26
|
+
} from '../../types';
|
|
27
|
+
|
|
28
|
+
// =============================================================================
|
|
29
|
+
// Config
|
|
30
|
+
// =============================================================================
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Configuration for useTableRowExpansion (inherited-columns mode).
|
|
34
|
+
*
|
|
35
|
+
* Child rows use the same columns as their parents, with indentation on the
|
|
36
|
+
* first content column. The consumer provides a **flat** data array (use
|
|
37
|
+
* {@link useTableRowExpansionState} to flatten a tree) and a `getDepth`
|
|
38
|
+
* function so the plugin knows each row's nesting level.
|
|
39
|
+
*/
|
|
40
|
+
export interface UseTableRowExpansionConfig<T extends Record<string, unknown>> {
|
|
41
|
+
/** Set of currently-expanded row keys. */
|
|
42
|
+
expandedKeys: Set<string>;
|
|
43
|
+
/** Called when a row's expansion is toggled. */
|
|
44
|
+
onToggle: (key: string) => void;
|
|
45
|
+
/** Derive a stable unique key from a row item. */
|
|
46
|
+
getRowKey: (item: T) => string;
|
|
47
|
+
/** Return the children of a row (used to determine expandability). */
|
|
48
|
+
getChildren: (item: T) => T[];
|
|
49
|
+
/** Return the depth of a row in the hierarchy (0 = top-level). */
|
|
50
|
+
getDepth?: (item: T) => number;
|
|
51
|
+
/** Optionally control which rows are expandable. @default checks getChildren length */
|
|
52
|
+
getIsItemExpandable?: (item: T) => boolean;
|
|
53
|
+
/**
|
|
54
|
+
* When true, clicking anywhere on the row toggles expansion (in addition to
|
|
55
|
+
* the chevron button). @default false — only the chevron triggers expansion.
|
|
56
|
+
*/
|
|
57
|
+
hasRowClickExpansion?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* State of the expand-all toggle in the header. `true` = all expanded,
|
|
60
|
+
* `false` = all collapsed, `'indeterminate'` = mixed. When provided
|
|
61
|
+
* (together with `onToggleExpandAll`), the header cell shows a toggle button.
|
|
62
|
+
*/
|
|
63
|
+
isAllExpanded?: boolean | 'indeterminate';
|
|
64
|
+
/** Called when the expand-all header toggle is clicked. */
|
|
65
|
+
onToggleExpandAll?: (expand: boolean) => void;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Configuration for {@link useTableRowExpansionState}.
|
|
70
|
+
*
|
|
71
|
+
* Mirrors the shape of {@link useTableSelectionState}: you own the
|
|
72
|
+
* `expandedKeys` set (via `useState`), and the hook derives everything the
|
|
73
|
+
* plugin needs — the flattened `data`, per-row depth, expand/collapse
|
|
74
|
+
* handlers, and the expand-all toggle state.
|
|
75
|
+
*/
|
|
76
|
+
export interface UseTableRowExpansionStateConfig<
|
|
77
|
+
T extends Record<string, unknown>,
|
|
78
|
+
> {
|
|
79
|
+
/** The full, un-flattened tree. */
|
|
80
|
+
baseData: T[];
|
|
81
|
+
/** Return the children of a row. Leaf rows return an empty array. */
|
|
82
|
+
getChildren: (item: T) => T[];
|
|
83
|
+
/** Derive a stable unique key from a row item. */
|
|
84
|
+
getRowKey: (item: T) => string;
|
|
85
|
+
/**
|
|
86
|
+
* Should this row be expandable? Rows that return `false` never show a
|
|
87
|
+
* chevron and are skipped by expand-all. @default rows with children
|
|
88
|
+
*/
|
|
89
|
+
getIsItemExpandable?: (item: T) => boolean;
|
|
90
|
+
/** Controlled set of currently-expanded row keys. */
|
|
91
|
+
expandedKeys: Set<string>;
|
|
92
|
+
/** Setter for the controlled expanded keys. */
|
|
93
|
+
setExpandedKeys: React.Dispatch<React.SetStateAction<Set<string>>>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface UseTableRowExpansionStateResult<
|
|
97
|
+
T extends Record<string, unknown>,
|
|
98
|
+
> {
|
|
99
|
+
/** The flattened, currently-visible rows. Pass to `<Table data>`. */
|
|
100
|
+
data: T[];
|
|
101
|
+
/** Ready-to-use config for {@link useTableRowExpansion}. */
|
|
102
|
+
expansionConfig: UseTableRowExpansionConfig<T>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Manages row-expansion state and derives the config for
|
|
107
|
+
* {@link useTableRowExpansion}. This is the recommended entry point — it
|
|
108
|
+
* removes the boilerplate of flattening the tree, tracking depth, and
|
|
109
|
+
* computing the expand-all state.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```tsx
|
|
113
|
+
* const [expandedKeys, setExpandedKeys] = useState<Set<string>>(new Set());
|
|
114
|
+
* const {data, expansionConfig} = useTableRowExpansionState({
|
|
115
|
+
* baseData: tree,
|
|
116
|
+
* getChildren: item => item.children ?? [],
|
|
117
|
+
* getRowKey: item => item.id,
|
|
118
|
+
* expandedKeys,
|
|
119
|
+
* setExpandedKeys,
|
|
120
|
+
* });
|
|
121
|
+
* const expansion = useTableRowExpansion(expansionConfig);
|
|
122
|
+
* <Table data={data} columns={columns} idKey="id" plugins={{expansion}} />;
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
export function useTableRowExpansionState<T extends Record<string, unknown>>({
|
|
126
|
+
baseData,
|
|
127
|
+
getChildren,
|
|
128
|
+
getRowKey,
|
|
129
|
+
getIsItemExpandable,
|
|
130
|
+
expandedKeys,
|
|
131
|
+
setExpandedKeys,
|
|
132
|
+
}: UseTableRowExpansionStateConfig<T>): UseTableRowExpansionStateResult<T> {
|
|
133
|
+
const isExpandable = useCallback(
|
|
134
|
+
(item: T): boolean =>
|
|
135
|
+
getIsItemExpandable
|
|
136
|
+
? getIsItemExpandable(item)
|
|
137
|
+
: getChildren(item).length > 0,
|
|
138
|
+
[getIsItemExpandable, getChildren],
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const depthMap = useMemo(() => {
|
|
142
|
+
const map = new Map<string, number>();
|
|
143
|
+
function walk(items: T[], depth: number) {
|
|
144
|
+
for (const item of items) {
|
|
145
|
+
const key = getRowKey(item);
|
|
146
|
+
map.set(key, depth);
|
|
147
|
+
if (expandedKeys.has(key)) {
|
|
148
|
+
walk(getChildren(item), depth + 1);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
walk(baseData, 0);
|
|
153
|
+
return map;
|
|
154
|
+
}, [baseData, getChildren, getRowKey, expandedKeys]);
|
|
155
|
+
|
|
156
|
+
const data = useMemo(() => {
|
|
157
|
+
const result: T[] = [];
|
|
158
|
+
function walk(items: T[]) {
|
|
159
|
+
for (const item of items) {
|
|
160
|
+
result.push(item);
|
|
161
|
+
const key = getRowKey(item);
|
|
162
|
+
if (expandedKeys.has(key)) {
|
|
163
|
+
walk(getChildren(item));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
walk(baseData);
|
|
168
|
+
return result;
|
|
169
|
+
}, [baseData, getChildren, getRowKey, expandedKeys]);
|
|
170
|
+
|
|
171
|
+
// Every expandable key across the whole tree (drives expand-all).
|
|
172
|
+
const allExpandableKeys = useMemo(() => {
|
|
173
|
+
const keys: string[] = [];
|
|
174
|
+
function walk(items: T[]) {
|
|
175
|
+
for (const item of items) {
|
|
176
|
+
if (isExpandable(item)) {
|
|
177
|
+
keys.push(getRowKey(item));
|
|
178
|
+
walk(getChildren(item));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
walk(baseData);
|
|
183
|
+
return keys;
|
|
184
|
+
}, [baseData, getChildren, getRowKey, isExpandable]);
|
|
185
|
+
|
|
186
|
+
const getDepth = useCallback(
|
|
187
|
+
(item: T) => depthMap.get(getRowKey(item)) ?? 0,
|
|
188
|
+
[depthMap, getRowKey],
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const onToggle = useCallback(
|
|
192
|
+
(key: string) => {
|
|
193
|
+
setExpandedKeys(prev => {
|
|
194
|
+
const next = new Set(prev);
|
|
195
|
+
if (next.has(key)) {
|
|
196
|
+
next.delete(key);
|
|
197
|
+
} else {
|
|
198
|
+
next.add(key);
|
|
199
|
+
}
|
|
200
|
+
return next;
|
|
201
|
+
});
|
|
202
|
+
},
|
|
203
|
+
[setExpandedKeys],
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
const isAllExpanded: boolean | 'indeterminate' = useMemo(() => {
|
|
207
|
+
if (allExpandableKeys.length === 0) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
const expandedCount = allExpandableKeys.filter(k =>
|
|
211
|
+
expandedKeys.has(k),
|
|
212
|
+
).length;
|
|
213
|
+
if (expandedCount === 0) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
if (expandedCount === allExpandableKeys.length) {
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
return 'indeterminate';
|
|
220
|
+
}, [allExpandableKeys, expandedKeys]);
|
|
221
|
+
|
|
222
|
+
const onToggleExpandAll = useCallback(
|
|
223
|
+
(expand: boolean) => {
|
|
224
|
+
setExpandedKeys(expand ? new Set(allExpandableKeys) : new Set());
|
|
225
|
+
},
|
|
226
|
+
[setExpandedKeys, allExpandableKeys],
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
const expansionConfig = useMemo(
|
|
230
|
+
(): UseTableRowExpansionConfig<T> => ({
|
|
231
|
+
expandedKeys,
|
|
232
|
+
onToggle,
|
|
233
|
+
getRowKey,
|
|
234
|
+
getChildren,
|
|
235
|
+
getDepth,
|
|
236
|
+
getIsItemExpandable,
|
|
237
|
+
isAllExpanded,
|
|
238
|
+
onToggleExpandAll,
|
|
239
|
+
}),
|
|
240
|
+
[
|
|
241
|
+
expandedKeys,
|
|
242
|
+
onToggle,
|
|
243
|
+
getRowKey,
|
|
244
|
+
getChildren,
|
|
245
|
+
getDepth,
|
|
246
|
+
getIsItemExpandable,
|
|
247
|
+
isAllExpanded,
|
|
248
|
+
onToggleExpandAll,
|
|
249
|
+
],
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
return {data, expansionConfig};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// =============================================================================
|
|
256
|
+
// Styles
|
|
257
|
+
// =============================================================================
|
|
258
|
+
|
|
259
|
+
const EXPANSION_COLUMN_WIDTH = {type: 'pixel' as const, value: 40};
|
|
260
|
+
|
|
261
|
+
/** Indentation applied per depth level, in pixels. */
|
|
262
|
+
const INDENT_PER_DEPTH = 24;
|
|
263
|
+
|
|
264
|
+
const expansionStyles = stylex.create({
|
|
265
|
+
chevronButton: {
|
|
266
|
+
display: 'inline-flex',
|
|
267
|
+
alignItems: 'center',
|
|
268
|
+
justifyContent: 'center',
|
|
269
|
+
width: '24px',
|
|
270
|
+
height: '24px',
|
|
271
|
+
background: 'transparent',
|
|
272
|
+
border: 'none',
|
|
273
|
+
borderRadius: radiusVars['--radius-inner'],
|
|
274
|
+
cursor: 'pointer',
|
|
275
|
+
color: colorVars['--color-icon-secondary'],
|
|
276
|
+
transitionProperty: 'transform, color, background-color',
|
|
277
|
+
transitionDuration: '150ms',
|
|
278
|
+
padding: 0,
|
|
279
|
+
flexShrink: '0',
|
|
280
|
+
// Match IconButton ghost hover: subtle overlay background
|
|
281
|
+
backgroundImage: {
|
|
282
|
+
default: null,
|
|
283
|
+
':hover': {
|
|
284
|
+
'@media (hover: hover)': `linear-gradient(${colorVars['--color-overlay-hover']}, ${colorVars['--color-overlay-hover']})`,
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
':hover': {
|
|
288
|
+
color: colorVars['--color-icon-primary'],
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
chevronExpanded: {
|
|
292
|
+
transform: 'rotate(90deg)',
|
|
293
|
+
},
|
|
294
|
+
chevronIcon: {
|
|
295
|
+
display: 'inline-flex',
|
|
296
|
+
transitionProperty: 'transform',
|
|
297
|
+
transitionDuration: '150ms',
|
|
298
|
+
},
|
|
299
|
+
indentedCell: {
|
|
300
|
+
display: 'flex',
|
|
301
|
+
alignItems: 'center',
|
|
302
|
+
gap: spacingVars['--spacing-1'],
|
|
303
|
+
},
|
|
304
|
+
indent: (px: number) => ({
|
|
305
|
+
paddingInlineStart: `${px}px`,
|
|
306
|
+
}),
|
|
307
|
+
placeholder: {
|
|
308
|
+
display: 'inline-block',
|
|
309
|
+
width: '24px',
|
|
310
|
+
height: '24px',
|
|
311
|
+
flexShrink: '0',
|
|
312
|
+
},
|
|
313
|
+
clickableRow: {
|
|
314
|
+
cursor: 'pointer',
|
|
315
|
+
},
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// =============================================================================
|
|
319
|
+
// Chevron
|
|
320
|
+
// =============================================================================
|
|
321
|
+
|
|
322
|
+
function ExpansionChevron({
|
|
323
|
+
isExpanded,
|
|
324
|
+
onToggle,
|
|
325
|
+
ariaLabel,
|
|
326
|
+
}: {
|
|
327
|
+
isExpanded: boolean;
|
|
328
|
+
onToggle: () => void;
|
|
329
|
+
ariaLabel: string;
|
|
330
|
+
}) {
|
|
331
|
+
return (
|
|
332
|
+
<button
|
|
333
|
+
type="button"
|
|
334
|
+
{...stylex.props(expansionStyles.chevronButton)}
|
|
335
|
+
onClick={e => {
|
|
336
|
+
e.stopPropagation();
|
|
337
|
+
onToggle();
|
|
338
|
+
}}
|
|
339
|
+
aria-label={ariaLabel}
|
|
340
|
+
aria-expanded={isExpanded}>
|
|
341
|
+
<span
|
|
342
|
+
{...stylex.props(
|
|
343
|
+
expansionStyles.chevronIcon,
|
|
344
|
+
isExpanded && expansionStyles.chevronExpanded,
|
|
345
|
+
)}>
|
|
346
|
+
<Icon icon="chevronRight" size="xsm" />
|
|
347
|
+
</span>
|
|
348
|
+
</button>
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// =============================================================================
|
|
353
|
+
// Hook
|
|
354
|
+
// =============================================================================
|
|
355
|
+
|
|
356
|
+
export function useTableRowExpansion<T extends Record<string, unknown>>(
|
|
357
|
+
config: UseTableRowExpansionConfig<T>,
|
|
358
|
+
): TablePlugin<T> {
|
|
359
|
+
const {
|
|
360
|
+
expandedKeys,
|
|
361
|
+
onToggle,
|
|
362
|
+
getRowKey,
|
|
363
|
+
getChildren,
|
|
364
|
+
getDepth,
|
|
365
|
+
getIsItemExpandable,
|
|
366
|
+
hasRowClickExpansion = false,
|
|
367
|
+
isAllExpanded,
|
|
368
|
+
onToggleExpandAll,
|
|
369
|
+
} = config;
|
|
370
|
+
|
|
371
|
+
// Track the first non-plugin column key for indentation.
|
|
372
|
+
const firstUserColumnKeyRef = useRef<string | null>(null);
|
|
373
|
+
|
|
374
|
+
const expansionColumn = useMemo(
|
|
375
|
+
(): TableColumn<T> => ({
|
|
376
|
+
key: '__expansion',
|
|
377
|
+
header: '',
|
|
378
|
+
width: EXPANSION_COLUMN_WIDTH,
|
|
379
|
+
resizable: false,
|
|
380
|
+
renderCell: (item: T) => {
|
|
381
|
+
// Child rows (depth > 0) show their chevron inline in the first user
|
|
382
|
+
// column instead — don't double up here.
|
|
383
|
+
const depth = getDepth ? getDepth(item) : 0;
|
|
384
|
+
if (depth > 0) {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const key = getRowKey(item);
|
|
389
|
+
const expandable = getIsItemExpandable
|
|
390
|
+
? getIsItemExpandable(item)
|
|
391
|
+
: getChildren(item).length > 0;
|
|
392
|
+
if (!expandable) {
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
const isExpanded = expandedKeys.has(key);
|
|
396
|
+
return (
|
|
397
|
+
<ExpansionChevron
|
|
398
|
+
isExpanded={isExpanded}
|
|
399
|
+
onToggle={() => onToggle(key)}
|
|
400
|
+
ariaLabel={isExpanded ? 'Collapse row' : 'Expand row'}
|
|
401
|
+
/>
|
|
402
|
+
);
|
|
403
|
+
},
|
|
404
|
+
}),
|
|
405
|
+
[
|
|
406
|
+
expandedKeys,
|
|
407
|
+
onToggle,
|
|
408
|
+
getRowKey,
|
|
409
|
+
getChildren,
|
|
410
|
+
getIsItemExpandable,
|
|
411
|
+
getDepth,
|
|
412
|
+
],
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
return useMemo(
|
|
416
|
+
(): TablePlugin<T> => ({
|
|
417
|
+
transformColumns(columns: TableColumn<T>[]) {
|
|
418
|
+
// Track the first user column for indentation.
|
|
419
|
+
const firstUserCol = columns.find(c => !c.key.startsWith('__'));
|
|
420
|
+
firstUserColumnKeyRef.current = firstUserCol?.key ?? null;
|
|
421
|
+
|
|
422
|
+
// Wrap the first user column's renderCell to add depth indentation +
|
|
423
|
+
// an inline chevron for child rows. This is the inherited-columns
|
|
424
|
+
// pattern: child rows use the same columns but indent their first
|
|
425
|
+
// content cell.
|
|
426
|
+
const wrappedColumns = columns.map(col => {
|
|
427
|
+
if (col.key !== firstUserColumnKeyRef.current) {
|
|
428
|
+
return col;
|
|
429
|
+
}
|
|
430
|
+
const originalRenderCell = col.renderCell;
|
|
431
|
+
return {
|
|
432
|
+
...col,
|
|
433
|
+
renderCell: (item: T): ReactNode => {
|
|
434
|
+
const depth = getDepth ? getDepth(item) : 0;
|
|
435
|
+
const originalContent = originalRenderCell
|
|
436
|
+
? originalRenderCell(item)
|
|
437
|
+
: String(
|
|
438
|
+
((item as Record<string, unknown>)[col.key] as
|
|
439
|
+
| string
|
|
440
|
+
| number
|
|
441
|
+
| null
|
|
442
|
+
| undefined) ?? '',
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
if (depth === 0) {
|
|
446
|
+
return originalContent;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const indent = (depth - 1) * INDENT_PER_DEPTH;
|
|
450
|
+
const key = getRowKey(item);
|
|
451
|
+
const isExpanded = expandedKeys.has(key);
|
|
452
|
+
const expandable = getIsItemExpandable
|
|
453
|
+
? getIsItemExpandable(item)
|
|
454
|
+
: getChildren(item).length > 0;
|
|
455
|
+
|
|
456
|
+
const chevron = expandable ? (
|
|
457
|
+
<ExpansionChevron
|
|
458
|
+
isExpanded={isExpanded}
|
|
459
|
+
onToggle={() => onToggle(key)}
|
|
460
|
+
ariaLabel={isExpanded ? 'Collapse row' : 'Expand row'}
|
|
461
|
+
/>
|
|
462
|
+
) : (
|
|
463
|
+
<span {...stylex.props(expansionStyles.placeholder)} />
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
return (
|
|
467
|
+
<div
|
|
468
|
+
{...stylex.props(
|
|
469
|
+
expansionStyles.indentedCell,
|
|
470
|
+
indent > 0 && expansionStyles.indent(indent),
|
|
471
|
+
)}>
|
|
472
|
+
{chevron}
|
|
473
|
+
{originalContent}
|
|
474
|
+
</div>
|
|
475
|
+
);
|
|
476
|
+
},
|
|
477
|
+
};
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
return [expansionColumn, ...wrappedColumns];
|
|
481
|
+
},
|
|
482
|
+
|
|
483
|
+
transformHeaderCell(
|
|
484
|
+
props: HeaderCellRenderProps,
|
|
485
|
+
column: TableColumn<T>,
|
|
486
|
+
): HeaderCellRenderProps {
|
|
487
|
+
if (column.key !== '__expansion') {
|
|
488
|
+
return props;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Show expand-all toggle when the consumer provides the state + callback.
|
|
492
|
+
if (isAllExpanded !== undefined && onToggleExpandAll) {
|
|
493
|
+
const allExpanded = isAllExpanded === true;
|
|
494
|
+
return {
|
|
495
|
+
...props,
|
|
496
|
+
content: (
|
|
497
|
+
<button
|
|
498
|
+
type="button"
|
|
499
|
+
{...stylex.props(expansionStyles.chevronButton)}
|
|
500
|
+
onClick={() => onToggleExpandAll(!allExpanded)}
|
|
501
|
+
aria-label={
|
|
502
|
+
allExpanded ? 'Collapse all rows' : 'Expand all rows'
|
|
503
|
+
}>
|
|
504
|
+
<span
|
|
505
|
+
{...stylex.props(
|
|
506
|
+
expansionStyles.chevronIcon,
|
|
507
|
+
allExpanded && expansionStyles.chevronExpanded,
|
|
508
|
+
)}>
|
|
509
|
+
<Icon icon="chevronRight" size="xsm" />
|
|
510
|
+
</span>
|
|
511
|
+
</button>
|
|
512
|
+
),
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return {...props, content: null};
|
|
517
|
+
},
|
|
518
|
+
|
|
519
|
+
transformBodyCell(
|
|
520
|
+
props: BodyCellRenderProps,
|
|
521
|
+
column: TableColumn<T>,
|
|
522
|
+
item: T,
|
|
523
|
+
): BodyCellRenderProps {
|
|
524
|
+
// Contribute "Expand/Collapse row" context-menu action on every cell
|
|
525
|
+
// so right-clicking anywhere in the row shows the option.
|
|
526
|
+
const expandable = getIsItemExpandable
|
|
527
|
+
? getIsItemExpandable(item)
|
|
528
|
+
: getChildren(item).length > 0;
|
|
529
|
+
if (!expandable) {
|
|
530
|
+
return props;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const key = getRowKey(item);
|
|
534
|
+
const isExpanded = expandedKeys.has(key);
|
|
535
|
+
return {
|
|
536
|
+
...props,
|
|
537
|
+
contextMenuActions: () => [
|
|
538
|
+
...resolveContextActions(props.contextMenuActions),
|
|
539
|
+
{
|
|
540
|
+
id: 'row-expansion-toggle',
|
|
541
|
+
group: 'row-expansion',
|
|
542
|
+
label: isExpanded ? 'Collapse row' : 'Expand row',
|
|
543
|
+
icon: (
|
|
544
|
+
<Icon
|
|
545
|
+
icon={isExpanded ? 'chevronDown' : 'chevronRight'}
|
|
546
|
+
size="xsm"
|
|
547
|
+
aria-hidden
|
|
548
|
+
/>
|
|
549
|
+
),
|
|
550
|
+
onSelect: () => onToggle(key),
|
|
551
|
+
},
|
|
552
|
+
],
|
|
553
|
+
};
|
|
554
|
+
},
|
|
555
|
+
|
|
556
|
+
transformBodyRow(props: BodyRowRenderProps, item: T): BodyRowRenderProps {
|
|
557
|
+
if (!hasRowClickExpansion) {
|
|
558
|
+
return props;
|
|
559
|
+
}
|
|
560
|
+
const expandable = getIsItemExpandable
|
|
561
|
+
? getIsItemExpandable(item)
|
|
562
|
+
: getChildren(item).length > 0;
|
|
563
|
+
if (!expandable) {
|
|
564
|
+
return props;
|
|
565
|
+
}
|
|
566
|
+
const key = getRowKey(item);
|
|
567
|
+
return {
|
|
568
|
+
...props,
|
|
569
|
+
htmlProps: {
|
|
570
|
+
...props.htmlProps,
|
|
571
|
+
onClick: () => onToggle(key),
|
|
572
|
+
},
|
|
573
|
+
styles: [...props.styles, expansionStyles.clickableRow],
|
|
574
|
+
};
|
|
575
|
+
},
|
|
576
|
+
}),
|
|
577
|
+
[
|
|
578
|
+
expandedKeys,
|
|
579
|
+
getRowKey,
|
|
580
|
+
onToggle,
|
|
581
|
+
getChildren,
|
|
582
|
+
getDepth,
|
|
583
|
+
getIsItemExpandable,
|
|
584
|
+
hasRowClickExpansion,
|
|
585
|
+
isAllExpanded,
|
|
586
|
+
onToggleExpandAll,
|
|
587
|
+
expansionColumn,
|
|
588
|
+
],
|
|
589
|
+
);
|
|
590
|
+
}
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* @position Testing; validates sortable plugin implementation
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {describe, it, expect, vi} from 'vitest';
|
|
11
|
-
import {render, screen} from '@testing-library/react';
|
|
10
|
+
import {describe, it, expect, vi, beforeEach} from 'vitest';
|
|
11
|
+
import {render, screen, fireEvent} from '@testing-library/react';
|
|
12
12
|
import userEvent from '@testing-library/user-event';
|
|
13
13
|
import {useState} from 'react';
|
|
14
14
|
import {Table} from '../../Table';
|
|
@@ -620,3 +620,92 @@ describe('useTableSortable', () => {
|
|
|
620
620
|
});
|
|
621
621
|
});
|
|
622
622
|
});
|
|
623
|
+
|
|
624
|
+
// =============================================================================
|
|
625
|
+
// Context-menu actions (colocated with the sortable plugin)
|
|
626
|
+
// =============================================================================
|
|
627
|
+
|
|
628
|
+
describe('useTableSortable — context menu actions', () => {
|
|
629
|
+
// jsdom doesn't implement the Popover API; mock it so the menu can "open"
|
|
630
|
+
// and its items become queryable (as hidden).
|
|
631
|
+
beforeEach(() => {
|
|
632
|
+
HTMLElement.prototype.showPopover = vi.fn(function (this: HTMLElement) {
|
|
633
|
+
this.setAttribute('popover-open', '');
|
|
634
|
+
const event = new Event('toggle', {bubbles: false});
|
|
635
|
+
Object.defineProperty(event, 'newState', {value: 'open'});
|
|
636
|
+
this.dispatchEvent(event);
|
|
637
|
+
});
|
|
638
|
+
HTMLElement.prototype.hidePopover = vi.fn(function (this: HTMLElement) {
|
|
639
|
+
this.removeAttribute('popover-open');
|
|
640
|
+
const event = new Event('toggle', {bubbles: false});
|
|
641
|
+
Object.defineProperty(event, 'newState', {value: 'closed'});
|
|
642
|
+
this.dispatchEvent(event);
|
|
643
|
+
});
|
|
644
|
+
const originalMatches = HTMLElement.prototype.matches;
|
|
645
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
646
|
+
(HTMLElement.prototype as any).matches = function (
|
|
647
|
+
selector: string,
|
|
648
|
+
): boolean {
|
|
649
|
+
if (selector === ':popover-open') {
|
|
650
|
+
return this.hasAttribute('popover-open');
|
|
651
|
+
}
|
|
652
|
+
return originalMatches.call(this, selector);
|
|
653
|
+
};
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
it('offers Sort ascending/descending on a sortable header, and Clear sort once sorted', () => {
|
|
657
|
+
render(<SortableTable allowUnsortedState />);
|
|
658
|
+
|
|
659
|
+
// Unsorted: asc + desc, no "Clear sort".
|
|
660
|
+
fireEvent.contextMenu(screen.getByText('Name'));
|
|
661
|
+
expect(
|
|
662
|
+
screen.getAllByRole('menuitem', {name: 'Sort ascending', hidden: true})
|
|
663
|
+
.length,
|
|
664
|
+
).toBeGreaterThan(0);
|
|
665
|
+
expect(
|
|
666
|
+
screen.getAllByRole('menuitem', {name: 'Sort descending', hidden: true})
|
|
667
|
+
.length,
|
|
668
|
+
).toBeGreaterThan(0);
|
|
669
|
+
expect(
|
|
670
|
+
screen.queryByRole('menuitem', {name: 'Clear sort', hidden: true}),
|
|
671
|
+
).not.toBeInTheDocument();
|
|
672
|
+
|
|
673
|
+
// Apply ascending → "Clear sort" now appears.
|
|
674
|
+
fireEvent.click(
|
|
675
|
+
screen.getAllByRole('menuitem', {name: 'Sort ascending', hidden: true})[0],
|
|
676
|
+
);
|
|
677
|
+
fireEvent.contextMenu(screen.getByText('Name'));
|
|
678
|
+
expect(
|
|
679
|
+
screen.getAllByRole('menuitem', {name: 'Clear sort', hidden: true}).length,
|
|
680
|
+
).toBeGreaterThan(0);
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
it('resolves fresh actions on each open as sort state changes (lazy getter)', () => {
|
|
684
|
+
const onSortChange = vi.fn();
|
|
685
|
+
render(<SortableTable allowUnsortedState onSortChange={onSortChange} />);
|
|
686
|
+
|
|
687
|
+
// Open (unsorted) and pick descending.
|
|
688
|
+
fireEvent.contextMenu(screen.getByText('Name'));
|
|
689
|
+
fireEvent.click(
|
|
690
|
+
screen.getAllByRole('menuitem', {
|
|
691
|
+
name: 'Sort descending',
|
|
692
|
+
hidden: true,
|
|
693
|
+
})[0],
|
|
694
|
+
);
|
|
695
|
+
expect(onSortChange).toHaveBeenLastCalledWith([
|
|
696
|
+
{sortKey: 'name', direction: 'descending'},
|
|
697
|
+
]);
|
|
698
|
+
|
|
699
|
+
// Re-open: the getter recomputes against the now-descending state, so
|
|
700
|
+
// "Clear sort" is present and clicking it clears — proving the actions are
|
|
701
|
+
// freshly derived on each open, not memoized from the first render.
|
|
702
|
+
fireEvent.contextMenu(screen.getByText('Name'));
|
|
703
|
+
const clear = screen.getAllByRole('menuitem', {
|
|
704
|
+
name: 'Clear sort',
|
|
705
|
+
hidden: true,
|
|
706
|
+
});
|
|
707
|
+
expect(clear.length).toBeGreaterThan(0);
|
|
708
|
+
fireEvent.click(clear[0]);
|
|
709
|
+
expect(onSortChange).toHaveBeenLastCalledWith([]);
|
|
710
|
+
});
|
|
711
|
+
});
|