@astryxdesign/core 0.7.7-canary.bf14580 → 0.7.7-canary.c19ca12
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 +4 -1
- package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
- package/dist/AlertDialog/AlertDialog.js +36 -6
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +76 -6
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +23 -4
- package/dist/BottomSheet/bottomSheetStack.d.ts.map +1 -1
- package/dist/BottomSheet/bottomSheetStack.js +5 -4
- package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
- package/dist/BottomSheet/useSheetGestures.js +3 -1
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +47 -3
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +13 -2
- package/dist/ComplexSelector/ComplexSelector.d.ts +4 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +14 -4
- package/dist/ContextMenu/ContextMenu.js +2 -2
- package/dist/DateInput/MonthScroller.d.ts.map +1 -1
- package/dist/DateInput/MonthScroller.js +13 -27
- package/dist/DateInput/Wheel.d.ts.map +1 -1
- package/dist/DateInput/Wheel.js +22 -41
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +7 -31
- package/dist/Field/Field.js +2 -2
- package/dist/HoverCard/HoverCard.d.ts +4 -3
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +27 -2
- package/dist/HoverCard/useHoverCard.d.ts +5 -4
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +17 -31
- package/dist/Icon/Icon.d.ts +5 -1
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +5 -2
- package/dist/Layer/layerAnimations.stylex.d.ts +7 -8
- package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
- package/dist/Layer/layerAnimations.stylex.js +25 -20
- package/dist/Layer/usePressPin.d.ts +17 -5
- package/dist/Layer/usePressPin.d.ts.map +1 -1
- package/dist/Layer/usePressPin.js +62 -12
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +18 -0
- package/dist/PowerSearch/PowerSearch.d.ts +36 -3
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +522 -269
- package/dist/PowerSearch/PowerSearchBottomSheet.d.ts +100 -0
- package/dist/PowerSearch/PowerSearchBottomSheet.d.ts.map +1 -0
- package/dist/PowerSearch/PowerSearchBottomSheet.js +1913 -0
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts +32 -1
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.js +17 -6
- package/dist/PowerSearch/PowerSearchValueEditor.d.ts +38 -3
- package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchValueEditor.js +170 -61
- package/dist/PowerSearch/formatFilterValue.d.ts +7 -0
- package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
- package/dist/PowerSearch/formatFilterValue.js +11 -1
- package/dist/PowerSearch/formatTokenValue.d.ts +28 -0
- package/dist/PowerSearch/formatTokenValue.d.ts.map +1 -0
- package/dist/PowerSearch/formatTokenValue.js +160 -0
- package/dist/PowerSearch/powerSearchSheetUtils.d.ts +65 -0
- package/dist/PowerSearch/powerSearchSheetUtils.d.ts.map +1 -0
- package/dist/PowerSearch/powerSearchSheetUtils.js +168 -0
- package/dist/RadioList/RadioList.d.ts.map +1 -1
- package/dist/RadioList/RadioList.js +3 -2
- package/dist/RadioList/RadioListItem.d.ts +1 -1
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +5 -3
- package/dist/SegmentedControl/useSegmentedSelectionMotion.d.ts.map +1 -1
- package/dist/SegmentedControl/useSegmentedSelectionMotion.js +3 -3
- package/dist/Slider/sliderTouchController.js +2 -2
- package/dist/Spinner/Spinner.d.ts +1 -1
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +60 -58
- package/dist/Switch/useSwitchTouch.js +4 -4
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +29 -8
- package/dist/TextInput/TextInput.d.ts +2 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +10 -7
- package/dist/Toast/Toast.d.ts +11 -1
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +25 -15
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +94 -34
- package/dist/Toast/types.d.ts +9 -3
- package/dist/Toast/types.d.ts.map +1 -1
- package/dist/Token/Token.d.ts +2 -2
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +12 -4
- package/dist/Token/TokenNamingContext.d.ts +14 -0
- package/dist/Token/TokenNamingContext.d.ts.map +1 -0
- package/dist/Token/TokenNamingContext.js +23 -0
- package/dist/Tooltip/useTooltip.d.ts +19 -1
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +34 -53
- package/dist/Typeahead/TypeaheadItem.d.ts +2 -1
- package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
- package/dist/animator/createAnimator.d.ts +98 -0
- package/dist/animator/createAnimator.d.ts.map +1 -0
- package/dist/animator/createAnimator.js +259 -0
- package/dist/astryx.css +22 -6
- package/dist/gestures/GestureHost.d.ts +27 -1
- package/dist/gestures/GestureHost.d.ts.map +1 -1
- package/dist/gestures/GestureHost.js +90 -8
- package/dist/gestures/PressTracker.d.ts.map +1 -1
- package/dist/gestures/PressTracker.js +4 -3
- package/dist/hooks/actionGroupTracker.d.ts +4 -1
- package/dist/hooks/actionGroupTracker.d.ts.map +1 -1
- package/dist/hooks/actionGroupTracker.js +13 -3
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/pressGroupContext.d.ts +6 -0
- package/dist/hooks/pressGroupContext.d.ts.map +1 -0
- package/dist/hooks/pressGroupContext.js +20 -0
- package/dist/hooks/useActionGroupTracking.d.ts +53 -0
- package/dist/hooks/useActionGroupTracking.d.ts.map +1 -0
- package/dist/hooks/useActionGroupTracking.js +174 -0
- package/dist/hooks/useAnimator.d.ts +41 -0
- package/dist/hooks/useAnimator.d.ts.map +1 -0
- package/dist/hooks/useAnimator.js +70 -0
- package/dist/hooks/useAttachment.d.ts +1 -1
- package/dist/hooks/useAttachment.js +1 -1
- package/dist/hooks/useInputStatusIcon.d.ts +1 -1
- package/dist/hooks/useInputStatusIcon.d.ts.map +1 -1
- package/dist/hooks/useInputStatusIcon.js +2 -2
- package/dist/hooks/useLongPress.d.ts +6 -2
- package/dist/hooks/useLongPress.d.ts.map +1 -1
- package/dist/hooks/useLongPress.js +95 -15
- package/dist/hooks/useMenuPress.d.ts.map +1 -1
- package/dist/hooks/useMenuPress.js +4 -2
- package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.d.ts +8 -0
- package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.d.ts.map +1 -0
- package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.js +42 -0
- package/dist/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.d.ts.map +1 -1
- package/dist/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.js +6 -0
- package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.d.ts +8 -0
- package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.d.ts.map +1 -0
- package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.js +14 -0
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +30 -0
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +30 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/internal/indicatorPress.stylex.d.ts +20 -0
- package/dist/internal/indicatorPress.stylex.d.ts.map +1 -0
- package/dist/internal/indicatorPress.stylex.js +26 -0
- package/dist/motion/animator.d.ts +14 -14
- package/dist/motion/animator.d.ts.map +1 -1
- package/dist/motion/animator.js +41 -18
- package/dist/motion/reducedMotion.d.ts +24 -0
- package/dist/motion/reducedMotion.d.ts.map +1 -1
- package/dist/motion/reducedMotion.js +78 -1
- package/dist/motion/uikit/alert.d.ts +41 -0
- package/dist/motion/uikit/alert.d.ts.map +1 -0
- package/dist/motion/uikit/alert.js +43 -0
- package/dist/privateAttributes/pressGroupItem.stylex.d.ts +15 -0
- package/dist/privateAttributes/pressGroupItem.stylex.d.ts.map +1 -0
- package/dist/privateAttributes/pressGroupItem.stylex.js +23 -0
- package/dist/utils/clickGuard.d.ts +8 -1
- package/dist/utils/clickGuard.d.ts.map +1 -1
- package/dist/utils/clickGuard.js +24 -1
- package/dist/utils/dateParser.d.ts.map +1 -1
- package/dist/utils/dateParser.js +12 -0
- package/dist/utils/focusReturn.d.ts +15 -0
- package/dist/utils/focusReturn.d.ts.map +1 -1
- package/dist/utils/focusReturn.js +28 -0
- package/dist/utils/interactionOverlay.stylex.d.ts +3 -2
- package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
- package/dist/utils/interactionOverlay.stylex.js +3 -2
- package/dist/utils/pressFeedback.d.ts.map +1 -1
- package/dist/utils/pressFeedback.js +19 -6
- package/dist/utils/triggerFocus.d.ts +36 -0
- package/dist/utils/triggerFocus.d.ts.map +1 -0
- package/dist/utils/triggerFocus.js +65 -0
- package/locales/en.json +120 -0
- package/locales/pseudo.json +90 -0
- package/package.json +9 -4
- package/src/AlertDialog/AlertDialog.doc.mjs +2 -2
- package/src/AlertDialog/AlertDialog.tsx +37 -5
- package/src/BottomSheet/BottomSheet.tsx +85 -5
- package/src/BottomSheet/BottomSheetPanel.tsx +40 -5
- package/src/BottomSheet/bottomSheetStack.ts +8 -4
- package/src/BottomSheet/useSheetGestures.ts +3 -1
- package/src/Button/Button.tsx +63 -5
- package/src/CheckboxInput/CheckboxInput.doc.mjs +18 -0
- package/src/CheckboxInput/CheckboxInput.tsx +36 -9
- package/src/ComplexSelector/ComplexSelector.tsx +20 -5
- package/src/ContextMenu/ContextMenu.tsx +2 -2
- package/src/DateInput/MonthScroller.tsx +18 -22
- package/src/DateInput/Wheel.tsx +30 -32
- package/src/Dialog/Dialog.tsx +10 -31
- package/src/Field/Field.tsx +2 -2
- package/src/HoverCard/HoverCard.doc.mjs +4 -2
- package/src/HoverCard/HoverCard.tsx +35 -4
- package/src/HoverCard/useHoverCard.doc.mjs +178 -36
- package/src/HoverCard/useHoverCard.tsx +46 -52
- package/src/Icon/Icon.doc.mjs +49 -8
- package/src/Icon/Icon.tsx +15 -7
- package/src/Layer/layerAnimations.stylex.ts +24 -16
- package/src/Layer/usePressPin.ts +81 -15
- package/src/Lightbox/Lightbox.tsx +18 -0
- package/src/PowerSearch/PowerSearch.doc.mjs +54 -5
- package/src/PowerSearch/PowerSearch.tsx +734 -288
- package/src/PowerSearch/PowerSearchBottomSheet.tsx +2515 -0
- package/src/PowerSearch/PowerSearchEditPopover.tsx +28 -6
- package/src/PowerSearch/PowerSearchValueEditor.tsx +203 -38
- package/src/PowerSearch/formatFilterValue.ts +18 -1
- package/src/PowerSearch/formatTokenValue.ts +215 -0
- package/src/PowerSearch/powerSearchSheetUtils.ts +224 -0
- package/src/RadioList/RadioList.tsx +3 -2
- package/src/RadioList/RadioListItem.tsx +5 -3
- package/src/SegmentedControl/useSegmentedSelectionMotion.ts +6 -3
- package/src/Slider/sliderTouchController.ts +2 -2
- package/src/Spinner/Spinner.tsx +77 -63
- package/src/Switch/useSwitchTouch.ts +4 -4
- package/src/Table/BaseTable.tsx +46 -12
- package/src/TextInput/TextInput.tsx +11 -10
- package/src/Toast/Toast.doc.mjs +4 -3
- package/src/Toast/Toast.tsx +52 -32
- package/src/Toast/ToastViewport.tsx +121 -35
- package/src/Toast/types.ts +9 -3
- package/src/Token/Token.tsx +13 -4
- package/src/Token/TokenNamingContext.ts +28 -0
- package/src/Tooltip/useTooltip.doc.mjs +24 -0
- package/src/Tooltip/useTooltip.tsx +61 -56
- package/src/Typeahead/TypeaheadItem.doc.mjs +6 -3
- package/src/Typeahead/TypeaheadItem.tsx +2 -1
- package/src/animator/createAnimator.doc.mjs +153 -0
- package/src/animator/createAnimator.ts +324 -0
- package/src/gestures/GestureHost.ts +105 -10
- package/src/gestures/PressTracker.ts +4 -3
- package/src/gestures/README.md +7 -1
- package/src/hooks/actionGroupTracker.ts +20 -5
- package/src/hooks/index.ts +2 -0
- package/src/hooks/pressGroupContext.ts +21 -0
- package/src/hooks/useActionGroupTracking.ts +224 -0
- package/src/hooks/useAnimator.doc.mjs +109 -0
- package/src/hooks/useAnimator.ts +67 -0
- package/src/hooks/useAttachment.ts +1 -1
- package/src/hooks/useInputStatusIcon.tsx +3 -2
- package/src/hooks/useLongPress.doc.mjs +2 -2
- package/src/hooks/useLongPress.ts +136 -15
- package/src/hooks/useMenuPress.ts +8 -2
- package/src/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.ts +43 -0
- package/src/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.ts +6 -0
- package/src/i18n/generated-english/PowerSearch/formatTokenValue.generated.ts +15 -0
- package/src/i18n/generated-locales/en.generated.ts +41 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +42 -0
- package/src/index.ts +13 -0
- package/src/internal/indicatorPress.stylex.ts +24 -0
- package/src/motion/README.md +8 -5
- package/src/motion/animator.ts +61 -29
- package/src/motion/reducedMotion.ts +79 -1
- package/src/motion/uikit/alert.ts +43 -0
- package/src/privateAttributes/pressGroupItem.stylex.ts +23 -0
- package/src/utils/clickGuard.ts +37 -1
- package/src/utils/dateParser.ts +16 -0
- package/src/utils/focusReturn.ts +30 -0
- package/src/utils/interactionOverlay.stylex.ts +3 -2
- package/src/utils/pressFeedback.ts +19 -6
- package/src/utils/triggerFocus.ts +80 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"focusReturn.d.ts","sourceRoot":"","sources":["../../src/utils/focusReturn.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,QAAmB,GAAG,OAAO,CAKjE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,QAAQ,GAAG,OAAO,CAM5E;AAED,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;CACjC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GACxC,WAAW,GAAG,IAAI,CAMpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,WAAW,GAAG,IAAI,EACxB,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EACtC,MAAM,GAAE,OAAO,GAAG,IAAW,GAC5B,OAAO,CAUT;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,YAAY,EACtB,QAAQ,GAAE,mBAAqD,GAC9D,IAAI,CA2BN"}
|
|
1
|
+
{"version":3,"file":"focusReturn.d.ts","sourceRoot":"","sources":["../../src/utils/focusReturn.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,QAAmB,GAAG,OAAO,CAKjE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,QAAQ,GAAG,OAAO,CAM5E;AAED,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;CACjC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GACxC,WAAW,GAAG,IAAI,CAMpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,WAAW,GAAG,IAAI,EACxB,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EACtC,MAAM,GAAE,OAAO,GAAG,IAAW,GAC5B,OAAO,CAUT;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,YAAY,EACtB,QAAQ,GAAE,mBAAqD,GAC9D,IAAI,CA2BN;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,OAAO,GACf,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAYlC"}
|
|
@@ -126,4 +126,32 @@ export function focusForLastInput(element, options, modality = getInteractionMod
|
|
|
126
126
|
...options,
|
|
127
127
|
focusVisible: false
|
|
128
128
|
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Prepares the focus return for an open surface that may be removed while
|
|
133
|
+
* open (rendered only while open, or removed with its view). Removing a
|
|
134
|
+
* `<dialog>` runs no close and no browser focus return. Call this while the
|
|
135
|
+
* surface is mounted: it reads the frame that hosts the surface now, because a
|
|
136
|
+
* removed frame's document has no window. Call the returned function from the
|
|
137
|
+
* effect cleanup with the opener.
|
|
138
|
+
*
|
|
139
|
+
* Once the commit has finished, focus moves to the opener only when the
|
|
140
|
+
* surface really left the document (StrictMode's simulated unmount keeps it),
|
|
141
|
+
* the opener is still on the page, and the removal lost focus, both in the
|
|
142
|
+
* surface's document and in the document that hosts its frame. A control the
|
|
143
|
+
* user pressed outside the surface, or outside its frame, keeps its focus.
|
|
144
|
+
*/
|
|
145
|
+
export function prepareFocusReturnOnRemoval(surface) {
|
|
146
|
+
const host = surface.ownerDocument.defaultView?.frameElement ?? null;
|
|
147
|
+
return opener => {
|
|
148
|
+
queueMicrotask(() => {
|
|
149
|
+
if (surface.isConnected || opener == null || !opener.isConnected) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (isFocusLost(surface) && (host == null || isFocusLost(host))) {
|
|
153
|
+
focusForLastInput(opener);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
};
|
|
129
157
|
}
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* SYNC: When modified, update pressFeedback.ts, pressGesture.ts (the fade
|
|
10
10
|
* clock), hooks/usePressFeedback.doc.mjs, the components that paint the touch
|
|
11
11
|
* press off an ancestor scope or a pseudo-element (Switch, Tab,
|
|
12
|
-
* CheckboxInput, RadioListItem, ClickableCard, SelectableCard, Thumbnail)
|
|
13
|
-
* and
|
|
12
|
+
* CheckboxInput, RadioListItem, ClickableCard, SelectableCard, Thumbnail),
|
|
13
|
+
* Button (a tracked action sizes its `:active` image to zero) and
|
|
14
|
+
* scripts/build-css.test.mjs.
|
|
14
15
|
*/
|
|
15
16
|
import * as stylex from '@stylexjs/stylex';
|
|
16
17
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactionOverlay.stylex.d.ts","sourceRoot":"","sources":["../../src/utils/interactionOverlay.stylex.ts"],"names":[],"mappings":"AAMA
|
|
1
|
+
{"version":3,"file":"interactionOverlay.stylex.d.ts","sourceRoot":"","sources":["../../src/utils/interactionOverlay.stylex.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;GAcG;AAmCH,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAG3C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,SAAS;;WAEpB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;IACtB,iEAAiE;;CAEjE,CAAC;AA8HH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8HnC,CAAC"}
|
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
* SYNC: When modified, update pressFeedback.ts, pressGesture.ts (the fade
|
|
16
16
|
* clock), hooks/usePressFeedback.doc.mjs, the components that paint the touch
|
|
17
17
|
* press off an ancestor scope or a pseudo-element (Switch, Tab,
|
|
18
|
-
* CheckboxInput, RadioListItem, ClickableCard, SelectableCard, Thumbnail)
|
|
19
|
-
* and
|
|
18
|
+
* CheckboxInput, RadioListItem, ClickableCard, SelectableCard, Thumbnail),
|
|
19
|
+
* Button (a tracked action sizes its `:active` image to zero) and
|
|
20
|
+
* scripts/build-css.test.mjs.
|
|
20
21
|
*/
|
|
21
22
|
|
|
22
23
|
// Every surface that paints a press uses one of these styles, so a change to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pressFeedback.d.ts","sourceRoot":"","sources":["../../src/utils/pressFeedback.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pressFeedback.d.ts","sourceRoot":"","sources":["../../src/utils/pressFeedback.ts"],"names":[],"mappings":"AAkDA;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,0BAA0B,CAAC;AAE3D;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AAErD,qDAAqD;AACrD,eAAO,MAAM,cAAc,EAAE;IAAC,QAAQ,CAAC,CAAC,mBAAmB,CAAC,EAAE,EAAE,CAAA;CAE/D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAwoB5C;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,IAAI,CA0BjD"}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @file pressFeedback.ts
|
|
5
|
-
* @input The press state machine (pressGesture.ts), the menu-press
|
|
6
|
-
*
|
|
5
|
+
* @input The press state machine (pressGesture.ts), the menu-press and
|
|
6
|
+
* press-group markers and the document's pointer, keyboard, scroll and
|
|
7
7
|
* visibility events
|
|
8
8
|
* @output PRESSABLE_ATTRIBUTE, PRESSED_ATTRIBUTE, pressableProps and
|
|
9
9
|
* installPressFeedback
|
|
@@ -38,6 +38,7 @@ import { isCoarsePointer, watchCoarsePointer } from "./coarsePointer.js";
|
|
|
38
38
|
import { subscribeInput } from "./inputStream.js";
|
|
39
39
|
import { TOUCH_QUERY } from "./touchPresentation.js";
|
|
40
40
|
import { holdsPressThroughDrag } from "../privateAttributes/pressHoldsDrag.stylex.js";
|
|
41
|
+
import { isTrackedByGroup } from "../privateAttributes/pressGroupItem.stylex.js";
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
44
|
* The marker the controller finds with `closest()`. Every Astryx component
|
|
@@ -288,14 +289,19 @@ function stylesheetDroppedActive() {
|
|
|
288
289
|
|
|
289
290
|
/**
|
|
290
291
|
* The surface a mouse button's or the Space key's press paints, if any: the
|
|
291
|
-
* innermost marked surface, outside a menu. A key's
|
|
292
|
-
* focused element that is itself the surface, as
|
|
292
|
+
* innermost marked surface, outside a menu and off a tracked action. A key's
|
|
293
|
+
* press paints only a focused element that is itself the surface, as
|
|
294
|
+
* `:active` does.
|
|
293
295
|
*/
|
|
294
296
|
function buttonSurfaceAt(target, pointerId) {
|
|
295
297
|
const element = surfaceAt(target);
|
|
296
298
|
if (element == null || element.closest(MENU_PRESS_ROOT) != null) {
|
|
297
299
|
return null;
|
|
298
300
|
}
|
|
301
|
+
// A group's tracker follows pointers only, so a key's press stays here.
|
|
302
|
+
if (pointerId != null && isTrackedByGroup(element)) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
299
305
|
if (pointerId == null && element !== target) {
|
|
300
306
|
return null;
|
|
301
307
|
}
|
|
@@ -379,7 +385,9 @@ function onPointerDown(event) {
|
|
|
379
385
|
const braking = element != null && scrollerIsBraking(element);
|
|
380
386
|
lastTouchAt = Date.now();
|
|
381
387
|
lastTouchTarget = event.target instanceof Node ? event.target : null;
|
|
382
|
-
|
|
388
|
+
// A group's tracker paints a tracked action, so two writers would erase each
|
|
389
|
+
// other's paint. The touch still counts for the brake above.
|
|
390
|
+
if (element == null || braking || isTrackedByGroup(element)) {
|
|
383
391
|
return;
|
|
384
392
|
}
|
|
385
393
|
takeOver(button, element);
|
|
@@ -509,6 +517,11 @@ function activatesOnSpace(target) {
|
|
|
509
517
|
return target instanceof HTMLInputElement && SPACE_ACTIVATED_INPUT_TYPES.has(target.type);
|
|
510
518
|
}
|
|
511
519
|
|
|
520
|
+
/** A tracked action takes no `:active` paint, so a key's press paints here. */
|
|
521
|
+
function isTrackedAction(target) {
|
|
522
|
+
return target instanceof Element && isTrackedByGroup(target);
|
|
523
|
+
}
|
|
524
|
+
|
|
512
525
|
/**
|
|
513
526
|
* Space went down on a focused button that is itself a pressable surface.
|
|
514
527
|
* Heard in the BUBBLE phase, after the page's own handlers, so a press the
|
|
@@ -516,7 +529,7 @@ function activatesOnSpace(target) {
|
|
|
516
529
|
* not engage for one.
|
|
517
530
|
*/
|
|
518
531
|
function onKeyDown(event) {
|
|
519
|
-
if (event.key !== ' ' || event.repeat || event.isComposing || event.defaultPrevented || !activatesOnSpace(event.target) || !stylesheetDroppedActive()) {
|
|
532
|
+
if (event.key !== ' ' || event.repeat || event.isComposing || event.defaultPrevented || !activatesOnSpace(event.target) || !(stylesheetDroppedActive() || isTrackedAction(event.target))) {
|
|
520
533
|
return;
|
|
521
534
|
}
|
|
522
535
|
pressButton(event.target, null);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file triggerFocus.ts
|
|
3
|
+
* @input A focus event on a hover-layer trigger and its focusTrigger value
|
|
4
|
+
* @output Whether that focus counts as focus on the trigger, and a gate that
|
|
5
|
+
* remembers it for the matching blur
|
|
6
|
+
* @position Shared focus-trigger judgement for Tooltip and HoverCard
|
|
7
|
+
*/
|
|
8
|
+
/** When focus on a trigger opens its layer. */
|
|
9
|
+
export type TriggerFocusMode = 'auto' | 'always' | 'never';
|
|
10
|
+
/** Whether `element` is in the tab order or naturally focusable. */
|
|
11
|
+
export declare function isFocusableTrigger(element: HTMLElement): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Whether a focus event on a trigger (its `currentTarget`) counts as focus on
|
|
14
|
+
* the trigger.
|
|
15
|
+
*
|
|
16
|
+
* Under `auto` it is decided when focus arrives, not when listeners attach: a
|
|
17
|
+
* roving-tabindex member that was `tabindex="-1"` then can be the tab stop
|
|
18
|
+
* now. A trigger that receives focus is focusable by definition, which covers
|
|
19
|
+
* focusable elements this check does not list, such as a `<summary>` or an SVG
|
|
20
|
+
* link. Focus inside the trigger counts only while the trigger is focusable
|
|
21
|
+
* too, so a plain wrapper ignores its children's focus.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isFocusForTrigger(event: Event, mode: TriggerFocusMode): boolean;
|
|
24
|
+
/** Remembers whether a trigger's current focus counted when it arrived. */
|
|
25
|
+
export interface TriggerFocusGate {
|
|
26
|
+
/** On focusin: whether this focus opens the layer. */
|
|
27
|
+
focusIn(event: Event, mode: TriggerFocusMode): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* On focusout: whether this blur closes the layer. A focus that counted
|
|
30
|
+
* closes on blur even if the trigger has since left the tab order.
|
|
31
|
+
*/
|
|
32
|
+
focusOut(event: Event, mode: TriggerFocusMode): boolean;
|
|
33
|
+
}
|
|
34
|
+
/** A gate for one trigger; each hook keeps one for its lifetime. */
|
|
35
|
+
export declare function createTriggerFocusGate(): TriggerFocusGate;
|
|
36
|
+
//# sourceMappingURL=triggerFocus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triggerFocus.d.ts","sourceRoot":"","sources":["../../src/utils/triggerFocus.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,+CAA+C;AAC/C,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE3D,oEAAoE;AACpE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAShE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAWT;AAED,2EAA2E;AAC3E,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC;IACvD;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC;CACzD;AAED,oEAAoE;AACpE,wBAAgB,sBAAsB,IAAI,gBAAgB,CAezD"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file triggerFocus.ts
|
|
5
|
+
* @input A focus event on a hover-layer trigger and its focusTrigger value
|
|
6
|
+
* @output Whether that focus counts as focus on the trigger, and a gate that
|
|
7
|
+
* remembers it for the matching blur
|
|
8
|
+
* @position Shared focus-trigger judgement for Tooltip and HoverCard
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** When focus on a trigger opens its layer. */
|
|
12
|
+
|
|
13
|
+
/** Whether `element` is in the tab order or naturally focusable. */
|
|
14
|
+
export function isFocusableTrigger(element) {
|
|
15
|
+
if (element.hasAttribute('tabindex')) {
|
|
16
|
+
return element.tabIndex >= 0;
|
|
17
|
+
}
|
|
18
|
+
const focusableTags = ['A', 'BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'];
|
|
19
|
+
if (focusableTags.includes(element.tagName)) {
|
|
20
|
+
return !element.disabled;
|
|
21
|
+
}
|
|
22
|
+
return element.isContentEditable;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Whether a focus event on a trigger (its `currentTarget`) counts as focus on
|
|
27
|
+
* the trigger.
|
|
28
|
+
*
|
|
29
|
+
* Under `auto` it is decided when focus arrives, not when listeners attach: a
|
|
30
|
+
* roving-tabindex member that was `tabindex="-1"` then can be the tab stop
|
|
31
|
+
* now. A trigger that receives focus is focusable by definition, which covers
|
|
32
|
+
* focusable elements this check does not list, such as a `<summary>` or an SVG
|
|
33
|
+
* link. Focus inside the trigger counts only while the trigger is focusable
|
|
34
|
+
* too, so a plain wrapper ignores its children's focus.
|
|
35
|
+
*/
|
|
36
|
+
export function isFocusForTrigger(event, mode) {
|
|
37
|
+
if (mode === 'always') {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
if (mode === 'never') {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
const trigger = event.currentTarget;
|
|
44
|
+
return trigger != null && (event.target === trigger || isFocusableTrigger(trigger));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Remembers whether a trigger's current focus counted when it arrived. */
|
|
48
|
+
|
|
49
|
+
/** A gate for one trigger; each hook keeps one for its lifetime. */
|
|
50
|
+
export function createTriggerFocusGate() {
|
|
51
|
+
let isCounted = false;
|
|
52
|
+
return {
|
|
53
|
+
focusIn(event, mode) {
|
|
54
|
+
isCounted = isFocusForTrigger(event, mode);
|
|
55
|
+
return isCounted;
|
|
56
|
+
},
|
|
57
|
+
focusOut(event, mode) {
|
|
58
|
+
if (!isCounted && !isFocusForTrigger(event, mode)) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
isCounted = false;
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
package/locales/en.json
CHANGED
|
@@ -255,6 +255,126 @@
|
|
|
255
255
|
"defaultMessage": "{count, number} {count, plural, one {result} other {results}}",
|
|
256
256
|
"description": "Live result-count text next to the PowerSearch input, announced to screen readers on change. Example: `12 results`, `1 result`; keep compact."
|
|
257
257
|
},
|
|
258
|
+
"@astryx.powersearch.sheet.filtersTitle": {
|
|
259
|
+
"defaultMessage": "Filters",
|
|
260
|
+
"description": "Heading and accessible name of the PowerSearch touch sheet that lists the active filters (experimental bottom-sheet presentation). Plural noun."
|
|
261
|
+
},
|
|
262
|
+
"@astryx.powersearch.sheet.addFilter": {
|
|
263
|
+
"defaultMessage": "Add filter",
|
|
264
|
+
"description": "Button label in the PowerSearch touch flow: in the Filters sheet header it opens the field list; in the value step it confirms a new filter. Imperative verb; no leading plus sign."
|
|
265
|
+
},
|
|
266
|
+
"@astryx.powersearch.sheet.noFilters": {
|
|
267
|
+
"defaultMessage": "No filters applied",
|
|
268
|
+
"description": "Heading of the PowerSearch Filters sheet empty state when no filter is active (experimental bottom-sheet presentation). Neutral tone."
|
|
269
|
+
},
|
|
270
|
+
"@astryx.powersearch.sheet.noFiltersDescription": {
|
|
271
|
+
"defaultMessage": "Add a filter to narrow your results and find what you need faster.",
|
|
272
|
+
"description": "Guidance line under the PowerSearch Filters sheet empty state, above its Add filter action. One short sentence."
|
|
273
|
+
},
|
|
274
|
+
"@astryx.powersearch.sheet.clearAll": {
|
|
275
|
+
"defaultMessage": "Clear all",
|
|
276
|
+
"description": "Button label in the PowerSearch Filters sheet footer that asks to remove every editable filter. Imperative verb + determiner."
|
|
277
|
+
},
|
|
278
|
+
"@astryx.powersearch.sheet.clearAllTitle": {
|
|
279
|
+
"defaultMessage": "Clear all filters?",
|
|
280
|
+
"description": "Title and accessible name of the confirmation dialog that Clear all opens in the PowerSearch touch flow. A short question."
|
|
281
|
+
},
|
|
282
|
+
"@astryx.powersearch.sheet.clearAllDescription": {
|
|
283
|
+
"defaultMessage": "This removes all editable filters from this search.",
|
|
284
|
+
"description": "Body text of the PowerSearch Clear all confirmation dialog. Read-only filters stay, so it names editable filters."
|
|
285
|
+
},
|
|
286
|
+
"@astryx.powersearch.sheet.clearAllConfirm": {
|
|
287
|
+
"defaultMessage": "Clear filters",
|
|
288
|
+
"description": "Destructive action of the PowerSearch Clear all confirmation dialog: removes the editable filters. Imperative verb + plural noun."
|
|
289
|
+
},
|
|
290
|
+
"@astryx.powersearch.sheet.clearAllCancel": {
|
|
291
|
+
"defaultMessage": "Keep filters",
|
|
292
|
+
"description": "Safe action of the PowerSearch Clear all confirmation dialog: closes it and changes nothing. Imperative verb + plural noun."
|
|
293
|
+
},
|
|
294
|
+
"@astryx.powersearch.sheet.done": {
|
|
295
|
+
"defaultMessage": "Done",
|
|
296
|
+
"description": "Primary button label in the PowerSearch Filters sheet footer that closes the sheet. Short; marks the end of the filtering task."
|
|
297
|
+
},
|
|
298
|
+
"@astryx.powersearch.sheet.search": {
|
|
299
|
+
"defaultMessage": "Search",
|
|
300
|
+
"description": "Screen-reader-only label of the content-search box at the top of the PowerSearch Add filter sheet; its suggestions list inline below it. Noun or verb as reads best."
|
|
301
|
+
},
|
|
302
|
+
"@astryx.powersearch.sheet.searchResults": {
|
|
303
|
+
"defaultMessage": "Search results",
|
|
304
|
+
"description": "Screen-reader-only name of the inline suggestion list under the PowerSearch Add filter sheet's content search. Plural noun."
|
|
305
|
+
},
|
|
306
|
+
"@astryx.powersearch.sheet.searchFields": {
|
|
307
|
+
"defaultMessage": "Search filters",
|
|
308
|
+
"description": "Screen-reader-only label of the field-list filter box in the PowerSearch Add filter sheet, shown once the config has eight or more fields. Imperative verb + plural noun."
|
|
309
|
+
},
|
|
310
|
+
"@astryx.powersearch.sheet.searchFieldsPlaceholder": {
|
|
311
|
+
"defaultMessage": "Search filters…",
|
|
312
|
+
"description": "Placeholder inside the field-list filter box in the PowerSearch Add filter sheet. Imperative verb; trailing `…` is one character."
|
|
313
|
+
},
|
|
314
|
+
"@astryx.powersearch.sheet.ungroupedFields": {
|
|
315
|
+
"defaultMessage": "General",
|
|
316
|
+
"description": "Heading of the PowerSearch Add filter sheet's list of fields that belong to no group, shown before the named groups. A short noun."
|
|
317
|
+
},
|
|
318
|
+
"@astryx.powersearch.sheet.noMatchingFields": {
|
|
319
|
+
"defaultMessage": "No filters match your search",
|
|
320
|
+
"description": "Empty-state text in the PowerSearch Add filter sheet when the field-list filter matches no field. Neutral tone."
|
|
321
|
+
},
|
|
322
|
+
"@astryx.powersearch.sheet.tryDifferentSearch": {
|
|
323
|
+
"defaultMessage": "Try a different search.",
|
|
324
|
+
"description": "Guidance line under the PowerSearch Add filter sheet's empty search result (\"No results found\", \"No filters match your search\"). One short sentence."
|
|
325
|
+
},
|
|
326
|
+
"@astryx.powersearch.sheet.noResults": {
|
|
327
|
+
"defaultMessage": "No results found",
|
|
328
|
+
"description": "Empty-state text in the PowerSearch Add filter sheet when the content search has no suggestion for the typed query. Neutral tone (not error-y)."
|
|
329
|
+
},
|
|
330
|
+
"@astryx.powersearch.sheet.filterUnavailable": {
|
|
331
|
+
"defaultMessage": "This filter is no longer available",
|
|
332
|
+
"description": "Message in the PowerSearch value step when a config update removed the field or operator being edited; Cancel remains as the way out, and the Filters row keeps its remove action."
|
|
333
|
+
},
|
|
334
|
+
"@astryx.powersearch.sheet.removeFilter": {
|
|
335
|
+
"defaultMessage": "Remove {field} filter",
|
|
336
|
+
"description": "Accessible name and tooltip of the trailing remove button on a PowerSearch Filters sheet row; field is the filter's field label (for example \"Remove Status filter\")."
|
|
337
|
+
},
|
|
338
|
+
"@astryx.powersearch.sheet.relativeDaysAgo": {
|
|
339
|
+
"defaultMessage": "{count, number} {count, plural, one {day} other {days}} ago",
|
|
340
|
+
"description": "A relative-date choice row in the PowerSearch touch sheet, in the past (for example \"3 days ago\"). The popover editor lists the same choices."
|
|
341
|
+
},
|
|
342
|
+
"@astryx.powersearch.sheet.relativeDaysFromNow": {
|
|
343
|
+
"defaultMessage": "{count, number} {count, plural, one {day} other {days}} from now",
|
|
344
|
+
"description": "A relative-date choice row in the PowerSearch touch sheet, in the future (for example \"3 days from now\"). The popover editor lists the same choices."
|
|
345
|
+
},
|
|
346
|
+
"@astryx.powersearch.sheet.relativeWeeksAgo": {
|
|
347
|
+
"defaultMessage": "{count, number} {count, plural, one {week} other {weeks}} ago",
|
|
348
|
+
"description": "A relative-date choice row in the PowerSearch touch sheet, in the past (for example \"3 weeks ago\"). The popover editor lists the same choices."
|
|
349
|
+
},
|
|
350
|
+
"@astryx.powersearch.sheet.relativeWeeksFromNow": {
|
|
351
|
+
"defaultMessage": "{count, number} {count, plural, one {week} other {weeks}} from now",
|
|
352
|
+
"description": "A relative-date choice row in the PowerSearch touch sheet, in the future (for example \"3 weeks from now\"). The popover editor lists the same choices."
|
|
353
|
+
},
|
|
354
|
+
"@astryx.powersearch.sheet.relativeMonthsAgo": {
|
|
355
|
+
"defaultMessage": "{count, number} {count, plural, one {month} other {months}} ago",
|
|
356
|
+
"description": "A relative-date choice row in the PowerSearch touch sheet, in the past (for example \"3 months ago\"). The popover editor lists the same choices."
|
|
357
|
+
},
|
|
358
|
+
"@astryx.powersearch.sheet.relativeMonthsFromNow": {
|
|
359
|
+
"defaultMessage": "{count, number} {count, plural, one {month} other {months}} from now",
|
|
360
|
+
"description": "A relative-date choice row in the PowerSearch touch sheet, in the future (for example \"3 months from now\"). The popover editor lists the same choices."
|
|
361
|
+
},
|
|
362
|
+
"@astryx.powersearch.sheet.fieldOperator": {
|
|
363
|
+
"defaultMessage": "{field} {operator}",
|
|
364
|
+
"description": "A field label joined with an operator label in the PowerSearch touch sheet: the value step's title, an operator radio's name, and the first part of a Filters row (for example \"Status is\"). Translators may reorder the two parts."
|
|
365
|
+
},
|
|
366
|
+
"@astryx.powersearch.sheet.labelValue": {
|
|
367
|
+
"defaultMessage": "{label} {value}",
|
|
368
|
+
"description": "A Filters row's \"field operator\" text joined with its value, as the removal announcement reads it (for example \"Status is Open\"). Translators may reorder the two parts."
|
|
369
|
+
},
|
|
370
|
+
"@astryx.powersearch.sheet.filtersClearedWithCount": {
|
|
371
|
+
"defaultMessage": "All filters removed. {resultCount}",
|
|
372
|
+
"description": "Polite screen-reader announcement after Clear all in the PowerSearch touch sheet when the result count changed with it; resultCount is the field's already formatted result count (for example \"240 results\"). Live-region text, never shown on screen."
|
|
373
|
+
},
|
|
374
|
+
"@astryx.powersearch.sheet.editableFiltersClearedWithCount": {
|
|
375
|
+
"defaultMessage": "Editable filters removed. {resultCount}",
|
|
376
|
+
"description": "Polite screen-reader announcement after Clear all in the PowerSearch touch sheet removes the editable filters, keeps read-only ones, and the result count changed with it; resultCount is the field's already formatted result count (for example \"240 results\"). Live-region text, never shown on screen."
|
|
377
|
+
},
|
|
258
378
|
"@astryx.alertDialog.cancel": {
|
|
259
379
|
"defaultMessage": "Cancel",
|
|
260
380
|
"description": "Button label on the secondary/dismiss button of an AlertDialog (modal confirmation). Imperative verb; consumers usually override with task-specific text."
|
package/locales/pseudo.json
CHANGED
|
@@ -191,6 +191,96 @@
|
|
|
191
191
|
"@astryx.powersearch.resultCount": {
|
|
192
192
|
"defaultMessage": "⟦{count, number} {count, plural, one {result} other {results}}⟧"
|
|
193
193
|
},
|
|
194
|
+
"@astryx.powersearch.sheet.filtersTitle": {
|
|
195
|
+
"defaultMessage": "⟦Ƒíłţéřš⟧"
|
|
196
|
+
},
|
|
197
|
+
"@astryx.powersearch.sheet.addFilter": {
|
|
198
|
+
"defaultMessage": "⟦Àðð ƒíłţéř⟧"
|
|
199
|
+
},
|
|
200
|
+
"@astryx.powersearch.sheet.noFilters": {
|
|
201
|
+
"defaultMessage": "⟦Ñó ƒíłţéřš àþþłíéð⟧"
|
|
202
|
+
},
|
|
203
|
+
"@astryx.powersearch.sheet.noFiltersDescription": {
|
|
204
|
+
"defaultMessage": "⟦Àðð à ƒíłţéř ţó ñàřřóŵ ýóúř řéšúłţš àñð ƒíñð ŵĥàţ ýóú ñééð ƒàšţéř.⟧"
|
|
205
|
+
},
|
|
206
|
+
"@astryx.powersearch.sheet.clearAll": {
|
|
207
|
+
"defaultMessage": "⟦Çłéàř àłł⟧"
|
|
208
|
+
},
|
|
209
|
+
"@astryx.powersearch.sheet.clearAllTitle": {
|
|
210
|
+
"defaultMessage": "⟦Çłéàř àłł ƒíłţéřš?⟧"
|
|
211
|
+
},
|
|
212
|
+
"@astryx.powersearch.sheet.clearAllDescription": {
|
|
213
|
+
"defaultMessage": "⟦Ţĥíš řéɱóṽéš àłł éðíţàƀłé ƒíłţéřš ƒřóɱ ţĥíš šéàřçĥ.⟧"
|
|
214
|
+
},
|
|
215
|
+
"@astryx.powersearch.sheet.clearAllConfirm": {
|
|
216
|
+
"defaultMessage": "⟦Çłéàř ƒíłţéřš⟧"
|
|
217
|
+
},
|
|
218
|
+
"@astryx.powersearch.sheet.clearAllCancel": {
|
|
219
|
+
"defaultMessage": "⟦Ķééþ ƒíłţéřš⟧"
|
|
220
|
+
},
|
|
221
|
+
"@astryx.powersearch.sheet.done": {
|
|
222
|
+
"defaultMessage": "⟦Ðóñé⟧"
|
|
223
|
+
},
|
|
224
|
+
"@astryx.powersearch.sheet.search": {
|
|
225
|
+
"defaultMessage": "⟦Šéàřçĥ⟧"
|
|
226
|
+
},
|
|
227
|
+
"@astryx.powersearch.sheet.searchResults": {
|
|
228
|
+
"defaultMessage": "⟦Šéàřçĥ řéšúłţš⟧"
|
|
229
|
+
},
|
|
230
|
+
"@astryx.powersearch.sheet.searchFields": {
|
|
231
|
+
"defaultMessage": "⟦Šéàřçĥ ƒíłţéřš⟧"
|
|
232
|
+
},
|
|
233
|
+
"@astryx.powersearch.sheet.searchFieldsPlaceholder": {
|
|
234
|
+
"defaultMessage": "⟦Šéàřçĥ ƒíłţéřš…⟧"
|
|
235
|
+
},
|
|
236
|
+
"@astryx.powersearch.sheet.ungroupedFields": {
|
|
237
|
+
"defaultMessage": "⟦Ĝéñéřàł⟧"
|
|
238
|
+
},
|
|
239
|
+
"@astryx.powersearch.sheet.noMatchingFields": {
|
|
240
|
+
"defaultMessage": "⟦Ñó ƒíłţéřš ɱàţçĥ ýóúř šéàřçĥ⟧"
|
|
241
|
+
},
|
|
242
|
+
"@astryx.powersearch.sheet.tryDifferentSearch": {
|
|
243
|
+
"defaultMessage": "⟦Ţřý à ð탃éřéñţ šéàřçĥ.⟧"
|
|
244
|
+
},
|
|
245
|
+
"@astryx.powersearch.sheet.noResults": {
|
|
246
|
+
"defaultMessage": "⟦Ñó řéšúłţš ƒóúñð⟧"
|
|
247
|
+
},
|
|
248
|
+
"@astryx.powersearch.sheet.filterUnavailable": {
|
|
249
|
+
"defaultMessage": "⟦Ţĥíš ƒíłţéř íš ñó łóñĝéř àṽàíłàƀłé⟧"
|
|
250
|
+
},
|
|
251
|
+
"@astryx.powersearch.sheet.removeFilter": {
|
|
252
|
+
"defaultMessage": "⟦Řéɱóṽé {field} ƒíłţéř⟧"
|
|
253
|
+
},
|
|
254
|
+
"@astryx.powersearch.sheet.relativeDaysAgo": {
|
|
255
|
+
"defaultMessage": "⟦{count, number} {count, plural, one {day} other {days}} àĝó⟧"
|
|
256
|
+
},
|
|
257
|
+
"@astryx.powersearch.sheet.relativeDaysFromNow": {
|
|
258
|
+
"defaultMessage": "⟦{count, number} {count, plural, one {day} other {days}} ƒřóɱ ñóŵ⟧"
|
|
259
|
+
},
|
|
260
|
+
"@astryx.powersearch.sheet.relativeWeeksAgo": {
|
|
261
|
+
"defaultMessage": "⟦{count, number} {count, plural, one {week} other {weeks}} àĝó⟧"
|
|
262
|
+
},
|
|
263
|
+
"@astryx.powersearch.sheet.relativeWeeksFromNow": {
|
|
264
|
+
"defaultMessage": "⟦{count, number} {count, plural, one {week} other {weeks}} ƒřóɱ ñóŵ⟧"
|
|
265
|
+
},
|
|
266
|
+
"@astryx.powersearch.sheet.relativeMonthsAgo": {
|
|
267
|
+
"defaultMessage": "⟦{count, number} {count, plural, one {month} other {months}} àĝó⟧"
|
|
268
|
+
},
|
|
269
|
+
"@astryx.powersearch.sheet.relativeMonthsFromNow": {
|
|
270
|
+
"defaultMessage": "⟦{count, number} {count, plural, one {month} other {months}} ƒřóɱ ñóŵ⟧"
|
|
271
|
+
},
|
|
272
|
+
"@astryx.powersearch.sheet.fieldOperator": {
|
|
273
|
+
"defaultMessage": "⟦{field} {operator}⟧"
|
|
274
|
+
},
|
|
275
|
+
"@astryx.powersearch.sheet.labelValue": {
|
|
276
|
+
"defaultMessage": "⟦{label} {value}⟧"
|
|
277
|
+
},
|
|
278
|
+
"@astryx.powersearch.sheet.filtersClearedWithCount": {
|
|
279
|
+
"defaultMessage": "⟦Àłł ƒíłţéřš řéɱóṽéð. {resultCount}⟧"
|
|
280
|
+
},
|
|
281
|
+
"@astryx.powersearch.sheet.editableFiltersClearedWithCount": {
|
|
282
|
+
"defaultMessage": "⟦Éðíţàƀłé ƒíłţéřš řéɱóṽéð. {resultCount}⟧"
|
|
283
|
+
},
|
|
194
284
|
"@astryx.alertDialog.cancel": {
|
|
195
285
|
"defaultMessage": "⟦Çàñçéł⟧"
|
|
196
286
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/core",
|
|
3
|
-
"version": "0.7.7-canary.
|
|
3
|
+
"version": "0.7.7-canary.c19ca12",
|
|
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",
|
|
@@ -824,6 +824,11 @@
|
|
|
824
824
|
"types": "./dist/Markdown/remark.d.ts",
|
|
825
825
|
"default": "./dist/Markdown/remark.js"
|
|
826
826
|
},
|
|
827
|
+
"./internal/indicatorPress.stylex": {
|
|
828
|
+
"source": "./src/internal/indicatorPress.stylex.ts",
|
|
829
|
+
"types": "./dist/internal/indicatorPress.stylex.d.ts",
|
|
830
|
+
"default": "./dist/internal/indicatorPress.stylex.js"
|
|
831
|
+
},
|
|
827
832
|
"./internal/touch": {
|
|
828
833
|
"source": "./src/internal/touch.ts",
|
|
829
834
|
"types": "./dist/internal/touch.d.ts",
|
|
@@ -865,9 +870,9 @@
|
|
|
865
870
|
"react-dom": ">=19.0.0"
|
|
866
871
|
},
|
|
867
872
|
"devDependencies": {
|
|
868
|
-
"@astryxdesign/a11y-spec": "0.7.7-canary.
|
|
869
|
-
"@astryxdesign/cli": "0.7.7-canary.
|
|
870
|
-
"@astryxdesign/interaction-harness": "0.7.7-canary.
|
|
873
|
+
"@astryxdesign/a11y-spec": "0.7.7-canary.c19ca12",
|
|
874
|
+
"@astryxdesign/cli": "0.7.7-canary.c19ca12",
|
|
875
|
+
"@astryxdesign/interaction-harness": "0.7.7-canary.c19ca12",
|
|
871
876
|
"@babel/cli": "^7.29.7",
|
|
872
877
|
"@babel/core": "^7.29.7",
|
|
873
878
|
"@babel/preset-react": "^7.29.7",
|
|
@@ -21,7 +21,7 @@ export const docs = {
|
|
|
21
21
|
],
|
|
22
22
|
usage: {
|
|
23
23
|
description:
|
|
24
|
-
'AlertDialog asks the user to confirm a destructive or irreversible action before it happens. Use it for things like deleting content, revoking access, or discarding unsaved changes.\n\nIt implements the WAI-ARIA APG [Alert Dialog pattern](https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog/): `role="alertdialog"`, a title linked by `aria-labelledby`, a consequence description linked by `aria-describedby`, focus moved into the dialog on open and returned to the trigger on close, and no dismissal by clicking outside. Escape cancels.\n\nAlertDialog passes its requested width through to Dialog, which clamps the surface to the container and dynamic viewport with token gutters. Generic Dialog footers should wrap, but Dialog does not own action semantics or order; consumer composition controls that. AlertDialog owns its confirmation semantics: above 640px, actions render horizontally and may move onto another row; at 640px and below, the destructive action appears above Cancel and both buttons fill the footer width. Button labels retain their standard single-line behavior. The breakpoint follows available width, not pointer or hover capability. The body scrolls when block space is constrained.\n\nFor cases where you want to show an alert without managing open state, use the `useImperativeAlertDialog` hook: call `alert.show(options)` and render `alert.element` in your tree.',
|
|
24
|
+
'AlertDialog asks the user to confirm a destructive or irreversible action before it happens. Use it for things like deleting content, revoking access, or discarding unsaved changes.\n\nIt implements the WAI-ARIA APG [Alert Dialog pattern](https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog/): `role="alertdialog"`, a title linked by `aria-labelledby`, a consequence description linked by `aria-describedby`, focus moved into the dialog on open and returned to the trigger on close, and no dismissal by clicking outside. Escape cancels.\n\nAlertDialog passes its requested width through to Dialog, which clamps the surface to the container and dynamic viewport with token gutters. Generic Dialog footers should wrap, but Dialog does not own action semantics or order; consumer composition controls that. AlertDialog owns its confirmation semantics: above 640px, actions render horizontally and may move onto another row; at 640px and below, the destructive action appears above Cancel and both buttons fill the footer width. Button labels retain their standard single-line behavior. The breakpoint follows available width, not pointer or hover capability. The body scrolls when block space is constrained.\n\nThe two actions are tracked as one group under every pointer, the way iOS tracks the actions of an alert: the action under the pointer highlights as soon as it is pressed, the highlight follows the pointer from one action to the other, and the release runs the action under it. Releasing off both actions runs nothing. The keyboard and assistive technology keep the click of each button.\n\nFor cases where you want to show an alert without managing open state, use the `useImperativeAlertDialog` hook: call `alert.show(options)` and render `alert.element` in your tree.',
|
|
25
25
|
bestPractices: [
|
|
26
26
|
{
|
|
27
27
|
guidance: true,
|
|
@@ -196,7 +196,7 @@ export const docsDense = {
|
|
|
196
196
|
'Confirms destructive/irreversible action before it happens (delete, revoke access, discard unsaved changes).',
|
|
197
197
|
usage: {
|
|
198
198
|
description:
|
|
199
|
-
'AlertDialog confirms destructive/irreversible action (delete, revoke access, discard changes). Implements WAI-ARIA APG Alert Dialog pattern (https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog/): role="alertdialog", aria-labelledby title, aria-describedby description, focus into dialog on open + back to trigger on close, no outside-click dismissal, Escape cancels. Dialog preserves requested width + clamps it to container/dynamic viewport gutters. Generic Dialog footers wrap while consumers own action order. AlertDialog owns confirmation action layout: >640px horizontal buttons may move to another row; <=640px puts the destructive action above Cancel and makes both buttons full width regardless of pointer/hover capability. Button labels remain single-line. Body scrolls when height constrained. To show w/o managing open state, use useImperativeAlertDialog hook: call alert.show(options) + render alert.element in tree.',
|
|
199
|
+
'AlertDialog confirms destructive/irreversible action (delete, revoke access, discard changes). Implements WAI-ARIA APG Alert Dialog pattern (https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog/): role="alertdialog", aria-labelledby title, aria-describedby description, focus into dialog on open + back to trigger on close, no outside-click dismissal, Escape cancels. Dialog preserves requested width + clamps it to container/dynamic viewport gutters. Generic Dialog footers wrap while consumers own action order. AlertDialog owns confirmation action layout: >640px horizontal buttons may move to another row; <=640px puts the destructive action above Cancel and makes both buttons full width regardless of pointer/hover capability. Button labels remain single-line. Body scrolls when height constrained. Every pointer: both actions tracked as one group like iOS alerts (action under pointer highlights at once, highlight follows pointer between actions, release runs action under pointer, release off both runs nothing); keyboard/AT keep each button click. To show w/o managing open state, use useImperativeAlertDialog hook: call alert.show(options) + render alert.element in tree.',
|
|
200
200
|
bestPractices: [
|
|
201
201
|
{
|
|
202
202
|
guidance: true,
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file AlertDialog.tsx
|
|
7
|
-
* @input Uses React, StyleX, Dialog, Layout, Heading, Text, Button
|
|
7
|
+
* @input Uses React, StyleX, Dialog, Layout, Heading, Text, Button, the
|
|
8
|
+
* action-group tracking (hooks/useActionGroupTracking) and the press-group
|
|
9
|
+
* marker (privateAttributes/pressGroupItem.stylex)
|
|
8
10
|
* @output Exports AlertDialog component, AlertDialogProps type
|
|
9
11
|
* @position Core implementation; consumed by index.ts, tested by AlertDialog.test.tsx
|
|
10
12
|
*
|
|
@@ -12,11 +14,12 @@
|
|
|
12
14
|
* - /packages/core/src/AlertDialog/AlertDialog.doc.mjs (props table, features, examples)
|
|
13
15
|
* - /packages/core/src/AlertDialog/AlertDialog.test.tsx (tests for new/changed behavior)
|
|
14
16
|
* - /packages/core/src/AlertDialog/index.ts (exports if types change)
|
|
17
|
+
* - /packages/core/src/AlertDialog/__tests__/AlertDialog.interaction.browser.spec.ts (touch tracking)
|
|
15
18
|
* - /apps/storybook/stories/AlertDialog.stories.tsx (storybook stories)
|
|
16
19
|
* - /packages/cli/assets/templates/blocks/components/AlertDialog/ (showcase blocks)
|
|
17
20
|
*/
|
|
18
21
|
|
|
19
|
-
import React, {useId, useCallback} from 'react';
|
|
22
|
+
import React, {useId, useCallback, useRef} from 'react';
|
|
20
23
|
import * as stylex from '@stylexjs/stylex';
|
|
21
24
|
import {Dialog} from '../Dialog/Dialog';
|
|
22
25
|
import {Layout} from '../Layout/Layout';
|
|
@@ -36,12 +39,22 @@ import {
|
|
|
36
39
|
useComponentTranslator,
|
|
37
40
|
} from '../i18n/useComponentTranslator';
|
|
38
41
|
import english from '../i18n/generated-english/AlertDialog/AlertDialog.generated';
|
|
42
|
+
import {useActionGroupTracking} from '../hooks/useActionGroupTracking';
|
|
43
|
+
import {PressGroupContext} from '../hooks/pressGroupContext';
|
|
44
|
+
import {alertController} from '../motion/uikit/alert';
|
|
45
|
+
import {pressGroupItemProps} from '../privateAttributes/pressGroupItem.stylex';
|
|
39
46
|
|
|
40
47
|
registerEnglishFallback(english);
|
|
41
48
|
|
|
42
49
|
const SMALL_SCREEN_QUERY = '(max-width: 640px)';
|
|
43
50
|
|
|
44
51
|
const styles = stylex.create({
|
|
52
|
+
// The browser may pinch-zoom on the actions but never pans there. Chrome on
|
|
53
|
+
// Android cancels a pointer it pans, which would cancel the group's press.
|
|
54
|
+
// The gesture host keeps an author's narrower touch-action.
|
|
55
|
+
trackingRow: {
|
|
56
|
+
touchAction: 'pinch-zoom',
|
|
57
|
+
},
|
|
45
58
|
action: {
|
|
46
59
|
maxWidth: '100%',
|
|
47
60
|
minWidth: 0,
|
|
@@ -177,6 +190,19 @@ export function AlertDialog({
|
|
|
177
190
|
onOpenChange(false);
|
|
178
191
|
}, [onOpenChange]);
|
|
179
192
|
|
|
193
|
+
// Each action carries the press-group marker from its first render, so the
|
|
194
|
+
// tracker is its only painter.
|
|
195
|
+
const actionsRef = useRef<HTMLElement>(null);
|
|
196
|
+
const isTracking = isOpen && isInline !== true;
|
|
197
|
+
useActionGroupTracking(actionsRef, {
|
|
198
|
+
// The actions row holds only the two buttons.
|
|
199
|
+
itemSelector: 'button',
|
|
200
|
+
highlightOnsetMs: alertController.actions.highlightOnsetMs,
|
|
201
|
+
highlightExpansion: alertController.actions.highlightExpansion,
|
|
202
|
+
isEnabled: isTracking,
|
|
203
|
+
});
|
|
204
|
+
const actionTrackingProps = isTracking ? pressGroupItemProps : undefined;
|
|
205
|
+
|
|
180
206
|
const buttonActionStyle = [
|
|
181
207
|
styles.action,
|
|
182
208
|
isSmallScreen && styles.stackedAction,
|
|
@@ -188,6 +214,7 @@ export function AlertDialog({
|
|
|
188
214
|
label={cancelLabel}
|
|
189
215
|
onClick={handleCancel}
|
|
190
216
|
xstyle={buttonActionStyle}
|
|
217
|
+
{...actionTrackingProps}
|
|
191
218
|
// Dialog focuses [data-autofocus] itself after showModal(), because
|
|
192
219
|
// React's autoFocus runs during commit while the dialog is invisible.
|
|
193
220
|
// Cancel is least destructive, so it remains the autofocus target even
|
|
@@ -203,6 +230,7 @@ export function AlertDialog({
|
|
|
203
230
|
onClick={onAction}
|
|
204
231
|
isLoading={isActionLoading}
|
|
205
232
|
xstyle={buttonActionStyle}
|
|
233
|
+
{...actionTrackingProps}
|
|
206
234
|
/>
|
|
207
235
|
);
|
|
208
236
|
|
|
@@ -244,13 +272,17 @@ export function AlertDialog({
|
|
|
244
272
|
destructive-above-Cancel narrow order because confirmation
|
|
245
273
|
actions have component-specific meaning here. */}
|
|
246
274
|
<Stack
|
|
275
|
+
ref={actionsRef}
|
|
276
|
+
xstyle={isTracking && styles.trackingRow}
|
|
247
277
|
direction={isSmallScreen ? 'vertical' : 'horizontal'}
|
|
248
278
|
gap={2}
|
|
249
279
|
hAlign={isSmallScreen ? 'stretch' : 'end'}
|
|
250
280
|
wrap={isSmallScreen ? 'nowrap' : 'wrap'}>
|
|
251
|
-
{
|
|
252
|
-
|
|
253
|
-
|
|
281
|
+
<PressGroupContext value={isTracking}>
|
|
282
|
+
{isSmallScreen
|
|
283
|
+
? [actionButton, cancelButton]
|
|
284
|
+
: [cancelButton, actionButton]}
|
|
285
|
+
</PressGroupContext>
|
|
254
286
|
</Stack>
|
|
255
287
|
</LayoutFooter>
|
|
256
288
|
}
|