@lodev09/react-native-true-sheet 3.11.6 → 3.11.8
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/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +46 -19
- package/lib/module/TrueSheet.web.js +159 -84
- package/lib/module/TrueSheet.web.js.map +1 -1
- package/lib/module/web/vaul/context.js +2 -0
- package/lib/module/web/vaul/context.js.map +1 -1
- package/lib/module/web/vaul/index.js +134 -19
- package/lib/module/web/vaul/index.js.map +1 -1
- package/lib/module/web/vaul/style.css +24 -1
- package/lib/module/web/vaul/use-snap-points.js +13 -4
- package/lib/module/web/vaul/use-snap-points.js.map +1 -1
- package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/context.d.ts +8 -0
- package/lib/typescript/src/web/vaul/context.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/index.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/TrueSheet.web.tsx +175 -95
- package/src/web/vaul/context.ts +14 -0
- package/src/web/vaul/index.tsx +147 -20
- package/src/web/vaul/style.css +24 -1
- package/src/web/vaul/use-snap-points.ts +14 -5
package/src/web/vaul/index.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import React from 'react';
|
|
|
5
5
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
6
6
|
import { Presence } from '@radix-ui/react-presence';
|
|
7
7
|
|
|
8
|
-
import { DrawerContext, useDrawerContext } from './context';
|
|
8
|
+
import { DrawerContext, useDrawerContext, type DragEvent } from './context';
|
|
9
9
|
import './style.css';
|
|
10
10
|
|
|
11
11
|
import { isIOS, isMobileFirefox } from './browser';
|
|
@@ -24,7 +24,7 @@ import type { DrawerDirection } from './types';
|
|
|
24
24
|
import { useComposedRefs } from './use-composed-refs';
|
|
25
25
|
import { useControllableState } from './use-controllable-state';
|
|
26
26
|
import { usePositionFixed } from './use-position-fixed';
|
|
27
|
-
import { isInput, usePreventScroll } from './use-prevent-scroll';
|
|
27
|
+
import { isInput, isScrollable, usePreventScroll } from './use-prevent-scroll';
|
|
28
28
|
import { useScaleBackground } from './use-scale-background';
|
|
29
29
|
import { useSnapPoints } from './use-snap-points';
|
|
30
30
|
|
|
@@ -337,6 +337,44 @@ export function Root({
|
|
|
337
337
|
noBodyStyles,
|
|
338
338
|
});
|
|
339
339
|
|
|
340
|
+
// While the sheet itself is being dragged, scrollables in the touched chain
|
|
341
|
+
// are frozen (overflow: hidden). Touch browsers latch the scroll gesture at
|
|
342
|
+
// touchstart and ignore preventDefault once scrolling has started, so making
|
|
343
|
+
// the scroller non-scrollable mid-gesture is the only reliable way to keep
|
|
344
|
+
// the content from panning along with the sheet.
|
|
345
|
+
const frozenScrollablesRef = React.useRef<
|
|
346
|
+
{ element: HTMLElement; overflowX: string; overflowY: string }[] | null
|
|
347
|
+
>(null);
|
|
348
|
+
|
|
349
|
+
function freezeScrollables(target: EventTarget) {
|
|
350
|
+
if (frozenScrollablesRef.current) return;
|
|
351
|
+
const frozen: { element: HTMLElement; overflowX: string; overflowY: string }[] = [];
|
|
352
|
+
let element = target instanceof HTMLElement ? target : null;
|
|
353
|
+
while (element && element !== drawerRef.current) {
|
|
354
|
+
if (isScrollable(element)) {
|
|
355
|
+
frozen.push({
|
|
356
|
+
element,
|
|
357
|
+
overflowX: element.style.overflowX,
|
|
358
|
+
overflowY: element.style.overflowY,
|
|
359
|
+
});
|
|
360
|
+
element.style.overflowX = 'hidden';
|
|
361
|
+
element.style.overflowY = 'hidden';
|
|
362
|
+
}
|
|
363
|
+
element = element.parentElement;
|
|
364
|
+
}
|
|
365
|
+
frozenScrollablesRef.current = frozen;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function unfreezeScrollables() {
|
|
369
|
+
const frozen = frozenScrollablesRef.current;
|
|
370
|
+
if (!frozen) return;
|
|
371
|
+
frozenScrollablesRef.current = null;
|
|
372
|
+
for (const { element, overflowX, overflowY } of frozen) {
|
|
373
|
+
element.style.overflowX = overflowX;
|
|
374
|
+
element.style.overflowY = overflowY;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
340
378
|
function getScale() {
|
|
341
379
|
return (window.innerWidth - WINDOW_TOP_OFFSET) / window.innerWidth;
|
|
342
380
|
}
|
|
@@ -386,7 +424,16 @@ export function Root({
|
|
|
386
424
|
}
|
|
387
425
|
|
|
388
426
|
if (swipeAmount !== null) {
|
|
389
|
-
|
|
427
|
+
// Translated past the drag threshold → keep dragging. Below the last
|
|
428
|
+
// snap point the threshold is 0, so the sheet always wins over content
|
|
429
|
+
// scrolling. At the last snap point the threshold is its resting
|
|
430
|
+
// translate — which can still be > 0 when the max detent < 1 — so an
|
|
431
|
+
// at-rest sheet falls through to the scroll checks and content
|
|
432
|
+
// scrolling wins, matching native. Mid-drag/mid-animation the sheet is
|
|
433
|
+
// displaced past rest and still wins.
|
|
434
|
+
const atLastSnapPoint = snapPoints && activeSnapPointIndex === snapPoints.length - 1;
|
|
435
|
+
const restOffset = atLastSnapPoint ? (snapPointsOffset?.[activeSnapPointIndex!] ?? 0) : 0;
|
|
436
|
+
if (direction === 'bottom' ? swipeAmount > restOffset + 1 : swipeAmount < restOffset - 1) {
|
|
390
437
|
return true;
|
|
391
438
|
}
|
|
392
439
|
}
|
|
@@ -396,13 +443,16 @@ export function Root({
|
|
|
396
443
|
return false;
|
|
397
444
|
}
|
|
398
445
|
|
|
399
|
-
// Disallow dragging if drawer was scrolled within `scrollLockTimeout
|
|
446
|
+
// Disallow dragging if drawer was scrolled within `scrollLockTimeout`.
|
|
447
|
+
// Don't re-arm the timestamp here — a prevented drag attempt is not a
|
|
448
|
+
// scroll, and re-arming would keep the lock alive for as long as the
|
|
449
|
+
// finger moves, deadening the whole gesture instead of just the first
|
|
450
|
+
// `scrollLockTimeout` ms after the last real scroll.
|
|
400
451
|
if (
|
|
401
452
|
lastTimeDragPrevented.current &&
|
|
402
453
|
date.getTime() - lastTimeDragPrevented.current.getTime() < scrollLockTimeout &&
|
|
403
454
|
swipeAmount === 0
|
|
404
455
|
) {
|
|
405
|
-
lastTimeDragPrevented.current = date;
|
|
406
456
|
return false;
|
|
407
457
|
}
|
|
408
458
|
|
|
@@ -417,7 +467,11 @@ export function Root({
|
|
|
417
467
|
while (element) {
|
|
418
468
|
// Check if the element is scrollable
|
|
419
469
|
if (element.scrollHeight > element.clientHeight) {
|
|
420
|
-
|
|
470
|
+
// `> 0`, not `!== 0`: Safari reports a negative scrollTop during the
|
|
471
|
+
// rubber-band bounce at the top — that's "at the top" for drag
|
|
472
|
+
// purposes, and treating it as scrolled would arm the scroll lock and
|
|
473
|
+
// delay the sheet drag until the bounce fully settles.
|
|
474
|
+
if (element.scrollTop > 0) {
|
|
421
475
|
lastTimeDragPrevented.current = new Date();
|
|
422
476
|
|
|
423
477
|
// The element is scrollable and not scrolled to the top, so don't drag
|
|
@@ -437,7 +491,7 @@ export function Root({
|
|
|
437
491
|
return true;
|
|
438
492
|
}
|
|
439
493
|
|
|
440
|
-
function
|
|
494
|
+
function drag(event: DragEvent, pointerEvent?: React.PointerEvent<HTMLDivElement>) {
|
|
441
495
|
if (!drawerRef.current) {
|
|
442
496
|
return;
|
|
443
497
|
}
|
|
@@ -480,10 +534,21 @@ export function Root({
|
|
|
480
534
|
return;
|
|
481
535
|
}
|
|
482
536
|
|
|
483
|
-
if (!isAllowedToDrag.current
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
537
|
+
if (!isAllowedToDrag.current) {
|
|
538
|
+
if (!shouldDrag(event.target, isDraggingInDirection)) return;
|
|
539
|
+
drawerRef.current.classList.add(DRAG_CLASS);
|
|
540
|
+
// If shouldDrag gave true once after pressing down on the drawer, we set isAllowedToDrag to true and it will remain true until we let go, there's no reason to disable dragging mid way, ever, and that's the solution to it
|
|
541
|
+
isAllowedToDrag.current = true;
|
|
542
|
+
// Touch pans latched onto a scroller would keep scrolling the content
|
|
543
|
+
// along with the sheet drag — freeze them for the drag's duration.
|
|
544
|
+
if (event.pointerType !== 'mouse') freezeScrollables(event.target);
|
|
545
|
+
// Drag can engage mid-gesture (content scrolled back to its top under
|
|
546
|
+
// the same finger, or the scroll lock expiring). Re-anchor and start
|
|
547
|
+
// moving on the next tick so the sheet tracks the finger from here
|
|
548
|
+
// instead of jumping by the distance the gesture already consumed.
|
|
549
|
+
pointerStart.current = isVertical(direction) ? event.pageY : event.pageX;
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
487
552
|
set(drawerRef.current, {
|
|
488
553
|
transition: 'none',
|
|
489
554
|
});
|
|
@@ -492,7 +557,7 @@ export function Root({
|
|
|
492
557
|
transition: 'none',
|
|
493
558
|
});
|
|
494
559
|
|
|
495
|
-
onDragProp?.(
|
|
560
|
+
if (pointerEvent) onDragProp?.(pointerEvent, percentageDragged);
|
|
496
561
|
|
|
497
562
|
if (snapPoints) {
|
|
498
563
|
onDragSnapPoints({ draggedDistance });
|
|
@@ -691,15 +756,17 @@ export function Root({
|
|
|
691
756
|
|
|
692
757
|
drawerRef.current.classList.remove(DRAG_CLASS);
|
|
693
758
|
isAllowedToDrag.current = false;
|
|
759
|
+
unfreezeScrollables();
|
|
694
760
|
setIsDragging(false);
|
|
695
761
|
dragEndTime.current = new Date();
|
|
696
762
|
}
|
|
697
763
|
|
|
698
|
-
function
|
|
764
|
+
function release(event: DragEvent | null, pointerEvent?: React.PointerEvent<HTMLDivElement>) {
|
|
699
765
|
if (!isDragging || !drawerRef.current) return;
|
|
700
766
|
|
|
701
767
|
drawerRef.current.classList.remove(DRAG_CLASS);
|
|
702
768
|
isAllowedToDrag.current = false;
|
|
769
|
+
unfreezeScrollables();
|
|
703
770
|
setIsDragging(false);
|
|
704
771
|
dragEndTime.current = new Date();
|
|
705
772
|
const swipeAmount = getTranslate(drawerRef.current, direction);
|
|
@@ -730,20 +797,20 @@ export function Root({
|
|
|
730
797
|
velocity,
|
|
731
798
|
dismissible,
|
|
732
799
|
});
|
|
733
|
-
onReleaseProp?.(
|
|
800
|
+
if (pointerEvent) onReleaseProp?.(pointerEvent, true);
|
|
734
801
|
return;
|
|
735
802
|
}
|
|
736
803
|
|
|
737
804
|
// Moved upwards, don't do anything
|
|
738
805
|
if (direction === 'bottom' || direction === 'right' ? distMoved > 0 : distMoved < 0) {
|
|
739
806
|
resetDrawer();
|
|
740
|
-
onReleaseProp?.(
|
|
807
|
+
if (pointerEvent) onReleaseProp?.(pointerEvent, true);
|
|
741
808
|
return;
|
|
742
809
|
}
|
|
743
810
|
|
|
744
811
|
if (velocity > VELOCITY_THRESHOLD) {
|
|
745
812
|
closeDrawer();
|
|
746
|
-
onReleaseProp?.(
|
|
813
|
+
if (pointerEvent) onReleaseProp?.(pointerEvent, false);
|
|
747
814
|
return;
|
|
748
815
|
}
|
|
749
816
|
|
|
@@ -762,11 +829,11 @@ export function Root({
|
|
|
762
829
|
(isHorizontalSwipe ? visibleDrawerWidth : visibleDrawerHeight) * closeThreshold
|
|
763
830
|
) {
|
|
764
831
|
closeDrawer();
|
|
765
|
-
onReleaseProp?.(
|
|
832
|
+
if (pointerEvent) onReleaseProp?.(pointerEvent, false);
|
|
766
833
|
return;
|
|
767
834
|
}
|
|
768
835
|
|
|
769
|
-
onReleaseProp?.(
|
|
836
|
+
if (pointerEvent) onReleaseProp?.(pointerEvent, true);
|
|
770
837
|
resetDrawer();
|
|
771
838
|
}
|
|
772
839
|
|
|
@@ -876,8 +943,10 @@ export function Root({
|
|
|
876
943
|
overlayRef,
|
|
877
944
|
onOpenChange,
|
|
878
945
|
onPress,
|
|
879
|
-
onRelease,
|
|
880
|
-
onDrag,
|
|
946
|
+
onRelease: (event) => release(event, event ?? undefined),
|
|
947
|
+
onDrag: (event) => drag(event, event),
|
|
948
|
+
onTouchDrag: (event, pointerEvent) => drag(event, pointerEvent),
|
|
949
|
+
onTouchRelease: (event, pointerEvent) => release(event, pointerEvent),
|
|
881
950
|
dismissible,
|
|
882
951
|
shouldAnimate,
|
|
883
952
|
handleOnly,
|
|
@@ -1021,6 +1090,8 @@ export const Content = React.forwardRef<HTMLDivElement, ContentProps>(
|
|
|
1021
1090
|
onPress,
|
|
1022
1091
|
onRelease,
|
|
1023
1092
|
onDrag,
|
|
1093
|
+
onTouchDrag,
|
|
1094
|
+
onTouchRelease,
|
|
1024
1095
|
keyboardIsOpen,
|
|
1025
1096
|
snapPointsOffset,
|
|
1026
1097
|
activeSnapPointIndex,
|
|
@@ -1077,6 +1148,7 @@ export const Content = React.forwardRef<HTMLDivElement, ContentProps>(
|
|
|
1077
1148
|
const composedRef = useComposedRefs(ref, drawerRef);
|
|
1078
1149
|
const pointerStartRef = React.useRef<{ x: number; y: number } | null>(null);
|
|
1079
1150
|
const lastKnownPointerEventRef = React.useRef<React.PointerEvent<HTMLDivElement> | null>(null);
|
|
1151
|
+
const continuingCanceledTouchRef = React.useRef(false);
|
|
1080
1152
|
const wasBeyondThePointRef = React.useRef(false);
|
|
1081
1153
|
const hasSnapPoints = snapPoints && snapPoints.length > 0;
|
|
1082
1154
|
useScaleBackground();
|
|
@@ -1309,6 +1381,7 @@ export const Content = React.forwardRef<HTMLDivElement, ContentProps>(
|
|
|
1309
1381
|
onPointerDown={(event) => {
|
|
1310
1382
|
if (handleOnly) return;
|
|
1311
1383
|
rest.onPointerDown?.(event);
|
|
1384
|
+
continuingCanceledTouchRef.current = false;
|
|
1312
1385
|
pointerStartRef.current = { x: event.pageX, y: event.pageY };
|
|
1313
1386
|
onPress(event);
|
|
1314
1387
|
}}
|
|
@@ -1395,14 +1468,68 @@ export const Content = React.forwardRef<HTMLDivElement, ContentProps>(
|
|
|
1395
1468
|
}}
|
|
1396
1469
|
onPointerUp={(event) => {
|
|
1397
1470
|
rest.onPointerUp?.(event);
|
|
1471
|
+
continuingCanceledTouchRef.current = false;
|
|
1398
1472
|
pointerStartRef.current = null;
|
|
1399
1473
|
wasBeyondThePointRef.current = false;
|
|
1400
1474
|
onRelease(event);
|
|
1401
1475
|
}}
|
|
1476
|
+
onPointerCancel={(event) => {
|
|
1477
|
+
rest.onPointerCancel?.(event);
|
|
1478
|
+
if (
|
|
1479
|
+
event.pointerType === 'touch' &&
|
|
1480
|
+
snapPoints &&
|
|
1481
|
+
activeSnapPointIndex === snapPoints.length - 1
|
|
1482
|
+
) {
|
|
1483
|
+
continuingCanceledTouchRef.current = true;
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
handleOnPointerUp(null);
|
|
1487
|
+
}}
|
|
1402
1488
|
onPointerOut={(event) => {
|
|
1403
1489
|
rest.onPointerOut?.(event);
|
|
1490
|
+
if (continuingCanceledTouchRef.current) return;
|
|
1404
1491
|
handleOnPointerUp(lastKnownPointerEventRef.current);
|
|
1405
1492
|
}}
|
|
1493
|
+
onTouchMove={(event) => {
|
|
1494
|
+
rest.onTouchMove?.(event);
|
|
1495
|
+
if (!continuingCanceledTouchRef.current) return;
|
|
1496
|
+
const touch = event.touches[0];
|
|
1497
|
+
if (!touch) return;
|
|
1498
|
+
onTouchDrag(
|
|
1499
|
+
{
|
|
1500
|
+
target: event.target,
|
|
1501
|
+
pageX: touch.pageX,
|
|
1502
|
+
pageY: touch.pageY,
|
|
1503
|
+
pointerType: 'touch',
|
|
1504
|
+
},
|
|
1505
|
+
lastKnownPointerEventRef.current ?? undefined
|
|
1506
|
+
);
|
|
1507
|
+
}}
|
|
1508
|
+
onTouchEnd={(event) => {
|
|
1509
|
+
rest.onTouchEnd?.(event);
|
|
1510
|
+
if (!continuingCanceledTouchRef.current) return;
|
|
1511
|
+
continuingCanceledTouchRef.current = false;
|
|
1512
|
+
pointerStartRef.current = null;
|
|
1513
|
+
wasBeyondThePointRef.current = false;
|
|
1514
|
+
const touch = event.changedTouches[0];
|
|
1515
|
+
onTouchRelease(
|
|
1516
|
+
touch
|
|
1517
|
+
? {
|
|
1518
|
+
target: event.target,
|
|
1519
|
+
pageX: touch.pageX,
|
|
1520
|
+
pageY: touch.pageY,
|
|
1521
|
+
pointerType: 'touch',
|
|
1522
|
+
}
|
|
1523
|
+
: null,
|
|
1524
|
+
lastKnownPointerEventRef.current ?? undefined
|
|
1525
|
+
);
|
|
1526
|
+
}}
|
|
1527
|
+
onTouchCancel={(event) => {
|
|
1528
|
+
rest.onTouchCancel?.(event);
|
|
1529
|
+
if (!continuingCanceledTouchRef.current) return;
|
|
1530
|
+
continuingCanceledTouchRef.current = false;
|
|
1531
|
+
handleOnPointerUp(null);
|
|
1532
|
+
}}
|
|
1406
1533
|
onContextMenu={(event) => {
|
|
1407
1534
|
rest.onContextMenu?.(event);
|
|
1408
1535
|
if (lastKnownPointerEventRef.current) {
|
package/src/web/vaul/style.css
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
|
+
/* Registered so it can transition in sync with `transform` during snaps.
|
|
2
|
+
Descendants derive their visible-height layout from it, so `inherits: true`
|
|
3
|
+
is required. Unsupported browsers ignore this and the value just jumps to
|
|
4
|
+
the snap target instead of animating. */
|
|
5
|
+
@property --snap-point-height {
|
|
6
|
+
syntax: '<length>';
|
|
7
|
+
inherits: true;
|
|
8
|
+
initial-value: 0px;
|
|
9
|
+
}
|
|
10
|
+
|
|
1
11
|
[data-vaul-drawer] {
|
|
2
12
|
touch-action: none;
|
|
3
13
|
will-change: transform;
|
|
4
|
-
transition:
|
|
14
|
+
transition:
|
|
15
|
+
transform 0.5s cubic-bezier(0.32, 0.72, 0, 1),
|
|
16
|
+
--snap-point-height 0.5s cubic-bezier(0.32, 0.72, 0, 1);
|
|
5
17
|
animation-duration: 0.5s;
|
|
6
18
|
animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1);
|
|
7
19
|
}
|
|
@@ -84,6 +96,17 @@
|
|
|
84
96
|
transform: translate3d(var(--snap-point-height, 0), 0, 0);
|
|
85
97
|
}
|
|
86
98
|
|
|
99
|
+
/* Below the last snap point, vertical touch pans should move the sheet — not
|
|
100
|
+
scroll the content (matches native). touch-action is latched at gesture
|
|
101
|
+
start and ancestors above a scroller aren't consulted, so every descendant
|
|
102
|
+
(nested scrollers included) must opt out of vertical panning ahead of time.
|
|
103
|
+
pan-x keeps horizontal carousels inside the content working. Wheel/trackpad
|
|
104
|
+
scrolling is unaffected. */
|
|
105
|
+
[data-vaul-scroll-locked],
|
|
106
|
+
[data-vaul-scroll-locked] * {
|
|
107
|
+
touch-action: pan-x !important;
|
|
108
|
+
}
|
|
109
|
+
|
|
87
110
|
[data-vaul-overlay][data-vaul-snap-points='false'] {
|
|
88
111
|
animation-duration: 0.5s;
|
|
89
112
|
animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1);
|
|
@@ -198,13 +198,17 @@ export function useSnapPoints({
|
|
|
198
198
|
|
|
199
199
|
const animateThisSnap = hasSnappedRef.current || initialAnimated;
|
|
200
200
|
hasSnappedRef.current = true;
|
|
201
|
+
// `--snap-point-height` transitions alongside `transform` (registered via
|
|
202
|
+
// @property) so layouts derived from it (e.g. the scrollable fill) resize
|
|
203
|
+
// in sync with the drawer's slide instead of jumping to the target.
|
|
201
204
|
set(drawerRef.current, {
|
|
202
|
-
transition: animateThisSnap
|
|
203
|
-
? `transform ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(',')})`
|
|
205
|
+
'transition': animateThisSnap
|
|
206
|
+
? `transform ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(',')}), --snap-point-height ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(',')})`
|
|
204
207
|
: 'none',
|
|
205
|
-
transform: isVertical(direction)
|
|
208
|
+
'transform': isVertical(direction)
|
|
206
209
|
? `translate3d(0, ${dimension}px, 0)`
|
|
207
210
|
: `translate3d(${dimension}px, 0, 0)`,
|
|
211
|
+
'--snap-point-height': `${dimension}px`,
|
|
208
212
|
});
|
|
209
213
|
|
|
210
214
|
// Snapping implies drag overshoot (if any) should be undone.
|
|
@@ -360,19 +364,24 @@ export function useSnapPoints({
|
|
|
360
364
|
if ((direction === 'bottom' || direction === 'right') && newValue > snapPointsOffset[0]) {
|
|
361
365
|
const excess = newValue - snapPointsOffset[0];
|
|
362
366
|
set(drawerRef.current, {
|
|
363
|
-
transform: isVertical(direction)
|
|
367
|
+
'transform': isVertical(direction)
|
|
364
368
|
? `translate3d(0, ${snapPointsOffset[0]}px, 0)`
|
|
365
369
|
: `translate3d(${snapPointsOffset[0]}px, 0, 0)`,
|
|
370
|
+
'--snap-point-height': `${snapPointsOffset[0]}px`,
|
|
366
371
|
});
|
|
367
372
|
setDetachedWrapperTransform(excess, false);
|
|
368
373
|
return;
|
|
369
374
|
}
|
|
370
375
|
|
|
371
376
|
setDetachedWrapperTransform(0, false);
|
|
377
|
+
// Keep `--snap-point-height` tracking the live drag position so layouts
|
|
378
|
+
// derived from it (e.g. the scrollable fill) resize with the drawer
|
|
379
|
+
// instead of staying cut off at the last detent's visible height.
|
|
372
380
|
set(drawerRef.current, {
|
|
373
|
-
transform: isVertical(direction)
|
|
381
|
+
'transform': isVertical(direction)
|
|
374
382
|
? `translate3d(0, ${newValue}px, 0)`
|
|
375
383
|
: `translate3d(${newValue}px, 0, 0)`,
|
|
384
|
+
'--snap-point-height': `${newValue}px`,
|
|
376
385
|
});
|
|
377
386
|
}
|
|
378
387
|
|