@astryxdesign/core 0.7.5 → 0.7.6-canary.5cd7a15
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/AlertDialog/AlertDialog.d.ts +1 -1
- package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
- package/dist/AlertDialog/AlertDialog.js +5 -5
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +12 -3
- package/dist/Badge/Badge.d.ts.map +1 -1
- package/dist/Badge/Badge.js +7 -1
- package/dist/BottomSheet/BottomSheet.js +1 -1
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +2 -1
- package/dist/BottomSheet/useSheetGestures.d.ts +12 -0
- package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
- package/dist/BottomSheet/useSheetGestures.js +30 -3
- package/dist/Button/Button.js +4 -4
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +6 -5
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +12 -4
- package/dist/DateInput/MonthScroller.d.ts.map +1 -1
- package/dist/DateInput/MonthScroller.js +101 -15
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +8 -3
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +1 -1
- package/dist/DateTimeInput/DateTimeInput.d.ts +5 -2
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +23 -12
- package/dist/DateTimeInput/NativeTimeSegment.d.ts.map +1 -1
- package/dist/DateTimeInput/NativeTimeSegment.js +5 -4
- package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
- package/dist/DateTimeInput/TouchDateTimeField.js +4 -3
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +34 -9
- package/dist/Dialog/DialogHeader.d.ts.map +1 -1
- package/dist/Dialog/DialogHeader.js +5 -4
- package/dist/Divider/Divider.d.ts.map +1 -1
- package/dist/Divider/Divider.js +2 -1
- package/dist/Drawer/Drawer.d.ts +1 -0
- package/dist/Drawer/Drawer.d.ts.map +1 -1
- package/dist/Drawer/Drawer.js +7 -2
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +4 -1
- package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -1
- package/dist/DropdownMenu/MenuBottomSheetActionList.js +6 -5
- package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +10 -1
- package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -1
- package/dist/DropdownMenu/lazyMenuBottomSheet.js +16 -2
- package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
- package/dist/DropdownMenu/renderDropdownItems.js +21 -16
- package/dist/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/EmptyState/EmptyState.js +2 -1
- package/dist/Field/FieldLabel.d.ts +1 -1
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +4 -4
- package/dist/Field/InputClearButton.js +3 -3
- package/dist/Field/PanelSearchInput.js +2 -2
- package/dist/FieldStatus/FieldStatus.js +2 -2
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +7 -1
- package/dist/Heading/Heading.js +1 -1
- package/dist/Icon/Icon.js +1 -1
- package/dist/Indicator/CheckIndicator.d.ts.map +1 -1
- package/dist/Indicator/CheckIndicator.js +2 -1
- package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
- package/dist/Indicator/CheckboxIndicator.js +3 -1
- package/dist/Indicator/RadioIndicator.d.ts.map +1 -1
- package/dist/Indicator/RadioIndicator.js +3 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +2 -1
- package/dist/Item/ItemSwipeLayer.js +1 -1
- package/dist/Layout/Layout.js +1 -1
- package/dist/Layout/LayoutContent.js +1 -1
- package/dist/Layout/LayoutFooter.js +1 -1
- package/dist/Layout/LayoutHeader.js +1 -1
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +5 -0
- package/dist/Lightbox/LightboxViewport.a11y.browser.spec.js +5 -4
- package/dist/List/List.js +1 -1
- package/dist/List/ListItem.js +3 -3
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +7 -2
- package/dist/MultiSelector/MultiSelector.d.ts +1 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +5 -2
- package/dist/NumberInput/NumberInput.d.ts +3 -1
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +3 -3
- package/dist/NumberInput/numberParser.d.ts +3 -0
- package/dist/NumberInput/numberParser.d.ts.map +1 -1
- package/dist/NumberInput/numberParser.js +7 -44
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +16 -12
- package/dist/Resizable/useResizable.d.ts.map +1 -1
- package/dist/Resizable/useResizable.js +28 -2
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +4 -1
- package/dist/Selector/useSelectorPresentation.d.ts +8 -1
- package/dist/Selector/useSelectorPresentation.d.ts.map +1 -1
- package/dist/Selector/useSelectorPresentation.js +20 -4
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +7 -1
- package/dist/Spinner/Spinner.js +2 -2
- package/dist/Stack/Stack.js +1 -1
- package/dist/Stack/StackItem.js +1 -1
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +16 -1
- package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
- package/dist/Table/plugins/columnResize/useTableColumnResize.js +9 -1
- package/dist/Text/Text.js +1 -1
- package/dist/Text/useTruncation.d.ts.map +1 -1
- package/dist/Text/useTruncation.js +23 -5
- package/dist/TextArea/TextArea.d.ts +1 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +13 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +3 -3
- package/dist/TimeInput/TimeInput.d.ts +6 -2
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +21 -14
- package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
- package/dist/TimeInput/TouchTimeField.js +5 -4
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +2 -2
- package/dist/Timestamp/TimestampHoverCard.js +4 -4
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +60 -20
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +82 -51
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +13 -2
- package/dist/Tokenizer/TokenizerBottomSheet.js +3 -3
- package/dist/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/Toolbar/Toolbar.js +2 -1
- package/dist/Typeahead/Typeahead.d.ts +1 -1
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +9 -1
- package/dist/astryx.css +15 -1
- package/dist/gestures/GestureArena.d.ts +6 -0
- package/dist/gestures/GestureArena.d.ts.map +1 -1
- package/dist/gestures/GestureArena.js +39 -0
- package/dist/gestures/GestureHost.d.ts +352 -0
- package/dist/gestures/GestureHost.d.ts.map +1 -0
- package/dist/gestures/GestureHost.js +1773 -0
- package/dist/gestures/GestureRecognizer.d.ts +10 -0
- package/dist/gestures/GestureRecognizer.d.ts.map +1 -1
- package/dist/gestures/GestureRecognizer.js +16 -0
- package/dist/gestures/LongPressGestureRecognizer.d.ts +1 -0
- package/dist/gestures/LongPressGestureRecognizer.d.ts.map +1 -1
- package/dist/gestures/LongPressGestureRecognizer.js +3 -0
- package/dist/gestures/PanGestureRecognizer.d.ts +1 -0
- package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -1
- package/dist/gestures/PanGestureRecognizer.js +3 -0
- package/dist/gestures/PinchGestureRecognizer.d.ts +31 -0
- package/dist/gestures/PinchGestureRecognizer.d.ts.map +1 -0
- package/dist/gestures/PinchGestureRecognizer.js +128 -0
- package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +71 -0
- package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -0
- package/dist/gestures/ScreenEdgePanGestureRecognizer.js +223 -0
- package/dist/gestures/SwipeGestureRecognizer.d.ts +37 -0
- package/dist/gestures/SwipeGestureRecognizer.d.ts.map +1 -0
- package/dist/gestures/SwipeGestureRecognizer.js +148 -0
- package/dist/gestures/TapGestureRecognizer.d.ts +1 -0
- package/dist/gestures/TapGestureRecognizer.d.ts.map +1 -1
- package/dist/gestures/TapGestureRecognizer.js +3 -0
- package/dist/gestures/VelocityTracker.d.ts +6 -2
- package/dist/gestures/VelocityTracker.d.ts.map +1 -1
- package/dist/gestures/VelocityTracker.js +7 -3
- package/dist/gestures/haptics.d.ts +65 -0
- package/dist/gestures/haptics.d.ts.map +1 -0
- package/dist/gestures/haptics.js +182 -0
- package/dist/gestures/nativeScroll.d.ts +42 -0
- package/dist/gestures/nativeScroll.d.ts.map +1 -0
- package/dist/gestures/nativeScroll.js +228 -0
- package/dist/gestures/touchAction.d.ts +60 -0
- package/dist/gestures/touchAction.d.ts.map +1 -0
- package/dist/gestures/touchAction.js +157 -0
- package/dist/gestures/touchActionRule.d.ts +34 -0
- package/dist/gestures/touchActionRule.d.ts.map +1 -0
- package/dist/gestures/touchActionRule.js +140 -0
- package/dist/gestures/types.d.ts +18 -7
- package/dist/gestures/types.d.ts.map +1 -1
- package/dist/gestures/types.js +22 -2
- package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -1
- package/dist/hooks/useAdaptivePresentation.js +4 -1
- package/dist/hooks/useMenuHover.d.ts.map +1 -1
- package/dist/hooks/useMenuHover.js +12 -1
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +3 -0
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +3 -0
- package/dist/motion/animator.d.ts +7 -1
- package/dist/motion/animator.d.ts.map +1 -1
- package/dist/motion/animator.js +119 -27
- package/dist/theme/defineTheme.js +1 -1
- package/dist/theme/domainTokens/domainTokenDefaults.d.ts +3 -0
- package/dist/theme/domainTokens/domainTokenDefaults.d.ts.map +1 -0
- package/dist/theme/domainTokens/domainTokenDefaults.js +19 -0
- package/dist/theme/domainTokens/index.d.ts +5 -4
- package/dist/theme/domainTokens/index.d.ts.map +1 -1
- package/dist/theme/domainTokens/index.js +5 -9
- package/dist/utils/focusReturn.d.ts +17 -1
- package/dist/utils/focusReturn.d.ts.map +1 -1
- package/dist/utils/focusReturn.js +11 -4
- package/dist/utils/getNodeText.d.ts +8 -0
- package/dist/utils/getNodeText.d.ts.map +1 -0
- package/dist/utils/getNodeText.js +37 -0
- package/dist/utils/interactionModality.d.ts +11 -2
- package/dist/utils/interactionModality.d.ts.map +1 -1
- package/dist/utils/interactionModality.js +58 -5
- package/dist/utils/plainDate.d.ts +2 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +46 -3
- package/dist/utils/presentation.d.ts +50 -0
- package/dist/utils/presentation.d.ts.map +1 -0
- package/dist/utils/presentation.js +125 -0
- package/dist/utils/primaryClick.d.ts +11 -0
- package/dist/utils/primaryClick.d.ts.map +1 -0
- package/dist/utils/primaryClick.js +25 -0
- package/dist/utils/timeFormat.d.ts +47 -0
- package/dist/utils/timeFormat.d.ts.map +1 -0
- package/dist/utils/timeFormat.js +240 -0
- package/dist/utils/touchPresentation.d.ts.map +1 -1
- package/dist/utils/touchPresentation.js +5 -3
- package/dist/utils/touchPresentation.stylex.d.ts +15 -0
- package/dist/utils/touchPresentation.stylex.d.ts.map +1 -0
- package/dist/utils/touchPresentation.stylex.js +33 -0
- package/dist/utils/unicodeDigits.d.ts +20 -0
- package/dist/utils/unicodeDigits.d.ts.map +1 -0
- package/dist/utils/unicodeDigits.js +70 -0
- package/locales/en.json +15 -3
- package/locales/pseudo.json +9 -0
- package/package.json +5 -4
- package/src/AlertDialog/AlertDialog.tsx +6 -5
- package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +18 -6
- package/src/Avatar/Avatar.spec.md +22 -22
- package/src/Avatar/Avatar.tsx +18 -1
- package/src/Avatar/__tests__/AvatarForcedColors.a11y.chromium.spec.ts +126 -0
- package/src/Badge/Badge.doc.mjs +1 -1
- package/src/Badge/Badge.tsx +19 -2
- package/src/Badge/__tests__/BadgeLargerText.a11y.chromium.spec.ts +260 -0
- package/src/BottomSheet/BottomSheet.test.tsx +46 -0
- package/src/BottomSheet/BottomSheet.tsx +1 -1
- package/src/BottomSheet/BottomSheetPanel.tsx +2 -1
- package/src/BottomSheet/useSheetGestures.test.ts +52 -0
- package/src/BottomSheet/useSheetGestures.ts +37 -6
- package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.chromium.spec.ts +18 -6
- package/src/Button/Button.tsx +4 -4
- package/src/Calendar/Calendar.spec.md +87 -48
- package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +21 -7
- package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +21 -7
- package/src/CheckboxInput/CheckboxInput.tsx +6 -5
- package/src/Collapsible/Collapsible.spec.md +2 -0
- package/src/Collapsible/CollapsibleGroup.spec.md +57 -29
- package/src/Collapsible/__tests__/Collapsible.a11y.chromium.spec.ts +18 -7
- package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +18 -6
- package/src/ComplexSelector/ComplexSelector.test.tsx +37 -0
- package/src/ContextMenu/ContextMenu.test.tsx +35 -0
- package/src/DateInput/DateInput.test.tsx +115 -3
- package/src/DateInput/DateInput.tsx +29 -14
- package/src/DateInput/DateInputTouch.test.tsx +76 -0
- package/src/DateInput/MonthScroller.tsx +106 -20
- package/src/DateInput/MonthScrollerSettle.test.tsx +165 -0
- package/src/DateInput/TouchDateField.tsx +14 -3
- package/src/DateInput/__tests__/MonthScrollerSteps.interaction.browser.spec.ts +312 -0
- package/src/DateRangeInput/DateRangeInput.test.tsx +46 -3
- package/src/DateRangeInput/DateRangeInput.tsx +16 -12
- package/src/DateTimeInput/DateTimeInput.doc.mjs +10 -8
- package/src/DateTimeInput/DateTimeInput.spec.md +75 -51
- package/src/DateTimeInput/DateTimeInput.test.tsx +81 -0
- package/src/DateTimeInput/DateTimeInput.tsx +46 -24
- package/src/DateTimeInput/NativeTimeSegment.tsx +4 -6
- package/src/DateTimeInput/TouchDateTimeField.tsx +3 -7
- package/src/Dialog/Dialog.test.tsx +216 -2
- package/src/Dialog/Dialog.tsx +42 -9
- package/src/Dialog/DialogHeader.tsx +5 -4
- package/src/Dialog/__tests__/DialogSecondDocument.a11y.browser.spec.ts +202 -0
- package/src/Divider/Divider.tsx +2 -1
- package/src/Drawer/Drawer.spec.md +111 -80
- package/src/Drawer/Drawer.test.tsx +35 -0
- package/src/Drawer/Drawer.tsx +13 -2
- package/src/Drawer/DrawerHeader.spec.md +181 -0
- package/src/Drawer/__tests__/DrawerNonModalPageScroll.a11y.chromium.spec.ts +267 -0
- package/src/DropdownMenu/DropdownMenu.test.tsx +41 -0
- package/src/DropdownMenu/DropdownMenu.tsx +7 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +34 -0
- package/src/DropdownMenu/MenuBottomSheetActionList.tsx +6 -5
- package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +19 -7
- package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +21 -9
- package/src/DropdownMenu/lazyMenuBottomSheet.test.ts +53 -0
- package/src/DropdownMenu/lazyMenuBottomSheet.ts +23 -6
- package/src/DropdownMenu/renderDropdownItems.tsx +24 -19
- package/src/EmptyState/EmptyState.tsx +2 -1
- package/src/Field/FieldLabel.tsx +5 -4
- package/src/Field/InputClearButton.tsx +3 -3
- package/src/Field/PanelSearchInput.tsx +2 -2
- package/src/FieldStatus/FieldStatus.tsx +2 -2
- package/src/FileInput/FileInput.test.tsx +21 -0
- package/src/FileInput/FileInput.tsx +4 -1
- package/src/FormLayout/FormLayout.spec.md +7 -8
- package/src/Heading/Heading.tsx +1 -1
- package/src/Icon/Icon.tsx +1 -1
- package/src/Indicator/CheckIndicator.spec.md +47 -42
- package/src/Indicator/CheckIndicator.tsx +2 -1
- package/src/Indicator/CheckboxIndicator.spec.md +40 -37
- package/src/Indicator/CheckboxIndicator.tsx +3 -1
- package/src/Indicator/Indicator.spec.md +188 -0
- package/src/Indicator/RadioIndicator.tsx +3 -1
- package/src/Item/Item.tsx +2 -1
- package/src/Item/ItemSwipeLayer.tsx +1 -1
- package/src/Layout/Layout.spec.md +127 -131
- package/src/Layout/Layout.tsx +1 -1
- package/src/Layout/LayoutContent.spec.md +205 -0
- package/src/Layout/LayoutContent.tsx +1 -1
- package/src/Layout/LayoutFooter.spec.md +190 -0
- package/src/Layout/LayoutFooter.tsx +1 -1
- package/src/Layout/LayoutHeader.spec.md +193 -0
- package/src/Layout/LayoutHeader.tsx +1 -1
- package/src/Layout/LayoutPanel.spec.md +194 -0
- package/src/Layout/__tests__/Layout.a11y.chromium.spec.ts +18 -6
- package/src/Lightbox/Lightbox.test.tsx +18 -0
- package/src/Lightbox/Lightbox.tsx +5 -0
- package/src/Lightbox/LightboxViewport.a11y.browser.spec.ts +8 -4
- package/src/Link/__tests__/Link.a11y.chromium.spec.ts +18 -8
- package/src/List/List.tsx +1 -1
- package/src/List/ListItem.spec.md +205 -0
- package/src/List/ListItem.tsx +3 -3
- package/src/MobileNav/MobileNav.test.tsx +15 -0
- package/src/MobileNav/MobileNav.tsx +9 -1
- package/src/MobileNav/__tests__/MobileNavHeader.a11y.chromium.spec.ts +89 -0
- package/src/MoreMenu/MoreMenu.test.tsx +11 -0
- package/src/MultiSelector/MultiSelector.spec.md +7 -4
- package/src/MultiSelector/MultiSelector.test.tsx +118 -1
- package/src/MultiSelector/MultiSelector.tsx +6 -2
- package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +8 -1
- package/src/NavMenu/NavHeadingMenu.spec.md +1 -5
- package/src/NumberInput/NumberInput.doc.mjs +13 -7
- package/src/NumberInput/NumberInput.spec.md +59 -37
- package/src/NumberInput/NumberInput.tsx +13 -3
- package/src/NumberInput/__tests__/NumberInput.coarse-pointer.a11y.chromium.spec.ts +102 -0
- package/src/NumberInput/numberParser.ts +7 -45
- package/src/ProgressBar/ProgressBar.test.tsx +108 -32
- package/src/ProgressBar/ProgressBar.tsx +58 -10
- package/src/ProgressBar/__tests__/ProgressBar.a11y.chromium.spec.ts +21 -9
- package/src/ProgressBar/__tests__/ProgressBarMotion.a11y.chromium.spec.ts +831 -0
- package/src/Resizable/__tests__/ResizeHandle.a11y.chromium.spec.ts +21 -14
- package/src/Resizable/useResizable.test.ts +43 -0
- package/src/Resizable/useResizable.ts +32 -9
- package/src/SegmentedControl/SegmentedControl.test.tsx +84 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +11 -5
- package/src/Selector/Selector.test.tsx +90 -1
- package/src/Selector/__tests__/Selector.combobox.a11y.test.tsx +8 -1
- package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +8 -1
- package/src/Selector/useSelectorPresentation.ts +31 -3
- package/src/SideNav/SideNav.test.tsx +27 -0
- package/src/SideNav/__tests__/SideNavRailMotion.interaction.browser.spec.ts +176 -51
- package/src/Slider/Slider.test.tsx +12 -0
- package/src/Slider/Slider.tsx +4 -1
- package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +19 -7
- package/src/Spinner/Spinner.tsx +2 -2
- package/src/Stack/Stack.tsx +1 -1
- package/src/Stack/StackItem.tsx +1 -1
- package/src/TabList/TabList.test.tsx +58 -4
- package/src/TabList/TabList.tsx +16 -1
- package/src/TabList/__tests__/TabPressPointer.interaction.browser.spec.ts +163 -0
- package/src/Table/__tests__/Table.a11y.chromium.spec.ts +18 -6
- package/src/Table/plugins/columnResize/useTableColumnResize.test.tsx +22 -0
- package/src/Table/plugins/columnResize/useTableColumnResize.tsx +8 -4
- package/src/Text/Text.tsx +1 -1
- package/src/Text/useTruncation.test.tsx +128 -1
- package/src/Text/useTruncation.ts +23 -5
- package/src/TextArea/TextArea.spec.md +10 -13
- package/src/TextArea/TextArea.test.tsx +60 -0
- package/src/TextArea/TextArea.tsx +15 -1
- package/src/TextInput/TextInput.test.tsx +21 -0
- package/src/TextInput/TextInput.tsx +3 -1
- package/src/TimeInput/NativeTimeInput.test.tsx +17 -0
- package/src/TimeInput/Presentation.test.tsx +21 -0
- package/src/TimeInput/TimeInput.doc.mjs +8 -8
- package/src/TimeInput/TimeInput.spec.md +45 -48
- package/src/TimeInput/TimeInput.test.tsx +76 -0
- package/src/TimeInput/TimeInput.tsx +36 -18
- package/src/TimeInput/TouchTimeField.tsx +4 -6
- package/src/Timestamp/Timestamp.spec.md +6 -12
- package/src/Timestamp/Timestamp.test.tsx +30 -5
- package/src/Timestamp/Timestamp.tsx +6 -2
- package/src/Timestamp/TimestampHoverCard.tsx +4 -4
- package/src/Toast/Toast.spec.md +14 -20
- package/src/Toast/Toast.tsx +104 -36
- package/src/Toast/ToastViewport.test.tsx +719 -1
- package/src/Toast/ToastViewport.tsx +100 -50
- package/src/Tokenizer/Tokenizer.spec.md +5 -3
- package/src/Tokenizer/Tokenizer.test.tsx +68 -0
- package/src/Tokenizer/Tokenizer.tsx +14 -2
- package/src/Tokenizer/TokenizerBottomSheet.test.tsx +15 -4
- package/src/Tokenizer/TokenizerBottomSheet.tsx +3 -3
- package/src/Toolbar/Toolbar.spec.md +5 -6
- package/src/Toolbar/Toolbar.test.tsx +30 -0
- package/src/Toolbar/Toolbar.tsx +2 -1
- package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +18 -6
- package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +18 -7
- package/src/TopNav/TopNav.test.tsx +27 -0
- package/src/Typeahead/Typeahead.test.tsx +40 -0
- package/src/Typeahead/Typeahead.tsx +12 -1
- package/src/gestures/GestureArena.ts +35 -0
- package/src/gestures/GestureHost.ts +2065 -0
- package/src/gestures/GestureRecognizer.ts +18 -0
- package/src/gestures/LongPressGestureRecognizer.ts +4 -0
- package/src/gestures/PanGestureRecognizer.ts +4 -0
- package/src/gestures/PinchGestureRecognizer.ts +148 -0
- package/src/gestures/ScreenEdgePanGestureRecognizer.ts +256 -0
- package/src/gestures/SwipeGestureRecognizer.ts +197 -0
- package/src/gestures/TapGestureRecognizer.ts +4 -0
- package/src/gestures/VelocityTracker.ts +10 -3
- package/src/gestures/__tests__/GestureHost.test.ts +2087 -0
- package/src/gestures/__tests__/PanGestureRecognizer.test.ts +4 -4
- package/src/gestures/__tests__/PinchGestureRecognizer.test.ts +74 -0
- package/src/gestures/__tests__/ScreenEdgePanGestureRecognizer.test.ts +498 -0
- package/src/gestures/__tests__/SwipeGestureRecognizer.test.ts +108 -0
- package/src/gestures/__tests__/arena.test.ts +5 -0
- package/src/gestures/__tests__/arenaPinchSwipeEdge.test.ts +193 -0
- package/src/gestures/__tests__/browser/build-fixture.mjs +46 -0
- package/src/gestures/__tests__/browser/fixture.ts +307 -0
- package/src/gestures/__tests__/browser/gestures.interaction.browser.spec.ts +1137 -0
- package/src/gestures/__tests__/browserNegotiation.test.ts +293 -0
- package/src/gestures/__tests__/haptics.test.ts +187 -0
- package/src/gestures/__tests__/harness.ts +21 -2
- package/src/gestures/__tests__/recognizerKind.test.ts +78 -0
- package/src/gestures/__tests__/touchActionRule.test.ts +54 -0
- package/src/gestures/haptics.ts +203 -0
- package/src/gestures/nativeScroll.ts +277 -0
- package/src/gestures/touchAction.ts +191 -0
- package/src/gestures/touchActionRule.ts +157 -0
- package/src/gestures/types.ts +30 -9
- package/src/hooks/useAdaptivePresentation.ts +4 -1
- package/src/hooks/useMenuHover.ts +15 -1
- package/src/i18n/generated-locales/en.generated.ts +4 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +4 -0
- package/src/motion/README.md +11 -1
- package/src/motion/animator.test.ts +151 -3
- package/src/motion/animator.ts +149 -33
- package/src/theme/defineTheme.ts +1 -1
- package/src/theme/derivedVarRegistry.test.ts +4 -0
- package/src/theme/domainTokens/domainTokenDefaults.ts +19 -0
- package/src/theme/domainTokens/index.ts +6 -10
- package/src/utils/focusReturn.ts +17 -6
- package/src/utils/getNodeText.test.ts +24 -0
- package/src/utils/getNodeText.ts +37 -0
- package/src/utils/interactionModality.test.ts +45 -1
- package/src/utils/interactionModality.ts +64 -5
- package/src/utils/plainDate.test.ts +90 -0
- package/src/utils/plainDate.ts +58 -3
- package/src/utils/presentation.test.ts +380 -0
- package/src/utils/presentation.ts +180 -0
- package/src/utils/pressPaintPriority.test.ts +80 -0
- package/src/utils/primaryClick.test.ts +38 -0
- package/src/utils/primaryClick.ts +28 -0
- package/src/utils/timeFormat.test.ts +204 -0
- package/src/utils/timeFormat.ts +314 -0
- package/src/utils/touchPresentation.stylex.ts +43 -0
- package/src/utils/touchPresentation.test.ts +140 -1
- package/src/utils/touchPresentation.ts +5 -3
- package/src/utils/unicodeDigits.test.ts +44 -0
- package/src/utils/unicodeDigits.ts +71 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file SwipeGestureRecognizer.test.ts
|
|
5
|
+
* @input Synthetic touches with explicit timestamps through a GestureArena
|
|
6
|
+
* @output SwipeGestureRecognizer's state machine: recognition during the motion, and failure when too slow, off-axis or the wrong way
|
|
7
|
+
* @position Unit tests of packages/core/src/gestures/SwipeGestureRecognizer.ts
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {describe, expect, it} from 'vitest';
|
|
11
|
+
import {SwipeGestureRecognizer} from '../SwipeGestureRecognizer';
|
|
12
|
+
import {createHarness} from './harness';
|
|
13
|
+
|
|
14
|
+
describe('SwipeGestureRecognizer', () => {
|
|
15
|
+
it('is recognized during the motion, once the distance is covered', () => {
|
|
16
|
+
const h = createHarness();
|
|
17
|
+
const swipe = new SwipeGestureRecognizer({name: 'swipe'});
|
|
18
|
+
const finger = h.finger(1).down(0, 0, 0, {recognizers: [swipe]});
|
|
19
|
+
finger.move(30, 2, 30);
|
|
20
|
+
expect(swipe.state).toBe('possible');
|
|
21
|
+
finger.move(50, 4, 50);
|
|
22
|
+
expect(swipe.recognizedDirection).toBe('right');
|
|
23
|
+
expect(h.log[0]).toBe('swipe:ended@50');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('fails when too slow, off-axis, or the wrong way', () => {
|
|
27
|
+
const slow = createHarness();
|
|
28
|
+
const a = new SwipeGestureRecognizer({name: 'a'});
|
|
29
|
+
slow
|
|
30
|
+
.finger(1)
|
|
31
|
+
.down(0, 0, 0, {recognizers: [a]})
|
|
32
|
+
.move(30, 0, 400);
|
|
33
|
+
slow.advance(500);
|
|
34
|
+
expect(a.state).toBe('failed');
|
|
35
|
+
|
|
36
|
+
const diagonal = createHarness();
|
|
37
|
+
const b = new SwipeGestureRecognizer({name: 'b'});
|
|
38
|
+
diagonal
|
|
39
|
+
.finger(1)
|
|
40
|
+
.down(0, 0, 0, {recognizers: [b]})
|
|
41
|
+
.move(45, 55, 60);
|
|
42
|
+
// 55 px across is past the 50 px secondary allowance.
|
|
43
|
+
expect(b.state).toBe('failed');
|
|
44
|
+
|
|
45
|
+
const wrong = createHarness();
|
|
46
|
+
const c = new SwipeGestureRecognizer({name: 'c', direction: 'left'});
|
|
47
|
+
wrong
|
|
48
|
+
.finger(1)
|
|
49
|
+
.down(100, 0, 0, {recognizers: [c]})
|
|
50
|
+
.move(160, 0, 60);
|
|
51
|
+
expect(c.state).toBe('failed');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('takes several directions and fingers', () => {
|
|
55
|
+
const h = createHarness();
|
|
56
|
+
const swipe = new SwipeGestureRecognizer({
|
|
57
|
+
name: 'swipe',
|
|
58
|
+
direction: ['up', 'down'],
|
|
59
|
+
numberOfTouchesRequired: 2,
|
|
60
|
+
});
|
|
61
|
+
h.finger(1).down(0, 200, 0, {recognizers: [swipe]});
|
|
62
|
+
h.finger(2).down(40, 200, 5, {recognizers: [swipe]});
|
|
63
|
+
h.finger(1).move(0, 140, 50);
|
|
64
|
+
h.finger(2).move(40, 140, 50);
|
|
65
|
+
expect(swipe.recognizedDirection).toBe('up');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('gives the same verdict for the same path however its events are spaced', () => {
|
|
69
|
+
// A straight drag to (55, 40): along 55 past the 50 px distance, 40 px
|
|
70
|
+
// across within the 50 px allowance.
|
|
71
|
+
const sparse = createHarness();
|
|
72
|
+
const a = new SwipeGestureRecognizer({name: 'a'});
|
|
73
|
+
sparse
|
|
74
|
+
.finger(1)
|
|
75
|
+
.down(0, 0, 0, {recognizers: [a]})
|
|
76
|
+
.move(55, 40, 40);
|
|
77
|
+
expect(a.state).toBe('ended');
|
|
78
|
+
|
|
79
|
+
const dense = createHarness();
|
|
80
|
+
const b = new SwipeGestureRecognizer({name: 'b'});
|
|
81
|
+
const finger = dense.finger(1).down(0, 0, 0, {recognizers: [b]});
|
|
82
|
+
for (let step = 1; step <= 10; step += 1) {
|
|
83
|
+
finger.move(5.5 * step, 4 * step, 4 * step);
|
|
84
|
+
}
|
|
85
|
+
expect(b.state).toBe('ended');
|
|
86
|
+
expect(b.recognizedDirection).toBe('right');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('recognizes a 40\u00b0 swipe at 16 px per event as at small steps', () => {
|
|
90
|
+
// At 40\u00b0 the travel along reaches 50 px with 42 px across, inside
|
|
91
|
+
// the 50 px allowance; at 16 px per event the next event is already 51 px
|
|
92
|
+
// across, so the verdict must come from the path between the events.
|
|
93
|
+
const angle = (40 * Math.PI) / 180;
|
|
94
|
+
for (const step of [2, 16]) {
|
|
95
|
+
const h = createHarness();
|
|
96
|
+
const swipe = new SwipeGestureRecognizer({name: 'swipe'});
|
|
97
|
+
const finger = h.finger(1).down(0, 0, 0, {recognizers: [swipe]});
|
|
98
|
+
for (let d = step, t = 4; d <= 96; d += step, t += 4) {
|
|
99
|
+
finger.move(d * Math.cos(angle), d * Math.sin(angle), t);
|
|
100
|
+
if (swipe.state !== 'possible') {
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
expect(swipe.state).toBe('ended');
|
|
105
|
+
expect(swipe.recognizedDirection).toBe('right');
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -39,6 +39,11 @@ interface Script {
|
|
|
39
39
|
* gesture ends with its last touch and a possible one fails.
|
|
40
40
|
*/
|
|
41
41
|
class Scripted extends GestureRecognizer {
|
|
42
|
+
// A discrete one decides at the lift, as a tap does.
|
|
43
|
+
override get kind(): GestureRecognizer['kind'] {
|
|
44
|
+
return this.discrete ? 'tap' : 'pan';
|
|
45
|
+
}
|
|
46
|
+
|
|
42
47
|
/** Expects more input after its touches lifted (a multi-tap between taps). */
|
|
43
48
|
isWaiting = false;
|
|
44
49
|
private readonly discrete: boolean;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file arenaPinchSwipeEdge.test.ts
|
|
5
|
+
* @input GestureArena with pinches, swipes, edge pans and pans, driven by
|
|
6
|
+
* synthetic touches with explicit timestamps
|
|
7
|
+
* @output Simultaneous recognition (pinch + pan), the first to recognize
|
|
8
|
+
* winning without permission, edge pan vs inner pan, swipe vs pan, and a
|
|
9
|
+
* delayed touch delivery
|
|
10
|
+
* @position Unit tests of packages/core/src/gestures/GestureArena.ts
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {describe, expect, it} from 'vitest';
|
|
14
|
+
import {UIKIT_PINCH, UIKIT_SWIPE} from '../../motion/uikit/gestures';
|
|
15
|
+
import {GestureRecognizer} from '../GestureRecognizer';
|
|
16
|
+
import {PanGestureRecognizer} from '../PanGestureRecognizer';
|
|
17
|
+
import {PinchGestureRecognizer} from '../PinchGestureRecognizer';
|
|
18
|
+
import {ScreenEdgePanGestureRecognizer} from '../ScreenEdgePanGestureRecognizer';
|
|
19
|
+
import {SwipeGestureRecognizer} from '../SwipeGestureRecognizer';
|
|
20
|
+
import {createHarness, RecordingConsumer} from './harness';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A recognizer that stays possible, even past its finger's lift, until the
|
|
24
|
+
* test fails it: something another recognizer can wait on.
|
|
25
|
+
*/
|
|
26
|
+
class Held extends GestureRecognizer {
|
|
27
|
+
// Possible until failed, as a tap waiting for its next tap.
|
|
28
|
+
override get kind(): GestureRecognizer['kind'] {
|
|
29
|
+
return 'tap';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private isWaiting = true;
|
|
33
|
+
|
|
34
|
+
override isInvolved(): boolean {
|
|
35
|
+
return super.isInvolved() || this.isWaiting;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
fail(): void {
|
|
39
|
+
this.isWaiting = false;
|
|
40
|
+
this.setState('failed');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe('conflict matrix', () => {
|
|
45
|
+
it('pinch + pan recognize simultaneously when allowed', () => {
|
|
46
|
+
const h = createHarness();
|
|
47
|
+
const pinch = new PinchGestureRecognizer({name: 'pinch'});
|
|
48
|
+
const pan = new PanGestureRecognizer({name: 'pan'});
|
|
49
|
+
pinch.recognizeSimultaneouslyWith(pan);
|
|
50
|
+
h.finger(1).down(100, 100, 0, {recognizers: [pinch, pan]});
|
|
51
|
+
h.finger(2).down(200, 100, 0, {recognizers: [pinch, pan]});
|
|
52
|
+
h.finger(1).move(80, 120, 16);
|
|
53
|
+
h.finger(2).move(240, 120, 16);
|
|
54
|
+
expect(h.log.slice(0, 2)).toEqual(['pinch:began@16', 'pan:began@16']);
|
|
55
|
+
// Span 100 -> 160, measured against 100 + 8.
|
|
56
|
+
expect(pinch.scale).toBeCloseTo(160 / 108, 5);
|
|
57
|
+
// The pan began at the first finger's move, centroid (-10, 10), which
|
|
58
|
+
// the hysteresis swallows; the second finger's move brought it to (10, 20).
|
|
59
|
+
expect(pan.translation()).toEqual({x: 20, y: 10});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('pinch vs pan without permission: the first to recognize wins', () => {
|
|
63
|
+
const h = createHarness();
|
|
64
|
+
const pinch = new PinchGestureRecognizer({name: 'pinch'});
|
|
65
|
+
const pan = new PanGestureRecognizer({name: 'pan'});
|
|
66
|
+
h.finger(1).down(100, 100, 0, {recognizers: [pinch, pan]});
|
|
67
|
+
h.finger(2).down(200, 100, 0, {recognizers: [pinch, pan]});
|
|
68
|
+
h.finger(1).move(80, 120, 16);
|
|
69
|
+
h.finger(2).move(240, 120, 16);
|
|
70
|
+
expect(h.log.slice(0, 2)).toEqual(['pinch:began@16', 'pan:failed@16']);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('edge pan vs inner pan: in the band the edge pan wins, elsewhere the inner pan runs undelayed', () => {
|
|
74
|
+
const band = createHarness();
|
|
75
|
+
const edge = new ScreenEdgePanGestureRecognizer({name: 'edge'});
|
|
76
|
+
const inner = new PanGestureRecognizer({
|
|
77
|
+
name: 'inner',
|
|
78
|
+
direction: 'horizontal',
|
|
79
|
+
});
|
|
80
|
+
inner.requireToFail(edge);
|
|
81
|
+
// A thin edge view: the edge zone, where the pan takes its axis.
|
|
82
|
+
band.environment.view = {width: edge.edgeRegion, height: 844};
|
|
83
|
+
band.finger(1).down(8, 300, 0, {recognizers: [inner, edge]});
|
|
84
|
+
band.finger(1).drag(60, 2, 60, 6);
|
|
85
|
+
// The edge pan's own hysteresis is 15 px: the second 10 px step.
|
|
86
|
+
expect(band.log.slice(0, 2)).toEqual(['edge:began@20', 'inner:failed@20']);
|
|
87
|
+
|
|
88
|
+
const middle = createHarness();
|
|
89
|
+
const edge2 = new ScreenEdgePanGestureRecognizer({name: 'edge'});
|
|
90
|
+
const inner2 = new PanGestureRecognizer({
|
|
91
|
+
name: 'inner',
|
|
92
|
+
direction: 'horizontal',
|
|
93
|
+
});
|
|
94
|
+
inner2.requireToFail(edge2);
|
|
95
|
+
middle.finger(1).down(150, 300, 0, {recognizers: [inner2, edge2]});
|
|
96
|
+
// Failed at touch-down, before any movement: nothing waits on it.
|
|
97
|
+
expect(middle.log).toEqual(['edge:failed@0']);
|
|
98
|
+
middle.finger(1).drag(60, 2, 60, 6);
|
|
99
|
+
expect(middle.log[1]).toBe('inner:began@10');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('swipe vs pan: the pan wins by default, the swipe when the pan requires it to fail', () => {
|
|
103
|
+
const plain = createHarness();
|
|
104
|
+
const swipe = new SwipeGestureRecognizer({name: 'swipe'});
|
|
105
|
+
const pan = new PanGestureRecognizer({name: 'pan'});
|
|
106
|
+
plain
|
|
107
|
+
.finger(1)
|
|
108
|
+
.down(0, 0, 0, {recognizers: [swipe, pan]})
|
|
109
|
+
.drag(80, 0, 60, 6);
|
|
110
|
+
expect(plain.log.slice(0, 2)).toEqual(['pan:began@10', 'swipe:failed@10']);
|
|
111
|
+
|
|
112
|
+
const ordered = createHarness();
|
|
113
|
+
const swipe2 = new SwipeGestureRecognizer({name: 'swipe'});
|
|
114
|
+
const pan2 = new PanGestureRecognizer({name: 'pan'});
|
|
115
|
+
pan2.requireToFail(swipe2);
|
|
116
|
+
ordered
|
|
117
|
+
.finger(1)
|
|
118
|
+
.down(0, 0, 0, {recognizers: [swipe2, pan2]})
|
|
119
|
+
.drag(80, 0, 60, 8);
|
|
120
|
+
expect(ordered.log.slice(0, 2)).toEqual([
|
|
121
|
+
'swipe:ended@37.5',
|
|
122
|
+
'pan:failed@37.5',
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
const slow = createHarness();
|
|
126
|
+
const swipe3 = new SwipeGestureRecognizer({name: 'swipe'});
|
|
127
|
+
const pan3 = new PanGestureRecognizer({name: 'pan'});
|
|
128
|
+
pan3.requireToFail(swipe3);
|
|
129
|
+
slow
|
|
130
|
+
.finger(1)
|
|
131
|
+
.down(0, 0, 0, {recognizers: [swipe3, pan3]})
|
|
132
|
+
.drag(30, 0, 300, 3);
|
|
133
|
+
expect(pan3.state).toBe('possible');
|
|
134
|
+
slow.advance(500);
|
|
135
|
+
// The swipe ran out of time; the waiting pan begins with what it has.
|
|
136
|
+
expect(slow.log.slice(0, 2)).toEqual(['swipe:failed@500', 'pan:began@500']);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('a recognizer waiting on another', () => {
|
|
141
|
+
it('a swipe holds its recognition past its lift and its deadline (spec:AST-094 FR15)', () => {
|
|
142
|
+
const h = createHarness();
|
|
143
|
+
const held = new Held({name: 'held'});
|
|
144
|
+
const swipe = new SwipeGestureRecognizer({name: 'swipe'});
|
|
145
|
+
swipe.requireToFail(held);
|
|
146
|
+
h.finger(1)
|
|
147
|
+
.down(0, 0, 0, {recognizers: [swipe, held]})
|
|
148
|
+
.drag(80, 0, 60, 8)
|
|
149
|
+
.up(70);
|
|
150
|
+
h.advance(UIKIT_SWIPE.maximumDuration.value + 100);
|
|
151
|
+
expect(swipe.state).toBe('possible');
|
|
152
|
+
expect(h.log.some(entry => entry.startsWith('swipe:failed'))).toBe(false);
|
|
153
|
+
held.fail();
|
|
154
|
+
expect(h.log).toContain(
|
|
155
|
+
`swipe:ended@${UIKIT_SWIPE.maximumDuration.value + 100}`,
|
|
156
|
+
);
|
|
157
|
+
expect(swipe.recognizedDirection).toBe('right');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('a pinch keeps its start once it passes the hysteresis, so it begins at the scale its fingers show (spec:AST-094 FR15)', () => {
|
|
161
|
+
const h = createHarness();
|
|
162
|
+
const held = new Held({name: 'held'});
|
|
163
|
+
const pinch = new PinchGestureRecognizer({name: 'pinch'});
|
|
164
|
+
pinch.requireToFail(held);
|
|
165
|
+
h.finger(1).down(100, 100, 0, {recognizers: [pinch, held]});
|
|
166
|
+
h.finger(2).down(200, 100, 0, {recognizers: [pinch, held]});
|
|
167
|
+
// Span 100 -> 120 -> 140 -> 160 while the pinch waits.
|
|
168
|
+
h.finger(2).move(220, 100, 16);
|
|
169
|
+
h.finger(2).move(240, 100, 32);
|
|
170
|
+
h.finger(2).move(260, 100, 48);
|
|
171
|
+
expect(pinch.state).toBe('possible');
|
|
172
|
+
held.fail();
|
|
173
|
+
expect(h.log).toContain('pinch:began@48');
|
|
174
|
+
// Measured against 100 + 8 once, not re-based on every move.
|
|
175
|
+
const hysteresis = UIKIT_PINCH.hysteresis.value;
|
|
176
|
+
expect(pinch.scale).toBeCloseTo(160 / (100 + hysteresis), 5);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe('delivery to the view', () => {
|
|
181
|
+
it('holds the began with delaysTouchesBegan until the recognizer fails', () => {
|
|
182
|
+
const h = createHarness();
|
|
183
|
+
const consumer = new RecordingConsumer();
|
|
184
|
+
const swipe = new SwipeGestureRecognizer({
|
|
185
|
+
name: 'swipe',
|
|
186
|
+
delaysTouchesBegan: true,
|
|
187
|
+
});
|
|
188
|
+
h.finger(1).down(0, 0, 0, {recognizers: [swipe], consumer});
|
|
189
|
+
expect(consumer.events).toEqual([]);
|
|
190
|
+
h.advance(UIKIT_SWIPE.maximumDuration.value);
|
|
191
|
+
expect(consumer.events).toEqual(['began:1']);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @file build-fixture.mjs
|
|
6
|
+
* @input fixture.ts beside this file
|
|
7
|
+
* @output A standalone HTML page (the fixture bundled inline) for running the
|
|
8
|
+
* gesture proofs in any browser, including Mobile Safari on the iOS
|
|
9
|
+
* simulator
|
|
10
|
+
* @position Test-only helper of packages/core/src/gestures
|
|
11
|
+
*
|
|
12
|
+
* node packages/core/src/gestures/__tests__/browser/build-fixture.mjs out.html
|
|
13
|
+
*
|
|
14
|
+
* The page records every recognizer transition and every click on
|
|
15
|
+
* `window.__gestures`; read it with the Web Inspector or by evaluating
|
|
16
|
+
* `JSON.stringify(window.__gestures)`.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import fs from 'node:fs';
|
|
20
|
+
import path from 'node:path';
|
|
21
|
+
import {fileURLToPath} from 'node:url';
|
|
22
|
+
import {build} from 'esbuild';
|
|
23
|
+
|
|
24
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
const out = process.argv[2];
|
|
26
|
+
if (out == null) {
|
|
27
|
+
console.error('usage: build-fixture.mjs <out.html>');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
const result = await build({
|
|
31
|
+
entryPoints: [path.join(here, 'fixture.ts')],
|
|
32
|
+
bundle: true,
|
|
33
|
+
write: false,
|
|
34
|
+
format: 'iife',
|
|
35
|
+
platform: 'browser',
|
|
36
|
+
target: 'es2022',
|
|
37
|
+
});
|
|
38
|
+
const html = `<!doctype html>
|
|
39
|
+
<meta charset="utf-8">
|
|
40
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
41
|
+
<title>Gesture fixture</title>
|
|
42
|
+
<body></body>
|
|
43
|
+
<script>${result.outputFiles[0].text.replaceAll('</script', '<\\/script')}</script>
|
|
44
|
+
`;
|
|
45
|
+
fs.writeFileSync(out, html);
|
|
46
|
+
console.log(`wrote ${out} (${html.length} bytes)`);
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file fixture.ts
|
|
5
|
+
* @input Nothing: bundled by esbuild and injected into a blank page
|
|
6
|
+
* @output A page of gesture hosts (a horizontal pan inside a scroller, a tap
|
|
7
|
+
* target, a long press, a pinch, a sheet body that hands its scroll to a
|
|
8
|
+
* pan, a passive control: a press consumer under `pan-y` with no
|
|
9
|
+
* recognizer, pans and a long press under narrower author `touch-action`
|
|
10
|
+
* values, and leading screen-edge pans on an edge-zone strip and on a wider
|
|
11
|
+
* element, left to right and right to left) that records every recognizer
|
|
12
|
+
* transition, every consumer event and every click on `window.__gestures`
|
|
13
|
+
* @position Browser fixture of gestures.interaction.browser.spec.ts;
|
|
14
|
+
* test-only
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {getGestureHost} from '../../GestureHost';
|
|
18
|
+
import type {GestureRecognizer} from '../../GestureRecognizer';
|
|
19
|
+
import {LongPressGestureRecognizer} from '../../LongPressGestureRecognizer';
|
|
20
|
+
import {PanGestureRecognizer} from '../../PanGestureRecognizer';
|
|
21
|
+
import {PinchGestureRecognizer} from '../../PinchGestureRecognizer';
|
|
22
|
+
import {ScreenEdgePanGestureRecognizer} from '../../ScreenEdgePanGestureRecognizer';
|
|
23
|
+
import {TapGestureRecognizer} from '../../TapGestureRecognizer';
|
|
24
|
+
|
|
25
|
+
interface Entry {
|
|
26
|
+
name: string;
|
|
27
|
+
state: string;
|
|
28
|
+
time: number;
|
|
29
|
+
x?: number;
|
|
30
|
+
y?: number;
|
|
31
|
+
scale?: number;
|
|
32
|
+
beganAt?: number | null;
|
|
33
|
+
startedAt?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface ListenerEntry {
|
|
37
|
+
id: string;
|
|
38
|
+
type: string;
|
|
39
|
+
passive: boolean | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
declare global {
|
|
43
|
+
interface Window {
|
|
44
|
+
__gestures: Entry[];
|
|
45
|
+
__listeners: ListenerEntry[];
|
|
46
|
+
/** The page-level (document and window) listeners now added, by type. */
|
|
47
|
+
__pageListeners: Map<string, number>;
|
|
48
|
+
/** The page-level listener types the attachments below added. */
|
|
49
|
+
__attachListeners: string[];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
window.__gestures = [];
|
|
54
|
+
|
|
55
|
+
// Every touch listener added to an element with an id, as the engine sees
|
|
56
|
+
// it: which elements make a scroll wait for the page.
|
|
57
|
+
window.__listeners = [];
|
|
58
|
+
// And every listener on the document or the window, added and removed: what
|
|
59
|
+
// gesture work costs the page between presses (spec:AST-094 FR24).
|
|
60
|
+
window.__pageListeners = new Map();
|
|
61
|
+
const isPage = (target: EventTarget) =>
|
|
62
|
+
target === document || target === window;
|
|
63
|
+
const addListener = EventTarget.prototype.addEventListener;
|
|
64
|
+
EventTarget.prototype.addEventListener = function (
|
|
65
|
+
this: EventTarget,
|
|
66
|
+
type: string,
|
|
67
|
+
listener: EventListenerOrEventListenerObject | null,
|
|
68
|
+
options?: boolean | AddEventListenerOptions,
|
|
69
|
+
) {
|
|
70
|
+
if (this instanceof Element && this.id !== '' && type.startsWith('touch')) {
|
|
71
|
+
window.__listeners.push({
|
|
72
|
+
id: this.id,
|
|
73
|
+
type,
|
|
74
|
+
passive: typeof options === 'object' ? (options.passive ?? null) : null,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (isPage(this) && listener != null) {
|
|
78
|
+
window.__pageListeners.set(
|
|
79
|
+
type,
|
|
80
|
+
(window.__pageListeners.get(type) ?? 0) + 1,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
addListener.call(this, type, listener, options);
|
|
84
|
+
};
|
|
85
|
+
const removeListener = EventTarget.prototype.removeEventListener;
|
|
86
|
+
EventTarget.prototype.removeEventListener = function (
|
|
87
|
+
this: EventTarget,
|
|
88
|
+
type: string,
|
|
89
|
+
listener: EventListenerOrEventListenerObject | null,
|
|
90
|
+
options?: boolean | EventListenerOptions,
|
|
91
|
+
) {
|
|
92
|
+
if (isPage(this) && listener != null) {
|
|
93
|
+
window.__pageListeners.set(
|
|
94
|
+
type,
|
|
95
|
+
(window.__pageListeners.get(type) ?? 0) - 1,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
removeListener.call(this, type, listener, options);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
document.body.style.margin = '0';
|
|
102
|
+
document.body.innerHTML = `
|
|
103
|
+
<div id="page" style="font: 14px sans-serif">
|
|
104
|
+
<div id="scroller" style="height: 240px; overflow-y: auto; overscroll-behavior: contain; background: #eef">
|
|
105
|
+
<div style="height: 40px">scroller</div>
|
|
106
|
+
<div id="hpan" style="height: 140px; background: #ccd">
|
|
107
|
+
<button id="hbutton" style="width: 200px; height: 80px; margin: 30px">button</button>
|
|
108
|
+
</div>
|
|
109
|
+
<div id="scrollRow" style="height: 60px; background: #ece; touch-action: none">row (a press in the scroller)</div>
|
|
110
|
+
<div style="height: 1200px">content</div>
|
|
111
|
+
</div>
|
|
112
|
+
<div id="tapper" style="height: 60px; background: #efe">tap</div>
|
|
113
|
+
<div id="presser" style="height: 60px; background: #fee">press</div>
|
|
114
|
+
<div id="pinchable" style="height: 160px; background: #ffe">pinch</div>
|
|
115
|
+
<div id="sheetBody" style="height: 240px; overflow-y: auto; overscroll-behavior: contain; background: #eee">
|
|
116
|
+
<div style="height: 1200px">sheet content</div>
|
|
117
|
+
</div>
|
|
118
|
+
<div id="passive" style="height: 60px; background: #dfd; touch-action: pan-y pinch-zoom">passive control</div>
|
|
119
|
+
<div id="card" style="height: 80px; background: #def">card (swipe up)</div>
|
|
120
|
+
<style>
|
|
121
|
+
.author-none { touch-action: none; }
|
|
122
|
+
.author-pan-y { touch-action: pan-y; }
|
|
123
|
+
.author-pinch-zoom { touch-action: pinch-zoom; }
|
|
124
|
+
.author-pan-xy { touch-action: pan-x pan-y; }
|
|
125
|
+
</style>
|
|
126
|
+
<div id="authorNone" class="author-none" style="height: 60px; background: #fdd">author none</div>
|
|
127
|
+
<div id="authorPanY" class="author-pan-y" style="height: 60px; background: #dfd">author pan-y</div>
|
|
128
|
+
<div id="authorPinchZoom" class="author-pinch-zoom" style="height: 60px; background: #ffd">author pinch-zoom</div>
|
|
129
|
+
<div id="authorPanXY" class="author-pan-xy" style="height: 60px; background: #ddf">author pan-x pan-y</div>
|
|
130
|
+
<div id="inlinePanXY" style="height: 60px; background: #fdf; touch-action: pan-x pan-y">inline pan-x pan-y</div>
|
|
131
|
+
<div id="edgeZone" style="width: 40px; height: 120px; background: #fcf">edge</div>
|
|
132
|
+
<div id="edgeWide" style="width: 200px; height: 120px; overflow-x: auto; background: #cff">
|
|
133
|
+
<div style="width: 800px; height: 100px">wider than the band</div>
|
|
134
|
+
</div>
|
|
135
|
+
<div dir="rtl">
|
|
136
|
+
<div id="edgeZoneRtl" style="width: 40px; height: 120px; background: #fcf">edge</div>
|
|
137
|
+
<div id="edgeWideRtl" style="width: 200px; height: 120px; overflow-x: auto; background: #cff">
|
|
138
|
+
<div style="width: 800px; height: 100px">wider than the band</div>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
<div style="height: 1600px">page</div>
|
|
142
|
+
<div id="passiveEnd" style="height: 60px; background: #dfd; touch-action: pan-y pinch-zoom">passive control at the page's end</div>
|
|
143
|
+
</div>`;
|
|
144
|
+
|
|
145
|
+
function element(id: string): HTMLElement {
|
|
146
|
+
const found = document.getElementById(id);
|
|
147
|
+
if (found == null) {
|
|
148
|
+
throw new Error(`missing #${id}`);
|
|
149
|
+
}
|
|
150
|
+
return found;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const beforeAttach = new Map(window.__pageListeners);
|
|
154
|
+
const host = getGestureHost(document);
|
|
155
|
+
|
|
156
|
+
function record(recognizer: GestureRecognizer, extra: () => Partial<Entry>) {
|
|
157
|
+
recognizer.addTransitionListener((current, _from, to) => {
|
|
158
|
+
window.__gestures.push({
|
|
159
|
+
name: current.name,
|
|
160
|
+
state: to,
|
|
161
|
+
time: current.arena?.now() ?? performance.now(),
|
|
162
|
+
...(to === 'possible' || to === 'failed' ? {} : extra()),
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const hpan = new PanGestureRecognizer({name: 'hpan', direction: 'horizontal'});
|
|
168
|
+
record(hpan, () => ({x: hpan.translation().x, y: hpan.translation().y}));
|
|
169
|
+
host.attach(element('hpan'), hpan);
|
|
170
|
+
|
|
171
|
+
const tap = new TapGestureRecognizer({name: 'tap'});
|
|
172
|
+
record(tap, () => ({}));
|
|
173
|
+
host.attach(element('tapper'), tap);
|
|
174
|
+
|
|
175
|
+
const press = new LongPressGestureRecognizer({name: 'press'});
|
|
176
|
+
record(press, () => ({
|
|
177
|
+
beganAt: press.beganAt,
|
|
178
|
+
startedAt: press.trackedTouches[0]?.startTime,
|
|
179
|
+
}));
|
|
180
|
+
host.attach(element('presser'), press);
|
|
181
|
+
|
|
182
|
+
const pinch = new PinchGestureRecognizer({name: 'pinch'});
|
|
183
|
+
const pinchPan = new PanGestureRecognizer({
|
|
184
|
+
name: 'pinchPan',
|
|
185
|
+
maximumNumberOfTouches: 2,
|
|
186
|
+
});
|
|
187
|
+
pinch.recognizeSimultaneouslyWith(pinchPan);
|
|
188
|
+
record(pinch, () => ({scale: pinch.scale}));
|
|
189
|
+
record(pinchPan, () => ({x: pinchPan.translation().x}));
|
|
190
|
+
host.attach(element('pinchable'), pinch);
|
|
191
|
+
host.attach(element('pinchable'), pinchPan);
|
|
192
|
+
|
|
193
|
+
const sheet = new PanGestureRecognizer({
|
|
194
|
+
name: 'sheet',
|
|
195
|
+
direction: 'down',
|
|
196
|
+
scrollEdge: true,
|
|
197
|
+
});
|
|
198
|
+
record(sheet, () => ({y: sheet.translation().y}));
|
|
199
|
+
host.attach(element('sheetBody'), sheet);
|
|
200
|
+
|
|
201
|
+
// A one-way pan over the scrollable page, as a toast's upward swipe is: it
|
|
202
|
+
// claims its touch as it begins, at UIKit's 10 pt (spec:AST-094 FR19).
|
|
203
|
+
const card = new PanGestureRecognizer({name: 'card', direction: 'up'});
|
|
204
|
+
record(card, () => ({x: card.translation().x, y: card.translation().y}));
|
|
205
|
+
host.attach(element('card'), card);
|
|
206
|
+
|
|
207
|
+
// Narrower author touch-action (spec:AST-094 FR18, DEC-8): the host's value
|
|
208
|
+
// is the derived one intersected with the author's, never wider.
|
|
209
|
+
const authorNone = new LongPressGestureRecognizer({name: 'authorNone'});
|
|
210
|
+
record(authorNone, () => ({}));
|
|
211
|
+
host.attach(element('authorNone'), authorNone);
|
|
212
|
+
for (const id of [
|
|
213
|
+
'authorPanY',
|
|
214
|
+
'authorPinchZoom',
|
|
215
|
+
'authorPanXY',
|
|
216
|
+
'inlinePanXY',
|
|
217
|
+
]) {
|
|
218
|
+
const pan = new PanGestureRecognizer({name: id, direction: 'horizontal'});
|
|
219
|
+
record(pan, () => ({x: pan.translation().x}));
|
|
220
|
+
host.attach(element(id), pan);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Leading screen-edge pans (FR18, DEC-13): on an edge-zone strip within the
|
|
224
|
+
// 40.2 px band and on an element reaching beyond it, left to right and, with
|
|
225
|
+
// the leading edge on the right, right to left.
|
|
226
|
+
for (const id of ['edgeZone', 'edgeWide', 'edgeZoneRtl', 'edgeWideRtl']) {
|
|
227
|
+
const edge = new ScreenEdgePanGestureRecognizer({
|
|
228
|
+
name: id,
|
|
229
|
+
edges: ['leading'],
|
|
230
|
+
});
|
|
231
|
+
record(edge, () => ({x: edge.translation().x}));
|
|
232
|
+
host.attach(element(id), edge);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// A control with no recognizer of its own (no blocking listener): only a
|
|
236
|
+
// press consumer, under pan-y, as a passive switch is.
|
|
237
|
+
const passiveEvent = (state: string) =>
|
|
238
|
+
window.__gestures.push({name: 'passive', state, time: performance.now()});
|
|
239
|
+
host.attachConsumer(element('passive'), {
|
|
240
|
+
touchBegan: () => passiveEvent('began'),
|
|
241
|
+
touchMoved: () => passiveEvent('moved'),
|
|
242
|
+
touchEnded: () => passiveEvent('ended'),
|
|
243
|
+
touchCancelled: () => passiveEvent('cancelled'),
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// The same control at the very end of the page, where a page scrolled to its
|
|
247
|
+
// end has no room to scroll on: what ends its press is the signal FR20
|
|
248
|
+
// counts there.
|
|
249
|
+
const passiveEndEvent = (state: string) =>
|
|
250
|
+
window.__gestures.push({name: 'passiveEnd', state, time: performance.now()});
|
|
251
|
+
host.attachConsumer(element('passiveEnd'), {
|
|
252
|
+
touchBegan: () => passiveEndEvent('began'),
|
|
253
|
+
touchMoved: () => passiveEndEvent('moved'),
|
|
254
|
+
touchEnded: () => passiveEndEvent('ended'),
|
|
255
|
+
touchCancelled: () => passiveEndEvent('cancelled'),
|
|
256
|
+
});
|
|
257
|
+
// Which browser signal arrives, in order with the presses it ends: on the
|
|
258
|
+
// window, whose capture listeners run before the host's on the document.
|
|
259
|
+
addListener.call(
|
|
260
|
+
window,
|
|
261
|
+
'pointercancel',
|
|
262
|
+
event => {
|
|
263
|
+
if ((event as PointerEvent).pointerType === 'touch') {
|
|
264
|
+
window.__gestures.push({
|
|
265
|
+
name: 'dom:pointercancel',
|
|
266
|
+
state: 'dom',
|
|
267
|
+
time: performance.now(),
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
true,
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
// The fixture's own loggers go around the count of page listeners.
|
|
275
|
+
// A press consumer inside the scroller, as a list row is: a scroll of the
|
|
276
|
+
// scroller takes its press only once the finger has moved the take distance
|
|
277
|
+
// (FR20). `touch-action: none` keeps the browser's own pan out of it, so the
|
|
278
|
+
// only scroll is the one the test makes.
|
|
279
|
+
const rowEvent = (state: string) =>
|
|
280
|
+
window.__gestures.push({name: 'scrollRow', state, time: performance.now()});
|
|
281
|
+
host.attachConsumer(element('scrollRow'), {
|
|
282
|
+
touchBegan: () => rowEvent('began'),
|
|
283
|
+
touchMoved: () => rowEvent('moved'),
|
|
284
|
+
touchEnded: () => rowEvent('ended'),
|
|
285
|
+
touchCancelled: () => rowEvent('cancelled'),
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
for (const type of ['click', 'mousedown']) {
|
|
289
|
+
addListener.call(
|
|
290
|
+
document,
|
|
291
|
+
type,
|
|
292
|
+
event => {
|
|
293
|
+
const target = event.target as HTMLElement | null;
|
|
294
|
+
window.__gestures.push({
|
|
295
|
+
name: `${type}:${target?.id ?? ''}`,
|
|
296
|
+
state: 'dom',
|
|
297
|
+
time: event.timeStamp,
|
|
298
|
+
});
|
|
299
|
+
},
|
|
300
|
+
true,
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
window.__attachListeners = [...window.__pageListeners]
|
|
305
|
+
.filter(([type, count]) => count > (beforeAttach.get(type) ?? 0))
|
|
306
|
+
.map(([type]) => type)
|
|
307
|
+
.sort();
|