@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
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import {
|
|
18
|
-
isValidElement,
|
|
19
18
|
useCallback,
|
|
20
19
|
useEffect,
|
|
21
20
|
useLayoutEffect,
|
|
@@ -28,6 +27,7 @@ import {createPortal} from 'react-dom';
|
|
|
28
27
|
import * as stylex from '@stylexjs/stylex';
|
|
29
28
|
import {spacingVars, durationVars, easeVars} from '../theme/tokens.stylex';
|
|
30
29
|
import {mergeProps} from '../utils';
|
|
30
|
+
import {getNodeText} from '../utils/getNodeText';
|
|
31
31
|
import {INTERACTIVE_SELECTORS} from '../hooks/useClickableContainer';
|
|
32
32
|
import {useAnnounce} from '../hooks/useAnnounce';
|
|
33
33
|
import {layerTextReset} from '../Layer/layerTextReset.stylex';
|
|
@@ -172,29 +172,6 @@ const styles = stylex.create({
|
|
|
172
172
|
},
|
|
173
173
|
});
|
|
174
174
|
|
|
175
|
-
// Flatten a toast's rendered content (title, description, etc.) to the plain
|
|
176
|
-
// text that should be spoken by a screen reader. Only text is announced —
|
|
177
|
-
// interactive endContent is deliberately excluded (it is reachable via F6).
|
|
178
|
-
function getNodeText(node: ReactNode): string {
|
|
179
|
-
if (node == null || typeof node === 'boolean') {
|
|
180
|
-
return '';
|
|
181
|
-
}
|
|
182
|
-
if (typeof node === 'string') {
|
|
183
|
-
return node;
|
|
184
|
-
}
|
|
185
|
-
if (typeof node === 'number') {
|
|
186
|
-
return String(node);
|
|
187
|
-
}
|
|
188
|
-
if (Array.isArray(node)) {
|
|
189
|
-
return node.map(getNodeText).filter(Boolean).join(' ');
|
|
190
|
-
}
|
|
191
|
-
if (isValidElement(node)) {
|
|
192
|
-
const {children} = node.props as {children?: ReactNode};
|
|
193
|
-
return getNodeText(children);
|
|
194
|
-
}
|
|
195
|
-
return '';
|
|
196
|
-
}
|
|
197
|
-
|
|
198
175
|
export interface ToastViewportProps {
|
|
199
176
|
position?: ToastPosition;
|
|
200
177
|
/** Maximum number of visible toasts. @default 5 */
|
|
@@ -344,6 +321,19 @@ export function ToastViewport({
|
|
|
344
321
|
const [exitingIds, setExitingIds] = useState<Set<string>>(new Set());
|
|
345
322
|
const toastsRef = useRef(toasts);
|
|
346
323
|
toastsRef.current = toasts;
|
|
324
|
+
// The list as last rendered: addToast moves toastsRef ahead of it within
|
|
325
|
+
// a batch, so this tells a rendered toast from one raised since.
|
|
326
|
+
const renderedToastsRef = useRef(toasts);
|
|
327
|
+
renderedToastsRef.current = toasts;
|
|
328
|
+
// Read by removeToast, which keeps one identity across renders.
|
|
329
|
+
const maxVisibleRef = useRef(maxVisible);
|
|
330
|
+
maxVisibleRef.current = maxVisible;
|
|
331
|
+
// Rendered entries a repeat has replaced in this batch: still found by a
|
|
332
|
+
// dismissal in the same handler, as before the swap. One replaced before it
|
|
333
|
+
// rendered was never shown and reports no onHide (Toast.spec.md FR3). A
|
|
334
|
+
// render starts a new batch.
|
|
335
|
+
const replacedRef = useRef<Map<string, ToastEntry>>(new Map());
|
|
336
|
+
replacedRef.current.clear();
|
|
347
337
|
|
|
348
338
|
const viewportRef = useRef<HTMLDivElement>(null);
|
|
349
339
|
// Toast ids whose exit has begun — guards onHide from double-firing (see
|
|
@@ -410,6 +400,10 @@ export function ToastViewport({
|
|
|
410
400
|
const addToast = useCallback(
|
|
411
401
|
(entry: ToastEntry) => {
|
|
412
402
|
const {uniqueID, collisionBehavior = 'overwrite'} = entry.options;
|
|
403
|
+
// A toast holds its uniqueID until it unmounts, leaving included
|
|
404
|
+
// (Toast.spec.md FR8): an overwrite replaces it in place, and an ignored
|
|
405
|
+
// namesake is dropped.
|
|
406
|
+
const holdsUniqueID = (t: ToastEntry) => t.options.uniqueID === uniqueID;
|
|
413
407
|
// Resolve an ignored collision synchronously against the committed list
|
|
414
408
|
// so a suppressed toast is neither shown nor announced. The remaining
|
|
415
409
|
// announce + setToasts run outside the setToasts updater, which React may
|
|
@@ -417,16 +411,46 @@ export function ToastViewport({
|
|
|
417
411
|
if (
|
|
418
412
|
uniqueID &&
|
|
419
413
|
collisionBehavior === 'ignore' &&
|
|
420
|
-
toastsRef.current.some(
|
|
414
|
+
toastsRef.current.some(holdsUniqueID)
|
|
421
415
|
) {
|
|
422
416
|
return;
|
|
423
417
|
}
|
|
418
|
+
// Only text is announced; interactive endContent is reachable via F6.
|
|
424
419
|
const text = getNodeText(entry.options.body);
|
|
425
420
|
if (text) {
|
|
426
421
|
// Error toasts map to the assertive region (role="alert"); everything
|
|
427
422
|
// else to the polite region (role="status") — mirrors Toast.tsx.
|
|
428
423
|
announce(text, entry.options.type === 'error' ? 'assertive' : 'polite');
|
|
429
424
|
}
|
|
425
|
+
// A leaving toast that a new one pushes out of the visible window can no
|
|
426
|
+
// longer finish its exit on screen, so it leaves the list now (it
|
|
427
|
+
// already reported onHide); otherwise its row would come back collapsed
|
|
428
|
+
// when the window reached it again, holding a slot and the landmark.
|
|
429
|
+
const committed = toastsRef.current;
|
|
430
|
+
const overwritten = uniqueID ? committed.find(holdsUniqueID) : undefined;
|
|
431
|
+
if (overwritten && renderedToastsRef.current.includes(overwritten)) {
|
|
432
|
+
replacedRef.current.set(overwritten.id, overwritten);
|
|
433
|
+
}
|
|
434
|
+
const projected = overwritten
|
|
435
|
+
? committed.map(t => (t === overwritten ? entry : t))
|
|
436
|
+
: [...committed, entry];
|
|
437
|
+
// `maxVisible={0}` shows every toast (FR7): nothing leaves the window.
|
|
438
|
+
const firstVisible = maxVisible > 0 ? projected.length - maxVisible : 0;
|
|
439
|
+
const cutIds = new Set(
|
|
440
|
+
projected
|
|
441
|
+
.filter((t, i) => i < firstVisible && exitingIdsRef.current.has(t.id))
|
|
442
|
+
.map(t => t.id),
|
|
443
|
+
);
|
|
444
|
+
if (cutIds.size > 0) {
|
|
445
|
+
// Gone from every list, so a later dismissal reports nothing more.
|
|
446
|
+
for (const id of cutIds) {
|
|
447
|
+
exitingIdsRef.current.delete(id);
|
|
448
|
+
pendingEntriesRef.current.delete(id);
|
|
449
|
+
}
|
|
450
|
+
setExitingIds(prev => new Set([...prev].filter(id => !cutIds.has(id))));
|
|
451
|
+
}
|
|
452
|
+
// Later toasts in the same batch see this one before the next render.
|
|
453
|
+
toastsRef.current = projected.filter(t => !cutIds.has(t.id));
|
|
430
454
|
const pending = pendingEntriesRef.current;
|
|
431
455
|
if (uniqueID) {
|
|
432
456
|
// An overwrite replaces a toast that has not rendered yet too.
|
|
@@ -442,17 +466,17 @@ export function ToastViewport({
|
|
|
442
466
|
// dismissed. Its settled id is dropped by the prune below, which covers
|
|
443
467
|
// every silent exit with one rule rather than one branch per path.
|
|
444
468
|
setToasts(prev => {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
469
|
+
// The cut entries go first, then the choice the projection above made
|
|
470
|
+
// (by identity): a dismissal in the same handler may have marked the
|
|
471
|
+
// replaced namesake as leaving since, which must not turn the
|
|
472
|
+
// overwrite into an append. An ignored collision already returned.
|
|
473
|
+
const kept = prev.filter(t => !cutIds.has(t.id));
|
|
474
|
+
return overwritten && kept.includes(overwritten)
|
|
475
|
+
? kept.map(t => (t === overwritten ? entry : t))
|
|
476
|
+
: [...kept, entry];
|
|
453
477
|
});
|
|
454
478
|
},
|
|
455
|
-
[announce],
|
|
479
|
+
[announce, maxVisible],
|
|
456
480
|
);
|
|
457
481
|
|
|
458
482
|
const removeToast = useCallback((id: string, reason: ToastDismissReason) => {
|
|
@@ -465,6 +489,7 @@ export function ToastViewport({
|
|
|
465
489
|
}
|
|
466
490
|
const entry =
|
|
467
491
|
toastsRef.current.find(t => t.id === id) ??
|
|
492
|
+
replacedRef.current.get(id) ??
|
|
468
493
|
pendingEntriesRef.current.get(id);
|
|
469
494
|
if (entry == null) {
|
|
470
495
|
// Already gone: nothing to hide or report.
|
|
@@ -485,29 +510,54 @@ export function ToastViewport({
|
|
|
485
510
|
dismissedNode.contains(active)
|
|
486
511
|
) {
|
|
487
512
|
focusHandoffIdRef.current = id;
|
|
488
|
-
// Pick the
|
|
489
|
-
//
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
513
|
+
// Pick the toast to receive focus while the DOM is still intact: the
|
|
514
|
+
// nearest one after it, then before it, that shows once it is gone
|
|
515
|
+
// (FR10), else restore. The list may already run ahead of the render
|
|
516
|
+
// within this handler: a toast a repeat replaced has left it, and the
|
|
517
|
+
// replacement holds its place, so the neighbors are taken around the
|
|
518
|
+
// replacement, which takes focus only when no neighbor shows.
|
|
519
|
+
const list = toastsRef.current;
|
|
520
|
+
const {uniqueID} = entry.options;
|
|
521
|
+
const ownIndex = list.findIndex(t => t.id === id);
|
|
522
|
+
const placeIndex =
|
|
523
|
+
ownIndex >= 0 || uniqueID == null
|
|
524
|
+
? ownIndex
|
|
525
|
+
: list.findIndex(t => t.options.uniqueID === uniqueID);
|
|
526
|
+
const remaining = list.filter(t => t.id !== id);
|
|
527
|
+
const max = maxVisibleRef.current;
|
|
528
|
+
const shown = new Set(max > 0 ? remaining.slice(-max) : remaining);
|
|
529
|
+
const isShown = (t: ToastEntry) => shown.has(t);
|
|
530
|
+
const replacement = ownIndex < 0 ? list[placeIndex] : undefined;
|
|
531
|
+
const next =
|
|
532
|
+
placeIndex < 0
|
|
533
|
+
? undefined
|
|
534
|
+
: (list.slice(placeIndex + 1).find(isShown) ??
|
|
535
|
+
list.slice(0, placeIndex).reverse().find(isShown) ??
|
|
536
|
+
(replacement != null && isShown(replacement)
|
|
537
|
+
? replacement
|
|
538
|
+
: undefined));
|
|
539
|
+
pendingFocusRef.current = next ? next.id : 'restore';
|
|
500
540
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
541
|
+
// A toast this handler has already pushed out of the visible window still
|
|
542
|
+
// has its row now, but loses it when the batch renders.
|
|
543
|
+
const index = toastsRef.current.findIndex(t => t.id === id);
|
|
544
|
+
const isPushedOut =
|
|
545
|
+
maxVisibleRef.current > 0 &&
|
|
546
|
+
index >= 0 &&
|
|
547
|
+
index < toastsRef.current.length - maxVisibleRef.current;
|
|
548
|
+
if (dismissedNode == null || isPushedOut) {
|
|
549
|
+
// No row is mounted for it, or none will be: it is hidden past
|
|
550
|
+
// `maxVisible`, or it has not rendered yet. Nothing animates out, so it
|
|
551
|
+
// leaves the list now.
|
|
504
552
|
// Waiting for its row to finish exiting would keep it forever: when it
|
|
505
553
|
// surfaced, its row would mount already collapsed, with no transition
|
|
506
554
|
// left to end, and hold a visible slot as an empty row.
|
|
507
555
|
// It leaves the committed list now too, so a second dismissal before
|
|
508
|
-
// the next render finds nothing to report
|
|
556
|
+
// the next render finds nothing to report (nor does a toast a repeat
|
|
557
|
+
// replaced in this batch).
|
|
509
558
|
exitingIdsRef.current.delete(id);
|
|
510
559
|
pendingEntriesRef.current.delete(id);
|
|
560
|
+
replacedRef.current.delete(id);
|
|
511
561
|
toastsRef.current = toastsRef.current.filter(t => t.id !== id);
|
|
512
562
|
setToasts(prev => prev.filter(t => t.id !== id));
|
|
513
563
|
return;
|
|
@@ -371,9 +371,11 @@ presentation.
|
|
|
371
371
|
once the confirmation has closed, since a message sent while the
|
|
372
372
|
confirmation covers the sheet is not heard — `spec:AST-086/FR14`), the
|
|
373
373
|
search's busy start, and how each search
|
|
374
|
-
ended — the result count for a non-empty query, or the empty state's text
|
|
375
|
-
|
|
376
|
-
|
|
374
|
+
ended — the result count for a non-empty query, or the empty state's text when
|
|
375
|
+
it shows, both from the search's own `useAnnounce({hasReplace: true})`
|
|
376
|
+
instance (`spec:AST-086/FR9`, FR13), so a newer one replaces one not yet
|
|
377
|
+
spoken — are announced once per occasion from inside the sheet through
|
|
378
|
+
`useAnnounce`, which `spec:AST-086/FR14` routes into the persistent
|
|
377
379
|
polite container of the sheet's own dialog while it is open, because the
|
|
378
380
|
shared page-body channel is not exposed behind a native modal; the
|
|
379
381
|
container follows FR3, FR5, and FR6 of that record (WCAG 2.2 SC 4.1.3
|
|
@@ -723,6 +723,54 @@ describe('Tokenizer', () => {
|
|
|
723
723
|
bootstrap: () => [],
|
|
724
724
|
};
|
|
725
725
|
|
|
726
|
+
it('labels the inline create row from the catalog, following the locale', async () => {
|
|
727
|
+
const overrides = {
|
|
728
|
+
de: {'@astryx.tokenizer.create': '„{value}“ erstellen'},
|
|
729
|
+
};
|
|
730
|
+
const {rerender} = render(
|
|
731
|
+
<InternationalizationProvider locale="de" overrides={overrides}>
|
|
732
|
+
<Tokenizer
|
|
733
|
+
label="Obst"
|
|
734
|
+
searchSource={emptySource}
|
|
735
|
+
value={[]}
|
|
736
|
+
onChange={() => {}}
|
|
737
|
+
hasCreate
|
|
738
|
+
debounceMs={0}
|
|
739
|
+
/>
|
|
740
|
+
</InternationalizationProvider>,
|
|
741
|
+
);
|
|
742
|
+
await act(async () => {
|
|
743
|
+
fireEvent.change(screen.getByRole('combobox'), {
|
|
744
|
+
target: {value: 'Kiwi'},
|
|
745
|
+
});
|
|
746
|
+
});
|
|
747
|
+
await act(async () => {
|
|
748
|
+
await new Promise(r => setTimeout(r, 50));
|
|
749
|
+
});
|
|
750
|
+
expect(screen.getByText('„Kiwi“ erstellen')).toBeInTheDocument();
|
|
751
|
+
expect(screen.queryByText('Create "Kiwi"')).not.toBeInTheDocument();
|
|
752
|
+
|
|
753
|
+
rerender(
|
|
754
|
+
<InternationalizationProvider locale="en" overrides={overrides}>
|
|
755
|
+
<Tokenizer
|
|
756
|
+
label="Obst"
|
|
757
|
+
searchSource={emptySource}
|
|
758
|
+
value={[]}
|
|
759
|
+
onChange={() => {}}
|
|
760
|
+
hasCreate
|
|
761
|
+
debounceMs={0}
|
|
762
|
+
/>
|
|
763
|
+
</InternationalizationProvider>,
|
|
764
|
+
);
|
|
765
|
+
// The row is derived per query, so the next query takes the new locale.
|
|
766
|
+
await act(async () => {
|
|
767
|
+
fireEvent.change(screen.getByRole('combobox'), {
|
|
768
|
+
target: {value: 'Kiwis'},
|
|
769
|
+
});
|
|
770
|
+
});
|
|
771
|
+
expect(await screen.findByText('Create "Kiwis"')).toBeInTheDocument();
|
|
772
|
+
});
|
|
773
|
+
|
|
726
774
|
it('still offers Create below minQueryLength, and does not search', async () => {
|
|
727
775
|
// The threshold exists to avoid a fetch too broad to be worth making.
|
|
728
776
|
// Creating costs no fetch, so a field that can create `QA` should not
|
|
@@ -2119,3 +2167,23 @@ describe('Tokenizer consumer key handler order', () => {
|
|
|
2119
2167
|
expect(currentTarget).toBe(screen.getByRole('combobox'));
|
|
2120
2168
|
});
|
|
2121
2169
|
});
|
|
2170
|
+
|
|
2171
|
+
describe('Tokenizer caller aria-labelledby', () => {
|
|
2172
|
+
it('names the input by its label and a caller aria-labelledby', () => {
|
|
2173
|
+
render(
|
|
2174
|
+
<>
|
|
2175
|
+
<span id="billing-heading">Billing</span>
|
|
2176
|
+
<Tokenizer
|
|
2177
|
+
label="Members"
|
|
2178
|
+
searchSource={userSource}
|
|
2179
|
+
value={[]}
|
|
2180
|
+
onChange={() => {}}
|
|
2181
|
+
aria-labelledby="billing-heading"
|
|
2182
|
+
/>
|
|
2183
|
+
</>,
|
|
2184
|
+
);
|
|
2185
|
+
expect(
|
|
2186
|
+
screen.getByRole('combobox', {name: 'Members Billing'}),
|
|
2187
|
+
).toBeInTheDocument();
|
|
2188
|
+
});
|
|
2189
|
+
});
|
|
@@ -85,6 +85,7 @@ import {
|
|
|
85
85
|
} from '../theme/tokens.stylex';
|
|
86
86
|
import type {SearchableItem, SearchSource} from '../Typeahead/types';
|
|
87
87
|
import {composeEventHandlers, mergeProps} from '../utils';
|
|
88
|
+
import {joinAriaIDs} from '../utils/inputAria';
|
|
88
89
|
import {themeProps} from '../utils/themeProps';
|
|
89
90
|
import {useTranslator} from '../i18n';
|
|
90
91
|
import type {TokenizerBottomSheetProps} from './TokenizerBottomSheet';
|
|
@@ -754,6 +755,7 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
754
755
|
experimental,
|
|
755
756
|
id: idProp,
|
|
756
757
|
'aria-describedby': ariaDescribedByProp,
|
|
758
|
+
'aria-labelledby': ariaLabelledByProp,
|
|
757
759
|
...restProps
|
|
758
760
|
}: TokenizerWithPresentationProps<T>): React.JSX.Element {
|
|
759
761
|
const {rest, container} = useFieldInputStyling('Tokenizer', restProps, {
|
|
@@ -768,8 +770,15 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
768
770
|
const size = useSize(sizeProp, 'md');
|
|
769
771
|
const generatedInputId = useId();
|
|
770
772
|
const inputId = idProp ?? generatedInputId;
|
|
773
|
+
const fieldLabelId = useId();
|
|
771
774
|
const descriptionId = useId();
|
|
772
775
|
const statusMessageId = useId();
|
|
776
|
+
// A caller aria-labelledby names the input together with the field's own
|
|
777
|
+
// label, which it would otherwise replace.
|
|
778
|
+
const fieldLabelledBy =
|
|
779
|
+
ariaLabelledByProp != null
|
|
780
|
+
? joinAriaIDs(fieldLabelId, ariaLabelledByProp)
|
|
781
|
+
: undefined;
|
|
773
782
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
774
783
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
775
784
|
|
|
@@ -1111,12 +1120,12 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
1111
1120
|
return [
|
|
1112
1121
|
{
|
|
1113
1122
|
id: `${CREATABLE_ID_PREFIX}${trimmed}`,
|
|
1114
|
-
label:
|
|
1123
|
+
label: t('@astryx.tokenizer.create', {value: trimmed}),
|
|
1115
1124
|
auxiliaryData: {__createdValue: trimmed},
|
|
1116
1125
|
} as unknown as T,
|
|
1117
1126
|
];
|
|
1118
1127
|
},
|
|
1119
|
-
[hasCreate, selectedIds, selectedLabels],
|
|
1128
|
+
[hasCreate, selectedIds, selectedLabels, t],
|
|
1120
1129
|
);
|
|
1121
1130
|
|
|
1122
1131
|
const emptySource: SearchSource<T> = useMemo(
|
|
@@ -1391,6 +1400,7 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
1391
1400
|
isFocusableDisabled={showsDisabledMessage}
|
|
1392
1401
|
hasAutoFocus={hasAutoFocus}
|
|
1393
1402
|
inputId={inputId}
|
|
1403
|
+
ariaLabelledBy={fieldLabelledBy}
|
|
1394
1404
|
ariaDescribedBy={
|
|
1395
1405
|
[ariaDescribedByProp, ariaDescribedBy]
|
|
1396
1406
|
.filter(Boolean)
|
|
@@ -1457,6 +1467,7 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
1457
1467
|
ref={triggerMergedRef}
|
|
1458
1468
|
type="button"
|
|
1459
1469
|
id={inputId}
|
|
1470
|
+
aria-labelledby={fieldLabelledBy}
|
|
1460
1471
|
aria-haspopup="dialog"
|
|
1461
1472
|
aria-expanded={isSheetOpen}
|
|
1462
1473
|
aria-disabled={isDisabled || undefined}
|
|
@@ -1707,6 +1718,7 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
1707
1718
|
isLabelHidden={isLabelHidden}
|
|
1708
1719
|
description={description}
|
|
1709
1720
|
inputID={inputId}
|
|
1721
|
+
labelID={ariaLabelledByProp != null ? fieldLabelId : undefined}
|
|
1710
1722
|
descriptionID={description ? descriptionId : undefined}
|
|
1711
1723
|
isOptional={isOptional}
|
|
1712
1724
|
isRequired={isRequired}
|
|
@@ -75,6 +75,7 @@ function Harness({
|
|
|
75
75
|
maxEntries?: number;
|
|
76
76
|
isDisabled?: boolean;
|
|
77
77
|
disabledMessage?: string;
|
|
78
|
+
'aria-labelledby'?: string;
|
|
78
79
|
debounceMs?: number;
|
|
79
80
|
onFocus?: (event: React.FocusEvent) => void;
|
|
80
81
|
onBlur?: (event: React.FocusEvent) => void;
|
|
@@ -238,6 +239,16 @@ describe('Tokenizer experimental.presentation (FR16)', () => {
|
|
|
238
239
|
});
|
|
239
240
|
|
|
240
241
|
describe('Tokenizer sheet presentation (single-sheet touch flow)', () => {
|
|
242
|
+
it('names the sheet trigger by its label, then a caller aria-labelledby', () => {
|
|
243
|
+
render(
|
|
244
|
+
<>
|
|
245
|
+
<span id="billing-heading">Billing</span>
|
|
246
|
+
<Harness aria-labelledby="billing-heading" />
|
|
247
|
+
</>,
|
|
248
|
+
);
|
|
249
|
+
expect(screen.getByRole('button', {name: 'Tags Billing'})).toBeTruthy();
|
|
250
|
+
});
|
|
251
|
+
|
|
241
252
|
it('keeps rows stable while open and applies selected-first order on reopen (FR19)', async () => {
|
|
242
253
|
const spy = vi.fn();
|
|
243
254
|
render(<Harness spy={spy} />);
|
|
@@ -1787,7 +1798,7 @@ describe('Tokenizer sheet presentation (single-sheet touch flow)', () => {
|
|
|
1787
1798
|
// changes until the sheet closes.
|
|
1788
1799
|
compact = false;
|
|
1789
1800
|
act(() => {
|
|
1790
|
-
for (const cb of listeners) cb();
|
|
1801
|
+
for (const cb of listeners) {cb();}
|
|
1791
1802
|
});
|
|
1792
1803
|
expect(screen.getByRole('dialog', {name: 'Tags'})).toBe(dialog);
|
|
1793
1804
|
expect(trigger).toBeInTheDocument();
|
|
@@ -2531,7 +2542,7 @@ describe('Tokenizer sheet presentation (single-sheet touch flow)', () => {
|
|
|
2531
2542
|
// the hand-off inside the field reports neither a blur nor a focus.
|
|
2532
2543
|
compact = false;
|
|
2533
2544
|
act(() => {
|
|
2534
|
-
for (const cb of listeners) cb();
|
|
2545
|
+
for (const cb of listeners) {cb();}
|
|
2535
2546
|
});
|
|
2536
2547
|
expect(screen.getByRole('combobox')).toHaveFocus();
|
|
2537
2548
|
expect(onFocus).toHaveBeenCalledTimes(1);
|
|
@@ -2539,14 +2550,14 @@ describe('Tokenizer sheet presentation (single-sheet touch flow)', () => {
|
|
|
2539
2550
|
// And back: the input focused, the screen becomes compact again.
|
|
2540
2551
|
compact = true;
|
|
2541
2552
|
act(() => {
|
|
2542
|
-
for (const cb of listeners) cb();
|
|
2553
|
+
for (const cb of listeners) {cb();}
|
|
2543
2554
|
});
|
|
2544
2555
|
expect(openTrigger()).toHaveFocus();
|
|
2545
2556
|
// Unfocused, a change moves nothing.
|
|
2546
2557
|
openTrigger().blur();
|
|
2547
2558
|
compact = false;
|
|
2548
2559
|
act(() => {
|
|
2549
|
-
for (const cb of listeners) cb();
|
|
2560
|
+
for (const cb of listeners) {cb();}
|
|
2550
2561
|
});
|
|
2551
2562
|
expect(document.body).toHaveFocus();
|
|
2552
2563
|
});
|
|
@@ -41,15 +41,15 @@ import {BottomSheet} from '../BottomSheet/BottomSheet';
|
|
|
41
41
|
import {Button} from '../Button/Button';
|
|
42
42
|
import {EmptyState} from '../EmptyState/EmptyState';
|
|
43
43
|
import {PanelSearchInput} from '../Field/PanelSearchInput';
|
|
44
|
-
import {Icon} from '../Icon';
|
|
44
|
+
import {Icon} from '../Icon/Icon';
|
|
45
45
|
import {CheckboxIndicator} from '../Indicator/CheckboxIndicator';
|
|
46
|
-
import {Spinner} from '../Spinner';
|
|
46
|
+
import {Spinner} from '../Spinner/Spinner';
|
|
47
47
|
import {useBusyAnnouncement} from '../hooks/useBusyAnnouncement';
|
|
48
48
|
import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
|
|
49
49
|
import {useAnnounce} from '../hooks/useAnnounce';
|
|
50
50
|
import {useAnnounceRenderedText} from '../hooks/useAnnounceRenderedText';
|
|
51
51
|
import {Text} from '../Text/Text';
|
|
52
|
-
import {useTranslator} from '../i18n';
|
|
52
|
+
import {useTranslator} from '../i18n/useTranslator';
|
|
53
53
|
import {warnOnce} from '../utils/devWarning';
|
|
54
54
|
import type {SearchableItem, SearchSource} from '../Typeahead/types';
|
|
55
55
|
import {colorVars, radiusVars, spacingVars} from '../theme/tokens.stylex';
|
|
@@ -80,10 +80,9 @@ Consumer migration instructions belong in consumer docs and release notes.
|
|
|
80
80
|
that does not hold the stop, the stop stays on the earlier control, so
|
|
81
81
|
Shift+Tab from the clicked control lands on that earlier control inside the
|
|
82
82
|
toolbar before leaving it.
|
|
83
|
-
- **
|
|
84
|
-
|
|
85
|
-
it
|
|
86
|
-
makes the toolbar a single tab stop.
|
|
83
|
+
- **Some fields keep their own tab stops.** A `textarea` or `select` in the
|
|
84
|
+
row is outside the roving stop: it keeps its own tab stop and the arrow keys
|
|
85
|
+
skip it. The APG toolbar pattern makes the toolbar a single tab stop.
|
|
87
86
|
|
|
88
87
|
## Ownership boundary
|
|
89
88
|
|
|
@@ -115,7 +114,7 @@ owns the shared structural-region boundary.
|
|
|
115
114
|
| FR1 | The render contains Section-owned Outer chrome around one Toolbar carrying `role="toolbar"`, `aria-label` from `label`, `aria-orientation`, and the `toolbar` target with `size`. Caller `role`, `aria-label`, and `aria-orientation` are dropped; other DOM props reach the toolbar row; `ref`, `className`, `style`, and `xstyle` reach the Section. | Current source, docs, tests, and family |
|
|
116
115
|
| FR2 | Without center content the Toolbar is a flex line of the present start and end lanes, a row when horizontal and a column of lanes when vertical; with center content it is a three-lane grid whose lanes sit side by side in either orientation. Each lane lays its controls out in a row. No lane clips its content, and the center lane can shrink below its content width. `gap` spaces controls within and between lanes. | Current source and focused structure tests |
|
|
117
116
|
| FR3 | Variant (default `transparent`), selected divider edges, and block padding by size remain delegated to Section, while Toolbar retains toolbar semantics, keyboard behavior, and internal layout. | Current source, docs, and family contract |
|
|
118
|
-
| FR4 | The row MUST be a single tab stop. ArrowRight and ArrowLeft (horizontal) or ArrowDown and ArrowUp (vertical) move focus between its controls, wrapping at the ends and skipping disabled controls; Home and End move to the first and last. Implementation gap: only buttons, inputs, and elements with `tabindex` share the stop, so
|
|
117
|
+
| FR4 | The row MUST be a single tab stop. ArrowRight and ArrowLeft (horizontal) or ArrowDown and ArrowUp (vertical) move focus between its controls, wrapping at the ends and skipping disabled controls; Home and End move to the first and last. Implementation gap: only buttons, inputs, links, and elements with `tabindex` share the stop, so `textarea` and `select` carry their own tab stops, and a pointer click does not move the stop (Current-state impact). Arrows do not move focus out of a text input whose caret is mid-line, and inside an open composed menu arrow keys belong to the menu. The toolbar keeps its tab stop after a composed menu is dismissed from outside, and keeps its own arrow movement when rendered inside a popover. | APG toolbar pattern; current source and tests |
|
|
119
118
|
| FR5 | Caller `onKeyDown`, `onFocus`, and `onBlur` run first; when the caller cancels the event, the built-in handling is skipped. | Current source and tests |
|
|
120
119
|
| FR6 | Keyboard focus entering the row can show a brief, self-dismissing hint for its arrow-key axis. | Current source |
|
|
121
120
|
| FR7 | `size` (default `md`) is provided to descendant controls as their default size; Toolbar starts its own size scope and does not inherit an outer size provider (`architecture:component-size-cascade` INV7). | Current source and tests |
|
|
@@ -204,7 +203,7 @@ Read from source, with no focused test yet:
|
|
|
204
203
|
- FR2: the flex and grid layouts themselves, and `gap` spacing.
|
|
205
204
|
- FR3: divider edges.
|
|
206
205
|
- FR5: caller `onFocus` and `onBlur` running first and their cancellation.
|
|
207
|
-
- FR4:
|
|
206
|
+
- FR4: `textarea` and `select` keeping their own tab stops, and the stop
|
|
208
207
|
staying put after a pointer click.
|
|
209
208
|
- FR6.
|
|
210
209
|
- FR7: descendant controls taking `size` as their default, and the fresh size
|
|
@@ -370,6 +370,36 @@ describe('Toolbar', () => {
|
|
|
370
370
|
expect(buttons[2]).toHaveAttribute('tabindex', '-1');
|
|
371
371
|
});
|
|
372
372
|
|
|
373
|
+
it('keeps a link member in the arrow order and off the tab order', async () => {
|
|
374
|
+
const user = userEvent.setup();
|
|
375
|
+
render(
|
|
376
|
+
<>
|
|
377
|
+
<Toolbar
|
|
378
|
+
label="Actions"
|
|
379
|
+
startContent={
|
|
380
|
+
<>
|
|
381
|
+
<button type="button">Cut</button>
|
|
382
|
+
<a href="https://example.com">Docs</a>
|
|
383
|
+
<button type="button">Paste</button>
|
|
384
|
+
</>
|
|
385
|
+
}
|
|
386
|
+
/>
|
|
387
|
+
<button type="button">After</button>
|
|
388
|
+
</>,
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
const cut = screen.getByRole('button', {name: 'Cut'});
|
|
392
|
+
cut.focus();
|
|
393
|
+
await user.tab();
|
|
394
|
+
expect(screen.getByRole('button', {name: 'After'})).toHaveFocus();
|
|
395
|
+
|
|
396
|
+
cut.focus();
|
|
397
|
+
await user.keyboard('{ArrowRight}');
|
|
398
|
+
expect(screen.getByRole('link', {name: 'Docs'})).toHaveFocus();
|
|
399
|
+
await user.keyboard('{ArrowRight}');
|
|
400
|
+
expect(screen.getByRole('button', {name: 'Paste'})).toHaveFocus();
|
|
401
|
+
});
|
|
402
|
+
|
|
373
403
|
it('keeps its tab stop after outside dismissal of MoreMenu', async () => {
|
|
374
404
|
const user = userEvent.setup();
|
|
375
405
|
render(
|
package/src/Toolbar/Toolbar.tsx
CHANGED
|
@@ -248,7 +248,8 @@ export function Toolbar({
|
|
|
248
248
|
const gapVar = spacingVars[spacingStepToVar[gap]] as string;
|
|
249
249
|
|
|
250
250
|
const {listRef, handleKeyDown, handleFocus} = useListFocus<HTMLDivElement>({
|
|
251
|
-
|
|
251
|
+
// `a[href]` catches a Button rendered with `href`.
|
|
252
|
+
itemSelector: 'button, input, a[href], [tabindex]',
|
|
252
253
|
boundarySelector: '[role="toolbar"], [popover]',
|
|
253
254
|
orientation,
|
|
254
255
|
hasRovingTabIndex: true,
|
|
@@ -93,15 +93,27 @@ async function runState(
|
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
// Checking coverage runs every state again, which on a loaded runner nears
|
|
97
|
+
// the per-test timeout as one test. It runs as one serial part per state,
|
|
98
|
+
// sharing their results, then one check over all of them.
|
|
99
|
+
test.describe('every toolbar expectation is exercised by a Toolbar state', () => {
|
|
100
|
+
test.describe.configure({mode: 'serial'});
|
|
100
101
|
const results: BindingResult[] = [];
|
|
102
|
+
|
|
101
103
|
for (const state of TOOLBAR_BINDING_STATES) {
|
|
102
|
-
|
|
104
|
+
test(`runs ${state.id}`, async ({page}) => {
|
|
105
|
+
const cdp = await page.context().newCDPSession(page);
|
|
106
|
+
results.push(await runState(page, cdp, state));
|
|
107
|
+
});
|
|
103
108
|
}
|
|
104
|
-
|
|
109
|
+
|
|
110
|
+
test('no expectation is left unexercised', () => {
|
|
111
|
+
// Every part ran in this worker; this test alone proves nothing.
|
|
112
|
+
expect(results.map(result => result.state).sort()).toEqual(
|
|
113
|
+
TOOLBAR_BINDING_STATES.map(state => state.id).sort(),
|
|
114
|
+
);
|
|
115
|
+
expect(neverExercised(results)).toEqual([]);
|
|
116
|
+
});
|
|
105
117
|
});
|
|
106
118
|
|
|
107
119
|
/**
|
|
@@ -104,16 +104,27 @@ async function runState(
|
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
// Checking coverage runs every state again, which on a loaded runner nears
|
|
108
|
+
// the per-test timeout as one test. It runs as one serial part per state,
|
|
109
|
+
// sharing their results, then one check over all of them.
|
|
110
|
+
test.describe('every tooltip expectation is exercised by a Tooltip state', () => {
|
|
111
|
+
test.describe.configure({mode: 'serial'});
|
|
112
112
|
const results: BindingResult[] = [];
|
|
113
|
+
|
|
113
114
|
for (const state of TOOLTIP_BINDING_STATES) {
|
|
114
|
-
|
|
115
|
+
test(`runs ${state.id}`, async ({page}) => {
|
|
116
|
+
const cdp = await page.context().newCDPSession(page);
|
|
117
|
+
results.push(await runState(page, cdp, state));
|
|
118
|
+
});
|
|
115
119
|
}
|
|
116
|
-
|
|
120
|
+
|
|
121
|
+
test('no expectation is left unexercised', () => {
|
|
122
|
+
// Every part ran in this worker; this test alone proves nothing.
|
|
123
|
+
expect(results.map(result => result.state).sort()).toEqual(
|
|
124
|
+
TOOLTIP_BINDING_STATES.map(state => state.id).sort(),
|
|
125
|
+
);
|
|
126
|
+
expect(neverExercised(results)).toEqual([]);
|
|
127
|
+
});
|
|
117
128
|
});
|
|
118
129
|
|
|
119
130
|
for (const state of TOOLTIP_BINDING_STATES) {
|