@astryxdesign/core 0.3.0 → 0.4.0
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 +156 -0
- package/dist/AlertDialog/AlertDialog.d.ts +10 -2
- package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
- package/dist/AlertDialog/AlertDialog.js +22 -3
- package/dist/AppShell/AppShell.d.ts +2 -2
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/AppShell/AppShell.js +40 -9
- package/dist/AspectRatio/AspectRatio.d.ts +13 -0
- package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
- package/dist/AspectRatio/AspectRatio.js +9 -0
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +33 -20
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +2 -3
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +15 -14
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +21 -8
- package/dist/Breadcrumbs/index.d.ts +2 -1
- package/dist/Breadcrumbs/index.d.ts.map +1 -1
- package/dist/Breadcrumbs/index.js +1 -0
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +11 -15
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +2 -1
- package/dist/Calendar/styles.d.ts +0 -2
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +0 -2
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +8 -12
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +2 -1
- package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.js +3 -1
- package/dist/Chat/ChatSendButton.d.ts.map +1 -1
- package/dist/Chat/ChatSendButton.js +4 -3
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +17 -17
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +2 -6
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +36 -125
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +3 -11
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +84 -67
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +35 -15
- package/dist/CommandPalette/CommandPaletteItem.d.ts +1 -1
- package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteItem.js +6 -3
- package/dist/CommandPalette/CommandPaletteList.js +1 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts +1 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +35 -33
- package/dist/ContextMenu/ContextMenu.d.ts +2 -2
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +1 -1
- package/dist/ContextMenu/index.d.ts +2 -1
- package/dist/ContextMenu/index.d.ts.map +1 -1
- package/dist/ContextMenu/index.js +1 -0
- package/dist/DateInput/DateInput.d.ts +9 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +24 -23
- package/dist/DateRangeInput/DateRangeInput.d.ts +9 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +11 -16
- package/dist/DateTimeInput/DateTimeInput.d.ts +9 -1
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +22 -17
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +4 -4
- package/dist/DropdownMenu/DropdownMenu.d.ts +33 -8
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +62 -20
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +8 -11
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +32 -31
- package/dist/DropdownMenu/DropdownMenuDivider.d.ts +25 -0
- package/dist/DropdownMenu/DropdownMenuDivider.d.ts.map +1 -0
- package/dist/DropdownMenu/DropdownMenuDivider.js +66 -0
- package/dist/DropdownMenu/DropdownMenuItem.d.ts +15 -2
- package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuItem.js +20 -8
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +5 -5
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +24 -67
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +2 -8
- package/dist/DropdownMenu/index.d.ts +2 -1
- package/dist/DropdownMenu/index.d.ts.map +1 -1
- package/dist/DropdownMenu/index.js +4 -0
- package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
- package/dist/DropdownMenu/renderDropdownItems.js +35 -27
- package/dist/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/EmptyState/EmptyState.js +9 -5
- package/dist/Field/InputClearButton.d.ts +16 -3
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +15 -4
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +3 -19
- package/dist/Indicator/CheckIndicator.d.ts +25 -0
- package/dist/Indicator/CheckIndicator.d.ts.map +1 -0
- package/dist/Indicator/CheckIndicator.js +155 -0
- package/dist/Indicator/CheckboxIndicator.d.ts +22 -0
- package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -0
- package/dist/Indicator/CheckboxIndicator.js +173 -0
- package/dist/Indicator/RadioIndicator.d.ts +23 -0
- package/dist/Indicator/RadioIndicator.d.ts.map +1 -0
- package/dist/Indicator/RadioIndicator.js +137 -0
- package/dist/Indicator/index.d.ts +24 -0
- package/dist/Indicator/index.d.ts.map +1 -0
- package/dist/Indicator/index.js +26 -0
- package/dist/Indicator/indicator.markers.stylex.d.ts +16 -0
- package/dist/Indicator/indicator.markers.stylex.d.ts.map +1 -0
- package/dist/Indicator/indicator.markers.stylex.js +21 -0
- package/dist/Indicator/indicatorRegistry.d.ts +71 -0
- package/dist/Indicator/indicatorRegistry.d.ts.map +1 -0
- package/dist/Indicator/indicatorRegistry.js +93 -0
- package/dist/Indicator/types.d.ts +167 -0
- package/dist/Indicator/types.d.ts.map +1 -0
- package/dist/Indicator/types.js +1 -0
- package/dist/Indicator/useIndicator.d.ts +18 -0
- package/dist/Indicator/useIndicator.d.ts.map +1 -0
- package/dist/Indicator/useIndicator.js +30 -0
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +4 -8
- package/dist/Layer/useLayer.d.ts +14 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +25 -2
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +56 -53
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +4 -5
- package/dist/MobileNav/MobileNav.js +8 -8
- package/dist/MoreMenu/MoreMenu.d.ts +14 -1
- package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
- package/dist/MoreMenu/MoreMenu.js +4 -0
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +78 -75
- package/dist/NumberInput/NumberInput.d.ts +27 -1
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +230 -42
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +2 -3
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +61 -63
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +6 -8
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.js +7 -0
- package/dist/ProgressBar/ProgressBar.d.ts +11 -4
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +96 -6
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +29 -84
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +2 -3
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +2 -3
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +3 -11
- package/dist/Selector/Selector.d.ts +2 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +164 -94
- package/dist/Selector/hooks.d.ts +18 -6
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +57 -40
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +1 -1
- package/dist/SideNav/SideNavCollapseButton.d.ts +1 -1
- package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
- package/dist/SideNav/SideNavCollapseButton.js +29 -14
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +56 -20
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +28 -22
- package/dist/Stack/stack.stylex.d.ts +3 -3
- package/dist/Switch/Switch.js +11 -10
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +2 -3
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +41 -19
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +8 -0
- package/dist/Table/index.d.ts +1 -1
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +22 -18
- package/dist/Table/plugins/rowExpansion/index.d.ts +1 -1
- package/dist/Table/plugins/rowExpansion/index.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/index.js +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +41 -76
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +94 -345
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +23 -4
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +29 -33
- package/dist/Table/tableContextMenu.d.ts.map +1 -1
- package/dist/Table/tableContextMenu.js +2 -1
- package/dist/Table/types.d.ts +11 -0
- package/dist/Table/types.d.ts.map +1 -1
- package/dist/TextArea/TextArea.d.ts +10 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +16 -6
- package/dist/TextInput/TextInput.d.ts +10 -1
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +13 -19
- package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
- package/dist/Thumbnail/Thumbnail.js +32 -26
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +7 -15
- package/dist/Timestamp/TimestampHoverCard.d.ts.map +1 -1
- package/dist/Timestamp/TimestampHoverCard.js +16 -34
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +20 -11
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +4 -2
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +3 -19
- package/dist/TopNav/TopNav.d.ts.map +1 -1
- package/dist/TopNav/TopNav.js +6 -5
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +54 -16
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +3 -9
- package/dist/TopNav/TopNavMegaMenu.d.ts +7 -0
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +146 -60
- package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuItem.js +22 -3
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +83 -38
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +13 -0
- package/dist/TreeList/TreeListBranches.d.ts +1 -1
- package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
- package/dist/TreeList/TreeListBranches.js +14 -4
- package/dist/TreeList/TreeListItem.d.ts +11 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +57 -30
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +16 -8
- package/dist/astryx.css +74 -85
- package/dist/astryx.umd.js +56 -56
- package/dist/astryx.umd.js.map +4 -4
- package/dist/hooks/containerReveal.stylex.d.ts +61 -0
- package/dist/hooks/containerReveal.stylex.d.ts.map +1 -0
- package/dist/hooks/containerReveal.stylex.js +63 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/useClipboard.d.ts +59 -0
- package/dist/hooks/useClipboard.d.ts.map +1 -0
- package/dist/hooks/useClipboard.js +106 -0
- package/dist/hooks/useContainerReveal.d.ts +14 -8
- package/dist/hooks/useContainerReveal.d.ts.map +1 -1
- package/dist/hooks/useContainerReveal.js +28 -69
- package/dist/hooks/useIndicatorFocusRing.d.ts +28 -0
- package/dist/hooks/useIndicatorFocusRing.d.ts.map +1 -0
- package/dist/hooks/useIndicatorFocusRing.js +96 -0
- package/dist/hooks/useLongPress.d.ts.map +1 -1
- package/dist/hooks/useLongPress.js +12 -2
- package/dist/hooks/useScrollLock.d.ts.map +1 -1
- package/dist/hooks/useScrollLock.js +33 -18
- package/dist/hooks/useStreamingText.d.ts +18 -3
- package/dist/hooks/useStreamingText.d.ts.map +1 -1
- package/dist/hooks/useStreamingText.js +47 -7
- package/dist/hooks/useTreeFocus.d.ts.map +1 -1
- package/dist/hooks/useTreeFocus.js +9 -3
- package/dist/hooks/useTypeahead.d.ts +3 -2
- package/dist/hooks/useTypeahead.d.ts.map +1 -1
- package/dist/hooks/useTypeahead.js +19 -7
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/defineTheme.d.ts +16 -0
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +8 -0
- package/dist/theme/derivedVarRegistry.d.ts +8 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +14 -13
- package/dist/theme/expandColorScale.d.ts +3 -1
- package/dist/theme/expandColorScale.d.ts.map +1 -1
- package/dist/theme/expandColorScale.js +17 -7
- package/dist/theme/expandTypeScale.d.ts.map +1 -1
- package/dist/theme/expandTypeScale.js +17 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +11 -0
- package/dist/theme/index.d.ts +1 -0
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/utils/focusOutline.stylex.d.ts +107 -0
- package/dist/utils/focusOutline.stylex.d.ts.map +1 -0
- package/dist/utils/focusOutline.stylex.js +130 -0
- package/dist/utils/focusReturn.d.ts +24 -0
- package/dist/utils/focusReturn.d.ts.map +1 -0
- package/dist/utils/focusReturn.js +29 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/mergeRefs.d.ts.map +1 -1
- package/dist/utils/mergeRefs.js +7 -5
- package/dist/utils/rtlStyles.d.ts +2 -2
- package/dist/utils/rtlStyles.js +2 -2
- package/dist/utils/themeProps.d.ts +20 -1
- package/dist/utils/themeProps.d.ts.map +1 -1
- package/dist/utils/themeProps.js +8 -2
- package/locales/en.json +12 -0
- package/locales/pseudo.json +9 -0
- package/package.json +7 -2
- package/src/AlertDialog/AlertDialog.doc.mjs +16 -3
- package/src/AlertDialog/AlertDialog.test.tsx +208 -1
- package/src/AlertDialog/AlertDialog.tsx +21 -3
- package/src/AppShell/AppShell.doc.mjs +11 -0
- package/src/AppShell/AppShell.test.tsx +139 -0
- package/src/AppShell/AppShell.tsx +32 -22
- package/src/AspectRatio/AspectRatio.doc.mjs +27 -3
- package/src/AspectRatio/AspectRatio.test.tsx +30 -0
- package/src/AspectRatio/AspectRatio.tsx +13 -0
- package/src/Avatar/Avatar.doc.mjs +2 -13
- package/src/Avatar/Avatar.test.tsx +33 -8
- package/src/Avatar/Avatar.tsx +52 -50
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -9
- package/src/Banner/Banner.tsx +9 -6
- package/src/Breadcrumbs/BreadcrumbItem.tsx +16 -6
- package/src/Breadcrumbs/index.ts +5 -1
- package/src/Button/Button.tsx +21 -41
- package/src/Calendar/Calendar.tsx +2 -1
- package/src/Calendar/styles.ts +0 -8
- package/src/Carousel/Carousel.doc.mjs +3 -0
- package/src/Carousel/Carousel.tsx +10 -6
- package/src/Chat/Chat.doc.mjs +2 -0
- package/src/Chat/ChatDictationButton.tsx +7 -1
- package/src/Chat/ChatLayoutScrollButton.test.tsx +22 -0
- package/src/Chat/ChatLayoutScrollButton.tsx +8 -1
- package/src/Chat/ChatSendButton.tsx +2 -3
- package/src/Chat/ChatToolCalls.test.tsx +35 -0
- package/src/Chat/ChatToolCalls.tsx +36 -16
- package/src/Chat/useTriggerMenu.tsx +2 -5
- package/src/CheckboxInput/CheckboxInput.doc.mjs +4 -2
- package/src/CheckboxInput/CheckboxInput.test.tsx +115 -0
- package/src/CheckboxInput/CheckboxInput.tsx +45 -202
- package/src/ClickableCard/ClickableCard.tsx +6 -11
- package/src/CodeBlock/CodeBlock.doc.mjs +3 -0
- package/src/CodeBlock/CodeBlock.test.tsx +91 -0
- package/src/CodeBlock/CodeBlock.tsx +57 -80
- package/src/Collapsible/Collapsible.tsx +22 -18
- package/src/CommandPalette/CommandPalette.test.tsx +29 -0
- package/src/CommandPalette/CommandPaletteItem.tsx +7 -4
- package/src/CommandPalette/CommandPaletteList.tsx +2 -2
- package/src/ComplexSelector/ComplexSelector.doc.mjs +42 -0
- package/src/ComplexSelector/ComplexSelector.test.tsx +64 -0
- package/src/ComplexSelector/ComplexSelector.tsx +46 -29
- package/src/ContextMenu/ContextMenu.doc.mjs +1 -1
- package/src/ContextMenu/ContextMenu.test.tsx +41 -0
- package/src/ContextMenu/ContextMenu.tsx +3 -3
- package/src/ContextMenu/index.ts +5 -1
- package/src/DateInput/DateInput.doc.mjs +18 -3
- package/src/DateInput/DateInput.test.tsx +93 -11
- package/src/DateInput/DateInput.tsx +41 -19
- package/src/DateRangeInput/DateRangeInput.doc.mjs +10 -2
- package/src/DateRangeInput/DateRangeInput.test.tsx +110 -14
- package/src/DateRangeInput/DateRangeInput.tsx +24 -12
- package/src/DateTimeInput/DateTimeInput.doc.mjs +16 -2
- package/src/DateTimeInput/DateTimeInput.test.tsx +75 -0
- package/src/DateTimeInput/DateTimeInput.tsx +35 -8
- package/src/Dialog/Dialog.tsx +2 -9
- package/src/DropdownMenu/DropdownMenu.doc.mjs +5 -9
- package/src/DropdownMenu/DropdownMenu.test.tsx +534 -4
- package/src/DropdownMenu/DropdownMenu.tsx +113 -52
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +27 -30
- package/src/DropdownMenu/DropdownMenuDivider.doc.mjs +34 -0
- package/src/DropdownMenu/DropdownMenuDivider.tsx +81 -0
- package/src/DropdownMenu/DropdownMenuItem.doc.mjs +39 -4
- package/src/DropdownMenu/DropdownMenuItem.tsx +48 -10
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +30 -76
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +25 -19
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +44 -14
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +1 -5
- package/src/DropdownMenu/index.ts +8 -1
- package/src/DropdownMenu/renderDropdownItems.tsx +33 -34
- package/src/EmptyState/EmptyState.doc.mjs +4 -0
- package/src/EmptyState/EmptyState.test.tsx +62 -0
- package/src/EmptyState/EmptyState.tsx +16 -6
- package/src/Field/Field.doc.mjs +1 -0
- package/src/Field/InputClearButton.test.tsx +117 -0
- package/src/Field/InputClearButton.tsx +30 -3
- package/src/HoverCard/useHoverCard.tsx +2 -23
- package/src/Icon/Icon.doc.mjs +2 -1
- package/src/Indicator/CheckIndicator.tsx +174 -0
- package/src/Indicator/CheckboxIndicator.tsx +257 -0
- package/src/Indicator/Indicator.doc.mjs +344 -0
- package/src/Indicator/Indicator.test.tsx +393 -0
- package/src/Indicator/RadioIndicator.tsx +206 -0
- package/src/Indicator/index.ts +45 -0
- package/src/Indicator/indicator.markers.stylex.ts +19 -0
- package/src/Indicator/indicatorRegistry.test.tsx +106 -0
- package/src/Indicator/indicatorRegistry.ts +120 -0
- package/src/Indicator/types.ts +186 -0
- package/src/Indicator/useIndicator.ts +39 -0
- package/src/Item/Item.doc.mjs +1 -1
- package/src/Item/Item.tsx +7 -14
- package/src/Layer/useLayer.doc.mjs +2 -2
- package/src/Layer/useLayer.test.tsx +85 -0
- package/src/Layer/useLayer.tsx +39 -1
- package/src/Lightbox/Lightbox.doc.mjs +1 -1
- package/src/Lightbox/Lightbox.tsx +43 -38
- package/src/Link/Link.tsx +4 -11
- package/src/MobileNav/MobileNav.tsx +3 -3
- package/src/MoreMenu/MoreMenu.doc.mjs +31 -0
- package/src/MoreMenu/MoreMenu.test.tsx +68 -1
- package/src/MoreMenu/MoreMenu.tsx +19 -0
- package/src/MultiSelector/MultiSelector.doc.mjs +9 -1
- package/src/MultiSelector/MultiSelector.test.tsx +255 -16
- package/src/MultiSelector/MultiSelector.tsx +103 -99
- package/src/NumberInput/NumberInput.doc.mjs +265 -50
- package/src/NumberInput/NumberInput.test.tsx +726 -21
- package/src/NumberInput/NumberInput.tsx +353 -59
- package/src/Outline/Outline.tsx +2 -5
- package/src/Pagination/Pagination.doc.mjs +1 -1
- package/src/Pagination/Pagination.test.tsx +22 -7
- package/src/Pagination/Pagination.tsx +38 -35
- package/src/Popover/Popover.tsx +6 -7
- package/src/PowerSearch/PowerSearch.tsx +1 -1
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +42 -0
- package/src/PowerSearch/PowerSearchEditPopover.tsx +7 -0
- package/src/ProgressBar/ProgressBar.doc.mjs +27 -5
- package/src/ProgressBar/ProgressBar.test.tsx +224 -1
- package/src/ProgressBar/ProgressBar.tsx +124 -22
- package/src/RadioList/RadioList.doc.mjs +4 -2
- package/src/RadioList/RadioListItem.tsx +31 -130
- package/src/Resizable/ResizeHandle.tsx +2 -9
- package/src/SegmentedControl/SegmentedControlItem.tsx +2 -9
- package/src/SelectableCard/SelectableCard.tsx +4 -9
- package/src/Selector/Selector.doc.mjs +7 -4
- package/src/Selector/Selector.test.tsx +935 -25
- package/src/Selector/Selector.tsx +189 -106
- package/src/Selector/hooks.ts +77 -50
- package/src/SideNav/SideNav.test.tsx +46 -0
- package/src/SideNav/SideNav.tsx +1 -0
- package/src/SideNav/SideNavCollapseButton.tsx +15 -10
- package/src/SideNav/SideNavHeading.tsx +48 -10
- package/src/SideNav/SideNavItem.tsx +20 -12
- package/src/Stack/Stack.doc.mjs +110 -0
- package/src/StatusDot/StatusDot.doc.mjs +12 -3
- package/src/Switch/Switch.test.tsx +32 -0
- package/src/Switch/Switch.tsx +8 -8
- package/src/TabList/Tab.tsx +2 -9
- package/src/TabList/TabMenu.tsx +14 -21
- package/src/Table/BaseTable.tsx +11 -0
- package/src/Table/index.ts +1 -4
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +30 -14
- package/src/Table/plugins/rowExpansion/index.ts +1 -4
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +125 -175
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +115 -458
- package/src/Table/plugins/sortable/useTableSortable.tsx +2 -6
- package/src/Table/plugins/tree/useTableTreeData.tsx +43 -24
- package/src/Table/tableContextMenu.test.tsx +27 -0
- package/src/Table/tableContextMenu.tsx +1 -0
- package/src/Table/types.ts +11 -0
- package/src/Table/useTableGroupedRows.doc.mjs +1 -1
- package/src/Table/useTableRowExpansion.doc.mjs +43 -66
- package/src/TextArea/TextArea.doc.mjs +42 -2
- package/src/TextArea/TextArea.test.tsx +219 -0
- package/src/TextArea/TextArea.tsx +34 -7
- package/src/TextInput/TextInput.doc.mjs +18 -2
- package/src/TextInput/TextInput.test.tsx +189 -0
- package/src/TextInput/TextInput.tsx +25 -31
- package/src/Thumbnail/Thumbnail.tsx +2 -9
- package/src/TimeInput/TimeInput.doc.mjs +2 -2
- package/src/TimeInput/TimeInput.test.tsx +30 -3
- package/src/TimeInput/TimeInput.tsx +9 -26
- package/src/Timestamp/Timestamp.doc.mjs +4 -3
- package/src/Timestamp/TimestampHoverCard.tsx +13 -35
- package/src/Token/Token.tsx +5 -28
- package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
- package/src/Tokenizer/Tokenizer.test.tsx +45 -3
- package/src/Tokenizer/Tokenizer.tsx +10 -2
- package/src/Tooltip/useTooltip.tsx +2 -23
- package/src/TopNav/TopNav.tsx +1 -3
- package/src/TopNav/TopNavHeading.tsx +42 -13
- package/src/TopNav/TopNavItem.tsx +3 -21
- package/src/TopNav/TopNavMegaMenu.test.tsx +433 -33
- package/src/TopNav/TopNavMegaMenu.tsx +118 -53
- package/src/TopNav/TopNavMegaMenuItem.tsx +2 -9
- package/src/TopNav/TopNavMenu.tsx +34 -37
- package/src/TreeList/TreeList.doc.mjs +5 -0
- package/src/TreeList/TreeList.test.tsx +206 -7
- package/src/TreeList/TreeList.tsx +22 -0
- package/src/TreeList/TreeListBranches.tsx +25 -2
- package/src/TreeList/TreeListItem.tsx +89 -52
- package/src/Typeahead/BaseTypeahead.tsx +19 -6
- package/src/Typeahead/Typeahead.doc.mjs +1 -0
- package/src/Typeahead/Typeahead.test.tsx +76 -3
- package/src/hooks/containerReveal.stylex.ts +102 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useClipboard.doc.mjs +87 -0
- package/src/hooks/useClipboard.test.tsx +151 -0
- package/src/hooks/useClipboard.ts +135 -0
- package/src/hooks/useContainerReveal.doc.mjs +7 -7
- package/src/hooks/useContainerReveal.test.tsx +42 -62
- package/src/hooks/useContainerReveal.ts +36 -91
- package/src/hooks/useImageMode.test.ts +1 -1
- package/src/hooks/useIndicatorFocusRing.tsx +120 -0
- package/src/hooks/useLongPress.test.tsx +18 -0
- package/src/hooks/useLongPress.ts +12 -2
- package/src/hooks/useScrollLock.test.ts +72 -0
- package/src/hooks/useScrollLock.ts +51 -19
- package/src/hooks/useStreamingText.test.ts +46 -1
- package/src/hooks/useStreamingText.ts +49 -7
- package/src/hooks/useTreeFocus.test.tsx +50 -0
- package/src/hooks/useTreeFocus.ts +14 -3
- package/src/hooks/useTypeahead.test.tsx +150 -0
- package/src/hooks/useTypeahead.ts +24 -9
- package/src/i18n/InternationalizationProvider.doc.mjs +7 -2
- package/src/index.ts +1 -0
- package/src/theme/defineTheme.ts +24 -0
- package/src/theme/derivedVarRegistry.test.ts +21 -1
- package/src/theme/derivedVarRegistry.ts +19 -6
- package/src/theme/expandColorScale.test.ts +14 -0
- package/src/theme/expandColorScale.ts +24 -9
- package/src/theme/expandTypeScale.test.ts +43 -0
- package/src/theme/expandTypeScale.ts +17 -0
- package/src/theme/generateThemeRules.test.ts +61 -20
- package/src/theme/generateThemeRules.ts +11 -0
- package/src/theme/index.ts +13 -0
- package/src/utils/focusOutline.stylex.ts +163 -0
- package/src/utils/focusReturn.test.ts +42 -0
- package/src/utils/focusReturn.ts +31 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/mergeRefs.test.ts +48 -0
- package/src/utils/mergeRefs.ts +12 -6
- package/src/utils/rtlStyles.ts +2 -2
- package/src/utils/themeProps.ts +26 -4
- package/dist/CheckboxInput/checkbox.markers.stylex.d.ts +0 -9
- package/dist/CheckboxInput/checkbox.markers.stylex.d.ts.map +0 -1
- package/dist/CheckboxInput/checkbox.markers.stylex.js +0 -14
- package/dist/RadioList/radio.markers.stylex.d.ts +0 -7
- package/dist/RadioList/radio.markers.stylex.d.ts.map +0 -1
- package/dist/RadioList/radio.markers.stylex.js +0 -12
- package/dist/hooks/containerReveal.pool.stylex.d.ts +0 -303
- package/dist/hooks/containerReveal.pool.stylex.d.ts.map +0 -1
- package/dist/hooks/containerReveal.pool.stylex.js +0 -292
- package/src/CheckboxInput/checkbox.markers.stylex.ts +0 -12
- package/src/RadioList/radio.markers.stylex.ts +0 -10
- package/src/hooks/containerReveal.pool.stylex.ts +0 -571
|
@@ -3,61 +3,55 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @file useContainerReveal.test.tsx
|
|
5
5
|
* @input Uses vitest, @testing-library/react, useContainerReveal
|
|
6
|
-
* @output Unit tests for the
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* @output Unit tests for the enabled/disabled contract, the dynamic isEnabled
|
|
7
|
+
* prop, the content-option → style-block mapping, and the promise that a
|
|
8
|
+
* large flat list mounts without dev warnings.
|
|
9
|
+
* @position Testing; validates useContainerReveal.ts.
|
|
10
|
+
*
|
|
11
|
+
* Nesting isolation is a cascade behavior jsdom does not implement, so it is
|
|
12
|
+
* verified in a real browser (Storybook's NestedIsolation story) rather than
|
|
13
|
+
* asserted here.
|
|
9
14
|
*
|
|
10
15
|
* SYNC: When useContainerReveal.ts changes, update these tests.
|
|
11
16
|
*/
|
|
12
17
|
|
|
13
|
-
import {describe, it, expect} from 'vitest';
|
|
14
|
-
import {renderHook, render
|
|
18
|
+
import {describe, it, expect, vi, afterEach} from 'vitest';
|
|
19
|
+
import {renderHook, render} from '@testing-library/react';
|
|
15
20
|
import {useContainerReveal} from './useContainerReveal';
|
|
16
|
-
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
vi.restoreAllMocks();
|
|
24
|
+
});
|
|
17
25
|
|
|
18
26
|
describe('useContainerReveal', () => {
|
|
19
27
|
it('returns spreadable getter props for container and content', () => {
|
|
20
28
|
const {result} = renderHook(() => useContainerReveal());
|
|
21
29
|
const container = result.current.getContainerProps();
|
|
22
30
|
const content = result.current.getContentRevealProps();
|
|
23
|
-
expect(container).toHaveProperty('className');
|
|
24
|
-
expect(content).toHaveProperty('className');
|
|
25
31
|
expect(typeof container.className).toBe('string');
|
|
26
32
|
expect(typeof content.className).toBe('string');
|
|
27
33
|
});
|
|
28
34
|
|
|
29
|
-
it('is inert when disabled: no
|
|
30
|
-
const {result} = renderHook(() =>
|
|
31
|
-
useContainerReveal({isEnabled: false}),
|
|
32
|
-
);
|
|
35
|
+
it('is inert when disabled: no container class, empty content props', () => {
|
|
36
|
+
const {result} = renderHook(() => useContainerReveal({isEnabled: false}));
|
|
33
37
|
expect(result.current.getContainerProps()).toEqual({});
|
|
34
38
|
expect(result.current.getContentRevealProps()).toEqual({});
|
|
35
39
|
});
|
|
36
40
|
|
|
37
|
-
it('
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const classA = a.result.current.getContainerProps().className;
|
|
44
|
-
const classB = b.result.current.getContainerProps().className;
|
|
45
|
-
expect(classA).toBeTruthy();
|
|
46
|
-
expect(classB).toBeTruthy();
|
|
47
|
-
expect(classA).not.toBe(classB);
|
|
48
|
-
a.unmount();
|
|
49
|
-
b.unmount();
|
|
50
|
-
});
|
|
41
|
+
it('follows isEnabled after mount, in both directions', () => {
|
|
42
|
+
const {result, rerender} = renderHook(
|
|
43
|
+
({isEnabled}) => useContainerReveal({isEnabled}),
|
|
44
|
+
{initialProps: {isEnabled: true}},
|
|
45
|
+
);
|
|
46
|
+
expect(result.current.getContentRevealProps().className).toBeTruthy();
|
|
51
47
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
expect(secondClass).toBe(firstClass);
|
|
60
|
-
second.unmount();
|
|
48
|
+
rerender({isEnabled: false});
|
|
49
|
+
expect(result.current.getContainerProps()).toEqual({});
|
|
50
|
+
expect(result.current.getContentRevealProps()).toEqual({});
|
|
51
|
+
|
|
52
|
+
rerender({isEnabled: true});
|
|
53
|
+
expect(result.current.getContainerProps().className).toBeTruthy();
|
|
54
|
+
expect(result.current.getContentRevealProps().className).toBeTruthy();
|
|
61
55
|
});
|
|
62
56
|
|
|
63
57
|
it('reveal and conceal map to different style blocks', () => {
|
|
@@ -80,37 +74,23 @@ describe('useContainerReveal', () => {
|
|
|
80
74
|
expect(clipped).not.toBe(preserved);
|
|
81
75
|
});
|
|
82
76
|
|
|
83
|
-
it('
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return
|
|
77
|
+
it('mounts a large flat list without a dev warning', () => {
|
|
78
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
79
|
+
function Row() {
|
|
80
|
+
const {getContainerProps, getContentRevealProps} = useContainerReveal();
|
|
81
|
+
return (
|
|
82
|
+
<div {...getContainerProps()}>
|
|
83
|
+
<span {...getContentRevealProps()}>actions</span>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
88
86
|
}
|
|
89
|
-
|
|
90
|
-
const {unmount} = render(
|
|
87
|
+
render(
|
|
91
88
|
<>
|
|
92
|
-
{Array.from({length:
|
|
93
|
-
<
|
|
89
|
+
{Array.from({length: 500}, (_, i) => (
|
|
90
|
+
<Row key={i} />
|
|
94
91
|
))}
|
|
95
92
|
</>,
|
|
96
93
|
);
|
|
97
|
-
|
|
98
|
-
expect(unique.size).toBe(POOL_SIZE);
|
|
99
|
-
unmount();
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('survives repeated mount/unmount without leaking the pool', () => {
|
|
103
|
-
// Mount and unmount a full pool several times; each cycle must still hand
|
|
104
|
-
// out POOL_SIZE distinct markers, proving slots are released.
|
|
105
|
-
for (let cycle = 0; cycle < 3; cycle++) {
|
|
106
|
-
const hooks = Array.from({length: POOL_SIZE}, () =>
|
|
107
|
-
renderHook(() => useContainerReveal()),
|
|
108
|
-
);
|
|
109
|
-
const classes = hooks.map(
|
|
110
|
-
(h) => h.result.current.getContainerProps().className,
|
|
111
|
-
);
|
|
112
|
-
expect(new Set(classes).size).toBe(POOL_SIZE);
|
|
113
|
-
act(() => hooks.forEach((h) => h.unmount()));
|
|
114
|
-
}
|
|
94
|
+
expect(warn).not.toHaveBeenCalled();
|
|
115
95
|
});
|
|
116
96
|
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file useContainerReveal.ts
|
|
7
|
-
* @input Uses
|
|
7
|
+
* @input Uses the containerReveal styles
|
|
8
8
|
* @output Exports useContainerReveal — a headless hover/focus reveal primitive
|
|
9
9
|
* @position Core hook. Consumed by any component that reveals (or conceals)
|
|
10
10
|
* content when its container is hovered or focused — e.g. Thumbnail's remove
|
|
@@ -12,8 +12,13 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Gives a container a scoped hover/focus-within trigger that reveals or
|
|
14
14
|
* conceals content inside it, entirely in CSS (no hover state in JS, no
|
|
15
|
-
* re-render on hover). The caller authors NO StyleX: the hook hands out
|
|
16
|
-
*
|
|
15
|
+
* re-render on hover). The caller authors NO StyleX: the hook hands out the
|
|
16
|
+
* container style and the matching content styles.
|
|
17
|
+
*
|
|
18
|
+
* Scoping is by inheritance: the container publishes its reveal state as
|
|
19
|
+
* custom properties on itself and the content reads them, so a nested
|
|
20
|
+
* container shadows its ancestor's state for its own subtree. See
|
|
21
|
+
* containerReveal.stylex.ts.
|
|
17
22
|
*
|
|
18
23
|
* ACCESSIBILITY (WCAG 2.2 by construction):
|
|
19
24
|
* - Revealed content is visually hidden at rest via position + opacity, so it
|
|
@@ -27,56 +32,19 @@
|
|
|
27
32
|
*
|
|
28
33
|
* SYNC: When modified, update:
|
|
29
34
|
* - /packages/core/src/hooks/index.ts (export)
|
|
30
|
-
* - containerReveal.
|
|
35
|
+
* - containerReveal.stylex.ts (if the style blocks change)
|
|
31
36
|
*/
|
|
32
37
|
|
|
33
|
-
import {
|
|
38
|
+
import {useMemo, type CSSProperties} from 'react';
|
|
34
39
|
import * as stylex from '@stylexjs/stylex';
|
|
35
|
-
import {
|
|
36
|
-
import {useDevWarning} from './useDevWarning';
|
|
37
|
-
|
|
38
|
-
// Module-level free-list. Each mounted, enabled useContainerReveal claims a
|
|
39
|
-
// distinct pool slot so that any two CONCURRENTLY mounted containers — in
|
|
40
|
-
// particular a nested container inside another's revealed content — get
|
|
41
|
-
// different markers and cannot leak hover/focus into one another. Slots are
|
|
42
|
-
// returned on unmount. Sibling containers that would only ever collide when
|
|
43
|
-
// the pool is exhausted are harmless (a sibling is never an ancestor), so the
|
|
44
|
-
// pool only needs to cover the number of concurrently mounted containers, not
|
|
45
|
-
// instances over time.
|
|
46
|
-
const claimed: boolean[] = new Array(POOL_SIZE).fill(false);
|
|
47
|
-
|
|
48
|
-
interface Claim {
|
|
49
|
-
/** Pool index to use. */
|
|
50
|
-
index: number;
|
|
51
|
-
/** True when the pool was full and this claim fell back to a shared slot. */
|
|
52
|
-
isExhausted: boolean;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function claimSlot(): Claim {
|
|
56
|
-
for (let i = 0; i < POOL_SIZE; i++) {
|
|
57
|
-
if (!claimed[i]) {
|
|
58
|
-
claimed[i] = true;
|
|
59
|
-
return {index: i, isExhausted: false};
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
// Exhausted: fall back to slot 0. Safe for siblings (a sibling is never an
|
|
63
|
-
// ancestor); only nesting deeper than POOL_SIZE could reintroduce a leak.
|
|
64
|
-
// Surfaced via useDevWarning so the pool can be grown.
|
|
65
|
-
return {index: 0, isExhausted: true};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function releaseSlot(index: number, isExhausted: boolean): void {
|
|
69
|
-
// A fallback claim never owned the slot exclusively; leave it as-is.
|
|
70
|
-
if (!isExhausted) {
|
|
71
|
-
claimed[index] = false;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
40
|
+
import {styles} from './containerReveal.stylex';
|
|
74
41
|
|
|
75
42
|
export interface UseContainerRevealOptions {
|
|
76
43
|
/**
|
|
77
|
-
* When false the hook is inert:
|
|
78
|
-
* return no styles, so content is always shown.
|
|
79
|
-
* own prop (e.g.
|
|
44
|
+
* When false the hook is inert: the container gets no styles and content
|
|
45
|
+
* getters return no styles, so content is always shown. Read on every
|
|
46
|
+
* render, so a component can flip it with its own prop (e.g.
|
|
47
|
+
* `revealOn === 'hover'`).
|
|
80
48
|
* @default true
|
|
81
49
|
*/
|
|
82
50
|
isEnabled?: boolean;
|
|
@@ -114,7 +82,7 @@ const EMPTY = Object.freeze({});
|
|
|
114
82
|
* Scoped, CSS-only hover/focus reveal for content inside a container.
|
|
115
83
|
*
|
|
116
84
|
* @example
|
|
117
|
-
* ```
|
|
85
|
+
* ```
|
|
118
86
|
* const {getContainerProps, getContentRevealProps} = useContainerReveal({
|
|
119
87
|
* isEnabled: revealOn === 'hover',
|
|
120
88
|
* });
|
|
@@ -132,50 +100,27 @@ export function useContainerReveal(
|
|
|
132
100
|
): UseContainerRevealReturn {
|
|
133
101
|
const {isEnabled = true} = options;
|
|
134
102
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
useEffect(() => {
|
|
143
|
-
if (claim == null) {
|
|
144
|
-
return;
|
|
103
|
+
return useMemo(() => {
|
|
104
|
+
if (!isEnabled) {
|
|
105
|
+
return {
|
|
106
|
+
getContainerProps: () => EMPTY,
|
|
107
|
+
getContentRevealProps: () => EMPTY,
|
|
108
|
+
};
|
|
145
109
|
}
|
|
146
|
-
return () => releaseSlot(claim.index, claim.isExhausted);
|
|
147
|
-
}, [claim]);
|
|
148
|
-
|
|
149
|
-
useDevWarning(
|
|
150
|
-
'useContainerReveal',
|
|
151
|
-
`More than ${POOL_SIZE} reveal containers are mounted at once; nested ` +
|
|
152
|
-
`containers beyond the pool may share a marker. Add markers to ` +
|
|
153
|
-
`containerReveal.pool.stylex.ts and raise POOL_SIZE.`,
|
|
154
|
-
claim?.isExhausted ?? false,
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
if (claim == null) {
|
|
158
110
|
return {
|
|
159
|
-
getContainerProps: () =>
|
|
160
|
-
getContentRevealProps: () =>
|
|
111
|
+
getContainerProps: () => stylex.props(styles.container),
|
|
112
|
+
getContentRevealProps: (contentOptions: ContentRevealOptions = {}) => {
|
|
113
|
+
const {isRevealInverted = false, isLayoutPreserved = false} =
|
|
114
|
+
contentOptions;
|
|
115
|
+
const style = isRevealInverted
|
|
116
|
+
? isLayoutPreserved
|
|
117
|
+
? styles.concealLayoutPreserved
|
|
118
|
+
: styles.conceal
|
|
119
|
+
: isLayoutPreserved
|
|
120
|
+
? styles.revealLayoutPreserved
|
|
121
|
+
: styles.reveal;
|
|
122
|
+
return stylex.props(style);
|
|
123
|
+
},
|
|
161
124
|
};
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const slot: RevealSlot = POOL[claim.index];
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
getContainerProps: () => stylex.props(slot.marker),
|
|
168
|
-
getContentRevealProps: (contentOptions: ContentRevealOptions = {}) => {
|
|
169
|
-
const {isRevealInverted = false, isLayoutPreserved = false} =
|
|
170
|
-
contentOptions;
|
|
171
|
-
const style = isRevealInverted
|
|
172
|
-
? isLayoutPreserved
|
|
173
|
-
? slot.concealLayoutPreserved
|
|
174
|
-
: slot.conceal
|
|
175
|
-
: isLayoutPreserved
|
|
176
|
-
? slot.revealLayoutPreserved
|
|
177
|
-
: slot.reveal;
|
|
178
|
-
return stylex.props(style);
|
|
179
|
-
},
|
|
180
|
-
};
|
|
125
|
+
}, [isEnabled]);
|
|
181
126
|
}
|
|
@@ -105,7 +105,7 @@ describe('useImageMode', () => {
|
|
|
105
105
|
stubCorsBlockedFetch();
|
|
106
106
|
const {result} = renderHook(() =>
|
|
107
107
|
useImageMode(
|
|
108
|
-
'https://
|
|
108
|
+
'https://cdn.example.com/photos/moody-scene-vertical-2.png',
|
|
109
109
|
{fallback: null},
|
|
110
110
|
),
|
|
111
111
|
);
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file useIndicatorFocusRing.tsx
|
|
7
|
+
* @input A ref to the element wrapping only the indicator
|
|
8
|
+
* @output Focus handlers that draw the standard ring on the indicator itself
|
|
9
|
+
* @position Used by controls whose focusable input is visually hidden
|
|
10
|
+
*
|
|
11
|
+
* SYNC: When modified, update:
|
|
12
|
+
* - /packages/core/src/hooks/index.ts (exports)
|
|
13
|
+
*
|
|
14
|
+
* A checkbox or radio focuses a native `<input>` that is `opacity: 0`, so the
|
|
15
|
+
* visible focus indicator has to appear on the picture beside it — and that
|
|
16
|
+
* picture is a themeable indicator, which is what makes "who draws the ring"
|
|
17
|
+
* awkward:
|
|
18
|
+
*
|
|
19
|
+
* - Only the indicator's own element can shape the ring: `outline` follows
|
|
20
|
+
* that element's `border-radius`. Draw it on a wrapper and the owner has to
|
|
21
|
+
* hardcode a guess about whatever indicator it hosts (RadioListItem used to
|
|
22
|
+
* carry `border-radius: 50%` for a circle it did not own).
|
|
23
|
+
* - But an indicator supplied by a theme is third-party code. If drawing the
|
|
24
|
+
* ring is its job, a replacement that simply doesn't ships a control with no
|
|
25
|
+
* visible focus (WCAG 2.4.7) — and that is the DEFAULT outcome: the sample
|
|
26
|
+
* replacement in our own Storybook destructures `{state, size, isDisabled}`
|
|
27
|
+
* and drops the rest, which is what a theme author plausibly writes. Nothing
|
|
28
|
+
* can enforce otherwise; a component ignoring every prop is still assignable
|
|
29
|
+
* to `IndicatorComponent`, and branding the return type does not work either
|
|
30
|
+
* (JSX types every expression as `JSX.Element`).
|
|
31
|
+
*
|
|
32
|
+
* So the owner draws it, on the indicator's own element, imperatively at focus
|
|
33
|
+
* time. No cooperation is required and none can be forgotten.
|
|
34
|
+
*
|
|
35
|
+
* Two details that are load-bearing, both measured rather than assumed:
|
|
36
|
+
*
|
|
37
|
+
* 1. **Inline style, not a class.** React replaces `className` wholesale on
|
|
38
|
+
* re-render, so an injected class disappears the moment the control changes
|
|
39
|
+
* state — pressing Space on a focused checkbox lost the ring. React
|
|
40
|
+
* reconciles `style` per property, so an `outline` set here survives.
|
|
41
|
+
* 2. **`:focus-visible`, not `:focus`.** The CSS this replaces got
|
|
42
|
+
* keyboard-vs-pointer for free; an event handler has to ask. Checking the
|
|
43
|
+
* element keeps the browser's heuristic, including `focus({focusVisible:
|
|
44
|
+
* true})`, which a hand-rolled modality guess would miss.
|
|
45
|
+
*
|
|
46
|
+
* Imperative styling on an interaction event follows `useTableSelection`,
|
|
47
|
+
* which sets row-selection styles the same way.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
import {useCallback, useMemo} from 'react';
|
|
51
|
+
import type {FocusEvent, RefObject} from 'react';
|
|
52
|
+
import {
|
|
53
|
+
FOCUS_OUTLINE_PARTS,
|
|
54
|
+
FOCUS_OUTLINE_PARTS_NONE,
|
|
55
|
+
} from '../utils/focusOutline.stylex';
|
|
56
|
+
|
|
57
|
+
export interface UseIndicatorFocusRingReturn {
|
|
58
|
+
/** Spread onto the element that owns the focusable input. */
|
|
59
|
+
focusProps: {
|
|
60
|
+
onFocus: (event: FocusEvent<HTMLElement>) => void;
|
|
61
|
+
onBlur: () => void;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Draw the standard focus ring on the indicator inside `containerRef`, shaped
|
|
67
|
+
* by whatever that indicator actually is.
|
|
68
|
+
*
|
|
69
|
+
* @param containerRef - Wraps ONLY the indicator, so its single element child
|
|
70
|
+
* is unambiguously the thing to ring, whatever a theme renders there.
|
|
71
|
+
* @param isDisabled - Skip the ring; a disabled control is not focusable.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```
|
|
75
|
+
* const indicatorRef = useRef<HTMLSpanElement>(null);
|
|
76
|
+
* const {focusProps} = useIndicatorFocusRing(indicatorRef, isDisabled);
|
|
77
|
+
* <div {...focusProps}>
|
|
78
|
+
* <input type="checkbox" />
|
|
79
|
+
* <span ref={indicatorRef}><Indicator state="checked" /></span>
|
|
80
|
+
* </div>
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export function useIndicatorFocusRing(
|
|
84
|
+
containerRef: RefObject<HTMLElement | null>,
|
|
85
|
+
isDisabled = false,
|
|
86
|
+
): UseIndicatorFocusRingReturn {
|
|
87
|
+
const paint = useCallback(
|
|
88
|
+
(on: boolean) => {
|
|
89
|
+
// `firstElementChild`, not a search: the container holds the indicator
|
|
90
|
+
// and nothing else, so there is no ambiguity — and no way for a later
|
|
91
|
+
// sibling to quietly become the target.
|
|
92
|
+
const indicator = containerRef.current?.firstElementChild;
|
|
93
|
+
if (indicator instanceof HTMLElement) {
|
|
94
|
+
Object.assign(
|
|
95
|
+
indicator.style,
|
|
96
|
+
on ? FOCUS_OUTLINE_PARTS : FOCUS_OUTLINE_PARTS_NONE,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
[containerRef],
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const onFocus = useCallback(
|
|
104
|
+
(event: FocusEvent<HTMLElement>) => {
|
|
105
|
+
if (isDisabled) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const target = event.target;
|
|
109
|
+
if (target instanceof HTMLElement && !target.matches(':focus-visible')) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
paint(true);
|
|
113
|
+
},
|
|
114
|
+
[isDisabled, paint],
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const onBlur = useCallback(() => paint(false), [paint]);
|
|
118
|
+
|
|
119
|
+
return useMemo(() => ({focusProps: {onFocus, onBlur}}), [onFocus, onBlur]);
|
|
120
|
+
}
|
|
@@ -81,6 +81,24 @@ describe('useLongPress', () => {
|
|
|
81
81
|
expect(onLongPress).not.toHaveBeenCalled();
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
+
it('cancels when a second finger touches down mid-press', () => {
|
|
85
|
+
const onLongPress = vi.fn();
|
|
86
|
+
const {result} = renderHook(() => useLongPress({onLongPress}));
|
|
87
|
+
|
|
88
|
+
act(() => {
|
|
89
|
+
result.current.onTouchStart(touchEvent([{clientX: 0, clientY: 0}]));
|
|
90
|
+
// A second finger joins before the press fires (e.g. pinch-to-zoom).
|
|
91
|
+
result.current.onTouchStart(
|
|
92
|
+
touchEvent([
|
|
93
|
+
{clientX: 0, clientY: 0},
|
|
94
|
+
{clientX: 50, clientY: 50},
|
|
95
|
+
]),
|
|
96
|
+
);
|
|
97
|
+
vi.advanceTimersByTime(500);
|
|
98
|
+
});
|
|
99
|
+
expect(onLongPress).not.toHaveBeenCalled();
|
|
100
|
+
});
|
|
101
|
+
|
|
84
102
|
it('cancels when the finger moves past the threshold', () => {
|
|
85
103
|
const onLongPress = vi.fn();
|
|
86
104
|
const {result} = renderHook(() => useLongPress({onLongPress}));
|
|
@@ -70,7 +70,12 @@ export function useLongPress(
|
|
|
70
70
|
|
|
71
71
|
const onTouchStart = useCallback(
|
|
72
72
|
(e: React.TouchEvent) => {
|
|
73
|
-
if (disabled
|
|
73
|
+
if (disabled) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (e.touches.length !== 1) {
|
|
77
|
+
// Multi-touch cancels any pending long-press.
|
|
78
|
+
clear();
|
|
74
79
|
return;
|
|
75
80
|
}
|
|
76
81
|
const touch = e.touches[0];
|
|
@@ -92,7 +97,12 @@ export function useLongPress(
|
|
|
92
97
|
const onTouchMove = useCallback(
|
|
93
98
|
(e: React.TouchEvent) => {
|
|
94
99
|
const start = startRef.current;
|
|
95
|
-
if (start == null
|
|
100
|
+
if (start == null) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (e.touches.length !== 1) {
|
|
104
|
+
// Multi-touch cancels the pending long-press.
|
|
105
|
+
clear();
|
|
96
106
|
return;
|
|
97
107
|
}
|
|
98
108
|
const touch = e.touches[0];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file useScrollLock.test.ts
|
|
5
|
+
* @input Uses vitest, @testing-library/react, useScrollLock hook
|
|
6
|
+
* @output Unit tests for single and concurrent useScrollLock instances
|
|
7
|
+
* @position Testing; validates useScrollLock.ts implementation
|
|
8
|
+
*
|
|
9
|
+
* SYNC: When useScrollLock.ts changes, update tests to match new behavior
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {afterEach, describe, expect, it, vi} from 'vitest';
|
|
13
|
+
import {cleanup, renderHook} from '@testing-library/react';
|
|
14
|
+
import {useScrollLock} from './useScrollLock';
|
|
15
|
+
|
|
16
|
+
describe('useScrollLock', () => {
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
cleanup();
|
|
19
|
+
document.body.style.cssText = '';
|
|
20
|
+
vi.restoreAllMocks();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('restores body styles and scroll position after a single lock is released', () => {
|
|
24
|
+
document.body.style.overflow = 'auto';
|
|
25
|
+
document.body.style.position = 'relative';
|
|
26
|
+
|
|
27
|
+
vi.spyOn(window, 'scrollX', 'get').mockReturnValue(120);
|
|
28
|
+
vi.spyOn(window, 'scrollY', 'get').mockReturnValue(480);
|
|
29
|
+
vi.spyOn(window, 'scrollTo').mockImplementation(() => {});
|
|
30
|
+
|
|
31
|
+
const lock = renderHook(() => useScrollLock(true));
|
|
32
|
+
|
|
33
|
+
expect(document.body.style.overflow).toBe('hidden');
|
|
34
|
+
expect(document.body.style.position).toBe('fixed');
|
|
35
|
+
|
|
36
|
+
lock.unmount();
|
|
37
|
+
|
|
38
|
+
expect(document.body.style.overflow).toBe('auto');
|
|
39
|
+
expect(document.body.style.position).toBe('relative');
|
|
40
|
+
expect(window.scrollTo).toHaveBeenCalledWith(120, 480);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('stays locked while a second overlay is still open, even if the first closes out of order', () => {
|
|
44
|
+
vi.spyOn(window, 'scrollTo').mockImplementation(() => {});
|
|
45
|
+
|
|
46
|
+
const first = renderHook(() => useScrollLock(true));
|
|
47
|
+
const second = renderHook(() => useScrollLock(true));
|
|
48
|
+
|
|
49
|
+
first.unmount();
|
|
50
|
+
|
|
51
|
+
expect(document.body.style.position).toBe('fixed');
|
|
52
|
+
expect(document.body.style.overflow).toBe('hidden');
|
|
53
|
+
|
|
54
|
+
second.unmount();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('fully restores the body once every overlay has closed, regardless of close order', () => {
|
|
58
|
+
vi.spyOn(window, 'scrollTo').mockImplementation(() => {});
|
|
59
|
+
|
|
60
|
+
const first = renderHook(() => useScrollLock(true));
|
|
61
|
+
const second = renderHook(() => useScrollLock(true));
|
|
62
|
+
|
|
63
|
+
first.unmount();
|
|
64
|
+
second.unmount();
|
|
65
|
+
|
|
66
|
+
expect(document.body.style.position).toBe('');
|
|
67
|
+
expect(document.body.style.overflow).toBe('');
|
|
68
|
+
expect(document.body.style.top).toBe('');
|
|
69
|
+
expect(document.body.style.left).toBe('');
|
|
70
|
+
expect(document.body.style.right).toBe('');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -17,6 +17,19 @@
|
|
|
17
17
|
|
|
18
18
|
import {useEffect} from 'react';
|
|
19
19
|
|
|
20
|
+
interface ScrollLockSnapshot {
|
|
21
|
+
scrollX: number;
|
|
22
|
+
scrollY: number;
|
|
23
|
+
overflow: string;
|
|
24
|
+
position: string;
|
|
25
|
+
top: string;
|
|
26
|
+
left: string;
|
|
27
|
+
right: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let lockCount = 0;
|
|
31
|
+
let originalBodyState: ScrollLockSnapshot | null = null;
|
|
32
|
+
|
|
20
33
|
/**
|
|
21
34
|
* Locks body scroll when `isLocked` is true.
|
|
22
35
|
*
|
|
@@ -36,28 +49,47 @@ export function useScrollLock(isLocked: boolean): void {
|
|
|
36
49
|
return;
|
|
37
50
|
}
|
|
38
51
|
|
|
39
|
-
const scrollX = window.scrollX;
|
|
40
|
-
const scrollY = window.scrollY;
|
|
41
52
|
const {body} = document;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
|
|
54
|
+
if (lockCount === 0) {
|
|
55
|
+
const scrollX = window.scrollX;
|
|
56
|
+
const scrollY = window.scrollY;
|
|
57
|
+
|
|
58
|
+
originalBodyState = {
|
|
59
|
+
scrollX,
|
|
60
|
+
scrollY,
|
|
61
|
+
overflow: body.style.overflow,
|
|
62
|
+
position: body.style.position,
|
|
63
|
+
top: body.style.top,
|
|
64
|
+
left: body.style.left,
|
|
65
|
+
right: body.style.right,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
body.style.overflow = 'hidden';
|
|
69
|
+
body.style.position = 'fixed';
|
|
70
|
+
body.style.top = `-${scrollY}px`;
|
|
71
|
+
body.style.left = '0';
|
|
72
|
+
body.style.right = '0';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
lockCount += 1;
|
|
53
76
|
|
|
54
77
|
return () => {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
78
|
+
lockCount -= 1;
|
|
79
|
+
|
|
80
|
+
if (lockCount !== 0 || originalBodyState == null) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const state = originalBodyState;
|
|
85
|
+
originalBodyState = null;
|
|
86
|
+
|
|
87
|
+
body.style.overflow = state.overflow;
|
|
88
|
+
body.style.position = state.position;
|
|
89
|
+
body.style.top = state.top;
|
|
90
|
+
body.style.left = state.left;
|
|
91
|
+
body.style.right = state.right;
|
|
92
|
+
window.scrollTo(state.scrollX, state.scrollY);
|
|
61
93
|
};
|
|
62
94
|
}, [isLocked]);
|
|
63
95
|
}
|