@jobber/components 8.26.3 → 8.27.1
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/Select.d.ts +1 -0
- package/Select.js +17 -0
- package/dist/BottomSheet-cjs.js +8 -7
- package/dist/BottomSheet-es.js +9 -8
- package/dist/ComboboxChipRemove-cjs.js +2 -1
- package/dist/ComboboxChipRemove-es.js +4 -3
- package/dist/DrawerDescription-cjs.js +4 -97
- package/dist/DrawerDescription-es.js +6 -98
- package/dist/FieldDescription-cjs.js +880 -0
- package/dist/FieldDescription-es.js +856 -0
- package/dist/InputNumberExperimental-cjs.js +5 -875
- package/dist/InputNumberExperimental-es.js +2 -854
- package/dist/MenuSubmenuTrigger-es.js +4 -4
- package/dist/Modal/index.cjs +12 -2
- package/dist/Modal/index.mjs +13 -3
- package/dist/NumberFieldInput-cjs.js +2 -2
- package/dist/NumberFieldInput-es.js +1 -1
- package/dist/ScrollAreaViewport-cjs.js +2122 -12
- package/dist/ScrollAreaViewport-es.js +2118 -13
- package/dist/Select/Select.d.ts +31 -0
- package/dist/Select/Select.types.d.ts +145 -0
- package/dist/Select/SelectBottomSheet.d.ts +4 -0
- package/dist/Select/SelectDropdown.d.ts +4 -0
- package/dist/Select/index.cjs +41 -0
- package/dist/Select/index.d.ts +2 -0
- package/dist/Select/index.mjs +35 -0
- package/dist/Select-cjs.js +231 -0
- package/dist/Select-es.js +229 -0
- package/dist/SelectPrimitive-cjs.js +20 -3
- package/dist/SelectPrimitive-es.js +20 -3
- package/dist/dialogReturnFocus-cjs.js +8 -5
- package/dist/dialogReturnFocus-es.js +9 -6
- package/dist/docs/Dialog/Dialog.md +74 -21
- package/dist/docs/Select/Select.md +428 -0
- package/dist/docs/SelectPrimitive/SelectPrimitive.md +14 -1
- package/dist/docs/index.md +1 -0
- package/dist/floating-ui.react-dom-es.js +1 -1
- package/dist/floating-ui.react-es.js +1 -1
- package/dist/floating-ui.utils.dom-es.js +1 -1
- package/dist/index.cjs +9 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +8 -0
- package/dist/primitives/ComboboxPrimitive/index.cjs +1 -0
- package/dist/primitives/ComboboxPrimitive/index.mjs +1 -0
- package/dist/primitives/HelperText/HelperText.d.ts +2 -1
- package/dist/primitives/InputNumberExperimental/index.cjs +3 -1
- package/dist/primitives/InputNumberExperimental/index.mjs +3 -1
- package/dist/primitives/SelectPrimitive/SelectPrimitive.d.ts +11 -0
- package/dist/primitives/SelectPrimitive/index.d.ts +1 -1
- package/dist/primitives/SelectPrimitive/types.d.ts +15 -0
- package/dist/primitives/index.cjs +2 -0
- package/dist/primitives/index.mjs +2 -0
- package/dist/stringifyLocale-cjs.js +13 -0
- package/dist/stringifyLocale-es.js +11 -0
- package/dist/styles.css +300 -10
- package/dist/unstyledPrimitives/index.cjs +219 -2230
- package/dist/unstyledPrimitives/index.mjs +225 -2236
- package/dist/useButton-es.js +2 -2
- package/dist/useCompositeListItem-es.js +1 -1
- package/dist/useLabel-cjs.js +0 -11
- package/dist/useLabel-es.js +2 -12
- package/dist/useScrollLock-es.js +3 -3
- package/dist/utils/meta/meta.json +5 -0
- package/package.json +7 -2
|
@@ -10,18 +10,19 @@ var DrawerDescription = require('../DrawerDescription-cjs.js');
|
|
|
10
10
|
var DrawerTitle = require('../DrawerTitle-cjs.js');
|
|
11
11
|
var ScrollAreaViewport = require('../ScrollAreaViewport-cjs.js');
|
|
12
12
|
var useRenderElement = require('../useRenderElement-cjs.js');
|
|
13
|
+
var useScrollLock = require('../useScrollLock-cjs.js');
|
|
13
14
|
var floatingUi_utils_dom = require('../floating-ui.utils.dom-cjs.js');
|
|
14
15
|
var clamp = require('../clamp-cjs.js');
|
|
15
|
-
var useScrollLock = require('../useScrollLock-cjs.js');
|
|
16
|
-
var ReactDOM = require('react-dom');
|
|
17
16
|
var MenuSubmenuTrigger = require('../MenuSubmenuTrigger-cjs.js');
|
|
18
17
|
var useCompositeListItem = require('../useCompositeListItem-cjs.js');
|
|
18
|
+
var ReactDOM = require('react-dom');
|
|
19
19
|
var SelectGroupLabel = require('../SelectGroupLabel-cjs.js');
|
|
20
20
|
var floatingUi_utils = require('../floating-ui.utils-cjs.js');
|
|
21
21
|
var NumberFieldInput = require('../NumberFieldInput-cjs.js');
|
|
22
22
|
var useLabelableId = require('../useLabelableId-cjs.js');
|
|
23
23
|
var useLabel = require('../useLabel-cjs.js');
|
|
24
24
|
var scrollEdges = require('../scrollEdges-cjs.js');
|
|
25
|
+
require('../stringifyLocale-cjs.js');
|
|
25
26
|
require('../isElementDisabled-cjs.js');
|
|
26
27
|
require('../floating-ui.react-dom-cjs.js');
|
|
27
28
|
|
|
@@ -216,7 +217,7 @@ var index_parts$6 = /*#__PURE__*/Object.freeze({
|
|
|
216
217
|
Root: ScrollAreaViewport.DialogRoot,
|
|
217
218
|
Title: DrawerTitle.DialogTitle,
|
|
218
219
|
Trigger: ScrollAreaViewport.DialogTrigger,
|
|
219
|
-
Viewport:
|
|
220
|
+
Viewport: ScrollAreaViewport.DialogViewport,
|
|
220
221
|
createHandle: DrawerDescription.createDialogHandle
|
|
221
222
|
});
|
|
222
223
|
|
|
@@ -419,1198 +420,188 @@ function createVisualStateStore() {
|
|
|
419
420
|
};
|
|
420
421
|
}
|
|
421
422
|
|
|
422
|
-
function
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
if (isScrollable(node, axis)) {
|
|
447
|
-
return true;
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
node = floatingUi_utils_dom.getParentNode(node);
|
|
451
|
-
}
|
|
452
|
-
return false;
|
|
453
|
-
}
|
|
454
|
-
function findScrollableTouchTarget(target, root, axis = 'vertical', allowOverflowIntent = false) {
|
|
455
|
-
// `getParentNode` crosses shadow boundaries (and slots), so a target inside a shadow root
|
|
456
|
-
// still reaches a scrollable ancestor in the light DOM.
|
|
457
|
-
let node = floatingUi_utils_dom.isHTMLElement(target) ? target : null;
|
|
458
|
-
while (floatingUi_utils_dom.isHTMLElement(node) && node !== root && !floatingUi_utils_dom.isLastTraversableNode(node)) {
|
|
459
|
-
if (isScrollable(node, axis, allowOverflowIntent)) {
|
|
460
|
-
return node;
|
|
461
|
-
}
|
|
462
|
-
node = floatingUi_utils_dom.getParentNode(node);
|
|
463
|
-
}
|
|
464
|
-
return isScrollable(root, axis, allowOverflowIntent) ? root : null;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
function getElementAtPoint(doc, x, y) {
|
|
468
|
-
return typeof doc?.elementFromPoint === 'function' ? doc.elementFromPoint(x, y) : null;
|
|
469
|
-
}
|
|
423
|
+
let DrawerSwipeAreaDataAttributes = function (DrawerSwipeAreaDataAttributes) {
|
|
424
|
+
/**
|
|
425
|
+
* Present when the drawer is open.
|
|
426
|
+
*/
|
|
427
|
+
DrawerSwipeAreaDataAttributes[DrawerSwipeAreaDataAttributes["open"] = useScrollLock.CommonPopupDataAttributes.open] = "open";
|
|
428
|
+
/**
|
|
429
|
+
* Present when the drawer is closed.
|
|
430
|
+
*/
|
|
431
|
+
DrawerSwipeAreaDataAttributes[DrawerSwipeAreaDataAttributes["closed"] = useScrollLock.CommonPopupDataAttributes.closed] = "closed";
|
|
432
|
+
/**
|
|
433
|
+
* Present when the swipe area is disabled.
|
|
434
|
+
*/
|
|
435
|
+
DrawerSwipeAreaDataAttributes["disabled"] = "data-disabled";
|
|
436
|
+
/**
|
|
437
|
+
* Indicates the swipe direction.
|
|
438
|
+
* @type {'up' | 'down' | 'left' | 'right'}
|
|
439
|
+
*/
|
|
440
|
+
DrawerSwipeAreaDataAttributes["swipeDirection"] = "data-swipe-direction";
|
|
441
|
+
/**
|
|
442
|
+
* Present when the drawer is being swiped.
|
|
443
|
+
*/
|
|
444
|
+
DrawerSwipeAreaDataAttributes["swiping"] = "data-swiping";
|
|
445
|
+
return DrawerSwipeAreaDataAttributes;
|
|
446
|
+
}({});
|
|
470
447
|
|
|
471
|
-
const
|
|
472
|
-
const
|
|
473
|
-
const
|
|
474
|
-
const
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
const values = matrix[1].split(', ').map(parseFloat);
|
|
502
|
-
if (values.length === 6) {
|
|
503
|
-
translateX = values[4];
|
|
504
|
-
translateY = values[5];
|
|
505
|
-
scale = Math.sqrt(values[0] * values[0] + values[1] * values[1]);
|
|
506
|
-
} else if (values.length === 16) {
|
|
507
|
-
translateX = values[12];
|
|
508
|
-
translateY = values[13];
|
|
509
|
-
scale = values[0];
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
return {
|
|
514
|
-
x: translateX,
|
|
515
|
-
y: translateY,
|
|
516
|
-
scale
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
function getValidTimeStamp(timeStamp) {
|
|
520
|
-
return Number.isFinite(timeStamp) && timeStamp > 0 ? timeStamp : null;
|
|
521
|
-
}
|
|
522
|
-
function getDragTransform(dragOffset, scale) {
|
|
523
|
-
return `translate3d(${dragOffset.x}px,${dragOffset.y}px,0) scale(${scale})`;
|
|
524
|
-
}
|
|
525
|
-
function hasPrimaryMouseButton(buttons) {
|
|
526
|
-
return buttons % 2 === 1;
|
|
527
|
-
}
|
|
528
|
-
function safelyChangePointerCapture(element, pointerId, method) {
|
|
529
|
-
const pointerCaptureMethod = element[method];
|
|
530
|
-
if (typeof pointerCaptureMethod !== 'function') {
|
|
531
|
-
return;
|
|
532
|
-
}
|
|
533
|
-
try {
|
|
534
|
-
pointerCaptureMethod.call(element, pointerId);
|
|
535
|
-
} catch (error) {
|
|
536
|
-
if (error && typeof error === 'object' && 'name' in error && error.name === 'NotFoundError') {
|
|
537
|
-
return;
|
|
538
|
-
}
|
|
539
|
-
throw error;
|
|
448
|
+
const DEFAULT_SWIPE_OPEN_RATIO = 0.5;
|
|
449
|
+
const MIN_SWIPE_START_DISTANCE = 1;
|
|
450
|
+
const VELOCITY_THRESHOLD = 0.1;
|
|
451
|
+
const FALLBACK_SWIPE_OPEN_THRESHOLD = 40;
|
|
452
|
+
const SWIPE_AREA_OPEN_HOOK = {
|
|
453
|
+
[DrawerSwipeAreaDataAttributes.open]: ''
|
|
454
|
+
};
|
|
455
|
+
const SWIPE_AREA_CLOSED_HOOK = {
|
|
456
|
+
[DrawerSwipeAreaDataAttributes.closed]: ''
|
|
457
|
+
};
|
|
458
|
+
const SWIPE_AREA_SWIPING_HOOK = {
|
|
459
|
+
[DrawerSwipeAreaDataAttributes.swiping]: ''
|
|
460
|
+
};
|
|
461
|
+
const SWIPE_AREA_DISABLED_HOOK = {
|
|
462
|
+
[DrawerSwipeAreaDataAttributes.disabled]: ''
|
|
463
|
+
};
|
|
464
|
+
const stateAttributesMapping$3 = {
|
|
465
|
+
open(value) {
|
|
466
|
+
return value ? SWIPE_AREA_OPEN_HOOK : SWIPE_AREA_CLOSED_HOOK;
|
|
467
|
+
},
|
|
468
|
+
swiping(value) {
|
|
469
|
+
return value ? SWIPE_AREA_SWIPING_HOOK : null;
|
|
470
|
+
},
|
|
471
|
+
swipeDirection(value) {
|
|
472
|
+
return value ? {
|
|
473
|
+
[DrawerSwipeAreaDataAttributes.swipeDirection]: value
|
|
474
|
+
} : null;
|
|
475
|
+
},
|
|
476
|
+
disabled(value) {
|
|
477
|
+
return value ? SWIPE_AREA_DISABLED_HOOK : null;
|
|
540
478
|
}
|
|
479
|
+
};
|
|
480
|
+
const oppositeSwipeDirection = {
|
|
481
|
+
up: 'down',
|
|
482
|
+
down: 'up',
|
|
483
|
+
left: 'right',
|
|
484
|
+
right: 'left'
|
|
485
|
+
};
|
|
486
|
+
function resolveTouchAction(direction) {
|
|
487
|
+
return direction === 'left' || direction === 'right' ? 'pan-y' : 'pan-x';
|
|
541
488
|
}
|
|
542
|
-
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* An invisible area that listens for swipe gestures to open the drawer.
|
|
492
|
+
* Renders a `<div>` element.
|
|
493
|
+
*
|
|
494
|
+
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
495
|
+
*/
|
|
496
|
+
const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function DrawerSwipeArea(componentProps, forwardedRef) {
|
|
543
497
|
const {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const
|
|
561
|
-
const
|
|
562
|
-
const
|
|
563
|
-
const
|
|
564
|
-
const
|
|
565
|
-
const allowUp = directions.includes('up');
|
|
566
|
-
const allowDown = directions.includes('down');
|
|
567
|
-
const hasHorizontal = allowLeft || allowRight;
|
|
568
|
-
const hasVertical = allowUp || allowDown;
|
|
569
|
-
const scrollAxes = React__namespace.useMemo(() => {
|
|
570
|
-
const axes = [];
|
|
571
|
-
if (hasVertical) {
|
|
572
|
-
axes.push('vertical');
|
|
573
|
-
}
|
|
574
|
-
if (hasHorizontal) {
|
|
575
|
-
axes.push('horizontal');
|
|
576
|
-
}
|
|
577
|
-
return axes;
|
|
578
|
-
}, [hasHorizontal, hasVertical]);
|
|
579
|
-
const [currentSwipeDirection, setCurrentSwipeDirection] = React__namespace.useState(undefined);
|
|
580
|
-
const [isSwiping, setIsSwiping] = React__namespace.useState(false);
|
|
581
|
-
const [dragDismissed, setDragDismissed] = React__namespace.useState(false);
|
|
582
|
-
const dragStartPosRef = React__namespace.useRef({
|
|
583
|
-
x: 0,
|
|
584
|
-
y: 0
|
|
585
|
-
});
|
|
586
|
-
const dragOffsetRef = React__namespace.useRef({
|
|
587
|
-
x: 0,
|
|
588
|
-
y: 0
|
|
589
|
-
});
|
|
590
|
-
const lastMovePosRef = React__namespace.useRef(null);
|
|
591
|
-
const initialTransformRef = React__namespace.useRef({
|
|
592
|
-
x: 0,
|
|
593
|
-
y: 0,
|
|
594
|
-
scale: 1
|
|
595
|
-
});
|
|
596
|
-
const intendedSwipeDirectionRef = React__namespace.useRef(undefined);
|
|
597
|
-
const maxSwipeDisplacementRef = React__namespace.useRef(0);
|
|
598
|
-
const cancelledSwipeRef = React__namespace.useRef(false);
|
|
599
|
-
const swipeCancelBaselineRef = React__namespace.useRef({
|
|
600
|
-
x: 0,
|
|
601
|
-
y: 0
|
|
602
|
-
});
|
|
603
|
-
const lockedDirectionRef = React__namespace.useRef(null);
|
|
604
|
-
const isFirstPointerMoveRef = React__namespace.useRef(false);
|
|
605
|
-
const pendingSwipeRef = React__namespace.useRef(false);
|
|
606
|
-
const pendingSwipeStartPosRef = React__namespace.useRef(null);
|
|
607
|
-
const swipeFromScrollableRef = React__namespace.useRef(false);
|
|
608
|
-
const sawPrimaryButtonsOnMoveRef = React__namespace.useRef(false);
|
|
609
|
-
const elementSizeRef = React__namespace.useRef({
|
|
610
|
-
width: 0,
|
|
611
|
-
height: 0
|
|
612
|
-
});
|
|
613
|
-
const swipeProgressRef = React__namespace.useRef(0);
|
|
614
|
-
const swipeThresholdRef = React__namespace.useRef(swipeThresholdDefault);
|
|
615
|
-
const swipeStartTimeRef = React__namespace.useRef(null);
|
|
616
|
-
const lastDragSampleRef = React__namespace.useRef(null);
|
|
617
|
-
const lastDragVelocityRef = React__namespace.useRef({
|
|
498
|
+
render,
|
|
499
|
+
className,
|
|
500
|
+
style,
|
|
501
|
+
disabled = false,
|
|
502
|
+
swipeDirection: swipeDirectionProp,
|
|
503
|
+
...elementProps
|
|
504
|
+
} = componentProps;
|
|
505
|
+
const {
|
|
506
|
+
store
|
|
507
|
+
} = ScrollAreaViewport.useDialogRootContext();
|
|
508
|
+
const {
|
|
509
|
+
swipeDirection,
|
|
510
|
+
frontmostHeight
|
|
511
|
+
} = ScrollAreaViewport.useDrawerRootContext();
|
|
512
|
+
const providerContext = ScrollAreaViewport.useDrawerProviderContext();
|
|
513
|
+
const [swipeActive, setSwipeActive] = React__namespace.useState(false);
|
|
514
|
+
const releaseDismissTimeout = useButton.useTimeout();
|
|
515
|
+
const swipeAreaRef = React__namespace.useRef(null);
|
|
516
|
+
const swipeStartEventRef = React__namespace.useRef(null);
|
|
517
|
+
const openedBySwipeRef = React__namespace.useRef(false);
|
|
518
|
+
const dragDeltaRef = React__namespace.useRef({
|
|
618
519
|
x: 0,
|
|
619
520
|
y: 0
|
|
620
521
|
});
|
|
621
|
-
const
|
|
622
|
-
const
|
|
623
|
-
const
|
|
624
|
-
const
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
onSwipingChange?.(nextSwiping);
|
|
522
|
+
const closedOffsetRef = React__namespace.useRef(null);
|
|
523
|
+
const appliedSwipeStylesRef = React__namespace.useRef(false);
|
|
524
|
+
const popupTransitionRef = React__namespace.useRef(null);
|
|
525
|
+
const swipeAreaId = useButton.useBaseUiId(componentProps.id);
|
|
526
|
+
const registerTrigger = useScrollLock.useTriggerRegistration(swipeAreaId, store);
|
|
527
|
+
const open = store.useState('open');
|
|
528
|
+
const resetDragDelta = useButton.useStableCallback(() => {
|
|
529
|
+
dragDeltaRef.current.x = 0;
|
|
530
|
+
dragDeltaRef.current.y = 0;
|
|
631
531
|
});
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
const value = swipeThresholdProp({
|
|
645
|
-
element,
|
|
646
|
-
direction
|
|
532
|
+
const resolvedSwipeDirection = swipeDirectionProp ?? oppositeSwipeDirection[swipeDirection];
|
|
533
|
+
const dismissDirection = oppositeSwipeDirection[resolvedSwipeDirection];
|
|
534
|
+
const enabled = !disabled && (!open || swipeActive);
|
|
535
|
+
function disableDismissForSwipe() {
|
|
536
|
+
releaseDismissTimeout.clear();
|
|
537
|
+
store.context.outsidePressEnabledRef.current = false;
|
|
538
|
+
}
|
|
539
|
+
function enableDismissAfterRelease() {
|
|
540
|
+
// Safari can dispatch outside-press for the same swipe-open gesture
|
|
541
|
+
// after release, so defer re-enabling dismissal to the next macrotask.
|
|
542
|
+
releaseDismissTimeout.start(0, () => {
|
|
543
|
+
store.context.outsidePressEnabledRef.current = true;
|
|
647
544
|
});
|
|
648
|
-
swipeThresholdRef.current = Math.max(0, value);
|
|
649
545
|
}
|
|
650
|
-
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
if (details) {
|
|
655
|
-
const lastDetails = lastProgressDetailsRef.current;
|
|
656
|
-
detailsChanged = !lastDetails || lastDetails.deltaX !== details.deltaX || lastDetails.deltaY !== details.deltaY || lastDetails.direction !== details.direction;
|
|
657
|
-
}
|
|
658
|
-
if (!progressChanged && !detailsChanged) {
|
|
659
|
-
return;
|
|
660
|
-
}
|
|
661
|
-
swipeProgressRef.current = nextProgress;
|
|
662
|
-
if (details) {
|
|
663
|
-
lastProgressDetailsRef.current = details;
|
|
664
|
-
} else if (progressChanged) {
|
|
665
|
-
lastProgressDetailsRef.current = null;
|
|
666
|
-
}
|
|
667
|
-
onProgress?.(nextProgress, details);
|
|
668
|
-
});
|
|
669
|
-
const syncDragStyles = useButton.useStableCallback(swiping => {
|
|
670
|
-
const element = elementRef.current;
|
|
671
|
-
if (!trackDrag || !element) {
|
|
672
|
-
if (!swiping) {
|
|
673
|
-
dragStyleSnapshotRef.current = null;
|
|
674
|
-
}
|
|
675
|
-
return;
|
|
676
|
-
}
|
|
677
|
-
const style = element.style;
|
|
678
|
-
const dragStyleSnapshot = dragStyleSnapshotRef.current;
|
|
679
|
-
if (swiping) {
|
|
680
|
-
if (!dragStyleSnapshot) {
|
|
681
|
-
dragStyleSnapshotRef.current = [style.transition, style.transform];
|
|
682
|
-
}
|
|
683
|
-
style.transition = 'none';
|
|
684
|
-
} else if (dragStyleSnapshot) {
|
|
685
|
-
[style.transition, style.transform] = dragStyleSnapshot;
|
|
686
|
-
dragStyleSnapshotRef.current = null;
|
|
687
|
-
}
|
|
688
|
-
const dragOffset = dragOffsetRef.current;
|
|
689
|
-
const initialTransform = initialTransformRef.current;
|
|
690
|
-
const deltaX = dragOffset.x - initialTransform.x;
|
|
691
|
-
const deltaY = dragOffset.y - initialTransform.y;
|
|
692
|
-
if (swiping) {
|
|
693
|
-
style.transform = getDragTransform(dragOffset, initialTransform.scale);
|
|
694
|
-
}
|
|
695
|
-
style.setProperty(movementCssVars.x, `${deltaX}px`);
|
|
696
|
-
style.setProperty(movementCssVars.y, `${deltaY}px`);
|
|
697
|
-
});
|
|
698
|
-
function recordDragSample(offset, timeStamp) {
|
|
699
|
-
if (timeStamp === null) {
|
|
700
|
-
return;
|
|
546
|
+
function resolvePopupSize() {
|
|
547
|
+
const popupElement = store.context.popupRef.current;
|
|
548
|
+
if (!popupElement) {
|
|
549
|
+
return null;
|
|
701
550
|
}
|
|
702
|
-
const
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
x: (offset.x - lastSample.x) / durationMs,
|
|
707
|
-
y: (offset.y - lastSample.y) / durationMs
|
|
708
|
-
};
|
|
551
|
+
const isHorizontal = dismissDirection === 'left' || dismissDirection === 'right';
|
|
552
|
+
const size = isHorizontal ? popupElement.offsetWidth : popupElement.offsetHeight;
|
|
553
|
+
if (size <= 0) {
|
|
554
|
+
return null;
|
|
709
555
|
}
|
|
710
|
-
|
|
711
|
-
x: offset.x,
|
|
712
|
-
y: offset.y,
|
|
713
|
-
time: timeStamp
|
|
714
|
-
};
|
|
556
|
+
return size;
|
|
715
557
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
updateSwipeProgress(0);
|
|
721
|
-
swipeThresholdRef.current = swipeThresholdDefault;
|
|
722
|
-
dragStartPosRef.current = {
|
|
723
|
-
x: 0,
|
|
724
|
-
y: 0
|
|
725
|
-
};
|
|
726
|
-
dragOffsetRef.current = {
|
|
727
|
-
x: 0,
|
|
728
|
-
y: 0
|
|
729
|
-
};
|
|
730
|
-
initialTransformRef.current = {
|
|
731
|
-
x: 0,
|
|
732
|
-
y: 0,
|
|
733
|
-
scale: 1
|
|
734
|
-
};
|
|
735
|
-
intendedSwipeDirectionRef.current = undefined;
|
|
736
|
-
maxSwipeDisplacementRef.current = 0;
|
|
737
|
-
cancelledSwipeRef.current = false;
|
|
738
|
-
swipeCancelBaselineRef.current = {
|
|
739
|
-
x: 0,
|
|
740
|
-
y: 0
|
|
741
|
-
};
|
|
742
|
-
lockedDirectionRef.current = null;
|
|
743
|
-
isFirstPointerMoveRef.current = false;
|
|
744
|
-
lastMovePosRef.current = null;
|
|
745
|
-
pendingSwipeRef.current = false;
|
|
746
|
-
pendingSwipeStartPosRef.current = null;
|
|
747
|
-
swipeFromScrollableRef.current = false;
|
|
748
|
-
sawPrimaryButtonsOnMoveRef.current = false;
|
|
749
|
-
elementSizeRef.current = {
|
|
750
|
-
width: 0,
|
|
751
|
-
height: 0
|
|
752
|
-
};
|
|
753
|
-
swipeStartTimeRef.current = null;
|
|
754
|
-
lastDragSampleRef.current = null;
|
|
755
|
-
lastDragVelocityRef.current = {
|
|
756
|
-
x: 0,
|
|
757
|
-
y: 0
|
|
758
|
-
};
|
|
759
|
-
lastProgressDetailsRef.current = null;
|
|
760
|
-
syncDragStyles(false);
|
|
761
|
-
}, [setSwiping, swipeThresholdDefault, syncDragStyles, updateSwipeProgress]);
|
|
762
|
-
React__namespace.useEffect(() => {
|
|
763
|
-
if (typeof swipeThresholdProp !== 'function') {
|
|
764
|
-
swipeThresholdRef.current = swipeThresholdDefault;
|
|
558
|
+
function resolveClosedOffset() {
|
|
559
|
+
const offset = resolvePopupSize();
|
|
560
|
+
if (offset == null) {
|
|
561
|
+
return null;
|
|
765
562
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
const touch = event.touches[0];
|
|
770
|
-
return touch ? {
|
|
771
|
-
x: touch.clientX,
|
|
772
|
-
y: touch.clientY
|
|
773
|
-
} : null;
|
|
563
|
+
const popupElement = store.context.popupRef.current;
|
|
564
|
+
if (!popupElement) {
|
|
565
|
+
return offset;
|
|
774
566
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
function isTouchLikeEvent(event) {
|
|
781
|
-
if ('touches' in event) {
|
|
782
|
-
return true;
|
|
567
|
+
const isHorizontal = dismissDirection === 'left' || dismissDirection === 'right';
|
|
568
|
+
const transform = ScrollAreaViewport.getElementTransform(popupElement);
|
|
569
|
+
const transformOffset = isHorizontal ? transform.x : transform.y;
|
|
570
|
+
if (Number.isFinite(transformOffset) && Math.abs(transformOffset) > 0.5) {
|
|
571
|
+
return Math.min(offset, Math.abs(transformOffset));
|
|
783
572
|
}
|
|
784
|
-
return
|
|
785
|
-
}
|
|
786
|
-
function getTargetAtPoint(position, nativeEvent) {
|
|
787
|
-
const doc = useButton.ownerDocument(elementRef.current);
|
|
788
|
-
const elementAtPoint = getElementAtPoint(doc, position.x, position.y);
|
|
789
|
-
const target = elementAtPoint ?? useButton.getTarget(nativeEvent);
|
|
790
|
-
return target;
|
|
573
|
+
return offset;
|
|
791
574
|
}
|
|
792
|
-
function
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
if (hasVertical && !hasHorizontal) {
|
|
797
|
-
return findScrollableTouchTarget(target, root, 'vertical');
|
|
575
|
+
function resolveSwipeOpenThreshold() {
|
|
576
|
+
const popupSize = resolvePopupSize();
|
|
577
|
+
if (popupSize == null) {
|
|
578
|
+
return FALLBACK_SWIPE_OPEN_THRESHOLD;
|
|
798
579
|
}
|
|
799
|
-
return
|
|
580
|
+
return popupSize * DEFAULT_SWIPE_OPEN_RATIO;
|
|
800
581
|
}
|
|
801
|
-
function
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
const target = getTargetAtPoint(position, event.nativeEvent);
|
|
805
|
-
const doc = useButton.ownerDocument(elementRef.current);
|
|
806
|
-
const body = doc.body;
|
|
807
|
-
const scrollableTarget = touchLike && body ? findGestureScrollableTouchTarget(target, body) : null;
|
|
808
|
-
const ignoreScrollableTarget = startOptions?.ignoreScrollableTarget ?? false;
|
|
809
|
-
if (scrollableTarget && !ignoreScrollableTarget) {
|
|
810
|
-
return false;
|
|
582
|
+
function applySwipeMovement() {
|
|
583
|
+
if (!swipeActive) {
|
|
584
|
+
return;
|
|
811
585
|
}
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
return false;
|
|
586
|
+
const popupElement = store.context.popupRef.current;
|
|
587
|
+
if (!popupElement) {
|
|
588
|
+
return;
|
|
816
589
|
}
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
const ignoreAncestors = startOptions?.ignoreScrollableAncestors ?? false;
|
|
820
|
-
if (!ignoreAncestors && hasScrollableAncestor(target, element, scrollAxes)) {
|
|
821
|
-
return false;
|
|
822
|
-
}
|
|
590
|
+
if (!store.select('open') || !store.select('mounted')) {
|
|
591
|
+
return;
|
|
823
592
|
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
maxSwipeDisplacementRef.current = 0;
|
|
827
|
-
dragStartPosRef.current = position;
|
|
828
|
-
swipeStartTimeRef.current = getValidTimeStamp(event.timeStamp);
|
|
829
|
-
swipeCancelBaselineRef.current = position;
|
|
830
|
-
lastMovePosRef.current = position;
|
|
831
|
-
if (element) {
|
|
832
|
-
elementSizeRef.current = {
|
|
833
|
-
width: element.offsetWidth,
|
|
834
|
-
height: element.offsetHeight
|
|
835
|
-
};
|
|
836
|
-
resolveSwipeThreshold(primaryDirection);
|
|
837
|
-
const transform = getElementTransform(element);
|
|
838
|
-
initialTransformRef.current = transform;
|
|
839
|
-
dragOffsetRef.current = {
|
|
840
|
-
x: transform.x,
|
|
841
|
-
y: transform.y
|
|
842
|
-
};
|
|
843
|
-
recordDragSample({
|
|
844
|
-
x: transform.x,
|
|
845
|
-
y: transform.y
|
|
846
|
-
}, swipeStartTimeRef.current);
|
|
847
|
-
if (!('touches' in event)) {
|
|
848
|
-
safelyChangePointerCapture(element, event.pointerId, 'setPointerCapture');
|
|
849
|
-
}
|
|
593
|
+
if (closedOffsetRef.current == null) {
|
|
594
|
+
closedOffsetRef.current = resolveClosedOffset();
|
|
850
595
|
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
lockedDirectionRef.current = null;
|
|
854
|
-
isFirstPointerMoveRef.current = true;
|
|
855
|
-
updateSwipeProgress(0);
|
|
856
|
-
syncDragStyles(true);
|
|
857
|
-
return true;
|
|
858
|
-
}
|
|
859
|
-
function resetPendingSwipeState() {
|
|
860
|
-
clearPendingSwipeStartState();
|
|
861
|
-
swipeFromScrollableRef.current = false;
|
|
862
|
-
lastMovePosRef.current = null;
|
|
863
|
-
}
|
|
864
|
-
function clearPendingSwipeStartState() {
|
|
865
|
-
pendingSwipeRef.current = false;
|
|
866
|
-
pendingSwipeStartPosRef.current = null;
|
|
867
|
-
}
|
|
868
|
-
function cancelSwipeInteraction(event) {
|
|
869
|
-
resetPendingSwipeState();
|
|
870
|
-
if (!isSwipingRef.current) {
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
setSwiping(false);
|
|
874
|
-
lockedDirectionRef.current = null;
|
|
875
|
-
const resolvedInitialTransform = initialTransformRef.current;
|
|
876
|
-
dragOffsetRef.current = {
|
|
877
|
-
x: resolvedInitialTransform.x,
|
|
878
|
-
y: resolvedInitialTransform.y
|
|
879
|
-
};
|
|
880
|
-
setCurrentSwipeDirection(undefined);
|
|
881
|
-
sawPrimaryButtonsOnMoveRef.current = false;
|
|
882
|
-
syncDragStyles(false);
|
|
883
|
-
const element = elementRef.current;
|
|
884
|
-
if (element) {
|
|
885
|
-
safelyChangePointerCapture(element, event.pointerId, 'releasePointerCapture');
|
|
886
|
-
}
|
|
887
|
-
updateSwipeProgress(0, {
|
|
888
|
-
deltaX: 0,
|
|
889
|
-
deltaY: 0,
|
|
890
|
-
direction: undefined
|
|
891
|
-
});
|
|
892
|
-
onCancel?.(event.nativeEvent);
|
|
893
|
-
}
|
|
894
|
-
function applyDirectionalDamping(deltaX, deltaY) {
|
|
895
|
-
const exponent = value => value >= 0 ? value ** 0.5 : -(Math.abs(value) ** 0.5);
|
|
896
|
-
const dampAxis = (delta, allowNegative, allowPositive) => {
|
|
897
|
-
if (!allowNegative && delta < 0) {
|
|
898
|
-
return exponent(delta);
|
|
899
|
-
}
|
|
900
|
-
if (!allowPositive && delta > 0) {
|
|
901
|
-
return exponent(delta);
|
|
902
|
-
}
|
|
903
|
-
return delta;
|
|
904
|
-
};
|
|
905
|
-
const newDeltaX = hasHorizontal ? dampAxis(deltaX, allowLeft, allowRight) : exponent(deltaX);
|
|
906
|
-
const newDeltaY = hasVertical ? dampAxis(deltaY, allowUp, allowDown) : exponent(deltaY);
|
|
907
|
-
return {
|
|
908
|
-
x: newDeltaX,
|
|
909
|
-
y: newDeltaY
|
|
910
|
-
};
|
|
911
|
-
}
|
|
912
|
-
function canSwipeFromScrollEdgeOnPendingMove(scrollTarget, deltaX, deltaY) {
|
|
913
|
-
const absDeltaX = Math.abs(deltaX);
|
|
914
|
-
const absDeltaY = Math.abs(deltaY);
|
|
915
|
-
const useVerticalAxis = hasVertical && deltaY !== 0 && (!hasHorizontal || absDeltaY >= absDeltaX);
|
|
916
|
-
if (useVerticalAxis) {
|
|
917
|
-
const maxScrollTop = Math.max(0, scrollTarget.scrollHeight - scrollTarget.clientHeight);
|
|
918
|
-
const atTop = scrollTarget.scrollTop <= 0;
|
|
919
|
-
const atBottom = scrollTarget.scrollTop >= maxScrollTop;
|
|
920
|
-
const movingDown = deltaY > 0;
|
|
921
|
-
const movingUp = deltaY < 0;
|
|
922
|
-
const canSwipeDown = movingDown && atTop && allowDown;
|
|
923
|
-
const canSwipeUp = movingUp && atBottom && allowUp;
|
|
924
|
-
return canSwipeDown || canSwipeUp;
|
|
925
|
-
}
|
|
926
|
-
const useHorizontalAxis = hasHorizontal && deltaX !== 0 && (!hasVertical || absDeltaX > absDeltaY);
|
|
927
|
-
if (useHorizontalAxis) {
|
|
928
|
-
const maxScrollLeft = Math.max(0, scrollTarget.scrollWidth - scrollTarget.clientWidth);
|
|
929
|
-
const atLeft = scrollTarget.scrollLeft <= 0;
|
|
930
|
-
const atRight = scrollTarget.scrollLeft >= maxScrollLeft;
|
|
931
|
-
const movingRight = deltaX > 0;
|
|
932
|
-
const movingLeft = deltaX < 0;
|
|
933
|
-
const canSwipeRight = movingRight && atLeft && allowRight;
|
|
934
|
-
const canSwipeLeft = movingLeft && atRight && allowLeft;
|
|
935
|
-
return canSwipeRight || canSwipeLeft;
|
|
936
|
-
}
|
|
937
|
-
return null;
|
|
938
|
-
}
|
|
939
|
-
const handleStart = useButton.useStableCallback(event => {
|
|
940
|
-
if (!enabled) {
|
|
941
|
-
return;
|
|
942
|
-
}
|
|
943
|
-
if (event.defaultPrevented || event.nativeEvent.defaultPrevented) {
|
|
944
|
-
return;
|
|
945
|
-
}
|
|
946
|
-
if (!('touches' in event) && event.button !== 0) {
|
|
947
|
-
return;
|
|
948
|
-
}
|
|
949
|
-
const startPos = getPrimaryPointerPosition(event);
|
|
950
|
-
if (!startPos) {
|
|
951
|
-
return;
|
|
952
|
-
}
|
|
953
|
-
pendingSwipeRef.current = true;
|
|
954
|
-
pendingSwipeStartPosRef.current = startPos;
|
|
955
|
-
swipeFromScrollableRef.current = false;
|
|
956
|
-
sawPrimaryButtonsOnMoveRef.current = false;
|
|
957
|
-
const allowedToStart = canStart ? canStart(startPos, {
|
|
958
|
-
nativeEvent: event.nativeEvent,
|
|
959
|
-
direction: primaryDirection
|
|
960
|
-
}) : true;
|
|
961
|
-
if (!allowedToStart) {
|
|
962
|
-
return;
|
|
963
|
-
}
|
|
964
|
-
if (startSwipeAtPosition(event, startPos)) {
|
|
965
|
-
clearPendingSwipeStartState();
|
|
966
|
-
}
|
|
967
|
-
});
|
|
968
|
-
function handleMoveCore(event, position, movement) {
|
|
969
|
-
if (!enabled || !isSwipingRef.current) {
|
|
970
|
-
return;
|
|
971
|
-
}
|
|
972
|
-
const target = useButton.getTarget(event.nativeEvent);
|
|
973
|
-
if (isTouchLikeEvent(event) && !swipeFromScrollableRef.current) {
|
|
974
|
-
const boundaryElement = event.currentTarget;
|
|
975
|
-
if (findGestureScrollableTouchTarget(target, boundaryElement)) {
|
|
976
|
-
return;
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
if (!('touches' in event)) {
|
|
980
|
-
// Prevent text selection on Safari
|
|
981
|
-
event.preventDefault();
|
|
982
|
-
}
|
|
983
|
-
if (isFirstPointerMoveRef.current) {
|
|
984
|
-
// Adjust the starting position to the current position on the first move
|
|
985
|
-
// to account for the delay between pointerdown and the first pointermove on iOS.
|
|
986
|
-
dragStartPosRef.current = position;
|
|
987
|
-
const moveTime = getValidTimeStamp(event.timeStamp);
|
|
988
|
-
if (moveTime !== null) {
|
|
989
|
-
swipeStartTimeRef.current = moveTime;
|
|
990
|
-
}
|
|
991
|
-
isFirstPointerMoveRef.current = false;
|
|
992
|
-
}
|
|
993
|
-
const clientX = position.x;
|
|
994
|
-
const clientY = position.y;
|
|
995
|
-
const movementX = movement.x;
|
|
996
|
-
const movementY = movement.y;
|
|
997
|
-
if (movementY < 0 && clientY > swipeCancelBaselineRef.current.y || movementY > 0 && clientY < swipeCancelBaselineRef.current.y) {
|
|
998
|
-
swipeCancelBaselineRef.current = {
|
|
999
|
-
x: swipeCancelBaselineRef.current.x,
|
|
1000
|
-
y: clientY
|
|
1001
|
-
};
|
|
1002
|
-
}
|
|
1003
|
-
if (movementX < 0 && clientX > swipeCancelBaselineRef.current.x || movementX > 0 && clientX < swipeCancelBaselineRef.current.x) {
|
|
1004
|
-
swipeCancelBaselineRef.current = {
|
|
1005
|
-
x: clientX,
|
|
1006
|
-
y: swipeCancelBaselineRef.current.y
|
|
1007
|
-
};
|
|
1008
|
-
}
|
|
1009
|
-
const deltaX = clientX - dragStartPosRef.current.x;
|
|
1010
|
-
const deltaY = clientY - dragStartPosRef.current.y;
|
|
1011
|
-
const cancelDeltaY = clientY - swipeCancelBaselineRef.current.y;
|
|
1012
|
-
const cancelDeltaX = clientX - swipeCancelBaselineRef.current.x;
|
|
1013
|
-
let lockedDirection = lockedDirectionRef.current;
|
|
1014
|
-
if (lockedDirection === null && hasHorizontal && hasVertical) {
|
|
1015
|
-
const movementDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
|
1016
|
-
if (movementDistance >= MIN_DRAG_THRESHOLD) {
|
|
1017
|
-
lockedDirection = Math.abs(deltaX) > Math.abs(deltaY) ? 'horizontal' : 'vertical';
|
|
1018
|
-
lockedDirectionRef.current = lockedDirection;
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
let candidate;
|
|
1022
|
-
if (!intendedSwipeDirectionRef.current) {
|
|
1023
|
-
if (lockedDirection === 'vertical') {
|
|
1024
|
-
if (deltaY > 0) {
|
|
1025
|
-
candidate = 'down';
|
|
1026
|
-
} else if (deltaY < 0) {
|
|
1027
|
-
candidate = 'up';
|
|
1028
|
-
}
|
|
1029
|
-
} else if (lockedDirection === 'horizontal') {
|
|
1030
|
-
if (deltaX > 0) {
|
|
1031
|
-
candidate = 'right';
|
|
1032
|
-
} else if (deltaX < 0) {
|
|
1033
|
-
candidate = 'left';
|
|
1034
|
-
}
|
|
1035
|
-
} else if (Math.abs(deltaX) >= Math.abs(deltaY)) {
|
|
1036
|
-
candidate = deltaX > 0 ? 'right' : 'left';
|
|
1037
|
-
} else {
|
|
1038
|
-
candidate = deltaY > 0 ? 'down' : 'up';
|
|
1039
|
-
}
|
|
1040
|
-
if (candidate) {
|
|
1041
|
-
const isAllowed = candidate === 'left' && allowLeft || candidate === 'right' && allowRight || candidate === 'up' && allowUp || candidate === 'down' && allowDown;
|
|
1042
|
-
if (isAllowed) {
|
|
1043
|
-
intendedSwipeDirectionRef.current = candidate;
|
|
1044
|
-
maxSwipeDisplacementRef.current = getDisplacement(candidate, deltaX, deltaY);
|
|
1045
|
-
setCurrentSwipeDirection(candidate);
|
|
1046
|
-
resolveSwipeThreshold(candidate);
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
} else {
|
|
1050
|
-
const direction = intendedSwipeDirectionRef.current;
|
|
1051
|
-
const currentDisplacement = getDisplacement(direction, cancelDeltaX, cancelDeltaY);
|
|
1052
|
-
if (currentDisplacement > swipeThresholdRef.current) {
|
|
1053
|
-
cancelledSwipeRef.current = false;
|
|
1054
|
-
setCurrentSwipeDirection(direction);
|
|
1055
|
-
} else if (!(allowLeft && allowRight) && !(allowUp && allowDown) && maxSwipeDisplacementRef.current - currentDisplacement >= REVERSE_CANCEL_THRESHOLD) {
|
|
1056
|
-
// Mark that a change-of-mind has occurred
|
|
1057
|
-
cancelledSwipeRef.current = true;
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
const dampedDelta = applyDirectionalDamping(deltaX, deltaY);
|
|
1061
|
-
let newOffsetX = initialTransformRef.current.x;
|
|
1062
|
-
let newOffsetY = initialTransformRef.current.y;
|
|
1063
|
-
if (lockedDirection === 'horizontal') {
|
|
1064
|
-
if (hasHorizontal) {
|
|
1065
|
-
newOffsetX += dampedDelta.x;
|
|
1066
|
-
}
|
|
1067
|
-
} else if (lockedDirection === 'vertical') {
|
|
1068
|
-
if (hasVertical) {
|
|
1069
|
-
newOffsetY += dampedDelta.y;
|
|
1070
|
-
}
|
|
1071
|
-
} else {
|
|
1072
|
-
if (hasHorizontal) {
|
|
1073
|
-
newOffsetX += dampedDelta.x;
|
|
1074
|
-
}
|
|
1075
|
-
if (hasVertical) {
|
|
1076
|
-
newOffsetY += dampedDelta.y;
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
dragOffsetRef.current = {
|
|
1080
|
-
x: newOffsetX,
|
|
1081
|
-
y: newOffsetY
|
|
1082
|
-
};
|
|
1083
|
-
syncDragStyles(true);
|
|
1084
|
-
recordDragSample({
|
|
1085
|
-
x: newOffsetX,
|
|
1086
|
-
y: newOffsetY
|
|
1087
|
-
}, getValidTimeStamp(event.timeStamp));
|
|
1088
|
-
const dragDeltaX = newOffsetX - initialTransformRef.current.x;
|
|
1089
|
-
const dragDeltaY = newOffsetY - initialTransformRef.current.y;
|
|
1090
|
-
const swipeDirectionDetails = intendedSwipeDirectionRef.current;
|
|
1091
|
-
const progressDirection = primaryDirection ?? intendedSwipeDirectionRef.current;
|
|
1092
|
-
if (!progressDirection) {
|
|
1093
|
-
updateSwipeProgress(0, {
|
|
1094
|
-
deltaX: dragDeltaX,
|
|
1095
|
-
deltaY: dragDeltaY,
|
|
1096
|
-
direction: swipeDirectionDetails
|
|
1097
|
-
});
|
|
1098
|
-
return;
|
|
1099
|
-
}
|
|
1100
|
-
const size = progressDirection === 'left' || progressDirection === 'right' ? elementSizeRef.current.width : elementSizeRef.current.height;
|
|
1101
|
-
const scale = initialTransformRef.current.scale || 1;
|
|
1102
|
-
if (size <= 0 || scale <= 0) {
|
|
1103
|
-
updateSwipeProgress(0, {
|
|
1104
|
-
deltaX: dragDeltaX,
|
|
1105
|
-
deltaY: dragDeltaY,
|
|
1106
|
-
direction: swipeDirectionDetails
|
|
1107
|
-
});
|
|
1108
|
-
return;
|
|
1109
|
-
}
|
|
1110
|
-
const progressDisplacement = getDisplacement(progressDirection, newOffsetX - initialTransformRef.current.x, newOffsetY - initialTransformRef.current.y);
|
|
1111
|
-
if (progressDisplacement <= 0) {
|
|
1112
|
-
updateSwipeProgress(0, {
|
|
1113
|
-
deltaX: dragDeltaX,
|
|
1114
|
-
deltaY: dragDeltaY,
|
|
1115
|
-
direction: swipeDirectionDetails
|
|
1116
|
-
});
|
|
1117
|
-
return;
|
|
1118
|
-
}
|
|
1119
|
-
updateSwipeProgress(progressDisplacement / (size * scale), {
|
|
1120
|
-
deltaX: dragDeltaX,
|
|
1121
|
-
deltaY: dragDeltaY,
|
|
1122
|
-
direction: swipeDirectionDetails
|
|
1123
|
-
});
|
|
1124
|
-
}
|
|
1125
|
-
const handleEnd = useButton.useStableCallback(event => {
|
|
1126
|
-
if (!enabled) {
|
|
1127
|
-
return;
|
|
1128
|
-
}
|
|
1129
|
-
const resolvedDragOffset = dragOffsetRef.current;
|
|
1130
|
-
const resolvedInitialTransform = initialTransformRef.current;
|
|
1131
|
-
const releaseDeltaX = resolvedDragOffset.x - resolvedInitialTransform.x;
|
|
1132
|
-
const releaseDeltaY = resolvedDragOffset.y - resolvedInitialTransform.y;
|
|
1133
|
-
const progressDetails = {
|
|
1134
|
-
deltaX: releaseDeltaX,
|
|
1135
|
-
deltaY: releaseDeltaY,
|
|
1136
|
-
direction: intendedSwipeDirectionRef.current
|
|
1137
|
-
};
|
|
1138
|
-
if (!isSwipingRef.current) {
|
|
1139
|
-
resetPendingSwipeState();
|
|
1140
|
-
updateSwipeProgress(0, progressDetails);
|
|
1141
|
-
return;
|
|
1142
|
-
}
|
|
1143
|
-
setSwiping(false);
|
|
1144
|
-
lockedDirectionRef.current = null;
|
|
1145
|
-
resetPendingSwipeState();
|
|
1146
|
-
sawPrimaryButtonsOnMoveRef.current = false;
|
|
1147
|
-
const element = elementRef.current;
|
|
1148
|
-
if (element) {
|
|
1149
|
-
if (!('touches' in event)) {
|
|
1150
|
-
safelyChangePointerCapture(element, event.pointerId, 'releasePointerCapture');
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
const deltaX = releaseDeltaX;
|
|
1154
|
-
const deltaY = releaseDeltaY;
|
|
1155
|
-
const startTime = swipeStartTimeRef.current;
|
|
1156
|
-
const endTime = getValidTimeStamp(event.timeStamp);
|
|
1157
|
-
const durationMs = startTime !== null && endTime !== null && endTime > startTime ? endTime - startTime : 0;
|
|
1158
|
-
const velocityDurationMs = durationMs > 0 ? Math.max(durationMs, MIN_VELOCITY_DURATION_MS) : 0;
|
|
1159
|
-
const velocityX = velocityDurationMs > 0 ? deltaX / velocityDurationMs : 0;
|
|
1160
|
-
const velocityY = velocityDurationMs > 0 ? deltaY / velocityDurationMs : 0;
|
|
1161
|
-
let releaseVelocityX = lastDragVelocityRef.current.x;
|
|
1162
|
-
let releaseVelocityY = lastDragVelocityRef.current.y;
|
|
1163
|
-
const lastSample = lastDragSampleRef.current;
|
|
1164
|
-
if (lastSample && endTime !== null && endTime >= lastSample.time) {
|
|
1165
|
-
const ageMs = endTime - lastSample.time;
|
|
1166
|
-
if (ageMs <= MAX_RELEASE_VELOCITY_AGE_MS) {
|
|
1167
|
-
const sampleDurationMs = Math.max(ageMs, MIN_RELEASE_VELOCITY_DURATION_MS);
|
|
1168
|
-
const deltaFromLastSampleX = resolvedDragOffset.x - lastSample.x;
|
|
1169
|
-
const deltaFromLastSampleY = resolvedDragOffset.y - lastSample.y;
|
|
1170
|
-
const sampleVelocityX = deltaFromLastSampleX / sampleDurationMs;
|
|
1171
|
-
const sampleVelocityY = deltaFromLastSampleY / sampleDurationMs;
|
|
1172
|
-
if (sampleVelocityX !== 0) {
|
|
1173
|
-
releaseVelocityX = sampleVelocityX;
|
|
1174
|
-
}
|
|
1175
|
-
if (sampleVelocityY !== 0) {
|
|
1176
|
-
releaseVelocityY = sampleVelocityY;
|
|
1177
|
-
}
|
|
1178
|
-
} else {
|
|
1179
|
-
releaseVelocityX = 0;
|
|
1180
|
-
releaseVelocityY = 0;
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
const releaseDecision = onRelease?.({
|
|
1184
|
-
event: event.nativeEvent,
|
|
1185
|
-
direction: intendedSwipeDirectionRef.current,
|
|
1186
|
-
deltaX,
|
|
1187
|
-
deltaY,
|
|
1188
|
-
velocityX,
|
|
1189
|
-
velocityY,
|
|
1190
|
-
releaseVelocityX,
|
|
1191
|
-
releaseVelocityY
|
|
1192
|
-
});
|
|
1193
|
-
const hasReleaseDecision = typeof releaseDecision === 'boolean';
|
|
1194
|
-
if (cancelledSwipeRef.current && !hasReleaseDecision) {
|
|
1195
|
-
dragOffsetRef.current = {
|
|
1196
|
-
x: resolvedInitialTransform.x,
|
|
1197
|
-
y: resolvedInitialTransform.y
|
|
1198
|
-
};
|
|
1199
|
-
setCurrentSwipeDirection(undefined);
|
|
1200
|
-
syncDragStyles(false);
|
|
1201
|
-
updateSwipeProgress(0, progressDetails);
|
|
1202
|
-
return;
|
|
1203
|
-
}
|
|
1204
|
-
let shouldClose = false;
|
|
1205
|
-
let dismissDirection;
|
|
1206
|
-
if (hasReleaseDecision) {
|
|
1207
|
-
shouldClose = releaseDecision;
|
|
1208
|
-
dismissDirection = intendedSwipeDirectionRef.current ?? primaryDirection;
|
|
1209
|
-
} else {
|
|
1210
|
-
for (const direction of directions) {
|
|
1211
|
-
switch (direction) {
|
|
1212
|
-
case 'right':
|
|
1213
|
-
if (deltaX > swipeThresholdRef.current) {
|
|
1214
|
-
shouldClose = true;
|
|
1215
|
-
dismissDirection = 'right';
|
|
1216
|
-
}
|
|
1217
|
-
break;
|
|
1218
|
-
case 'left':
|
|
1219
|
-
if (deltaX < -swipeThresholdRef.current) {
|
|
1220
|
-
shouldClose = true;
|
|
1221
|
-
dismissDirection = 'left';
|
|
1222
|
-
}
|
|
1223
|
-
break;
|
|
1224
|
-
case 'down':
|
|
1225
|
-
if (deltaY > swipeThresholdRef.current) {
|
|
1226
|
-
shouldClose = true;
|
|
1227
|
-
dismissDirection = 'down';
|
|
1228
|
-
}
|
|
1229
|
-
break;
|
|
1230
|
-
case 'up':
|
|
1231
|
-
if (deltaY < -swipeThresholdRef.current) {
|
|
1232
|
-
shouldClose = true;
|
|
1233
|
-
dismissDirection = 'up';
|
|
1234
|
-
}
|
|
1235
|
-
break;
|
|
1236
|
-
}
|
|
1237
|
-
if (shouldClose) {
|
|
1238
|
-
break;
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
if (shouldClose && dismissDirection) {
|
|
1243
|
-
setCurrentSwipeDirection(dismissDirection);
|
|
1244
|
-
setDragDismissed(true);
|
|
1245
|
-
syncDragStyles(false);
|
|
1246
|
-
onDismiss?.(event.nativeEvent, {
|
|
1247
|
-
direction: dismissDirection
|
|
1248
|
-
});
|
|
1249
|
-
} else {
|
|
1250
|
-
dragOffsetRef.current = {
|
|
1251
|
-
x: resolvedInitialTransform.x,
|
|
1252
|
-
y: resolvedInitialTransform.y
|
|
1253
|
-
};
|
|
1254
|
-
setCurrentSwipeDirection(undefined);
|
|
1255
|
-
syncDragStyles(false);
|
|
1256
|
-
updateSwipeProgress(0, progressDetails);
|
|
1257
|
-
}
|
|
1258
|
-
});
|
|
1259
|
-
const handleMove = useButton.useStableCallback(event => {
|
|
1260
|
-
const currentPos = getPrimaryPointerPosition(event);
|
|
1261
|
-
if (!currentPos) {
|
|
1262
|
-
return;
|
|
1263
|
-
}
|
|
1264
|
-
let endAfterMove = false;
|
|
1265
|
-
if (!('touches' in event)) {
|
|
1266
|
-
const hasPrimaryButton = hasPrimaryMouseButton(event.buttons);
|
|
1267
|
-
if (hasPrimaryButton) {
|
|
1268
|
-
sawPrimaryButtonsOnMoveRef.current = true;
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
|
-
// Cancel the swipe if a non-primary button takes over the interaction.
|
|
1272
|
-
// This handles cases where a right-click interrupts dragging.
|
|
1273
|
-
if (event.buttons !== 0 && !hasPrimaryButton) {
|
|
1274
|
-
cancelSwipeInteraction(event);
|
|
1275
|
-
return;
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
// A `buttons: 0` pointermove means the primary button was already released, so the gesture is
|
|
1279
|
-
// over even if no pointerup reached us. On fast trackpad flicks this trailing move is
|
|
1280
|
-
// dispatched just before pointerup; treat it as the release (mirroring touchend) instead of
|
|
1281
|
-
// cancelling and snapping the element back.
|
|
1282
|
-
if (event.buttons === 0 && sawPrimaryButtonsOnMoveRef.current) {
|
|
1283
|
-
if (!isSwipingRef.current) {
|
|
1284
|
-
// The gesture never activated — discard it.
|
|
1285
|
-
handleEnd(event);
|
|
1286
|
-
return;
|
|
1287
|
-
}
|
|
1288
|
-
// This release move can itself carry the threshold-crossing displacement (and the peak
|
|
1289
|
-
// release velocity), so let it flow through `handleMoveCore` below to update the drag
|
|
1290
|
-
// offset / velocity sample, then commit the release afterwards.
|
|
1291
|
-
endAfterMove = true;
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
if (!isSwiping && pendingSwipeRef.current) {
|
|
1295
|
-
if (!isTouchLikeEvent(event) && (event.defaultPrevented || event.nativeEvent.defaultPrevented)) {
|
|
1296
|
-
resetPendingSwipeState();
|
|
1297
|
-
return;
|
|
1298
|
-
}
|
|
1299
|
-
const allowedToStart = canStart ? canStart(currentPos, {
|
|
1300
|
-
nativeEvent: event.nativeEvent,
|
|
1301
|
-
direction: primaryDirection
|
|
1302
|
-
}) : true;
|
|
1303
|
-
if (allowedToStart) {
|
|
1304
|
-
const pendingStartPos = pendingSwipeStartPosRef.current;
|
|
1305
|
-
let ignoreScrollableOnStart = false;
|
|
1306
|
-
if (isTouchLikeEvent(event)) {
|
|
1307
|
-
const element = elementRef.current;
|
|
1308
|
-
if (pendingStartPos && element) {
|
|
1309
|
-
const target = getTargetAtPoint(currentPos, event.nativeEvent);
|
|
1310
|
-
const doc = useButton.ownerDocument(element);
|
|
1311
|
-
const body = doc.body;
|
|
1312
|
-
const scrollTarget = body ? findGestureScrollableTouchTarget(target, body) : null;
|
|
1313
|
-
if (scrollTarget && (useButton.contains(element, scrollTarget) || useButton.contains(scrollTarget, element))) {
|
|
1314
|
-
const deltaX = currentPos.x - pendingStartPos.x;
|
|
1315
|
-
const deltaY = currentPos.y - pendingStartPos.y;
|
|
1316
|
-
const canSwipeFromEdge = canSwipeFromScrollEdgeOnPendingMove(scrollTarget, deltaX, deltaY);
|
|
1317
|
-
if (canSwipeFromEdge === false) {
|
|
1318
|
-
return;
|
|
1319
|
-
}
|
|
1320
|
-
if (canSwipeFromEdge === true) {
|
|
1321
|
-
ignoreScrollableOnStart = true;
|
|
1322
|
-
}
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
const started = startSwipeAtPosition(event, currentPos, {
|
|
1327
|
-
ignoreScrollableTarget: ignoreScrollableOnStart,
|
|
1328
|
-
ignoreScrollableAncestors: ignoreScrollableOnStart
|
|
1329
|
-
});
|
|
1330
|
-
if (started) {
|
|
1331
|
-
if (pendingStartPos && ignoreScrollableOnStart) {
|
|
1332
|
-
// Preserve displacement between touchstart and the move that activates swipe from
|
|
1333
|
-
// a scroll-edge so quick flicks can dismiss.
|
|
1334
|
-
clearPendingSwipeStartState();
|
|
1335
|
-
dragStartPosRef.current = pendingStartPos;
|
|
1336
|
-
swipeCancelBaselineRef.current = pendingStartPos;
|
|
1337
|
-
lastMovePosRef.current = pendingStartPos;
|
|
1338
|
-
isFirstPointerMoveRef.current = false;
|
|
1339
|
-
} else {
|
|
1340
|
-
// Start from the current in-bounds position without dropping follow-up move
|
|
1341
|
-
// displacement; this avoids jumps when entering from outside the element while
|
|
1342
|
-
// keeping swipe tracking responsive on the next move.
|
|
1343
|
-
clearPendingSwipeStartState();
|
|
1344
|
-
swipeFromScrollableRef.current = false;
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
const previousPos = lastMovePosRef.current;
|
|
1350
|
-
const movement = previousPos === null ? {
|
|
1351
|
-
x: 0,
|
|
1352
|
-
y: 0
|
|
1353
|
-
} : {
|
|
1354
|
-
x: currentPos.x - previousPos.x,
|
|
1355
|
-
y: currentPos.y - previousPos.y
|
|
1356
|
-
};
|
|
1357
|
-
lastMovePosRef.current = currentPos;
|
|
1358
|
-
handleMoveCore(event, currentPos, movement);
|
|
1359
|
-
|
|
1360
|
-
// `endAfterMove` is only set in the non-touch branch above; the `'touches'` guard re-narrows the
|
|
1361
|
-
// event type for `handleEnd` after the shared move handling has run.
|
|
1362
|
-
if (endAfterMove && !('touches' in event)) {
|
|
1363
|
-
handleEnd(event);
|
|
1364
|
-
}
|
|
1365
|
-
});
|
|
1366
|
-
|
|
1367
|
-
// Feeds a native touchmove into the swipe pipeline. Used by consumers that claim the gesture
|
|
1368
|
-
// in a capture-phase listener and stop it from reaching React's delegated touch handlers.
|
|
1369
|
-
const moveNative = useButton.useStableCallback((nativeEvent, currentTarget) => {
|
|
1370
|
-
handleMove({
|
|
1371
|
-
touches: nativeEvent.touches,
|
|
1372
|
-
currentTarget,
|
|
1373
|
-
nativeEvent,
|
|
1374
|
-
defaultPrevented: nativeEvent.defaultPrevented,
|
|
1375
|
-
timeStamp: nativeEvent.timeStamp
|
|
1376
|
-
});
|
|
1377
|
-
});
|
|
1378
|
-
const getDragStyles = React__namespace.useCallback(() => {
|
|
1379
|
-
const dragOffset = dragOffsetRef.current;
|
|
1380
|
-
const initialTransform = initialTransformRef.current;
|
|
1381
|
-
const deltaX = dragOffset.x - initialTransform.x;
|
|
1382
|
-
const deltaY = dragOffset.y - initialTransform.y;
|
|
1383
|
-
if (!isSwiping && deltaX === 0 && deltaY === 0 && !dragDismissed) {
|
|
1384
|
-
return {
|
|
1385
|
-
[movementCssVars.x]: '0px',
|
|
1386
|
-
[movementCssVars.y]: '0px'
|
|
1387
|
-
};
|
|
1388
|
-
}
|
|
1389
|
-
return {
|
|
1390
|
-
transition: isSwiping ? 'none' : undefined,
|
|
1391
|
-
// While swiping, freeze the element at its current visual transform so it doesn't snap to the
|
|
1392
|
-
// end position.
|
|
1393
|
-
transform: isSwiping ? getDragTransform(dragOffset, initialTransform.scale) : undefined,
|
|
1394
|
-
[movementCssVars.x]: `${deltaX}px`,
|
|
1395
|
-
[movementCssVars.y]: `${deltaY}px`
|
|
1396
|
-
};
|
|
1397
|
-
}, [dragDismissed, isSwiping, movementCssVars]);
|
|
1398
|
-
const getPointerProps = React__namespace.useCallback(() => {
|
|
1399
|
-
if (!enabled) {
|
|
1400
|
-
return {};
|
|
1401
|
-
}
|
|
1402
|
-
return {
|
|
1403
|
-
onPointerDown: handleStart,
|
|
1404
|
-
onPointerMove: handleMove,
|
|
1405
|
-
onPointerUp: handleEnd,
|
|
1406
|
-
onPointerCancel: handleEnd
|
|
1407
|
-
};
|
|
1408
|
-
}, [enabled, handleEnd, handleMove, handleStart]);
|
|
1409
|
-
const getTouchProps = React__namespace.useCallback(() => {
|
|
1410
|
-
if (!enabled) {
|
|
1411
|
-
return {};
|
|
1412
|
-
}
|
|
1413
|
-
return {
|
|
1414
|
-
onTouchStart: handleStart,
|
|
1415
|
-
onTouchMove: handleMove,
|
|
1416
|
-
onTouchEnd: handleEnd,
|
|
1417
|
-
onTouchCancel: handleEnd
|
|
1418
|
-
};
|
|
1419
|
-
}, [enabled, handleEnd, handleMove, handleStart]);
|
|
1420
|
-
return {
|
|
1421
|
-
swiping: isSwiping,
|
|
1422
|
-
swipeDirection: currentSwipeDirection,
|
|
1423
|
-
dragDismissed,
|
|
1424
|
-
getPointerProps,
|
|
1425
|
-
getTouchProps,
|
|
1426
|
-
moveNative,
|
|
1427
|
-
getDragStyles,
|
|
1428
|
-
reset
|
|
1429
|
-
};
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
let DrawerSwipeAreaDataAttributes = function (DrawerSwipeAreaDataAttributes) {
|
|
1433
|
-
/**
|
|
1434
|
-
* Present when the drawer is open.
|
|
1435
|
-
*/
|
|
1436
|
-
DrawerSwipeAreaDataAttributes[DrawerSwipeAreaDataAttributes["open"] = useScrollLock.CommonPopupDataAttributes.open] = "open";
|
|
1437
|
-
/**
|
|
1438
|
-
* Present when the drawer is closed.
|
|
1439
|
-
*/
|
|
1440
|
-
DrawerSwipeAreaDataAttributes[DrawerSwipeAreaDataAttributes["closed"] = useScrollLock.CommonPopupDataAttributes.closed] = "closed";
|
|
1441
|
-
/**
|
|
1442
|
-
* Present when the swipe area is disabled.
|
|
1443
|
-
*/
|
|
1444
|
-
DrawerSwipeAreaDataAttributes["disabled"] = "data-disabled";
|
|
1445
|
-
/**
|
|
1446
|
-
* Indicates the swipe direction.
|
|
1447
|
-
* @type {'up' | 'down' | 'left' | 'right'}
|
|
1448
|
-
*/
|
|
1449
|
-
DrawerSwipeAreaDataAttributes["swipeDirection"] = "data-swipe-direction";
|
|
1450
|
-
/**
|
|
1451
|
-
* Present when the drawer is being swiped.
|
|
1452
|
-
*/
|
|
1453
|
-
DrawerSwipeAreaDataAttributes["swiping"] = "data-swiping";
|
|
1454
|
-
return DrawerSwipeAreaDataAttributes;
|
|
1455
|
-
}({});
|
|
1456
|
-
|
|
1457
|
-
const DEFAULT_SWIPE_OPEN_RATIO = 0.5;
|
|
1458
|
-
const MIN_SWIPE_START_DISTANCE = 1;
|
|
1459
|
-
const VELOCITY_THRESHOLD = 0.1;
|
|
1460
|
-
const FALLBACK_SWIPE_OPEN_THRESHOLD = 40;
|
|
1461
|
-
const SWIPE_AREA_OPEN_HOOK = {
|
|
1462
|
-
[DrawerSwipeAreaDataAttributes.open]: ''
|
|
1463
|
-
};
|
|
1464
|
-
const SWIPE_AREA_CLOSED_HOOK = {
|
|
1465
|
-
[DrawerSwipeAreaDataAttributes.closed]: ''
|
|
1466
|
-
};
|
|
1467
|
-
const SWIPE_AREA_SWIPING_HOOK = {
|
|
1468
|
-
[DrawerSwipeAreaDataAttributes.swiping]: ''
|
|
1469
|
-
};
|
|
1470
|
-
const SWIPE_AREA_DISABLED_HOOK = {
|
|
1471
|
-
[DrawerSwipeAreaDataAttributes.disabled]: ''
|
|
1472
|
-
};
|
|
1473
|
-
const stateAttributesMapping$3 = {
|
|
1474
|
-
open(value) {
|
|
1475
|
-
return value ? SWIPE_AREA_OPEN_HOOK : SWIPE_AREA_CLOSED_HOOK;
|
|
1476
|
-
},
|
|
1477
|
-
swiping(value) {
|
|
1478
|
-
return value ? SWIPE_AREA_SWIPING_HOOK : null;
|
|
1479
|
-
},
|
|
1480
|
-
swipeDirection(value) {
|
|
1481
|
-
return value ? {
|
|
1482
|
-
[DrawerSwipeAreaDataAttributes.swipeDirection]: value
|
|
1483
|
-
} : null;
|
|
1484
|
-
},
|
|
1485
|
-
disabled(value) {
|
|
1486
|
-
return value ? SWIPE_AREA_DISABLED_HOOK : null;
|
|
1487
|
-
}
|
|
1488
|
-
};
|
|
1489
|
-
const oppositeSwipeDirection = {
|
|
1490
|
-
up: 'down',
|
|
1491
|
-
down: 'up',
|
|
1492
|
-
left: 'right',
|
|
1493
|
-
right: 'left'
|
|
1494
|
-
};
|
|
1495
|
-
function resolveTouchAction(direction) {
|
|
1496
|
-
return direction === 'left' || direction === 'right' ? 'pan-y' : 'pan-x';
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
/**
|
|
1500
|
-
* An invisible area that listens for swipe gestures to open the drawer.
|
|
1501
|
-
* Renders a `<div>` element.
|
|
1502
|
-
*
|
|
1503
|
-
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
1504
|
-
*/
|
|
1505
|
-
const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function DrawerSwipeArea(componentProps, forwardedRef) {
|
|
1506
|
-
const {
|
|
1507
|
-
render,
|
|
1508
|
-
className,
|
|
1509
|
-
style,
|
|
1510
|
-
disabled = false,
|
|
1511
|
-
swipeDirection: swipeDirectionProp,
|
|
1512
|
-
...elementProps
|
|
1513
|
-
} = componentProps;
|
|
1514
|
-
const {
|
|
1515
|
-
store
|
|
1516
|
-
} = ScrollAreaViewport.useDialogRootContext();
|
|
1517
|
-
const {
|
|
1518
|
-
swipeDirection,
|
|
1519
|
-
frontmostHeight
|
|
1520
|
-
} = ScrollAreaViewport.useDrawerRootContext();
|
|
1521
|
-
const providerContext = ScrollAreaViewport.useDrawerProviderContext();
|
|
1522
|
-
const [swipeActive, setSwipeActive] = React__namespace.useState(false);
|
|
1523
|
-
const releaseDismissTimeout = useButton.useTimeout();
|
|
1524
|
-
const swipeAreaRef = React__namespace.useRef(null);
|
|
1525
|
-
const swipeStartEventRef = React__namespace.useRef(null);
|
|
1526
|
-
const openedBySwipeRef = React__namespace.useRef(false);
|
|
1527
|
-
const dragDeltaRef = React__namespace.useRef({
|
|
1528
|
-
x: 0,
|
|
1529
|
-
y: 0
|
|
1530
|
-
});
|
|
1531
|
-
const closedOffsetRef = React__namespace.useRef(null);
|
|
1532
|
-
const appliedSwipeStylesRef = React__namespace.useRef(false);
|
|
1533
|
-
const popupTransitionRef = React__namespace.useRef(null);
|
|
1534
|
-
const swipeAreaId = useButton.useBaseUiId(componentProps.id);
|
|
1535
|
-
const registerTrigger = useScrollLock.useTriggerRegistration(swipeAreaId, store);
|
|
1536
|
-
const open = store.useState('open');
|
|
1537
|
-
const resetDragDelta = useButton.useStableCallback(() => {
|
|
1538
|
-
dragDeltaRef.current.x = 0;
|
|
1539
|
-
dragDeltaRef.current.y = 0;
|
|
1540
|
-
});
|
|
1541
|
-
const resolvedSwipeDirection = swipeDirectionProp ?? oppositeSwipeDirection[swipeDirection];
|
|
1542
|
-
const dismissDirection = oppositeSwipeDirection[resolvedSwipeDirection];
|
|
1543
|
-
const enabled = !disabled && (!open || swipeActive);
|
|
1544
|
-
function disableDismissForSwipe() {
|
|
1545
|
-
releaseDismissTimeout.clear();
|
|
1546
|
-
store.context.outsidePressEnabledRef.current = false;
|
|
1547
|
-
}
|
|
1548
|
-
function enableDismissAfterRelease() {
|
|
1549
|
-
// Safari can dispatch outside-press for the same swipe-open gesture
|
|
1550
|
-
// after release, so defer re-enabling dismissal to the next macrotask.
|
|
1551
|
-
releaseDismissTimeout.start(0, () => {
|
|
1552
|
-
store.context.outsidePressEnabledRef.current = true;
|
|
1553
|
-
});
|
|
1554
|
-
}
|
|
1555
|
-
function resolvePopupSize() {
|
|
1556
|
-
const popupElement = store.context.popupRef.current;
|
|
1557
|
-
if (!popupElement) {
|
|
1558
|
-
return null;
|
|
1559
|
-
}
|
|
1560
|
-
const isHorizontal = dismissDirection === 'left' || dismissDirection === 'right';
|
|
1561
|
-
const size = isHorizontal ? popupElement.offsetWidth : popupElement.offsetHeight;
|
|
1562
|
-
if (size <= 0) {
|
|
1563
|
-
return null;
|
|
1564
|
-
}
|
|
1565
|
-
return size;
|
|
1566
|
-
}
|
|
1567
|
-
function resolveClosedOffset() {
|
|
1568
|
-
const offset = resolvePopupSize();
|
|
1569
|
-
if (offset == null) {
|
|
1570
|
-
return null;
|
|
1571
|
-
}
|
|
1572
|
-
const popupElement = store.context.popupRef.current;
|
|
1573
|
-
if (!popupElement) {
|
|
1574
|
-
return offset;
|
|
1575
|
-
}
|
|
1576
|
-
const isHorizontal = dismissDirection === 'left' || dismissDirection === 'right';
|
|
1577
|
-
const transform = getElementTransform(popupElement);
|
|
1578
|
-
const transformOffset = isHorizontal ? transform.x : transform.y;
|
|
1579
|
-
if (Number.isFinite(transformOffset) && Math.abs(transformOffset) > 0.5) {
|
|
1580
|
-
return Math.min(offset, Math.abs(transformOffset));
|
|
1581
|
-
}
|
|
1582
|
-
return offset;
|
|
1583
|
-
}
|
|
1584
|
-
function resolveSwipeOpenThreshold() {
|
|
1585
|
-
const popupSize = resolvePopupSize();
|
|
1586
|
-
if (popupSize == null) {
|
|
1587
|
-
return FALLBACK_SWIPE_OPEN_THRESHOLD;
|
|
1588
|
-
}
|
|
1589
|
-
return popupSize * DEFAULT_SWIPE_OPEN_RATIO;
|
|
1590
|
-
}
|
|
1591
|
-
function applySwipeMovement() {
|
|
1592
|
-
if (!swipeActive) {
|
|
1593
|
-
return;
|
|
1594
|
-
}
|
|
1595
|
-
const popupElement = store.context.popupRef.current;
|
|
1596
|
-
if (!popupElement) {
|
|
1597
|
-
return;
|
|
1598
|
-
}
|
|
1599
|
-
if (!store.select('open') || !store.select('mounted')) {
|
|
1600
|
-
return;
|
|
1601
|
-
}
|
|
1602
|
-
if (closedOffsetRef.current == null) {
|
|
1603
|
-
closedOffsetRef.current = resolveClosedOffset();
|
|
1604
|
-
}
|
|
1605
|
-
const closedOffset = closedOffsetRef.current;
|
|
1606
|
-
if (!closedOffset || !Number.isFinite(closedOffset) || closedOffset <= 0) {
|
|
596
|
+
const closedOffset = closedOffsetRef.current;
|
|
597
|
+
if (!closedOffset || !Number.isFinite(closedOffset) || closedOffset <= 0) {
|
|
1607
598
|
return;
|
|
1608
599
|
}
|
|
1609
600
|
const {
|
|
1610
601
|
x,
|
|
1611
602
|
y
|
|
1612
603
|
} = dragDeltaRef.current;
|
|
1613
|
-
const displacement = getDisplacement(resolvedSwipeDirection, x, y);
|
|
604
|
+
const displacement = ScrollAreaViewport.getDisplacement(resolvedSwipeDirection, x, y);
|
|
1614
605
|
const clampedDisplacement = Math.max(0, displacement);
|
|
1615
606
|
const dampedDisplacement = clampedDisplacement > closedOffset ? closedOffset + Math.sqrt(clampedDisplacement - closedOffset) : clampedDisplacement;
|
|
1616
607
|
const remaining = closedOffset - dampedDisplacement;
|
|
@@ -1692,7 +683,7 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
1692
683
|
resetDragDelta();
|
|
1693
684
|
clearSwipeStyles();
|
|
1694
685
|
}
|
|
1695
|
-
const swipe = useSwipeDismiss({
|
|
686
|
+
const swipe = ScrollAreaViewport.useSwipeDismiss({
|
|
1696
687
|
enabled,
|
|
1697
688
|
directions: [resolvedSwipeDirection],
|
|
1698
689
|
elementRef: swipeAreaRef,
|
|
@@ -1715,856 +706,89 @@ const DrawerSwipeArea = /*#__PURE__*/React__namespace.forwardRef(function Drawer
|
|
|
1715
706
|
if (!swipeStartEventRef.current) {
|
|
1716
707
|
return;
|
|
1717
708
|
}
|
|
1718
|
-
dragDeltaRef.current.x = details.deltaX;
|
|
1719
|
-
dragDeltaRef.current.y = details.deltaY;
|
|
1720
|
-
if (details.direction !== resolvedSwipeDirection) {
|
|
1721
|
-
return;
|
|
1722
|
-
}
|
|
1723
|
-
const displacement = getDisplacement(resolvedSwipeDirection, details.deltaX, details.deltaY);
|
|
1724
|
-
if (displacement < MIN_SWIPE_START_DISTANCE && !openedBySwipeRef.current) {
|
|
1725
|
-
return;
|
|
1726
|
-
}
|
|
1727
|
-
if (!openedBySwipeRef.current) {
|
|
1728
|
-
openDrawer(swipeStartEventRef.current);
|
|
1729
|
-
}
|
|
1730
|
-
applySwipeMovement();
|
|
1731
|
-
},
|
|
1732
|
-
onRelease({
|
|
1733
|
-
event,
|
|
1734
|
-
direction,
|
|
1735
|
-
deltaX,
|
|
1736
|
-
deltaY,
|
|
1737
|
-
releaseVelocityX,
|
|
1738
|
-
releaseVelocityY
|
|
1739
|
-
}) {
|
|
1740
|
-
const displacement = getDisplacement(resolvedSwipeDirection, deltaX, deltaY);
|
|
1741
|
-
const releaseVelocity = getDisplacement(resolvedSwipeDirection, releaseVelocityX, releaseVelocityY);
|
|
1742
|
-
const threshold = resolveSwipeOpenThreshold();
|
|
1743
|
-
const hasEnoughDistance = threshold != null && displacement >= threshold;
|
|
1744
|
-
const hasEnoughVelocity = releaseVelocity >= VELOCITY_THRESHOLD;
|
|
1745
|
-
const shouldOpen = threshold != null && direction === resolvedSwipeDirection && (hasEnoughDistance || hasEnoughVelocity) && !disabled;
|
|
1746
|
-
if (shouldOpen) {
|
|
1747
|
-
if (!store.select('open')) {
|
|
1748
|
-
openDrawer(event);
|
|
1749
|
-
}
|
|
1750
|
-
} else if (openedBySwipeRef.current) {
|
|
1751
|
-
closeDrawer(event);
|
|
1752
|
-
}
|
|
1753
|
-
finishSwipeInteraction();
|
|
1754
|
-
return false;
|
|
1755
|
-
},
|
|
1756
|
-
onCancel: finishSwipeInteraction
|
|
1757
|
-
});
|
|
1758
|
-
const swipePointerProps = swipe.getPointerProps();
|
|
1759
|
-
const swipeTouchProps = swipe.getTouchProps();
|
|
1760
|
-
const resetSwipe = swipe.reset;
|
|
1761
|
-
React__namespace.useEffect(() => {
|
|
1762
|
-
if (!enabled) {
|
|
1763
|
-
resetSwipe();
|
|
1764
|
-
resetDragDelta();
|
|
1765
|
-
clearSwipeStyles();
|
|
1766
|
-
resetSwipeInteractionState();
|
|
1767
|
-
}
|
|
1768
|
-
}, [clearSwipeStyles, enabled, resetDragDelta, resetSwipe]);
|
|
1769
|
-
React__namespace.useEffect(() => {
|
|
1770
|
-
return () => {
|
|
1771
|
-
store.context.outsidePressEnabledRef.current = true;
|
|
1772
|
-
};
|
|
1773
|
-
}, [store]);
|
|
1774
|
-
const state = {
|
|
1775
|
-
open,
|
|
1776
|
-
swiping: swipe.swiping,
|
|
1777
|
-
swipeDirection: resolvedSwipeDirection,
|
|
1778
|
-
disabled
|
|
1779
|
-
};
|
|
1780
|
-
return useRenderElement.useRenderElement('div', componentProps, {
|
|
1781
|
-
state,
|
|
1782
|
-
ref: [forwardedRef, swipeAreaRef, registerTrigger],
|
|
1783
|
-
stateAttributesMapping: stateAttributesMapping$3,
|
|
1784
|
-
props: [{
|
|
1785
|
-
role: 'presentation',
|
|
1786
|
-
'aria-hidden': true,
|
|
1787
|
-
style: {
|
|
1788
|
-
pointerEvents: !enabled ? 'none' : undefined,
|
|
1789
|
-
touchAction: resolveTouchAction(resolvedSwipeDirection)
|
|
1790
|
-
},
|
|
1791
|
-
onPointerDown(event) {
|
|
1792
|
-
if (event.pointerType === 'touch') {
|
|
1793
|
-
return;
|
|
1794
|
-
}
|
|
1795
|
-
swipePointerProps.onPointerDown?.(event);
|
|
1796
|
-
|
|
1797
|
-
// Prevent native text selection/drag gestures from competing with swipe-open dragging.
|
|
1798
|
-
if (event.cancelable) {
|
|
1799
|
-
event.preventDefault();
|
|
1800
|
-
}
|
|
1801
|
-
},
|
|
1802
|
-
onPointerMove(event) {
|
|
1803
|
-
if (event.pointerType === 'touch') {
|
|
1804
|
-
return;
|
|
1805
|
-
}
|
|
1806
|
-
swipePointerProps.onPointerMove?.(event);
|
|
1807
|
-
},
|
|
1808
|
-
onPointerUp(event) {
|
|
1809
|
-
if (event.pointerType === 'touch') {
|
|
1810
|
-
return;
|
|
1811
|
-
}
|
|
1812
|
-
swipePointerProps.onPointerUp?.(event);
|
|
1813
|
-
},
|
|
1814
|
-
onPointerCancel(event) {
|
|
1815
|
-
if (event.pointerType === 'touch') {
|
|
1816
|
-
return;
|
|
1817
|
-
}
|
|
1818
|
-
swipePointerProps.onPointerCancel?.(event);
|
|
1819
|
-
}
|
|
1820
|
-
}, swipeTouchProps, swipeAreaId ? {
|
|
1821
|
-
id: swipeAreaId
|
|
1822
|
-
} : undefined, elementProps]
|
|
1823
|
-
});
|
|
1824
|
-
});
|
|
1825
|
-
if (process.env.NODE_ENV !== "production") DrawerSwipeArea.displayName = "DrawerSwipeArea";
|
|
1826
|
-
|
|
1827
|
-
const DrawerVirtualKeyboardContext = /*#__PURE__*/React__namespace.createContext(undefined);
|
|
1828
|
-
if (process.env.NODE_ENV !== "production") DrawerVirtualKeyboardContext.displayName = "DrawerVirtualKeyboardContext";
|
|
1829
|
-
function useDrawerVirtualKeyboardContext() {
|
|
1830
|
-
return React__namespace.useContext(DrawerVirtualKeyboardContext);
|
|
1831
|
-
}
|
|
1832
|
-
|
|
1833
|
-
const MIN_SWIPE_THRESHOLD = 10;
|
|
1834
|
-
const FAST_SWIPE_VELOCITY = 0.5;
|
|
1835
|
-
const SNAP_VELOCITY_THRESHOLD = 0.5;
|
|
1836
|
-
const SNAP_VELOCITY_MULTIPLIER = 300;
|
|
1837
|
-
const MAX_SNAP_VELOCITY = 4;
|
|
1838
|
-
const MIN_SWIPE_RELEASE_VELOCITY = 0.2;
|
|
1839
|
-
const MAX_SWIPE_RELEASE_VELOCITY = 4;
|
|
1840
|
-
const MIN_SWIPE_RELEASE_DURATION_MS = 80;
|
|
1841
|
-
const MAX_SWIPE_RELEASE_DURATION_MS = 360;
|
|
1842
|
-
const MIN_SWIPE_RELEASE_SCALAR = 0.1;
|
|
1843
|
-
const MAX_SWIPE_RELEASE_SCALAR = 1;
|
|
1844
|
-
const DRAWER_CONTENT_SELECTOR = `[${ScrollAreaViewport.DRAWER_CONTENT_ATTRIBUTE}]`;
|
|
1845
|
-
/**
|
|
1846
|
-
* A positioning container for the drawer popup that can be made scrollable.
|
|
1847
|
-
* Renders a `<div>` element.
|
|
1848
|
-
*
|
|
1849
|
-
* Documentation: [Base UI Drawer](https://base-ui.com/react/components/drawer)
|
|
1850
|
-
*/
|
|
1851
|
-
const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerViewport(props, forwardedRef) {
|
|
1852
|
-
const {
|
|
1853
|
-
render,
|
|
1854
|
-
className,
|
|
1855
|
-
style,
|
|
1856
|
-
children,
|
|
1857
|
-
...elementProps
|
|
1858
|
-
} = props;
|
|
1859
|
-
const {
|
|
1860
|
-
store
|
|
1861
|
-
} = ScrollAreaViewport.useDialogRootContext();
|
|
1862
|
-
const popupRef = store.context.popupRef;
|
|
1863
|
-
const backdropRef = store.context.backdropRef;
|
|
1864
|
-
const {
|
|
1865
|
-
swipeDirection,
|
|
1866
|
-
notifyParentSwipingChange,
|
|
1867
|
-
notifyParentSwipeProgressChange,
|
|
1868
|
-
frontmostHeight,
|
|
1869
|
-
snapToSequentialPoints
|
|
1870
|
-
} = ScrollAreaViewport.useDrawerRootContext();
|
|
1871
|
-
const providerContext = ScrollAreaViewport.useDrawerProviderContext();
|
|
1872
|
-
const {
|
|
1873
|
-
snapPoints,
|
|
1874
|
-
resolvedSnapPoints,
|
|
1875
|
-
activeSnapPoint,
|
|
1876
|
-
activeSnapPointOffset,
|
|
1877
|
-
setActiveSnapPoint,
|
|
1878
|
-
popupHeight
|
|
1879
|
-
} = ScrollAreaViewport.useDrawerSnapPoints();
|
|
1880
|
-
const open = store.useState('open');
|
|
1881
|
-
const mounted = store.useState('mounted');
|
|
1882
|
-
const nested = store.useState('nested');
|
|
1883
|
-
const nestedOpenDrawerCount = store.useState('nestedOpenDrawerCount');
|
|
1884
|
-
const viewportElement = store.useState('viewportElement');
|
|
1885
|
-
const popupElementState = store.useState('popupElement');
|
|
1886
|
-
const visualStateStore = providerContext?.visualStateStore;
|
|
1887
|
-
const nestedDrawerOpen = nestedOpenDrawerCount > 0;
|
|
1888
|
-
const scrollAxis = swipeDirection === 'left' || swipeDirection === 'right' ? 'horizontal' : 'vertical';
|
|
1889
|
-
const isVerticalScrollAxis = scrollAxis === 'vertical';
|
|
1890
|
-
const crossScrollAxis = isVerticalScrollAxis ? 'horizontal' : 'vertical';
|
|
1891
|
-
const [swipeRelease, setSwipeRelease] = React__namespace.useState(null);
|
|
1892
|
-
const pendingSwipeCloseSnapPointRef = React__namespace.useRef(undefined);
|
|
1893
|
-
const resetSwipeRef = React__namespace.useRef(null);
|
|
1894
|
-
const controlledDismissFrame = useButton.useAnimationFrame();
|
|
1895
|
-
const swipingRef = React__namespace.useRef(false);
|
|
1896
|
-
const nestedSwipeActiveRef = React__namespace.useRef(false);
|
|
1897
|
-
const lastPointerTypeRef = React__namespace.useRef('');
|
|
1898
|
-
const ignoreNextTouchStartFromPenRef = React__namespace.useRef(false);
|
|
1899
|
-
const ignoreTouchSwipeRef = React__namespace.useRef(false);
|
|
1900
|
-
const touchScrollStateRef = React__namespace.useRef(null);
|
|
1901
|
-
const virtualKeyboard = useDrawerVirtualKeyboardContext();
|
|
1902
|
-
const snapPointRange = React__namespace.useMemo(() => {
|
|
1903
|
-
if (!snapPoints || snapPoints.length < 2) {
|
|
1904
|
-
return null;
|
|
1905
|
-
}
|
|
1906
|
-
if (swipeDirection !== 'down' && swipeDirection !== 'up') {
|
|
1907
|
-
return null;
|
|
1908
|
-
}
|
|
1909
|
-
if (resolvedSnapPoints.length < 2) {
|
|
1910
|
-
return null;
|
|
1911
|
-
}
|
|
1912
|
-
const offsets = resolvedSnapPoints.map(point => point.offset).filter(offset => Number.isFinite(offset)).sort((a, b) => a - b);
|
|
1913
|
-
if (offsets.length < 2) {
|
|
1914
|
-
return null;
|
|
1915
|
-
}
|
|
1916
|
-
const minOffset = offsets[0];
|
|
1917
|
-
const nextOffset = offsets[1];
|
|
1918
|
-
const maxOffset = offsets[offsets.length - 1];
|
|
1919
|
-
let range = nextOffset - minOffset;
|
|
1920
|
-
if (!Number.isFinite(range) || range <= 0) {
|
|
1921
|
-
const fallbackRange = maxOffset - minOffset;
|
|
1922
|
-
if (!Number.isFinite(fallbackRange) || fallbackRange <= 0) {
|
|
1923
|
-
return null;
|
|
1924
|
-
}
|
|
1925
|
-
range = fallbackRange;
|
|
1926
|
-
}
|
|
1927
|
-
return {
|
|
1928
|
-
minOffset,
|
|
1929
|
-
range
|
|
1930
|
-
};
|
|
1931
|
-
}, [resolvedSnapPoints, snapPoints, swipeDirection]);
|
|
1932
|
-
const snapPointProgress = React__namespace.useMemo(() => {
|
|
1933
|
-
if (!snapPointRange || activeSnapPointOffset === null) {
|
|
1934
|
-
return null;
|
|
1935
|
-
}
|
|
1936
|
-
return clamp.clamp((activeSnapPointOffset - snapPointRange.minOffset) / snapPointRange.range, 0, 1);
|
|
1937
|
-
}, [activeSnapPointOffset, snapPointRange]);
|
|
1938
|
-
const swipeDirections = React__namespace.useMemo(() => {
|
|
1939
|
-
if (snapPoints && snapPoints.length > 0 && (swipeDirection === 'down' || swipeDirection === 'up')) {
|
|
1940
|
-
return swipeDirection === 'down' ? ['down', 'up'] : ['up', 'down'];
|
|
1941
|
-
}
|
|
1942
|
-
return [swipeDirection];
|
|
1943
|
-
}, [snapPoints, swipeDirection]);
|
|
1944
|
-
const setSwipeDismissed = useButton.useStableCallback(dismissed => {
|
|
1945
|
-
setSwipeDismissedElements(popupRef.current, backdropRef.current, dismissed);
|
|
1946
|
-
});
|
|
1947
|
-
const clearSwipeRelease = useButton.useStableCallback(() => {
|
|
1948
|
-
setSwipeDismissed(false);
|
|
1949
|
-
popupRef.current?.removeAttribute(useButton.TransitionStatusDataAttributes.endingStyle);
|
|
1950
|
-
setSwipeRelease(null);
|
|
1951
|
-
});
|
|
1952
|
-
const finishNestedSwipe = useButton.useStableCallback(() => {
|
|
1953
|
-
if (!nestedSwipeActiveRef.current) {
|
|
1954
|
-
return;
|
|
1955
|
-
}
|
|
1956
|
-
nestedSwipeActiveRef.current = false;
|
|
1957
|
-
notifyParentSwipingChange?.(false);
|
|
1958
|
-
});
|
|
1959
|
-
const applySwipeProgress = useButton.useStableCallback(({
|
|
1960
|
-
resolvedProgress,
|
|
1961
|
-
shouldTrackProgress,
|
|
1962
|
-
notifyParent
|
|
1963
|
-
}) => {
|
|
1964
|
-
const isActive = open && !nested && shouldTrackProgress;
|
|
1965
|
-
const swipeProgress = isActive ? resolvedProgress : 0;
|
|
1966
|
-
const nestedSwipeProgress = open && shouldTrackProgress ? resolvedProgress : 0;
|
|
1967
|
-
if (notifyParent && notifyParentSwipeProgressChange) {
|
|
1968
|
-
notifyParentSwipeProgressChange(nestedSwipeProgress);
|
|
1969
|
-
if (nestedSwipeProgress <= 0) {
|
|
1970
|
-
finishNestedSwipe();
|
|
1971
|
-
}
|
|
1972
|
-
}
|
|
1973
|
-
visualStateStore?.set({
|
|
1974
|
-
swipeProgress,
|
|
1975
|
-
frontmostHeight: swipeProgress > 0 ? frontmostHeight : 0
|
|
1976
|
-
});
|
|
1977
|
-
const backdropElement = backdropRef.current;
|
|
1978
|
-
if (!backdropElement) {
|
|
1979
|
-
return;
|
|
1980
|
-
}
|
|
1981
|
-
if (!isActive || swipeProgress <= 0) {
|
|
1982
|
-
backdropElement.style.setProperty(ScrollAreaViewport.DrawerBackdropCssVars.swipeProgress, '0');
|
|
1983
|
-
backdropElement.style.removeProperty(ScrollAreaViewport.DrawerPopupCssVars.height);
|
|
1984
|
-
return;
|
|
1985
|
-
}
|
|
1986
|
-
backdropElement.style.setProperty(ScrollAreaViewport.DrawerBackdropCssVars.swipeProgress, `${swipeProgress}`);
|
|
1987
|
-
if (frontmostHeight > 0) {
|
|
1988
|
-
backdropElement.style.setProperty(ScrollAreaViewport.DrawerPopupCssVars.height, `${frontmostHeight}px`);
|
|
1989
|
-
} else {
|
|
1990
|
-
backdropElement.style.removeProperty(ScrollAreaViewport.DrawerPopupCssVars.height);
|
|
1991
|
-
}
|
|
1992
|
-
});
|
|
1993
|
-
function resolveSwipeRelease({
|
|
1994
|
-
direction,
|
|
1995
|
-
deltaX,
|
|
1996
|
-
deltaY,
|
|
1997
|
-
velocityX,
|
|
1998
|
-
velocityY,
|
|
1999
|
-
releaseVelocityX,
|
|
2000
|
-
releaseVelocityY
|
|
2001
|
-
}) {
|
|
2002
|
-
if (!direction) {
|
|
2003
|
-
return null;
|
|
2004
|
-
}
|
|
2005
|
-
const popupElement = store.context.popupRef.current;
|
|
2006
|
-
if (!popupElement) {
|
|
2007
|
-
return null;
|
|
2008
|
-
}
|
|
2009
|
-
const size = direction === 'left' || direction === 'right' ? popupElement.offsetWidth : popupElement.offsetHeight;
|
|
2010
|
-
if (!Number.isFinite(size) || size <= 0) {
|
|
2011
|
-
return null;
|
|
2012
|
-
}
|
|
2013
|
-
const axisDelta = direction === 'left' || direction === 'right' ? deltaX : deltaY;
|
|
2014
|
-
const snapPointBaseOffset = snapPoints && snapPoints.length > 0 ? activeSnapPointOffset ?? 0 : 0;
|
|
2015
|
-
let baseOffset = 0;
|
|
2016
|
-
if (direction === 'down') {
|
|
2017
|
-
baseOffset = snapPointBaseOffset;
|
|
2018
|
-
} else if (direction === 'up') {
|
|
2019
|
-
baseOffset = -snapPointBaseOffset;
|
|
2020
|
-
}
|
|
2021
|
-
const translation = baseOffset + axisDelta;
|
|
2022
|
-
const translationAlongDirection = direction === 'left' || direction === 'up' ? -translation : translation;
|
|
2023
|
-
const remainingDistance = Math.max(0, size - translationAlongDirection);
|
|
2024
|
-
if (!Number.isFinite(remainingDistance) || remainingDistance <= 0) {
|
|
2025
|
-
return null;
|
|
2026
|
-
}
|
|
2027
|
-
const axisVelocity = direction === 'left' || direction === 'right' ? releaseVelocityX : releaseVelocityY;
|
|
2028
|
-
const fallbackVelocity = direction === 'left' || direction === 'right' ? velocityX : velocityY;
|
|
2029
|
-
const resolvedVelocity = Math.abs(axisVelocity) > 0 && Number.isFinite(axisVelocity) ? axisVelocity : fallbackVelocity;
|
|
2030
|
-
const directionalVelocity = direction === 'left' || direction === 'up' ? -resolvedVelocity : resolvedVelocity;
|
|
2031
|
-
if (!Number.isFinite(directionalVelocity) || directionalVelocity <= MIN_SWIPE_RELEASE_VELOCITY) {
|
|
2032
|
-
return null;
|
|
2033
|
-
}
|
|
2034
|
-
const clampedVelocity = clamp.clamp(directionalVelocity, MIN_SWIPE_RELEASE_VELOCITY, MAX_SWIPE_RELEASE_VELOCITY);
|
|
2035
|
-
const durationMs = clamp.clamp(remainingDistance / clampedVelocity, MIN_SWIPE_RELEASE_DURATION_MS, MAX_SWIPE_RELEASE_DURATION_MS);
|
|
2036
|
-
if (!Number.isFinite(durationMs)) {
|
|
2037
|
-
return null;
|
|
2038
|
-
}
|
|
2039
|
-
const normalizedDuration = (durationMs - MIN_SWIPE_RELEASE_DURATION_MS) / (MAX_SWIPE_RELEASE_DURATION_MS - MIN_SWIPE_RELEASE_DURATION_MS);
|
|
2040
|
-
const durationScalar = clamp.clamp(MIN_SWIPE_RELEASE_SCALAR + normalizedDuration * (MAX_SWIPE_RELEASE_SCALAR - MIN_SWIPE_RELEASE_SCALAR), MIN_SWIPE_RELEASE_SCALAR, MAX_SWIPE_RELEASE_SCALAR);
|
|
2041
|
-
if (!Number.isFinite(durationScalar) || durationScalar <= 0) {
|
|
2042
|
-
return null;
|
|
2043
|
-
}
|
|
2044
|
-
return durationScalar;
|
|
2045
|
-
}
|
|
2046
|
-
function updateNestedSwipeActive(details) {
|
|
2047
|
-
if (nestedSwipeActiveRef.current || !details) {
|
|
2048
|
-
return;
|
|
2049
|
-
}
|
|
2050
|
-
const direction = details.direction ?? swipeDirection;
|
|
2051
|
-
const delta = direction === 'left' || direction === 'right' ? details.deltaX : details.deltaY;
|
|
2052
|
-
if (!Number.isFinite(delta) || Math.abs(delta) < MIN_SWIPE_THRESHOLD) {
|
|
2053
|
-
return;
|
|
2054
|
-
}
|
|
2055
|
-
nestedSwipeActiveRef.current = true;
|
|
2056
|
-
notifyParentSwipingChange?.(true);
|
|
2057
|
-
}
|
|
2058
|
-
const swipe = useSwipeDismiss({
|
|
2059
|
-
enabled: mounted && !nestedDrawerOpen,
|
|
2060
|
-
directions: swipeDirections,
|
|
2061
|
-
elementRef: store.context.popupRef,
|
|
2062
|
-
ignoreSelectorWhenTouch: false,
|
|
2063
|
-
ignoreScrollableAncestors: true,
|
|
2064
|
-
movementCssVars: {
|
|
2065
|
-
x: ScrollAreaViewport.DrawerPopupCssVars.swipeMovementX,
|
|
2066
|
-
y: ScrollAreaViewport.DrawerPopupCssVars.swipeMovementY
|
|
2067
|
-
},
|
|
2068
|
-
onSwipeStart(event) {
|
|
2069
|
-
if ('touches' in event || 'pointerType' in event && event.pointerType === 'touch') {
|
|
2070
|
-
return;
|
|
2071
|
-
}
|
|
2072
|
-
const popupElement = popupRef.current;
|
|
2073
|
-
if (!popupElement) {
|
|
2074
|
-
return;
|
|
2075
|
-
}
|
|
2076
|
-
const doc = useButton.ownerDocument(popupElement);
|
|
2077
|
-
const selection = doc.getSelection?.();
|
|
2078
|
-
if (!selection || selection.isCollapsed) {
|
|
709
|
+
dragDeltaRef.current.x = details.deltaX;
|
|
710
|
+
dragDeltaRef.current.y = details.deltaY;
|
|
711
|
+
if (details.direction !== resolvedSwipeDirection) {
|
|
2079
712
|
return;
|
|
2080
713
|
}
|
|
2081
|
-
const
|
|
2082
|
-
|
|
2083
|
-
if (!useButton.contains(popupElement, anchorElement) && !useButton.contains(popupElement, focusElement)) {
|
|
714
|
+
const displacement = ScrollAreaViewport.getDisplacement(resolvedSwipeDirection, details.deltaX, details.deltaY);
|
|
715
|
+
if (displacement < MIN_SWIPE_START_DISTANCE && !openedBySwipeRef.current) {
|
|
2084
716
|
return;
|
|
2085
717
|
}
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
onSwipingChange(swiping) {
|
|
2089
|
-
swipingRef.current = swiping;
|
|
2090
|
-
setBackdropSwipingAttribute(store.context.backdropRef.current, swiping);
|
|
2091
|
-
if (!swiping && !notifyParentSwipeProgressChange) {
|
|
2092
|
-
finishNestedSwipe();
|
|
2093
|
-
}
|
|
2094
|
-
},
|
|
2095
|
-
swipeThreshold({
|
|
2096
|
-
element,
|
|
2097
|
-
direction
|
|
2098
|
-
}) {
|
|
2099
|
-
return getBaseSwipeThreshold(element, direction);
|
|
2100
|
-
},
|
|
2101
|
-
canStart(position, details) {
|
|
2102
|
-
const popupElement = store.context.popupRef.current;
|
|
2103
|
-
if (!popupElement) {
|
|
2104
|
-
return false;
|
|
2105
|
-
}
|
|
2106
|
-
const doc = popupElement.ownerDocument;
|
|
2107
|
-
const elementAtPoint = getElementAtPoint(doc, position.x, position.y);
|
|
2108
|
-
if (!elementAtPoint || !useButton.contains(popupElement, elementAtPoint)) {
|
|
2109
|
-
return false;
|
|
2110
|
-
}
|
|
2111
|
-
const nativeEvent = details.nativeEvent;
|
|
2112
|
-
const touchLike = 'touches' in nativeEvent || 'pointerType' in nativeEvent && nativeEvent.pointerType === 'touch';
|
|
2113
|
-
if (touchLike && shouldIgnoreSwipeForTextSelection(doc, popupElement)) {
|
|
2114
|
-
return false;
|
|
2115
|
-
}
|
|
2116
|
-
if (nativeEvent.type === 'touchstart' && isSwipeIgnoredTarget(elementAtPoint)) {
|
|
2117
|
-
return false;
|
|
2118
|
-
}
|
|
2119
|
-
return true;
|
|
2120
|
-
},
|
|
2121
|
-
onProgress(progress, details) {
|
|
2122
|
-
updateNestedSwipeActive(details);
|
|
2123
|
-
const hasSnapPoints = Boolean(snapPoints && snapPoints.length > 0);
|
|
2124
|
-
if (swipingRef.current && swipeDirection === 'down' && hasSnapPoints && details && Number.isFinite(details.deltaY)) {
|
|
2125
|
-
const popupElement = store.context.popupRef.current;
|
|
2126
|
-
if (popupElement) {
|
|
2127
|
-
popupElement.style.removeProperty('transform');
|
|
2128
|
-
popupElement.style.setProperty(ScrollAreaViewport.DrawerPopupCssVars.swipeMovementY, `${ScrollAreaViewport.getSnapPointSwipeMovement(activeSnapPointOffset ?? 0, details.deltaY)}px`);
|
|
2129
|
-
}
|
|
2130
|
-
}
|
|
2131
|
-
const currentDirection = details?.direction ?? swipe.swipeDirection;
|
|
2132
|
-
const isDismissSwipe = currentDirection === undefined || currentDirection === swipeDirection;
|
|
2133
|
-
const isVerticalSwipe = swipeDirection === 'down' || swipeDirection === 'up';
|
|
2134
|
-
const shouldTrackProgress = hasSnapPoints && isVerticalSwipe || !hasSnapPoints || swipeDirection === 'left' || swipeDirection === 'right' || isDismissSwipe;
|
|
2135
|
-
let resolvedProgress = progress;
|
|
2136
|
-
if (snapPointRange && popupHeight > 0) {
|
|
2137
|
-
if (details && Number.isFinite(details.deltaY)) {
|
|
2138
|
-
const baseOffset = activeSnapPointOffset ?? snapPointRange.minOffset;
|
|
2139
|
-
const nextOffset = clamp.clamp(baseOffset + details.deltaY, 0, popupHeight);
|
|
2140
|
-
resolvedProgress = clamp.clamp((nextOffset - snapPointRange.minOffset) / snapPointRange.range, 0, 1);
|
|
2141
|
-
} else if (snapPointProgress !== null) {
|
|
2142
|
-
resolvedProgress = snapPointProgress;
|
|
2143
|
-
} else if (currentDirection === 'down' || currentDirection === 'up') {
|
|
2144
|
-
const displacement = progress * popupHeight;
|
|
2145
|
-
const baseOffset = activeSnapPointOffset ?? snapPointRange.minOffset;
|
|
2146
|
-
const nextOffset = currentDirection === 'down' ? baseOffset + displacement : baseOffset - displacement;
|
|
2147
|
-
resolvedProgress = clamp.clamp((nextOffset - snapPointRange.minOffset) / snapPointRange.range, 0, 1);
|
|
2148
|
-
}
|
|
718
|
+
if (!openedBySwipeRef.current) {
|
|
719
|
+
openDrawer(swipeStartEventRef.current);
|
|
2149
720
|
}
|
|
2150
|
-
|
|
2151
|
-
resolvedProgress,
|
|
2152
|
-
shouldTrackProgress,
|
|
2153
|
-
notifyParent: true
|
|
2154
|
-
});
|
|
721
|
+
applySwipeMovement();
|
|
2155
722
|
},
|
|
2156
723
|
onRelease({
|
|
2157
724
|
event,
|
|
725
|
+
direction,
|
|
2158
726
|
deltaX,
|
|
2159
727
|
deltaY,
|
|
2160
|
-
direction,
|
|
2161
|
-
velocityX,
|
|
2162
|
-
velocityY,
|
|
2163
728
|
releaseVelocityX,
|
|
2164
729
|
releaseVelocityY
|
|
2165
730
|
}) {
|
|
2166
|
-
const
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
// Start ending transition styles earlier and synchronously to prevent a period where
|
|
2176
|
-
// the popup appears stuck on release before the actual closing animation starts.
|
|
2177
|
-
const popupElement = store.context.popupRef.current;
|
|
2178
|
-
if (!popupElement) {
|
|
2179
|
-
return;
|
|
2180
|
-
}
|
|
2181
|
-
finishNestedSwipe();
|
|
2182
|
-
setSwipeDismissed(true);
|
|
2183
|
-
popupElement.style.removeProperty('transition');
|
|
2184
|
-
popupElement.setAttribute(useButton.TransitionStatusDataAttributes.endingStyle, '');
|
|
2185
|
-
ReactDOM__namespace.flushSync(() => {
|
|
2186
|
-
setSwipeRelease(resolveSwipeRelease({
|
|
2187
|
-
direction: resolvedDirection,
|
|
2188
|
-
...swipeReleasePayload
|
|
2189
|
-
}));
|
|
2190
|
-
});
|
|
2191
|
-
}
|
|
2192
|
-
if (!snapPoints || snapPoints.length === 0) {
|
|
2193
|
-
if (!direction) {
|
|
2194
|
-
clearSwipeRelease();
|
|
2195
|
-
return undefined;
|
|
2196
|
-
}
|
|
2197
|
-
const element = store.context.popupRef.current;
|
|
2198
|
-
if (!element) {
|
|
2199
|
-
clearSwipeRelease();
|
|
2200
|
-
return undefined;
|
|
2201
|
-
}
|
|
2202
|
-
const baseThreshold = getBaseSwipeThreshold(element, direction);
|
|
2203
|
-
const delta = direction === 'left' || direction === 'right' ? deltaX : deltaY;
|
|
2204
|
-
if (!Number.isFinite(delta)) {
|
|
2205
|
-
clearSwipeRelease();
|
|
2206
|
-
return undefined;
|
|
2207
|
-
}
|
|
2208
|
-
const directionalDelta = direction === 'left' || direction === 'up' ? -delta : delta;
|
|
2209
|
-
if (directionalDelta <= 0) {
|
|
2210
|
-
clearSwipeRelease();
|
|
2211
|
-
return false;
|
|
2212
|
-
}
|
|
2213
|
-
const velocity = direction === 'left' || direction === 'right' ? velocityX : velocityY;
|
|
2214
|
-
const directionalVelocity = direction === 'left' || direction === 'up' ? -velocity : velocity;
|
|
2215
|
-
if (directionalVelocity >= FAST_SWIPE_VELOCITY && directionalDelta > 0) {
|
|
2216
|
-
startSwipeRelease(direction);
|
|
2217
|
-
return true;
|
|
2218
|
-
}
|
|
2219
|
-
const shouldClose = directionalDelta > baseThreshold;
|
|
2220
|
-
if (shouldClose) {
|
|
2221
|
-
startSwipeRelease(direction);
|
|
2222
|
-
} else {
|
|
2223
|
-
clearSwipeRelease();
|
|
2224
|
-
}
|
|
2225
|
-
return shouldClose;
|
|
2226
|
-
}
|
|
2227
|
-
if (swipeDirection !== 'down' && swipeDirection !== 'up') {
|
|
2228
|
-
clearSwipeRelease();
|
|
2229
|
-
return undefined;
|
|
2230
|
-
}
|
|
2231
|
-
if (!popupHeight || resolvedSnapPoints.length === 0) {
|
|
2232
|
-
clearSwipeRelease();
|
|
2233
|
-
return undefined;
|
|
2234
|
-
}
|
|
2235
|
-
const dragDelta = swipeDirection === 'down' ? deltaY : -deltaY;
|
|
2236
|
-
if (!Number.isFinite(dragDelta)) {
|
|
2237
|
-
clearSwipeRelease();
|
|
2238
|
-
return undefined;
|
|
2239
|
-
}
|
|
2240
|
-
const dragDirection = Math.sign(dragDelta);
|
|
2241
|
-
const releaseDirectionalVelocity = swipeDirection === 'down' ? releaseVelocityY : -releaseVelocityY;
|
|
2242
|
-
const fallbackDirectionalVelocity = swipeDirection === 'down' ? velocityY : -velocityY;
|
|
2243
|
-
let resolvedDirectionalVelocity = Number.isFinite(releaseDirectionalVelocity) ? releaseDirectionalVelocity : fallbackDirectionalVelocity;
|
|
2244
|
-
if (dragDirection !== 0 && Math.abs(dragDelta) >= MIN_SWIPE_THRESHOLD && Number.isFinite(resolvedDirectionalVelocity)) {
|
|
2245
|
-
const velocityDirection = Math.sign(resolvedDirectionalVelocity);
|
|
2246
|
-
if (velocityDirection !== 0 && velocityDirection !== dragDirection) {
|
|
2247
|
-
// Ignore touch reversals that would otherwise flip the snap decision.
|
|
2248
|
-
resolvedDirectionalVelocity = fallbackDirectionalVelocity;
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
const currentOffset = activeSnapPointOffset ?? 0;
|
|
2252
|
-
const dragTargetOffset = clamp.clamp(currentOffset + dragDelta, 0, popupHeight);
|
|
2253
|
-
const velocityOffset = Number.isFinite(resolvedDirectionalVelocity) && Math.abs(resolvedDirectionalVelocity) >= SNAP_VELOCITY_THRESHOLD ? clamp.clamp(resolvedDirectionalVelocity, -MAX_SNAP_VELOCITY, MAX_SNAP_VELOCITY) * SNAP_VELOCITY_MULTIPLIER : 0;
|
|
2254
|
-
const targetOffset = snapToSequentialPoints ? dragTargetOffset : clamp.clamp(dragTargetOffset + velocityOffset, 0, popupHeight);
|
|
2255
|
-
const snapPointEventDetails = useButton.createChangeEventDetails(useButton.swipe, event);
|
|
2256
|
-
const closeFromSnapPoints = () => {
|
|
2257
|
-
pendingSwipeCloseSnapPointRef.current = activeSnapPoint;
|
|
2258
|
-
setActiveSnapPoint?.(null, snapPointEventDetails);
|
|
2259
|
-
startSwipeRelease(swipeDirection);
|
|
2260
|
-
return true;
|
|
2261
|
-
};
|
|
2262
|
-
if (snapToSequentialPoints) {
|
|
2263
|
-
const orderedSnapPoints = [...resolvedSnapPoints].sort((first, second) => first.offset - second.offset);
|
|
2264
|
-
if (orderedSnapPoints.length === 0) {
|
|
2265
|
-
clearSwipeRelease();
|
|
2266
|
-
return false;
|
|
2267
|
-
}
|
|
2268
|
-
let currentIndex = 0;
|
|
2269
|
-
let closestDistance = Math.abs(currentOffset - orderedSnapPoints[0].offset);
|
|
2270
|
-
for (let index = 1; index < orderedSnapPoints.length; index += 1) {
|
|
2271
|
-
const distance = Math.abs(currentOffset - orderedSnapPoints[index].offset);
|
|
2272
|
-
if (distance < closestDistance) {
|
|
2273
|
-
closestDistance = distance;
|
|
2274
|
-
currentIndex = index;
|
|
2275
|
-
}
|
|
2276
|
-
}
|
|
2277
|
-
let targetSnapPoint = orderedSnapPoints[0];
|
|
2278
|
-
closestDistance = Math.abs(targetOffset - targetSnapPoint.offset);
|
|
2279
|
-
for (const snapPoint of orderedSnapPoints) {
|
|
2280
|
-
const distance = Math.abs(targetOffset - snapPoint.offset);
|
|
2281
|
-
if (distance < closestDistance) {
|
|
2282
|
-
closestDistance = distance;
|
|
2283
|
-
targetSnapPoint = snapPoint;
|
|
2284
|
-
}
|
|
2285
|
-
}
|
|
2286
|
-
const velocityDirection = Math.sign(resolvedDirectionalVelocity);
|
|
2287
|
-
const shouldAdvance = dragDirection !== 0 && velocityDirection !== 0 && velocityDirection === dragDirection && Math.abs(resolvedDirectionalVelocity) >= SNAP_VELOCITY_THRESHOLD;
|
|
2288
|
-
let effectiveTargetOffset = targetOffset;
|
|
2289
|
-
if (shouldAdvance) {
|
|
2290
|
-
const adjacentIndex = clamp.clamp(currentIndex + dragDirection, 0, orderedSnapPoints.length - 1);
|
|
2291
|
-
if (adjacentIndex !== currentIndex) {
|
|
2292
|
-
const adjacentPoint = orderedSnapPoints[adjacentIndex];
|
|
2293
|
-
const shouldForceAdjacent = dragDirection > 0 ? targetOffset < adjacentPoint.offset : targetOffset > adjacentPoint.offset;
|
|
2294
|
-
if (shouldForceAdjacent) {
|
|
2295
|
-
targetSnapPoint = adjacentPoint;
|
|
2296
|
-
effectiveTargetOffset = adjacentPoint.offset;
|
|
2297
|
-
}
|
|
2298
|
-
} else if (dragDirection > 0) {
|
|
2299
|
-
return closeFromSnapPoints();
|
|
2300
|
-
}
|
|
2301
|
-
}
|
|
2302
|
-
const closeOffset = popupHeight;
|
|
2303
|
-
const closeDistance = Math.abs(effectiveTargetOffset - closeOffset);
|
|
2304
|
-
const snapDistance = Math.abs(effectiveTargetOffset - targetSnapPoint.offset);
|
|
2305
|
-
if (closeDistance < snapDistance) {
|
|
2306
|
-
return closeFromSnapPoints();
|
|
2307
|
-
}
|
|
2308
|
-
setActiveSnapPoint?.(targetSnapPoint.value, snapPointEventDetails);
|
|
2309
|
-
clearSwipeRelease();
|
|
2310
|
-
return false;
|
|
2311
|
-
}
|
|
2312
|
-
if (resolvedDirectionalVelocity >= FAST_SWIPE_VELOCITY && dragDelta > 0) {
|
|
2313
|
-
return closeFromSnapPoints();
|
|
2314
|
-
}
|
|
2315
|
-
let closestSnapPoint = resolvedSnapPoints[0];
|
|
2316
|
-
let closestDistance = Math.abs(targetOffset - closestSnapPoint.offset);
|
|
2317
|
-
for (const snapPoint of resolvedSnapPoints) {
|
|
2318
|
-
const distance = Math.abs(targetOffset - snapPoint.offset);
|
|
2319
|
-
if (distance < closestDistance) {
|
|
2320
|
-
closestDistance = distance;
|
|
2321
|
-
closestSnapPoint = snapPoint;
|
|
731
|
+
const displacement = ScrollAreaViewport.getDisplacement(resolvedSwipeDirection, deltaX, deltaY);
|
|
732
|
+
const releaseVelocity = ScrollAreaViewport.getDisplacement(resolvedSwipeDirection, releaseVelocityX, releaseVelocityY);
|
|
733
|
+
const threshold = resolveSwipeOpenThreshold();
|
|
734
|
+
const hasEnoughDistance = threshold != null && displacement >= threshold;
|
|
735
|
+
const hasEnoughVelocity = releaseVelocity >= VELOCITY_THRESHOLD;
|
|
736
|
+
const shouldOpen = threshold != null && direction === resolvedSwipeDirection && (hasEnoughDistance || hasEnoughVelocity) && !disabled;
|
|
737
|
+
if (shouldOpen) {
|
|
738
|
+
if (!store.select('open')) {
|
|
739
|
+
openDrawer(event);
|
|
2322
740
|
}
|
|
741
|
+
} else if (openedBySwipeRef.current) {
|
|
742
|
+
closeDrawer(event);
|
|
2323
743
|
}
|
|
2324
|
-
|
|
2325
|
-
const closeDistance = Math.abs(targetOffset - closeOffset);
|
|
2326
|
-
if (closeDistance < closestDistance) {
|
|
2327
|
-
return closeFromSnapPoints();
|
|
2328
|
-
}
|
|
2329
|
-
setActiveSnapPoint?.(closestSnapPoint.value, snapPointEventDetails);
|
|
2330
|
-
clearSwipeRelease();
|
|
744
|
+
finishSwipeInteraction();
|
|
2331
745
|
return false;
|
|
2332
746
|
},
|
|
2333
|
-
|
|
2334
|
-
visualStateStore?.set({
|
|
2335
|
-
swipeProgress: 0,
|
|
2336
|
-
frontmostHeight: 0
|
|
2337
|
-
});
|
|
2338
|
-
const backdropElement = store.context.backdropRef.current;
|
|
2339
|
-
if (backdropElement) {
|
|
2340
|
-
backdropElement.style.setProperty(ScrollAreaViewport.DrawerBackdropCssVars.swipeProgress, '0');
|
|
2341
|
-
backdropElement.style.removeProperty(ScrollAreaViewport.DrawerPopupCssVars.height);
|
|
2342
|
-
}
|
|
2343
|
-
const dismissEventDetails = useButton.createChangeEventDetails(useButton.swipe, event);
|
|
2344
|
-
store.setOpen(false, dismissEventDetails);
|
|
2345
|
-
if (dismissEventDetails.isCanceled) {
|
|
2346
|
-
const pendingSnapPoint = pendingSwipeCloseSnapPointRef.current;
|
|
2347
|
-
if (pendingSnapPoint !== undefined) {
|
|
2348
|
-
setActiveSnapPoint?.(pendingSnapPoint, useButton.createChangeEventDetails(useButton.swipe, event));
|
|
2349
|
-
}
|
|
2350
|
-
pendingSwipeCloseSnapPointRef.current = undefined;
|
|
2351
|
-
resetSwipeRef.current?.();
|
|
2352
|
-
clearSwipeRelease();
|
|
2353
|
-
return;
|
|
2354
|
-
}
|
|
2355
|
-
|
|
2356
|
-
// In controlled mode, the effective open state may not have changed yet
|
|
2357
|
-
// (openProp takes precedence over state.open). Proceed optimistically with the
|
|
2358
|
-
// dismiss animation — React's Scheduler flushes before the next rAF, so we can
|
|
2359
|
-
// reliably check whether the parent accepted or rejected the close.
|
|
2360
|
-
// Note: if onOpenChange is asynchronous (e.g., closes the drawer after a network
|
|
2361
|
-
// call), the rAF check will see open === true, revert the animation, and the
|
|
2362
|
-
// drawer will close without animation when the parent eventually sets open={false}.
|
|
2363
|
-
if (store.select('open')) {
|
|
2364
|
-
const savedEvent = event;
|
|
2365
|
-
controlledDismissFrame.request(() => {
|
|
2366
|
-
if (store.select('open')) {
|
|
2367
|
-
// Parent rejected: revert animation and restore snap point.
|
|
2368
|
-
const pendingSnapPoint = pendingSwipeCloseSnapPointRef.current;
|
|
2369
|
-
if (pendingSnapPoint !== undefined) {
|
|
2370
|
-
setActiveSnapPoint?.(pendingSnapPoint, useButton.createChangeEventDetails(useButton.swipe, savedEvent));
|
|
2371
|
-
}
|
|
2372
|
-
pendingSwipeCloseSnapPointRef.current = undefined;
|
|
2373
|
-
clearSwipeRelease();
|
|
2374
|
-
resetSwipeRef.current?.();
|
|
2375
|
-
} else {
|
|
2376
|
-
// Parent accepted: clean up the ref.
|
|
2377
|
-
pendingSwipeCloseSnapPointRef.current = undefined;
|
|
2378
|
-
}
|
|
2379
|
-
});
|
|
2380
|
-
return;
|
|
2381
|
-
}
|
|
2382
|
-
pendingSwipeCloseSnapPointRef.current = undefined;
|
|
2383
|
-
setSwipeDismissed(true);
|
|
2384
|
-
}
|
|
747
|
+
onCancel: finishSwipeInteraction
|
|
2385
748
|
});
|
|
2386
749
|
const swipePointerProps = swipe.getPointerProps();
|
|
2387
750
|
const swipeTouchProps = swipe.getTouchProps();
|
|
2388
|
-
const
|
|
2389
|
-
moveNative: moveSwipeNative,
|
|
2390
|
-
reset: resetSwipe
|
|
2391
|
-
} = swipe;
|
|
2392
|
-
resetSwipeRef.current = resetSwipe;
|
|
2393
|
-
React__namespace.useEffect(() => {
|
|
2394
|
-
const rootElement = viewportElement ?? popupElementState;
|
|
2395
|
-
if (!rootElement) {
|
|
2396
|
-
return undefined;
|
|
2397
|
-
}
|
|
2398
|
-
const resolvedRootElement = rootElement;
|
|
2399
|
-
const doc = useButton.ownerDocument(resolvedRootElement);
|
|
2400
|
-
const win = floatingUi_utils_dom.getWindow(doc);
|
|
2401
|
-
function handleNativeTouchMove(event) {
|
|
2402
|
-
// The virtual keyboard provider observes the move to tell a tap apart from a drag.
|
|
2403
|
-
// It must run even when the swipe gesture below claims the event with
|
|
2404
|
-
// `stopPropagation()`, which would otherwise prevent React's delegated handlers
|
|
2405
|
-
// (and the provider) from ever seeing the move.
|
|
2406
|
-
virtualKeyboard?.onTouchMove(event);
|
|
2407
|
-
if (ignoreTouchSwipeRef.current) {
|
|
2408
|
-
return;
|
|
2409
|
-
}
|
|
2410
|
-
const touchState = touchScrollStateRef.current;
|
|
2411
|
-
const touch = event.touches[0];
|
|
2412
|
-
if (!touch || !touchState) {
|
|
2413
|
-
return;
|
|
2414
|
-
}
|
|
2415
|
-
const drawerAxisDelta = isVerticalScrollAxis ? touch.clientY - touchState.lastY : touch.clientX - touchState.lastX;
|
|
2416
|
-
|
|
2417
|
-
// Preserve native range interaction by never locking touchmove for range inputs.
|
|
2418
|
-
if (isEventOnRangeInput(event, win)) {
|
|
2419
|
-
touchState.allowSwipe = false;
|
|
2420
|
-
updateTouchScrollPosition(touchState, touch);
|
|
2421
|
-
return;
|
|
2422
|
-
}
|
|
2423
|
-
|
|
2424
|
-
// Avoid blocking pinch zoom or text selection adjustments on iOS Safari.
|
|
2425
|
-
if (event.touches.length === 2) {
|
|
2426
|
-
updateTouchScrollPosition(touchState, touch);
|
|
2427
|
-
return;
|
|
2428
|
-
}
|
|
2429
|
-
const allowTouchMove = shouldIgnoreSwipeForTextSelection(doc, resolvedRootElement);
|
|
2430
|
-
if (allowTouchMove || !open || !mounted || nestedDrawerOpen) {
|
|
2431
|
-
updateTouchScrollPosition(touchState, touch);
|
|
2432
|
-
return;
|
|
2433
|
-
}
|
|
2434
|
-
if (preserveNativeCrossAxisScrollOnMove(touchState, touch, isVerticalScrollAxis)) {
|
|
2435
|
-
updateTouchScrollPosition(touchState, touch);
|
|
2436
|
-
return;
|
|
2437
|
-
}
|
|
2438
|
-
const scrollTarget = touchState.scrollTarget;
|
|
2439
|
-
if (!scrollTarget || scrollTarget === doc.documentElement || scrollTarget === doc.body) {
|
|
2440
|
-
if (event.cancelable) {
|
|
2441
|
-
event.preventDefault();
|
|
2442
|
-
}
|
|
2443
|
-
// Claim the gesture before React's delegated touch handlers see it; dispatching the
|
|
2444
|
-
// move through React re-rasterizes the popup content on every frame.
|
|
2445
|
-
event.stopPropagation();
|
|
2446
|
-
moveSwipeNative(event, resolvedRootElement);
|
|
2447
|
-
updateTouchScrollPosition(touchState, touch);
|
|
2448
|
-
return;
|
|
2449
|
-
}
|
|
2450
|
-
const hasScrollableContent = hasScrollableContentOnAxis(scrollTarget, scrollAxis);
|
|
2451
|
-
if (!hasScrollableContent) {
|
|
2452
|
-
// If the scroll container doesn't overflow on the drawer axis, prevent the window from
|
|
2453
|
-
// scrolling instead.
|
|
2454
|
-
if (event.cancelable) {
|
|
2455
|
-
event.preventDefault();
|
|
2456
|
-
}
|
|
2457
|
-
event.stopPropagation();
|
|
2458
|
-
updateTouchScrollPosition(touchState, touch);
|
|
2459
|
-
return;
|
|
2460
|
-
}
|
|
2461
|
-
const delta = drawerAxisDelta;
|
|
2462
|
-
if (delta !== 0) {
|
|
2463
|
-
const canSwipeFromScrollEdge = canSwipeFromScrollEdgeOnMove(scrollTarget, scrollAxis, swipeDirection, delta);
|
|
2464
|
-
if (!touchState.allowSwipe) {
|
|
2465
|
-
if (!event.cancelable) {
|
|
2466
|
-
touchState.allowSwipe = false;
|
|
2467
|
-
} else if (canSwipeFromScrollEdge) {
|
|
2468
|
-
touchState.allowSwipe = true;
|
|
2469
|
-
event.preventDefault();
|
|
2470
|
-
} else {
|
|
2471
|
-
touchState.allowSwipe = false;
|
|
2472
|
-
}
|
|
2473
|
-
} else if (event.cancelable) {
|
|
2474
|
-
event.preventDefault();
|
|
2475
|
-
}
|
|
2476
|
-
}
|
|
2477
|
-
if (touchState.allowSwipe === true) {
|
|
2478
|
-
event.stopPropagation();
|
|
2479
|
-
moveSwipeNative(event, resolvedRootElement);
|
|
2480
|
-
}
|
|
2481
|
-
updateTouchScrollPosition(touchState, touch);
|
|
2482
|
-
}
|
|
2483
|
-
return useButton.addEventListener(doc, 'touchmove', handleNativeTouchMove, {
|
|
2484
|
-
passive: false,
|
|
2485
|
-
capture: true
|
|
2486
|
-
});
|
|
2487
|
-
}, [mounted, nestedDrawerOpen, open, popupElementState, isVerticalScrollAxis, scrollAxis, swipeDirection, moveSwipeNative, viewportElement, virtualKeyboard]);
|
|
2488
|
-
React__namespace.useEffect(() => {
|
|
2489
|
-
if (!snapPointRange || swipe.swiping) {
|
|
2490
|
-
return;
|
|
2491
|
-
}
|
|
2492
|
-
const resolvedProgress = !open || nested ? 0 : snapPointProgress ?? 0;
|
|
2493
|
-
applySwipeProgress({
|
|
2494
|
-
resolvedProgress,
|
|
2495
|
-
shouldTrackProgress: true,
|
|
2496
|
-
notifyParent: false
|
|
2497
|
-
});
|
|
2498
|
-
}, [applySwipeProgress, frontmostHeight, nested, notifyParentSwipeProgressChange, open, snapPointProgress, snapPointRange, swipe.swiping, store, visualStateStore]);
|
|
2499
|
-
React__namespace.useEffect(() => {
|
|
2500
|
-
if (!notifyParentSwipeProgressChange) {
|
|
2501
|
-
return undefined;
|
|
2502
|
-
}
|
|
2503
|
-
if (!open) {
|
|
2504
|
-
notifyParentSwipeProgressChange(0);
|
|
2505
|
-
}
|
|
2506
|
-
return () => {
|
|
2507
|
-
notifyParentSwipeProgressChange(0);
|
|
2508
|
-
};
|
|
2509
|
-
}, [notifyParentSwipeProgressChange, open]);
|
|
751
|
+
const resetSwipe = swipe.reset;
|
|
2510
752
|
React__namespace.useEffect(() => {
|
|
2511
|
-
if (
|
|
753
|
+
if (!enabled) {
|
|
2512
754
|
resetSwipe();
|
|
2513
|
-
|
|
755
|
+
resetDragDelta();
|
|
756
|
+
clearSwipeStyles();
|
|
757
|
+
resetSwipeInteractionState();
|
|
2514
758
|
}
|
|
2515
|
-
}, [
|
|
759
|
+
}, [clearSwipeStyles, enabled, resetDragDelta, resetSwipe]);
|
|
2516
760
|
React__namespace.useEffect(() => {
|
|
2517
|
-
const backdropElement = backdropRef.current;
|
|
2518
761
|
return () => {
|
|
2519
|
-
|
|
2520
|
-
swipeProgress: 0,
|
|
2521
|
-
frontmostHeight: 0
|
|
2522
|
-
});
|
|
2523
|
-
setBackdropSwipingAttribute(backdropElement, false);
|
|
2524
|
-
// `data-swiping` is set on whichever backdrop is current when a swipe starts, which can
|
|
2525
|
-
// differ from the captured element if the backdrop mounted late or changed identity.
|
|
2526
|
-
// Reading the live ref here is intentional so the current backdrop is cleared too.
|
|
2527
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2528
|
-
const currentBackdrop = backdropRef.current;
|
|
2529
|
-
if (currentBackdrop !== backdropElement) {
|
|
2530
|
-
setBackdropSwipingAttribute(currentBackdrop, false);
|
|
2531
|
-
}
|
|
2532
|
-
finishNestedSwipe();
|
|
762
|
+
store.context.outsidePressEnabledRef.current = true;
|
|
2533
763
|
};
|
|
2534
|
-
}, [
|
|
2535
|
-
const
|
|
764
|
+
}, [store]);
|
|
765
|
+
const state = {
|
|
766
|
+
open,
|
|
2536
767
|
swiping: swipe.swiping,
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
render: render,
|
|
2552
|
-
...useRenderElement.mergeProps(elementProps, {
|
|
768
|
+
swipeDirection: resolvedSwipeDirection,
|
|
769
|
+
disabled
|
|
770
|
+
};
|
|
771
|
+
return useRenderElement.useRenderElement('div', componentProps, {
|
|
772
|
+
state,
|
|
773
|
+
ref: [forwardedRef, swipeAreaRef, registerTrigger],
|
|
774
|
+
stateAttributesMapping: stateAttributesMapping$3,
|
|
775
|
+
props: [{
|
|
776
|
+
role: 'presentation',
|
|
777
|
+
'aria-hidden': true,
|
|
778
|
+
style: {
|
|
779
|
+
pointerEvents: !enabled ? 'none' : undefined,
|
|
780
|
+
touchAction: resolveTouchAction(resolvedSwipeDirection)
|
|
781
|
+
},
|
|
2553
782
|
onPointerDown(event) {
|
|
2554
|
-
lastPointerTypeRef.current = event.pointerType;
|
|
2555
|
-
ignoreNextTouchStartFromPenRef.current = event.pointerType === 'pen';
|
|
2556
|
-
if (!open || !mounted || nestedDrawerOpen) {
|
|
2557
|
-
return;
|
|
2558
|
-
}
|
|
2559
|
-
const doc = useButton.ownerDocument(event.currentTarget);
|
|
2560
|
-
const elementAtPoint = getElementAtPoint(doc, event.clientX, event.clientY);
|
|
2561
|
-
if (isSwipeIgnoredTarget(elementAtPoint) || isDrawerContentTarget(elementAtPoint)) {
|
|
2562
|
-
return;
|
|
2563
|
-
}
|
|
2564
783
|
if (event.pointerType === 'touch') {
|
|
2565
784
|
return;
|
|
2566
785
|
}
|
|
2567
786
|
swipePointerProps.onPointerDown?.(event);
|
|
787
|
+
|
|
788
|
+
// Prevent native text selection/drag gestures from competing with swipe-open dragging.
|
|
789
|
+
if (event.cancelable) {
|
|
790
|
+
event.preventDefault();
|
|
791
|
+
}
|
|
2568
792
|
},
|
|
2569
793
|
onPointerMove(event) {
|
|
2570
794
|
if (event.pointerType === 'touch') {
|
|
@@ -2573,258 +797,23 @@ const DrawerViewport = /*#__PURE__*/React__namespace.forwardRef(function DrawerV
|
|
|
2573
797
|
swipePointerProps.onPointerMove?.(event);
|
|
2574
798
|
},
|
|
2575
799
|
onPointerUp(event) {
|
|
2576
|
-
if (lastPointerTypeRef.current === event.pointerType) {
|
|
2577
|
-
lastPointerTypeRef.current = '';
|
|
2578
|
-
}
|
|
2579
800
|
if (event.pointerType === 'touch') {
|
|
2580
801
|
return;
|
|
2581
802
|
}
|
|
2582
803
|
swipePointerProps.onPointerUp?.(event);
|
|
2583
804
|
},
|
|
2584
805
|
onPointerCancel(event) {
|
|
2585
|
-
if (lastPointerTypeRef.current === event.pointerType) {
|
|
2586
|
-
lastPointerTypeRef.current = '';
|
|
2587
|
-
}
|
|
2588
806
|
if (event.pointerType === 'touch') {
|
|
2589
807
|
return;
|
|
2590
808
|
}
|
|
2591
809
|
swipePointerProps.onPointerCancel?.(event);
|
|
2592
|
-
}
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
ignoreNextTouchStartFromPenRef.current = false;
|
|
2597
|
-
ignoreTouchSwipeRef.current = false;
|
|
2598
|
-
touchScrollStateRef.current = null;
|
|
2599
|
-
return;
|
|
2600
|
-
}
|
|
2601
|
-
if (!open || !mounted || nestedDrawerOpen) {
|
|
2602
|
-
ignoreTouchSwipeRef.current = false;
|
|
2603
|
-
touchScrollStateRef.current = null;
|
|
2604
|
-
return;
|
|
2605
|
-
}
|
|
2606
|
-
const touch = event.touches[0];
|
|
2607
|
-
if (!touch) {
|
|
2608
|
-
return;
|
|
2609
|
-
}
|
|
2610
|
-
if (isReactTouchEventOnRangeInput(event)) {
|
|
2611
|
-
ignoreTouchSwipeRef.current = false;
|
|
2612
|
-
touchScrollStateRef.current = null;
|
|
2613
|
-
return;
|
|
2614
|
-
}
|
|
2615
|
-
const doc = useButton.ownerDocument(event.currentTarget);
|
|
2616
|
-
const elementAtPoint = getElementAtPoint(doc, touch.clientX, touch.clientY);
|
|
2617
|
-
const rootElement = viewportElement ?? popupElementState;
|
|
2618
|
-
const eventTarget = useButton.getTarget(event.nativeEvent);
|
|
2619
|
-
const target = floatingUi_utils_dom.isElement(eventTarget) ? eventTarget : null;
|
|
2620
|
-
if (rootElement && target && !useButton.contains(rootElement, target)) {
|
|
2621
|
-
ignoreTouchSwipeRef.current = true;
|
|
2622
|
-
touchScrollStateRef.current = null;
|
|
2623
|
-
return;
|
|
2624
|
-
}
|
|
2625
|
-
virtualKeyboard?.onTouchStart(event);
|
|
2626
|
-
ignoreTouchSwipeRef.current = isSwipeIgnoredTarget(elementAtPoint);
|
|
2627
|
-
if (ignoreTouchSwipeRef.current) {
|
|
2628
|
-
touchScrollStateRef.current = null;
|
|
2629
|
-
return;
|
|
2630
|
-
}
|
|
2631
|
-
let scrollTarget = null;
|
|
2632
|
-
let hasCrossAxisScrollableContent = false;
|
|
2633
|
-
if (rootElement && target) {
|
|
2634
|
-
scrollTarget = findScrollableTouchTarget(target, rootElement, scrollAxis);
|
|
2635
|
-
hasCrossAxisScrollableContent = findScrollableTouchTarget(target, rootElement, crossScrollAxis) != null;
|
|
2636
|
-
}
|
|
2637
|
-
let allowSwipe = null;
|
|
2638
|
-
if (scrollTarget) {
|
|
2639
|
-
const canSwipeFromEdge = isAtSwipeStartEdge(scrollTarget, scrollAxis, swipeDirection);
|
|
2640
|
-
allowSwipe = canSwipeFromEdge ? null : false;
|
|
2641
|
-
}
|
|
2642
|
-
touchScrollStateRef.current = {
|
|
2643
|
-
startX: touch.clientX,
|
|
2644
|
-
startY: touch.clientY,
|
|
2645
|
-
lastX: touch.clientX,
|
|
2646
|
-
lastY: touch.clientY,
|
|
2647
|
-
scrollTarget,
|
|
2648
|
-
hasCrossAxisScrollableContent,
|
|
2649
|
-
allowSwipe,
|
|
2650
|
-
preserveNativeCrossAxisScroll: false
|
|
2651
|
-
};
|
|
2652
|
-
swipeTouchProps.onTouchStart?.(event);
|
|
2653
|
-
},
|
|
2654
|
-
onTouchEnd(event) {
|
|
2655
|
-
virtualKeyboard?.onTouchEnd(event);
|
|
2656
|
-
resetTouchTrackingState();
|
|
2657
|
-
swipeTouchProps.onTouchEnd?.(event);
|
|
2658
|
-
},
|
|
2659
|
-
onTouchCancel(event) {
|
|
2660
|
-
virtualKeyboard?.onTouchCancel();
|
|
2661
|
-
resetTouchTrackingState();
|
|
2662
|
-
swipeTouchProps.onTouchCancel?.(event);
|
|
2663
|
-
},
|
|
2664
|
-
// Drawer popups use drawer-specific nested state attributes.
|
|
2665
|
-
// Suppress DialogViewport's generic nested dialog attribute.
|
|
2666
|
-
['data-nested-dialog-open']: undefined
|
|
2667
|
-
}),
|
|
2668
|
-
children: /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.DrawerViewportContext.Provider, {
|
|
2669
|
-
value: swipeProviderValue,
|
|
2670
|
-
children: children
|
|
2671
|
-
})
|
|
810
|
+
}
|
|
811
|
+
}, swipeTouchProps, swipeAreaId ? {
|
|
812
|
+
id: swipeAreaId
|
|
813
|
+
} : undefined, elementProps]
|
|
2672
814
|
});
|
|
2673
815
|
});
|
|
2674
|
-
if (process.env.NODE_ENV !== "production")
|
|
2675
|
-
function setSwipeDismissedElements(popupElement, backdropElement, dismissed) {
|
|
2676
|
-
if (dismissed) {
|
|
2677
|
-
popupElement?.setAttribute(ScrollAreaViewport.DrawerPopupDataAttributes.swipeDismiss, '');
|
|
2678
|
-
backdropElement?.setAttribute(ScrollAreaViewport.DrawerPopupDataAttributes.swipeDismiss, '');
|
|
2679
|
-
return;
|
|
2680
|
-
}
|
|
2681
|
-
popupElement?.removeAttribute(ScrollAreaViewport.DrawerPopupDataAttributes.swipeDismiss);
|
|
2682
|
-
backdropElement?.removeAttribute(ScrollAreaViewport.DrawerPopupDataAttributes.swipeDismiss);
|
|
2683
|
-
}
|
|
2684
|
-
function setBackdropSwipingAttribute(backdropElement, swiping) {
|
|
2685
|
-
if (!backdropElement) {
|
|
2686
|
-
return;
|
|
2687
|
-
}
|
|
2688
|
-
if (swiping) {
|
|
2689
|
-
backdropElement.setAttribute(ScrollAreaViewport.DrawerPopupDataAttributes.swiping, '');
|
|
2690
|
-
return;
|
|
2691
|
-
}
|
|
2692
|
-
backdropElement.removeAttribute(ScrollAreaViewport.DrawerPopupDataAttributes.swiping);
|
|
2693
|
-
}
|
|
2694
|
-
function isSwipeIgnoredTarget(target) {
|
|
2695
|
-
return Boolean(target?.closest(useScrollLock.BASE_UI_SWIPE_IGNORE_SELECTOR));
|
|
2696
|
-
}
|
|
2697
|
-
function isDrawerContentTarget(target) {
|
|
2698
|
-
return Boolean(target?.closest(DRAWER_CONTENT_SELECTOR));
|
|
2699
|
-
}
|
|
2700
|
-
function getBaseSwipeThreshold(element, direction) {
|
|
2701
|
-
const size = direction === 'left' || direction === 'right' ? element.offsetWidth : element.offsetHeight;
|
|
2702
|
-
return Math.max(size * 0.5, MIN_SWIPE_THRESHOLD);
|
|
2703
|
-
}
|
|
2704
|
-
function isRangeInput(target, win) {
|
|
2705
|
-
return target instanceof win.HTMLInputElement && target.type === 'range';
|
|
2706
|
-
}
|
|
2707
|
-
function isTextSelectionControl(target) {
|
|
2708
|
-
if (!floatingUi_utils_dom.isElement(target)) {
|
|
2709
|
-
return false;
|
|
2710
|
-
}
|
|
2711
|
-
return target.tagName === 'INPUT' || target.tagName === 'TEXTAREA';
|
|
2712
|
-
}
|
|
2713
|
-
function hasExpandedSelectionWithinTarget(selection, target) {
|
|
2714
|
-
const anchorElement = floatingUi_utils_dom.isElement(selection.anchorNode) ? selection.anchorNode : selection.anchorNode?.parentElement;
|
|
2715
|
-
const focusElement = floatingUi_utils_dom.isElement(selection.focusNode) ? selection.focusNode : selection.focusNode?.parentElement;
|
|
2716
|
-
return selection.containsNode(target, true) || useButton.contains(target, anchorElement) || useButton.contains(target, focusElement);
|
|
2717
|
-
}
|
|
2718
|
-
function shouldIgnoreSwipeForTextSelection(doc, rootElement) {
|
|
2719
|
-
const activeEl = useButton.activeElement(doc);
|
|
2720
|
-
const activeElementWithinRoot = Boolean(activeEl && useButton.contains(rootElement, activeEl));
|
|
2721
|
-
if (activeElementWithinRoot && isTextSelectionControl(activeEl)) {
|
|
2722
|
-
const {
|
|
2723
|
-
selectionStart,
|
|
2724
|
-
selectionEnd
|
|
2725
|
-
} = activeEl;
|
|
2726
|
-
if (selectionStart != null && selectionEnd != null && selectionStart < selectionEnd) {
|
|
2727
|
-
return true;
|
|
2728
|
-
}
|
|
2729
|
-
}
|
|
2730
|
-
const selection = doc.getSelection?.();
|
|
2731
|
-
if (!selection || selection.isCollapsed) {
|
|
2732
|
-
return false;
|
|
2733
|
-
}
|
|
2734
|
-
return hasExpandedSelectionWithinTarget(selection, rootElement);
|
|
2735
|
-
}
|
|
2736
|
-
function isEventOnRangeInput(event, win) {
|
|
2737
|
-
const composedPath = event.composedPath();
|
|
2738
|
-
if (composedPath) {
|
|
2739
|
-
return composedPath.some(pathTarget => isRangeInput(pathTarget, win));
|
|
2740
|
-
}
|
|
2741
|
-
return isRangeInput(useButton.getTarget(event), win);
|
|
2742
|
-
}
|
|
2743
|
-
function isReactTouchEventOnRangeInput(event) {
|
|
2744
|
-
return isEventOnRangeInput(event.nativeEvent, floatingUi_utils_dom.getWindow(event.currentTarget));
|
|
2745
|
-
}
|
|
2746
|
-
function updateTouchScrollPosition(touchState, touch) {
|
|
2747
|
-
touchState.lastX = touch.clientX;
|
|
2748
|
-
touchState.lastY = touch.clientY;
|
|
2749
|
-
}
|
|
2750
|
-
function preserveNativeCrossAxisScrollOnMove(touchState, touch, isVerticalScrollAxis) {
|
|
2751
|
-
if (touchState.preserveNativeCrossAxisScroll) {
|
|
2752
|
-
return true;
|
|
2753
|
-
}
|
|
2754
|
-
if (touchState.allowSwipe === true || !touchState.hasCrossAxisScrollableContent) {
|
|
2755
|
-
return false;
|
|
2756
|
-
}
|
|
2757
|
-
const drawerAxisGestureDelta = isVerticalScrollAxis ? touch.clientY - touchState.startY : touch.clientX - touchState.startX;
|
|
2758
|
-
const crossAxisGestureDelta = isVerticalScrollAxis ? touch.clientX - touchState.startX : touch.clientY - touchState.startY;
|
|
2759
|
-
const absDrawerAxisGestureDelta = Math.abs(drawerAxisGestureDelta);
|
|
2760
|
-
const absCrossAxisGestureDelta = Math.abs(crossAxisGestureDelta);
|
|
2761
|
-
if (absCrossAxisGestureDelta < 6 || absCrossAxisGestureDelta <= absDrawerAxisGestureDelta + 2) {
|
|
2762
|
-
return false;
|
|
2763
|
-
}
|
|
2764
|
-
touchState.preserveNativeCrossAxisScroll = true;
|
|
2765
|
-
return true;
|
|
2766
|
-
}
|
|
2767
|
-
function hasScrollableContentOnAxis(scrollTarget, axis) {
|
|
2768
|
-
return axis === 'vertical' ? scrollTarget.scrollHeight > scrollTarget.clientHeight : scrollTarget.scrollWidth > scrollTarget.clientWidth;
|
|
2769
|
-
}
|
|
2770
|
-
function getScrollMetrics(scrollTarget, axis) {
|
|
2771
|
-
if (axis === 'vertical') {
|
|
2772
|
-
const max = Math.max(0, scrollTarget.scrollHeight - scrollTarget.clientHeight);
|
|
2773
|
-
return {
|
|
2774
|
-
offset: scrollTarget.scrollTop,
|
|
2775
|
-
max
|
|
2776
|
-
};
|
|
2777
|
-
}
|
|
2778
|
-
const max = Math.max(0, scrollTarget.scrollWidth - scrollTarget.clientWidth);
|
|
2779
|
-
return {
|
|
2780
|
-
offset: scrollTarget.scrollLeft,
|
|
2781
|
-
max
|
|
2782
|
-
};
|
|
2783
|
-
}
|
|
2784
|
-
function isAtSwipeStartEdge(scrollTarget, axis, direction) {
|
|
2785
|
-
const {
|
|
2786
|
-
offset,
|
|
2787
|
-
max
|
|
2788
|
-
} = getScrollMetrics(scrollTarget, axis);
|
|
2789
|
-
const dismissFromStartEdge = shouldDismissFromStartEdge(direction, axis);
|
|
2790
|
-
if (dismissFromStartEdge === null) {
|
|
2791
|
-
return false;
|
|
2792
|
-
}
|
|
2793
|
-
return dismissFromStartEdge ? offset <= 0 : offset >= max;
|
|
2794
|
-
}
|
|
2795
|
-
function canSwipeFromScrollEdgeOnMove(scrollTarget, axis, direction, delta) {
|
|
2796
|
-
const {
|
|
2797
|
-
offset,
|
|
2798
|
-
max
|
|
2799
|
-
} = getScrollMetrics(scrollTarget, axis);
|
|
2800
|
-
const dismissFromStartEdge = shouldDismissFromStartEdge(direction, axis);
|
|
2801
|
-
if (dismissFromStartEdge === null) {
|
|
2802
|
-
return false;
|
|
2803
|
-
}
|
|
2804
|
-
const movingTowardDismiss = dismissFromStartEdge ? delta > 0 : delta < 0;
|
|
2805
|
-
if (!movingTowardDismiss) {
|
|
2806
|
-
return false;
|
|
2807
|
-
}
|
|
2808
|
-
return dismissFromStartEdge ? offset <= 0 : offset >= max;
|
|
2809
|
-
}
|
|
2810
|
-
function shouldDismissFromStartEdge(direction, axis) {
|
|
2811
|
-
if (axis === 'vertical') {
|
|
2812
|
-
if (direction === 'down') {
|
|
2813
|
-
return true;
|
|
2814
|
-
}
|
|
2815
|
-
if (direction === 'up') {
|
|
2816
|
-
return false;
|
|
2817
|
-
}
|
|
2818
|
-
return null;
|
|
2819
|
-
}
|
|
2820
|
-
if (direction === 'right') {
|
|
2821
|
-
return true;
|
|
2822
|
-
}
|
|
2823
|
-
if (direction === 'left') {
|
|
2824
|
-
return false;
|
|
2825
|
-
}
|
|
2826
|
-
return null;
|
|
2827
|
-
}
|
|
816
|
+
if (process.env.NODE_ENV !== "production") DrawerSwipeArea.displayName = "DrawerSwipeArea";
|
|
2828
817
|
|
|
2829
818
|
let DrawerViewportCssVars = /*#__PURE__*/function (DrawerViewportCssVars) {
|
|
2830
819
|
/**
|
|
@@ -3147,7 +1136,7 @@ function DrawerVirtualKeyboardProvider(props) {
|
|
|
3147
1136
|
onTouchEnd,
|
|
3148
1137
|
onTouchCancel: resetTouchTrackingState
|
|
3149
1138
|
}), [onTouchEnd, onTouchMove, onTouchStart, resetTouchTrackingState]);
|
|
3150
|
-
return /*#__PURE__*/jsxRuntime.jsx(DrawerVirtualKeyboardContext.Provider, {
|
|
1139
|
+
return /*#__PURE__*/jsxRuntime.jsx(ScrollAreaViewport.DrawerVirtualKeyboardContext.Provider, {
|
|
3151
1140
|
value: contextValue,
|
|
3152
1141
|
children: children
|
|
3153
1142
|
});
|
|
@@ -3196,7 +1185,7 @@ function getContentEditableHost(element) {
|
|
|
3196
1185
|
return host;
|
|
3197
1186
|
}
|
|
3198
1187
|
function resolveKeyboardTouchTargetFromPoint(doc, clientX, clientY) {
|
|
3199
|
-
const exactTarget = getElementAtPoint(doc, clientX, clientY);
|
|
1188
|
+
const exactTarget = ScrollAreaViewport.getElementAtPoint(doc, clientX, clientY);
|
|
3200
1189
|
const exactKeyboardTarget = resolveKeyboardInputTarget(exactTarget);
|
|
3201
1190
|
if (exactKeyboardTarget) {
|
|
3202
1191
|
return {
|
|
@@ -3215,7 +1204,7 @@ function resolveKeyboardTouchTargetFromPoint(doc, clientX, clientY) {
|
|
|
3215
1204
|
return KEYBOARD_TAP_BLOCKED;
|
|
3216
1205
|
}
|
|
3217
1206
|
for (const [offsetX, offsetY] of [[0, INPUT_TAP_HIT_SLOP], [0, -INPUT_TAP_HIT_SLOP], [INPUT_TAP_HIT_SLOP, 0], [-INPUT_TAP_HIT_SLOP, 0]]) {
|
|
3218
|
-
const keyboardTarget = resolveKeyboardInputTarget(getElementAtPoint(doc, clientX + offsetX, clientY + offsetY));
|
|
1207
|
+
const keyboardTarget = resolveKeyboardInputTarget(ScrollAreaViewport.getElementAtPoint(doc, clientX + offsetX, clientY + offsetY));
|
|
3219
1208
|
if (keyboardTarget) {
|
|
3220
1209
|
return {
|
|
3221
1210
|
focusTarget: keyboardTarget,
|
|
@@ -3269,7 +1258,7 @@ function findKeyboardScrollTarget(target, root) {
|
|
|
3269
1258
|
// that only becomes scrollable once keyboard slack is added (overflow intent without
|
|
3270
1259
|
// current overflow).
|
|
3271
1260
|
const scrollStart = floatingUi_utils_dom.getParentNode(target);
|
|
3272
|
-
return findScrollableTouchTarget(scrollStart, root, 'vertical') ?? findScrollableTouchTarget(scrollStart, root, 'vertical', true);
|
|
1261
|
+
return ScrollAreaViewport.findScrollableTouchTarget(scrollStart, root, 'vertical') ?? ScrollAreaViewport.findScrollableTouchTarget(scrollStart, root, 'vertical', true);
|
|
3273
1262
|
}
|
|
3274
1263
|
function getKeyboardVisualViewport(win) {
|
|
3275
1264
|
const visualViewport = win.visualViewport;
|
|
@@ -3310,7 +1299,7 @@ var index_parts$5 = /*#__PURE__*/Object.freeze({
|
|
|
3310
1299
|
SwipeArea: DrawerSwipeArea,
|
|
3311
1300
|
Title: DrawerTitle.DrawerTitle,
|
|
3312
1301
|
Trigger: ScrollAreaViewport.DrawerTrigger,
|
|
3313
|
-
Viewport: DrawerViewport,
|
|
1302
|
+
Viewport: ScrollAreaViewport.DrawerViewport,
|
|
3314
1303
|
VirtualKeyboardProvider: DrawerVirtualKeyboardProvider,
|
|
3315
1304
|
createHandle: DrawerDescription.createDialogHandle
|
|
3316
1305
|
});
|