@astryxdesign/core 0.7.5 → 0.7.6-canary.0ef60dd
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/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +37 -4
- 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 +7 -3
- package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -1
- package/dist/DropdownMenu/MenuBottomSheetActionList.js +6 -5
- package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +20 -2
- package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -1
- package/dist/DropdownMenu/lazyMenuBottomSheet.js +31 -3
- 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/Layer/popoverOperations.d.ts +27 -0
- package/dist/Layer/popoverOperations.d.ts.map +1 -0
- package/dist/Layer/popoverOperations.js +159 -0
- package/dist/Layer/useLayer.d.ts +1 -1
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +93 -59
- 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/CreateRow.a11y.chromium.spec.js +7 -6
- package/dist/MultiSelector/MultiSelector.d.ts +1 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +26 -10
- 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/Skeleton/Skeleton.d.ts.map +1 -1
- package/dist/Skeleton/Skeleton.js +1 -1
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +10 -2
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +3 -3
- 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/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +3 -0
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +1 -0
- 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 +20 -4
- 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/index.d.ts +1 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/modalAnnounce.d.ts.map +1 -1
- package/dist/hooks/modalAnnounce.js +107 -61
- package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -1
- package/dist/hooks/useAdaptivePresentation.js +4 -1
- package/dist/hooks/useAnnounce.d.ts +101 -42
- package/dist/hooks/useAnnounce.d.ts.map +1 -1
- package/dist/hooks/useAnnounce.js +161 -75
- package/dist/hooks/useAnnounceRenderedText.d.ts +11 -3
- package/dist/hooks/useAnnounceRenderedText.d.ts.map +1 -1
- package/dist/hooks/useAnnounceRenderedText.js +5 -3
- package/dist/hooks/useBusyAnnouncement.d.ts.map +1 -1
- package/dist/hooks/useBusyAnnouncement.js +6 -12
- 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 +5 -0
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +5 -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.d.ts +19 -5
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +64 -4
- 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/theme/index.d.ts +1 -0
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/motionKnobs.d.ts +56 -0
- package/dist/theme/motionKnobs.d.ts.map +1 -0
- package/dist/theme/motionKnobs.js +48 -0
- package/dist/theme/resolveThemeValues.d.ts +11 -4
- package/dist/theme/resolveThemeValues.d.ts.map +1 -1
- package/dist/theme/resolveThemeValues.js +40 -4
- package/dist/theme/themeAdaptations.d.ts +7 -3
- package/dist/theme/themeAdaptations.d.ts.map +1 -1
- package/dist/theme/themeAdaptations.js +36 -7
- package/dist/theme/themeMotion.d.ts +96 -0
- package/dist/theme/themeMotion.d.ts.map +1 -0
- package/dist/theme/themeMotion.js +177 -0
- package/dist/theme/tokenReferences.d.ts +31 -0
- package/dist/theme/tokenReferences.d.ts.map +1 -0
- package/dist/theme/tokenReferences.js +132 -0
- package/dist/theme/tokens.d.ts +1 -0
- package/dist/theme/tokens.d.ts.map +1 -1
- package/dist/theme/tokens.js +9 -129
- package/dist/theme/tokens.stylex.d.ts +12 -0
- package/dist/theme/tokens.stylex.d.ts.map +1 -1
- package/dist/theme/tokens.stylex.js +12 -0
- 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/interactionOverlay.stylex.d.ts.map +1 -1
- package/dist/utils/interactionOverlay.stylex.js +17 -8
- 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/pressFeedback.d.ts.map +1 -1
- package/dist/utils/pressFeedback.js +20 -1
- 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 +23 -3
- package/locales/pseudo.json +15 -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/ClickableCard/ClickableCard.test.tsx +96 -0
- package/src/ClickableCard/ClickableCard.tsx +48 -4
- 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 +10 -3
- 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 +60 -0
- package/src/DropdownMenu/lazyMenuBottomSheet.ts +36 -7
- 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/Kbd/Kbd.spec.md +81 -38
- package/src/Layer/__tests__/LayerBrowserHide.a11y.chromium.spec.ts +126 -0
- package/src/Layer/popoverOperations.test.ts +205 -0
- package/src/Layer/popoverOperations.ts +172 -0
- package/src/Layer/useLayer.test.tsx +348 -1
- package/src/Layer/useLayer.tsx +118 -71
- 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/MetadataList/MetadataList.spec.md +187 -0
- package/src/MetadataList/MetadataListItem.spec.md +165 -0
- 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/CreateRow.a11y.chromium.spec.ts +7 -8
- package/src/MultiSelector/MultiSelector.spec.md +7 -4
- package/src/MultiSelector/MultiSelector.test.tsx +270 -1
- package/src/MultiSelector/MultiSelector.tsx +25 -10
- 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/Skeleton/Skeleton.tsx +3 -1
- package/src/Slider/Slider.test.tsx +31 -0
- package/src/Slider/Slider.tsx +8 -3
- package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +19 -7
- package/src/Spinner/Spinner.tsx +5 -3
- 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/TopNav/TopNavMegaMenu.test.tsx +21 -0
- package/src/TopNav/TopNavMegaMenu.tsx +4 -1
- package/src/TopNav/TopNavMenu.test.tsx +17 -0
- package/src/TopNav/TopNavMenu.tsx +1 -0
- package/src/Typeahead/Typeahead.test.tsx +40 -0
- package/src/Typeahead/Typeahead.tsx +12 -1
- package/src/__tests__/pressState.ts +8 -4
- 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/index.ts +5 -1
- package/src/hooks/modalAnnounce.ts +129 -72
- package/src/hooks/useAdaptivePresentation.ts +4 -1
- package/src/hooks/useAnnounce.doc.mjs +35 -3
- package/src/hooks/useAnnounce.replace.test.tsx +516 -0
- package/src/hooks/useAnnounce.ts +209 -102
- package/src/hooks/useAnnounceRenderedText.adopters.test.tsx +10 -1
- package/src/hooks/useAnnounceRenderedText.ts +17 -3
- package/src/hooks/useBusyAnnouncement.ts +7 -10
- package/src/hooks/useMenuHover.ts +15 -1
- package/src/i18n/generated-locales/en.generated.ts +6 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +6 -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/Theme.doc.mjs +1 -1
- package/src/theme/defineTheme.ts +117 -8
- 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/theme/expandMotionScale.test.ts +1 -1
- package/src/theme/index.ts +5 -0
- package/src/theme/motionKnobs.ts +82 -0
- package/src/theme/resolveThemeValues.ts +68 -6
- package/src/theme/themeAdaptations.ts +52 -12
- package/src/theme/themeMotion.test.ts +620 -0
- package/src/theme/themeMotion.ts +221 -0
- package/src/theme/tokenReferences.ts +149 -0
- package/src/theme/tokens.stylex.ts +10 -0
- package/src/theme/tokens.ts +15 -158
- 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/interactionOverlay.stylex.ts +12 -3
- 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/pressFeedback.test.ts +138 -0
- package/src/utils/pressFeedback.ts +34 -11
- 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,293 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file browserNegotiation.test.ts
|
|
5
|
+
* @input Recognizer sets, touch-action strings, and jsdom elements with
|
|
6
|
+
* scripted scroll metrics
|
|
7
|
+
* @output What the browser is told (touch-action and long-press styles) and
|
|
8
|
+
* what the native scroll probe answers (edges, touch-action, chaining,
|
|
9
|
+
* RTL)
|
|
10
|
+
* @position Unit tests of touchAction.ts and nativeScroll.ts
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
|
|
14
|
+
import {LongPressGestureRecognizer} from '../LongPressGestureRecognizer';
|
|
15
|
+
import {createNativeScrollProbe, parseTouchAction} from '../nativeScroll';
|
|
16
|
+
import {PanGestureRecognizer} from '../PanGestureRecognizer';
|
|
17
|
+
import {PinchGestureRecognizer} from '../PinchGestureRecognizer';
|
|
18
|
+
import {ScreenEdgePanGestureRecognizer} from '../ScreenEdgePanGestureRecognizer';
|
|
19
|
+
import {SwipeGestureRecognizer} from '../SwipeGestureRecognizer';
|
|
20
|
+
import {TapGestureRecognizer} from '../TapGestureRecognizer';
|
|
21
|
+
import {
|
|
22
|
+
deriveTouchAction,
|
|
23
|
+
gestureHostStyle,
|
|
24
|
+
holdSelectionStyle,
|
|
25
|
+
} from '../touchAction';
|
|
26
|
+
|
|
27
|
+
describe('deriveTouchAction', () => {
|
|
28
|
+
it('needs nothing without touch recognizers', () => {
|
|
29
|
+
expect(deriveTouchAction([])).toBeNull();
|
|
30
|
+
expect(
|
|
31
|
+
deriveTouchAction([
|
|
32
|
+
new PanGestureRecognizer({allowedPointerTypes: ['mouse']}),
|
|
33
|
+
]),
|
|
34
|
+
).toBeNull();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('removes only double-tap zoom for taps and long presses', () => {
|
|
38
|
+
expect(deriveTouchAction([new TapGestureRecognizer()])).toBe(
|
|
39
|
+
'manipulation',
|
|
40
|
+
);
|
|
41
|
+
expect(deriveTouchAction([new LongPressGestureRecognizer()])).toBe(
|
|
42
|
+
'manipulation',
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('gives the browser the other axis of a one-axis pan or swipe, and keeps pinch-zoom', () => {
|
|
47
|
+
expect(
|
|
48
|
+
deriveTouchAction([new PanGestureRecognizer({direction: 'horizontal'})]),
|
|
49
|
+
).toBe('pan-y pinch-zoom');
|
|
50
|
+
expect(
|
|
51
|
+
deriveTouchAction([new PanGestureRecognizer({direction: 'vertical'})]),
|
|
52
|
+
).toBe('pan-x pinch-zoom');
|
|
53
|
+
expect(deriveTouchAction([new PanGestureRecognizer()])).toBe('pinch-zoom');
|
|
54
|
+
expect(
|
|
55
|
+
deriveTouchAction([new SwipeGestureRecognizer({direction: 'left'})]),
|
|
56
|
+
).toBe('pan-y pinch-zoom');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('leaves the browser everything for a one-way pan, or one that shares native scrolling', () => {
|
|
60
|
+
// The other direction keeps scrolling natively; the pan claims its own
|
|
61
|
+
// by cancelling touchmove when it begins.
|
|
62
|
+
expect(
|
|
63
|
+
deriveTouchAction([new PanGestureRecognizer({direction: 'down'})]),
|
|
64
|
+
).toBeNull();
|
|
65
|
+
// A screen-edge pan from one edge goes one way, inward (spec:AST-094 FR18).
|
|
66
|
+
expect(
|
|
67
|
+
deriveTouchAction([
|
|
68
|
+
new ScreenEdgePanGestureRecognizer({edges: ['leading']}),
|
|
69
|
+
]),
|
|
70
|
+
).toBeNull();
|
|
71
|
+
expect(
|
|
72
|
+
deriveTouchAction([
|
|
73
|
+
new PanGestureRecognizer({direction: 'down', scrollEdge: true}),
|
|
74
|
+
]),
|
|
75
|
+
).toBeNull();
|
|
76
|
+
expect(
|
|
77
|
+
deriveTouchAction([
|
|
78
|
+
new PanGestureRecognizer({direction: 'down', scrollEdge: true}),
|
|
79
|
+
new TapGestureRecognizer(),
|
|
80
|
+
]),
|
|
81
|
+
).toBe('manipulation');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('takes pinch-zoom only for a pinch recognizer', () => {
|
|
85
|
+
expect(deriveTouchAction([new PinchGestureRecognizer()])).toBe(
|
|
86
|
+
'pan-x pan-y',
|
|
87
|
+
);
|
|
88
|
+
expect(
|
|
89
|
+
deriveTouchAction([
|
|
90
|
+
new PinchGestureRecognizer(),
|
|
91
|
+
new PanGestureRecognizer(),
|
|
92
|
+
]),
|
|
93
|
+
).toBe('none');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('intersects every recognizer on the element', () => {
|
|
97
|
+
expect(
|
|
98
|
+
deriveTouchAction([
|
|
99
|
+
new TapGestureRecognizer(),
|
|
100
|
+
new PanGestureRecognizer({direction: 'horizontal'}),
|
|
101
|
+
]),
|
|
102
|
+
).toBe('pan-y pinch-zoom');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('locks selection only for a held press, never on the element (spec:AST-094 FR41)', () => {
|
|
106
|
+
// The attached style is the touch-action alone: a mouse and a keyboard
|
|
107
|
+
// keep selecting (spec:AST-017 FR59).
|
|
108
|
+
expect(gestureHostStyle([new LongPressGestureRecognizer()])).toEqual({
|
|
109
|
+
touchAction: 'manipulation',
|
|
110
|
+
});
|
|
111
|
+
// The host applies this for one press, from touch-down to the lift.
|
|
112
|
+
expect(holdSelectionStyle([new LongPressGestureRecognizer()])).toEqual({
|
|
113
|
+
WebkitTouchCallout: 'none',
|
|
114
|
+
WebkitUserSelect: 'none',
|
|
115
|
+
userSelect: 'none',
|
|
116
|
+
});
|
|
117
|
+
// A hold that does nothing selects natively.
|
|
118
|
+
expect(holdSelectionStyle([new TapGestureRecognizer()])).toBeNull();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('parseTouchAction', () => {
|
|
123
|
+
it('reads the pans each value allows', () => {
|
|
124
|
+
expect(parseTouchAction('auto')).toEqual({x: true, y: true});
|
|
125
|
+
expect(parseTouchAction('manipulation')).toEqual({x: true, y: true});
|
|
126
|
+
expect(parseTouchAction('none')).toEqual({x: false, y: false});
|
|
127
|
+
expect(parseTouchAction('pan-y pinch-zoom')).toEqual({x: false, y: true});
|
|
128
|
+
expect(parseTouchAction('pan-left')).toEqual({x: true, y: false});
|
|
129
|
+
expect(parseTouchAction('pinch-zoom')).toEqual({x: false, y: false});
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
/** Give an element the scroll metrics jsdom cannot lay out. */
|
|
134
|
+
function scroller(
|
|
135
|
+
element: HTMLElement,
|
|
136
|
+
metrics: {
|
|
137
|
+
scrollTop?: number;
|
|
138
|
+
scrollHeight?: number;
|
|
139
|
+
clientHeight?: number;
|
|
140
|
+
scrollLeft?: number;
|
|
141
|
+
scrollWidth?: number;
|
|
142
|
+
clientWidth?: number;
|
|
143
|
+
},
|
|
144
|
+
): void {
|
|
145
|
+
for (const [key, value] of Object.entries(metrics)) {
|
|
146
|
+
Object.defineProperty(element, key, {configurable: true, value});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* jsdom drops `touch-action` from styles, so the elements under test carry
|
|
152
|
+
* it in `data-touch-action` and computed style reports it from there.
|
|
153
|
+
*/
|
|
154
|
+
function withTouchActionFromData(): () => void {
|
|
155
|
+
const original = window.getComputedStyle.bind(window);
|
|
156
|
+
const spy = vi
|
|
157
|
+
.spyOn(window, 'getComputedStyle')
|
|
158
|
+
.mockImplementation((element: Element, pseudo?: string | null) => {
|
|
159
|
+
const style = original(element, pseudo);
|
|
160
|
+
const touchAction = element.getAttribute('data-touch-action');
|
|
161
|
+
if (touchAction == null) {
|
|
162
|
+
return style;
|
|
163
|
+
}
|
|
164
|
+
return new Proxy(style, {
|
|
165
|
+
get(target, key): string | number | object | null | undefined {
|
|
166
|
+
if (key === 'touchAction') {
|
|
167
|
+
return touchAction;
|
|
168
|
+
}
|
|
169
|
+
const value = Reflect.get(target, key) as
|
|
170
|
+
string | number | object | null | undefined;
|
|
171
|
+
return typeof value === 'function' ? value.bind(target) : value;
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
return () => spy.mockRestore();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
describe('createNativeScrollProbe', () => {
|
|
179
|
+
let restore: () => void = () => {};
|
|
180
|
+
beforeEach(() => {
|
|
181
|
+
restore = withTouchActionFromData();
|
|
182
|
+
});
|
|
183
|
+
afterEach(() => {
|
|
184
|
+
restore();
|
|
185
|
+
document.body.innerHTML = '';
|
|
186
|
+
document.documentElement.style.overflow = '';
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
function setup(listStyle: string) {
|
|
190
|
+
// The page itself does not scroll in these cases.
|
|
191
|
+
document.documentElement.style.overflow = 'hidden';
|
|
192
|
+
document.body.innerHTML = `<div id="list" style="${listStyle}"><button id="row">Row</button></div>`;
|
|
193
|
+
const list = document.getElementById('list') as HTMLElement;
|
|
194
|
+
const row = document.getElementById('row') as HTMLElement;
|
|
195
|
+
return {list, row};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
it('answers by edge: at the top a pull down scrolls nothing, a pull up does', () => {
|
|
199
|
+
const {list, row} = setup('overflow-y: auto');
|
|
200
|
+
scroller(list, {scrollTop: 0, scrollHeight: 1000, clientHeight: 400});
|
|
201
|
+
const probe = createNativeScrollProbe(row);
|
|
202
|
+
expect(probe.canScroll(0, 20)).toBe(false);
|
|
203
|
+
expect(probe.canScroll(0, -20)).toBe(true);
|
|
204
|
+
expect(probe.isInsideScroller).toBe(true);
|
|
205
|
+
scroller(list, {scrollTop: 600});
|
|
206
|
+
expect(probe.canScroll(0, -20)).toBe(false);
|
|
207
|
+
expect(probe.canScroll(0, 20)).toBe(true);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('finds a scroller in a shadow tree around the slot a light-DOM row is slotted into', () => {
|
|
211
|
+
document.documentElement.style.overflow = 'hidden';
|
|
212
|
+
document.body.innerHTML =
|
|
213
|
+
'<div id="host"><button id="row">Row</button></div>';
|
|
214
|
+
const host = document.getElementById('host') as HTMLElement;
|
|
215
|
+
const row = document.getElementById('row') as HTMLElement;
|
|
216
|
+
const shadow = host.attachShadow({mode: 'open'});
|
|
217
|
+
shadow.innerHTML =
|
|
218
|
+
'<div id="list" style="overflow-y: auto"><slot></slot></div>';
|
|
219
|
+
const list = shadow.getElementById('list') as HTMLElement;
|
|
220
|
+
scroller(list, {scrollTop: 0, scrollHeight: 1000, clientHeight: 400});
|
|
221
|
+
const probe = createNativeScrollProbe(row);
|
|
222
|
+
expect(probe.isInsideScroller).toBe(true);
|
|
223
|
+
expect(probe.canScroll(0, -20)).toBe(true);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('puts a control in a fixed bar outside the page it floats over (spec:AST-094 FR11)', () => {
|
|
227
|
+
document.body.innerHTML =
|
|
228
|
+
'<div id="bar" style="position: fixed"><button id="row">Row</button></div>';
|
|
229
|
+
const root = document.scrollingElement ?? document.documentElement;
|
|
230
|
+
scroller(root as HTMLElement, {
|
|
231
|
+
scrollTop: 0,
|
|
232
|
+
scrollHeight: 3000,
|
|
233
|
+
clientHeight: 800,
|
|
234
|
+
});
|
|
235
|
+
const probe = createNativeScrollProbe(document.getElementById('row'));
|
|
236
|
+
// The page still scrolls under a drag that starts on the bar, but the bar
|
|
237
|
+
// is not in a scroll view, so its control gets no content-touch delay.
|
|
238
|
+
expect(probe.isInsideScroller).toBe(false);
|
|
239
|
+
expect(probe.canScroll(0, -20)).toBe(true);
|
|
240
|
+
for (const key of ['scrollTop', 'scrollHeight', 'clientHeight']) {
|
|
241
|
+
Reflect.deleteProperty(root, key);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('honors touch-action between the touch and the scroller', () => {
|
|
246
|
+
const {list, row} = setup('overflow-y: auto');
|
|
247
|
+
row.setAttribute('data-touch-action', 'pan-x');
|
|
248
|
+
scroller(list, {scrollTop: 100, scrollHeight: 1000, clientHeight: 400});
|
|
249
|
+
const probe = createNativeScrollProbe(row);
|
|
250
|
+
expect(probe.canScroll(0, 20)).toBe(false);
|
|
251
|
+
expect(probe.allowsNativePan).toBe(true);
|
|
252
|
+
row.setAttribute('data-touch-action', 'none');
|
|
253
|
+
expect(createNativeScrollProbe(row).allowsNativePan).toBe(false);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('ignores the wobble of a mostly straight drag', () => {
|
|
257
|
+
const {list, row} = setup('overflow-x: auto; overflow-y: hidden');
|
|
258
|
+
scroller(list, {scrollLeft: 50, scrollWidth: 1000, clientWidth: 300});
|
|
259
|
+
const probe = createNativeScrollProbe(row);
|
|
260
|
+
expect(probe.canScroll(2, 30)).toBe(false);
|
|
261
|
+
expect(probe.canScroll(30, 2)).toBe(true);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('follows the RTL scrollLeft range', () => {
|
|
265
|
+
const {list, row} = setup(
|
|
266
|
+
'overflow-x: auto; overflow-y: hidden; direction: rtl',
|
|
267
|
+
);
|
|
268
|
+
// RTL starts at 0 and runs negative toward the inline end (the left).
|
|
269
|
+
scroller(list, {scrollLeft: 0, scrollWidth: 1000, clientWidth: 300});
|
|
270
|
+
const probe = createNativeScrollProbe(row);
|
|
271
|
+
expect(probe.canScroll(30, 0)).toBe(true); // reveals content on the left
|
|
272
|
+
expect(probe.canScroll(-30, 0)).toBe(false);
|
|
273
|
+
scroller(list, {scrollLeft: -700});
|
|
274
|
+
expect(probe.canScroll(30, 0)).toBe(false);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('stops the chain at overscroll-behavior: contain', () => {
|
|
278
|
+
document.documentElement.style.overflow = '';
|
|
279
|
+
document.body.innerHTML = `<div id="outer" style="overflow-y: auto"><div id="inner" style="overflow-y: auto; overscroll-behavior: contain"><span id="t">x</span></div></div>`;
|
|
280
|
+
const outer = document.getElementById('outer') as HTMLElement;
|
|
281
|
+
const inner = document.getElementById('inner') as HTMLElement;
|
|
282
|
+
scroller(outer, {scrollTop: 300, scrollHeight: 2000, clientHeight: 500});
|
|
283
|
+
scroller(inner, {scrollTop: 0, scrollHeight: 800, clientHeight: 400});
|
|
284
|
+
const probe = createNativeScrollProbe(document.getElementById('t'));
|
|
285
|
+
// The inner list is at its top and contains its overscroll: a pull
|
|
286
|
+
// down reaches nothing, though the outer one could scroll.
|
|
287
|
+
expect(probe.canScroll(0, 20)).toBe(false);
|
|
288
|
+
inner.style.overscrollBehavior = 'auto';
|
|
289
|
+
expect(
|
|
290
|
+
createNativeScrollProbe(document.getElementById('t')).canScroll(0, 20),
|
|
291
|
+
).toBe(true);
|
|
292
|
+
});
|
|
293
|
+
});
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file haptics.test.ts
|
|
5
|
+
* @input playHaptic, attachTapHaptic and the support probes, with
|
|
6
|
+
* navigator.vibrate stubbed or absent, in jsdom
|
|
7
|
+
* @output Vibration patterns per feedback kind where the platform vibrates,
|
|
8
|
+
* nothing where it does not; the hidden switch iOS Safari plays its tap
|
|
9
|
+
* haptic on: hidden from layout, touch and assistive technology, its click
|
|
10
|
+
* and change kept inside, removed on release
|
|
11
|
+
* @position Unit tests of packages/core/src/gestures/haptics.ts
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {afterEach, describe, expect, it, vi} from 'vitest';
|
|
15
|
+
import {
|
|
16
|
+
HAPTIC_FEEDBACK_KINDS,
|
|
17
|
+
HAPTIC_VIBRATION_PATTERNS,
|
|
18
|
+
} from '../../motion/uikit/gestures';
|
|
19
|
+
import {
|
|
20
|
+
attachTapHaptic,
|
|
21
|
+
canVibrate,
|
|
22
|
+
HAPTIC_SWITCH_ATTRIBUTE,
|
|
23
|
+
playHaptic,
|
|
24
|
+
supportsSwitchControl,
|
|
25
|
+
} from '../haptics';
|
|
26
|
+
|
|
27
|
+
const original = Object.getOwnPropertyDescriptor(navigator, 'vibrate');
|
|
28
|
+
|
|
29
|
+
function stubVibrate(implementation: (pattern: number[]) => boolean) {
|
|
30
|
+
const vibrate = vi.fn(implementation);
|
|
31
|
+
Object.defineProperty(navigator, 'vibrate', {
|
|
32
|
+
configurable: true,
|
|
33
|
+
value: vibrate,
|
|
34
|
+
});
|
|
35
|
+
return vibrate;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
if (original == null) {
|
|
40
|
+
delete (navigator as {vibrate?: unknown}).vibrate;
|
|
41
|
+
} else {
|
|
42
|
+
Object.defineProperty(navigator, 'vibrate', original);
|
|
43
|
+
}
|
|
44
|
+
document.body.innerHTML = '';
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('playHaptic', () => {
|
|
48
|
+
it('vibrates each feedback kind with its own pattern', () => {
|
|
49
|
+
const vibrate = stubVibrate(() => true);
|
|
50
|
+
expect(canVibrate()).toBe(true);
|
|
51
|
+
for (const kind of HAPTIC_FEEDBACK_KINDS) {
|
|
52
|
+
expect(playHaptic(kind)).toBe(true);
|
|
53
|
+
expect(vibrate).toHaveBeenLastCalledWith([
|
|
54
|
+
...HAPTIC_VIBRATION_PATTERNS[kind].value,
|
|
55
|
+
]);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('plays nothing where the platform cannot vibrate, or refuses', () => {
|
|
60
|
+
delete (navigator as {vibrate?: unknown}).vibrate;
|
|
61
|
+
expect(canVibrate()).toBe(false);
|
|
62
|
+
expect(playHaptic('impactLight')).toBe(false);
|
|
63
|
+
stubVibrate(() => false);
|
|
64
|
+
expect(playHaptic('selection')).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('lets an error from the platform through: a vibrate that throws is not a refusal', () => {
|
|
68
|
+
stubVibrate(() => {
|
|
69
|
+
throw new Error('blocked');
|
|
70
|
+
});
|
|
71
|
+
expect(() => playHaptic('selection')).toThrow('blocked');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('attachTapHaptic', () => {
|
|
76
|
+
it('gives the label a hidden switch that keeps its own events inside', () => {
|
|
77
|
+
document.body.innerHTML = '<label id="tap">Tap</label>';
|
|
78
|
+
const label = document.getElementById('tap') as HTMLLabelElement;
|
|
79
|
+
const onClick = vi.fn();
|
|
80
|
+
const onChange = vi.fn();
|
|
81
|
+
label.addEventListener('click', onClick);
|
|
82
|
+
label.addEventListener('change', onChange);
|
|
83
|
+
|
|
84
|
+
const release = attachTapHaptic(label);
|
|
85
|
+
const input = label.querySelector(`[${HAPTIC_SWITCH_ATTRIBUTE}]`);
|
|
86
|
+
expect(input).toBeInstanceOf(HTMLInputElement);
|
|
87
|
+
const sw = input as HTMLInputElement;
|
|
88
|
+
expect(sw.type).toBe('checkbox');
|
|
89
|
+
expect(sw.hasAttribute('switch')).toBe(true);
|
|
90
|
+
expect(sw.getAttribute('aria-hidden')).toBe('true');
|
|
91
|
+
expect(sw.tabIndex).toBe(-1);
|
|
92
|
+
// It never takes the touch itself, so a pan starting on it still
|
|
93
|
+
// scrolls, and it takes no room.
|
|
94
|
+
expect(sw.style.pointerEvents).toBe('none');
|
|
95
|
+
expect(sw.style.position).toBe('absolute');
|
|
96
|
+
|
|
97
|
+
// The switch toggling (the label's activation) does not reach the
|
|
98
|
+
// control as a second click or a change.
|
|
99
|
+
sw.click();
|
|
100
|
+
expect(onClick).not.toHaveBeenCalled();
|
|
101
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
102
|
+
|
|
103
|
+
release();
|
|
104
|
+
expect(label.querySelector(`[${HAPTIC_SWITCH_ATTRIBUTE}]`)).toBeNull();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('never leaves the focus on its hidden switch', () => {
|
|
108
|
+
document.body.innerHTML =
|
|
109
|
+
'<button id="before">Before</button><label id="tap">Tap</label>';
|
|
110
|
+
const before = document.getElementById('before') as HTMLButtonElement;
|
|
111
|
+
const label = document.getElementById('tap') as HTMLLabelElement;
|
|
112
|
+
const release = attachTapHaptic(label);
|
|
113
|
+
const sw = label.querySelector<HTMLInputElement>(
|
|
114
|
+
`[${HAPTIC_SWITCH_ATTRIBUTE}]`,
|
|
115
|
+
)!;
|
|
116
|
+
before.focus();
|
|
117
|
+
// Chromium focuses a label's control on its activation.
|
|
118
|
+
sw.focus();
|
|
119
|
+
expect(document.activeElement).not.toBe(sw);
|
|
120
|
+
expect(document.activeElement).toBe(before);
|
|
121
|
+
release();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('keeps a label\u2019s own control: the tap plays and the control still toggles', () => {
|
|
125
|
+
document.body.innerHTML =
|
|
126
|
+
'<label id="tap"><input id="own" type="checkbox"> Remember me</label>';
|
|
127
|
+
const label = document.getElementById('tap') as HTMLLabelElement;
|
|
128
|
+
const own = document.getElementById('own') as HTMLInputElement;
|
|
129
|
+
const onOwnClick = vi.fn();
|
|
130
|
+
own.addEventListener('click', onOwnClick);
|
|
131
|
+
const release = attachTapHaptic(label);
|
|
132
|
+
const sw = label.querySelector<HTMLInputElement>(
|
|
133
|
+
`[${HAPTIC_SWITCH_ATTRIBUTE}]`,
|
|
134
|
+
)!;
|
|
135
|
+
// The switch takes the label's activation, so a tap plays.
|
|
136
|
+
expect(label.control).toBe(sw);
|
|
137
|
+
// The checkbox keeps its name: the label's text, through aria-labelledby.
|
|
138
|
+
expect(own).toHaveAccessibleName('Remember me');
|
|
139
|
+
sw.click();
|
|
140
|
+
expect(sw.checked).toBe(true);
|
|
141
|
+
expect(own.checked).toBe(true);
|
|
142
|
+
expect(onOwnClick).toHaveBeenCalledTimes(1);
|
|
143
|
+
release();
|
|
144
|
+
expect(label.control).toBe(own);
|
|
145
|
+
expect(own).not.toHaveAttribute('aria-labelledby');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('gives a disabled control no feedback and leaves no focus on the switch (FR23)', () => {
|
|
149
|
+
document.body.innerHTML =
|
|
150
|
+
'<button id="before">Before</button>' +
|
|
151
|
+
'<label id="tap"><input id="own" type="checkbox" disabled> Remember me</label>';
|
|
152
|
+
const before = document.getElementById('before') as HTMLButtonElement;
|
|
153
|
+
const label = document.getElementById('tap') as HTMLLabelElement;
|
|
154
|
+
const own = document.getElementById('own') as HTMLInputElement;
|
|
155
|
+
const release = attachTapHaptic(label);
|
|
156
|
+
const sw = label.querySelector<HTMLInputElement>(
|
|
157
|
+
`[${HAPTIC_SWITCH_ATTRIBUTE}]`,
|
|
158
|
+
)!;
|
|
159
|
+
before.focus();
|
|
160
|
+
sw.focus();
|
|
161
|
+
sw.click();
|
|
162
|
+
// The switch did not toggle (nothing plays), the control did not change,
|
|
163
|
+
// and focus is not stranded on the hidden switch.
|
|
164
|
+
expect(sw.checked).toBe(false);
|
|
165
|
+
expect(own.checked).toBe(false);
|
|
166
|
+
expect(document.activeElement).toBe(before);
|
|
167
|
+
release();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('leaves a label whose control is already a switch, or tied by for, as it is', () => {
|
|
171
|
+
document.body.innerHTML =
|
|
172
|
+
'<label id="a"><input type="checkbox" switch> Wi-Fi</label>' +
|
|
173
|
+
'<label id="b" for="c">Bluetooth</label><input id="c" type="checkbox">';
|
|
174
|
+
for (const id of ['a', 'b']) {
|
|
175
|
+
const label = document.getElementById(id) as HTMLLabelElement;
|
|
176
|
+
const release = attachTapHaptic(label);
|
|
177
|
+
expect(label.querySelector(`[${HAPTIC_SWITCH_ATTRIBUTE}]`)).toBeNull();
|
|
178
|
+
release();
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('reports whether the browser knows the switch control', () => {
|
|
183
|
+
// jsdom has no `switch` property on checkbox inputs, like browsers
|
|
184
|
+
// before Safari 17.4.
|
|
185
|
+
expect(supportsSwitchControl(document)).toBe(false);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
@@ -40,7 +40,13 @@ export interface Harness {
|
|
|
40
40
|
claims: number[];
|
|
41
41
|
/** Deferred clicks as they resolved. */
|
|
42
42
|
deferredClicks: {id: number; allowed: boolean; time: number}[];
|
|
43
|
-
environment: {
|
|
43
|
+
environment: {
|
|
44
|
+
width: number;
|
|
45
|
+
height: number;
|
|
46
|
+
rtl: boolean;
|
|
47
|
+
/** The box every recognizer's view measures, when a test sets one. */
|
|
48
|
+
view?: {left?: number; top?: number; width: number; height: number};
|
|
49
|
+
};
|
|
44
50
|
finger(id: number): Finger;
|
|
45
51
|
/** Advance the clock and run every timer due by `time`. */
|
|
46
52
|
advance(time: number): void;
|
|
@@ -51,7 +57,11 @@ export function createHarness(): Harness {
|
|
|
51
57
|
const log: string[] = [];
|
|
52
58
|
const claims: number[] = [];
|
|
53
59
|
const deferredClicks: Harness['deferredClicks'] = [];
|
|
54
|
-
const environment = {
|
|
60
|
+
const environment: Harness['environment'] = {
|
|
61
|
+
width: 390,
|
|
62
|
+
height: 844,
|
|
63
|
+
rtl: false,
|
|
64
|
+
};
|
|
55
65
|
const fingers = new Map<number, Finger>();
|
|
56
66
|
const env: GestureEnvironment = {
|
|
57
67
|
viewportSize: () => ({
|
|
@@ -59,6 +69,15 @@ export function createHarness(): Harness {
|
|
|
59
69
|
height: environment.height,
|
|
60
70
|
}),
|
|
61
71
|
isRtl: () => environment.rtl,
|
|
72
|
+
viewRect: () =>
|
|
73
|
+
environment.view == null
|
|
74
|
+
? null
|
|
75
|
+
: {
|
|
76
|
+
left: environment.view.left ?? 0,
|
|
77
|
+
top: environment.view.top ?? 0,
|
|
78
|
+
width: environment.view.width,
|
|
79
|
+
height: environment.view.height,
|
|
80
|
+
},
|
|
62
81
|
};
|
|
63
82
|
const arena: GestureArena = new GestureArena({
|
|
64
83
|
clock,
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file recognizerKind.test.ts
|
|
5
|
+
* @input Each recognizer of the family, and the sources of Core and Lab
|
|
6
|
+
* @output A recognizer is told apart by its `kind`, never by `instanceof`
|
|
7
|
+
* (architecture:react-component-runtime INV13): each one reports its kind,
|
|
8
|
+
* a screen-edge pan its own; and no source checks a recognizer's class
|
|
9
|
+
* @position Unit and source boundary test of packages/core/src/gestures
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import {describe, expect, it} from 'vitest';
|
|
15
|
+
import {LongPressGestureRecognizer} from '../LongPressGestureRecognizer';
|
|
16
|
+
import {PanGestureRecognizer} from '../PanGestureRecognizer';
|
|
17
|
+
import {PinchGestureRecognizer} from '../PinchGestureRecognizer';
|
|
18
|
+
import {ScreenEdgePanGestureRecognizer} from '../ScreenEdgePanGestureRecognizer';
|
|
19
|
+
import {SwipeGestureRecognizer} from '../SwipeGestureRecognizer';
|
|
20
|
+
import {TapGestureRecognizer} from '../TapGestureRecognizer';
|
|
21
|
+
|
|
22
|
+
const ROOT = path.resolve(__dirname, '../../../../..');
|
|
23
|
+
|
|
24
|
+
function sourcesUnder(directory: string): string[] {
|
|
25
|
+
const files: string[] = [];
|
|
26
|
+
const visit = (current: string) => {
|
|
27
|
+
for (const entry of fs.readdirSync(current, {withFileTypes: true})) {
|
|
28
|
+
if (entry.name === 'node_modules' || entry.name.startsWith('.')) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const full = path.join(current, entry.name);
|
|
32
|
+
if (entry.isDirectory()) {
|
|
33
|
+
visit(full);
|
|
34
|
+
} else if (/\.(m?[jt]sx?)$/.test(entry.name)) {
|
|
35
|
+
files.push(full);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
if (fs.existsSync(directory)) {
|
|
40
|
+
visit(directory);
|
|
41
|
+
}
|
|
42
|
+
return files;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
describe('recognizer kinds', () => {
|
|
46
|
+
it('each recognizer reports its kind, a screen-edge pan its own (architecture:react-component-runtime INV13)', () => {
|
|
47
|
+
const kinds = [
|
|
48
|
+
new TapGestureRecognizer(),
|
|
49
|
+
new LongPressGestureRecognizer(),
|
|
50
|
+
new PanGestureRecognizer(),
|
|
51
|
+
new ScreenEdgePanGestureRecognizer({edges: ['leading']}),
|
|
52
|
+
new SwipeGestureRecognizer(),
|
|
53
|
+
new PinchGestureRecognizer(),
|
|
54
|
+
].map(recognizer => (recognizer as {kind?: string}).kind);
|
|
55
|
+
expect(kinds).toEqual([
|
|
56
|
+
'tap',
|
|
57
|
+
'longPress',
|
|
58
|
+
'pan',
|
|
59
|
+
'screenEdgePan',
|
|
60
|
+
'swipe',
|
|
61
|
+
'pinch',
|
|
62
|
+
]);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('is never told apart by instanceof in Core or Lab (architecture:react-component-runtime INV13)', () => {
|
|
66
|
+
// Built from parts, so this file does not match itself.
|
|
67
|
+
const check = new RegExp(
|
|
68
|
+
['\\binstanceof\\s+', '[A-Za-z]*', 'GestureRecognizer\\b'].join(''),
|
|
69
|
+
);
|
|
70
|
+
const offenders = [
|
|
71
|
+
...sourcesUnder(path.join(ROOT, 'packages/core/src')),
|
|
72
|
+
...sourcesUnder(path.join(ROOT, 'packages/lab/src')),
|
|
73
|
+
]
|
|
74
|
+
.filter(file => check.test(fs.readFileSync(file, 'utf8')))
|
|
75
|
+
.map(file => path.relative(ROOT, file));
|
|
76
|
+
expect(offenders).toEqual([]);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file touchActionRule.test.ts
|
|
5
|
+
* @input markTouchAction and unmarkTouchAction on a document
|
|
6
|
+
* @output Where the rule lives: an adopted constructable sheet where the
|
|
7
|
+
* engine has one, a style element where it has none, and an error from a
|
|
8
|
+
* constructable sheet that exists is not taken for a missing one
|
|
9
|
+
* @position Unit test of packages/core/src/gestures/touchActionRule.ts
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {afterEach, describe, expect, it, vi} from 'vitest';
|
|
13
|
+
import {markTouchAction, unmarkTouchAction} from '../touchActionRule';
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
vi.unstubAllGlobals();
|
|
17
|
+
document.body.innerHTML = '';
|
|
18
|
+
document.head.innerHTML = '';
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('touchActionRule', () => {
|
|
22
|
+
it('writes the rule into a style element where the engine has no constructable sheets', () => {
|
|
23
|
+
expect('adoptedStyleSheets' in document).toBe(false);
|
|
24
|
+
const element = document.createElement('div');
|
|
25
|
+
document.body.append(element);
|
|
26
|
+
expect(markTouchAction(element, 'pan-y')).toBe(true);
|
|
27
|
+
expect(document.head.querySelector('style')?.textContent).toContain(
|
|
28
|
+
'pan-y',
|
|
29
|
+
);
|
|
30
|
+
unmarkTouchAction(element);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('lets an error from a constructable sheet that exists through, instead of taking it for a missing one', () => {
|
|
34
|
+
class BrokenSheet {
|
|
35
|
+
constructor() {
|
|
36
|
+
throw new Error('broken sheet');
|
|
37
|
+
}
|
|
38
|
+
replaceSync(): void {}
|
|
39
|
+
}
|
|
40
|
+
vi.stubGlobal('CSSStyleSheet', BrokenSheet);
|
|
41
|
+
Object.defineProperty(document, 'adoptedStyleSheets', {
|
|
42
|
+
configurable: true,
|
|
43
|
+
writable: true,
|
|
44
|
+
value: [],
|
|
45
|
+
});
|
|
46
|
+
try {
|
|
47
|
+
const element = document.createElement('div');
|
|
48
|
+
document.body.append(element);
|
|
49
|
+
expect(() => markTouchAction(element, 'pan-x')).toThrow('broken sheet');
|
|
50
|
+
} finally {
|
|
51
|
+
delete (document as {adoptedStyleSheets?: unknown}).adoptedStyleSheets;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
});
|