@astryxdesign/core 0.1.1 → 0.1.2-canary.04e71b2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +105 -0
- package/README.md +131 -13
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +11 -5
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +4 -1
- package/dist/Banner/Banner.d.ts +7 -0
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +9 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +24 -5
- package/dist/Button/Button.d.ts +12 -2
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +53 -17
- package/dist/Calendar/Calendar.d.ts +5 -4
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +82 -43
- package/dist/Calendar/hooks/index.d.ts +0 -2
- package/dist/Calendar/hooks/index.d.ts.map +1 -1
- package/dist/Calendar/hooks/index.js +1 -2
- package/dist/Calendar/index.d.ts +3 -3
- package/dist/Calendar/index.d.ts.map +1 -1
- package/dist/Calendar/index.js +1 -1
- package/dist/Calendar/styles.d.ts +3 -9
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +3 -11
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +17 -3
- package/dist/Center/Center.d.ts +11 -1
- package/dist/Center/Center.d.ts.map +1 -1
- package/dist/Center/Center.js +9 -3
- package/dist/Chat/ChatMessageList.d.ts +14 -1
- package/dist/Chat/ChatMessageList.d.ts.map +1 -1
- package/dist/Chat/ChatMessageList.js +2 -0
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +4 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts +23 -2
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +51 -9
- package/dist/CheckboxList/CheckboxList.d.ts +13 -1
- package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxList.js +39 -9
- package/dist/CheckboxList/CheckboxListContext.d.ts +7 -0
- package/dist/CheckboxList/CheckboxListContext.d.ts.map +1 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +3 -3
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +49 -37
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +5 -5
- package/dist/ContextMenu/ContextMenu.d.ts +4 -5
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +93 -11
- package/dist/DateInput/DateInput.d.ts +23 -1
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +59 -8
- package/dist/DateRangeInput/DateRangeInput.d.ts +23 -1
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +42 -9
- package/dist/DateTimeInput/DateTimeInput.d.ts +35 -2
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +78 -15
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +12 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts +1 -8
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +42 -14
- package/dist/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/EmptyState/EmptyState.js +7 -1
- package/dist/Field/Field.d.ts +19 -2
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +4 -0
- package/dist/Field/FieldLabel.d.ts +21 -2
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +41 -26
- package/dist/FileInput/FileInput.d.ts +22 -1
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +56 -10
- package/dist/Grid/Grid.d.ts +11 -1
- package/dist/Grid/Grid.d.ts.map +1 -1
- package/dist/Grid/Grid.js +8 -0
- package/dist/HoverCard/HoverCard.d.ts +2 -2
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +18 -6
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +7 -3
- package/dist/InputGroup/InputGroup.d.ts +2 -2
- package/dist/InputGroup/InputGroup.d.ts.map +1 -1
- package/dist/InputGroup/InputGroup.js +14 -5
- package/dist/InputGroup/InputGroupContext.d.ts +4 -0
- package/dist/InputGroup/InputGroupContext.d.ts.map +1 -1
- package/dist/InputGroup/InputGroupContext.js +2 -2
- package/dist/InputGroup/index.d.ts +1 -0
- package/dist/InputGroup/index.d.ts.map +1 -1
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +34 -2
- package/dist/Layer/anchorName.d.ts +20 -0
- package/dist/Layer/anchorName.d.ts.map +1 -0
- package/dist/Layer/anchorName.js +36 -0
- package/dist/Layer/layerAnimations.stylex.d.ts +4 -0
- package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
- package/dist/Layer/layerAnimations.stylex.js +8 -4
- package/dist/Layer/useLayer.d.ts +29 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +55 -11
- package/dist/Layout/Layout.d.ts +4 -11
- package/dist/Layout/Layout.d.ts.map +1 -1
- package/dist/Layout/Layout.js +10 -11
- package/dist/Layout/LayoutFooter.d.ts +2 -2
- package/dist/Layout/LayoutFooter.d.ts.map +1 -1
- package/dist/Layout/LayoutHeader.d.ts +2 -2
- package/dist/Layout/LayoutHeader.d.ts.map +1 -1
- package/dist/Layout/LayoutPanel.d.ts +2 -2
- package/dist/Layout/LayoutPanel.d.ts.map +1 -1
- package/dist/Layout/padding.stylex.d.ts +51 -0
- package/dist/Layout/padding.stylex.d.ts.map +1 -1
- package/dist/Layout/padding.stylex.js +63 -0
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +4 -2
- package/dist/Link/Link.d.ts +17 -2
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +20 -9
- package/dist/Link/LinkProvider.d.ts +1 -0
- package/dist/Link/LinkProvider.d.ts.map +1 -1
- package/dist/Link/LinkProvider.js +1 -0
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +18 -3
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +13 -0
- package/dist/MoreMenu/MoreMenu.d.ts +1 -7
- package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
- package/dist/MoreMenu/MoreMenu.js +0 -2
- package/dist/MultiSelector/MultiSelector.d.ts +25 -2
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +103 -22
- package/dist/MultiSelector/hooks.d.ts +12 -1
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +14 -1
- package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenu.js +34 -3
- package/dist/NumberInput/NumberInput.d.ts +23 -2
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +62 -12
- package/dist/Pagination/Pagination.d.ts +1 -1
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +46 -28
- package/dist/Popover/usePopover.d.ts +25 -2
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +18 -6
- package/dist/PowerSearch/PowerSearch.d.ts +11 -1
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +6 -1
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +3 -5
- package/dist/RadioList/RadioList.d.ts +20 -2
- package/dist/RadioList/RadioList.d.ts.map +1 -1
- package/dist/RadioList/RadioList.js +105 -9
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +13 -2
- package/dist/SegmentedControl/SegmentedControl.d.ts +13 -2
- package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControl.js +78 -44
- package/dist/SegmentedControl/SegmentedControlContext.d.ts +7 -0
- package/dist/SegmentedControl/SegmentedControlContext.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +13 -2
- package/dist/Selector/Selector.d.ts +22 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +84 -23
- package/dist/Selector/hooks.d.ts +8 -1
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +14 -1
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +1 -1
- package/dist/Skeleton/Skeleton.d.ts.map +1 -1
- package/dist/Skeleton/Skeleton.js +8 -2
- package/dist/Slider/Slider.d.ts +21 -0
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +38 -11
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +1 -1
- package/dist/Stack/Stack.d.ts +38 -23
- package/dist/Stack/Stack.d.ts.map +1 -1
- package/dist/Stack/Stack.js +25 -1
- package/dist/Stack/StackItem.d.ts +12 -23
- package/dist/Stack/StackItem.d.ts.map +1 -1
- package/dist/Stack/StackItem.js +8 -1
- package/dist/Switch/Switch.d.ts +23 -2
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +41 -11
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +6 -0
- package/dist/TabList/TabList.d.ts +16 -4
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +86 -10
- package/dist/TabList/TabListContext.d.ts +5 -0
- package/dist/TabList/TabListContext.d.ts.map +1 -1
- package/dist/TabList/TabListContext.js +5 -0
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +6 -1
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +38 -16
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +36 -7
- package/dist/Table/TableCell.d.ts +8 -1
- package/dist/Table/TableCell.d.ts.map +1 -1
- package/dist/Table/TableCell.js +10 -10
- package/dist/Table/TableHeaderCell.d.ts +8 -1
- package/dist/Table/TableHeaderCell.d.ts.map +1 -1
- package/dist/Table/TableHeaderCell.js +16 -16
- package/dist/Table/TableRow.d.ts +6 -1
- package/dist/Table/TableRow.d.ts.map +1 -1
- package/dist/Table/TableRow.js +15 -7
- package/dist/Table/index.d.ts +4 -1
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +3 -2
- package/dist/Table/plugins/pagination/paginateData.d.ts +2 -1
- package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
- package/dist/Table/plugins/pagination/paginateData.js +8 -3
- package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
- package/dist/Table/plugins/pagination/useTablePagination.js +6 -1
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +59 -3
- package/dist/Table/plugins/stickyColumns/index.d.ts +3 -0
- package/dist/Table/plugins/stickyColumns/index.d.ts.map +1 -0
- package/dist/Table/plugins/stickyColumns/index.js +3 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts +25 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +369 -0
- package/dist/Table/tableContextMenu.d.ts +33 -0
- package/dist/Table/tableContextMenu.d.ts.map +1 -0
- package/dist/Table/tableContextMenu.js +133 -0
- package/dist/Table/types.d.ts +161 -5
- package/dist/Table/types.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.js +1 -1
- package/dist/Text/text.stylex.d.ts +2 -2
- package/dist/Text/text.stylex.js +2 -2
- package/dist/TextArea/TextArea.d.ts +22 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +41 -9
- package/dist/TextInput/TextInput.d.ts +23 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +55 -10
- package/dist/TimeInput/TimeInput.d.ts +23 -1
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +53 -10
- package/dist/Timestamp/Timestamp.d.ts +1 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +28 -3
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +14 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +132 -3
- package/dist/ToggleButton/ToggleButton.d.ts +7 -9
- package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButton.js +34 -57
- package/dist/Tokenizer/Tokenizer.d.ts +12 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +27 -5
- package/dist/Toolbar/Toolbar.d.ts +3 -3
- package/dist/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/Toolbar/Toolbar.js +51 -7
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +57 -9
- package/dist/TreeList/TreeList.d.ts +1 -1
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +72 -2
- package/dist/TreeList/TreeListItem.d.ts +11 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +51 -12
- package/dist/TreeList/treeListItem.markers.stylex.d.ts +16 -0
- package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +1 -0
- package/dist/TreeList/treeListItem.markers.stylex.js +22 -0
- package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +67 -6
- package/dist/Typeahead/Typeahead.d.ts +24 -1
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +29 -5
- package/dist/VisuallyHidden/VisuallyHidden.d.ts +61 -0
- package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
- package/dist/VisuallyHidden/VisuallyHidden.js +65 -0
- package/dist/VisuallyHidden/index.d.ts +11 -0
- package/dist/VisuallyHidden/index.d.ts.map +1 -0
- package/dist/VisuallyHidden/index.js +13 -0
- package/dist/astryx.css +40 -1
- package/dist/astryx.umd.js +147 -0
- package/dist/astryx.umd.js.map +7 -0
- package/dist/hooks/focusableSelector.d.ts +22 -0
- package/dist/hooks/focusableSelector.d.ts.map +1 -0
- package/dist/hooks/focusableSelector.js +24 -0
- package/dist/hooks/index.d.ts +12 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +7 -2
- package/dist/hooks/useAnnounce.d.ts +40 -0
- package/dist/hooks/useAnnounce.d.ts.map +1 -0
- package/dist/hooks/useAnnounce.js +142 -0
- package/dist/hooks/useClickableContainer.d.ts +16 -1
- package/dist/hooks/useClickableContainer.d.ts.map +1 -1
- package/dist/hooks/useClickableContainer.js +16 -4
- package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
- package/dist/hooks/useEntryAnimation.js +4 -4
- package/dist/hooks/useFocusTrap.d.ts +18 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +87 -3
- package/dist/hooks/useGridFocus.d.ts +88 -1
- package/dist/hooks/useGridFocus.d.ts.map +1 -1
- package/dist/hooks/useGridFocus.js +261 -62
- package/dist/hooks/useKeyboardHint.d.ts +82 -0
- package/dist/hooks/useKeyboardHint.d.ts.map +1 -0
- package/dist/hooks/useKeyboardHint.js +220 -0
- package/dist/hooks/useListFocus.d.ts +78 -7
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +305 -52
- package/dist/hooks/useLongPress.d.ts +21 -0
- package/dist/hooks/useLongPress.d.ts.map +1 -0
- package/dist/hooks/useLongPress.js +89 -0
- package/dist/hooks/useTreeFocus.d.ts +157 -0
- package/dist/hooks/useTreeFocus.d.ts.map +1 -0
- package/dist/hooks/useTreeFocus.js +337 -0
- package/dist/hooks/useTypeahead.d.ts +63 -0
- package/dist/hooks/useTypeahead.d.ts.map +1 -0
- package/dist/hooks/useTypeahead.js +117 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/generateThemeRules.js +1 -1
- package/dist/theme/syntax/SyntaxTheme.d.ts +1 -1
- package/dist/theme/syntax/SyntaxTheme.js +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.js +2 -2
- package/dist/theme/syntax/presets.d.ts +1 -1
- package/dist/theme/syntax/presets.d.ts.map +1 -1
- package/dist/theme/syntax/presets.js +1 -1
- package/dist/theme/syntax/tokens.d.ts +1 -1
- package/dist/theme/syntax/tokens.js +1 -1
- package/dist/theme/types.d.ts +1 -1
- package/dist/utils/dateTypes.d.ts +12 -0
- package/dist/utils/dateTypes.d.ts.map +1 -1
- package/dist/utils/dateTypes.js +41 -1
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/inputAria.d.ts +29 -0
- package/dist/utils/inputAria.d.ts.map +1 -0
- package/dist/utils/inputAria.js +30 -0
- package/dist/utils/timeParser.d.ts.map +1 -1
- package/dist/utils/timeParser.js +5 -2
- package/package.json +15 -5
- package/src/Avatar/Avatar.test.tsx +37 -0
- package/src/Avatar/Avatar.tsx +10 -5
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +3 -0
- package/src/Banner/Banner.doc.mjs +8 -0
- package/src/Banner/Banner.test.tsx +16 -7
- package/src/Banner/Banner.tsx +9 -2
- package/src/Breadcrumbs/BreadcrumbItem.tsx +25 -7
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -10
- package/src/Button/Button.doc.mjs +6 -0
- package/src/Button/Button.test.tsx +105 -11
- package/src/Button/Button.tsx +76 -21
- package/src/Calendar/Calendar.doc.mjs +4 -4
- package/src/Calendar/Calendar.test.tsx +168 -30
- package/src/Calendar/Calendar.tsx +121 -66
- package/src/Calendar/hooks/index.ts +0 -6
- package/src/Calendar/index.ts +1 -3
- package/src/Calendar/styles.ts +4 -9
- package/src/Carousel/Carousel.doc.mjs +7 -1
- package/src/Carousel/Carousel.test.tsx +20 -0
- package/src/Carousel/Carousel.tsx +16 -1
- package/src/Center/Center.doc.mjs +12 -2
- package/src/Center/Center.tsx +28 -3
- package/src/Chat/ChatComposer.doc.mjs +3 -0
- package/src/Chat/ChatComposerDrawer.doc.mjs +12 -0
- package/src/Chat/ChatMessageList.doc.mjs +8 -0
- package/src/Chat/ChatMessageList.test.tsx +18 -0
- package/src/Chat/ChatMessageList.tsx +16 -0
- package/src/Chat/useTriggerMenu.tsx +3 -0
- package/src/CheckboxInput/CheckboxInput.doc.mjs +18 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +172 -27
- package/src/CheckboxInput/CheckboxInput.tsx +78 -6
- package/src/CheckboxList/CheckboxList.doc.mjs +9 -0
- package/src/CheckboxList/CheckboxList.test.tsx +169 -16
- package/src/CheckboxList/CheckboxList.tsx +56 -3
- package/src/CheckboxList/CheckboxListContext.tsx +7 -0
- package/src/Citation/Citation.doc.mjs +10 -0
- package/src/Citation/Citation.test.tsx +117 -0
- package/src/Citation/Citation.tsx +9 -1
- package/src/ClickableCard/ClickableCard.doc.mjs +15 -0
- package/src/CodeBlock/CodeBlock.test.tsx +115 -0
- package/src/CodeBlock/CodeBlock.tsx +61 -33
- package/src/CommandPalette/CommandPalette.test.tsx +47 -1
- package/src/CommandPalette/CommandPalette.tsx +9 -21
- package/src/ContextMenu/ContextMenu.doc.mjs +4 -4
- package/src/ContextMenu/ContextMenu.test.tsx +155 -1
- package/src/ContextMenu/ContextMenu.tsx +113 -16
- package/src/DateInput/DateInput.doc.mjs +281 -56
- package/src/DateInput/DateInput.test.tsx +188 -2
- package/src/DateInput/DateInput.tsx +89 -10
- package/src/DateRangeInput/DateRangeInput.doc.mjs +251 -46
- package/src/DateRangeInput/DateRangeInput.test.tsx +182 -20
- package/src/DateRangeInput/DateRangeInput.tsx +63 -5
- package/src/DateTimeInput/DateTimeInput.doc.mjs +368 -67
- package/src/DateTimeInput/DateTimeInput.test.tsx +279 -11
- package/src/DateTimeInput/DateTimeInput.tsx +125 -17
- package/src/Dialog/Dialog.doc.mjs +2 -2
- package/src/Dialog/Dialog.tsx +12 -0
- package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -8
- package/src/DropdownMenu/DropdownMenu.test.tsx +56 -42
- package/src/DropdownMenu/DropdownMenu.tsx +52 -18
- package/src/EmptyState/EmptyState.test.tsx +4 -2
- package/src/EmptyState/EmptyState.tsx +6 -2
- package/src/Field/Field.test.tsx +32 -0
- package/src/Field/Field.tsx +23 -5
- package/src/Field/FieldLabel.tsx +55 -17
- package/src/FileInput/FileInput.doc.mjs +17 -0
- package/src/FileInput/FileInput.test.tsx +283 -49
- package/src/FileInput/FileInput.tsx +76 -4
- package/src/Grid/Grid.doc.mjs +14 -4
- package/src/Grid/Grid.tsx +20 -0
- package/src/HoverCard/HoverCard.doc.mjs +3 -0
- package/src/HoverCard/HoverCard.test.tsx +189 -2
- package/src/HoverCard/HoverCard.tsx +20 -16
- package/src/HoverCard/useHoverCard.tsx +13 -10
- package/src/Icon/Icon.doc.mjs +8 -0
- package/src/InputGroup/InputGroup.doc.mjs +2 -2
- package/src/InputGroup/InputGroup.test.tsx +98 -60
- package/src/InputGroup/InputGroup.tsx +21 -4
- package/src/InputGroup/InputGroupContext.ts +9 -4
- package/src/InputGroup/index.ts +1 -0
- package/src/Kbd/Kbd.test.tsx +22 -4
- package/src/Kbd/Kbd.tsx +37 -12
- package/src/Layer/anchorName.test.ts +146 -0
- package/src/Layer/anchorName.ts +46 -0
- package/src/Layer/layerAnimations.stylex.ts +20 -4
- package/src/Layer/useLayer.doc.mjs +12 -2
- package/src/Layer/useLayer.tsx +100 -15
- package/src/Layout/Layout.doc.mjs +1 -1
- package/src/Layout/Layout.tsx +8 -16
- package/src/Layout/LayoutFooter.doc.mjs +4 -4
- package/src/Layout/LayoutFooter.tsx +3 -3
- package/src/Layout/LayoutHeader.doc.mjs +4 -4
- package/src/Layout/LayoutHeader.tsx +3 -3
- package/src/Layout/LayoutPanel.tsx +3 -3
- package/src/Layout/padding.stylex.ts +52 -0
- package/src/Lightbox/Lightbox.doc.mjs +9 -2
- package/src/Lightbox/Lightbox.test.tsx +53 -5
- package/src/Lightbox/Lightbox.tsx +9 -4
- package/src/Link/Link.doc.mjs +14 -0
- package/src/Link/Link.test.tsx +52 -2
- package/src/Link/Link.tsx +42 -7
- package/src/Link/LinkProvider.tsx +1 -0
- package/src/List/List.doc.mjs +7 -0
- package/src/Markdown/Markdown.doc.mjs +2 -0
- package/src/Markdown/Markdown.test.tsx +28 -26
- package/src/Markdown/Markdown.tsx +21 -6
- package/src/MetadataList/MetadataListItem.doc.mjs +4 -0
- package/src/MobileNav/MobileNav.doc.mjs +8 -8
- package/src/MobileNav/MobileNav.tsx +13 -0
- package/src/MobileNav/MobileNavReopen.test.tsx +118 -0
- package/src/MoreMenu/MoreMenu.doc.mjs +2 -17
- package/src/MoreMenu/MoreMenu.tsx +0 -9
- package/src/MultiSelector/MultiSelector.doc.mjs +25 -0
- package/src/MultiSelector/MultiSelector.test.tsx +375 -8
- package/src/MultiSelector/MultiSelector.tsx +145 -21
- package/src/MultiSelector/hooks.ts +27 -0
- package/src/NavMenu/NavHeadingMenu.test.tsx +77 -1
- package/src/NavMenu/NavHeadingMenu.tsx +50 -3
- package/src/NumberInput/NumberInput.doc.mjs +17 -0
- package/src/NumberInput/NumberInput.test.tsx +242 -40
- package/src/NumberInput/NumberInput.tsx +89 -11
- package/src/OverflowList/OverflowList.doc.mjs +17 -0
- package/src/Pagination/Pagination.doc.mjs +3 -3
- package/src/Pagination/Pagination.test.tsx +250 -14
- package/src/Pagination/Pagination.tsx +54 -29
- package/src/Popover/usePopover.doc.mjs +7 -3
- package/src/Popover/usePopover.tsx +49 -6
- package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
- package/src/PowerSearch/PowerSearch.test.tsx +97 -1
- package/src/PowerSearch/PowerSearch.tsx +16 -3
- package/src/ProgressBar/ProgressBar.test.tsx +45 -27
- package/src/ProgressBar/ProgressBar.tsx +3 -4
- package/src/RadioList/RadioList.doc.mjs +9 -0
- package/src/RadioList/RadioList.test.tsx +252 -16
- package/src/RadioList/RadioList.tsx +166 -10
- package/src/RadioList/RadioListItem.tsx +14 -2
- package/src/Resizable/Resizable.doc.mjs +1 -1
- package/src/Section/Section.doc.mjs +11 -0
- package/src/SegmentedControl/SegmentedControl.doc.mjs +9 -0
- package/src/SegmentedControl/SegmentedControl.test.tsx +214 -42
- package/src/SegmentedControl/SegmentedControl.tsx +102 -54
- package/src/SegmentedControl/SegmentedControlContext.ts +7 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +14 -1
- package/src/SelectableCard/SelectableCard.doc.mjs +15 -0
- package/src/Selector/Selector.doc.mjs +25 -0
- package/src/Selector/Selector.test.tsx +322 -15
- package/src/Selector/Selector.tsx +126 -40
- package/src/Selector/hooks.ts +23 -0
- package/src/SideNav/SideNav.test.tsx +16 -0
- package/src/SideNav/SideNavItem.tsx +2 -4
- package/src/Skeleton/Skeleton.doc.mjs +11 -1
- package/src/Skeleton/Skeleton.test.tsx +25 -0
- package/src/Skeleton/Skeleton.tsx +11 -1
- package/src/Slider/Slider.doc.mjs +19 -0
- package/src/Slider/Slider.test.tsx +158 -18
- package/src/Slider/Slider.tsx +54 -6
- package/src/Spinner/Spinner.tsx +7 -1
- package/src/Stack/Stack.doc.mjs +77 -0
- package/src/Stack/Stack.test.tsx +55 -5
- package/src/Stack/Stack.tsx +73 -24
- package/src/Stack/StackItem.test.tsx +23 -0
- package/src/Stack/StackItem.tsx +20 -23
- package/src/Switch/Switch.doc.mjs +15 -0
- package/src/Switch/Switch.test.tsx +162 -27
- package/src/Switch/Switch.tsx +61 -21
- package/src/TabList/Tab.tsx +6 -0
- package/src/TabList/TabList.doc.mjs +12 -0
- package/src/TabList/TabList.test.tsx +208 -0
- package/src/TabList/TabList.tsx +102 -12
- package/src/TabList/TabListContext.ts +7 -3
- package/src/TabList/TabMenu.tsx +6 -3
- package/src/Table/BaseTable.tsx +72 -41
- package/src/Table/Table.doc.mjs +14 -0
- package/src/Table/Table.test.tsx +39 -30
- package/src/Table/Table.tsx +27 -1
- package/src/Table/TableCell.tsx +25 -23
- package/src/Table/TableHeaderCell.tsx +28 -29
- package/src/Table/TableRow.tsx +37 -7
- package/src/Table/index.ts +6 -2
- package/src/Table/plugins/pagination/paginateData.ts +10 -3
- package/src/Table/plugins/pagination/useTablePagination.test.tsx +16 -0
- package/src/Table/plugins/pagination/useTablePagination.tsx +8 -1
- package/src/Table/plugins/sortable/useTableSortable.test.tsx +91 -2
- package/src/Table/plugins/sortable/useTableSortable.tsx +53 -1
- package/src/Table/plugins/stickyColumns/index.ts +4 -0
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.test.tsx +163 -0
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +407 -0
- package/src/Table/tableContextMenu.test.tsx +157 -0
- package/src/Table/tableContextMenu.tsx +142 -0
- package/src/Table/types.ts +175 -4
- package/src/Table/useBaseTablePlugins.ts +1 -0
- package/src/Table/useTableColumnResize.doc.mjs +96 -0
- package/src/Table/useTableStickyColumns.doc.mjs +59 -0
- package/src/Text/Heading.doc.mjs +15 -2
- package/src/Text/Text.doc.mjs +7 -1
- package/src/Text/text.stylex.ts +2 -2
- package/src/TextArea/TextArea.doc.mjs +17 -0
- package/src/TextArea/TextArea.test.tsx +167 -35
- package/src/TextArea/TextArea.tsx +62 -15
- package/src/TextInput/TextInput.doc.mjs +17 -0
- package/src/TextInput/TextInput.test.tsx +168 -34
- package/src/TextInput/TextInput.tsx +77 -9
- package/src/TimeInput/TimeInput.doc.mjs +335 -60
- package/src/TimeInput/TimeInput.test.tsx +144 -7
- package/src/TimeInput/TimeInput.tsx +74 -5
- package/src/Timestamp/Timestamp.doc.mjs +9 -0
- package/src/Timestamp/Timestamp.test.tsx +44 -18
- package/src/Timestamp/Timestamp.tsx +30 -10
- package/src/Toast/Toast.tsx +14 -0
- package/src/Toast/ToastViewport.test.tsx +204 -0
- package/src/Toast/ToastViewport.tsx +167 -21
- package/src/ToggleButton/ToggleButton.doc.mjs +9 -3
- package/src/ToggleButton/ToggleButton.test.tsx +39 -18
- package/src/ToggleButton/ToggleButton.tsx +46 -83
- package/src/Tokenizer/Tokenizer.doc.mjs +15 -0
- package/src/Tokenizer/Tokenizer.test.tsx +105 -1
- package/src/Tokenizer/Tokenizer.tsx +41 -2
- package/src/Toolbar/Toolbar.doc.mjs +65 -5
- package/src/Toolbar/Toolbar.test.tsx +109 -6
- package/src/Toolbar/Toolbar.tsx +59 -5
- package/src/Tooltip/Tooltip.test.tsx +81 -0
- package/src/Tooltip/useTooltip.tsx +57 -11
- package/src/TreeList/TreeList.test.tsx +295 -6
- package/src/TreeList/TreeList.tsx +73 -1
- package/src/TreeList/TreeListItem.tsx +51 -5
- package/src/TreeList/treeListItem.markers.stylex.ts +20 -0
- package/src/Typeahead/BaseTypeahead.tsx +86 -9
- package/src/Typeahead/Typeahead.doc.mjs +136 -30
- package/src/Typeahead/Typeahead.test.tsx +331 -1
- package/src/Typeahead/Typeahead.tsx +52 -1
- package/src/VisuallyHidden/VisuallyHidden.doc.mjs +80 -0
- package/src/VisuallyHidden/VisuallyHidden.test.tsx +76 -0
- package/src/VisuallyHidden/VisuallyHidden.tsx +113 -0
- package/src/VisuallyHidden/index.ts +15 -0
- package/src/hooks/focusableSelector.ts +25 -0
- package/src/hooks/index.ts +28 -2
- package/src/hooks/useAnnounce.test.tsx +101 -0
- package/src/hooks/useAnnounce.ts +168 -0
- package/src/hooks/useClickableContainer.ts +16 -4
- package/src/hooks/useEntryAnimation.ts +16 -4
- package/src/hooks/useFocusTrap.test.tsx +132 -0
- package/src/hooks/useFocusTrap.ts +98 -4
- package/src/hooks/useGridFocus.doc.mjs +40 -2
- package/src/hooks/useGridFocus.test.tsx +132 -0
- package/src/hooks/useGridFocus.ts +343 -67
- package/src/hooks/useImageMode.test.ts +133 -0
- package/src/hooks/useKeyboardHint.doc.mjs +101 -0
- package/src/hooks/useKeyboardHint.test.tsx +70 -0
- package/src/hooks/useKeyboardHint.tsx +332 -0
- package/src/hooks/useListFocus.doc.mjs +50 -10
- package/src/hooks/useListFocus.test.tsx +375 -0
- package/src/hooks/useListFocus.ts +395 -57
- package/src/hooks/useLongPress.test.tsx +134 -0
- package/src/hooks/useLongPress.ts +119 -0
- package/src/hooks/useTreeFocus.doc.mjs +140 -0
- package/src/hooks/useTreeFocus.test.tsx +214 -0
- package/src/hooks/useTreeFocus.ts +559 -0
- package/src/hooks/useTypeahead.test.tsx +109 -0
- package/src/hooks/useTypeahead.ts +183 -0
- package/src/index.ts +1 -0
- package/src/theme/derivedVarRegistry.test.ts +4 -0
- package/src/theme/generateThemeRules.test.ts +7 -8
- package/src/theme/generateThemeRules.ts +1 -1
- package/src/theme/syntax/SyntaxTheme.tsx +1 -1
- package/src/theme/syntax/defineSyntaxTheme.ts +20 -11
- package/src/theme/syntax/presets.ts +5 -2
- package/src/theme/syntax/tokens.ts +1 -1
- package/src/theme/types.ts +1 -1
- package/src/utils/dateTypes.test.ts +40 -0
- package/src/utils/dateTypes.ts +40 -0
- package/src/utils/index.ts +9 -0
- package/src/utils/inputAria.test.ts +39 -0
- package/src/utils/inputAria.ts +58 -0
- package/src/utils/timeParser.test.ts +10 -0
- package/src/utils/timeParser.ts +5 -2
- package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts +0 -57
- package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts.map +0 -1
- package/dist/Calendar/hooks/useCalendarRovingTabindex.js +0 -96
- package/src/Calendar/hooks/useCalendarRovingTabindex.ts +0 -118
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import {describe, it, expect, vi, beforeAll, afterAll} from 'vitest';
|
|
13
|
-
import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
13
|
+
import {render, screen, fireEvent, waitFor, act} from '@testing-library/react';
|
|
14
|
+
import {renderToString} from 'react-dom/server';
|
|
15
|
+
import {hydrateRoot} from 'react-dom/client';
|
|
16
|
+
import {StrictMode} from 'react';
|
|
14
17
|
import {HoverCard} from './HoverCard';
|
|
15
18
|
|
|
16
19
|
// Store original matches to restore later
|
|
@@ -55,6 +58,17 @@ describe('HoverCard', () => {
|
|
|
55
58
|
expect(screen.getByRole('button', {name: 'Trigger'})).toBeInTheDocument();
|
|
56
59
|
});
|
|
57
60
|
|
|
61
|
+
it('gives the floating layer role="dialog"', () => {
|
|
62
|
+
render(
|
|
63
|
+
<HoverCard content={<span>Card content</span>}>
|
|
64
|
+
<button type="button">Trigger</button>
|
|
65
|
+
</HoverCard>,
|
|
66
|
+
);
|
|
67
|
+
expect(screen.getByRole('dialog', {hidden: true})).toHaveTextContent(
|
|
68
|
+
'Card content',
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
58
72
|
it('wraps element children in an inline-safe span', () => {
|
|
59
73
|
const {container} = render(
|
|
60
74
|
<p>
|
|
@@ -73,6 +87,31 @@ describe('HoverCard', () => {
|
|
|
73
87
|
expect(paragraph?.querySelector('div')).toBeNull();
|
|
74
88
|
});
|
|
75
89
|
|
|
90
|
+
it('renders the floating layer with inline-safe markup (no block elements in a paragraph)', () => {
|
|
91
|
+
// HoverCard renders its floating layer inline (no portal), so the layer
|
|
92
|
+
// must be phrasing content to stay valid — and stay put on hydration —
|
|
93
|
+
// inside a <p>. Assert the layer popover element is a <span> and that the
|
|
94
|
+
// paragraph contains no <div> descendants at all.
|
|
95
|
+
const {container} = render(
|
|
96
|
+
<p>
|
|
97
|
+
Before{' '}
|
|
98
|
+
<HoverCard content={<span>Card content</span>}>
|
|
99
|
+
<a href="#trigger">Trigger</a>
|
|
100
|
+
</HoverCard>{' '}
|
|
101
|
+
after
|
|
102
|
+
</p>,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const paragraph = container.querySelector('p');
|
|
106
|
+
const layer = screen.getByText('Card content').closest('[popover]');
|
|
107
|
+
|
|
108
|
+
expect(layer).not.toBeNull();
|
|
109
|
+
expect(layer?.tagName).toBe('SPAN');
|
|
110
|
+
// The whole layer subtree lives inside the paragraph with no block boxes.
|
|
111
|
+
expect(paragraph?.contains(layer as Node)).toBe(true);
|
|
112
|
+
expect(paragraph?.querySelector('div')).toBeNull();
|
|
113
|
+
});
|
|
114
|
+
|
|
76
115
|
it('does not show content initially', () => {
|
|
77
116
|
render(
|
|
78
117
|
<HoverCard content={<span>Card content</span>}>
|
|
@@ -84,7 +123,7 @@ describe('HoverCard', () => {
|
|
|
84
123
|
expect(content).toBeInTheDocument();
|
|
85
124
|
});
|
|
86
125
|
|
|
87
|
-
it('applies the theme body font to the
|
|
126
|
+
it('applies the theme body font to the floating layer', () => {
|
|
88
127
|
render(
|
|
89
128
|
<HoverCard content={<span>Card content</span>}>
|
|
90
129
|
<button type="button">Trigger</button>
|
|
@@ -370,4 +409,152 @@ describe('HoverCard', () => {
|
|
|
370
409
|
expect(onOpenChange).not.toHaveBeenCalledWith(true);
|
|
371
410
|
});
|
|
372
411
|
});
|
|
412
|
+
|
|
413
|
+
describe('SSR / hydration', () => {
|
|
414
|
+
// Regression coverage for the hydration mismatch (#3107). The floating
|
|
415
|
+
// layer used to be portaled into document.body behind a
|
|
416
|
+
// `typeof document !== 'undefined'` gate: the server rendered nothing while
|
|
417
|
+
// the first client render emitted the portal, so the two trees disagreed.
|
|
418
|
+
//
|
|
419
|
+
// The layer is now rendered inline as inline-safe phrasing markup (a
|
|
420
|
+
// `<span popover>`), identically on the server and the client, so there is
|
|
421
|
+
// nothing for hydration to mismatch.
|
|
422
|
+
|
|
423
|
+
it('renders the floating layer in server markup (no document gate)', () => {
|
|
424
|
+
const html = renderToString(
|
|
425
|
+
<HoverCard content={<span>Card content</span>}>
|
|
426
|
+
<button type="button">Trigger</button>
|
|
427
|
+
</HoverCard>,
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
// The popover element is present in the server output...
|
|
431
|
+
expect(html).toContain('popover="manual"');
|
|
432
|
+
expect(html).toContain('Card content');
|
|
433
|
+
// ...and it is a <span> (inline-safe), not a <div>.
|
|
434
|
+
expect(html).toMatch(/<span[^>]*popover="manual"/);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it('keeps the floating layer inline-safe in server markup inside a paragraph', () => {
|
|
438
|
+
const html = renderToString(
|
|
439
|
+
<p>
|
|
440
|
+
Before{' '}
|
|
441
|
+
<HoverCard content={<span>Card content</span>}>
|
|
442
|
+
<a href="#trigger">Trigger</a>
|
|
443
|
+
</HoverCard>{' '}
|
|
444
|
+
after
|
|
445
|
+
</p>,
|
|
446
|
+
);
|
|
447
|
+
|
|
448
|
+
// No <div> is emitted inside the paragraph — the layer and its wrappers
|
|
449
|
+
// are all phrasing content, so the server string is valid <p> markup that
|
|
450
|
+
// the browser parser will not reparent (which would itself desync
|
|
451
|
+
// hydration).
|
|
452
|
+
expect(html).not.toContain('<div');
|
|
453
|
+
expect(html).toMatch(/<span[^>]*popover="manual"/);
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it('server markup matches the first client render (no hydration mismatch)', async () => {
|
|
457
|
+
const tree = (
|
|
458
|
+
<StrictMode>
|
|
459
|
+
<p>
|
|
460
|
+
Glossary:{' '}
|
|
461
|
+
<HoverCard content={<span>Definition</span>}>
|
|
462
|
+
<a href="#term">term</a>
|
|
463
|
+
</HoverCard>
|
|
464
|
+
.
|
|
465
|
+
</p>
|
|
466
|
+
</StrictMode>
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
const serverHTML = renderToString(tree);
|
|
470
|
+
|
|
471
|
+
const container = document.createElement('div');
|
|
472
|
+
container.innerHTML = serverHTML;
|
|
473
|
+
document.body.appendChild(container);
|
|
474
|
+
|
|
475
|
+
// Capture any hydration diagnostics. React reports hydration mismatches
|
|
476
|
+
// both through console.error and through onRecoverableError.
|
|
477
|
+
const consoleErrorSpy = vi
|
|
478
|
+
.spyOn(console, 'error')
|
|
479
|
+
.mockImplementation(() => {});
|
|
480
|
+
const recoverableErrors: unknown[] = [];
|
|
481
|
+
|
|
482
|
+
let root: ReturnType<typeof hydrateRoot>;
|
|
483
|
+
await act(async () => {
|
|
484
|
+
root = hydrateRoot(container, tree, {
|
|
485
|
+
onRecoverableError: error => {
|
|
486
|
+
recoverableErrors.push(error);
|
|
487
|
+
},
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
const hydrationErrors = consoleErrorSpy.mock.calls.filter(call =>
|
|
492
|
+
String(call[0] ?? '')
|
|
493
|
+
.toLowerCase()
|
|
494
|
+
.includes('hydrat'),
|
|
495
|
+
);
|
|
496
|
+
|
|
497
|
+
expect(hydrationErrors).toEqual([]);
|
|
498
|
+
expect(recoverableErrors).toEqual([]);
|
|
499
|
+
|
|
500
|
+
await act(async () => {
|
|
501
|
+
root.unmount();
|
|
502
|
+
});
|
|
503
|
+
consoleErrorSpy.mockRestore();
|
|
504
|
+
container.remove();
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
it('hydrates a default-open hover card without a mismatch', async () => {
|
|
508
|
+
vi.mocked(HTMLElement.prototype.showPopover).mockClear();
|
|
509
|
+
|
|
510
|
+
const tree = (
|
|
511
|
+
<HoverCard content={<span>Default open</span>} isDefaultOpen>
|
|
512
|
+
<button type="button">Trigger</button>
|
|
513
|
+
</HoverCard>
|
|
514
|
+
);
|
|
515
|
+
|
|
516
|
+
const serverHTML = renderToString(tree);
|
|
517
|
+
// isDefaultOpen must not leak the open state into SSR markup — the open
|
|
518
|
+
// call happens in an effect after hydration, so the server output is the
|
|
519
|
+
// same closed markup the first client render produces.
|
|
520
|
+
expect(serverHTML).toContain('popover="manual"');
|
|
521
|
+
|
|
522
|
+
const container = document.createElement('div');
|
|
523
|
+
container.innerHTML = serverHTML;
|
|
524
|
+
document.body.appendChild(container);
|
|
525
|
+
|
|
526
|
+
const consoleErrorSpy = vi
|
|
527
|
+
.spyOn(console, 'error')
|
|
528
|
+
.mockImplementation(() => {});
|
|
529
|
+
const recoverableErrors: unknown[] = [];
|
|
530
|
+
|
|
531
|
+
let root: ReturnType<typeof hydrateRoot>;
|
|
532
|
+
await act(async () => {
|
|
533
|
+
root = hydrateRoot(container, tree, {
|
|
534
|
+
onRecoverableError: error => {
|
|
535
|
+
recoverableErrors.push(error);
|
|
536
|
+
},
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
const hydrationErrors = consoleErrorSpy.mock.calls.filter(call =>
|
|
541
|
+
String(call[0] ?? '')
|
|
542
|
+
.toLowerCase()
|
|
543
|
+
.includes('hydrat'),
|
|
544
|
+
);
|
|
545
|
+
expect(hydrationErrors).toEqual([]);
|
|
546
|
+
expect(recoverableErrors).toEqual([]);
|
|
547
|
+
|
|
548
|
+
// The card opens after hydration via the mount effect.
|
|
549
|
+
await waitFor(() => {
|
|
550
|
+
expect(HTMLElement.prototype.showPopover).toHaveBeenCalled();
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
await act(async () => {
|
|
554
|
+
root.unmount();
|
|
555
|
+
});
|
|
556
|
+
consoleErrorSpy.mockRestore();
|
|
557
|
+
container.remove();
|
|
558
|
+
});
|
|
559
|
+
});
|
|
373
560
|
});
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file HoverCard.tsx
|
|
7
|
-
* @input Uses React,
|
|
7
|
+
* @input Uses React, useHoverCard hook
|
|
8
8
|
* @output Exports HoverCard component for hover/focus triggered layers
|
|
9
|
-
* @position Layer component; uses inline-safe trigger wrapper and
|
|
9
|
+
* @position Layer component; uses inline-safe trigger wrapper and renders the floating layer inline
|
|
10
10
|
*
|
|
11
11
|
* SYNC: When modified, update these files to stay in sync:
|
|
12
12
|
* - /packages/core/src/HoverCard/HoverCard.test.tsx
|
|
@@ -15,13 +15,7 @@
|
|
|
15
15
|
* - /packages/cli/templates/blocks/components/HoverCard/ (showcase blocks)
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import
|
|
19
|
-
useCallback,
|
|
20
|
-
useRef,
|
|
21
|
-
type ReactElement,
|
|
22
|
-
type ReactNode,
|
|
23
|
-
} from 'react';
|
|
24
|
-
import {createPortal} from 'react-dom';
|
|
18
|
+
import {useCallback, useRef, type ReactElement, type ReactNode} from 'react';
|
|
25
19
|
import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
|
|
26
20
|
import * as stylex from '@stylexjs/stylex';
|
|
27
21
|
import {useHoverCard, type HoverCardFocusTrigger} from './useHoverCard';
|
|
@@ -245,13 +239,23 @@ export function HoverCard({
|
|
|
245
239
|
};
|
|
246
240
|
}, [textOnly, hoverCard.ref, hoverCard.describedBy]);
|
|
247
241
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
242
|
+
// Render the floating layer inline, in the same place on the server and the
|
|
243
|
+
// client. The layer is a `popover` element opened via the Popover API, so the
|
|
244
|
+
// browser promotes it to the top layer when shown — that already escapes
|
|
245
|
+
// ancestor clipping, stacking, and transform containing-block traps, and CSS
|
|
246
|
+
// anchor positioning resolves the trigger reference regardless of where the
|
|
247
|
+
// element sits in the DOM, so no portal is needed to "escape" layout.
|
|
248
|
+
//
|
|
249
|
+
// The layer renders as inline-safe phrasing markup (a `<span>`, see
|
|
250
|
+
// useHoverCard), which stays put inside a `<p>` instead of being reparented
|
|
251
|
+
// by the HTML parser. That keeps the server markup and the first client
|
|
252
|
+
// render identical, so there is no hydration mismatch — and it preserves the
|
|
253
|
+
// inline-safety guarantee (no block elements injected into a paragraph).
|
|
254
|
+
const renderedHoverCard = hoverCard.renderHoverCard(content, {
|
|
255
|
+
xstyle,
|
|
256
|
+
className,
|
|
257
|
+
style,
|
|
258
|
+
});
|
|
255
259
|
|
|
256
260
|
// For text-only children: use inline span with ref on wrapper
|
|
257
261
|
if (textOnly) {
|
|
@@ -58,8 +58,12 @@ const styles = stylex.create({
|
|
|
58
58
|
marginInlineStart: spacingVars['--spacing-1'],
|
|
59
59
|
marginInlineEnd: spacingVars['--spacing-1'],
|
|
60
60
|
},
|
|
61
|
-
// Content wrapper for padding and mouse events
|
|
61
|
+
// Content wrapper for padding and mouse events.
|
|
62
|
+
// `display: block` keeps the wrapper a block box even though it renders as a
|
|
63
|
+
// `span` (the layer uses inline-safe phrasing markup so it is valid inside a
|
|
64
|
+
// paragraph and produces identical server/client markup).
|
|
62
65
|
content: {
|
|
66
|
+
display: 'block',
|
|
63
67
|
paddingBlockStart: spacingVars['--spacing-3'],
|
|
64
68
|
paddingBlockEnd: spacingVars['--spacing-3'],
|
|
65
69
|
paddingInlineStart: spacingVars['--spacing-3'],
|
|
@@ -234,9 +238,7 @@ function isFocusable(element: HTMLElement): boolean {
|
|
|
234
238
|
* {hoverCard.renderHoverCard(<ProfileCard user={user} />)}
|
|
235
239
|
* ```
|
|
236
240
|
*/
|
|
237
|
-
export function useHoverCard(
|
|
238
|
-
options: HoverCardOptions = {},
|
|
239
|
-
): HoverCardReturn {
|
|
241
|
+
export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
|
|
240
242
|
const {
|
|
241
243
|
placement = 'above',
|
|
242
244
|
alignment = 'center',
|
|
@@ -453,15 +455,16 @@ export function useHoverCard(
|
|
|
453
455
|
const renderProps = {
|
|
454
456
|
placement: renderPlacement,
|
|
455
457
|
alignment: props?.alignment ?? alignment,
|
|
458
|
+
role: 'dialog',
|
|
456
459
|
xstyle: [popoverXstyle, layerAnimations[renderPlacement]],
|
|
460
|
+
// Render the layer as inline-safe phrasing markup so HoverCard stays
|
|
461
|
+
// valid (and hydration-stable) inside inline contexts like a `<p>`.
|
|
462
|
+
as: 'span' as const,
|
|
457
463
|
};
|
|
458
464
|
|
|
459
465
|
return layer.render(
|
|
460
|
-
<
|
|
461
|
-
{...mergeProps(
|
|
462
|
-
themeProps('hovercard'),
|
|
463
|
-
stylex.props(styles.content),
|
|
464
|
-
)}
|
|
466
|
+
<span
|
|
467
|
+
{...mergeProps(themeProps('hovercard'), stylex.props(styles.content))}
|
|
465
468
|
onMouseEnter={() => {
|
|
466
469
|
isHoveringContentRef.current = true;
|
|
467
470
|
clearTimeouts();
|
|
@@ -502,7 +505,7 @@ export function useHoverCard(
|
|
|
502
505
|
scheduleHide();
|
|
503
506
|
}}>
|
|
504
507
|
{children}
|
|
505
|
-
</
|
|
508
|
+
</span>,
|
|
506
509
|
renderProps,
|
|
507
510
|
);
|
|
508
511
|
},
|
package/src/Icon/Icon.doc.mjs
CHANGED
|
@@ -7,6 +7,14 @@ export const docs = {
|
|
|
7
7
|
displayName: 'Icon',
|
|
8
8
|
category: 'Content',
|
|
9
9
|
keywords: ["icon","svg","glyph","symbol","pictogram","graphic","vector"],
|
|
10
|
+
playground: {
|
|
11
|
+
// `icon` is required and its type can't be auto-generated, so the
|
|
12
|
+
// properties-tab preview showed "Missing: icon". Seed a valid semantic
|
|
13
|
+
// icon name so the interactive preview renders.
|
|
14
|
+
defaults: {
|
|
15
|
+
icon: 'search',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
10
18
|
props: [
|
|
11
19
|
{
|
|
12
20
|
name: 'icon',
|
|
@@ -92,7 +92,7 @@ export const docs = {
|
|
|
92
92
|
bestPractices: [
|
|
93
93
|
{guidance: true, description: 'Use text addons to show units, prefixes, or suffixes that clarify the input format (e.g., "$", "kg", "https://").'},
|
|
94
94
|
{guidance: true, description: 'Use InputGroupText for static prefixes/suffixes like "$", "kg", or "https://".'},
|
|
95
|
-
{guidance: true, description: '
|
|
95
|
+
{guidance: true, description: "Keep each inner input's label specific; grouped inputs automatically combine the group label with their own label and inherit the group description/status context."},
|
|
96
96
|
{guidance: false, description: 'Don\'t put multiple text inputs in one group; use separate fields instead.'},
|
|
97
97
|
{guidance: false, description: 'Don\'t use InputGroup for unrelated inputs; it\'s for a single input with decorations.'},
|
|
98
98
|
],
|
|
@@ -114,7 +114,7 @@ export const docsDense = {
|
|
|
114
114
|
bestPractices: [
|
|
115
115
|
{guidance: true, description: 'Use text addons to show units, prefixes, or suffixes that clarify input format (e.g. "$", "kg", "https://").'},
|
|
116
116
|
{guidance: true, description: 'Use InputGroupText for static prefixes/suffixes like "$", "kg", or "https://".'},
|
|
117
|
-
{guidance: true, description:
|
|
117
|
+
{guidance: true, description: "Keep each inner input's label specific; grouped inputs combine the group label with their own label and inherit group description/status."},
|
|
118
118
|
{guidance: false, description: 'Don\'t put multiple text inputs in one group; use separate fields instead.'},
|
|
119
119
|
{guidance: false, description: 'Don\'t use InputGroup for unrelated inputs; it\'s for a single input with decorations.'},
|
|
120
120
|
],
|
|
@@ -14,35 +14,113 @@ import {render, screen} from '@testing-library/react';
|
|
|
14
14
|
import {InputGroup} from './InputGroup';
|
|
15
15
|
import {InputGroupText} from './InputGroupText';
|
|
16
16
|
import {TextInput} from '../TextInput';
|
|
17
|
+
import {NumberInput} from '../NumberInput';
|
|
17
18
|
|
|
18
19
|
describe('InputGroup', () => {
|
|
19
|
-
it('
|
|
20
|
+
it('names the group via the label element (forms-14)', () => {
|
|
20
21
|
render(
|
|
21
22
|
<InputGroup label="Price">
|
|
22
23
|
<InputGroupText>$</InputGroupText>
|
|
23
|
-
<TextInput
|
|
24
|
+
<TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
|
|
25
|
+
</InputGroup>,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// The group is named by the field label via aria-labelledby (not a
|
|
29
|
+
// duplicated aria-label). The label is rendered as a <span> (not a literal
|
|
30
|
+
// <label>, which can't name a group) and carries no orphaned htmlFor.
|
|
31
|
+
const group = screen.getByRole('group', {name: 'Price'});
|
|
32
|
+
expect(group).toBeInTheDocument();
|
|
33
|
+
expect(group).not.toHaveAttribute('aria-label');
|
|
34
|
+
const label = screen.getByText('Price');
|
|
35
|
+
expect(label.tagName).toBe('SPAN');
|
|
36
|
+
expect(label.closest('label')).toBeNull();
|
|
37
|
+
expect(label).not.toHaveAttribute('for');
|
|
38
|
+
expect(group.getAttribute('aria-labelledby')).toBe(label.id);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('associates group description and status through aria-describedby', () => {
|
|
42
|
+
render(
|
|
43
|
+
<InputGroup
|
|
44
|
+
label="Price"
|
|
45
|
+
description="Enter the amount in USD"
|
|
46
|
+
status={{type: 'error', message: 'Price is required'}}>
|
|
47
|
+
<InputGroupText>$</InputGroupText>
|
|
48
|
+
<TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
|
|
49
|
+
</InputGroup>,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const group = screen.getByRole('group', {name: 'Price'});
|
|
53
|
+
const describedBy = group.getAttribute('aria-describedby');
|
|
54
|
+
expect(describedBy).toBeTruthy();
|
|
55
|
+
expect(describedBy!.split(' ')).toHaveLength(2);
|
|
56
|
+
expect(describedBy).toContain(
|
|
57
|
+
screen.getByText('Enter the amount in USD').id,
|
|
58
|
+
);
|
|
59
|
+
expect(describedBy).toContain(screen.getByText('Price is required').id);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('labels grouped TextInput from the group and inner input labels', () => {
|
|
63
|
+
render(
|
|
64
|
+
<InputGroup
|
|
65
|
+
label="Price"
|
|
66
|
+
description="Enter the amount in USD"
|
|
67
|
+
status={{type: 'error', message: 'Price is required'}}>
|
|
68
|
+
<InputGroupText>$</InputGroupText>
|
|
69
|
+
<TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
|
|
70
|
+
</InputGroup>,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const group = screen.getByRole('group', {name: 'Price'});
|
|
74
|
+
const groupLabelID = group.getAttribute('aria-labelledby');
|
|
75
|
+
const describedBy = group.getAttribute('aria-describedby');
|
|
76
|
+
const input = screen.getByRole('textbox', {name: 'Price Amount'});
|
|
77
|
+
const labelledByIDs =
|
|
78
|
+
input.getAttribute('aria-labelledby')?.split(' ') ?? [];
|
|
79
|
+
|
|
80
|
+
expect(labelledByIDs).toHaveLength(2);
|
|
81
|
+
expect(labelledByIDs[0]).toBe(groupLabelID);
|
|
82
|
+
expect(document.getElementById(labelledByIDs[1])).toHaveTextContent(
|
|
83
|
+
'Amount',
|
|
84
|
+
);
|
|
85
|
+
expect(input).not.toHaveAttribute('aria-label');
|
|
86
|
+
expect(input).toHaveAttribute('aria-describedby', describedBy);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('labels grouped NumberInput from the group and inner input labels', () => {
|
|
90
|
+
render(
|
|
91
|
+
<InputGroup label="Budget" description="Whole dollars only">
|
|
92
|
+
<InputGroupText>$</InputGroupText>
|
|
93
|
+
<NumberInput
|
|
24
94
|
label="Amount"
|
|
25
95
|
isLabelHidden
|
|
26
|
-
value=
|
|
96
|
+
value={null}
|
|
27
97
|
onChange={() => {}}
|
|
28
98
|
/>
|
|
29
99
|
</InputGroup>,
|
|
30
100
|
);
|
|
31
101
|
|
|
32
|
-
const group = screen.getByRole('group');
|
|
33
|
-
|
|
34
|
-
|
|
102
|
+
const group = screen.getByRole('group', {name: 'Budget'});
|
|
103
|
+
const groupLabelID = group.getAttribute('aria-labelledby');
|
|
104
|
+
const input = screen.getByRole('spinbutton', {name: 'Budget Amount'});
|
|
105
|
+
const labelledByIDs =
|
|
106
|
+
input.getAttribute('aria-labelledby')?.split(' ') ?? [];
|
|
107
|
+
|
|
108
|
+
expect(labelledByIDs).toHaveLength(2);
|
|
109
|
+
expect(labelledByIDs[0]).toBe(groupLabelID);
|
|
110
|
+
expect(document.getElementById(labelledByIDs[1])).toHaveTextContent(
|
|
111
|
+
'Amount',
|
|
112
|
+
);
|
|
113
|
+
expect(input).not.toHaveAttribute('aria-label');
|
|
114
|
+
expect(input).toHaveAttribute(
|
|
115
|
+
'aria-describedby',
|
|
116
|
+
group.getAttribute('aria-describedby'),
|
|
117
|
+
);
|
|
35
118
|
});
|
|
36
119
|
|
|
37
120
|
it('renders the visible label', () => {
|
|
38
121
|
render(
|
|
39
122
|
<InputGroup label="Price">
|
|
40
|
-
<TextInput
|
|
41
|
-
label="Amount"
|
|
42
|
-
isLabelHidden
|
|
43
|
-
value=""
|
|
44
|
-
onChange={() => {}}
|
|
45
|
-
/>
|
|
123
|
+
<TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
|
|
46
124
|
</InputGroup>,
|
|
47
125
|
);
|
|
48
126
|
|
|
@@ -53,12 +131,7 @@ describe('InputGroup', () => {
|
|
|
53
131
|
render(
|
|
54
132
|
<InputGroup label="Price">
|
|
55
133
|
<InputGroupText>$</InputGroupText>
|
|
56
|
-
<TextInput
|
|
57
|
-
label="Amount"
|
|
58
|
-
isLabelHidden
|
|
59
|
-
value=""
|
|
60
|
-
onChange={() => {}}
|
|
61
|
-
/>
|
|
134
|
+
<TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
|
|
62
135
|
</InputGroup>,
|
|
63
136
|
);
|
|
64
137
|
|
|
@@ -68,12 +141,7 @@ describe('InputGroup', () => {
|
|
|
68
141
|
it('renders the input', () => {
|
|
69
142
|
render(
|
|
70
143
|
<InputGroup label="Price">
|
|
71
|
-
<TextInput
|
|
72
|
-
label="Amount"
|
|
73
|
-
isLabelHidden
|
|
74
|
-
value=""
|
|
75
|
-
onChange={() => {}}
|
|
76
|
-
/>
|
|
144
|
+
<TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
|
|
77
145
|
</InputGroup>,
|
|
78
146
|
);
|
|
79
147
|
|
|
@@ -97,12 +165,7 @@ describe('InputGroup', () => {
|
|
|
97
165
|
it('applies data-testid', () => {
|
|
98
166
|
render(
|
|
99
167
|
<InputGroup label="Price" data-testid="price-group">
|
|
100
|
-
<TextInput
|
|
101
|
-
label="Amount"
|
|
102
|
-
isLabelHidden
|
|
103
|
-
value=""
|
|
104
|
-
onChange={() => {}}
|
|
105
|
-
/>
|
|
168
|
+
<TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
|
|
106
169
|
</InputGroup>,
|
|
107
170
|
);
|
|
108
171
|
|
|
@@ -112,12 +175,7 @@ describe('InputGroup', () => {
|
|
|
112
175
|
it('renders description text', () => {
|
|
113
176
|
render(
|
|
114
177
|
<InputGroup label="Price" description="Enter the price in USD">
|
|
115
|
-
<TextInput
|
|
116
|
-
label="Amount"
|
|
117
|
-
isLabelHidden
|
|
118
|
-
value=""
|
|
119
|
-
onChange={() => {}}
|
|
120
|
-
/>
|
|
178
|
+
<TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
|
|
121
179
|
</InputGroup>,
|
|
122
180
|
);
|
|
123
181
|
|
|
@@ -129,12 +187,7 @@ describe('InputGroup', () => {
|
|
|
129
187
|
<InputGroup
|
|
130
188
|
label="Price"
|
|
131
189
|
status={{type: 'error', message: 'Price is required'}}>
|
|
132
|
-
<TextInput
|
|
133
|
-
label="Amount"
|
|
134
|
-
isLabelHidden
|
|
135
|
-
value=""
|
|
136
|
-
onChange={() => {}}
|
|
137
|
-
/>
|
|
190
|
+
<TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
|
|
138
191
|
</InputGroup>,
|
|
139
192
|
);
|
|
140
193
|
|
|
@@ -144,12 +197,7 @@ describe('InputGroup', () => {
|
|
|
144
197
|
it('renders with hidden label', () => {
|
|
145
198
|
render(
|
|
146
199
|
<InputGroup label="Price" isLabelHidden>
|
|
147
|
-
<TextInput
|
|
148
|
-
label="Amount"
|
|
149
|
-
isLabelHidden
|
|
150
|
-
value=""
|
|
151
|
-
onChange={() => {}}
|
|
152
|
-
/>
|
|
200
|
+
<TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
|
|
153
201
|
</InputGroup>,
|
|
154
202
|
);
|
|
155
203
|
|
|
@@ -160,24 +208,14 @@ describe('InputGroup', () => {
|
|
|
160
208
|
it('renders with different sizes', () => {
|
|
161
209
|
const {rerender} = render(
|
|
162
210
|
<InputGroup label="Price" size="sm">
|
|
163
|
-
<TextInput
|
|
164
|
-
label="Amount"
|
|
165
|
-
isLabelHidden
|
|
166
|
-
value=""
|
|
167
|
-
onChange={() => {}}
|
|
168
|
-
/>
|
|
211
|
+
<TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
|
|
169
212
|
</InputGroup>,
|
|
170
213
|
);
|
|
171
214
|
expect(screen.getByRole('textbox')).toBeInTheDocument();
|
|
172
215
|
|
|
173
216
|
rerender(
|
|
174
217
|
<InputGroup label="Price" size="lg">
|
|
175
|
-
<TextInput
|
|
176
|
-
label="Amount"
|
|
177
|
-
isLabelHidden
|
|
178
|
-
value=""
|
|
179
|
-
onChange={() => {}}
|
|
180
|
-
/>
|
|
218
|
+
<TextInput label="Amount" isLabelHidden value="" onChange={() => {}} />
|
|
181
219
|
</InputGroup>,
|
|
182
220
|
);
|
|
183
221
|
expect(screen.getByRole('textbox')).toBeInTheDocument();
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file InputGroup.tsx
|
|
7
|
-
* @input Uses React, StyleX, theme tokens, InputGroupContext
|
|
8
|
-
* @output Exports InputGroup component
|
|
7
|
+
* @input Uses React, StyleX, theme tokens, InputGroupContext, Field
|
|
8
|
+
* @output Exports InputGroup component with group label/description ARIA wiring
|
|
9
9
|
* @position Groups input with prefix/suffix addons; consumed by index.ts
|
|
10
10
|
*
|
|
11
11
|
* Children (TextInput, NumberInput) consume the InputGroup context
|
|
@@ -156,9 +156,22 @@ export function InputGroup({
|
|
|
156
156
|
}: InputGroupProps) {
|
|
157
157
|
const size = useSize(sizeProp, 'md');
|
|
158
158
|
const inputId = useId();
|
|
159
|
+
const labelID = useId();
|
|
160
|
+
const descriptionID = useId();
|
|
159
161
|
const statusMessageId = useId();
|
|
160
162
|
|
|
161
|
-
const
|
|
163
|
+
const describedByIDs =
|
|
164
|
+
[
|
|
165
|
+
description ? descriptionID : null,
|
|
166
|
+
status?.message ? statusMessageId : null,
|
|
167
|
+
]
|
|
168
|
+
.filter(Boolean)
|
|
169
|
+
.join(' ') || undefined;
|
|
170
|
+
|
|
171
|
+
const contextValue = useMemo(
|
|
172
|
+
() => ({isInGroup: true as const, labelID, describedByIDs}),
|
|
173
|
+
[labelID, describedByIDs],
|
|
174
|
+
);
|
|
162
175
|
|
|
163
176
|
return (
|
|
164
177
|
<InputGroupContext value={contextValue}>
|
|
@@ -168,6 +181,9 @@ export function InputGroup({
|
|
|
168
181
|
isLabelHidden={isLabelHidden}
|
|
169
182
|
description={description}
|
|
170
183
|
inputID={inputId}
|
|
184
|
+
labelID={labelID}
|
|
185
|
+
descriptionID={description ? descriptionID : undefined}
|
|
186
|
+
isGroupLabel
|
|
171
187
|
isOptional={isOptional}
|
|
172
188
|
isRequired={isRequired}
|
|
173
189
|
isDisabled={isDisabled}
|
|
@@ -185,7 +201,8 @@ export function InputGroup({
|
|
|
185
201
|
<div
|
|
186
202
|
ref={ref}
|
|
187
203
|
role="group"
|
|
188
|
-
aria-
|
|
204
|
+
aria-labelledby={labelID}
|
|
205
|
+
aria-describedby={describedByIDs}
|
|
189
206
|
data-testid={testId}
|
|
190
207
|
{...rest}
|
|
191
208
|
{...mergeProps(
|