@astryxdesign/core 0.7.8 → 0.7.9-canary.048476f
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/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +5 -0
- package/dist/Calendar/styles.d.ts +1 -1
- package/dist/ClickableCard/ClickableCard.d.ts +1 -1
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +5 -1
- package/dist/DateInput/PickerWheel.d.ts.map +1 -1
- package/dist/DateInput/PickerWheel.js +7 -1
- package/dist/DateRangeInput/DateRangeInput.js +1 -1
- package/dist/Dialog/Dialog.d.ts +2 -1
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +12 -1
- package/dist/Drawer/useDrawerDialogPresence.d.ts +2 -1
- package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -1
- package/dist/Drawer/useDrawerDialogPresence.js +11 -2
- package/dist/DropdownMenu/DropdownMenu.d.ts +9 -1
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +9 -4
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +3 -2
- package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuItem.js +3 -2
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +3 -2
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +3 -2
- package/dist/Field/inputDisabledFocus.d.ts +4 -4
- package/dist/Field/inputStyles.stylex.d.ts +1 -1
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +16 -2
- package/dist/Icon/Icon.d.ts +1 -1
- package/dist/InfoTip/InfoTip.d.ts +1 -0
- package/dist/InfoTip/InfoTip.d.ts.map +1 -1
- package/dist/InfoTip/InfoTip.js +1 -0
- package/dist/Item/Item.d.ts +2 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +29 -6
- package/dist/Layer/holdEntranceInput.d.ts +24 -0
- package/dist/Layer/holdEntranceInput.d.ts.map +1 -0
- package/dist/Layer/holdEntranceInput.js +65 -0
- package/dist/Layer/inputHold.d.ts +49 -0
- package/dist/Layer/inputHold.d.ts.map +1 -0
- package/dist/Layer/inputHold.js +636 -0
- package/dist/Layer/preserveAnimations.d.ts +1 -5
- package/dist/Layer/preserveAnimations.d.ts.map +1 -1
- package/dist/Layer/preserveAnimations.js +12 -214
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +4 -0
- package/dist/MetadataList/MetadataList.js +1 -1
- package/dist/MobileNav/MobileNav.d.ts +11 -1
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +34 -1
- package/dist/MoreMenu/MoreMenu.d.ts +5 -3
- package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +4 -1
- package/dist/SelectableCard/SelectableCard.d.ts +1 -1
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +5 -1
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +12 -2
- package/dist/Table/plugins/sortable/useTableSortable.js +1 -1
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +9 -0
- package/dist/Token/TokenLink.d.ts +1 -1
- package/dist/Token/TokenLink.d.ts.map +1 -1
- package/dist/Token/TokenLink.js +4 -1
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +162 -59
- package/dist/TreeList/TreeListItem.d.ts +2 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +27 -3
- package/dist/astryx.css +30 -7
- package/dist/gestures/GestureHost.d.ts +2 -2
- package/dist/gestures/GestureHost.d.ts.map +1 -1
- package/dist/gestures/GestureHost.js +21 -6
- package/dist/gestures/nativeScroll.d.ts +3 -6
- package/dist/gestures/nativeScroll.d.ts.map +1 -1
- package/dist/gestures/nativeScroll.js +7 -52
- package/dist/gestures/wheelSegmenter.d.ts +68 -1
- package/dist/gestures/wheelSegmenter.d.ts.map +1 -1
- package/dist/gestures/wheelSegmenter.js +199 -10
- package/dist/hooks/menuPressGesture.d.ts +133 -21
- package/dist/hooks/menuPressGesture.d.ts.map +1 -1
- package/dist/hooks/menuPressGesture.js +155 -30
- package/dist/hooks/menuPressValues.d.ts +16 -0
- package/dist/hooks/menuPressValues.d.ts.map +1 -0
- package/dist/hooks/menuPressValues.js +18 -0
- package/dist/hooks/useClickableContainer.d.ts +27 -5
- package/dist/hooks/useClickableContainer.d.ts.map +1 -1
- package/dist/hooks/useClickableContainer.js +41 -5
- package/dist/hooks/useFocusTrap.d.ts +10 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +225 -132
- package/dist/hooks/useMenuPress.d.ts +34 -1
- package/dist/hooks/useMenuPress.d.ts.map +1 -1
- package/dist/hooks/useMenuPress.js +93 -5
- package/dist/hooks/usePressFeedback.d.ts +6 -6
- package/dist/hooks/usePressFeedback.js +6 -6
- package/dist/motion/carryAnimations.d.ts +58 -0
- package/dist/motion/carryAnimations.d.ts.map +1 -0
- package/dist/motion/carryAnimations.js +305 -0
- package/dist/motion/transientCopy.d.ts +4 -2
- package/dist/motion/transientCopy.d.ts.map +1 -1
- package/dist/motion/transientCopy.js +34 -5
- package/dist/motion/uikit/gestures.d.ts +41 -0
- package/dist/motion/uikit/gestures.d.ts.map +1 -1
- package/dist/motion/uikit/gestures.js +25 -0
- package/dist/motion/uikit/index.d.ts +1 -1
- package/dist/motion/uikit/index.d.ts.map +1 -1
- package/dist/motion/uikit/index.js +1 -1
- package/dist/privateAttributes/menuPressLit.stylex.d.ts +52 -0
- package/dist/privateAttributes/menuPressLit.stylex.d.ts.map +1 -0
- package/dist/privateAttributes/menuPressLit.stylex.js +99 -0
- package/dist/privateAttributes/press.stylex.d.ts +139 -0
- package/dist/privateAttributes/press.stylex.d.ts.map +1 -0
- package/dist/privateAttributes/press.stylex.js +98 -0
- package/dist/theme/tokens.stylex.d.ts +2 -2
- package/dist/theme/tokens.stylex.js +1 -1
- package/dist/utils/flatTree.d.ts +6 -3
- package/dist/utils/flatTree.d.ts.map +1 -1
- package/dist/utils/flatTree.js +13 -3
- package/dist/utils/hitArea.d.ts.map +1 -1
- package/dist/utils/hitArea.js +82 -5
- package/dist/utils/inputStream.d.ts +14 -1
- package/dist/utils/inputStream.d.ts.map +1 -1
- package/dist/utils/inputStream.js +40 -9
- package/dist/utils/interactionOverlay.stylex.d.ts +2 -1
- package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
- package/dist/utils/interactionOverlay.stylex.js +7 -2
- package/dist/utils/pressFeedback.d.ts +7 -0
- package/dist/utils/pressFeedback.d.ts.map +1 -1
- package/dist/utils/pressFeedback.js +32 -7
- package/dist/utils/pressGesture.d.ts +6 -0
- package/dist/utils/pressGesture.d.ts.map +1 -1
- package/dist/utils/pressGesture.js +17 -0
- package/dist/utils/rowPressLayer.stylex.d.ts +14 -0
- package/dist/utils/rowPressLayer.stylex.d.ts.map +1 -0
- package/dist/utils/rowPressLayer.stylex.js +25 -0
- package/dist/utils/scrollView.d.ts +25 -0
- package/dist/utils/scrollView.d.ts.map +1 -0
- package/dist/utils/scrollView.js +108 -0
- package/dist/utils/selectionLock.d.ts.map +1 -1
- package/dist/utils/selectionLock.js +1 -10
- package/dist/utils/triggerFocus.d.ts +5 -0
- package/dist/utils/triggerFocus.d.ts.map +1 -1
- package/dist/utils/triggerFocus.js +9 -2
- package/package.json +5 -5
- package/src/BottomSheet/BottomSheet.tsx +5 -0
- package/src/ClickableCard/ClickableCard.tsx +8 -1
- package/src/DateInput/PickerWheel.tsx +7 -2
- package/src/DateRangeInput/DateRangeInput.tsx +1 -1
- package/src/Dialog/Dialog.doc.mjs +1 -1
- package/src/Dialog/Dialog.tsx +12 -1
- package/src/Drawer/Drawer.doc.mjs +1 -1
- package/src/Drawer/useDrawerDialogPresence.ts +9 -2
- package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -2
- package/src/DropdownMenu/DropdownMenu.tsx +29 -5
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +5 -1
- package/src/DropdownMenu/DropdownMenuItem.tsx +8 -4
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +5 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +5 -1
- package/src/FileInput/FileInput.tsx +16 -2
- package/src/InfoTip/InfoTip.doc.mjs +26 -2
- package/src/InfoTip/InfoTip.tsx +1 -0
- package/src/Item/Item.tsx +51 -9
- package/src/Layer/holdEntranceInput.ts +84 -0
- package/src/Layer/inputHold.ts +734 -0
- package/src/Layer/preserveAnimations.ts +12 -275
- package/src/Lightbox/Lightbox.tsx +4 -0
- package/src/MetadataList/MetadataList.tsx +1 -1
- package/src/MobileNav/MobileNav.doc.mjs +3 -3
- package/src/MobileNav/MobileNav.tsx +34 -1
- package/src/MoreMenu/MoreMenu.doc.mjs +2 -4
- package/src/MoreMenu/MoreMenu.tsx +5 -3
- package/src/RadioList/RadioListItem.tsx +4 -5
- package/src/SelectableCard/SelectableCard.tsx +8 -1
- package/src/Spinner/Spinner.tsx +13 -3
- package/src/Table/plugins/sortable/useTableSortable.tsx +1 -1
- package/src/Token/Token.tsx +18 -1
- package/src/Token/TokenLink.tsx +7 -1
- package/src/Tooltip/useTooltip.tsx +175 -79
- package/src/TreeList/TreeListItem.tsx +36 -2
- package/src/gestures/GestureHost.ts +21 -5
- package/src/gestures/README.md +12 -4
- package/src/gestures/nativeScroll.ts +12 -68
- package/src/gestures/wheelSegmenter.ts +243 -10
- package/src/hooks/menuPressGesture.ts +244 -38
- package/src/hooks/menuPressValues.ts +18 -0
- package/src/hooks/useClickableContainer.doc.mjs +8 -2
- package/src/hooks/useClickableContainer.ts +72 -6
- package/src/hooks/useFocusTrap.ts +268 -151
- package/src/hooks/useMenuPress.ts +118 -11
- package/src/hooks/usePressFeedback.doc.mjs +3 -3
- package/src/hooks/usePressFeedback.ts +6 -6
- package/src/motion/MEASUREMENTS.md +11 -0
- package/src/motion/carryAnimations.ts +389 -0
- package/src/motion/transientCopy.ts +45 -5
- package/src/motion/uikit/gestures.ts +22 -0
- package/src/motion/uikit/index.ts +1 -0
- package/src/privateAttributes/menuPressLit.stylex.ts +104 -0
- package/src/privateAttributes/press.stylex.ts +244 -0
- package/src/theme/tokens.stylex.ts +1 -1
- package/src/utils/flatTree.ts +15 -3
- package/src/utils/hitArea.ts +107 -5
- package/src/utils/inputStream.ts +47 -10
- package/src/utils/interactionOverlay.stylex.ts +7 -2
- package/src/utils/pressFeedback.ts +31 -6
- package/src/utils/pressGesture.ts +24 -1
- package/src/utils/rowPressLayer.stylex.ts +27 -0
- package/src/utils/scrollView.ts +135 -0
- package/src/utils/selectionLock.ts +5 -10
- package/src/utils/triggerFocus.ts +17 -4
package/src/Token/TokenLink.tsx
CHANGED
|
@@ -90,12 +90,13 @@ export function TokenLink({
|
|
|
90
90
|
removeButton,
|
|
91
91
|
onClick: onClickProp,
|
|
92
92
|
onMouseUp: onMouseUpProp,
|
|
93
|
+
onPointerDown: onPointerDownProp,
|
|
93
94
|
...containerProps
|
|
94
95
|
}: TokenLinkProps) {
|
|
95
96
|
const containerRef = useRef<HTMLElement | null>(null);
|
|
96
97
|
const linkRef = useRef<HTMLElement | null>(null);
|
|
97
98
|
|
|
98
|
-
const {onClick, onMouseUp} = useClickableContainer({
|
|
99
|
+
const {onClick, onMouseUp, onPointerDown} = useClickableContainer({
|
|
99
100
|
containerRef,
|
|
100
101
|
interactiveRef: linkRef,
|
|
101
102
|
href,
|
|
@@ -113,6 +114,11 @@ export function TokenLink({
|
|
|
113
114
|
isDisabled
|
|
114
115
|
? onMouseUpProp
|
|
115
116
|
: composeEventHandlers(onMouseUpProp, onMouseUp)
|
|
117
|
+
}
|
|
118
|
+
onPointerDown={
|
|
119
|
+
isDisabled
|
|
120
|
+
? onPointerDownProp
|
|
121
|
+
: composeEventHandlers(onPointerDownProp, onPointerDown)
|
|
116
122
|
}>
|
|
117
123
|
{icon}
|
|
118
124
|
{isDisabled ? (
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
type ReactNode,
|
|
22
22
|
type RefCallback,
|
|
23
23
|
} from 'react';
|
|
24
|
-
import {createTriggerFocusGate} from '../utils/triggerFocus';
|
|
24
|
+
import {createTriggerFocusGate, isFocusOnTrigger} from '../utils/triggerFocus';
|
|
25
25
|
import * as stylex from '@stylexjs/stylex';
|
|
26
26
|
import {
|
|
27
27
|
useLayerInternal,
|
|
@@ -308,6 +308,17 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
308
308
|
const showTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
309
309
|
const hideTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
310
310
|
const triggerRef = useRef<HTMLElement | null>(null);
|
|
311
|
+
// Whether the tooltip is enabled now, for a show that runs after a render
|
|
312
|
+
// (a pending hover show) and for the trigger ref callback.
|
|
313
|
+
const isEnabledRef = useRef(isEnabled);
|
|
314
|
+
isEnabledRef.current = isEnabled;
|
|
315
|
+
// Counts the renders in which the tooltip is disabled. A pending show
|
|
316
|
+
// records it, so a show scheduled before a disable is dropped even when
|
|
317
|
+
// the tooltip is enabled again before the timer fires.
|
|
318
|
+
const disabledRendersRef = useRef(0);
|
|
319
|
+
if (!isEnabled) {
|
|
320
|
+
disabledRendersRef.current += 1;
|
|
321
|
+
}
|
|
311
322
|
|
|
312
323
|
// Clear all timeouts
|
|
313
324
|
const clearTimeouts = useCallback(() => {
|
|
@@ -460,22 +471,16 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
460
471
|
return;
|
|
461
472
|
}
|
|
462
473
|
clearTimeouts();
|
|
474
|
+
const disabledRenders = disabledRendersRef.current;
|
|
463
475
|
showTimeoutRef.current = setTimeout(() => {
|
|
464
|
-
|
|
476
|
+
// A show runs only if the tooltip stayed enabled since it was
|
|
477
|
+
// scheduled: nothing would close a tooltip that opens after a disable.
|
|
478
|
+
if (disabledRendersRef.current === disabledRenders) {
|
|
479
|
+
showLayer();
|
|
480
|
+
}
|
|
465
481
|
}, delay);
|
|
466
482
|
}, [isEnabled, isOpen, clearTimeouts, showLayer, delay]);
|
|
467
483
|
|
|
468
|
-
// A show scheduled while the triggers were enabled must not outlive them:
|
|
469
|
-
// disabling also detaches the leave listener that would have cancelled it,
|
|
470
|
-
// so the timer would open a tooltip that nothing ever closes. Only the
|
|
471
|
-
// pending show is dropped; a pending hide still runs.
|
|
472
|
-
useEffect(() => {
|
|
473
|
-
if (!isEnabled && showTimeoutRef.current) {
|
|
474
|
-
clearTimeout(showTimeoutRef.current);
|
|
475
|
-
showTimeoutRef.current = null;
|
|
476
|
-
}
|
|
477
|
-
}, [isEnabled]);
|
|
478
|
-
|
|
479
484
|
// Schedule hide with delay (suppressed when isOpen is true).
|
|
480
485
|
// A small hover bridge (when hideDelay is 0) lets the pointer travel from the
|
|
481
486
|
// trigger onto the tooltip surface without the tooltip vanishing — required
|
|
@@ -537,23 +542,25 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
537
542
|
// focus that counted still hides on blur (utils/triggerFocus.ts).
|
|
538
543
|
const [focusGate] = useState(createTriggerFocusGate);
|
|
539
544
|
|
|
545
|
+
// Whether focus on `target` opens the tooltip. With a `trigger`, its
|
|
546
|
+
// `focusTrigger` rule applies too. Only `:focus-visible` focus opens it, and
|
|
547
|
+
// a tap never does: a tapped `<input>` also matches `:focus-visible`.
|
|
548
|
+
const opensOnFocus = useCallback(
|
|
549
|
+
(target: HTMLElement, trigger: HTMLElement | null): boolean => {
|
|
550
|
+
if (trigger != null && !isFocusOnTrigger(target, trigger, focusTrigger)) {
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
553
|
+
return !isTouchInteraction() && target.matches(':focus-visible');
|
|
554
|
+
},
|
|
555
|
+
[focusTrigger, isTouchInteraction],
|
|
556
|
+
);
|
|
557
|
+
|
|
540
558
|
const handleFocusIn = useCallback(
|
|
541
559
|
(e: Event) => {
|
|
542
560
|
if (!focusGate.focusIn(e, focusTrigger) || !isEnabled) {
|
|
543
561
|
return;
|
|
544
562
|
}
|
|
545
|
-
|
|
546
|
-
// filter that out on every element: a tapped `<input>` or contenteditable
|
|
547
|
-
// matches it. Those are exactly the action triggers `auto` just decided
|
|
548
|
-
// to keep shut, so without this the focus reopens what the tap
|
|
549
|
-
// suppressed, over the field the user is trying to type into.
|
|
550
|
-
if (isTouchInteraction()) {
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
553
|
-
// Only show tooltip for keyboard focus (:focus-visible),
|
|
554
|
-
// not programmatic focus (e.g. dialog auto-focus, touch tap)
|
|
555
|
-
const target = e.target as HTMLElement;
|
|
556
|
-
if (!target.matches(':focus-visible')) {
|
|
563
|
+
if (!opensOnFocus(e.target as HTMLElement, null)) {
|
|
557
564
|
return;
|
|
558
565
|
}
|
|
559
566
|
clearTimeouts();
|
|
@@ -563,7 +570,7 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
563
570
|
focusGate,
|
|
564
571
|
focusTrigger,
|
|
565
572
|
isEnabled,
|
|
566
|
-
|
|
573
|
+
opensOnFocus,
|
|
567
574
|
clearTimeouts,
|
|
568
575
|
showLayer,
|
|
569
576
|
],
|
|
@@ -656,66 +663,155 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
|
|
|
656
663
|
],
|
|
657
664
|
);
|
|
658
665
|
|
|
659
|
-
//
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
666
|
+
// The trigger's listeners call the latest handlers through this ref, so the
|
|
667
|
+
// trigger ref callback keeps one identity.
|
|
668
|
+
const handlersRef = useRef({
|
|
669
|
+
handleMouseEnter,
|
|
670
|
+
handleMouseLeave,
|
|
671
|
+
handleFocusIn,
|
|
672
|
+
handleFocusOut,
|
|
673
|
+
handleHeldFocusOut,
|
|
674
|
+
handlePointerEnter,
|
|
675
|
+
handlePointerDown,
|
|
676
|
+
focusTrigger,
|
|
677
|
+
isOpen,
|
|
678
|
+
dropHold,
|
|
679
|
+
hideNow,
|
|
680
|
+
showNow,
|
|
681
|
+
opensOnFocus,
|
|
682
|
+
});
|
|
683
|
+
handlersRef.current = {
|
|
684
|
+
handleMouseEnter,
|
|
685
|
+
handleMouseLeave,
|
|
686
|
+
handleFocusIn,
|
|
687
|
+
handleFocusOut,
|
|
688
|
+
handleHeldFocusOut,
|
|
689
|
+
handlePointerEnter,
|
|
690
|
+
handlePointerDown,
|
|
691
|
+
focusTrigger,
|
|
692
|
+
isOpen,
|
|
693
|
+
dropHold,
|
|
694
|
+
hideNow,
|
|
695
|
+
showNow,
|
|
696
|
+
opensOnFocus,
|
|
697
|
+
};
|
|
679
698
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
699
|
+
// Removes the attached trigger's listeners (the trigger ref callback's
|
|
700
|
+
// cleanup).
|
|
701
|
+
const detachTriggerRef = useRef<(() => void) | null>(null);
|
|
702
|
+
// Set when the trigger detached while the tooltip was disabled: the
|
|
703
|
+
// caller removed the wiring (DropdownMenu's Button while its menu is
|
|
704
|
+
// open), so the next enabled attach reads the focus that arrived meanwhile.
|
|
705
|
+
const wasSuppressedRef = useRef(false);
|
|
706
|
+
|
|
707
|
+
// The trigger's ref callback owns every trigger listener, and reads the
|
|
708
|
+
// trigger's state when it attaches and detaches.
|
|
709
|
+
const interactionRef = useCallback((el: HTMLElement | null) => {
|
|
710
|
+
// A caller that reports `null` by hand detaches the trigger, as the
|
|
711
|
+
// returned cleanup does.
|
|
712
|
+
if (el == null) {
|
|
713
|
+
detachTriggerRef.current?.();
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
if (el === triggerRef.current) {
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
detachTriggerRef.current?.();
|
|
720
|
+
const latest = () => handlersRef.current;
|
|
721
|
+
// `pointerenter` runs before the synthesized `mouseenter` a tap produces,
|
|
722
|
+
// which is what lets the hover path know it is looking at a finger.
|
|
723
|
+
const onPointerEnter = (e: PointerEvent) => latest().handlePointerEnter(e);
|
|
724
|
+
const onMouseEnter = () => latest().handleMouseEnter();
|
|
725
|
+
const onMouseLeave = (e: Event) => latest().handleMouseLeave(e);
|
|
726
|
+
// Press-to-dismiss on a mouse; tap-to-open on a touch pointer.
|
|
727
|
+
const onPointerDown = (e: PointerEvent) => latest().handlePointerDown(e);
|
|
728
|
+
// Focus counts unless focus never opens the tooltip; `auto` decides per
|
|
729
|
+
// event (isFocusForTrigger).
|
|
730
|
+
const onFocusIn = (e: Event) => {
|
|
731
|
+
if (latest().focusTrigger !== 'never') {
|
|
732
|
+
latest().handleFocusIn(e);
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
const onFocusOut = (e: Event) => {
|
|
736
|
+
if (latest().focusTrigger !== 'never') {
|
|
737
|
+
latest().handleFocusOut(e);
|
|
696
738
|
}
|
|
739
|
+
};
|
|
740
|
+
// A held tooltip's own focus-leave close, whatever `focusTrigger` is.
|
|
741
|
+
const onHeldFocusOut = (e: FocusEvent) => latest().handleHeldFocusOut(e);
|
|
742
|
+
el.addEventListener('pointerenter', onPointerEnter);
|
|
743
|
+
el.addEventListener('mouseenter', onMouseEnter);
|
|
744
|
+
el.addEventListener('mouseleave', onMouseLeave);
|
|
745
|
+
el.addEventListener('pointerdown', onPointerDown);
|
|
746
|
+
el.addEventListener('focusin', onFocusIn);
|
|
747
|
+
el.addEventListener('focusout', onFocusOut);
|
|
748
|
+
el.addEventListener('focusout', onHeldFocusOut);
|
|
749
|
+
triggerRef.current = el;
|
|
750
|
+
|
|
751
|
+
// A trigger that attaches again after its wiring was removed
|
|
752
|
+
// (DropdownMenu's Button as its menu closes) missed the focus that
|
|
753
|
+
// arrived meanwhile. Show for it only if it would open the tooltip:
|
|
754
|
+
// returned keyboard focus does, focus returned after a pointer pick does
|
|
755
|
+
// not. Any other attach leaves the tooltip as it is, so a tooltip
|
|
756
|
+
// dismissed with Escape stays closed.
|
|
757
|
+
const focused = el.ownerDocument.activeElement;
|
|
758
|
+
const wasSuppressed = wasSuppressedRef.current;
|
|
759
|
+
if (isEnabledRef.current) {
|
|
760
|
+
wasSuppressedRef.current = false;
|
|
761
|
+
}
|
|
762
|
+
if (
|
|
763
|
+
wasSuppressed &&
|
|
764
|
+
isEnabledRef.current &&
|
|
765
|
+
latest().isOpen === undefined &&
|
|
766
|
+
latest().focusTrigger !== 'never' &&
|
|
767
|
+
focused instanceof HTMLElement &&
|
|
768
|
+
el.contains(focused) &&
|
|
769
|
+
latest().opensOnFocus(focused, el)
|
|
770
|
+
) {
|
|
771
|
+
latest().showNow();
|
|
772
|
+
}
|
|
697
773
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
774
|
+
const detach = () => {
|
|
775
|
+
if (detachTriggerRef.current === detach) {
|
|
776
|
+
detachTriggerRef.current = null;
|
|
777
|
+
}
|
|
778
|
+
el.removeEventListener('pointerenter', onPointerEnter);
|
|
779
|
+
el.removeEventListener('mouseenter', onMouseEnter);
|
|
780
|
+
el.removeEventListener('mouseleave', onMouseLeave);
|
|
781
|
+
el.removeEventListener('pointerdown', onPointerDown);
|
|
782
|
+
el.removeEventListener('focusin', onFocusIn);
|
|
783
|
+
el.removeEventListener('focusout', onFocusOut);
|
|
784
|
+
el.removeEventListener('focusout', onHeldFocusOut);
|
|
785
|
+
stopPressTrackingRef.current?.();
|
|
786
|
+
if (triggerRef.current === el) {
|
|
787
|
+
triggerRef.current = null;
|
|
788
|
+
}
|
|
789
|
+
// A caller removes the wiring as it disables the tooltip. Close an
|
|
790
|
+
// uncontrolled tooltip then, or the next attach shows a stale tooltip.
|
|
791
|
+
// A detach while enabled, such as a merged ref that changes identity
|
|
792
|
+
// on a re-render, keeps a hovered or held tooltip open.
|
|
793
|
+
if (!isEnabledRef.current && latest().isOpen === undefined) {
|
|
794
|
+
wasSuppressedRef.current = true;
|
|
795
|
+
latest().dropHold();
|
|
796
|
+
latest().hideNow();
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
detachTriggerRef.current = detach;
|
|
800
|
+
return detach;
|
|
801
|
+
}, []);
|
|
713
802
|
|
|
714
803
|
// Combined ref - shorthand for calling both positionRef and interactionRef
|
|
715
|
-
const ref
|
|
804
|
+
const ref = useCallback(
|
|
716
805
|
(el: HTMLElement | null) => {
|
|
717
806
|
layerRef(el);
|
|
718
|
-
interactionRef(el);
|
|
807
|
+
const detachInteraction = interactionRef(el);
|
|
808
|
+
if (el == null) {
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
return () => {
|
|
812
|
+
detachInteraction?.();
|
|
813
|
+
layerRef(null);
|
|
814
|
+
};
|
|
719
815
|
},
|
|
720
816
|
[layerRef, interactionRef],
|
|
721
817
|
);
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file TreeListItem.tsx
|
|
7
|
-
* @input Uses React, StyleX, theme tokens, TreeListBranches
|
|
7
|
+
* @input Uses React, StyleX, theme tokens, TreeListBranches, the shared press
|
|
8
|
+
* overlays and the compositor press layer
|
|
8
9
|
* @output Exports TreeListItem component (internal, not publicly exported)
|
|
9
10
|
* @position Internal implementation; consumed by TreeList.tsx
|
|
10
11
|
*
|
|
@@ -27,8 +28,10 @@ import {
|
|
|
27
28
|
} from '../theme/tokens.stylex';
|
|
28
29
|
import {focusOutlineProps} from '../utils/focusOutline.stylex';
|
|
29
30
|
import {interactionOverlayStyles} from '../utils/interactionOverlay.stylex';
|
|
31
|
+
import {rowPressLayerStyles} from '../privateAttributes/press.stylex';
|
|
30
32
|
import {usePressFeedback} from '../hooks/usePressFeedback';
|
|
31
33
|
import {
|
|
34
|
+
cancelNestedTouchPress,
|
|
32
35
|
hasInteractiveAncestor,
|
|
33
36
|
useClickableContainer,
|
|
34
37
|
} from '../hooks/useClickableContainer';
|
|
@@ -485,6 +488,28 @@ export function TreeListItem({
|
|
|
485
488
|
interactiveRef: linkRef,
|
|
486
489
|
disabled: isDisabled || !forwardsToLink,
|
|
487
490
|
});
|
|
491
|
+
|
|
492
|
+
// A finger press that starts on a control inside the row does not activate
|
|
493
|
+
// the row, so the row shows no press for it. The row's own action, its link
|
|
494
|
+
// or invisible button, activates it. The Chevron does too when the row's
|
|
495
|
+
// surface toggles, since it runs that same toggle.
|
|
496
|
+
const actionButtonRef = useRef<HTMLButtonElement>(null);
|
|
497
|
+
const chevronRef = useRef<HTMLButtonElement>(null);
|
|
498
|
+
const surfaceToggles = onClick == null && handleClick != null;
|
|
499
|
+
const pressOnRow = (event: React.PointerEvent<HTMLDivElement>) => {
|
|
500
|
+
if (isDisabled) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const chevron = chevronRef.current;
|
|
504
|
+
const ownAction =
|
|
505
|
+
surfaceToggles &&
|
|
506
|
+
chevron != null &&
|
|
507
|
+
event.target instanceof Node &&
|
|
508
|
+
chevron.contains(event.target)
|
|
509
|
+
? chevron
|
|
510
|
+
: (linkRef.current ?? actionButtonRef.current);
|
|
511
|
+
cancelNestedTouchPress(event, event.currentTarget, ownAction);
|
|
512
|
+
};
|
|
488
513
|
const {onMouseUp: openLinkOnMiddleClick} = useClickableContainer({
|
|
489
514
|
containerRef: linkRowRef,
|
|
490
515
|
href,
|
|
@@ -566,6 +591,7 @@ export function TreeListItem({
|
|
|
566
591
|
// focusable element to receive Enter/Space). The row's handleClick ignores
|
|
567
592
|
// clicks originating inside a <button>, so this never double-toggles.
|
|
568
593
|
<button
|
|
594
|
+
ref={chevronRef}
|
|
569
595
|
type="button"
|
|
570
596
|
aria-expanded={isExpanded}
|
|
571
597
|
aria-label={t('@astryx.treeList.toggleChildren')}
|
|
@@ -642,6 +668,7 @@ export function TreeListItem({
|
|
|
642
668
|
</LinkComponent>
|
|
643
669
|
) : onClick != null ? (
|
|
644
670
|
<button
|
|
671
|
+
ref={actionButtonRef}
|
|
645
672
|
type="button"
|
|
646
673
|
onClick={onClick}
|
|
647
674
|
aria-disabled={isDisabled || undefined}
|
|
@@ -712,6 +739,10 @@ export function TreeListItem({
|
|
|
712
739
|
densityStyles[density],
|
|
713
740
|
styles.interactive,
|
|
714
741
|
interactionOverlayStyles.backgroundImage,
|
|
742
|
+
// The touch press on a compositor layer (after the
|
|
743
|
+
// overlay, whose own touch paint it turns off).
|
|
744
|
+
rowPressLayerStyles.cell,
|
|
745
|
+
rowPressLayerStyles.cellOnImage,
|
|
715
746
|
isDisabled && styles.disabled,
|
|
716
747
|
isSelected && styles.selected,
|
|
717
748
|
xstyle,
|
|
@@ -732,7 +763,10 @@ export function TreeListItem({
|
|
|
732
763
|
)}
|
|
733
764
|
ref={forwardsToLink ? linkRowRef : undefined}
|
|
734
765
|
onClick={forwardsToLink ? delegateToLink : handleClick}
|
|
735
|
-
onMouseUp={forwardsToLink ? openLinkOnMiddleClick : undefined}
|
|
766
|
+
onMouseUp={forwardsToLink ? openLinkOnMiddleClick : undefined}
|
|
767
|
+
onPointerDown={
|
|
768
|
+
forwardsToLink || handleClick != null ? pressOnRow : undefined
|
|
769
|
+
}>
|
|
736
770
|
<div {...stylex.props(styles.indentedContent)}>{innerContent}</div>
|
|
737
771
|
</div>
|
|
738
772
|
</div>
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @file GestureHost.ts
|
|
5
5
|
* @input DOM touch, pointer, click, contextmenu, scroll and focus events of
|
|
6
|
-
* one document; elements with recognizers and consumers attached
|
|
6
|
+
* one document; elements with recognizers and consumers attached; the
|
|
7
|
+
* input hold's held layers (Layer/inputHold `holdsTouch`)
|
|
7
8
|
* @output Exports GestureHost (the DOM side of the gesture system) and
|
|
8
9
|
* getGestureHost (one host per document)
|
|
9
10
|
* @position Browser adapter of packages/core/src/gestures: turns real events
|
|
@@ -149,6 +150,7 @@ import {
|
|
|
149
150
|
import {containsAlongFlatTree} from '../utils/flatTree';
|
|
150
151
|
import {isIosWebKit} from '../utils/touchQueries';
|
|
151
152
|
import {type WheelSegment, WheelSegmenter} from './wheelSegmenter';
|
|
153
|
+
import {holdsTouch} from '../Layer/inputHold';
|
|
152
154
|
import {
|
|
153
155
|
gestureHostStyle,
|
|
154
156
|
type GestureHostStyle,
|
|
@@ -2126,9 +2128,12 @@ export class GestureHost {
|
|
|
2126
2128
|
const recognizers: GestureRecognizer[] = [];
|
|
2127
2129
|
let consumer: TouchConsumer | null = null;
|
|
2128
2130
|
let consumerElement: Element | null = null;
|
|
2131
|
+
// A layer that the input hold holds takes no touch while it presents.
|
|
2132
|
+
// The host asks the hold, so the hold needs nothing from gestures/. A
|
|
2133
|
+
// root-entry component can then use the hold with no gesture code.
|
|
2129
2134
|
if (
|
|
2130
2135
|
target instanceof Node &&
|
|
2131
|
-
[...this.touchGates].some(gate => gate(target))
|
|
2136
|
+
(holdsTouch(target) || [...this.touchGates].some(gate => gate(target)))
|
|
2132
2137
|
) {
|
|
2133
2138
|
return {recognizers, consumer, consumerElement};
|
|
2134
2139
|
}
|
|
@@ -2287,17 +2292,20 @@ export class GestureHost {
|
|
|
2287
2292
|
};
|
|
2288
2293
|
this.wheel = gesture;
|
|
2289
2294
|
}
|
|
2290
|
-
|
|
2295
|
+
let {dx, dy} = wheelPixels(wheel, this.doc.defaultView);
|
|
2291
2296
|
const horizontal = Math.abs(dx) > Math.abs(dy);
|
|
2292
2297
|
// The splitter reads a pan's stream only. A ctrl-wheel pinch has no
|
|
2293
2298
|
// fingers' phase or momentum to tell apart, and ends 100 ms after its
|
|
2294
2299
|
// last wheel.
|
|
2295
2300
|
let seg: WheelSegment | null = null;
|
|
2296
2301
|
if (kind === 'pan') {
|
|
2302
|
+
// Only a trackpad's wheel can join its glide late; a mouse wheel's
|
|
2303
|
+
// notches keep the splitter's other rules.
|
|
2297
2304
|
seg = this.segmenter.push(
|
|
2298
2305
|
time,
|
|
2299
2306
|
horizontal ? dx : dy,
|
|
2300
2307
|
horizontal ? WHEEL_FOLLOW_END_MS : WHEEL_FOLLOW_END_V_MS,
|
|
2308
|
+
scrollTypeOf(wheel) === 'continuous',
|
|
2301
2309
|
);
|
|
2302
2310
|
} else {
|
|
2303
2311
|
this.segmenter.end();
|
|
@@ -2309,6 +2317,14 @@ export class GestureHost {
|
|
|
2309
2317
|
gesture = null;
|
|
2310
2318
|
}
|
|
2311
2319
|
}
|
|
2320
|
+
// A late wheel the glide took was the fingers' first when this one grows.
|
|
2321
|
+
if (seg != null && seg.carried !== 0) {
|
|
2322
|
+
if (horizontal) {
|
|
2323
|
+
dx += seg.carried;
|
|
2324
|
+
} else {
|
|
2325
|
+
dy += seg.carried;
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2312
2328
|
if (gesture == null) {
|
|
2313
2329
|
gesture = this.beginWheel(wheel, kind, dx, dy, time);
|
|
2314
2330
|
this.wheel = gesture;
|
|
@@ -2868,8 +2884,8 @@ export class GestureHost {
|
|
|
2868
2884
|
|
|
2869
2885
|
/**
|
|
2870
2886
|
* Hold touches away from every participant while `gate(target)` answers
|
|
2871
|
-
* true
|
|
2872
|
-
*
|
|
2887
|
+
* true. Returns the release. The input hold's held layers need no gate,
|
|
2888
|
+
* because the host asks `holdsTouch` for every touch.
|
|
2873
2889
|
*/
|
|
2874
2890
|
addTouchGate(gate: (target: Node) => boolean): () => void {
|
|
2875
2891
|
this.touchGates.add(gate);
|
package/src/gestures/README.md
CHANGED
|
@@ -434,11 +434,15 @@ subscriber cancels it: the host cancels `touchend` and `contextmenu` there
|
|
|
434
434
|
while a claiming participant is attached, never a `touchstart` or a
|
|
435
435
|
`touchmove`, and the click guard (`../utils/clickGuard.ts`) keeps a
|
|
436
436
|
cancelling `click` while it is armed, and from the menu press model's first
|
|
437
|
-
arm on. A
|
|
437
|
+
arm on. A layer's input hold (`../Layer/inputHold.ts`) cancels pointer and
|
|
438
|
+
mouse events, clicks, `touchmove` and `touchend` there while a layer is held,
|
|
439
|
+
never a `touchstart`. A blocking `touchmove` sits on a claiming
|
|
438
440
|
element and on a claimed touch's target, on the document while an element a
|
|
439
441
|
claiming recognizer lives in is moving (Touches on moving elements), or on
|
|
440
|
-
the window only while a page hold is held, so a page
|
|
441
|
-
no scroll.
|
|
442
|
+
the window only while a page hold or a layer's input hold is held, so a page
|
|
443
|
+
of pressables blocks no scroll. The stream records the type of the latest
|
|
444
|
+
pointer event it delivers (`getLastPointerType`); the input hold reads it as
|
|
445
|
+
a layer opens.
|
|
442
446
|
|
|
443
447
|
### Holding the page still
|
|
444
448
|
|
|
@@ -525,7 +529,11 @@ it never moves it; when the fingers carry on instead, their moves absorb
|
|
|
525
529
|
what the pan showed past their travel, or short of it, so it never steps
|
|
526
530
|
back and ends on their travel. Fingers that stop release still, once the end
|
|
527
531
|
time passes. In momentum, a reversal, a delta that grows
|
|
528
|
-
against the decay, or a 50 ms pause starts a new gesture
|
|
532
|
+
against the decay, or a 50 ms pause starts a new gesture; a late, coalesced
|
|
533
|
+
trackpad wheel that continues the glide's deceleration (at or below the next
|
|
534
|
+
step, or near the sum of the next steps its stall spans) belongs to the same
|
|
535
|
+
flick. When the next wheel grows instead, it starts a new gesture with the late
|
|
536
|
+
wheel's travel. A finger, mouse or
|
|
529
537
|
pen that comes down ends it, and a wheel claim keeps the page's text
|
|
530
538
|
selection. A gesture a
|
|
531
539
|
recognizer took is latched to it, as a browser latches a scroller: while it
|
|
@@ -31,33 +31,18 @@
|
|
|
31
31
|
import {isRtlElement} from '../hooks/isRtlElement';
|
|
32
32
|
import type {NativeScrollProbe} from './types';
|
|
33
33
|
import {parentAcrossShadow} from '../utils/flatTree';
|
|
34
|
+
import {
|
|
35
|
+
isInsideScrollView,
|
|
36
|
+
parseTouchAction,
|
|
37
|
+
rootOverflow,
|
|
38
|
+
SCROLLABLE_OVERFLOW as SCROLLABLE,
|
|
39
|
+
type AllowedPans,
|
|
40
|
+
} from '../utils/scrollView';
|
|
34
41
|
|
|
35
42
|
export {parentAcrossShadow};
|
|
36
43
|
|
|
37
|
-
export
|
|
38
|
-
|
|
39
|
-
readonly y: boolean;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Which pans a `touch-action` value lets the browser perform. */
|
|
43
|
-
export function parseTouchAction(value: string): AllowedPans {
|
|
44
|
-
const tokens = value.trim().split(/\s+/);
|
|
45
|
-
if (tokens.includes('auto') || tokens.includes('manipulation')) {
|
|
46
|
-
return {x: true, y: true};
|
|
47
|
-
}
|
|
48
|
-
if (tokens.includes('none')) {
|
|
49
|
-
return {x: false, y: false};
|
|
50
|
-
}
|
|
51
|
-
return {
|
|
52
|
-
x: tokens.some(
|
|
53
|
-
token =>
|
|
54
|
-
token === 'pan-x' || token === 'pan-left' || token === 'pan-right',
|
|
55
|
-
),
|
|
56
|
-
y: tokens.some(
|
|
57
|
-
token => token === 'pan-y' || token === 'pan-up' || token === 'pan-down',
|
|
58
|
-
),
|
|
59
|
-
};
|
|
60
|
-
}
|
|
44
|
+
export {parseTouchAction};
|
|
45
|
+
export type {AllowedPans};
|
|
61
46
|
|
|
62
47
|
interface ChainEntry {
|
|
63
48
|
readonly element: Element;
|
|
@@ -66,15 +51,8 @@ interface ChainEntry {
|
|
|
66
51
|
readonly isRtl: boolean;
|
|
67
52
|
readonly stopsX: boolean;
|
|
68
53
|
readonly stopsY: boolean;
|
|
69
|
-
/**
|
|
70
|
-
* The scroller sits beyond a `position: fixed` ancestor of the touch: it
|
|
71
|
-
* still scrolls under the finger, but it does not carry the touched
|
|
72
|
-
* element, so the element is not inside a scroll view (spec:AST-094 FR11).
|
|
73
|
-
*/
|
|
74
|
-
readonly isBeyondFixed: boolean;
|
|
75
54
|
}
|
|
76
55
|
|
|
77
|
-
const SCROLLABLE = new Set(['auto', 'scroll', 'overlay']);
|
|
78
56
|
const EDGE_TOLERANCE = 1;
|
|
79
57
|
|
|
80
58
|
interface Chain {
|
|
@@ -94,7 +72,6 @@ function buildChain(target: Element, readsTouchAction: boolean): Chain {
|
|
|
94
72
|
let allowX = true;
|
|
95
73
|
let allowY = true;
|
|
96
74
|
let reachedRoot = false;
|
|
97
|
-
let isBeyondFixed = false;
|
|
98
75
|
for (
|
|
99
76
|
let node: Node | null = target;
|
|
100
77
|
node != null;
|
|
@@ -128,15 +105,11 @@ function buildChain(target: Element, readsTouchAction: boolean): Chain {
|
|
|
128
105
|
isRtl: isRtlElement(element as HTMLElement),
|
|
129
106
|
stopsX: behaviorX !== 'auto',
|
|
130
107
|
stopsY: behaviorY !== 'auto',
|
|
131
|
-
isBeyondFixed,
|
|
132
108
|
});
|
|
133
109
|
}
|
|
134
110
|
if (isRoot) {
|
|
135
111
|
break;
|
|
136
112
|
}
|
|
137
|
-
if (style.position === 'fixed') {
|
|
138
|
-
isBeyondFixed = true;
|
|
139
|
-
}
|
|
140
113
|
}
|
|
141
114
|
if (!reachedRoot && root instanceof Element) {
|
|
142
115
|
chain.push({
|
|
@@ -146,7 +119,6 @@ function buildChain(target: Element, readsTouchAction: boolean): Chain {
|
|
|
146
119
|
isRtl: false,
|
|
147
120
|
stopsX: false,
|
|
148
121
|
stopsY: false,
|
|
149
|
-
isBeyondFixed,
|
|
150
122
|
});
|
|
151
123
|
}
|
|
152
124
|
return {entries: chain, allowsPan: allowX || allowY};
|
|
@@ -167,28 +139,6 @@ function overscrollBehavior(style: CSSStyleDeclaration): [string, string] {
|
|
|
167
139
|
return [x || first, y || second];
|
|
168
140
|
}
|
|
169
141
|
|
|
170
|
-
/**
|
|
171
|
-
* The viewport scrolls unless the root or the body clips it (a scroll lock
|
|
172
|
-
* sets `overflow: hidden` on one of them).
|
|
173
|
-
*/
|
|
174
|
-
function rootOverflow(doc: Document, axis: 'x' | 'y'): string {
|
|
175
|
-
const view = doc.defaultView;
|
|
176
|
-
if (view == null) {
|
|
177
|
-
return 'hidden';
|
|
178
|
-
}
|
|
179
|
-
for (const element of [doc.documentElement, doc.body]) {
|
|
180
|
-
if (element == null) {
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
const style = view.getComputedStyle(element);
|
|
184
|
-
const value = axis === 'x' ? style.overflowX : style.overflowY;
|
|
185
|
-
if (value === 'hidden' || value === 'clip') {
|
|
186
|
-
return 'hidden';
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return 'auto';
|
|
190
|
-
}
|
|
191
|
-
|
|
192
142
|
function canMoveY(element: Element, dy: number): boolean {
|
|
193
143
|
if (element.scrollHeight - element.clientHeight <= EDGE_TOLERANCE) {
|
|
194
144
|
return false;
|
|
@@ -288,15 +238,9 @@ export function createNativeScrollProbe(
|
|
|
288
238
|
return chain?.allowsPan === true;
|
|
289
239
|
},
|
|
290
240
|
get isInsideScroller(): boolean {
|
|
291
|
-
return
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
((entry.y &&
|
|
295
|
-
entry.element.scrollHeight - entry.element.clientHeight >
|
|
296
|
-
EDGE_TOLERANCE) ||
|
|
297
|
-
(entry.x &&
|
|
298
|
-
entry.element.scrollWidth - entry.element.clientWidth >
|
|
299
|
-
EDGE_TOLERANCE)),
|
|
241
|
+
return (
|
|
242
|
+
target instanceof Element &&
|
|
243
|
+
isInsideScrollView(target, {readsTouchAction})
|
|
300
244
|
);
|
|
301
245
|
},
|
|
302
246
|
};
|