@astryxdesign/core 0.4.4 → 0.4.5-canary.013e728
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 +40 -0
- package/dist/AvatarGroup/AvatarGroupOverflow.js +1 -1
- package/dist/BottomSheet/BottomSheet.d.ts +11 -2
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +4 -0
- package/dist/BottomSheet/BottomSheetPanel.d.ts +5 -2
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +65 -15
- package/dist/BottomSheet/index.d.ts +1 -1
- package/dist/BottomSheet/index.d.ts.map +1 -1
- package/dist/BottomSheet/snapOffsets.d.ts +57 -20
- package/dist/BottomSheet/snapOffsets.d.ts.map +1 -1
- package/dist/BottomSheet/snapOffsets.js +106 -30
- package/dist/BottomSheet/useSheetGestures.d.ts +13 -8
- package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
- package/dist/BottomSheet/useSheetGestures.js +160 -64
- package/dist/Breadcrumbs/BreadcrumbItem.js +6 -6
- package/dist/Button/Button.js +5 -5
- package/dist/Calendar/Calendar.d.ts +17 -0
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +55 -15
- package/dist/Calendar/getStandaloneShortWeekdayNames.d.ts +14 -0
- package/dist/Calendar/getStandaloneShortWeekdayNames.d.ts.map +1 -0
- package/dist/Calendar/getStandaloneShortWeekdayNames.js +26 -0
- package/dist/Calendar/hooks/useCalendarConstraints.d.ts +22 -1
- package/dist/Calendar/hooks/useCalendarConstraints.d.ts.map +1 -1
- package/dist/Calendar/hooks/useCalendarConstraints.js +26 -4
- package/dist/Calendar/hooks/useCalendarDays.d.ts.map +1 -1
- package/dist/Calendar/hooks/useCalendarDays.js +14 -10
- package/dist/Calendar/hooks/useCalendarNavigation.d.ts.map +1 -1
- package/dist/Calendar/hooks/useCalendarNavigation.js +8 -4
- package/dist/Calendar/standaloneShortWeekdayNames.generated.d.ts +47 -0
- package/dist/Calendar/standaloneShortWeekdayNames.generated.d.ts.map +1 -0
- package/dist/Calendar/standaloneShortWeekdayNames.generated.js +40 -0
- package/dist/Calendar/styles.js +3 -3
- package/dist/Center/Center.d.ts +23 -1
- package/dist/Center/Center.d.ts.map +1 -1
- package/dist/Center/Center.js +12 -6
- package/dist/Chat/ChatComposer.d.ts.map +1 -1
- package/dist/Chat/ChatComposer.js +2 -2
- package/dist/Chat/ChatToolCalls.js +1 -1
- package/dist/Chat/useChatDictation.d.ts +1 -1
- package/dist/Chat/useChatDictation.d.ts.map +1 -1
- package/dist/Chat/useSpeechRecognition.d.ts +1 -1
- package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
- package/dist/Chat/useSpeechRecognition.js +4 -3
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +9 -0
- package/dist/Citation/Citation.js +3 -3
- package/dist/ClickableCard/ClickableCard.js +2 -2
- package/dist/CommandPalette/CommandPaletteItem.js +1 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +8 -3
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +17 -9
- package/dist/DateRangeInput/DateRangeInput.d.ts +23 -1
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +47 -9
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +18 -10
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +3 -3
- package/dist/Field/FieldLabel.d.ts +2 -1
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +21 -3
- package/dist/Field/InputClearButton.d.ts +2 -1
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +12 -1
- package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
- package/dist/Field/inputStyles.stylex.js +4 -4
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +2 -2
- package/dist/FormLayout/FormLayout.d.ts +24 -2
- package/dist/FormLayout/FormLayout.d.ts.map +1 -1
- package/dist/FormLayout/FormLayout.js +7 -2
- package/dist/FormLayout/FormLayoutContext.d.ts +15 -2
- package/dist/FormLayout/FormLayoutContext.d.ts.map +1 -1
- package/dist/FormLayout/FormLayoutContext.js +19 -4
- package/dist/FormLayout/index.d.ts +1 -1
- package/dist/FormLayout/index.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.d.ts +13 -3
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +2 -0
- package/dist/HoverCard/index.d.ts +1 -1
- package/dist/HoverCard/index.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.d.ts +17 -2
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +78 -9
- package/dist/Item/Item.d.ts +9 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +46 -8
- package/dist/Layer/index.d.ts +4 -2
- package/dist/Layer/index.d.ts.map +1 -1
- package/dist/Layer/index.js +2 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +3 -2
- package/dist/Layer/useTouchTrigger.d.ts +113 -0
- package/dist/Layer/useTouchTrigger.d.ts.map +1 -0
- package/dist/Layer/useTouchTrigger.js +241 -0
- package/dist/Layout/container.stylex.d.ts +4 -2
- package/dist/Layout/container.stylex.d.ts.map +1 -1
- package/dist/Layout/container.stylex.js +19 -11
- package/dist/Layout/index.d.ts +1 -0
- package/dist/Layout/index.d.ts.map +1 -1
- package/dist/Layout/index.js +4 -0
- package/dist/Layout/padding.stylex.d.ts +315 -12
- package/dist/Layout/padding.stylex.d.ts.map +1 -1
- package/dist/Layout/padding.stylex.js +389 -12
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +2 -1
- package/dist/Link/Link.js +4 -4
- package/dist/Markdown/Markdown.d.ts +8 -0
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +31 -3
- package/dist/Markdown/parser.d.ts +14 -2
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +50 -2
- package/dist/MobileNav/MobileNav.d.ts +1 -0
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +24 -6
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +8 -3
- package/dist/NavItem/navItemStyles.stylex.d.ts +2 -2
- package/dist/NavItem/navItemStyles.stylex.js +2 -2
- package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +38 -5
- package/dist/Outline/Outline.js +2 -2
- package/dist/Outline/parseOutlineFromMarkdown.d.ts +2 -0
- package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
- package/dist/Outline/parseOutlineFromMarkdown.js +5 -31
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +11 -12
- package/dist/PowerSearch/PowerSearchToken.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchToken.js +3 -1
- package/dist/PowerSearch/formatFilterValue.d.ts +11 -2
- package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
- package/dist/PowerSearch/formatFilterValue.js +23 -8
- package/dist/RadioList/RadioList.d.ts.map +1 -1
- package/dist/RadioList/RadioList.js +12 -1
- package/dist/RadioList/RadioListItem.d.ts +2 -2
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +68 -38
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +3 -3
- package/dist/Section/Section.d.ts +36 -1
- package/dist/Section/Section.d.ts.map +1 -1
- package/dist/Section/Section.js +12 -2
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +6 -1
- package/dist/SelectableCard/SelectableCard.js +1 -1
- package/dist/Selector/Selector.d.ts +26 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +95 -17
- package/dist/Selector/SelectorOption.d.ts +14 -1
- package/dist/Selector/SelectorOption.d.ts.map +1 -1
- package/dist/Selector/SelectorOption.js +6 -0
- package/dist/Selector/SelectorRowLayoutContext.d.ts +8 -0
- package/dist/Selector/SelectorRowLayoutContext.d.ts.map +1 -0
- package/dist/Selector/SelectorRowLayoutContext.js +27 -0
- package/dist/Selector/types.d.ts +1 -0
- package/dist/Selector/types.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +1 -1
- package/dist/SideNav/SideNavItem.js +1 -1
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +3 -3
- package/dist/Stack/Stack.d.ts +23 -1
- package/dist/Stack/Stack.d.ts.map +1 -1
- package/dist/Stack/Stack.js +12 -6
- package/dist/StatusDot/StatusDot.d.ts +43 -3
- package/dist/StatusDot/StatusDot.d.ts.map +1 -1
- package/dist/StatusDot/StatusDot.js +42 -5
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +9 -0
- package/dist/TabList/TabMenu.js +1 -1
- package/dist/Table/TableRow.js +4 -4
- package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
- package/dist/Table/plugins/columnResize/useTableColumnResize.js +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +7 -2
- package/dist/Table/plugins/sortable/useTableSortableState.d.ts +5 -3
- package/dist/Table/plugins/sortable/useTableSortableState.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortableState.js +12 -9
- package/dist/Table/plugins/tree/useTableTreeData.js +2 -2
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +6 -1
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +6 -1
- package/dist/Thumbnail/Thumbnail.js +1 -1
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +6 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +6 -4
- package/dist/Timestamp/formatInstant.d.ts +3 -2
- package/dist/Timestamp/formatInstant.d.ts.map +1 -1
- package/dist/Timestamp/formatInstant.js +8 -8
- package/dist/Timestamp/tooltipEntries.d.ts +2 -1
- package/dist/Timestamp/tooltipEntries.d.ts.map +1 -1
- package/dist/Timestamp/tooltipEntries.js +5 -3
- package/dist/Token/Token.js +1 -1
- package/dist/Tooltip/Tooltip.d.ts +16 -3
- package/dist/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip/Tooltip.js +2 -0
- package/dist/Tooltip/index.d.ts +1 -1
- package/dist/Tooltip/index.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.d.ts +21 -2
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +71 -13
- package/dist/TopNav/TopNavHeading.js +2 -2
- package/dist/TopNav/TopNavItem.js +2 -2
- package/dist/TopNav/TopNavMegaMenu.js +1 -1
- package/dist/TopNav/TopNavMegaMenuItem.js +1 -1
- package/dist/TopNav/TopNavMenu.js +2 -2
- package/dist/TreeList/TreeListItem.js +1 -1
- package/dist/astryx.css +85 -60
- package/dist/hooks/containerReveal.stylex.d.ts.map +1 -1
- package/dist/hooks/containerReveal.stylex.js +18 -18
- package/dist/hooks/scrollbarGutter.d.ts +28 -0
- package/dist/hooks/scrollbarGutter.d.ts.map +1 -0
- package/dist/hooks/scrollbarGutter.js +103 -0
- package/dist/hooks/useResolvedRequired.d.ts +19 -0
- package/dist/hooks/useResolvedRequired.d.ts.map +1 -0
- package/dist/hooks/useResolvedRequired.js +40 -0
- package/dist/hooks/useScrollLock.d.ts +4 -0
- package/dist/hooks/useScrollLock.d.ts.map +1 -1
- package/dist/hooks/useScrollLock.js +13 -1
- package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
- package/dist/i18n/InternationalizationContext.js +2 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +6 -0
- package/dist/i18n/useCollator.d.ts +12 -0
- package/dist/i18n/useCollator.d.ts.map +1 -0
- package/dist/i18n/useCollator.js +40 -0
- package/dist/i18n/useLocale.d.ts +3 -0
- package/dist/i18n/useLocale.d.ts.map +1 -0
- package/dist/i18n/useLocale.js +31 -0
- package/dist/theme/defineTheme.d.ts +5 -0
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +5 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +7 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +66 -5
- package/dist/utils/dateParser.d.ts +4 -3
- package/dist/utils/dateParser.d.ts.map +1 -1
- package/dist/utils/dateParser.js +8 -8
- package/dist/utils/plainDate.d.ts +9 -2
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +16 -4
- package/locales/af-ZA.json +958 -0
- package/locales/ar-SA.json +998 -0
- package/locales/ca-ES.json +974 -0
- package/locales/cs-CZ.json +990 -0
- package/locales/da-DK.json +966 -0
- package/locales/de-DE.json +966 -0
- package/locales/el-GR.json +990 -0
- package/locales/en.json +8 -0
- package/locales/es-ES.json +978 -0
- package/locales/fi-FI.json +990 -0
- package/locales/fr-FR.json +928 -0
- package/locales/he-IL.json +990 -0
- package/locales/hu-HU.json +990 -0
- package/locales/it-IT.json +978 -0
- package/locales/ja-JP.json +998 -0
- package/locales/ko-KR.json +990 -0
- package/locales/nl-NL.json +954 -0
- package/locales/no-NO.json +978 -0
- package/locales/pl-PL.json +982 -0
- package/locales/pseudo.json +6 -0
- package/locales/pt-BR.json +982 -0
- package/locales/pt-PT.json +982 -0
- package/locales/ro-RO.json +982 -0
- package/locales/ru-RU.json +990 -0
- package/locales/sr-SP.json +990 -0
- package/locales/sv-SE.json +986 -0
- package/locales/tr-TR.json +990 -0
- package/locales/uk-UA.json +990 -0
- package/locales/vi-VN.json +986 -0
- package/locales/zh-CN.json +998 -0
- package/locales/zh-TW.json +998 -0
- package/package.json +3 -3
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +1 -1
- package/src/Banner/Banner.doc.mjs +2 -0
- package/src/BottomSheet/BottomSheet.doc.mjs +36 -3
- package/src/BottomSheet/BottomSheet.test.tsx +177 -2
- package/src/BottomSheet/BottomSheet.tsx +16 -2
- package/src/BottomSheet/BottomSheetPanel.test.tsx +41 -0
- package/src/BottomSheet/BottomSheetPanel.tsx +95 -15
- package/src/BottomSheet/index.ts +5 -1
- package/src/BottomSheet/snapOffsets.test.ts +114 -47
- package/src/BottomSheet/snapOffsets.ts +119 -33
- package/src/BottomSheet/useSheetGestures.test.ts +113 -15
- package/src/BottomSheet/useSheetGestures.ts +196 -100
- package/src/Breadcrumbs/BreadcrumbItem.tsx +1 -1
- package/src/Button/Button.tsx +7 -7
- package/src/Calendar/Calendar.doc.mjs +16 -0
- package/src/Calendar/Calendar.test.tsx +137 -0
- package/src/Calendar/Calendar.tsx +80 -11
- package/src/Calendar/getStandaloneShortWeekdayNames.test.ts +54 -0
- package/src/Calendar/getStandaloneShortWeekdayNames.ts +38 -0
- package/src/Calendar/hooks/useCalendarConstraints.ts +54 -3
- package/src/Calendar/hooks/useCalendarDays.ts +13 -10
- package/src/Calendar/hooks/useCalendarNavigation.ts +6 -4
- package/src/Calendar/standaloneShortWeekdayNames.generated.ts +50 -0
- package/src/Calendar/styles.ts +3 -3
- package/src/Center/Center.doc.mjs +48 -0
- package/src/Center/Center.test.tsx +158 -0
- package/src/Center/Center.tsx +50 -9
- package/src/Chat/ChatComposer.tsx +7 -4
- package/src/Chat/ChatToolCalls.tsx +1 -1
- package/src/Chat/{useChatDictation.test.ts → useChatDictation.test.tsx} +29 -14
- package/src/Chat/useChatDictation.ts +1 -1
- package/src/Chat/useSpeechRecognition.ts +5 -3
- package/src/CheckboxInput/CheckboxInput.tsx +6 -0
- package/src/Citation/Citation.tsx +3 -3
- package/src/ClickableCard/ClickableCard.tsx +2 -2
- package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
- package/src/ComplexSelector/ComplexSelector.doc.mjs +10 -0
- package/src/ComplexSelector/ComplexSelector.tsx +8 -5
- package/src/DateInput/DateInput.test.tsx +17 -1
- package/src/DateInput/DateInput.tsx +13 -9
- package/src/DateRangeInput/DateRangeInput.doc.mjs +16 -0
- package/src/DateRangeInput/DateRangeInput.test.tsx +81 -1
- package/src/DateRangeInput/DateRangeInput.tsx +88 -8
- package/src/DateTimeInput/DateTimeInput.tsx +23 -8
- package/src/Dialog/Dialog.test.tsx +24 -0
- package/src/Dialog/Dialog.tsx +3 -0
- package/src/Field/Field.doc.mjs +3 -0
- package/src/Field/FieldLabel.tsx +20 -4
- package/src/Field/InputClearButton.test.tsx +134 -2
- package/src/Field/InputClearButton.tsx +42 -1
- package/src/Field/inputStyles.stylex.ts +16 -12
- package/src/FileInput/FileInput.tsx +5 -4
- package/src/FormLayout/FormLayout.doc.mjs +13 -0
- package/src/FormLayout/FormLayout.test.tsx +181 -4
- package/src/FormLayout/FormLayout.tsx +33 -2
- package/src/FormLayout/FormLayoutContext.ts +22 -7
- package/src/FormLayout/index.ts +1 -1
- package/src/HoverCard/HoverCard.doc.mjs +18 -0
- package/src/HoverCard/HoverCard.test.tsx +189 -0
- package/src/HoverCard/HoverCard.tsx +22 -2
- package/src/HoverCard/index.ts +1 -0
- package/src/HoverCard/useHoverCard.doc.mjs +2 -0
- package/src/HoverCard/useHoverCard.tsx +103 -7
- package/src/Item/Item.doc.mjs +1 -0
- package/src/Item/Item.test.tsx +50 -0
- package/src/Item/Item.tsx +41 -2
- package/src/Layer/index.ts +10 -0
- package/src/Layer/useLayer.tsx +13 -2
- package/src/Layer/useTouchTrigger.test.ts +70 -0
- package/src/Layer/useTouchTrigger.ts +366 -0
- package/src/Layout/Layout.doc.mjs +18 -0
- package/src/Layout/container.stylex.ts +11 -3
- package/src/Layout/index.ts +4 -0
- package/src/Layout/overlayPaddingReset.test.tsx +222 -0
- package/src/Layout/padding.stylex.ts +192 -12
- package/src/Lightbox/Lightbox.tsx +2 -1
- package/src/Link/Link.tsx +4 -4
- package/src/Markdown/Markdown.doc.mjs +3 -0
- package/src/Markdown/Markdown.test.tsx +78 -0
- package/src/Markdown/Markdown.tsx +41 -1
- package/src/Markdown/parser.ts +60 -2
- package/src/MobileNav/MobileNav.tsx +61 -5
- package/src/MobileNav/MobileNavEntryAnimation.test.tsx +212 -0
- package/src/MobileNav/MobileNavScrollbarGutter.test.tsx +109 -0
- package/src/MultiSelector/MultiSelector.test.tsx +1 -1
- package/src/MultiSelector/MultiSelector.tsx +8 -5
- package/src/NavItem/navItemStyles.stylex.ts +2 -2
- package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
- package/src/NumberInput/NumberInput.doc.mjs +24 -0
- package/src/NumberInput/NumberInput.test.tsx +138 -0
- package/src/NumberInput/NumberInput.tsx +44 -6
- package/src/Outline/Outline.doc.mjs +2 -0
- package/src/Outline/Outline.tsx +1 -1
- package/src/Outline/parseOutlineFromMarkdown.ts +10 -40
- package/src/PowerSearch/PowerSearch.tsx +17 -8
- package/src/PowerSearch/PowerSearchToken.tsx +3 -0
- package/src/PowerSearch/formatFilterValue.test.ts +22 -2
- package/src/PowerSearch/formatFilterValue.ts +31 -6
- package/src/RadioList/RadioList.doc.mjs +1 -1
- package/src/RadioList/RadioList.test.tsx +170 -2
- package/src/RadioList/RadioList.tsx +9 -1
- package/src/RadioList/RadioListItem.tsx +83 -51
- package/src/Resizable/ResizeHandle.test.tsx +22 -0
- package/src/Resizable/ResizeHandle.tsx +9 -3
- package/src/Section/Section.doc.mjs +55 -0
- package/src/Section/Section.test.tsx +201 -4
- package/src/Section/Section.tsx +69 -0
- package/src/SegmentedControl/SegmentedControl.test.tsx +31 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +11 -2
- package/src/SelectableCard/SelectableCard.tsx +1 -1
- package/src/Selector/Selector.doc.mjs +16 -2
- package/src/Selector/Selector.test.tsx +525 -1
- package/src/Selector/Selector.tsx +166 -21
- package/src/Selector/SelectorOption.doc.mjs +7 -0
- package/src/Selector/SelectorOption.tsx +21 -0
- package/src/Selector/SelectorRowLayoutContext.ts +32 -0
- package/src/Selector/types.ts +4 -4
- package/src/SideNav/SideNavHeading.tsx +2 -2
- package/src/SideNav/SideNavItem.tsx +1 -1
- package/src/Slider/Slider.tsx +11 -1
- package/src/Stack/Stack.doc.mjs +72 -0
- package/src/Stack/Stack.test.tsx +156 -0
- package/src/Stack/Stack.tsx +50 -8
- package/src/StatusDot/StatusDot.doc.mjs +13 -0
- package/src/StatusDot/StatusDot.test.tsx +115 -8
- package/src/StatusDot/StatusDot.tsx +74 -9
- package/src/Switch/Switch.tsx +6 -0
- package/src/TabList/TabMenu.tsx +1 -1
- package/src/Table/TableRow.tsx +4 -4
- package/src/Table/plugins/columnResize/useTableColumnResize.tsx +2 -1
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +2 -1
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +22 -4
- package/src/Table/plugins/sortable/useTableSortableState.test.tsx +34 -0
- package/src/Table/plugins/sortable/useTableSortableState.tsx +26 -23
- package/src/Table/plugins/tree/useTableTreeData.tsx +2 -2
- package/src/TextArea/TextArea.doc.mjs +1 -1
- package/src/TextArea/TextArea.tsx +3 -1
- package/src/TextInput/TextInput.tsx +3 -1
- package/src/Thumbnail/Thumbnail.tsx +1 -1
- package/src/TimeInput/TimeInput.tsx +3 -1
- package/src/Timestamp/Timestamp.test.tsx +27 -7
- package/src/Timestamp/Timestamp.tsx +8 -4
- package/src/Timestamp/formatInstant.ts +9 -7
- package/src/Timestamp/tooltipEntries.test.ts +11 -6
- package/src/Timestamp/tooltipEntries.ts +6 -2
- package/src/Token/Token.tsx +1 -1
- package/src/Tooltip/Tooltip.doc.mjs +18 -0
- package/src/Tooltip/Tooltip.test.tsx +254 -1
- package/src/Tooltip/Tooltip.tsx +22 -2
- package/src/Tooltip/index.ts +1 -0
- package/src/Tooltip/useTooltip.doc.mjs +2 -0
- package/src/Tooltip/useTooltip.tsx +99 -21
- package/src/TopNav/TopNavHeading.tsx +1 -1
- package/src/TopNav/TopNavItem.tsx +2 -2
- package/src/TopNav/TopNavMegaMenu.tsx +1 -1
- package/src/TopNav/TopNavMegaMenuItem.tsx +1 -1
- package/src/TopNav/TopNavMenu.tsx +2 -2
- package/src/TreeList/TreeListItem.tsx +1 -1
- package/src/hooks/containerReveal.stylex.ts +54 -18
- package/src/hooks/scrollbarGutter.test.ts +167 -0
- package/src/hooks/scrollbarGutter.ts +121 -0
- package/src/hooks/useResolvedRequired.ts +42 -0
- package/src/hooks/useScrollLock.doc.mjs +4 -4
- package/src/hooks/useScrollLock.test.ts +73 -0
- package/src/hooks/useScrollLock.ts +14 -0
- package/src/i18n/InternationalizationContext.ts +2 -0
- package/src/i18n/__tests__/e2e-powersearch.test.tsx +37 -1
- package/src/i18n/__tests__/useCollator.test.tsx +115 -0
- package/src/i18n/__tests__/useLocale.test.tsx +52 -0
- package/src/i18n/index.ts +6 -0
- package/src/i18n/useCollator.doc.mjs +84 -0
- package/src/i18n/useCollator.ts +44 -0
- package/src/i18n/useLocale.doc.mjs +70 -0
- package/src/i18n/useLocale.ts +34 -0
- package/src/i18n/useTranslator.doc.mjs +1 -1
- package/src/theme/defineTheme.test.ts +9 -3
- package/src/theme/defineTheme.ts +5 -0
- package/src/theme/derivedVarRegistry.test.ts +19 -5
- package/src/theme/derivedVarRegistry.ts +4 -0
- package/src/theme/generateThemeRules.test.ts +118 -0
- package/src/theme/generateThemeRules.ts +83 -5
- package/src/utils/dateParser.test.ts +20 -0
- package/src/utils/dateParser.ts +14 -7
- package/src/utils/plainDate.test.ts +56 -0
- package/src/utils/plainDate.ts +17 -4
|
@@ -129,7 +129,9 @@ describe('useSheetGestures', () => {
|
|
|
129
129
|
expect(onDismiss).not.toHaveBeenCalled();
|
|
130
130
|
expect(hook.result.current.settledOffset).toBe(200);
|
|
131
131
|
expect(onSnap).toHaveBeenLastCalledWith(200);
|
|
132
|
-
|
|
132
|
+
// The 200px stop is half the sheet — a working surface, not a peek — so
|
|
133
|
+
// the backdrop stays full there.
|
|
134
|
+
expect(onScrimOpacity).toHaveBeenLastCalledWith(1);
|
|
133
135
|
});
|
|
134
136
|
|
|
135
137
|
it('expands to the tallest detent on a fast upward flick', () => {
|
|
@@ -218,13 +220,62 @@ describe('useSheetGestures', () => {
|
|
|
218
220
|
expect(hook.result.current.settledLayoutOffset).toBe(0);
|
|
219
221
|
});
|
|
220
222
|
|
|
221
|
-
it('
|
|
223
|
+
it('re-anchors to the same stop when the snap heights change at rest', () => {
|
|
224
|
+
const onDismiss = vi.fn();
|
|
225
|
+
const hook = renderHook(
|
|
226
|
+
(props: UseSheetGesturesOptions) => useSheetGestures(props),
|
|
227
|
+
{
|
|
228
|
+
initialProps: {
|
|
229
|
+
isOpen: true,
|
|
230
|
+
onDismiss,
|
|
231
|
+
snapHeights: () => [200],
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
);
|
|
235
|
+
const t = makeTarget();
|
|
236
|
+
|
|
237
|
+
// Settle on the one collapsed stop: 400 - 200 = 200px of travel.
|
|
238
|
+
down(hook, 0, 0, t);
|
|
239
|
+
move(hook, 180, 700, t);
|
|
240
|
+
up(hook, 180, 1100, t);
|
|
241
|
+
act(() => hook.result.current.completeScrollAreaSettle());
|
|
242
|
+
expect(hook.result.current.settledOffset).toBe(200);
|
|
243
|
+
|
|
244
|
+
// A new resolver is a new set of stops. The sheet is resting on the one it
|
|
245
|
+
// names, so it follows: a 150px stop is 250px of travel. The resolver is
|
|
246
|
+
// read during render, not from a passive effect — the re-anchor runs in a
|
|
247
|
+
// layout effect, which would otherwise still see the previous one.
|
|
248
|
+
hook.rerender({
|
|
249
|
+
isOpen: true,
|
|
250
|
+
onDismiss,
|
|
251
|
+
snapHeights: () => [150],
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
expect(hook.result.current.settledOffset).toBe(250);
|
|
255
|
+
expect(hook.result.current.settledLayoutOffset).toBe(250);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('resizes the scrolling area at a collapsed stop that is a working height', () => {
|
|
259
|
+
// A 200px stop on the 400px sheet is half of it: the scrolling area takes
|
|
260
|
+
// that travel as layout height rather than sliding the sheet away.
|
|
222
261
|
const {hook} = setup({snapHeights: () => [200]});
|
|
223
262
|
const t = makeTarget();
|
|
224
263
|
down(hook, 0, 0, t);
|
|
225
264
|
move(hook, 180, 700, t);
|
|
226
265
|
up(hook, 180, 1100, t);
|
|
227
266
|
expect(hook.result.current.settledOffset).toBe(200);
|
|
267
|
+
expect(hook.result.current.settledLayoutOffset).toBe(200);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('treats the only collapsed stop as a peek when it is a sliver', () => {
|
|
271
|
+
// 60px of a 400px sheet is inside the quarter that makes a peek, so the
|
|
272
|
+
// sheet keeps its full layout height and slides below the viewport.
|
|
273
|
+
const {hook} = setup({snapHeights: () => [60]});
|
|
274
|
+
const t = makeTarget();
|
|
275
|
+
down(hook, 0, 0, t);
|
|
276
|
+
move(hook, 320, 700, t);
|
|
277
|
+
up(hook, 320, 1100, t);
|
|
278
|
+
expect(hook.result.current.settledOffset).toBe(340);
|
|
228
279
|
expect(hook.result.current.settledLayoutOffset).toBe(0);
|
|
229
280
|
});
|
|
230
281
|
|
|
@@ -297,20 +348,22 @@ describe('useSheetGestures', () => {
|
|
|
297
348
|
|
|
298
349
|
expect(onDismiss).not.toHaveBeenCalled();
|
|
299
350
|
expect(hook.result.current.settledOffset).toBe(200);
|
|
300
|
-
|
|
351
|
+
// Rebounding restores the scrim the 200px stop rests under — full, since
|
|
352
|
+
// half a sheet is a working surface rather than a glance.
|
|
353
|
+
expect(onScrimOpacity).toHaveBeenLastCalledWith(1);
|
|
301
354
|
});
|
|
302
355
|
|
|
303
356
|
it('fades the scrim from full toward the peek floor as it collapses onto the peek detent', () => {
|
|
304
357
|
const onScrimOpacity = vi.fn();
|
|
305
|
-
// Sheet 400,
|
|
306
|
-
// spans the mid detent (offset 100) to the peek
|
|
307
|
-
//
|
|
308
|
-
const {hook} = setup({snapHeights: () => [
|
|
358
|
+
// Sheet 400, stops at 300 and a 60px sliver -> offsets [0, 100, 340]. The
|
|
359
|
+
// fade spans the mid detent (offset 100) to the peek (offset 340): full
|
|
360
|
+
// at/above 100, thinned to the peek floor (0.3) at/below 340.
|
|
361
|
+
const {hook} = setup({snapHeights: () => [60, 300], onScrimOpacity});
|
|
309
362
|
const t = makeTarget();
|
|
310
363
|
down(hook, 0, 0, t);
|
|
311
364
|
move(hook, 60, 200, t); // offset 60, above the mid detent -> full
|
|
312
|
-
move(hook,
|
|
313
|
-
move(hook,
|
|
365
|
+
move(hook, 220, 600, t); // offset 220, halfway -> between 1 and 0.3 (~0.65)
|
|
366
|
+
move(hook, 360, 1000, t); // offset 360, past the peek -> peek floor
|
|
314
367
|
const values = onScrimOpacity.mock.calls.map(c => Number(c[0]));
|
|
315
368
|
expect(values[0]).toBe(1);
|
|
316
369
|
expect(values[1]).toBeGreaterThan(0.55);
|
|
@@ -320,14 +373,14 @@ describe('useSheetGestures', () => {
|
|
|
320
373
|
|
|
321
374
|
it('thins the scrim to the peek floor when settled at the peek detent (still modal)', () => {
|
|
322
375
|
const onScrimOpacity = vi.fn();
|
|
323
|
-
const {hook} = setup({snapHeights: () => [
|
|
376
|
+
const {hook} = setup({snapHeights: () => [60, 300], onScrimOpacity});
|
|
324
377
|
const t = makeTarget();
|
|
325
|
-
// Slow drag down to the peek detent (offset
|
|
378
|
+
// Slow drag down to the peek detent (offset 340).
|
|
326
379
|
down(hook, 0, 0, t);
|
|
327
|
-
move(hook,
|
|
328
|
-
move(hook,
|
|
329
|
-
up(hook,
|
|
330
|
-
expect(hook.result.current.settledOffset).toBe(
|
|
380
|
+
move(hook, 170, 400, t);
|
|
381
|
+
move(hook, 340, 900, t);
|
|
382
|
+
up(hook, 340, 1400, t);
|
|
383
|
+
expect(hook.result.current.settledOffset).toBe(340);
|
|
331
384
|
// Last reported opacity (on settle) is the peek floor, not fully hidden —
|
|
332
385
|
// the sheet is still modal, so the backdrop keeps a minimum dim.
|
|
333
386
|
const values = onScrimOpacity.mock.calls.map(c => Number(c[0]));
|
|
@@ -726,6 +779,51 @@ describe('useSheetGestures', () => {
|
|
|
726
779
|
return el;
|
|
727
780
|
}
|
|
728
781
|
|
|
782
|
+
// iOS Safari raises PointerEvents for a finger under the SAME numeric id
|
|
783
|
+
// it puts in `Touch.identifier`, so a drag the touch path starts is keyed
|
|
784
|
+
// to a live pointer. WebKit takes that pointer's capture straight back,
|
|
785
|
+
// and the `lostpointercapture` that follows used to cancel the drag one
|
|
786
|
+
// event after it began — leaving the sheet inert for the rest of the pull
|
|
787
|
+
// while the handle still worked. Every browser that keeps the two id
|
|
788
|
+
// spaces apart hides this, which is why it only showed up on device.
|
|
789
|
+
it('survives a lostpointercapture for the finger driving it', () => {
|
|
790
|
+
const {hook} = setup({snapHeights: () => [200]});
|
|
791
|
+
const el = midDetentScroller(hook, 600); // parked at the content end
|
|
792
|
+
act(() => {
|
|
793
|
+
touch(el, 'touchstart', 500, 7);
|
|
794
|
+
touch(el, 'touchmove', 450, 7); // promotes at the armed bottom edge
|
|
795
|
+
});
|
|
796
|
+
expect(hook.result.current.isDragging).toBe(true);
|
|
797
|
+
act(() => {
|
|
798
|
+
hook.result.current.bodyProps.onLostPointerCapture(
|
|
799
|
+
pointerEvent(450, 0, el, 7), // same id as the touch: iOS does this
|
|
800
|
+
);
|
|
801
|
+
});
|
|
802
|
+
expect(hook.result.current.isDragging).toBe(true);
|
|
803
|
+
act(() => {
|
|
804
|
+
touch(el, 'touchmove', 400, 7);
|
|
805
|
+
});
|
|
806
|
+
// 100px of pull past the touchstart, from the 200px detent.
|
|
807
|
+
expect(hook.result.current.dragOffset).toBe(100);
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
// `pointercancel` for that same finger arrives the moment WebKit claims
|
|
811
|
+
// the gesture. Ending the drag on it settles the sheet mid-pull.
|
|
812
|
+
it('does not end the touch drag on a pointercancel for that finger', () => {
|
|
813
|
+
const {hook} = setup({snapHeights: () => [200]});
|
|
814
|
+
const el = midDetentScroller(hook, 600);
|
|
815
|
+
act(() => {
|
|
816
|
+
touch(el, 'touchstart', 500, 7);
|
|
817
|
+
touch(el, 'touchmove', 450, 7);
|
|
818
|
+
});
|
|
819
|
+
act(() => {
|
|
820
|
+
hook.result.current.bodyProps.onPointerCancel(
|
|
821
|
+
pointerEvent(450, 0, el, 7),
|
|
822
|
+
);
|
|
823
|
+
});
|
|
824
|
+
expect(hook.result.current.isDragging).toBe(true);
|
|
825
|
+
});
|
|
826
|
+
|
|
729
827
|
it('hands off when the content runs out under a moving finger', () => {
|
|
730
828
|
const {hook} = setup({snapHeights: () => [200]});
|
|
731
829
|
const el = midDetentScroller(hook, 300); // finger lands mid-content
|
|
@@ -19,14 +19,16 @@
|
|
|
19
19
|
* the part the scrolling area gives up as layout height, and the remainder is
|
|
20
20
|
* a transform. Gestures and snaps only ever move the transform, so they stay
|
|
21
21
|
* on the compositor; layout height changes at rest, in one transition-free
|
|
22
|
-
* render whose visible geometry is identical.
|
|
23
|
-
*
|
|
22
|
+
* render whose visible geometry is identical. A peek detent — a stop that is
|
|
23
|
+
* only a sliver of the sheet — keeps the full height and slides below the
|
|
24
|
+
* viewport instead of reflowing to that sliver.
|
|
24
25
|
*
|
|
25
|
-
* Those are pixels, and the
|
|
26
|
-
* sheet at rest re-resolves its detent on `resize` / `orientationchange
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
26
|
+
* Those are pixels, and the stops behind them are relative to the viewport, so
|
|
27
|
+
* a sheet at rest re-resolves its detent on `resize` / `orientationchange`,
|
|
28
|
+
* and whenever the host swaps the snap points, and re-anchors to the new
|
|
29
|
+
* geometry without animating. The detent it returns to is tracked by index:
|
|
30
|
+
* the pixels stop meaning the same thing when the viewport changes, the stop
|
|
31
|
+
* the user chose does not.
|
|
30
32
|
*
|
|
31
33
|
* On touch, the scrolling body hands the gesture to the sheet at a scroll
|
|
32
34
|
* edge. Two shapes, because the browser only offers one of them a choice: a
|
|
@@ -66,11 +68,20 @@ import {
|
|
|
66
68
|
import {useMediaQuery} from '../hooks';
|
|
67
69
|
import {
|
|
68
70
|
computeDetentOffsets,
|
|
69
|
-
|
|
71
|
+
peekOffsetFor,
|
|
70
72
|
resolveSettleOffset,
|
|
71
73
|
scrimOpacityForOffset,
|
|
72
74
|
} from './snapOffsets';
|
|
73
75
|
|
|
76
|
+
/**
|
|
77
|
+
* The stops a sheet of a given height rests at: offsets from fully-open in px,
|
|
78
|
+
* ascending, plus which of them (if any) is the peek.
|
|
79
|
+
*/
|
|
80
|
+
interface SheetDetents {
|
|
81
|
+
offsets: number[];
|
|
82
|
+
peekOffset: number | null;
|
|
83
|
+
}
|
|
84
|
+
|
|
74
85
|
// A flick (fast throw) dismisses (down) or expands (up) regardless of where
|
|
75
86
|
// it ends. Requires both a speed and a distance floor so a small nudge
|
|
76
87
|
// doesn't trigger it.
|
|
@@ -82,6 +93,19 @@ const DISMISS_OVERSHOOT_RATIO = 0.4;
|
|
|
82
93
|
// Within this many px of a detent, the live drag is magnetically eased toward
|
|
83
94
|
// it so it "clicks" into place instead of hovering just off the mark.
|
|
84
95
|
const MAGNET_RANGE = 40;
|
|
96
|
+
// The touch path drives the sheet through the same machinery the pointer path
|
|
97
|
+
// uses, by handing it a pointer-shaped object built from a `Touch`. On iOS
|
|
98
|
+
// Safari that object is indistinguishable from the real thing: WebKit raises
|
|
99
|
+
// PointerEvents for a finger under the SAME numeric id it puts in
|
|
100
|
+
// `Touch.identifier`, so such a drag is keyed to a live pointer and the
|
|
101
|
+
// handlers that guard a mouse drag fire against it. Mark the synthetic object
|
|
102
|
+
// so they can tell the two apart.
|
|
103
|
+
type SyntheticTouchPointer = ReactPointerEvent & {syntheticTouch?: true};
|
|
104
|
+
|
|
105
|
+
function isSyntheticTouch(event: ReactPointerEvent): boolean {
|
|
106
|
+
return (event as SyntheticTouchPointer).syntheticTouch === true;
|
|
107
|
+
}
|
|
108
|
+
|
|
85
109
|
// Rubber-band factor for dragging up past fully-open, capped at OVERSCROLL_MAX
|
|
86
110
|
// (the sheet reserves that much bottom padding for the lift to reveal).
|
|
87
111
|
const OVERSCROLL_RESISTANCE = 0.35;
|
|
@@ -192,6 +216,9 @@ export interface UseSheetGesturesOptions {
|
|
|
192
216
|
* (rotation, a resized desktop window, collapsing browser chrome). The fully
|
|
193
217
|
* open height is always the tallest detent. Omit for a single-height sheet
|
|
194
218
|
* (a drag then only dismisses or springs back).
|
|
219
|
+
*
|
|
220
|
+
* Keep the identity stable: a new function is read as new stops, and
|
|
221
|
+
* re-anchors a resting sheet to them.
|
|
195
222
|
*/
|
|
196
223
|
snapHeights?: () => number[];
|
|
197
224
|
/** Notified when the settled visible detent height (px) changes. */
|
|
@@ -279,7 +306,7 @@ export interface UseSheetGesturesResult {
|
|
|
279
306
|
/**
|
|
280
307
|
* How much of `settledOffset` is expressed as layout height rather than as a
|
|
281
308
|
* transform. Equals `settledOffset` at the resizing detents; 0 at fully open
|
|
282
|
-
* and at the peek, which keep the sheet's full height (see
|
|
309
|
+
* and at the peek, which keep the sheet's full height (see peekOffsetFor).
|
|
283
310
|
*/
|
|
284
311
|
settledLayoutOffset: number;
|
|
285
312
|
}
|
|
@@ -326,7 +353,7 @@ export function useSheetGestures({
|
|
|
326
353
|
const [scrollPreservationInset, setScrollPreservationInset] = useState(0);
|
|
327
354
|
// How much of the settled travel is expressed as layout height. Equal to
|
|
328
355
|
// settledOffset for the resizing detents, and 0 at fully open and at the
|
|
329
|
-
// peek (see
|
|
356
|
+
// peek (see peekOffsetFor), which keep the full height and use a transform.
|
|
330
357
|
const [settledLayoutOffset, setSettledLayoutOffset] = useState(0);
|
|
331
358
|
const settledLayoutOffsetRef = useRef(0);
|
|
332
359
|
// WHICH detent the sheet rests on, as an index into the resolved list. The
|
|
@@ -419,21 +446,30 @@ export function useSheetGestures({
|
|
|
419
446
|
const isOpenRef = useRef(isOpen);
|
|
420
447
|
isOpenRef.current = isOpen;
|
|
421
448
|
|
|
449
|
+
// The resolver is refreshed during render, not with the callbacks below: the
|
|
450
|
+
// layout effect that re-anchors on a change to it runs BEFORE passive
|
|
451
|
+
// effects, so a resolver parked in one would still be the previous set of
|
|
452
|
+
// stops by the time the re-anchor read it.
|
|
453
|
+
const snapHeightsRef = useRef(snapHeights);
|
|
454
|
+
snapHeightsRef.current = snapHeights;
|
|
455
|
+
|
|
422
456
|
const onDismissRef = useRef(onDismiss);
|
|
423
457
|
const canDismissRef = useRef(canDismiss);
|
|
424
458
|
const onSnapRef = useRef(onSnap);
|
|
425
459
|
const onScrimOpacityRef = useRef(onScrimOpacity);
|
|
426
|
-
const snapHeightsRef = useRef(snapHeights);
|
|
427
460
|
useEffect(() => {
|
|
428
461
|
onDismissRef.current = onDismiss;
|
|
429
462
|
canDismissRef.current = canDismiss;
|
|
430
463
|
onSnapRef.current = onSnap;
|
|
431
464
|
onScrimOpacityRef.current = onScrimOpacity;
|
|
432
|
-
snapHeightsRef.current = snapHeights;
|
|
433
465
|
});
|
|
434
466
|
|
|
435
467
|
// Live drag bookkeeping (refs so pointermove doesn't churn renders).
|
|
436
468
|
const dragStateRef = useRef<{
|
|
469
|
+
// Whether the touch path drives this drag. Such a drag holds no pointer
|
|
470
|
+
// capture and takes its events from `touchmove`, so every real-pointer
|
|
471
|
+
// handler has to leave it alone.
|
|
472
|
+
syntheticTouch: boolean;
|
|
437
473
|
pointerId: number;
|
|
438
474
|
startCoord: number;
|
|
439
475
|
lastCoord: number;
|
|
@@ -545,20 +581,22 @@ export function useSheetGestures({
|
|
|
545
581
|
return sheetElRef.current?.getBoundingClientRect().height ?? 0;
|
|
546
582
|
}, []);
|
|
547
583
|
|
|
548
|
-
// Detent translate offsets (px) from the tallest detent, ascending
|
|
549
|
-
// the border-box portion reserved below the
|
|
550
|
-
// candidate visible heights; otherwise every
|
|
551
|
-
// too low. Snap heights are resolved lazily so
|
|
552
|
-
|
|
584
|
+
// Detent translate offsets (px) from the tallest detent, ascending, plus the
|
|
585
|
+
// peek among them. Exclude the border-box portion reserved below the
|
|
586
|
+
// viewport before comparing the candidate visible heights; otherwise every
|
|
587
|
+
// snap point lands that many px too low. Snap heights are resolved lazily so
|
|
588
|
+
// they track the viewport.
|
|
589
|
+
const resolveDetents = useCallback((height: number): SheetDetents => {
|
|
553
590
|
const visibleSheetHeight = visibleHeightForOffset(
|
|
554
591
|
height,
|
|
555
592
|
0,
|
|
556
593
|
offscreenBlockEndInsetRef.current,
|
|
557
594
|
);
|
|
558
|
-
|
|
595
|
+
const offsets = computeDetentOffsets(
|
|
559
596
|
visibleSheetHeight,
|
|
560
597
|
snapHeightsRef.current?.() ?? [],
|
|
561
598
|
);
|
|
599
|
+
return {offsets, peekOffset: peekOffsetFor(offsets, visibleSheetHeight)};
|
|
562
600
|
}, []);
|
|
563
601
|
|
|
564
602
|
// The height the sheet WOULD have fully open, right now. While it rests at a
|
|
@@ -592,87 +630,105 @@ export function useSheetGestures({
|
|
|
592
630
|
//
|
|
593
631
|
// Re-resolve the SAME detent — by index, the one thing that survives the
|
|
594
632
|
// units changing — against the new geometry, and re-anchor without
|
|
595
|
-
// animating: the
|
|
633
|
+
// animating: the geometry moved, not the user's finger, so there is no
|
|
596
634
|
// gesture to continue and nothing to ease.
|
|
597
|
-
|
|
598
|
-
|
|
635
|
+
const reanchorToSettledDetent = useCallback(() => {
|
|
636
|
+
// A closed sheet re-anchors on its way back open; a live drag re-measures
|
|
637
|
+
// on its own, and a settle in flight owns the layout until it lands.
|
|
638
|
+
if (
|
|
639
|
+
!isOpenRef.current ||
|
|
640
|
+
dragStateRef.current != null ||
|
|
641
|
+
settlingLayoutOffsetRef.current != null
|
|
642
|
+
) {
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
const height = measureFullyOpenHeight();
|
|
646
|
+
if (height <= 0) {
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
const {offsets, peekOffset} = resolveDetents(height);
|
|
650
|
+
const index = Math.min(settledDetentIndexRef.current, offsets.length - 1);
|
|
651
|
+
const target = offsets[index];
|
|
652
|
+
const targetLayoutOffset = target === peekOffset ? 0 : target;
|
|
653
|
+
const baseLayoutOffset = settledLayoutOffsetRef.current;
|
|
654
|
+
if (
|
|
655
|
+
height === sheetHeightRef.current &&
|
|
656
|
+
Math.abs(target - activeOffsetRef.current) <= 0.5 &&
|
|
657
|
+
Math.abs(targetLayoutOffset - baseLayoutOffset) <= 0.5
|
|
658
|
+
) {
|
|
599
659
|
return;
|
|
600
660
|
}
|
|
601
|
-
const handleViewportChange = () => {
|
|
602
|
-
// A live drag re-measures on its own, and a settle in flight owns the
|
|
603
|
-
// layout until it lands.
|
|
604
|
-
if (
|
|
605
|
-
dragStateRef.current != null ||
|
|
606
|
-
settlingLayoutOffsetRef.current != null
|
|
607
|
-
) {
|
|
608
|
-
return;
|
|
609
|
-
}
|
|
610
|
-
const height = measureFullyOpenHeight();
|
|
611
|
-
if (height <= 0) {
|
|
612
|
-
return;
|
|
613
|
-
}
|
|
614
|
-
const offsets = detentOffsets(height);
|
|
615
|
-
const index = Math.min(settledDetentIndexRef.current, offsets.length - 1);
|
|
616
|
-
const target = offsets[index];
|
|
617
|
-
const targetLayoutOffset = isPeekOffset(target, offsets) ? 0 : target;
|
|
618
|
-
const baseLayoutOffset = settledLayoutOffsetRef.current;
|
|
619
|
-
if (
|
|
620
|
-
height === sheetHeightRef.current &&
|
|
621
|
-
Math.abs(target - activeOffsetRef.current) <= 0.5 &&
|
|
622
|
-
Math.abs(targetLayoutOffset - baseLayoutOffset) <= 0.5
|
|
623
|
-
) {
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
661
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
662
|
+
sheetHeightRef.current = height;
|
|
663
|
+
// Re-anchoring is a measurement: the geometry it reads is only knowable
|
|
664
|
+
// after layout, so the state it corrects can only be set from an effect
|
|
665
|
+
// (or, on the resize path, from the listener). Both writes below are
|
|
666
|
+
// guarded by the equality check above, so a re-anchor that finds nothing
|
|
667
|
+
// to change sets nothing.
|
|
668
|
+
// eslint-disable-next-line @eslint-react/set-state-in-effect -- corrects settled geometry from a measurement
|
|
669
|
+
setSheetHeight(height);
|
|
670
|
+
settledDetentIndexRef.current = index;
|
|
671
|
+
prepareScrollAreaSettle(
|
|
672
|
+
baseLayoutOffset,
|
|
673
|
+
target,
|
|
674
|
+
targetLayoutOffset,
|
|
675
|
+
target,
|
|
676
|
+
baseLayoutOffset,
|
|
677
|
+
naturalEndGapFor(bodyNodeRef.current),
|
|
678
|
+
false,
|
|
679
|
+
);
|
|
680
|
+
recordSettledLayoutOffset(targetLayoutOffset);
|
|
681
|
+
// eslint-disable-next-line @eslint-react/set-state-in-effect -- corrects settled geometry from a measurement
|
|
682
|
+
setSettledOffset(target);
|
|
683
|
+
onSnapRef.current?.(
|
|
684
|
+
visibleHeightForOffset(height, target, offscreenBlockEndInsetRef.current),
|
|
685
|
+
);
|
|
686
|
+
const maxOffset = offsets[offsets.length - 1];
|
|
687
|
+
const shortestDetentHeight = visibleHeightForOffset(
|
|
688
|
+
height,
|
|
689
|
+
maxOffset,
|
|
690
|
+
offscreenBlockEndInsetRef.current,
|
|
691
|
+
);
|
|
692
|
+
onScrimOpacityRef.current?.(
|
|
693
|
+
scrimOpacityForOffset(
|
|
634
694
|
target,
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
)
|
|
639
|
-
|
|
640
|
-
setSettledOffset(target);
|
|
641
|
-
onSnapRef.current?.(
|
|
642
|
-
visibleHeightForOffset(
|
|
643
|
-
height,
|
|
644
|
-
target,
|
|
645
|
-
offscreenBlockEndInsetRef.current,
|
|
646
|
-
),
|
|
647
|
-
);
|
|
648
|
-
const maxOffset = offsets[offsets.length - 1];
|
|
649
|
-
const shortestDetentHeight = visibleHeightForOffset(
|
|
650
|
-
height,
|
|
651
|
-
maxOffset,
|
|
652
|
-
offscreenBlockEndInsetRef.current,
|
|
653
|
-
);
|
|
654
|
-
onScrimOpacityRef.current?.(
|
|
655
|
-
scrimOpacityForOffset(
|
|
656
|
-
target,
|
|
657
|
-
offsets,
|
|
658
|
-
maxOffset + shortestDetentHeight * DISMISS_OVERSHOOT_RATIO,
|
|
659
|
-
),
|
|
660
|
-
);
|
|
661
|
-
};
|
|
662
|
-
window.addEventListener('resize', handleViewportChange);
|
|
663
|
-
window.addEventListener('orientationchange', handleViewportChange);
|
|
664
|
-
return () => {
|
|
665
|
-
window.removeEventListener('resize', handleViewportChange);
|
|
666
|
-
window.removeEventListener('orientationchange', handleViewportChange);
|
|
667
|
-
};
|
|
695
|
+
offsets,
|
|
696
|
+
maxOffset + shortestDetentHeight * DISMISS_OVERSHOOT_RATIO,
|
|
697
|
+
peekOffset,
|
|
698
|
+
),
|
|
699
|
+
);
|
|
668
700
|
}, [
|
|
669
|
-
detentOffsets,
|
|
670
|
-
isOpen,
|
|
671
701
|
measureFullyOpenHeight,
|
|
672
702
|
prepareScrollAreaSettle,
|
|
673
703
|
recordSettledLayoutOffset,
|
|
704
|
+
resolveDetents,
|
|
674
705
|
]);
|
|
675
706
|
|
|
707
|
+
useEffect(() => {
|
|
708
|
+
if (!isOpen || typeof window === 'undefined') {
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
window.addEventListener('resize', reanchorToSettledDetent);
|
|
712
|
+
window.addEventListener('orientationchange', reanchorToSettledDetent);
|
|
713
|
+
return () => {
|
|
714
|
+
window.removeEventListener('resize', reanchorToSettledDetent);
|
|
715
|
+
window.removeEventListener('orientationchange', reanchorToSettledDetent);
|
|
716
|
+
};
|
|
717
|
+
}, [isOpen, reanchorToSettledDetent]);
|
|
718
|
+
|
|
719
|
+
// The other input to the same geometry: the snap points themselves. A host
|
|
720
|
+
// that swaps them while the sheet rests has moved the stops out from under
|
|
721
|
+
// it, exactly as a rotation does, so re-anchor the same way. Skipped on the
|
|
722
|
+
// first run — the sheet is already anchored to the detents it opened with.
|
|
723
|
+
const hasAnchoredSnapHeightsRef = useRef(false);
|
|
724
|
+
useLayoutEffect(() => {
|
|
725
|
+
if (!hasAnchoredSnapHeightsRef.current) {
|
|
726
|
+
hasAnchoredSnapHeightsRef.current = true;
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
reanchorToSettledDetent();
|
|
730
|
+
}, [reanchorToSettledDetent, snapHeights]);
|
|
731
|
+
|
|
676
732
|
const cancelDrag = useCallback(
|
|
677
733
|
(target?: HTMLElement) => {
|
|
678
734
|
const state = dragStateRef.current;
|
|
@@ -701,7 +757,7 @@ export function useSheetGestures({
|
|
|
701
757
|
// An interrupted drag returns to its previous resting detent. Restore
|
|
702
758
|
// the matching scrim opacity as well so the modal shell cannot remain
|
|
703
759
|
// dimmed with its sheet translated out of view.
|
|
704
|
-
const offsets =
|
|
760
|
+
const {offsets, peekOffset} = resolveDetents(state.height);
|
|
705
761
|
const maxOffset = offsets[offsets.length - 1];
|
|
706
762
|
const shortestDetentHeight = visibleHeightForOffset(
|
|
707
763
|
state.height,
|
|
@@ -711,10 +767,15 @@ export function useSheetGestures({
|
|
|
711
767
|
const dismissOffset =
|
|
712
768
|
maxOffset + shortestDetentHeight * DISMISS_OVERSHOOT_RATIO;
|
|
713
769
|
onScrimOpacityRef.current?.(
|
|
714
|
-
scrimOpacityForOffset(
|
|
770
|
+
scrimOpacityForOffset(
|
|
771
|
+
state.baseOffset,
|
|
772
|
+
offsets,
|
|
773
|
+
dismissOffset,
|
|
774
|
+
peekOffset,
|
|
775
|
+
),
|
|
715
776
|
);
|
|
716
777
|
},
|
|
717
|
-
[
|
|
778
|
+
[prepareScrollAreaSettle, resolveDetents],
|
|
718
779
|
);
|
|
719
780
|
|
|
720
781
|
useEffect(() => {
|
|
@@ -745,7 +806,7 @@ export function useSheetGestures({
|
|
|
745
806
|
layoutOffset: number,
|
|
746
807
|
naturalEndGap: number,
|
|
747
808
|
) => {
|
|
748
|
-
const offsets =
|
|
809
|
+
const {offsets, peekOffset} = resolveDetents(height);
|
|
749
810
|
const maxOffset = offsets[offsets.length - 1];
|
|
750
811
|
const shortestDetentHeight = visibleHeightForOffset(
|
|
751
812
|
height,
|
|
@@ -757,7 +818,7 @@ export function useSheetGestures({
|
|
|
757
818
|
const settleAt = (target: number) => {
|
|
758
819
|
// A peek keeps the full layout height and slides below the viewport;
|
|
759
820
|
// every taller detent resizes the scrolling area to what it shows.
|
|
760
|
-
const targetLayoutOffset =
|
|
821
|
+
const targetLayoutOffset = target === peekOffset ? 0 : target;
|
|
761
822
|
prepareScrollAreaSettle(
|
|
762
823
|
baseLayoutOffset,
|
|
763
824
|
target,
|
|
@@ -780,7 +841,7 @@ export function useSheetGestures({
|
|
|
780
841
|
const dismissOffset =
|
|
781
842
|
maxOffset + shortestDetentHeight * DISMISS_OVERSHOOT_RATIO;
|
|
782
843
|
onScrimOpacityRef.current?.(
|
|
783
|
-
scrimOpacityForOffset(target, offsets, dismissOffset),
|
|
844
|
+
scrimOpacityForOffset(target, offsets, dismissOffset, peekOffset),
|
|
784
845
|
);
|
|
785
846
|
if (target !== baseOffset) {
|
|
786
847
|
hapticTick();
|
|
@@ -849,13 +910,22 @@ export function useSheetGestures({
|
|
|
849
910
|
const target = resolveSettleOffset(offset, offsets, dir, baseOffset);
|
|
850
911
|
settleAt(target);
|
|
851
912
|
},
|
|
852
|
-
[
|
|
913
|
+
[prepareScrollAreaSettle, recordSettledLayoutOffset, resolveDetents],
|
|
853
914
|
);
|
|
854
915
|
|
|
855
916
|
const beginDrag = useCallback(
|
|
856
917
|
(event: ReactPointerEvent, sheetHeight: number, startCoord?: number) => {
|
|
857
918
|
const target = event.currentTarget as HTMLElement;
|
|
858
|
-
|
|
919
|
+
const syntheticTouch = isSyntheticTouch(event);
|
|
920
|
+
// Never capture for a touch drag. The id came from `Touch.identifier`,
|
|
921
|
+
// which on iOS names a live pointer: the capture succeeds, WebKit takes
|
|
922
|
+
// it straight back for its own gesture handling, and the
|
|
923
|
+
// `lostpointercapture` a millisecond later cancels the drag that just
|
|
924
|
+
// started. Touch drags need no capture — the listener is on the
|
|
925
|
+
// scroller itself.
|
|
926
|
+
if (!syntheticTouch) {
|
|
927
|
+
target.setPointerCapture?.(event.pointerId);
|
|
928
|
+
}
|
|
859
929
|
// `startCoord` lets a body-overscroll drag anchor at the original
|
|
860
930
|
// pointer-down position (not the promotion point), so the first frame's
|
|
861
931
|
// delta reflects the full pull distance.
|
|
@@ -863,6 +933,7 @@ export function useSheetGestures({
|
|
|
863
933
|
const naturalEndGap = naturalEndGapFor(bodyNodeRef.current);
|
|
864
934
|
const baseLayoutOffset = settledLayoutOffsetRef.current;
|
|
865
935
|
dragStateRef.current = {
|
|
936
|
+
syntheticTouch,
|
|
866
937
|
pointerId: event.pointerId,
|
|
867
938
|
startCoord: start,
|
|
868
939
|
lastCoord: event.clientY,
|
|
@@ -917,6 +988,12 @@ export function useSheetGestures({
|
|
|
917
988
|
|
|
918
989
|
const handleLostPointerCapture = useCallback(
|
|
919
990
|
(event: ReactPointerEvent) => {
|
|
991
|
+
// A touch drag never took capture, so this is WebKit reclaiming its own
|
|
992
|
+
// pointer for the finger doing the dragging — not the drag losing its
|
|
993
|
+
// grip.
|
|
994
|
+
if (dragStateRef.current?.syntheticTouch) {
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
920
997
|
if (dragStateRef.current?.pointerId === event.pointerId) {
|
|
921
998
|
cancelDrag();
|
|
922
999
|
}
|
|
@@ -930,6 +1007,11 @@ export function useSheetGestures({
|
|
|
930
1007
|
if (!state || state.pointerId !== event.pointerId) {
|
|
931
1008
|
return;
|
|
932
1009
|
}
|
|
1010
|
+
// Same finger, real pointer event: the touch path already drove this
|
|
1011
|
+
// move. Let it own the drag rather than driving it twice.
|
|
1012
|
+
if (state.syntheticTouch && !isSyntheticTouch(event)) {
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
933
1015
|
const delta = event.clientY - state.startCoord;
|
|
934
1016
|
const dt = event.timeStamp - state.lastTime;
|
|
935
1017
|
if (dt > 0) {
|
|
@@ -937,7 +1019,7 @@ export function useSheetGestures({
|
|
|
937
1019
|
state.lastCoord = event.clientY;
|
|
938
1020
|
state.lastTime = event.timeStamp;
|
|
939
1021
|
}
|
|
940
|
-
const offsets =
|
|
1022
|
+
const {offsets, peekOffset} = resolveDetents(state.height);
|
|
941
1023
|
|
|
942
1024
|
const raw = state.baseOffset + delta;
|
|
943
1025
|
const maxDetentOffset = offsets[offsets.length - 1];
|
|
@@ -979,10 +1061,10 @@ export function useSheetGestures({
|
|
|
979
1061
|
const dismissOffset =
|
|
980
1062
|
floorOffset + shortestDetentHeight * DISMISS_OVERSHOOT_RATIO;
|
|
981
1063
|
onScrimOpacityRef.current?.(
|
|
982
|
-
scrimOpacityForOffset(next, offsets, dismissOffset),
|
|
1064
|
+
scrimOpacityForOffset(next, offsets, dismissOffset, peekOffset),
|
|
983
1065
|
);
|
|
984
1066
|
},
|
|
985
|
-
[
|
|
1067
|
+
[resolveDetents, updateScrollPreservationInset],
|
|
986
1068
|
);
|
|
987
1069
|
|
|
988
1070
|
const endDrag = useCallback(
|
|
@@ -991,12 +1073,20 @@ export function useSheetGestures({
|
|
|
991
1073
|
if (!state || state.pointerId !== event.pointerId) {
|
|
992
1074
|
return;
|
|
993
1075
|
}
|
|
1076
|
+
// `pointercancel` fires for the finger the moment WebKit claims the
|
|
1077
|
+
// gesture; ending a touch drag on it settles the sheet mid-pull. The
|
|
1078
|
+
// touchend handler is what finishes a touch drag.
|
|
1079
|
+
if (state.syntheticTouch && !isSyntheticTouch(event)) {
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
994
1082
|
const target = event.currentTarget as HTMLElement;
|
|
995
1083
|
const delta = event.clientY - state.startCoord;
|
|
996
1084
|
const offset = Math.max(0, state.baseOffset + delta);
|
|
997
1085
|
const dir = delta === 0 ? 0 : delta > 0 ? 1 : -1;
|
|
998
1086
|
dragStateRef.current = null;
|
|
999
|
-
|
|
1087
|
+
if (!state.syntheticTouch) {
|
|
1088
|
+
target.releasePointerCapture?.(event.pointerId);
|
|
1089
|
+
}
|
|
1000
1090
|
setIsDragging(false);
|
|
1001
1091
|
settleFromDrag(
|
|
1002
1092
|
offset,
|
|
@@ -1067,6 +1157,11 @@ export function useSheetGestures({
|
|
|
1067
1157
|
const handleBodyEnd = useCallback(
|
|
1068
1158
|
(event: ReactPointerEvent) => {
|
|
1069
1159
|
armedBodyRef.current = null;
|
|
1160
|
+
// The pointerup/pointercancel for a finger already driving a touch drag
|
|
1161
|
+
// arrives here carrying that drag's own id; touchend ends those.
|
|
1162
|
+
if (dragStateRef.current?.syntheticTouch) {
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1070
1165
|
if (dragStateRef.current) {
|
|
1071
1166
|
endDrag(event);
|
|
1072
1167
|
}
|
|
@@ -1118,6 +1213,7 @@ export function useSheetGestures({
|
|
|
1118
1213
|
const bodyRef = useCallback((node: HTMLElement | null) => {
|
|
1119
1214
|
const asPointer = (touch: Touch, target: HTMLElement) =>
|
|
1120
1215
|
({
|
|
1216
|
+
syntheticTouch: true,
|
|
1121
1217
|
pointerId: touch.identifier,
|
|
1122
1218
|
clientY: touch.clientY,
|
|
1123
1219
|
timeStamp: Date.now(),
|