@astryxdesign/core 0.5.2-canary.2da7a39 → 0.5.2-canary.2e51213
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/dist/AppShell/AppShell.d.ts +2 -2
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/AppShell/AppShell.js +10 -7
- package/dist/Banner/Banner.d.ts +5 -0
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +7 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts +3 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +22 -15
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +2 -2
- package/dist/Chat/ChatComposer.d.ts +2 -2
- package/dist/Chat/ChatComposer.d.ts.map +1 -1
- package/dist/Chat/ChatComposer.js +21 -2
- package/dist/Chat/ChatToolCalls.d.ts +1 -1
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +12 -34
- package/dist/Chat/useChatNewMessages.js +3 -3
- package/dist/CheckboxList/CheckboxListItem.d.ts +5 -3
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.d.ts +47 -13
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +269 -162
- package/dist/DateTimeInput/NativeDateSegment.d.ts +24 -0
- package/dist/DateTimeInput/NativeDateSegment.d.ts.map +1 -0
- package/dist/DateTimeInput/NativeDateSegment.js +235 -0
- package/dist/DateTimeInput/NativeTimeSegment.d.ts +30 -0
- package/dist/DateTimeInput/NativeTimeSegment.d.ts.map +1 -0
- package/dist/DateTimeInput/NativeTimeSegment.js +248 -0
- package/dist/DateTimeInput/index.d.ts +1 -1
- package/dist/DateTimeInput/index.d.ts.map +1 -1
- package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts +95 -0
- package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts.map +1 -0
- package/dist/DateTimeInput/nativePickerSegmentStyles.js +103 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +2 -4
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +10 -4
- package/dist/Field/PanelSearchInput.d.ts.map +1 -1
- package/dist/Field/PanelSearchInput.js +3 -5
- package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
- package/dist/FieldStatus/FieldStatus.js +4 -2
- package/dist/Layer/useTouchTrigger.d.ts.map +1 -1
- package/dist/Layer/useTouchTrigger.js +2 -4
- package/dist/Layout/Layout.d.ts +7 -8
- package/dist/Layout/Layout.d.ts.map +1 -1
- package/dist/Layout/Layout.js +7 -8
- package/dist/MultiSelector/MultiSelector.d.ts +11 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +89 -45
- package/dist/RadioList/RadioListItem.d.ts +30 -5
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +17 -4
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +102 -44
- package/dist/Resizable/index.d.ts +2 -0
- package/dist/Resizable/index.d.ts.map +1 -1
- package/dist/Resizable/index.js +1 -0
- package/dist/Resizable/useResizable.d.ts +89 -8
- package/dist/Resizable/useResizable.d.ts.map +1 -1
- package/dist/Resizable/useResizable.js +521 -38
- package/dist/Resizable/utils.d.ts +35 -0
- package/dist/Resizable/utils.d.ts.map +1 -0
- package/dist/Resizable/utils.js +27 -0
- package/dist/Selector/Selector.d.ts +10 -0
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +105 -57
- package/dist/Selector/useSelectorPresentation.d.ts +1 -0
- package/dist/Selector/useSelectorPresentation.d.ts.map +1 -1
- package/dist/Selector/useSelectorPresentation.js +17 -2
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +3 -5
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +9 -10
- package/dist/Stepper/Step.d.ts +2 -1
- package/dist/Stepper/Step.d.ts.map +1 -1
- package/dist/Stepper/Step.js +75 -11
- package/dist/Stepper/Stepper.d.ts.map +1 -1
- package/dist/Stepper/Stepper.js +1 -0
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +2 -3
- package/dist/Table/index.d.ts +16 -1
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +4 -0
- package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
- package/dist/Table/plugins/columnResize/useTableColumnResize.js +8 -9
- package/dist/Table/plugins/rowStatus/index.d.ts +1 -1
- package/dist/Table/plugins/rowStatus/index.d.ts.map +1 -1
- package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts +11 -30
- package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -1
- package/dist/Table/plugins/rowStatus/useTableRowStatus.js +108 -62
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +9 -1
- package/dist/Text/useTruncation.d.ts +1 -1
- package/dist/Text/useTruncation.d.ts.map +1 -1
- package/dist/Text/useTruncation.js +8 -7
- package/dist/TimeInput/TimeInput.d.ts +16 -1
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +98 -60
- package/dist/TimeInput/index.d.ts +1 -1
- package/dist/TimeInput/index.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.d.ts +2 -2
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +4 -145
- package/dist/Timestamp/formatRelativeTime.d.ts +20 -0
- package/dist/Timestamp/formatRelativeTime.d.ts.map +1 -0
- package/dist/Timestamp/formatRelativeTime.js +81 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +125 -77
- package/dist/Tokenizer/Tokenizer.d.ts +0 -38
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +94 -26
- package/dist/Tokenizer/useEndLaneReserve.d.ts +31 -0
- package/dist/Tokenizer/useEndLaneReserve.d.ts.map +1 -0
- package/dist/Tokenizer/useEndLaneReserve.js +136 -0
- package/dist/Tooltip/useTooltip.d.ts +1 -1
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +53 -42
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +85 -30
- package/dist/Typeahead/Typeahead.d.ts +0 -21
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +108 -67
- package/dist/Typeahead/busyIndicatorLane.d.ts +62 -0
- package/dist/Typeahead/busyIndicatorLane.d.ts.map +1 -0
- package/dist/Typeahead/busyIndicatorLane.js +98 -0
- package/dist/astryx.css +25 -7
- package/dist/hooks/useFocusReturnVisibility.d.ts.map +1 -1
- package/dist/hooks/useFocusReturnVisibility.js +3 -5
- package/dist/hooks/useIsomorphicLayoutEffect.d.ts +2 -2
- package/dist/hooks/useIsomorphicLayoutEffect.d.ts.map +1 -1
- package/dist/hooks/useOverflow.js +11 -11
- package/dist/hooks/useScrollOverflow.d.ts.map +1 -1
- package/dist/hooks/useScrollOverflow.js +7 -4
- package/dist/theme/defineTheme.d.ts +13 -0
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +7 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +1 -1
- package/dist/theme/localTokens.d.ts +18 -0
- package/dist/theme/localTokens.d.ts.map +1 -0
- package/dist/theme/localTokens.js +162 -0
- package/dist/utils/interactionModality.d.ts +6 -28
- package/dist/utils/interactionModality.d.ts.map +1 -1
- package/dist/utils/interactionModality.js +72 -37
- package/dist/utils/sharedResizeObserver.d.ts +17 -9
- package/dist/utils/sharedResizeObserver.d.ts.map +1 -1
- package/dist/utils/sharedResizeObserver.js +54 -12
- package/locales/en.json +8 -0
- package/locales/pseudo.json +6 -0
- package/package.json +7 -2
- package/src/AlertDialog/useImperativeAlertDialog.test.tsx +163 -0
- package/src/AppShell/AppShell.doc.mjs +4 -3
- package/src/AppShell/AppShell.test.tsx +21 -0
- package/src/AppShell/AppShell.tsx +12 -7
- package/src/Banner/Banner.doc.mjs +5 -1
- package/src/Banner/Banner.tsx +12 -1
- package/src/BottomSheet/BottomSheet.doc.mjs +31 -0
- package/src/BottomSheet/BottomSheet.spec.md +178 -0
- package/src/Breadcrumbs/BreadcrumbItem.tsx +18 -9
- package/src/Breadcrumbs/Breadcrumbs.doc.mjs +4 -1
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +12 -0
- package/src/Button/Button.doc.mjs +56 -0
- package/src/ButtonGroup/ButtonGroup.doc.mjs +47 -0
- package/src/Calendar/hooks/useCalendarConstraints.test.ts +153 -0
- package/src/Calendar/hooks/useCalendarDays.test.ts +265 -0
- package/src/Calendar/hooks/useCalendarNavigation.test.ts +252 -0
- package/src/Carousel/Carousel.test.tsx +83 -0
- package/src/Carousel/Carousel.tsx +8 -2
- package/src/Chat/ChatComposer.doc.mjs +7 -4
- package/src/Chat/ChatComposer.test.tsx +84 -2
- package/src/Chat/ChatComposer.tsx +45 -3
- package/src/Chat/ChatSendButton.test.tsx +189 -0
- package/src/Chat/ChatToolCalls.doc.mjs +1 -1
- package/src/Chat/ChatToolCalls.test.tsx +33 -1
- package/src/Chat/ChatToolCalls.tsx +13 -34
- package/src/Chat/useChatNewMessages.ts +3 -3
- package/src/Chat/useChatPasteAsToken.test.ts +191 -0
- package/src/CheckboxList/CheckboxList.doc.mjs +172 -31
- package/src/CheckboxList/CheckboxList.spec.md +215 -0
- package/src/CheckboxList/CheckboxList.test.tsx +45 -0
- package/src/CheckboxList/CheckboxListItem.doc.mjs +11 -9
- package/src/CheckboxList/CheckboxListItem.tsx +5 -3
- package/src/Collapsible/useCollapsible.test.tsx +236 -0
- package/src/CommandPalette/CommandPalette.doc.mjs +72 -0
- package/src/CommandPalette/CommandPalette.spec.md +224 -0
- package/src/CommandPalette/CommandPaletteEmpty.test.tsx +101 -0
- package/src/ComplexSelector/ComplexSelector.doc.mjs +42 -0
- package/src/ComplexSelector/ComplexSelector.spec.md +190 -0
- package/src/ContextMenu/ContextMenu.doc.mjs +48 -0
- package/src/ContextMenu/ContextMenu.spec.md +207 -0
- package/src/DateTimeInput/DateTimeInput.doc.mjs +43 -23
- package/src/DateTimeInput/DateTimeInput.tsx +388 -181
- package/src/DateTimeInput/DateTimeInputTouch.test.tsx +10 -2
- package/src/DateTimeInput/NativeDateSegment.tsx +308 -0
- package/src/DateTimeInput/NativePickerSegments.test.tsx +626 -0
- package/src/DateTimeInput/NativeTimeSegment.tsx +331 -0
- package/src/DateTimeInput/index.ts +1 -0
- package/src/DateTimeInput/nativePickerSegmentStyles.ts +120 -0
- package/src/Divider/Divider.doc.mjs +24 -0
- package/src/Divider/Divider.spec.md +157 -0
- package/src/DropdownMenu/DropdownMenu.doc.mjs +104 -0
- package/src/DropdownMenu/DropdownMenu.spec.md +246 -0
- package/src/DropdownMenu/DropdownMenu.tsx +2 -4
- package/src/Field/Field.doc.mjs +1 -0
- package/src/Field/Field.test.tsx +39 -0
- package/src/Field/Field.tsx +18 -1
- package/src/Field/InputClearButton.test.tsx +68 -6
- package/src/Field/PanelSearchInput.tsx +3 -5
- package/src/FieldStatus/FieldStatus.doc.mjs +21 -0
- package/src/FieldStatus/FieldStatus.spec.md +213 -0
- package/src/FieldStatus/FieldStatus.test.tsx +17 -0
- package/src/FieldStatus/FieldStatus.tsx +7 -2
- package/src/Grid/Grid.doc.mjs +19 -0
- package/src/Grid/Grid.spec.md +162 -0
- package/src/Icon/Icon.doc.mjs +196 -48
- package/src/Icon/Icon.spec.md +192 -0
- package/src/IconButton/IconButton.doc.mjs +38 -0
- package/src/Kbd/Kbd.doc.mjs +18 -0
- package/src/Kbd/Kbd.spec.md +142 -0
- package/src/Layer/useTouchTrigger.ts +2 -4
- package/src/Layout/Layout.doc.mjs +57 -17
- package/src/Layout/Layout.spec.md +235 -0
- package/src/Layout/Layout.test.tsx +1 -1
- package/src/Layout/Layout.tsx +7 -8
- package/src/Layout/LayoutHeader.doc.mjs +9 -0
- package/src/Layout/LayoutPanel.doc.mjs +4 -3
- package/src/Lightbox/Lightbox.doc.mjs +149 -33
- package/src/Lightbox/Lightbox.spec.md +198 -0
- package/src/Lightbox/useLightbox.test.tsx +263 -0
- package/src/Markdown/Markdown.doc.mjs +60 -0
- package/src/Markdown/Markdown.spec.md +207 -0
- package/src/MobileNav/MobileNav.doc.mjs +140 -32
- package/src/MobileNav/MobileNav.spec.md +209 -0
- package/src/MoreMenu/MoreMenu.doc.mjs +42 -0
- package/src/MoreMenu/MoreMenu.spec.md +222 -0
- package/src/MultiSelector/MultiSelector.doc.mjs +124 -1
- package/src/MultiSelector/MultiSelector.spec.md +293 -0
- package/src/MultiSelector/MultiSelector.test.tsx +305 -2
- package/src/MultiSelector/MultiSelector.tsx +124 -55
- package/src/NavIcon/NavIcon.doc.mjs +17 -0
- package/src/NavIcon/NavIcon.spec.md +134 -0
- package/src/NavMenu/NavHeadingMenu.spec.md +210 -0
- package/src/NavMenu/NavMenu.doc.mjs +37 -0
- package/src/Outline/Outline.doc.mjs +35 -0
- package/src/Outline/Outline.spec.md +162 -0
- package/src/OverflowList/OverflowList.doc.mjs +24 -0
- package/src/OverflowList/OverflowList.spec.md +157 -0
- package/src/Pagination/Pagination.doc.mjs +74 -0
- package/src/Pagination/Pagination.spec.md +226 -0
- package/src/Popover/Popover.doc.mjs +264 -65
- package/src/Popover/Popover.spec.md +421 -0
- package/src/Popover/usePopover.doc.mjs +208 -33
- package/src/PowerSearch/PowerSearch.spec.md +291 -0
- package/src/PowerSearch/PowerSearchFilterEditor.test.tsx +253 -0
- package/src/PowerSearch/PowerSearchToken.test.tsx +228 -0
- package/src/ProgressBar/ProgressBar.doc.mjs +198 -38
- package/src/ProgressBar/ProgressBar.spec.md +261 -0
- package/src/RadioList/RadioList.test.tsx +136 -2
- package/src/RadioList/RadioListItem.doc.mjs +30 -11
- package/src/RadioList/RadioListItem.tsx +44 -8
- package/src/Resizable/Resizable.doc.mjs +130 -24
- package/src/Resizable/Resizable.spec.md +246 -0
- package/src/Resizable/ResizeHandle.test.tsx +177 -56
- package/src/Resizable/ResizeHandle.tsx +128 -45
- package/src/Resizable/index.ts +2 -0
- package/src/Resizable/shippedDirections.test.ts +462 -0
- package/src/Resizable/useResizable.doc.mjs +124 -29
- package/src/Resizable/useResizable.test.ts +1277 -3
- package/src/Resizable/useResizable.ts +760 -48
- package/src/Resizable/utils.test.ts +74 -0
- package/src/Resizable/utils.ts +35 -0
- package/src/Section/Section.doc.mjs +17 -0
- package/src/Section/Section.spec.md +139 -0
- package/src/SegmentedControl/SegmentedControl.doc.mjs +83 -0
- package/src/SegmentedControl/SegmentedControl.spec.md +152 -0
- package/src/Selector/Selector.doc.mjs +133 -97
- package/src/Selector/Selector.spec.md +300 -0
- package/src/Selector/Selector.test.tsx +318 -1
- package/src/Selector/Selector.tsx +127 -60
- package/src/Selector/useSelectorPresentation.ts +24 -4
- package/src/SideNav/SideNav.test.tsx +3 -3
- package/src/SideNav/SideNavCollapseButton.doc.mjs +8 -0
- package/src/SideNav/SideNavItem.doc.mjs +1 -1
- package/src/Skeleton/Skeleton.doc.mjs +12 -0
- package/src/Skeleton/Skeleton.spec.md +127 -0
- package/src/Slider/Slider.doc.mjs +184 -30
- package/src/Slider/Slider.spec.md +224 -0
- package/src/Slider/Slider.tsx +2 -5
- package/src/Spinner/Spinner.doc.mjs +5 -5
- package/src/Spinner/Spinner.test.tsx +32 -7
- package/src/Spinner/Spinner.tsx +46 -14
- package/src/Stack/Stack.doc.mjs +22 -0
- package/src/Stack/Stack.spec.md +155 -0
- package/src/StatusDot/StatusDot.doc.mjs +17 -0
- package/src/StatusDot/StatusDot.spec.md +138 -0
- package/src/Stepper/Step.doc.mjs +1 -1
- package/src/Stepper/Step.tsx +118 -5
- package/src/Stepper/Stepper.doc.mjs +51 -1
- package/src/Stepper/Stepper.spec.md +245 -0
- package/src/Stepper/Stepper.test.tsx +315 -0
- package/src/Stepper/Stepper.tsx +8 -0
- package/src/Switch/Switch.doc.mjs +40 -0
- package/src/Switch/Switch.spec.md +175 -0
- package/src/TabList/TabList.tsx +2 -3
- package/src/Table/Table.doc.mjs +102 -24
- package/src/Table/Table.perf.test.tsx +51 -1
- package/src/Table/Table.spec.md +325 -0
- package/src/Table/TableHeaderCell.test.tsx +291 -0
- package/src/Table/index.ts +19 -4
- package/src/Table/plugins/columnResize/useTableColumnResize.tsx +8 -12
- package/src/Table/plugins/filtering/useTableFilterState.test.tsx +143 -0
- package/src/Table/plugins/groupedRows/useTableGroupedRows.test.tsx +2 -1
- package/src/Table/plugins/rowStatus/index.ts +1 -4
- package/src/Table/plugins/rowStatus/useTableRowStatus.public.test.ts +92 -0
- package/src/Table/plugins/rowStatus/useTableRowStatus.spec.md +354 -0
- package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +431 -56
- package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +155 -84
- package/src/Table/plugins/sortable/useTableSortable.test.tsx +72 -0
- package/src/Table/plugins/sortable/useTableSortable.tsx +18 -1
- package/src/Table/useTableGroupedRows.doc.mjs +2 -2
- package/src/Table/useTableRowStatus.doc.mjs +5 -5
- package/src/Text/Text.doc.mjs +190 -43
- package/src/Text/Text.spec.md +206 -0
- package/src/Text/useTruncation.ts +8 -7
- package/src/TextArea/TextArea.doc.mjs +255 -45
- package/src/TextArea/TextArea.spec.md +205 -0
- package/src/TimeInput/NativeTimeInput.test.tsx +269 -0
- package/src/TimeInput/TimeInput.doc.mjs +47 -23
- package/src/TimeInput/TimeInput.tsx +109 -50
- package/src/TimeInput/index.ts +1 -0
- package/src/Timestamp/Timestamp.doc.mjs +2 -2
- package/src/Timestamp/Timestamp.test.tsx +75 -3
- package/src/Timestamp/Timestamp.tsx +7 -153
- package/src/Timestamp/formatRelativeTime.ts +96 -0
- package/src/Toast/ToastViewport.test.tsx +194 -0
- package/src/Toast/ToastViewport.tsx +136 -58
- package/src/ToggleButton/ToggleButton.doc.mjs +56 -0
- package/src/Tokenizer/Tokenizer.doc.mjs +2 -0
- package/src/Tokenizer/Tokenizer.spec.md +293 -0
- package/src/Tokenizer/Tokenizer.test.tsx +335 -1
- package/src/Tokenizer/Tokenizer.tsx +129 -46
- package/src/Tokenizer/useEndLaneReserve.ts +146 -0
- package/src/Toolbar/Toolbar.doc.mjs +19 -0
- package/src/Toolbar/Toolbar.spec.md +174 -0
- package/src/Tooltip/Tooltip.doc.mjs +17 -0
- package/src/Tooltip/Tooltip.spec.md +142 -0
- package/src/Tooltip/Tooltip.test.tsx +21 -1
- package/src/Tooltip/useTooltip.test.tsx +318 -0
- package/src/Tooltip/useTooltip.tsx +60 -39
- package/src/TreeList/TreeList.doc.mjs +58 -0
- package/src/TreeList/TreeList.spec.md +224 -0
- package/src/Typeahead/BaseTypeahead.tsx +96 -25
- package/src/Typeahead/Typeahead.doc.mjs +89 -1
- package/src/Typeahead/Typeahead.spec.md +257 -0
- package/src/Typeahead/Typeahead.test.tsx +502 -1
- package/src/Typeahead/Typeahead.tsx +187 -69
- package/src/Typeahead/TypeaheadItem.test.tsx +93 -2
- package/src/Typeahead/busyIndicatorLane.tsx +109 -0
- package/src/__tests__/stylexDeclarations.ts +51 -0
- package/src/hooks/useFocusReturnVisibility.ts +3 -5
- package/src/hooks/useOverflow.ts +11 -11
- package/src/hooks/useScrollLock.test.ts +103 -0
- package/src/hooks/useScrollOverflow.ts +7 -4
- package/src/i18n/useTranslator.test.tsx +197 -0
- package/src/theme/defineTheme.test.ts +227 -0
- package/src/theme/defineTheme.ts +30 -0
- package/src/theme/derivedVarRegistry.test.ts +6 -0
- package/src/theme/generateThemeRules.ts +4 -1
- package/src/theme/localTokens.ts +272 -0
- package/src/theme/themingTargets.test.ts +126 -28
- package/src/utils/interactionModality.test.ts +83 -0
- package/src/utils/interactionModality.ts +88 -36
- package/src/utils/sharedResizeObserver.test.ts +124 -5
- package/src/utils/sharedResizeObserver.ts +60 -14
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 3
|
|
3
|
+
template_version: 3
|
|
4
|
+
kind: component
|
|
5
|
+
id: component:Resizable
|
|
6
|
+
authority: draft
|
|
7
|
+
archive_reason: null
|
|
8
|
+
superseded_by: null
|
|
9
|
+
approved_by: null
|
|
10
|
+
approved_at: null
|
|
11
|
+
owners: [cixzhang]
|
|
12
|
+
review_triggers: [behavior, layout, theming, accessibility]
|
|
13
|
+
verified_by:
|
|
14
|
+
[
|
|
15
|
+
packages/core/src/Resizable/ResizeHandle.test.tsx,
|
|
16
|
+
packages/core/src/Resizable/useResizable.test.ts,
|
|
17
|
+
packages/core/src/Resizable/shippedDirections.test.ts,
|
|
18
|
+
packages/core/src/Resizable/utils.test.ts,
|
|
19
|
+
packages/core/src/theme/themingTargets.test.ts,
|
|
20
|
+
scripts/check-knowledge.mjs,
|
|
21
|
+
]
|
|
22
|
+
modules: []
|
|
23
|
+
families: []
|
|
24
|
+
design_specs: []
|
|
25
|
+
architecture:
|
|
26
|
+
[
|
|
27
|
+
architecture:component-theming-surface,
|
|
28
|
+
architecture:interaction-modality,
|
|
29
|
+
architecture:public-component-api,
|
|
30
|
+
]
|
|
31
|
+
contributing: []
|
|
32
|
+
system_specs: [spec:AST-010]
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
# Resizable component contract
|
|
36
|
+
|
|
37
|
+
## Intent
|
|
38
|
+
|
|
39
|
+
Resizable combines the useResizable state and behavior hook with a focusable
|
|
40
|
+
ResizeHandle. The handle presents a default Grip pill over an enlarged invisible
|
|
41
|
+
Grab zone. AST-010 adds explicit pixel and percentage configuration while keeping
|
|
42
|
+
selected state, persistence, callbacks, paint, and ARIA in resolved pixels.
|
|
43
|
+
|
|
44
|
+
## Compatibility and migration
|
|
45
|
+
|
|
46
|
+
- Released default preserved: `yes`; numeric and exact `Npx` stay pixels, exact
|
|
47
|
+
`N%` retains released one-time default behavior, and the broad `defaultSize`
|
|
48
|
+
string type remains source-compatible
|
|
49
|
+
- Compatibility class: additive `minSize` / `maxSize`, structured percentage helper,
|
|
50
|
+
and optional container basis; deprecated pixel aliases remain supported
|
|
51
|
+
- Controlled/uncontrolled behavior: unchanged
|
|
52
|
+
- Migration decision: CSS-like `min()` / `max()` strings are not supported. Use
|
|
53
|
+
`percent(value, {min: pixel(value)})` or
|
|
54
|
+
`percent(value, {max: pixel(value)})`.
|
|
55
|
+
|
|
56
|
+
Consumer migration instructions belong in consumer docs and release notes.
|
|
57
|
+
|
|
58
|
+
## Ownership boundary
|
|
59
|
+
|
|
60
|
+
**Owns**
|
|
61
|
+
|
|
62
|
+
- useResizable size, collapse, snapping, persistence, and resize lifecycle.
|
|
63
|
+
- ResizeHandle's separator semantics, pointer and keyboard interaction, and
|
|
64
|
+
current `resize-handle` target.
|
|
65
|
+
- The default Grip pill and its current `resize-handle-pill` target, plus the
|
|
66
|
+
aligned invisible Grab zone.
|
|
67
|
+
|
|
68
|
+
**Does not own / non-goals**
|
|
69
|
+
|
|
70
|
+
- The structural region being resized — owned by LayoutPanel, SideNav, or another
|
|
71
|
+
caller.
|
|
72
|
+
- Layout-region topology, inset, divider, or scrolling rules.
|
|
73
|
+
- A public target for the Grab zone; none exists on current `main`.
|
|
74
|
+
- Fixing the missing runtime reflection for the documented Handle `direction`
|
|
75
|
+
theming state; that remains a separate theming follow-up.
|
|
76
|
+
|
|
77
|
+
## Public concepts
|
|
78
|
+
|
|
79
|
+
`ResizableSize` is a Resizable-specific union: pixel number, exact `Npx`, exact
|
|
80
|
+
`N%`, `PixelWidth`, or `ResizablePercentSize`.
|
|
81
|
+
`pixel(value)` is Table's existing canonical structured pixel helper;
|
|
82
|
+
`percent(value, {min: pixel(value)})` creates a literal percentage with a pixel
|
|
83
|
+
floor; `percent(value, {max: pixel(value)})` creates one with a pixel ceiling.
|
|
84
|
+
The options argument is required and the two bounds are mutually exclusive.
|
|
85
|
+
`defaultSize` retains its released broad `SizeValue` type and adds the structured
|
|
86
|
+
`PixelWidth` and `ResizablePercentSize` values; runtime validation remains
|
|
87
|
+
authoritative for legacy strings.
|
|
88
|
+
|
|
89
|
+
Numbers and exact `Npx` remain pixels. A descriptor default resolves once; a
|
|
90
|
+
descriptor bound remains live. Consumer props, outputs, and examples are documented
|
|
91
|
+
in `Resizable.doc.mjs` and `useResizable.doc.mjs`.
|
|
92
|
+
|
|
93
|
+
## Behavioral and layout contract
|
|
94
|
+
|
|
95
|
+
| ID | Candidate invariant | Basis | Draft review state |
|
|
96
|
+
| --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------- |
|
|
97
|
+
| FR1 | ResizeHandle renders one focusable Handle and one enlarged Grab zone; the default render also contains a Grip pill, while caller-provided children replace that pill. | Current source, docs, and tests | Verified current behavior; no new behavior decided |
|
|
98
|
+
| FR2 | Handle carries `resize-handle`, Grip pill carries `resize-handle-pill`, and Grab zone carries no public target. | Current source and public docs | Verified current target inventory; no target change |
|
|
99
|
+
| FR3 | Pointer, keyboard, collapse, snap, persistence, reversal, and size behavior remain owned by ResizeHandle and useResizable rather than layout-regions collaborators. | Current source, docs, and tests | Verified current ownership; resize semantics remain unchanged |
|
|
100
|
+
| FR4 | Resizable metadata advertises `direction` as a Handle visual state, but current runtime calls `themeProps('resize-handle')` without reflecting that value, so direction selectors cannot match. | Current source and public docs | Verified audit gap; deliberately not fixed in this change |
|
|
101
|
+
| FR5 | `percent(value, {min: pixel(value)})` and `percent(value, {max: pixel(value)})` resolve against the AST-010 basis; a default selects pixels once, while a bound re-resolves and clamps selected pixels. Both/neither bounds are invalid. | AST-010, source, tests, Chromium | New structured sizing behavior; selected state remains pixels |
|
|
102
|
+
| FR6 | Deprecated pixel aliases remain source-compatible and mutually exclusive with unified bounds; untyped exact atomic strings keep their released runtime behavior, and untyped conflicts prefer the unified value and warn. | AST-010, source, tests | Additive migration with deterministic precedence |
|
|
103
|
+
|
|
104
|
+
### Allowed variation
|
|
105
|
+
|
|
106
|
+
- **AV1 — Axis.** Handle may resize along the horizontal or vertical layout axis;
|
|
107
|
+
separator orientation and cursor follow the current implementation.
|
|
108
|
+
- **AV2 — Placement.** Handle may participate inline or overlay its parent, and
|
|
109
|
+
Grip pill may sit at start, end, center, or the current automatic side.
|
|
110
|
+
- **AV3 — Grip content.** Caller-provided children may replace Grip pill without
|
|
111
|
+
changing Handle or Grab zone ownership.
|
|
112
|
+
- **AV4 — Divider.** Handle may paint its current divider treatment; a composing
|
|
113
|
+
region remains responsible for avoiding a duplicate adjacent divider.
|
|
114
|
+
- **AV5 — Structured percentage bound.** A descriptor carries exactly one `min`
|
|
115
|
+
or `max`, whose value is a `PixelWidth`. Atomic percentages use the existing
|
|
116
|
+
exact `N%` string; arbitrary CSS expressions are outside this contract.
|
|
117
|
+
|
|
118
|
+
### Representative states
|
|
119
|
+
|
|
120
|
+
| State | Required invariant | Allowed variation |
|
|
121
|
+
| ---------------------- | --------------------------------------------------------------------- | -------------------------------------------------- |
|
|
122
|
+
| Default handle | Handle, Grab zone, and Grip pill render. | Divider and always-visible treatment may vary. |
|
|
123
|
+
| Custom handle content | Handle and Grab zone remain; caller content replaces Grip pill. | Caller content remains caller-owned. |
|
|
124
|
+
| Horizontal or vertical | Interaction follows the selected axis and current ARIA orientation. | Size, reversal, and pill placement may vary. |
|
|
125
|
+
| Collapsed or expanded | Handle preserves valid separator value semantics and resize controls. | Grip pill automatic side follows current behavior. |
|
|
126
|
+
| Disabled | Handle remains represented but is removed from interactive tab order. | Painted treatment follows existing styles. |
|
|
127
|
+
|
|
128
|
+
### Transformation and precedence order
|
|
129
|
+
|
|
130
|
+
- Parse atomic strings exactly; validate `percent()` descriptors as a finite 0–100
|
|
131
|
+
percentage with exactly one finite non-negative pixel bound.
|
|
132
|
+
- Resolve percentages against one active basis, then apply the descriptor's floor or
|
|
133
|
+
ceiling.
|
|
134
|
+
- Commit a structured default as one initial pixel choice; keep percentage bounds
|
|
135
|
+
live and clamp with `Math.min(max, Math.max(min, size))`.
|
|
136
|
+
- Maximum wins when resolved bounds conflict; interaction and persistence stay
|
|
137
|
+
pixel-only.
|
|
138
|
+
|
|
139
|
+
### Performance and resources
|
|
140
|
+
|
|
141
|
+
- Atomic pixel paths add no observer or render work.
|
|
142
|
+
- A structured default observes a supplied container only until its initial pixel
|
|
143
|
+
choice is final; persisted pixels skip that measurement.
|
|
144
|
+
- Percentage bounds reuse the shared ResizeObserver and remain subscribed while
|
|
145
|
+
live. Structured validation and resolution are constant-time; no CSS parser is
|
|
146
|
+
introduced.
|
|
147
|
+
|
|
148
|
+
## Accessibility contract
|
|
149
|
+
|
|
150
|
+
The structured API does not change ResizeHandle's separator role, label,
|
|
151
|
+
orientation, collapsed value text, focus, pointer, or keyboard behavior. Its
|
|
152
|
+
`aria-valuemin`, `aria-valuemax`, and `aria-valuenow` remain the same resolved pixel
|
|
153
|
+
values used by hook state and painted geometry.
|
|
154
|
+
|
|
155
|
+
## Design relationships
|
|
156
|
+
|
|
157
|
+
| Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
|
|
158
|
+
| ---------------- | ----------------------------------------------------------------------- | ------------------------------ | -------------- | ------------------ |
|
|
159
|
+
| Handle | Presents the focusable resize separator and optional divider treatment. | Current source and public docs | Prominent | FR1, FR2, FR3 |
|
|
160
|
+
| Grip pill | Presents the default visible resize affordance. | Current source and public docs | Supporting | FR1, FR2 |
|
|
161
|
+
| Grab zone | Enlarges pointer reach while remaining visually transparent. | Current source and tests | Supporting | FR1, FR2 |
|
|
162
|
+
| Direction state | Selects horizontal or vertical resize presentation. | Current public metadata | Supporting | FR3, FR4 |
|
|
163
|
+
|
|
164
|
+
Grab zone is interaction structure rather than a painted public theming seam. Its
|
|
165
|
+
`none` disposition records factual reachability. The missing Handle direction
|
|
166
|
+
reflection is a separate current audit gap: the target exists, but runtime does
|
|
167
|
+
not emit the documented target state.
|
|
168
|
+
|
|
169
|
+
### Theming anatomy
|
|
170
|
+
|
|
171
|
+
<!-- anatomy-theming:v1 -->
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"Handle": {"target": "resize-handle"},
|
|
176
|
+
"Grip pill": {"target": "resize-handle-pill"},
|
|
177
|
+
"Grab zone": {
|
|
178
|
+
"none": {
|
|
179
|
+
"reason": "intentional: The invisible pointer hit area is nonvisual interaction structure and has no public target"
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Family and system relationships
|
|
186
|
+
|
|
187
|
+
- `architecture:component-theming-surface` owns anatomy qualification, target
|
|
188
|
+
mapping, and target-state reflection requirements.
|
|
189
|
+
- `architecture:interaction-modality` owns shared modality behavior;
|
|
190
|
+
`architecture:public-component-api` owns the additive structured API and
|
|
191
|
+
compatibility boundary.
|
|
192
|
+
- `Resizable/utils` is server-safe and re-exports Table's exact `pixel()` binding
|
|
193
|
+
plus `PixelWidth`, alongside Resizable's `percent()` and structured types.
|
|
194
|
+
- `family:layout-regions` lists useResizable and ResizeHandle as collaborators
|
|
195
|
+
that may drive a LayoutPanel's size. Resizable is not a layout-regions member,
|
|
196
|
+
and that family does not own or redefine resize state, snapping, persistence,
|
|
197
|
+
collapse, pointer, or keyboard semantics.
|
|
198
|
+
|
|
199
|
+
## Verification map
|
|
200
|
+
|
|
201
|
+
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
202
|
+
| ------------------- | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- |
|
|
203
|
+
| FR1 | `ResizeHandle.test.tsx` plus source inspection | Default, custom, collapsed, disabled, both axes | Handle and Grab zone regressions fail focused tests; custom Grip replacement currently relies on source review. | `audit:Resizable/anatomy` |
|
|
204
|
+
| FR2 | Source inspection and `themingTargets.test.ts` | Handle, Grip pill, and Grab zone | Removing a target or documenting an unshipped Grab zone target fails evidence or inventory. | `audit:Resizable/theming` |
|
|
205
|
+
| FR3 | `ResizeHandle.test.tsx` and `useResizable.test.ts` | Pointer, keyboard, snap, collapse, persistence | Moving resize ownership or changing current transformations fails focused behavior coverage. | `audit:Resizable/behavior` |
|
|
206
|
+
| FR4 | Source and public metadata comparison | Horizontal and vertical Handle | No current test detects that documented `direction` is absent from runtime target-state reflection. | `audit:Resizable/theming` |
|
|
207
|
+
| FR5 | Hook/utils tests, typecheck, and Chromium | Canonical floor/ceiling/default; invalid XOR shape; SSR/hydration; basis changes; numeric `containerRef` parity | Wrong resolution, rescaling defaults, stale clamps, observer leaks, extra numeric renders/ref reads, or state/paint/storage/ARIA divergence fails. | `audit:Resizable/behavior` |
|
|
208
|
+
| FR6 | Hook type/runtime tests | Old-only aliases; untyped exact atomic strings; typed and untyped conflicts | Alias incompatibility, ambiguous config, or wrong precedence fails focused tests. | `audit:Resizable/behavior` |
|
|
209
|
+
| Theming anatomy map | `scripts/check-knowledge.mjs` | Canonical anatomy and two current targets | Missing, extra, prefixed, stale, or multiply assigned mappings fail repository validation. | `audit:Resizable/theming` |
|
|
210
|
+
|
|
211
|
+
Current tests exercise Handle and Grab zone structure and behavior but do not
|
|
212
|
+
render `children` to prove that custom content replaces Grip pill. That branch is
|
|
213
|
+
source-inspected and lacks focused regression evidence. The documented
|
|
214
|
+
`direction` visual axis is a closed union, so `extensibleAxes.test.ts` does not
|
|
215
|
+
cover its missing runtime reflection; that mismatch is currently unguarded.
|
|
216
|
+
|
|
217
|
+
## Decision log
|
|
218
|
+
|
|
219
|
+
### Structured percentages use a Table-style helper
|
|
220
|
+
|
|
221
|
+
**Decision:** `percent(value, {min: pixel(value)})` or
|
|
222
|
+
`percent(value, {max: pixel(value)})` represents a percentage with exactly one
|
|
223
|
+
pixel bound. Reuse Table's exact `pixel()` binding and `PixelWidth`; do not create
|
|
224
|
+
a parallel static helper. The required options and XOR type avoid a second
|
|
225
|
+
spelling for plain percentages and make every supported combination explicit.
|
|
226
|
+
The pure helper is available with the same `pixel()` binding from the server-safe
|
|
227
|
+
`Resizable/utils` subpath, matching Table's established helper/export pattern.
|
|
228
|
+
`proportional()` is deliberately not reused because it means sibling weight, not a
|
|
229
|
+
literal percentage.
|
|
230
|
+
|
|
231
|
+
**Rejected:** parsing recursive CSS `min()` / `max()` strings. That would create a
|
|
232
|
+
partial second CSS implementation without a demonstrated need for arbitrary
|
|
233
|
+
composition.
|
|
234
|
+
|
|
235
|
+
## Open questions
|
|
236
|
+
|
|
237
|
+
- **OQ1 — Which follow-up should add and verify the missing Handle `direction`
|
|
238
|
+
target-state reflection?** (`checkable`)
|
|
239
|
+
- **OQ2 — Which focused test should pin custom content replacing Grip pill?**
|
|
240
|
+
(`checkable`)
|
|
241
|
+
|
|
242
|
+
## Content boundary
|
|
243
|
+
|
|
244
|
+
This file does not duplicate consumer prop tables/examples, resize algorithms,
|
|
245
|
+
layout-region rules, current audit results, or implementation steps. It links to
|
|
246
|
+
their owners.
|
|
@@ -44,6 +44,27 @@ function getSeparator(): HTMLElement {
|
|
|
44
44
|
return screen.getByRole('separator');
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
function getHitArea(): HTMLElement {
|
|
48
|
+
return getSeparator().firstElementChild as HTMLElement;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Stub region props, so drag assertions read the calls directly. */
|
|
52
|
+
function makeResizable(): ResizableProps {
|
|
53
|
+
return {
|
|
54
|
+
_size: 200,
|
|
55
|
+
_isCollapsed: false,
|
|
56
|
+
_onResizeStart: vi.fn(),
|
|
57
|
+
_onResizeMove: vi.fn(),
|
|
58
|
+
_onResizeEnd: vi.fn(),
|
|
59
|
+
_minSizePx: 100,
|
|
60
|
+
_maxSizePx: 400,
|
|
61
|
+
_snaps: [],
|
|
62
|
+
_collapsedSize: 40,
|
|
63
|
+
_collapsible: false,
|
|
64
|
+
_isResizableProps: true,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
47
68
|
describe('ResizeHandle', () => {
|
|
48
69
|
// --- ARIA wiring ---
|
|
49
70
|
|
|
@@ -120,7 +141,12 @@ describe('ResizeHandle', () => {
|
|
|
120
141
|
it('resizes along the block axis for a vertical handle', () => {
|
|
121
142
|
render(
|
|
122
143
|
<Harness
|
|
123
|
-
config={{
|
|
144
|
+
config={{
|
|
145
|
+
defaultSize: 200,
|
|
146
|
+
minSizePx: 100,
|
|
147
|
+
maxSizePx: 400,
|
|
148
|
+
direction: 'vertical',
|
|
149
|
+
}}
|
|
124
150
|
handleProps={{direction: 'vertical'}}
|
|
125
151
|
/>,
|
|
126
152
|
);
|
|
@@ -136,6 +162,25 @@ describe('ResizeHandle', () => {
|
|
|
136
162
|
expect(separator).toHaveAttribute('aria-valuenow', '200');
|
|
137
163
|
});
|
|
138
164
|
|
|
165
|
+
it('warns when the handle and hook use different axes', () => {
|
|
166
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
167
|
+
render(
|
|
168
|
+
<Harness
|
|
169
|
+
config={{
|
|
170
|
+
defaultSize: 200,
|
|
171
|
+
direction: 'vertical',
|
|
172
|
+
}}
|
|
173
|
+
handleProps={{direction: 'horizontal'}}
|
|
174
|
+
/>,
|
|
175
|
+
);
|
|
176
|
+
expect(warn).toHaveBeenCalledWith(
|
|
177
|
+
'ResizeHandle: direction="horizontal" but its useResizable region is ' +
|
|
178
|
+
'"vertical". They must match: the hook measures one axis and the ' +
|
|
179
|
+
'handle drags the other.',
|
|
180
|
+
);
|
|
181
|
+
warn.mockRestore();
|
|
182
|
+
});
|
|
183
|
+
|
|
139
184
|
it('collapses on Enter when the region is collapsible', () => {
|
|
140
185
|
render(
|
|
141
186
|
<Harness
|
|
@@ -213,37 +258,128 @@ describe('ResizeHandle', () => {
|
|
|
213
258
|
|
|
214
259
|
// --- Drag listener lifecycle ---
|
|
215
260
|
|
|
216
|
-
it('
|
|
217
|
-
const resizable
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
261
|
+
it('takes pointer capture on the grab zone when a drag starts', () => {
|
|
262
|
+
const resizable = makeResizable();
|
|
263
|
+
render(<ResizeHandle resizable={resizable} label="Resize" />);
|
|
264
|
+
const hitArea = getHitArea();
|
|
265
|
+
const setPointerCapture = vi.fn();
|
|
266
|
+
Object.defineProperty(hitArea, 'setPointerCapture', {
|
|
267
|
+
value: setPointerCapture,
|
|
268
|
+
configurable: true,
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
fireEvent.pointerDown(hitArea, {pointerId: 7, clientX: 0, clientY: 0});
|
|
272
|
+
// Capture keeps the rest of the gesture on this element, so an embedded
|
|
273
|
+
// frame under the cursor can't swallow the drag into its own document.
|
|
274
|
+
expect(setPointerCapture).toHaveBeenCalledWith(7);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('drives and ends the drag from events on the grab zone', () => {
|
|
278
|
+
const resizable = makeResizable();
|
|
279
|
+
render(<ResizeHandle resizable={resizable} label="Resize" />);
|
|
280
|
+
const hitArea = getHitArea();
|
|
281
|
+
|
|
282
|
+
fireEvent.pointerDown(hitArea, {pointerId: 1, clientX: 0, clientY: 0});
|
|
283
|
+
fireEvent.pointerMove(hitArea, {pointerId: 1, clientX: 30, clientY: 0});
|
|
284
|
+
expect(resizable._onResizeMove).toHaveBeenLastCalledWith(30);
|
|
285
|
+
fireEvent.pointerUp(hitArea, {pointerId: 1, clientX: 30, clientY: 0});
|
|
286
|
+
expect(resizable._onResizeEnd).toHaveBeenCalledTimes(1);
|
|
287
|
+
|
|
288
|
+
// The drag is over: a later move must not resize anything.
|
|
289
|
+
fireEvent.pointerMove(hitArea, {pointerId: 1, clientX: 90, clientY: 0});
|
|
290
|
+
expect(resizable._onResizeMove).toHaveBeenCalledTimes(1);
|
|
291
|
+
expect(document.body.style.cursor).toBe('');
|
|
292
|
+
expect(document.body.style.userSelect).toBe('');
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('ignores moves from a pointer that does not own the drag', () => {
|
|
296
|
+
const resizable = makeResizable();
|
|
297
|
+
render(<ResizeHandle resizable={resizable} label="Resize" />);
|
|
298
|
+
const hitArea = getHitArea();
|
|
299
|
+
|
|
300
|
+
fireEvent.pointerDown(hitArea, {pointerId: 1, clientX: 0, clientY: 0});
|
|
301
|
+
fireEvent.pointerMove(hitArea, {pointerId: 2, clientX: 30, clientY: 0});
|
|
302
|
+
expect(resizable._onResizeMove).not.toHaveBeenCalled();
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it.each([
|
|
306
|
+
['pointercancel', fireEvent.pointerCancel],
|
|
307
|
+
['lostpointercapture', fireEvent.lostPointerCapture],
|
|
308
|
+
])('ends the drag on %s without signalling a resize end', (_name, fire) => {
|
|
309
|
+
const resizable = makeResizable();
|
|
310
|
+
render(<ResizeHandle resizable={resizable} label="Resize" />);
|
|
311
|
+
const hitArea = getHitArea();
|
|
312
|
+
|
|
313
|
+
fireEvent.pointerDown(hitArea, {pointerId: 1, clientX: 0, clientY: 0});
|
|
314
|
+
fire(hitArea, {pointerId: 1});
|
|
315
|
+
expect(resizable._onResizeEnd).not.toHaveBeenCalled();
|
|
316
|
+
expect(document.body.style.cursor).toBe('');
|
|
317
|
+
expect(document.body.style.userSelect).toBe('');
|
|
318
|
+
|
|
319
|
+
fireEvent.pointerMove(hitArea, {pointerId: 1, clientX: 30, clientY: 0});
|
|
320
|
+
expect(resizable._onResizeMove).not.toHaveBeenCalled();
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it.each([
|
|
324
|
+
['pointercancel', fireEvent.pointerCancel],
|
|
325
|
+
['lostpointercapture', fireEvent.lostPointerCapture],
|
|
326
|
+
])('tells the region the gesture is over on %s', (_name, fire) => {
|
|
327
|
+
// A cancelled drag is not a resize end, but it IS the end of the gesture:
|
|
328
|
+
// the region freezes its percentage basis for the duration of a drag, and
|
|
329
|
+
// without this it stays frozen at the container size from grab time.
|
|
330
|
+
const resizable = {...makeResizable(), _onResizeCancel: vi.fn()};
|
|
331
|
+
render(<ResizeHandle resizable={resizable} label="Resize" />);
|
|
332
|
+
const hitArea = getHitArea();
|
|
333
|
+
|
|
334
|
+
fireEvent.pointerDown(hitArea, {pointerId: 1, clientX: 0, clientY: 0});
|
|
335
|
+
fire(hitArea, {pointerId: 1});
|
|
336
|
+
expect(resizable._onResizeCancel).toHaveBeenCalledTimes(1);
|
|
337
|
+
expect(resizable._onResizeEnd).not.toHaveBeenCalled();
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('does not report a cancel for a drag that ended normally', () => {
|
|
341
|
+
const resizable = {...makeResizable(), _onResizeCancel: vi.fn()};
|
|
342
|
+
render(<ResizeHandle resizable={resizable} label="Resize" />);
|
|
343
|
+
const hitArea = getHitArea();
|
|
344
|
+
|
|
345
|
+
fireEvent.pointerDown(hitArea, {pointerId: 1, clientX: 0, clientY: 0});
|
|
346
|
+
fireEvent.pointerUp(hitArea, {pointerId: 1, clientX: 30, clientY: 0});
|
|
347
|
+
expect(resizable._onResizeEnd).toHaveBeenCalledTimes(1);
|
|
348
|
+
// lostpointercapture follows every release; the drag is already cleared.
|
|
349
|
+
fireEvent.lostPointerCapture(hitArea, {pointerId: 1});
|
|
350
|
+
expect(resizable._onResizeCancel).not.toHaveBeenCalled();
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('tells the region the gesture is over when unmounted mid-drag', () => {
|
|
354
|
+
// The region outlives the handle here, so nothing else would release it.
|
|
355
|
+
const resizable = {...makeResizable(), _onResizeCancel: vi.fn()};
|
|
230
356
|
const {unmount} = render(
|
|
231
357
|
<ResizeHandle resizable={resizable} label="Resize" />,
|
|
232
358
|
);
|
|
233
|
-
|
|
234
|
-
|
|
359
|
+
fireEvent.pointerDown(getHitArea(), {pointerId: 1, clientX: 0, clientY: 0});
|
|
360
|
+
unmount();
|
|
361
|
+
expect(resizable._onResizeCancel).toHaveBeenCalledTimes(1);
|
|
362
|
+
expect(resizable._onResizeEnd).not.toHaveBeenCalled();
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it('stops driving the region and releases body styles when unmounted mid-drag', () => {
|
|
366
|
+
const resizable = makeResizable();
|
|
367
|
+
const {unmount} = render(
|
|
368
|
+
<ResizeHandle resizable={resizable} label="Resize" />,
|
|
369
|
+
);
|
|
370
|
+
const hitArea = getHitArea();
|
|
235
371
|
|
|
236
372
|
// Start a drag and confirm moves reach the region.
|
|
237
|
-
fireEvent.pointerDown(hitArea, {clientX: 0, clientY: 0});
|
|
373
|
+
fireEvent.pointerDown(hitArea, {pointerId: 1, clientX: 0, clientY: 0});
|
|
238
374
|
expect(resizable._onResizeStart).toHaveBeenCalledTimes(1);
|
|
239
|
-
fireEvent.pointerMove(
|
|
375
|
+
fireEvent.pointerMove(hitArea, {pointerId: 1, clientX: 10, clientY: 0});
|
|
240
376
|
expect(resizable._onResizeMove).toHaveBeenCalledTimes(1);
|
|
241
377
|
|
|
242
|
-
//
|
|
243
|
-
// pointer
|
|
244
|
-
//
|
|
378
|
+
// Unmounting removes the capturing element, which implicitly releases the
|
|
379
|
+
// pointer and takes its listeners with it. The body cursor/user-select
|
|
380
|
+
// overrides live outside the element, so they must be released here.
|
|
245
381
|
unmount();
|
|
246
|
-
fireEvent.pointerMove(
|
|
382
|
+
fireEvent.pointerMove(hitArea, {pointerId: 1, clientX: 50, clientY: 0});
|
|
247
383
|
expect(resizable._onResizeMove).toHaveBeenCalledTimes(1);
|
|
248
384
|
expect(document.body.style.cursor).toBe('');
|
|
249
385
|
expect(document.body.style.userSelect).toBe('');
|
|
@@ -252,43 +388,18 @@ describe('ResizeHandle', () => {
|
|
|
252
388
|
// --- RTL pointer-drag direction ---
|
|
253
389
|
|
|
254
390
|
it('drives the region with the raw pointer delta under LTR', () => {
|
|
255
|
-
const resizable
|
|
256
|
-
_size: 200,
|
|
257
|
-
_isCollapsed: false,
|
|
258
|
-
_onResizeStart: vi.fn(),
|
|
259
|
-
_onResizeMove: vi.fn(),
|
|
260
|
-
_onResizeEnd: vi.fn(),
|
|
261
|
-
_minSizePx: 100,
|
|
262
|
-
_maxSizePx: 400,
|
|
263
|
-
_snaps: [],
|
|
264
|
-
_collapsedSize: 40,
|
|
265
|
-
_collapsible: false,
|
|
266
|
-
_isResizableProps: true,
|
|
267
|
-
};
|
|
391
|
+
const resizable = makeResizable();
|
|
268
392
|
render(<ResizeHandle resizable={resizable} label="Resize" />);
|
|
269
|
-
const hitArea =
|
|
270
|
-
.firstElementChild as HTMLElement;
|
|
393
|
+
const hitArea = getHitArea();
|
|
271
394
|
|
|
272
|
-
fireEvent.pointerDown(hitArea, {clientX: 0, clientY: 0});
|
|
395
|
+
fireEvent.pointerDown(hitArea, {pointerId: 1, clientX: 0, clientY: 0});
|
|
273
396
|
// Pointer moves +40px to the right → panel grows by +40 under LTR.
|
|
274
|
-
fireEvent.pointerMove(
|
|
397
|
+
fireEvent.pointerMove(hitArea, {pointerId: 1, clientX: 40, clientY: 0});
|
|
275
398
|
expect(resizable._onResizeMove).toHaveBeenLastCalledWith(40);
|
|
276
399
|
});
|
|
277
400
|
|
|
278
401
|
it('inverts the pointer delta under RTL so dragging resizes intuitively', () => {
|
|
279
|
-
const resizable
|
|
280
|
-
_size: 200,
|
|
281
|
-
_isCollapsed: false,
|
|
282
|
-
_onResizeStart: vi.fn(),
|
|
283
|
-
_onResizeMove: vi.fn(),
|
|
284
|
-
_onResizeEnd: vi.fn(),
|
|
285
|
-
_minSizePx: 100,
|
|
286
|
-
_maxSizePx: 400,
|
|
287
|
-
_snaps: [],
|
|
288
|
-
_collapsedSize: 40,
|
|
289
|
-
_collapsible: false,
|
|
290
|
-
_isResizableProps: true,
|
|
291
|
-
};
|
|
402
|
+
const resizable = makeResizable();
|
|
292
403
|
// Under RTL the start panel sits on the RIGHT, so a pointer move to the
|
|
293
404
|
// right (+clientX) must SHRINK it — the delta is inverted. The handle reads
|
|
294
405
|
// its own computed `direction` via getRTLMultiplier(); jsdom doesn't resolve
|
|
@@ -308,9 +419,9 @@ describe('ResizeHandle', () => {
|
|
|
308
419
|
return realGetComputedStyle(el, pseudo ?? undefined);
|
|
309
420
|
});
|
|
310
421
|
|
|
311
|
-
fireEvent.pointerDown(hitArea, {clientX: 0, clientY: 0});
|
|
422
|
+
fireEvent.pointerDown(hitArea, {pointerId: 1, clientX: 0, clientY: 0});
|
|
312
423
|
// Same +40px physical move as LTR, but mirrored → −40 delta under RTL.
|
|
313
|
-
fireEvent.pointerMove(
|
|
424
|
+
fireEvent.pointerMove(hitArea, {pointerId: 1, clientX: 40, clientY: 0});
|
|
314
425
|
expect(resizable._onResizeMove).toHaveBeenLastCalledWith(-40);
|
|
315
426
|
|
|
316
427
|
gcsSpy.mockRestore();
|
|
@@ -352,7 +463,17 @@ describe('ResizeHandle', () => {
|
|
|
352
463
|
['horizontal' as const, 'translateX'],
|
|
353
464
|
['vertical' as const, 'translateY'],
|
|
354
465
|
])('offsets the %s grab zone along the pill axis only', (direction, axis) => {
|
|
355
|
-
render(
|
|
466
|
+
render(
|
|
467
|
+
<Harness
|
|
468
|
+
config={{
|
|
469
|
+
defaultSize: 200,
|
|
470
|
+
minSizePx: 100,
|
|
471
|
+
maxSizePx: 400,
|
|
472
|
+
direction,
|
|
473
|
+
}}
|
|
474
|
+
handleProps={{direction, pillPlacement: 'start'}}
|
|
475
|
+
/>,
|
|
476
|
+
);
|
|
356
477
|
const hitArea = getSeparator().firstElementChild as HTMLElement;
|
|
357
478
|
const translates = (hitArea.getAttribute('style') ?? '')
|
|
358
479
|
.split(';')
|