@astryxdesign/core 0.7.5 → 0.7.6-canary.bb18c81
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/BottomSheet/BottomSheet.js +1 -1
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +2 -1
- package/dist/BottomSheet/useSheetGestures.d.ts +12 -0
- package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
- package/dist/BottomSheet/useSheetGestures.js +30 -3
- package/dist/Button/Button.js +4 -4
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +6 -5
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +4 -1
- package/dist/DateInput/MonthScroller.d.ts.map +1 -1
- package/dist/DateInput/MonthScroller.js +101 -15
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +1 -1
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +4 -1
- 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.map +1 -1
- package/dist/Drawer/Drawer.js +5 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +4 -1
- package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -1
- package/dist/DropdownMenu/MenuBottomSheetActionList.js +6 -5
- package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +10 -1
- package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -1
- package/dist/DropdownMenu/lazyMenuBottomSheet.js +16 -2
- package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
- package/dist/DropdownMenu/renderDropdownItems.js +21 -16
- package/dist/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/EmptyState/EmptyState.js +2 -1
- package/dist/Field/FieldLabel.d.ts +1 -1
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +4 -4
- package/dist/Field/InputClearButton.js +3 -3
- package/dist/Field/PanelSearchInput.js +2 -2
- package/dist/FieldStatus/FieldStatus.js +2 -2
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +7 -1
- package/dist/Heading/Heading.js +1 -1
- package/dist/Icon/Icon.js +1 -1
- package/dist/Indicator/CheckIndicator.d.ts.map +1 -1
- package/dist/Indicator/CheckIndicator.js +2 -1
- package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
- package/dist/Indicator/CheckboxIndicator.js +3 -1
- package/dist/Indicator/RadioIndicator.d.ts.map +1 -1
- package/dist/Indicator/RadioIndicator.js +3 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +2 -1
- package/dist/Item/ItemSwipeLayer.js +1 -1
- package/dist/Layout/Layout.js +1 -1
- package/dist/Layout/LayoutContent.js +1 -1
- package/dist/Layout/LayoutFooter.js +1 -1
- package/dist/Layout/LayoutHeader.js +1 -1
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +5 -0
- package/dist/Lightbox/LightboxViewport.a11y.browser.spec.js +5 -4
- package/dist/List/List.js +1 -1
- package/dist/List/ListItem.js +3 -3
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +7 -2
- package/dist/MultiSelector/MultiSelector.d.ts +1 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +5 -2
- package/dist/NumberInput/NumberInput.d.ts +3 -1
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +3 -3
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +16 -12
- package/dist/Resizable/useResizable.d.ts.map +1 -1
- package/dist/Resizable/useResizable.js +28 -2
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +4 -1
- package/dist/Selector/useSelectorPresentation.d.ts +8 -1
- package/dist/Selector/useSelectorPresentation.d.ts.map +1 -1
- package/dist/Selector/useSelectorPresentation.js +20 -4
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +7 -1
- package/dist/Spinner/Spinner.js +2 -2
- package/dist/Stack/Stack.js +1 -1
- package/dist/Stack/StackItem.js +1 -1
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +16 -1
- package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
- package/dist/Table/plugins/columnResize/useTableColumnResize.js +9 -1
- package/dist/Text/Text.js +1 -1
- package/dist/Text/useTruncation.d.ts.map +1 -1
- package/dist/Text/useTruncation.js +23 -5
- package/dist/TextArea/TextArea.d.ts +1 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +13 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +3 -3
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +2 -2
- package/dist/Timestamp/TimestampHoverCard.js +4 -4
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +82 -51
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +13 -2
- package/dist/Tokenizer/TokenizerBottomSheet.js +3 -3
- package/dist/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/Toolbar/Toolbar.js +2 -1
- package/dist/Typeahead/Typeahead.d.ts +1 -1
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +9 -1
- package/dist/astryx.css +14 -1
- package/dist/gestures/PinchGestureRecognizer.d.ts +30 -0
- package/dist/gestures/PinchGestureRecognizer.d.ts.map +1 -0
- package/dist/gestures/PinchGestureRecognizer.js +125 -0
- package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +70 -0
- package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -0
- package/dist/gestures/ScreenEdgePanGestureRecognizer.js +220 -0
- package/dist/gestures/SwipeGestureRecognizer.d.ts +36 -0
- package/dist/gestures/SwipeGestureRecognizer.d.ts.map +1 -0
- package/dist/gestures/SwipeGestureRecognizer.js +145 -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/types.d.ts +11 -7
- package/dist/gestures/types.d.ts.map +1 -1
- package/dist/gestures/types.js +22 -2
- package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -1
- package/dist/hooks/useAdaptivePresentation.js +4 -1
- package/dist/hooks/useMenuHover.d.ts.map +1 -1
- package/dist/hooks/useMenuHover.js +12 -1
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +3 -0
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +3 -0
- package/dist/motion/animator.d.ts +7 -1
- package/dist/motion/animator.d.ts.map +1 -1
- package/dist/motion/animator.js +119 -27
- package/dist/theme/defineTheme.js +1 -1
- package/dist/theme/domainTokens/domainTokenDefaults.d.ts +3 -0
- package/dist/theme/domainTokens/domainTokenDefaults.d.ts.map +1 -0
- package/dist/theme/domainTokens/domainTokenDefaults.js +19 -0
- package/dist/theme/domainTokens/index.d.ts +5 -4
- package/dist/theme/domainTokens/index.d.ts.map +1 -1
- package/dist/theme/domainTokens/index.js +5 -9
- package/dist/utils/focusReturn.d.ts +17 -1
- package/dist/utils/focusReturn.d.ts.map +1 -1
- package/dist/utils/focusReturn.js +11 -4
- package/dist/utils/getNodeText.d.ts +8 -0
- package/dist/utils/getNodeText.d.ts.map +1 -0
- package/dist/utils/getNodeText.js +37 -0
- package/dist/utils/interactionModality.d.ts +11 -2
- package/dist/utils/interactionModality.d.ts.map +1 -1
- package/dist/utils/interactionModality.js +58 -5
- package/dist/utils/presentation.d.ts +50 -0
- package/dist/utils/presentation.d.ts.map +1 -0
- package/dist/utils/presentation.js +125 -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/locales/en.json +13 -1
- package/locales/pseudo.json +9 -0
- package/package.json +5 -4
- package/src/AlertDialog/AlertDialog.tsx +6 -5
- package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +18 -6
- package/src/Avatar/Avatar.spec.md +22 -22
- package/src/Avatar/Avatar.tsx +18 -1
- package/src/Avatar/__tests__/AvatarForcedColors.a11y.chromium.spec.ts +126 -0
- package/src/BottomSheet/BottomSheet.test.tsx +46 -0
- package/src/BottomSheet/BottomSheet.tsx +1 -1
- package/src/BottomSheet/BottomSheetPanel.tsx +2 -1
- package/src/BottomSheet/useSheetGestures.test.ts +52 -0
- package/src/BottomSheet/useSheetGestures.ts +37 -6
- package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.chromium.spec.ts +18 -6
- package/src/Button/Button.tsx +4 -4
- package/src/Calendar/Calendar.spec.md +87 -48
- package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +21 -7
- package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +21 -7
- package/src/CheckboxInput/CheckboxInput.tsx +6 -5
- package/src/Collapsible/Collapsible.spec.md +2 -0
- package/src/Collapsible/CollapsibleGroup.spec.md +57 -29
- package/src/Collapsible/__tests__/Collapsible.a11y.chromium.spec.ts +18 -7
- package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +18 -6
- package/src/ContextMenu/ContextMenu.test.tsx +35 -0
- package/src/DateInput/DateInput.test.tsx +53 -2
- package/src/DateInput/DateInput.tsx +15 -11
- package/src/DateInput/MonthScroller.tsx +106 -20
- package/src/DateInput/MonthScrollerSettle.test.tsx +165 -0
- 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.spec.md +71 -48
- package/src/DateTimeInput/DateTimeInput.test.tsx +61 -0
- package/src/DateTimeInput/DateTimeInput.tsx +15 -11
- 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 +22 -0
- package/src/Drawer/Drawer.tsx +5 -0
- package/src/Drawer/DrawerHeader.spec.md +181 -0
- package/src/DropdownMenu/DropdownMenu.test.tsx +41 -0
- package/src/DropdownMenu/DropdownMenu.tsx +7 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +34 -0
- package/src/DropdownMenu/MenuBottomSheetActionList.tsx +6 -5
- package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +19 -7
- package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +21 -9
- package/src/DropdownMenu/lazyMenuBottomSheet.test.ts +53 -0
- package/src/DropdownMenu/lazyMenuBottomSheet.ts +23 -6
- package/src/DropdownMenu/renderDropdownItems.tsx +24 -19
- package/src/EmptyState/EmptyState.tsx +2 -1
- package/src/Field/FieldLabel.tsx +5 -4
- package/src/Field/InputClearButton.tsx +3 -3
- package/src/Field/PanelSearchInput.tsx +2 -2
- package/src/FieldStatus/FieldStatus.tsx +2 -2
- package/src/FileInput/FileInput.test.tsx +21 -0
- package/src/FileInput/FileInput.tsx +4 -1
- package/src/FormLayout/FormLayout.spec.md +7 -8
- package/src/Heading/Heading.tsx +1 -1
- package/src/Icon/Icon.tsx +1 -1
- package/src/Indicator/CheckIndicator.spec.md +47 -42
- package/src/Indicator/CheckIndicator.tsx +2 -1
- package/src/Indicator/CheckboxIndicator.spec.md +40 -37
- package/src/Indicator/CheckboxIndicator.tsx +3 -1
- package/src/Indicator/Indicator.spec.md +188 -0
- package/src/Indicator/RadioIndicator.tsx +3 -1
- package/src/Item/Item.tsx +2 -1
- package/src/Item/ItemSwipeLayer.tsx +1 -1
- package/src/Layout/Layout.spec.md +127 -131
- package/src/Layout/Layout.tsx +1 -1
- package/src/Layout/LayoutContent.spec.md +205 -0
- package/src/Layout/LayoutContent.tsx +1 -1
- package/src/Layout/LayoutFooter.spec.md +190 -0
- package/src/Layout/LayoutFooter.tsx +1 -1
- package/src/Layout/LayoutHeader.spec.md +193 -0
- package/src/Layout/LayoutHeader.tsx +1 -1
- package/src/Layout/LayoutPanel.spec.md +194 -0
- package/src/Layout/__tests__/Layout.a11y.chromium.spec.ts +18 -6
- package/src/Lightbox/Lightbox.test.tsx +18 -0
- package/src/Lightbox/Lightbox.tsx +5 -0
- package/src/Lightbox/LightboxViewport.a11y.browser.spec.ts +8 -4
- package/src/Link/__tests__/Link.a11y.chromium.spec.ts +18 -8
- package/src/List/List.tsx +1 -1
- package/src/List/ListItem.tsx +3 -3
- package/src/MobileNav/MobileNav.test.tsx +15 -0
- package/src/MobileNav/MobileNav.tsx +9 -1
- package/src/MobileNav/__tests__/MobileNavHeader.a11y.chromium.spec.ts +89 -0
- package/src/MoreMenu/MoreMenu.test.tsx +11 -0
- package/src/MultiSelector/MultiSelector.spec.md +7 -4
- package/src/MultiSelector/MultiSelector.test.tsx +118 -1
- package/src/MultiSelector/MultiSelector.tsx +6 -2
- package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +8 -1
- package/src/NavMenu/NavHeadingMenu.spec.md +1 -5
- package/src/NumberInput/NumberInput.doc.mjs +13 -7
- package/src/NumberInput/NumberInput.spec.md +59 -37
- package/src/NumberInput/NumberInput.tsx +13 -3
- package/src/NumberInput/__tests__/NumberInput.coarse-pointer.a11y.chromium.spec.ts +102 -0
- package/src/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/Slider/Slider.test.tsx +12 -0
- package/src/Slider/Slider.tsx +4 -1
- package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +19 -7
- package/src/Spinner/Spinner.tsx +2 -2
- package/src/Stack/Stack.tsx +1 -1
- package/src/Stack/StackItem.tsx +1 -1
- package/src/TabList/TabList.test.tsx +52 -1
- 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/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 +7 -10
- package/src/Toast/ToastViewport.test.tsx +575 -1
- package/src/Toast/ToastViewport.tsx +100 -50
- package/src/Tokenizer/Tokenizer.spec.md +5 -3
- package/src/Tokenizer/Tokenizer.test.tsx +68 -0
- package/src/Tokenizer/Tokenizer.tsx +14 -2
- package/src/Tokenizer/TokenizerBottomSheet.test.tsx +15 -4
- package/src/Tokenizer/TokenizerBottomSheet.tsx +3 -3
- package/src/Toolbar/Toolbar.spec.md +5 -6
- package/src/Toolbar/Toolbar.test.tsx +30 -0
- package/src/Toolbar/Toolbar.tsx +2 -1
- package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +18 -6
- package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +18 -7
- package/src/TopNav/TopNav.test.tsx +27 -0
- package/src/Typeahead/Typeahead.test.tsx +40 -0
- package/src/Typeahead/Typeahead.tsx +12 -1
- package/src/gestures/PinchGestureRecognizer.ts +144 -0
- package/src/gestures/ScreenEdgePanGestureRecognizer.ts +252 -0
- package/src/gestures/SwipeGestureRecognizer.ts +193 -0
- package/src/gestures/VelocityTracker.ts +10 -3
- 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__/arenaPinchSwipeEdge.test.ts +188 -0
- package/src/gestures/__tests__/harness.ts +21 -2
- package/src/gestures/types.ts +23 -9
- package/src/hooks/useAdaptivePresentation.ts +4 -1
- package/src/hooks/useMenuHover.ts +15 -1
- package/src/i18n/generated-locales/en.generated.ts +4 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +4 -0
- package/src/motion/README.md +11 -1
- package/src/motion/animator.test.ts +151 -3
- package/src/motion/animator.ts +149 -33
- package/src/theme/defineTheme.ts +1 -1
- package/src/theme/derivedVarRegistry.test.ts +4 -0
- package/src/theme/domainTokens/domainTokenDefaults.ts +19 -0
- package/src/theme/domainTokens/index.ts +6 -10
- package/src/utils/focusReturn.ts +17 -6
- package/src/utils/getNodeText.test.ts +24 -0
- package/src/utils/getNodeText.ts +37 -0
- package/src/utils/interactionModality.test.ts +45 -1
- package/src/utils/interactionModality.ts +64 -5
- package/src/utils/presentation.test.ts +380 -0
- package/src/utils/presentation.ts +180 -0
- package/src/utils/pressPaintPriority.test.ts +80 -0
- package/src/utils/touchPresentation.stylex.ts +43 -0
- package/src/utils/touchPresentation.test.ts +140 -1
- package/src/utils/touchPresentation.ts +5 -3
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { AdaptivePresentation } from '../hooks/useAdaptivePresentation.js';
|
|
2
|
+
import type { CompactDefinition } from '../theme/themeAdaptations.js';
|
|
3
|
+
import { type TouchPresentation } from './touchPresentation.js';
|
|
4
|
+
/** What a component does when the caller omits `presentation`. */
|
|
5
|
+
export type PresentationDefault = 'popover' | 'touch';
|
|
6
|
+
export interface ResolvedPresentation {
|
|
7
|
+
/** The surface to render. */
|
|
8
|
+
readonly surface: 'popover' | 'bottom-sheet';
|
|
9
|
+
/**
|
|
10
|
+
* The component's touch input modes apply: a finger, and `presentation`
|
|
11
|
+
* not pinned to `'popover'`.
|
|
12
|
+
*/
|
|
13
|
+
readonly touchModes: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface PresentationOptions {
|
|
16
|
+
/** What an omitted `presentation` means. @default 'popover' */
|
|
17
|
+
readonly whenOmitted?: PresentationDefault;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* usePresentation's options. There is no server hint: the server and
|
|
21
|
+
* hydrating render never present touch modes (`spec:AST-094` FR13).
|
|
22
|
+
*/
|
|
23
|
+
export type UsePresentationOptions = PresentationOptions;
|
|
24
|
+
export interface ReadPresentationOptions extends PresentationOptions {
|
|
25
|
+
/** The window to read; the global one by default. */
|
|
26
|
+
readonly view?: Window | null;
|
|
27
|
+
/**
|
|
28
|
+
* The active theme's compact definition (`useCompactDefinition()`, read
|
|
29
|
+
* while rendering), so a theme that moves `md` moves the sheet too
|
|
30
|
+
* (`spec:AST-012` FR9).
|
|
31
|
+
*/
|
|
32
|
+
readonly compact: CompactDefinition;
|
|
33
|
+
}
|
|
34
|
+
/** The decision, from a presentation request and a touch presentation. */
|
|
35
|
+
export declare function resolvePresentation(presentation: AdaptivePresentation | undefined, touch: TouchPresentation, whenOmitted?: PresentationDefault): ResolvedPresentation;
|
|
36
|
+
/**
|
|
37
|
+
* The presentation now, following the pointer and the size as they change
|
|
38
|
+
* (a tablet docking a trackpad). SSR-safe: renders the server default (not
|
|
39
|
+
* touch, not compact) until hydrated (`spec:AST-094` FR13). It subscribes
|
|
40
|
+
* only to what the request reads: a pinned `'popover'` to neither query,
|
|
41
|
+
* `'bottom-sheet'` and the omitted `'touch'` default to the pointer, and
|
|
42
|
+
* `'adaptive'` to the pointer and the compact size.
|
|
43
|
+
*/
|
|
44
|
+
export declare function usePresentation(presentation: AdaptivePresentation | undefined, { whenOmitted }?: UsePresentationOptions): ResolvedPresentation;
|
|
45
|
+
/**
|
|
46
|
+
* The presentation at this moment, for a decision taken once (a menu
|
|
47
|
+
* deciding how it follows the finger that opened it).
|
|
48
|
+
*/
|
|
49
|
+
export declare function readPresentation(presentation: AdaptivePresentation | undefined, { whenOmitted, view, compact }: ReadPresentationOptions): ResolvedPresentation;
|
|
50
|
+
//# sourceMappingURL=presentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../../src/utils/presentation.ts"],"names":[],"mappings":"AAoDA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,kCAAkC,CAAC;AAC3E,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,qBAAqB,CAAC;AAE7B,kEAAkE;AAClE,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtD,MAAM,WAAW,oBAAoB;IACnC,6BAA6B;IAC7B,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,cAAc,CAAC;IAC7C;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,+DAA+D;IAC/D,QAAQ,CAAC,WAAW,CAAC,EAAE,mBAAmB,CAAC;CAC5C;AAED;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAEzD,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE,qDAAqD;IACrD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;CACrC;AAED,0EAA0E;AAC1E,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,oBAAoB,GAAG,SAAS,EAC9C,KAAK,EAAE,iBAAiB,EACxB,WAAW,GAAE,mBAA+B,GAC3C,oBAAoB,CAStB;AA8BD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,oBAAoB,GAAG,SAAS,EAC9C,EAAC,WAAuB,EAAC,GAAE,sBAA2B,GACrD,oBAAoB,CAWtB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,oBAAoB,GAAG,SAAS,EAC9C,EAAC,WAAuB,EAAE,IAAI,EAAE,OAAO,EAAC,EAAE,uBAAuB,GAChE,oBAAoB,CAQtB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file presentation.ts
|
|
7
|
+
* @input A component's `presentation` prop (a caller's value, or omitted),
|
|
8
|
+
* what the component does when it is omitted, and the touch presentation
|
|
9
|
+
* (utils/touchPresentation.ts)
|
|
10
|
+
* @output usePresentation and readPresentation (and the pure
|
|
11
|
+
* resolvePresentation): the surface to render and whether the component's
|
|
12
|
+
* touch input modes apply
|
|
13
|
+
* @position Internal resolver for stable components that, under a finger,
|
|
14
|
+
* present a different surface or switch how an open surface follows input
|
|
15
|
+
* (architecture:public-component-api INV16)
|
|
16
|
+
*
|
|
17
|
+
* A caller's explicit `presentation` always wins over the touch default:
|
|
18
|
+
*
|
|
19
|
+
* - `'popover'`: the fine-pointer surface AND input modes, on every device;
|
|
20
|
+
* - `'bottom-sheet'`: the sheet everywhere, with touch input modes under a
|
|
21
|
+
* finger;
|
|
22
|
+
* - `'adaptive'`: the sheet on a compact touch screen and the popover
|
|
23
|
+
* elsewhere, with touch input modes under a finger;
|
|
24
|
+
* - omitted: the component's default. `whenOmitted: 'popover'` answers as
|
|
25
|
+
* `'popover'` (today's components). `whenOmitted: 'touch'` keeps the
|
|
26
|
+
* popover surface and turns the component's touch input modes on under a
|
|
27
|
+
* finger, as UIMenu tracks a finger in an anchored menu. Making `'touch'`
|
|
28
|
+
* a released component's default is a functional default change
|
|
29
|
+
* (`spec:AST-017` FR3) whose Changeset names `presentation="popover"`.
|
|
30
|
+
*
|
|
31
|
+
* One touch model on every touch device: the modes depend on the pointer,
|
|
32
|
+
* never on the platform. Touch styling (press paint, the text-size floor)
|
|
33
|
+
* and touch-only behavior that a component's own record defines (a row
|
|
34
|
+
* swipe, a slider's thumb) do not read this: they keep the touch
|
|
35
|
+
* presentation.
|
|
36
|
+
*
|
|
37
|
+
* CSS: a style that implements a touch surface or input mode is applied with
|
|
38
|
+
* `touchModes` (`stylex.props(touchModes && styles.touchMode)`), never as a
|
|
39
|
+
* bare media key on a base style, so a pinned `'popover'` keeps none of it.
|
|
40
|
+
* A rule inside it that needs the touch query uses the touch presentation's
|
|
41
|
+
* touch key; the iOS `@supports` gate is only for the one style iOS WebKit
|
|
42
|
+
* itself requires (the 16px text-size floor), never for a touch mode. On the
|
|
43
|
+
* server and while hydrating, `touchModes` is false and `'adaptive'` is the
|
|
44
|
+
* popover: a touch surface or mode opens only after hydration
|
|
45
|
+
* (`spec:AST-094` FR13), and no hint changes that. usePresentation listens
|
|
46
|
+
* only to the queries a request reads (`architecture:react-component-runtime`
|
|
47
|
+
* INV5): none for a pinned `'popover'`.
|
|
48
|
+
*
|
|
49
|
+
* SYNC: When modified, update presentation.test.ts.
|
|
50
|
+
*/
|
|
51
|
+
import { useCallback, useMemo, useSyncExternalStore } from 'react';
|
|
52
|
+
import { readTouchPresentation, TOUCH_QUERY, useCompactDefinition } from "./touchPresentation.js";
|
|
53
|
+
|
|
54
|
+
/** What a component does when the caller omits `presentation`. */
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* usePresentation's options. There is no server hint: the server and
|
|
58
|
+
* hydrating render never present touch modes (`spec:AST-094` FR13).
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
/** The decision, from a presentation request and a touch presentation. */
|
|
62
|
+
export function resolvePresentation(presentation, touch, whenOmitted = 'popover') {
|
|
63
|
+
const request = presentation ?? whenOmitted;
|
|
64
|
+
const surface = request === 'bottom-sheet' || request === 'adaptive' && touch.isTouch && touch.isCompact ? 'bottom-sheet' : 'popover';
|
|
65
|
+
const touchModes = request !== 'popover' && touch.isTouch;
|
|
66
|
+
return {
|
|
67
|
+
surface,
|
|
68
|
+
touchModes
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const noSubscription = () => () => {};
|
|
72
|
+
/** The server and hydrating render match no query (`spec:AST-094` FR13). */
|
|
73
|
+
const matchesNothing = () => false;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A media query's match, subscribed only while `query` is given
|
|
77
|
+
* (`architecture:react-component-runtime` INV5); false on the server and
|
|
78
|
+
* while hydrating (`spec:AST-094` FR13).
|
|
79
|
+
*/
|
|
80
|
+
function useMatchWhileRead(query) {
|
|
81
|
+
const subscribe = useCallback(onStoreChange => {
|
|
82
|
+
if (query == null) {
|
|
83
|
+
return noSubscription();
|
|
84
|
+
}
|
|
85
|
+
const mql = window.matchMedia(query);
|
|
86
|
+
mql.addEventListener('change', onStoreChange);
|
|
87
|
+
return () => mql.removeEventListener('change', onStoreChange);
|
|
88
|
+
}, [query]);
|
|
89
|
+
const getSnapshot = useCallback(() => query != null && window.matchMedia(query).matches, [query]);
|
|
90
|
+
return useSyncExternalStore(subscribe, getSnapshot, matchesNothing);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The presentation now, following the pointer and the size as they change
|
|
95
|
+
* (a tablet docking a trackpad). SSR-safe: renders the server default (not
|
|
96
|
+
* touch, not compact) until hydrated (`spec:AST-094` FR13). It subscribes
|
|
97
|
+
* only to what the request reads: a pinned `'popover'` to neither query,
|
|
98
|
+
* `'bottom-sheet'` and the omitted `'touch'` default to the pointer, and
|
|
99
|
+
* `'adaptive'` to the pointer and the compact size.
|
|
100
|
+
*/
|
|
101
|
+
export function usePresentation(presentation, {
|
|
102
|
+
whenOmitted = 'popover'
|
|
103
|
+
} = {}) {
|
|
104
|
+
const request = presentation ?? whenOmitted;
|
|
105
|
+
const compact = useCompactDefinition();
|
|
106
|
+
const isTouch = useMatchWhileRead(request === 'popover' ? null : TOUCH_QUERY);
|
|
107
|
+
const isCompact = useMatchWhileRead(request === 'adaptive' ? compact.query : null);
|
|
108
|
+
return useMemo(() => resolvePresentation(presentation, {
|
|
109
|
+
isTouch,
|
|
110
|
+
isCompact
|
|
111
|
+
}, whenOmitted), [presentation, isTouch, isCompact, whenOmitted]);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The presentation at this moment, for a decision taken once (a menu
|
|
116
|
+
* deciding how it follows the finger that opened it).
|
|
117
|
+
*/
|
|
118
|
+
export function readPresentation(presentation, {
|
|
119
|
+
whenOmitted = 'popover',
|
|
120
|
+
view,
|
|
121
|
+
compact
|
|
122
|
+
}) {
|
|
123
|
+
const target = view === undefined ? typeof window === 'undefined' ? null : window : view;
|
|
124
|
+
return resolvePresentation(presentation, readTouchPresentation(target, compact), whenOmitted);
|
|
125
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"touchPresentation.d.ts","sourceRoot":"","sources":["../../src/utils/touchPresentation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"touchPresentation.d.ts","sourceRoot":"","sources":["../../src/utils/touchPresentation.ts"],"names":[],"mappings":"AA+DA,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,2BAA2B,CAAC;AAGnC,uDAAuD;AACvD,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAE/C;;;;;GAKG;AACH,eAAO,MAAM,aAAa,QAAmC,CAAC;AAE9D,wEAAwE;AACxE,eAAO,MAAM,mBAAmB,QACe,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,kCAAkC,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,oBAAoB,kFAGvB,CAAC;AAEX,MAAM,WAAW,iBAAiB;IAChC,gDAAgD;IAChD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,+BAA+B;IAC/B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,iBAAiB,CAOxD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,aAAa,GAAE,OAAO,CAAC,iBAAiB,CAAM,GAC7C,iBAAiB,CAQnB;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,OAAO,EAAE,iBAAiB,GACzB,iBAAiB,CAOnB"}
|
|
@@ -46,9 +46,11 @@
|
|
|
46
46
|
* test keeps core's compact-touch keys identical to COMPACT_TOUCH_QUERY and
|
|
47
47
|
* every touch-callout key spelled and nested as above. The iOS style gate
|
|
48
48
|
* is only for a style iOS WebKit itself requires (core's 16px input floor);
|
|
49
|
-
* it never selects a behaviour.
|
|
50
|
-
*
|
|
51
|
-
*
|
|
49
|
+
* it never selects a behaviour. Core spells the keys literally: an imported
|
|
50
|
+
* `defineConsts` key compiles to a different StyleX priority than the same
|
|
51
|
+
* literal, which would reorder the cascade. `touchKeys`
|
|
52
|
+
* (touchPresentation.stylex.ts, internal to core) holds the same keys, and a
|
|
53
|
+
* test keeps every literal equal to them. The hook is for behaviour. It answers the server default
|
|
52
54
|
* (not touch, not compact) until hydrated unless the caller passes a server
|
|
53
55
|
* hint, and follows the pointer and size when they change (a tablet docking
|
|
54
56
|
* a mouse).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const touchKeys: {
|
|
2
|
+
/** The primary pointer is coarse (TOUCH_QUERY). */
|
|
3
|
+
touch: string;
|
|
4
|
+
/** The viewport is compact (COMPACT_QUERY, `spec:AST-012` FR9). */
|
|
5
|
+
compact: string;
|
|
6
|
+
/** Both: a presentation such as a sheet in place of a popover. */
|
|
7
|
+
compactTouch: string;
|
|
8
|
+
/**
|
|
9
|
+
* The iOS WebKit gate, inside `touch` (IOS_SUPPORTS_QUERY): only for a
|
|
10
|
+
* style iOS WebKit itself requires (the 16px input floor), never a
|
|
11
|
+
* behaviour; touch behaviour is one model on every touch device.
|
|
12
|
+
*/
|
|
13
|
+
iosSupports: string;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=touchPresentation.stylex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"touchPresentation.stylex.d.ts","sourceRoot":"","sources":["../../src/utils/touchPresentation.stylex.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,SAAS;IACpB,mDAAmD;;IAEnD,mEAAmE;;IAEnE,kEAAkE;;IAGlE;;;;OAIG;;CAEH,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file touchPresentation.stylex.ts
|
|
5
|
+
* @input Uses StyleX defineConsts
|
|
6
|
+
* @output Exports touchKeys: the touch presentation resolver's queries as
|
|
7
|
+
* StyleX at-rule keys
|
|
8
|
+
* @position The reference spellings of the touch, compact and iOS-gate
|
|
9
|
+
* conditions. Core styles write these as literal keys wherever they need
|
|
10
|
+
* them (`spec:AST-094` FR13, `spec:AST-012` FR9), and a test pins each
|
|
11
|
+
* literal to these values; utils/touchPresentation.ts holds the same
|
|
12
|
+
* queries for script (matchMedia)
|
|
13
|
+
*
|
|
14
|
+
* These are the spellings to match. A style that changes with these
|
|
15
|
+
* conditions writes the same literal key (`'@media (pointer: coarse)'`, the
|
|
16
|
+
* iOS gate as that media key outside `'@supports (-webkit-touch-callout:
|
|
17
|
+
* none)'`), and a test pins every literal in core to these values. Do not use
|
|
18
|
+
* an imported key as a computed StyleX key: it compiles to a different
|
|
19
|
+
* priority than the literal (6000 against 3200) and reorders the cascade.
|
|
20
|
+
* The iOS supports gate is only for a style iOS WebKit itself requires (the
|
|
21
|
+
* 16px input floor), never a behaviour.
|
|
22
|
+
*
|
|
23
|
+
* SYNC: When modified, update touchPresentation.ts and
|
|
24
|
+
* touchPresentation.test.ts.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import * as stylex from '@stylexjs/stylex';
|
|
28
|
+
export const touchKeys = {
|
|
29
|
+
touch: "@media (pointer: coarse)",
|
|
30
|
+
compact: "@media (width < 768px), (height < 500px)",
|
|
31
|
+
compactTouch: "@media (width < 768px) and (pointer: coarse), (height < 500px) and (pointer: coarse)",
|
|
32
|
+
iosSupports: "@supports (-webkit-touch-callout: none)"
|
|
33
|
+
};
|
package/locales/en.json
CHANGED
|
@@ -803,6 +803,10 @@
|
|
|
803
803
|
"defaultMessage": "No data",
|
|
804
804
|
"description": "Fallback empty-state text in the table body when there are zero rows. Neutral tone (not error-y); consumers commonly override with something specific like \"No results\"."
|
|
805
805
|
},
|
|
806
|
+
"@astryx.table.columnResize.resizeColumn": {
|
|
807
|
+
"defaultMessage": "Resize column {label}",
|
|
808
|
+
"description": "Accessible name for a Table column-resize handle (a vertical separator between header cells). `label` is the column header's visible text, or the column key when the header has no text."
|
|
809
|
+
},
|
|
806
810
|
"@astryx.table.filter.allPlaceholder": {
|
|
807
811
|
"defaultMessage": "All",
|
|
808
812
|
"description": "Placeholder on a per-column filter dropdown when nothing is selected, meaning \"no filter — all rows match\". Determiner form (as in \"all values\"), not the pronoun."
|
|
@@ -1567,6 +1571,10 @@
|
|
|
1567
1571
|
"defaultMessage": "Expand all rows",
|
|
1568
1572
|
"description": "Aria label for the Table tree-data header toggle when rows are collapsed and clicking it expands them."
|
|
1569
1573
|
},
|
|
1574
|
+
"@astryx.textArea.counter": {
|
|
1575
|
+
"defaultMessage": "{count, number}/{limit, number}",
|
|
1576
|
+
"description": "Visible character counter at the bottom of a TextArea that has a character limit, for example `62/2,000`. `{count}` is the characters typed so far and `{limit}` the limit; keep both numbers and reorder or change the separator if your language needs to."
|
|
1577
|
+
},
|
|
1570
1578
|
"@astryx.textArea.charactersRemaining": {
|
|
1571
1579
|
"defaultMessage": "{count, number} {count, plural, one {character} other {characters}} remaining",
|
|
1572
1580
|
"description": "Screen-reader-only announcement of how many characters the user can still type before hitting a TextArea's maxLength. Announced politely as the count nears the limit. `{count}` is the number remaining — example: `12 characters remaining`."
|
|
@@ -1643,6 +1651,10 @@
|
|
|
1643
1651
|
"defaultMessage": "{count, number} of {total, number} selected",
|
|
1644
1652
|
"description": "Polite screen-reader announcement of how many MultiSelector options are selected out of the total, spoken after each toggle. Live-region text, never shown on screen; example: `3 of 12 selected`."
|
|
1645
1653
|
},
|
|
1654
|
+
"@astryx.multiSelector.selectedCount": {
|
|
1655
|
+
"defaultMessage": "{count, plural, one {# selected} other {# selected}}",
|
|
1656
|
+
"description": "Visible text on a closed MultiSelector's trigger when it shows a count of the chosen options (`triggerDisplay=\"count\"`), for example `2 selected`. `{count}` is the number of chosen options; use a plural form if your language needs one."
|
|
1657
|
+
},
|
|
1646
1658
|
"@astryx.multiSelector.createOption": {
|
|
1647
1659
|
"defaultMessage": "Create \"{query}\"",
|
|
1648
1660
|
"description": "Label of the first row in a MultiSelector's search panel when `hasCreate` is set and the typed text matches no option. Picking it reports a creation to the caller. `{query}` is the trimmed text the person typed, shown in quotes."
|
|
@@ -1693,7 +1705,7 @@
|
|
|
1693
1705
|
},
|
|
1694
1706
|
"@astryx.tokenizer.create": {
|
|
1695
1707
|
"defaultMessage": "Create \"{value}\"",
|
|
1696
|
-
"description": "Label of
|
|
1708
|
+
"description": "Label of a Tokenizer's create row, in the inline menu and the bottom sheet, when `hasCreate` is set and the typed text matches no existing item. `{value}` is the typed text, e.g. `Create \"Marketing\"`."
|
|
1697
1709
|
},
|
|
1698
1710
|
"@astryx.tokenizer.add": {
|
|
1699
1711
|
"defaultMessage": "Add",
|
package/locales/pseudo.json
CHANGED
|
@@ -602,6 +602,9 @@
|
|
|
602
602
|
"@astryx.table.noData": {
|
|
603
603
|
"defaultMessage": "⟦Ñó ðàţà⟧"
|
|
604
604
|
},
|
|
605
|
+
"@astryx.table.columnResize.resizeColumn": {
|
|
606
|
+
"defaultMessage": "⟦Řéšížé çółúɱñ {label}⟧"
|
|
607
|
+
},
|
|
605
608
|
"@astryx.table.filter.allPlaceholder": {
|
|
606
609
|
"defaultMessage": "⟦Àłł⟧"
|
|
607
610
|
},
|
|
@@ -1175,6 +1178,9 @@
|
|
|
1175
1178
|
"@astryx.tableTree.expandAllRows": {
|
|
1176
1179
|
"defaultMessage": "⟦Éẋþàñð àłł řóŵš⟧"
|
|
1177
1180
|
},
|
|
1181
|
+
"@astryx.textArea.counter": {
|
|
1182
|
+
"defaultMessage": "⟦{count, number}/{limit, number}⟧"
|
|
1183
|
+
},
|
|
1178
1184
|
"@astryx.textArea.charactersRemaining": {
|
|
1179
1185
|
"defaultMessage": "⟦{count, number} {count, plural, one {character} other {characters}} řéɱàíñíñĝ⟧"
|
|
1180
1186
|
},
|
|
@@ -1232,6 +1238,9 @@
|
|
|
1232
1238
|
"@astryx.multiSelector.selectionCount": {
|
|
1233
1239
|
"defaultMessage": "⟦{count, number} óƒ {total, number} šéłéçţéð⟧"
|
|
1234
1240
|
},
|
|
1241
|
+
"@astryx.multiSelector.selectedCount": {
|
|
1242
|
+
"defaultMessage": "⟦{count, plural, one {# selected} other {# selected}}⟧"
|
|
1243
|
+
},
|
|
1235
1244
|
"@astryx.multiSelector.createOption": {
|
|
1236
1245
|
"defaultMessage": "⟦Çřéàţé \"{query}\"⟧"
|
|
1237
1246
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/core",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.6-canary.bb18c81",
|
|
4
4
|
"displayName": "Astryx Core",
|
|
5
5
|
"description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
|
|
6
6
|
"author": "Meta Open Source",
|
|
@@ -847,6 +847,9 @@
|
|
|
847
847
|
"react-dom": ">=19.0.0"
|
|
848
848
|
},
|
|
849
849
|
"devDependencies": {
|
|
850
|
+
"@astryxdesign/a11y-spec": "0.7.6-canary.bb18c81",
|
|
851
|
+
"@astryxdesign/cli": "0.7.6-canary.bb18c81",
|
|
852
|
+
"@astryxdesign/interaction-harness": "0.7.6-canary.bb18c81",
|
|
850
853
|
"@babel/cli": "^7.29.7",
|
|
851
854
|
"@babel/core": "^7.29.7",
|
|
852
855
|
"@babel/preset-react": "^7.29.7",
|
|
@@ -857,9 +860,7 @@
|
|
|
857
860
|
"@testing-library/jest-dom": "^6.6.0",
|
|
858
861
|
"@testing-library/react": "^16.3.2",
|
|
859
862
|
"@types/babel__core": "^7.20.5",
|
|
860
|
-
"tailwindcss": "^4.3.2"
|
|
861
|
-
"@astryxdesign/cli": "0.7.5",
|
|
862
|
-
"@astryxdesign/a11y-spec": "0.0.0"
|
|
863
|
+
"tailwindcss": "^4.3.2"
|
|
863
864
|
},
|
|
864
865
|
"dependencies": {
|
|
865
866
|
"intl-messageformat": "^11.2.9"
|
|
@@ -18,18 +18,19 @@
|
|
|
18
18
|
|
|
19
19
|
import React, {useId, useCallback} from 'react';
|
|
20
20
|
import * as stylex from '@stylexjs/stylex';
|
|
21
|
-
import {Dialog} from '../Dialog';
|
|
21
|
+
import {Dialog} from '../Dialog/Dialog';
|
|
22
22
|
import {Layout} from '../Layout/Layout';
|
|
23
23
|
import {LayoutContent} from '../Layout/LayoutContent';
|
|
24
24
|
import {LayoutFooter} from '../Layout/LayoutFooter';
|
|
25
|
-
import {Stack} from '../Stack';
|
|
25
|
+
import {Stack} from '../Stack/Stack';
|
|
26
26
|
import {Heading} from '../Heading/Heading';
|
|
27
27
|
import {Text} from '../Text/Text';
|
|
28
|
-
import {Button
|
|
28
|
+
import {Button} from '../Button/Button';
|
|
29
|
+
import type {ButtonVariant} from '../Button';
|
|
29
30
|
import type {BaseProps} from '../BaseProps';
|
|
30
|
-
import {mergeProps} from '../utils';
|
|
31
|
+
import {mergeProps} from '../utils/mergeProps';
|
|
31
32
|
import {themeProps} from '../utils/themeProps';
|
|
32
|
-
import {useTranslator} from '../i18n';
|
|
33
|
+
import {useTranslator} from '../i18n/useTranslator';
|
|
33
34
|
import {useMediaQuery} from '../hooks/useMediaQuery';
|
|
34
35
|
|
|
35
36
|
const SMALL_SCREEN_QUERY = '(max-width: 640px)';
|
|
@@ -91,15 +91,27 @@ async function runState(
|
|
|
91
91
|
});
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
// Checking coverage runs every state again, which on a loaded runner nears
|
|
95
|
+
// the per-test timeout as one test. It runs as one serial part per state,
|
|
96
|
+
// sharing their results, then one check over all of them.
|
|
97
|
+
test.describe('every alert-dialog expectation is exercised by an AlertDialog state', () => {
|
|
98
|
+
test.describe.configure({mode: 'serial'});
|
|
98
99
|
const results: BindingResult[] = [];
|
|
100
|
+
|
|
99
101
|
for (const state of ALERT_DIALOG_BINDING_STATES) {
|
|
100
|
-
|
|
102
|
+
test(`runs ${state.id}`, async ({page}) => {
|
|
103
|
+
const cdp = await page.context().newCDPSession(page);
|
|
104
|
+
results.push(await runState(page, cdp, state));
|
|
105
|
+
});
|
|
101
106
|
}
|
|
102
|
-
|
|
107
|
+
|
|
108
|
+
test('no expectation is left unexercised', () => {
|
|
109
|
+
// Every part ran in this worker; this test alone proves nothing.
|
|
110
|
+
expect(results.map(result => result.state).sort()).toEqual(
|
|
111
|
+
ALERT_DIALOG_BINDING_STATES.map(state => state.id).sort(),
|
|
112
|
+
);
|
|
113
|
+
expect(neverExercised(results)).toEqual([]);
|
|
114
|
+
});
|
|
103
115
|
});
|
|
104
116
|
|
|
105
117
|
for (const state of ALERT_DIALOG_BINDING_STATES) {
|
|
@@ -122,17 +122,17 @@ Consumer migration instructions belong in consumer docs and release notes.
|
|
|
122
122
|
|
|
123
123
|
## Behavioral and layout contract
|
|
124
124
|
|
|
125
|
-
| ID | Invariant
|
|
126
|
-
| --- |
|
|
127
|
-
| FR1 | The root is a relative, non-shrinking inline-flex box of the resolved size with the shape's radius; it carries the `avatar` target, which reflects `size` and `shape`. A clipped content area fills it with the same radius and suppresses text selection.
|
|
128
|
-
| FR2 | The content area shows `src` while it has not failed, then `fallbackSrc` while it has not failed, then initials when the name yields any, then a default person icon at 60% of the box. Each image renders with empty `alt` and `object-fit: cover`. A failure is tracked per source, so a changed `src` or `fallbackSrc` is tried again.
|
|
129
|
-
| FR3 | Initials are the first letter, digit, or emoji of the first and last words of the trimmed `name`, uppercased; leading punctuation in a word is skipped, words with none are dropped, one qualifying word yields one initial, and grapheme clusters are never split. A whitespace-only name counts as absent. Initials and the default icon paint on the `avatar-fallback` target (reflecting `size`) with `--color-neutral`, secondary text, body family, medium weight, and initials at 40% of the box.
|
|
130
|
-
| FR4 | A truthy `status` renders in an absolutely positioned slot outside the clipped content area. On a circle it centers on the circle's edge at the bottom inline-end 45° point; on other shapes it sits at the bottom inline-end corner, offset outward by a quarter of its size. Placement mirrors in right-to-left documents.
|
|
131
|
-
| FR5 | The resolved name is `alt`, else `name` (blank strings count as absent), composed with the status label as the translated "{name}, {status}" when both exist; a status label alone also names the avatar. The status label comes from a string `label` on the passed element, read on every render, and from a label an AvatarStatusDot reports at any wrapper depth, which wins and updates the root before paint without a second render.
|
|
132
|
-
| FR6 | `href` renders the shared link component (or `as`) with `target` and `rel`; otherwise `onClick` renders a `button type="button"`; otherwise the root is a `div`. Link and button roots carry the `data-avatar-item` marker and the shared focus-visible outline; `onClick` attaches to the link or button. In development, an interactive avatar whose only name is a status label, or that has no name and no caller `aria-label`/`aria-labelledby`, logs a warning.
|
|
133
|
-
| FR7 | The tooltip shows the trimmed custom string, else the meaningful `name`, placed above, on hover and keyboard focus; `tooltip={false}` or a blank result shows none. A static avatar with a tooltip and outside a group gets `tabIndex={0}` so keyboard users can reveal it. A custom string is added to `aria-describedby` after any caller value; the default name tooltip is not, because it repeats the name. Implementation gap: a grouped link or button avatar that is not the group's tab stop stops opening its tooltip on focus after a re-render that re-attaches its root element: a new `status` element (an inline `status` prop creates one on every parent render), a changed `name`, `alt`, locale, caller ARIA, or caller `ref`, or a tooltip that turns on after mount (Current-state impact).
|
|
134
|
-
| FR8 | Inside an AvatarGroup in the same layer (`spec:AST-038` FR7, FR8), the group's size and shape win over the avatar's own props; the root gains a 2px surface-colored ring outside its box and the group's negative inline-start overlap; a static avatar adds no tooltip tab stop, and link and button roots keep the `data-avatar-item` marker so they join the group's roving set. An avatar in a hover card, popover, or other layer opened from a group keeps its own size and shape, gets no ring or overlap, and keeps its tooltip tab stop; a link or button avatar there still carries the marker, so the group's roving focus, which selects marked elements in its DOM subtree, still includes it.
|
|
135
|
-
| FR9 | `ref` reaches the root of every variant. Supported DOM, ARIA, data, and event props reach the root after the derived ARIA, so a caller `aria-label`, `role`, or `aria-hidden` wins (`architecture:public-component-api` INV5); `data-testid` reaches the root; `xstyle`, `className`, and `style` merge in that order after component styles. Implementation gap: on the static root the component sets `tabIndex` after caller props, so a caller `tabIndex` is replaced (Current-state impact).
|
|
125
|
+
| ID | Invariant | Basis |
|
|
126
|
+
| --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
|
|
127
|
+
| FR1 | The root is a relative, non-shrinking inline-flex box of the resolved size with the shape's radius; it carries the `avatar` target, which reflects `size` and `shape`. A clipped content area fills it with the same radius and suppresses text selection. | Current source and tests |
|
|
128
|
+
| FR2 | The content area shows `src` while it has not failed, then `fallbackSrc` while it has not failed, then initials when the name yields any, then a default person icon at 60% of the box. Each image renders with empty `alt` and `object-fit: cover`. A failure is tracked per source, so a changed `src` or `fallbackSrc` is tried again. | Current source and tests |
|
|
129
|
+
| FR3 | Initials are the first letter, digit, or emoji of the first and last words of the trimmed `name`, uppercased; leading punctuation in a word is skipped, words with none are dropped, one qualifying word yields one initial, and grapheme clusters are never split. A whitespace-only name counts as absent. Initials and the default icon paint on the `avatar-fallback` target (reflecting `size`) with `--color-neutral`, secondary text, body family, medium weight, and initials at 40% of the box. In forced colors, a lone Avatar's initials and default icon take the surrounding color (`currentColor`): the forced foreground by default, and the system color of a control that paints one around it (GrayText, HighlightText); inside an AvatarGroup they keep the forced foreground on the group's ring. | Current source and tests |
|
|
130
|
+
| FR4 | A truthy `status` renders in an absolutely positioned slot outside the clipped content area. On a circle it centers on the circle's edge at the bottom inline-end 45° point; on other shapes it sits at the bottom inline-end corner, offset outward by a quarter of its size. Placement mirrors in right-to-left documents. | Current source and tests |
|
|
131
|
+
| FR5 | The resolved name is `alt`, else `name` (blank strings count as absent), composed with the status label as the translated "{name}, {status}" when both exist; a status label alone also names the avatar. The status label comes from a string `label` on the passed element, read on every render, and from a label an AvatarStatusDot reports at any wrapper depth, which wins and updates the root before paint without a second render. | Current source and tests |
|
|
132
|
+
| FR6 | `href` renders the shared link component (or `as`) with `target` and `rel`; otherwise `onClick` renders a `button type="button"`; otherwise the root is a `div`. Link and button roots carry the `data-avatar-item` marker and the shared focus-visible outline; `onClick` attaches to the link or button. In development, an interactive avatar whose only name is a status label, or that has no name and no caller `aria-label`/`aria-labelledby`, logs a warning. | Current source and tests |
|
|
133
|
+
| FR7 | The tooltip shows the trimmed custom string, else the meaningful `name`, placed above, on hover and keyboard focus; `tooltip={false}` or a blank result shows none. A static avatar with a tooltip and outside a group gets `tabIndex={0}` so keyboard users can reveal it. A custom string is added to `aria-describedby` after any caller value; the default name tooltip is not, because it repeats the name. Implementation gap: a grouped link or button avatar that is not the group's tab stop stops opening its tooltip on focus after a re-render that re-attaches its root element: a new `status` element (an inline `status` prop creates one on every parent render), a changed `name`, `alt`, locale, caller ARIA, or caller `ref`, or a tooltip that turns on after mount (Current-state impact). | Current source and tests |
|
|
134
|
+
| FR8 | Inside an AvatarGroup in the same layer (`spec:AST-038` FR7, FR8), the group's size and shape win over the avatar's own props; the root gains a 2px surface-colored ring outside its box and the group's negative inline-start overlap; a static avatar adds no tooltip tab stop, and link and button roots keep the `data-avatar-item` marker so they join the group's roving set. An avatar in a hover card, popover, or other layer opened from a group keeps its own size and shape, gets no ring or overlap, and keeps its tooltip tab stop; a link or button avatar there still carries the marker, so the group's roving focus, which selects marked elements in its DOM subtree, still includes it. | Current source and tests |
|
|
135
|
+
| FR9 | `ref` reaches the root of every variant. Supported DOM, ARIA, data, and event props reach the root after the derived ARIA, so a caller `aria-label`, `role`, or `aria-hidden` wins (`architecture:public-component-api` INV5); `data-testid` reaches the root; `xstyle`, `className`, and `style` merge in that order after component styles. Implementation gap: on the static root the component sets `tabIndex` after caller props, so a caller `tabIndex` is replaced (Current-state impact). | Current source and tests |
|
|
136
136
|
|
|
137
137
|
### Allowed variation
|
|
138
138
|
|
|
@@ -227,17 +227,17 @@ no root part, so no anatomy-theming block is declared.
|
|
|
227
227
|
|
|
228
228
|
## Verification map
|
|
229
229
|
|
|
230
|
-
| Contract | Verification | Representative states
|
|
231
|
-
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
232
|
-
| FR1–FR3 | `Avatar.test.tsx` fallback, initials, retry, and target tests
|
|
233
|
-
| FR4 | `Avatar.test.tsx` shape and status tests; `Avatar.stories.tsx` status fixtures | Every shape with a status; RTL
|
|
234
|
-
| FR5, AR1, AR2, PR1 | `Avatar.test.tsx` status-name and wrapper suites | Direct, wrapped, changing, removed labels
|
|
235
|
-
| FR6, AR3 | `Avatar.test.tsx` interactivity suite | Link, button, static, dev warnings
|
|
236
|
-
| FR7, AR4, AR5 | `Avatar.test.tsx` name-tooltip suite | Default, custom, disabled, blank
|
|
237
|
-
| FR8 | `Avatar.test.tsx` group shape tests; `AvatarGroup.test.tsx` size-cascade, overlap, and roving suites; `layerScopedContext.test.tsx` AvatarGroup layer tests | Inside a group; in a layer opened from a group; outside a group
|
|
238
|
-
| FR9, AR6 | `Avatar.test.tsx` consumer-ARIA override suite | Static and interactive roots
|
|
239
|
-
| AR1–AR3, AR5 | Accessibility-tree evidence (`spec:AST-009` FR3) | Named, decorative, status-composed, interactive
|
|
240
|
-
| AR7 | `Avatar.stories.tsx` interactive and size fixtures in a browser | Interactive avatars at every size
|
|
230
|
+
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
231
|
+
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------- |
|
|
232
|
+
| FR1–FR3 | `Avatar.test.tsx` fallback, initials, retry, and target tests; `AvatarForcedColors.a11y.chromium.spec.ts` in real Chromium with forced colors emulated | Photo, failure, initials, punctuation, emoji, blank name; `lg` box; forced colors alone, inside GrayText and HighlightText, and grouped | A wrong initials-or-icon fallback, split grapheme, lost retry, missing target, wrong `lg` box size, or forced-colors initials that miss the surrounding system color (lone) or leave the forced foreground (grouped) fails. Gap: no test sets `src` and `fallbackSrc` together, so the `src`-first order is unchecked, and sizes other than `lg` and numeric sizes are visible only in `Avatar.stories.tsx`. | `audit:Avatar/behavior` |
|
|
233
|
+
| FR4 | `Avatar.test.tsx` shape and status tests; `Avatar.stories.tsx` status fixtures | Every shape with a status; RTL | A missing status slot fails. Gap: the tests assert presence only, so the slot's position, mirroring, and offset are visible only in the rendered fixtures. | `audit:Avatar/layout` |
|
|
234
|
+
| FR5, AR1, AR2, PR1 | `Avatar.test.tsx` status-name and wrapper suites | Direct, wrapped, changing, removed labels | A lost composed name, extra render, or stale label fails. | `audit:Avatar/a11y` |
|
|
235
|
+
| FR6, AR3 | `Avatar.test.tsx` interactivity suite | Link, button, static, dev warnings | A wrong root, a missing marker, or a missing warning fails. Gap: no test checks the focus-visible outline. | `audit:Avatar/behavior` |
|
|
236
|
+
| FR7, AR4, AR5 | `Avatar.test.tsx` name-tooltip suite | Default, custom, disabled, blank | A missing tab stop, a duplicated description, or a lost ref fails. Gap: no test covers a grouped avatar's tooltip after a re-render that re-attaches its root element: a new `status` element (an inline `status` prop creates one on every parent render), a changed `name`, `alt`, locale, caller ARIA, or caller `ref`, or a tooltip that turns on after mount. | `audit:Avatar/a11y` |
|
|
237
|
+
| FR8 | `Avatar.test.tsx` group shape tests; `AvatarGroup.test.tsx` size-cascade, overlap, and roving suites; `layerScopedContext.test.tsx` AvatarGroup layer tests | Inside a group; in a layer opened from a group; outside a group | An avatar size or shape prop winning inside a group, a lost overlap, an interactive avatar missing from the roving set, or a static avatar in a layer losing its tooltip tab stop fails. Gap: no test asserts the ring, or size and shape inside a layer. | `audit:Avatar/behavior` |
|
|
238
|
+
| FR9, AR6 | `Avatar.test.tsx` consumer-ARIA override suite | Static and interactive roots | A derived value replacing a caller `aria-label`, `role`, or `aria-hidden` fails. Gap: no test covers a caller `tabIndex`. | `audit:Avatar/a11y` |
|
|
239
|
+
| AR1–AR3, AR5 | Accessibility-tree evidence (`spec:AST-009` FR3) | Named, decorative, status-composed, interactive | Gap: no accessibility-tree check proves the computed roles, names, or description; the unit tests query the DOM. | `audit:Avatar/a11y` |
|
|
240
|
+
| AR7 | `Avatar.stories.tsx` interactive and size fixtures in a browser | Interactive avatars at every size | Gap: no automated target-size check; the undersized targets are the recorded gap. | `audit:Avatar/a11y` |
|
|
241
241
|
|
|
242
242
|
## Decision log
|
|
243
243
|
|
package/src/Avatar/Avatar.tsx
CHANGED
|
@@ -193,6 +193,19 @@ const styles = stylex.create({
|
|
|
193
193
|
fontWeight: fontWeightVars['--font-weight-medium'],
|
|
194
194
|
textTransform: 'uppercase',
|
|
195
195
|
},
|
|
196
|
+
// After `fallback` on a lone Avatar: in forced colors its initials and
|
|
197
|
+
// default icon take the color around them, which the browser forces to
|
|
198
|
+
// CanvasText, so a control that paints itself disabled (GrayText) or
|
|
199
|
+
// selected (HighlightText) carries them with it; an
|
|
200
|
+
// authored color would be forced to CanvasText whatever the control shows.
|
|
201
|
+
// A grouped face keeps it: its ring's opaque fill is forced to Canvas, so
|
|
202
|
+
// only CanvasText is sure to read on it.
|
|
203
|
+
loneFallback: {
|
|
204
|
+
color: {
|
|
205
|
+
default: colorVars['--color-text-secondary'],
|
|
206
|
+
'@media (forced-colors: active)': 'currentColor',
|
|
207
|
+
},
|
|
208
|
+
},
|
|
196
209
|
status: {
|
|
197
210
|
position: 'absolute',
|
|
198
211
|
},
|
|
@@ -784,6 +797,7 @@ export function Avatar({
|
|
|
784
797
|
themeProps('avatar-fallback', {size: resolvedSize}),
|
|
785
798
|
stylex.props(
|
|
786
799
|
styles.fallback,
|
|
800
|
+
avatarGroup == null && styles.loneFallback,
|
|
787
801
|
dynamicStyles.fontSize(numericSize),
|
|
788
802
|
),
|
|
789
803
|
)}>
|
|
@@ -794,7 +808,10 @@ export function Avatar({
|
|
|
794
808
|
<div
|
|
795
809
|
{...mergeProps(
|
|
796
810
|
themeProps('avatar-fallback', {size: resolvedSize}),
|
|
797
|
-
stylex.props(
|
|
811
|
+
stylex.props(
|
|
812
|
+
styles.fallback,
|
|
813
|
+
avatarGroup == null && styles.loneFallback,
|
|
814
|
+
),
|
|
798
815
|
)}>
|
|
799
816
|
<DefaultIcon size={numericSize} />
|
|
800
817
|
</div>
|