@surdeddd/bottom-sheet 0.12.0 → 0.14.0
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/README.md +85 -1
- package/dist/{BottomSheetEngine-D6oiEfZ4.d.cts → BottomSheetCore-Cp7dWy91.d.cts} +85 -5
- package/dist/{BottomSheetEngine-Dhy0X_e9.d.ts → BottomSheetCore-DJYwWOqt.d.ts} +85 -5
- package/dist/BottomSheetEngine-Lm7HIVHv.d.cts +7 -0
- package/dist/BottomSheetEngine-O5PbeKfe.d.ts +7 -0
- package/dist/core.cjs +3680 -0
- package/dist/core.d.cts +3 -0
- package/dist/core.d.ts +3 -0
- package/dist/core.js +3678 -0
- package/dist/debug.cjs +109 -0
- package/dist/debug.d.cts +22 -0
- package/dist/debug.d.ts +22 -0
- package/dist/debug.js +107 -0
- package/dist/element.cjs +1314 -829
- package/dist/element.d.cts +2 -1
- package/dist/element.d.ts +2 -1
- package/dist/element.iife.global.js +2 -2
- package/dist/element.js +1314 -829
- package/dist/features.cjs +489 -0
- package/dist/features.d.cts +13 -0
- package/dist/features.d.ts +13 -0
- package/dist/features.js +482 -0
- package/dist/index-Bb5TRmyg.d.cts +9 -0
- package/dist/index-Cl9ebCP2.d.ts +9 -0
- package/dist/index.cjs +979 -1293
- package/dist/index.d.cts +43 -55
- package/dist/index.d.ts +43 -55
- package/dist/index.js +973 -1280
- package/dist/integrations/formik.d.cts +1 -1
- package/dist/integrations/formik.d.ts +1 -1
- package/dist/integrations/react-hook-form.d.cts +1 -1
- package/dist/integrations/react-hook-form.d.ts +1 -1
- package/dist/overlay.cjs +11 -10
- package/dist/overlay.js +11 -10
- package/dist/preact.d.cts +2 -1
- package/dist/preact.d.ts +2 -1
- package/dist/qwik-lib/index.qwik.cjs +4418 -0
- package/dist/qwik-lib/index.qwik.mjs +4418 -0
- package/dist/qwik.cjs +1089 -657
- package/dist/qwik.d.cts +4 -2
- package/dist/qwik.d.ts +4 -2
- package/dist/qwik.js +1089 -657
- package/dist/react.cjs +1100 -665
- package/dist/react.d.cts +3 -3
- package/dist/react.d.ts +3 -3
- package/dist/react.js +1100 -665
- package/dist/solid.cjs +1095 -657
- package/dist/solid.d.cts +90 -4
- package/dist/solid.d.ts +90 -4
- package/dist/solid.js +1095 -657
- package/dist/solid.source.jsx +1103 -657
- package/dist/styles.css +24 -4
- package/dist/svelte-core.cjs +981 -557
- package/dist/svelte-core.js +981 -557
- package/dist/svelte-src/BottomSheet.svelte +14 -0
- package/dist/svelte.cjs +1091 -657
- package/dist/svelte.d.cts +2 -0
- package/dist/svelte.d.ts +2 -0
- package/dist/svelte.js +1091 -657
- package/dist/vue.cjs +1105 -657
- package/dist/vue.js +1105 -657
- package/dist/webgl.cjs +583 -0
- package/dist/webgl.d.cts +17 -0
- package/dist/webgl.d.ts +17 -0
- package/dist/webgl.js +581 -0
- package/package.json +88 -12
package/dist/react.cjs
CHANGED
|
@@ -8,7 +8,7 @@ var __defProp = Object.defineProperty;
|
|
|
8
8
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
9
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
10
10
|
|
|
11
|
-
// src/core/lifecycle/
|
|
11
|
+
// src/core/lifecycle/sheet-stack.ts
|
|
12
12
|
var BASE_Z = 100;
|
|
13
13
|
var STEP = 10;
|
|
14
14
|
var SheetStack = class {
|
|
@@ -139,7 +139,7 @@ function createEventBus() {
|
|
|
139
139
|
};
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
// src/core/primitives/
|
|
142
|
+
// src/core/primitives/css-length.ts
|
|
143
143
|
var probe = null;
|
|
144
144
|
var PROBE_ATTR = "data-bs-probe";
|
|
145
145
|
var ensureProbe = (axis) => {
|
|
@@ -193,7 +193,7 @@ var resolveSnap = (point, mode, measureFit) => {
|
|
|
193
193
|
return Math.max(0, el.getBoundingClientRect().width);
|
|
194
194
|
};
|
|
195
195
|
|
|
196
|
-
// src/core/primitives/
|
|
196
|
+
// src/core/primitives/dev-warn.ts
|
|
197
197
|
function devWarn(...args) {
|
|
198
198
|
if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
|
|
199
199
|
console.warn(...args);
|
|
@@ -358,74 +358,6 @@ var SnapResolver = class {
|
|
|
358
358
|
}
|
|
359
359
|
};
|
|
360
360
|
|
|
361
|
-
// src/core/features/persist.ts
|
|
362
|
-
function readPersistedId(key) {
|
|
363
|
-
if (!key) return null;
|
|
364
|
-
if (typeof window === "undefined") return null;
|
|
365
|
-
if (typeof localStorage === "undefined") return null;
|
|
366
|
-
try {
|
|
367
|
-
return localStorage.getItem(key);
|
|
368
|
-
} catch {
|
|
369
|
-
return null;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
function installPersist(engine, key) {
|
|
373
|
-
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
374
|
-
if (typeof window === "undefined") return;
|
|
375
|
-
if (typeof localStorage === "undefined") return;
|
|
376
|
-
try {
|
|
377
|
-
localStorage.setItem(key, id);
|
|
378
|
-
} catch {
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
return unsubscribe;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// src/core/features/auto-collapse.ts
|
|
385
|
-
function installAutoCollapse(deps) {
|
|
386
|
-
const { ms } = deps;
|
|
387
|
-
if (ms === void 0 || ms <= 0) {
|
|
388
|
-
return () => {
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
let timer = null;
|
|
392
|
-
const clearTimer = () => {
|
|
393
|
-
if (timer !== null) {
|
|
394
|
-
clearTimeout(timer);
|
|
395
|
-
timer = null;
|
|
396
|
-
}
|
|
397
|
-
};
|
|
398
|
-
const fire = () => {
|
|
399
|
-
if (deps.isDestroyed()) return;
|
|
400
|
-
if (deps.isDragging()) return;
|
|
401
|
-
const active = deps.resolveSnap(deps.getActiveId());
|
|
402
|
-
if (!active || active.size === 0) return;
|
|
403
|
-
let target = null;
|
|
404
|
-
for (const id of deps.getAllowedIds()) {
|
|
405
|
-
const snap = deps.resolveSnap(id);
|
|
406
|
-
if (!snap || snap.size <= 0) continue;
|
|
407
|
-
if (!target || snap.size < target.size) target = snap;
|
|
408
|
-
}
|
|
409
|
-
if (!target) return;
|
|
410
|
-
if (target.id === active.id || target.size >= active.size) return;
|
|
411
|
-
deps.snapTo(target.id);
|
|
412
|
-
};
|
|
413
|
-
const reset = () => {
|
|
414
|
-
clearTimer();
|
|
415
|
-
if (deps.isDestroyed()) return;
|
|
416
|
-
timer = setTimeout(() => {
|
|
417
|
-
timer = null;
|
|
418
|
-
fire();
|
|
419
|
-
}, ms);
|
|
420
|
-
};
|
|
421
|
-
const unsubscribe = deps.on("snap", () => reset());
|
|
422
|
-
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
|
|
423
|
-
return () => {
|
|
424
|
-
clearTimer();
|
|
425
|
-
unsubscribe();
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
|
|
429
361
|
// src/core/features/linked-sheets.ts
|
|
430
362
|
function notifyLinkedSheets(sheets, self) {
|
|
431
363
|
if (sheets.length === 0) return;
|
|
@@ -448,394 +380,65 @@ function notifyLinkedSheets(sheets, self) {
|
|
|
448
380
|
}
|
|
449
381
|
}
|
|
450
382
|
|
|
451
|
-
// src/core/features/
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
var pendingRebrand = null;
|
|
457
|
-
var listenerInstalled = false;
|
|
458
|
-
var patchInstalled = false;
|
|
459
|
-
var origPushState = null;
|
|
460
|
-
var origReplaceState = null;
|
|
461
|
-
var patchedPushState = null;
|
|
462
|
-
var patchedReplaceState = null;
|
|
463
|
-
var hasWindow = () => typeof window !== "undefined";
|
|
464
|
-
var hasHistory = () => typeof history !== "undefined";
|
|
465
|
-
var brandMarker = (surface) => ({
|
|
466
|
-
...surface.markerState(),
|
|
467
|
-
__bs: true
|
|
468
|
-
});
|
|
469
|
-
var runInternal = (fn) => {
|
|
470
|
-
internalDepth += 1;
|
|
471
|
-
try {
|
|
472
|
-
fn();
|
|
473
|
-
} finally {
|
|
474
|
-
internalDepth -= 1;
|
|
475
|
-
}
|
|
476
|
-
};
|
|
477
|
-
var notifyRouteChange = () => {
|
|
478
|
-
const snapshot = Array.from(subscribers);
|
|
479
|
-
for (const fn of snapshot) fn();
|
|
480
|
-
};
|
|
481
|
-
var ensureListener = () => {
|
|
482
|
-
if (listenerInstalled || !hasWindow()) return;
|
|
483
|
-
window.addEventListener("popstate", onPopState);
|
|
484
|
-
listenerInstalled = true;
|
|
485
|
-
};
|
|
486
|
-
var maybeTeardownListener = () => {
|
|
487
|
-
if (!listenerInstalled) return;
|
|
488
|
-
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
489
|
-
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
490
|
-
listenerInstalled = false;
|
|
491
|
-
};
|
|
492
|
-
var installPatch = () => {
|
|
493
|
-
if (patchInstalled || !hasHistory()) return;
|
|
494
|
-
origPushState = history.pushState;
|
|
495
|
-
origReplaceState = history.replaceState;
|
|
496
|
-
patchedPushState = function(...args) {
|
|
497
|
-
origPushState.apply(this, args);
|
|
498
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
499
|
-
};
|
|
500
|
-
patchedReplaceState = function(...args) {
|
|
501
|
-
origReplaceState.apply(this, args);
|
|
502
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
503
|
-
};
|
|
504
|
-
history.pushState = patchedPushState;
|
|
505
|
-
history.replaceState = patchedReplaceState;
|
|
506
|
-
patchInstalled = true;
|
|
507
|
-
};
|
|
508
|
-
var removePatch = () => {
|
|
509
|
-
if (!patchInstalled) return;
|
|
510
|
-
if (history.pushState === patchedPushState && origPushState) {
|
|
511
|
-
history.pushState = origPushState;
|
|
512
|
-
}
|
|
513
|
-
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
514
|
-
history.replaceState = origReplaceState;
|
|
515
|
-
}
|
|
516
|
-
origPushState = null;
|
|
517
|
-
origReplaceState = null;
|
|
518
|
-
patchedPushState = null;
|
|
519
|
-
patchedReplaceState = null;
|
|
520
|
-
patchInstalled = false;
|
|
521
|
-
};
|
|
522
|
-
function onPopState() {
|
|
523
|
-
if (suppress > 0) {
|
|
524
|
-
suppress -= 1;
|
|
525
|
-
const rebrand = pendingRebrand;
|
|
526
|
-
pendingRebrand = null;
|
|
527
|
-
if (rebrand) rebrand();
|
|
528
|
-
maybeTeardownListener();
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
if (entries.length === 0) {
|
|
532
|
-
notifyRouteChange();
|
|
533
|
-
maybeTeardownListener();
|
|
534
|
-
return;
|
|
383
|
+
// src/core/features/resize-observer.ts
|
|
384
|
+
function installResizeObserver(deps) {
|
|
385
|
+
if (typeof window === "undefined") {
|
|
386
|
+
return () => {
|
|
387
|
+
};
|
|
535
388
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
389
|
+
const onResize = () => {
|
|
390
|
+
if (deps.isDestroyed()) return;
|
|
391
|
+
deps.recomputeSnaps();
|
|
392
|
+
const mode = deps.getMode();
|
|
393
|
+
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
394
|
+
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
395
|
+
const max = deps.getMaxAxisSize();
|
|
396
|
+
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
397
|
+
deps.setMaxAxisSize(viewportSize2);
|
|
544
398
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
399
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
400
|
+
deps.cancelInFlight();
|
|
401
|
+
deps.newCycle();
|
|
402
|
+
const current = deps.resolveActiveSnap();
|
|
403
|
+
const newMax = deps.getMaxAxisSize();
|
|
404
|
+
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
405
|
+
deps.setSize(targetSize);
|
|
406
|
+
if (current && !deps.isDragging()) {
|
|
407
|
+
deps.applySize(targetSize);
|
|
408
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
549
409
|
}
|
|
410
|
+
};
|
|
411
|
+
let resizeObserver = null;
|
|
412
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
413
|
+
resizeObserver = new ResizeObserver(onResize);
|
|
414
|
+
resizeObserver.observe(document.documentElement);
|
|
415
|
+
} else {
|
|
416
|
+
window.addEventListener("resize", onResize);
|
|
550
417
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
if (
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
}
|
|
563
|
-
maybeTeardownListener();
|
|
418
|
+
window.addEventListener("orientationchange", onResize);
|
|
419
|
+
const onVisibility = () => {
|
|
420
|
+
if (deps.isDestroyed()) return;
|
|
421
|
+
if (document.hidden) deps.cancelInFlight();
|
|
422
|
+
};
|
|
423
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
424
|
+
return () => {
|
|
425
|
+
resizeObserver?.disconnect();
|
|
426
|
+
window.removeEventListener("resize", onResize);
|
|
427
|
+
window.removeEventListener("orientationchange", onResize);
|
|
428
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
429
|
+
};
|
|
564
430
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
entries.push(entry);
|
|
577
|
-
ensureListener();
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
function pushBackMarker(surface) {
|
|
581
|
-
const entry = { surface, priorUrl: void 0, live: false };
|
|
582
|
-
if (!hasWindow() || !hasHistory()) {
|
|
583
|
-
return entry;
|
|
584
|
-
}
|
|
585
|
-
entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
|
|
586
|
-
runInternal(() => {
|
|
587
|
-
try {
|
|
588
|
-
history.pushState(brandMarker(surface), "", surface.url);
|
|
589
|
-
entry.live = true;
|
|
590
|
-
} catch {
|
|
591
|
-
entry.live = false;
|
|
592
|
-
}
|
|
593
|
-
});
|
|
594
|
-
if (entry.live) {
|
|
595
|
-
entries.push(entry);
|
|
596
|
-
ensureListener();
|
|
597
|
-
}
|
|
598
|
-
return entry;
|
|
599
|
-
}
|
|
600
|
-
function popBackMarker(handle) {
|
|
601
|
-
if (!hasWindow() || !hasHistory()) return;
|
|
602
|
-
const entry = handle;
|
|
603
|
-
const idx = entries.indexOf(entry);
|
|
604
|
-
if (idx === -1 || !entry.live) return;
|
|
605
|
-
const last = entries.length - 1;
|
|
606
|
-
entry.live = false;
|
|
607
|
-
entries.splice(idx, 1);
|
|
608
|
-
if (idx !== last) {
|
|
609
|
-
const rebrandSurface = entries[entries.length - 1].surface;
|
|
610
|
-
const rebrandUrl = entry.priorUrl;
|
|
611
|
-
pendingRebrand = () => {
|
|
612
|
-
runInternal(() => {
|
|
613
|
-
history.replaceState(
|
|
614
|
-
brandMarker(rebrandSurface),
|
|
615
|
-
"",
|
|
616
|
-
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
617
|
-
);
|
|
618
|
-
});
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
suppress += 1;
|
|
622
|
-
runInternal(() => {
|
|
623
|
-
try {
|
|
624
|
-
history.back();
|
|
625
|
-
} catch {
|
|
626
|
-
suppress = Math.max(0, suppress - 1);
|
|
627
|
-
pendingRebrand = null;
|
|
628
|
-
}
|
|
629
|
-
});
|
|
630
|
-
maybeTeardownListener();
|
|
631
|
-
}
|
|
632
|
-
function subscribeRouteChange(fn) {
|
|
633
|
-
if (!hasWindow() || !hasHistory()) return () => {
|
|
634
|
-
};
|
|
635
|
-
subscribers.add(fn);
|
|
636
|
-
if (subscribers.size === 1) installPatch();
|
|
637
|
-
ensureListener();
|
|
638
|
-
return () => {
|
|
639
|
-
if (!subscribers.has(fn)) return;
|
|
640
|
-
subscribers.delete(fn);
|
|
641
|
-
if (subscribers.size === 0) removePatch();
|
|
642
|
-
maybeTeardownListener();
|
|
643
|
-
};
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
// src/core/features/route.ts
|
|
647
|
-
function installRoute(deps) {
|
|
648
|
-
if (typeof window === "undefined") {
|
|
649
|
-
return () => {
|
|
650
|
-
};
|
|
651
|
-
}
|
|
652
|
-
if (!deps.routedTo && !deps.closeOnBack) {
|
|
653
|
-
return () => {
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
let handle = null;
|
|
657
|
-
const onOpen = () => {
|
|
658
|
-
if (handle) return;
|
|
659
|
-
handle = pushBackMarker({
|
|
660
|
-
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
661
|
-
isTop: deps.isTopSheet,
|
|
662
|
-
close: deps.close,
|
|
663
|
-
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
664
|
-
url: deps.routedTo
|
|
665
|
-
});
|
|
666
|
-
};
|
|
667
|
-
const onClose = () => {
|
|
668
|
-
if (!handle) return;
|
|
669
|
-
popBackMarker(handle);
|
|
670
|
-
handle = null;
|
|
671
|
-
};
|
|
672
|
-
const unsubscribeOpen = deps.on("open", onOpen);
|
|
673
|
-
const unsubscribeClose = deps.on("close", onClose);
|
|
674
|
-
if (deps.getSize() > 0) onOpen();
|
|
675
|
-
return () => {
|
|
676
|
-
unsubscribeOpen();
|
|
677
|
-
unsubscribeClose();
|
|
678
|
-
if (handle) {
|
|
679
|
-
popBackMarker(handle);
|
|
680
|
-
handle = null;
|
|
681
|
-
}
|
|
682
|
-
};
|
|
683
|
-
}
|
|
684
|
-
function installRouteChange(deps) {
|
|
685
|
-
return subscribeRouteChange(() => {
|
|
686
|
-
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
687
|
-
void deps.close();
|
|
688
|
-
});
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
// src/core/features/content-swipe.ts
|
|
692
|
-
var CONTENT_PULL_THRESHOLD = 60;
|
|
693
|
-
function installContentSwipe(deps) {
|
|
694
|
-
const { container } = deps;
|
|
695
|
-
let startY = 0;
|
|
696
|
-
let startScrollTop = 0;
|
|
697
|
-
let moved = false;
|
|
698
|
-
const onTouchStart = (e) => {
|
|
699
|
-
const t = e.touches[0];
|
|
700
|
-
if (!t) return;
|
|
701
|
-
startY = t.clientY;
|
|
702
|
-
startScrollTop = container.scrollTop;
|
|
703
|
-
moved = false;
|
|
704
|
-
};
|
|
705
|
-
const onTouchMove = (e) => {
|
|
706
|
-
const t = e.touches[0];
|
|
707
|
-
if (!t) return;
|
|
708
|
-
if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
|
|
709
|
-
};
|
|
710
|
-
const onTouchEnd = (e) => {
|
|
711
|
-
if (!moved) return;
|
|
712
|
-
if (deps.isDragging() || deps.isAnimating()) return;
|
|
713
|
-
if (container.scrollTop !== startScrollTop) return;
|
|
714
|
-
const t = e.changedTouches[0];
|
|
715
|
-
if (!t) return;
|
|
716
|
-
const deltaY = t.clientY - startY;
|
|
717
|
-
const atTop = container.scrollTop <= 0;
|
|
718
|
-
const allowed = deps.getAllowedIds();
|
|
719
|
-
const idx = allowed.indexOf(deps.getActiveId());
|
|
720
|
-
if (idx === -1) return;
|
|
721
|
-
if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
|
|
722
|
-
deps.snapTo(allowed[idx - 1]);
|
|
723
|
-
} else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
|
|
724
|
-
deps.snapTo(allowed[idx + 1]);
|
|
725
|
-
}
|
|
726
|
-
};
|
|
727
|
-
container.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
728
|
-
container.addEventListener("touchmove", onTouchMove, { passive: true });
|
|
729
|
-
container.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
730
|
-
return () => {
|
|
731
|
-
container.removeEventListener("touchstart", onTouchStart);
|
|
732
|
-
container.removeEventListener("touchmove", onTouchMove);
|
|
733
|
-
container.removeEventListener("touchend", onTouchEnd);
|
|
734
|
-
};
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
// src/core/features/visual-viewport.ts
|
|
738
|
-
var SAFETY_PAD = 8;
|
|
739
|
-
function installVisualViewport(deps) {
|
|
740
|
-
if (typeof window === "undefined" || !window.visualViewport) {
|
|
741
|
-
return () => {
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
const vv = window.visualViewport;
|
|
745
|
-
let rafId = null;
|
|
746
|
-
const onResize = () => {
|
|
747
|
-
if (rafId !== null) return;
|
|
748
|
-
rafId = requestAnimationFrame(() => {
|
|
749
|
-
rafId = null;
|
|
750
|
-
if (deps.isDestroyed()) return;
|
|
751
|
-
deps.recomputeSnaps();
|
|
752
|
-
const isVertical = deps.isVerticalAxis();
|
|
753
|
-
const visible = isVertical ? vv.height : vv.width;
|
|
754
|
-
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
755
|
-
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
756
|
-
if (clamp < deps.getMaxAxisSize()) {
|
|
757
|
-
deps.setMaxAxisSize(clamp);
|
|
758
|
-
}
|
|
759
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
760
|
-
deps.cancelInFlight();
|
|
761
|
-
deps.newCycle();
|
|
762
|
-
const max = deps.getMaxAxisSize();
|
|
763
|
-
deps.setSize(Math.min(deps.getSize(), max));
|
|
764
|
-
const current = deps.resolveActiveSnap();
|
|
765
|
-
if (current && !deps.isDragging()) {
|
|
766
|
-
deps.applySize(Math.min(current.size, max));
|
|
767
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
768
|
-
} else {
|
|
769
|
-
deps.applySize(deps.getSize());
|
|
770
|
-
}
|
|
771
|
-
});
|
|
772
|
-
};
|
|
773
|
-
vv.addEventListener("resize", onResize);
|
|
774
|
-
return () => {
|
|
775
|
-
vv.removeEventListener("resize", onResize);
|
|
776
|
-
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
777
|
-
};
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
// src/core/features/resize-observer.ts
|
|
781
|
-
function installResizeObserver(deps) {
|
|
782
|
-
if (typeof window === "undefined") {
|
|
783
|
-
return () => {
|
|
784
|
-
};
|
|
785
|
-
}
|
|
786
|
-
const onResize = () => {
|
|
787
|
-
if (deps.isDestroyed()) return;
|
|
788
|
-
deps.recomputeSnaps();
|
|
789
|
-
const mode = deps.getMode();
|
|
790
|
-
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
791
|
-
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
792
|
-
const max = deps.getMaxAxisSize();
|
|
793
|
-
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
794
|
-
deps.setMaxAxisSize(viewportSize2);
|
|
795
|
-
}
|
|
796
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
797
|
-
deps.cancelInFlight();
|
|
798
|
-
deps.newCycle();
|
|
799
|
-
const current = deps.resolveActiveSnap();
|
|
800
|
-
const newMax = deps.getMaxAxisSize();
|
|
801
|
-
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
802
|
-
deps.setSize(targetSize);
|
|
803
|
-
if (current && !deps.isDragging()) {
|
|
804
|
-
deps.applySize(targetSize);
|
|
805
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
806
|
-
}
|
|
807
|
-
};
|
|
808
|
-
let resizeObserver = null;
|
|
809
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
810
|
-
resizeObserver = new ResizeObserver(onResize);
|
|
811
|
-
resizeObserver.observe(document.documentElement);
|
|
812
|
-
} else {
|
|
813
|
-
window.addEventListener("resize", onResize);
|
|
814
|
-
}
|
|
815
|
-
window.addEventListener("orientationchange", onResize);
|
|
816
|
-
const onVisibility = () => {
|
|
817
|
-
if (deps.isDestroyed()) return;
|
|
818
|
-
if (document.hidden) deps.cancelInFlight();
|
|
819
|
-
};
|
|
820
|
-
document.addEventListener("visibilitychange", onVisibility);
|
|
821
|
-
return () => {
|
|
822
|
-
resizeObserver?.disconnect();
|
|
823
|
-
window.removeEventListener("resize", onResize);
|
|
824
|
-
window.removeEventListener("orientationchange", onResize);
|
|
825
|
-
document.removeEventListener("visibilitychange", onVisibility);
|
|
826
|
-
};
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
// src/core/features/fit-observer.ts
|
|
830
|
-
var contentTargets = (scroller) => {
|
|
831
|
-
if (!scroller) return [];
|
|
832
|
-
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
833
|
-
const out = [];
|
|
834
|
-
for (const child of Array.from(scroller.children)) {
|
|
835
|
-
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
836
|
-
for (const el of child.assignedElements()) out.push(el);
|
|
837
|
-
} else {
|
|
838
|
-
out.push(child);
|
|
431
|
+
|
|
432
|
+
// src/core/features/fit-observer.ts
|
|
433
|
+
var contentTargets = (scroller) => {
|
|
434
|
+
if (!scroller) return [];
|
|
435
|
+
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
436
|
+
const out = [];
|
|
437
|
+
for (const child of Array.from(scroller.children)) {
|
|
438
|
+
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
439
|
+
for (const el of child.assignedElements()) out.push(el);
|
|
440
|
+
} else {
|
|
441
|
+
out.push(child);
|
|
839
442
|
}
|
|
840
443
|
}
|
|
841
444
|
return out;
|
|
@@ -1677,6 +1280,52 @@ function resolveAnimationPreset(animation) {
|
|
|
1677
1280
|
}
|
|
1678
1281
|
}
|
|
1679
1282
|
|
|
1283
|
+
// src/core/animation/waapi-settle.ts
|
|
1284
|
+
var SIM_HZ = 240;
|
|
1285
|
+
var SAMPLE_STRIDE = 4;
|
|
1286
|
+
var MAX_SIM_MS = 3e3;
|
|
1287
|
+
function sampleSpringSettle(from, to, velocityPxPerS, config) {
|
|
1288
|
+
const cfg = { ...DEFAULT_SPRING, ...config };
|
|
1289
|
+
const subDt = 1 / SIM_HZ;
|
|
1290
|
+
const stepMs = SAMPLE_STRIDE / SIM_HZ * 1e3;
|
|
1291
|
+
const maxSteps = Math.ceil(MAX_SIM_MS / 1e3 * SIM_HZ);
|
|
1292
|
+
const values = [from];
|
|
1293
|
+
let x = from;
|
|
1294
|
+
let v = velocityPxPerS;
|
|
1295
|
+
for (let i = 1; i <= maxSteps; i += 1) {
|
|
1296
|
+
const force = -cfg.stiffness * (x - to) - cfg.damping * v;
|
|
1297
|
+
v += force / cfg.mass * subDt;
|
|
1298
|
+
x += v * subDt;
|
|
1299
|
+
if (!Number.isFinite(x) || !Number.isFinite(v)) {
|
|
1300
|
+
values.push(to);
|
|
1301
|
+
break;
|
|
1302
|
+
}
|
|
1303
|
+
if (i % SAMPLE_STRIDE === 0) values.push(x);
|
|
1304
|
+
const atRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
|
|
1305
|
+
if (atRest) break;
|
|
1306
|
+
}
|
|
1307
|
+
if (values[values.length - 1] !== to) values.push(to);
|
|
1308
|
+
return {
|
|
1309
|
+
values,
|
|
1310
|
+
stepMs,
|
|
1311
|
+
durationMs: (values.length - 1) * stepMs
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
function sampleTweenSettle(from, to, durationMs, easing) {
|
|
1315
|
+
const count = Math.max(2, Math.min(60, Math.round(durationMs / 16)));
|
|
1316
|
+
const values = [];
|
|
1317
|
+
for (let i = 0; i <= count; i += 1) {
|
|
1318
|
+
const t = i / count;
|
|
1319
|
+
values.push(from + (to - from) * easing(t));
|
|
1320
|
+
}
|
|
1321
|
+
values[values.length - 1] = to;
|
|
1322
|
+
return {
|
|
1323
|
+
values,
|
|
1324
|
+
stepMs: durationMs / count,
|
|
1325
|
+
durationMs
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1680
1329
|
// src/core/controllers/animation-runner.ts
|
|
1681
1330
|
var DEFAULT_DURATION2 = 220;
|
|
1682
1331
|
var VELOCITY_PX_PER_S = 1e3;
|
|
@@ -1687,6 +1336,10 @@ var AnimationRunner = class {
|
|
|
1687
1336
|
__publicField(this, "applySizeFn");
|
|
1688
1337
|
__publicField(this, "getSize");
|
|
1689
1338
|
__publicField(this, "isDragging");
|
|
1339
|
+
__publicField(this, "applyAux");
|
|
1340
|
+
__publicField(this, "getTransformFor");
|
|
1341
|
+
__publicField(this, "settleWaapi");
|
|
1342
|
+
__publicField(this, "currentWaapi", null);
|
|
1690
1343
|
__publicField(this, "animationKind");
|
|
1691
1344
|
__publicField(this, "springConfig");
|
|
1692
1345
|
__publicField(this, "duration");
|
|
@@ -1702,6 +1355,9 @@ var AnimationRunner = class {
|
|
|
1702
1355
|
this.applySizeFn = deps.applySize;
|
|
1703
1356
|
this.getSize = deps.getSize;
|
|
1704
1357
|
this.isDragging = deps.isDragging;
|
|
1358
|
+
this.applyAux = deps.applyAux;
|
|
1359
|
+
this.getTransformFor = deps.getTransformFor;
|
|
1360
|
+
this.settleWaapi = opts.settleAnimation === "waapi";
|
|
1705
1361
|
const preset = resolveAnimationPreset(opts.animation);
|
|
1706
1362
|
this.animationKind = preset.kind;
|
|
1707
1363
|
this.duration = opts.duration ?? preset.duration ?? DEFAULT_DURATION2;
|
|
@@ -1726,11 +1382,20 @@ var AnimationRunner = class {
|
|
|
1726
1382
|
}
|
|
1727
1383
|
}
|
|
1728
1384
|
get isAnimating() {
|
|
1729
|
-
return this.currentTween !== null || this.currentSpring !== null;
|
|
1385
|
+
return this.currentTween !== null || this.currentSpring !== null || this.currentWaapi !== null;
|
|
1730
1386
|
}
|
|
1731
1387
|
cancel() {
|
|
1732
1388
|
this.currentTween?.cancel();
|
|
1733
1389
|
this.currentSpring?.cancel();
|
|
1390
|
+
if (this.currentWaapi) {
|
|
1391
|
+
const entry = this.currentWaapi;
|
|
1392
|
+
this.currentWaapi = null;
|
|
1393
|
+
entry.stop();
|
|
1394
|
+
try {
|
|
1395
|
+
entry.anim.cancel();
|
|
1396
|
+
} catch {
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1734
1399
|
}
|
|
1735
1400
|
async animateTo(target, velocityPxPerMs) {
|
|
1736
1401
|
if (target === this.getSize()) {
|
|
@@ -1749,6 +1414,27 @@ var AnimationRunner = class {
|
|
|
1749
1414
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1750
1415
|
return;
|
|
1751
1416
|
}
|
|
1417
|
+
if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
|
|
1418
|
+
const samples = this.animationKind === "spring" ? sampleSpringSettle(
|
|
1419
|
+
this.getSize(),
|
|
1420
|
+
target,
|
|
1421
|
+
velocityPxPerMs * VELOCITY_PX_PER_S,
|
|
1422
|
+
this.springConfig
|
|
1423
|
+
) : sampleTweenSettle(
|
|
1424
|
+
this.getSize(),
|
|
1425
|
+
target,
|
|
1426
|
+
this.duration,
|
|
1427
|
+
this.easing
|
|
1428
|
+
);
|
|
1429
|
+
if (samples.values.length >= 2 && samples.durationMs > 0) {
|
|
1430
|
+
await this.runWaapiSettle(samples, target);
|
|
1431
|
+
if (!this.isAnimating) {
|
|
1432
|
+
this.getRootEl()?.removeAttribute("data-animating");
|
|
1433
|
+
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1434
|
+
}
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1752
1438
|
if (this.animationKind === "spring") {
|
|
1753
1439
|
const spring = runSpring({
|
|
1754
1440
|
from: this.getSize(),
|
|
@@ -1777,15 +1463,70 @@ var AnimationRunner = class {
|
|
|
1777
1463
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1778
1464
|
}
|
|
1779
1465
|
}
|
|
1466
|
+
async runWaapiSettle(samples, target) {
|
|
1467
|
+
const applyAux = this.applyAux;
|
|
1468
|
+
const getTransformFor = this.getTransformFor;
|
|
1469
|
+
const frames = samples.values.map((v) => ({
|
|
1470
|
+
transform: getTransformFor(v)
|
|
1471
|
+
}));
|
|
1472
|
+
const anim = this.element.animate(frames, {
|
|
1473
|
+
duration: samples.durationMs,
|
|
1474
|
+
easing: "linear",
|
|
1475
|
+
fill: "forwards"
|
|
1476
|
+
});
|
|
1477
|
+
let stopped = false;
|
|
1478
|
+
let auxRaf = 0;
|
|
1479
|
+
const start = performance.now();
|
|
1480
|
+
const lastIdx = samples.values.length - 1;
|
|
1481
|
+
const auxTick = () => {
|
|
1482
|
+
if (stopped) return;
|
|
1483
|
+
const elapsed = performance.now() - start;
|
|
1484
|
+
const idx = Math.min(Math.floor(elapsed / samples.stepMs), lastIdx);
|
|
1485
|
+
applyAux(samples.values[idx]);
|
|
1486
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1487
|
+
};
|
|
1488
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1489
|
+
const entry = {
|
|
1490
|
+
anim,
|
|
1491
|
+
stop: () => {
|
|
1492
|
+
stopped = true;
|
|
1493
|
+
cancelAnimationFrame(auxRaf);
|
|
1494
|
+
}
|
|
1495
|
+
};
|
|
1496
|
+
this.currentWaapi = entry;
|
|
1497
|
+
try {
|
|
1498
|
+
await anim.finished;
|
|
1499
|
+
} catch {
|
|
1500
|
+
}
|
|
1501
|
+
entry.stop();
|
|
1502
|
+
const wasCurrent = this.currentWaapi === entry;
|
|
1503
|
+
if (wasCurrent) this.currentWaapi = null;
|
|
1504
|
+
if (wasCurrent && anim.playState === "finished") {
|
|
1505
|
+
this.applySizeFn(target);
|
|
1506
|
+
try {
|
|
1507
|
+
anim.cancel();
|
|
1508
|
+
} catch {
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1780
1512
|
destroy() {
|
|
1781
1513
|
this.detachReducedMotion?.();
|
|
1782
1514
|
this.detachReducedMotion = null;
|
|
1783
1515
|
this.currentTween = null;
|
|
1784
1516
|
this.currentSpring = null;
|
|
1517
|
+
if (this.currentWaapi) {
|
|
1518
|
+
const entry = this.currentWaapi;
|
|
1519
|
+
this.currentWaapi = null;
|
|
1520
|
+
entry.stop();
|
|
1521
|
+
try {
|
|
1522
|
+
entry.anim.cancel();
|
|
1523
|
+
} catch {
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1785
1526
|
}
|
|
1786
1527
|
};
|
|
1787
1528
|
|
|
1788
|
-
// src/core/lifecycle/
|
|
1529
|
+
// src/core/lifecycle/focus-trap.ts
|
|
1789
1530
|
var FOCUSABLE = [
|
|
1790
1531
|
"a[href]",
|
|
1791
1532
|
"area[href]",
|
|
@@ -1903,7 +1644,7 @@ var installFocusTrap = (container, options = {}) => {
|
|
|
1903
1644
|
};
|
|
1904
1645
|
};
|
|
1905
1646
|
|
|
1906
|
-
// src/core/lifecycle/
|
|
1647
|
+
// src/core/lifecycle/scroll-lock.ts
|
|
1907
1648
|
var lockCount = 0;
|
|
1908
1649
|
var savedStyles = null;
|
|
1909
1650
|
var lockBodyScroll = () => {
|
|
@@ -2085,30 +1826,44 @@ var SampleRing = class {
|
|
|
2085
1826
|
this.size = 0;
|
|
2086
1827
|
}
|
|
2087
1828
|
};
|
|
2088
|
-
var installGestures = (handle, mode, callbacks) => {
|
|
1829
|
+
var installGestures = (handle, mode, callbacks, options = {}) => {
|
|
2089
1830
|
let activePointerId = null;
|
|
2090
1831
|
let activePointerType = "touch";
|
|
2091
1832
|
let startCoord = 0;
|
|
2092
1833
|
let lastCoord = 0;
|
|
1834
|
+
let pendingStart = false;
|
|
2093
1835
|
const VELOCITY_WINDOW_MS = (kind) => kind === "mouse" ? 160 : 120;
|
|
2094
1836
|
const MAX_SAMPLES = 32;
|
|
2095
1837
|
const samples = new SampleRing(MAX_SAMPLES);
|
|
2096
1838
|
const axis = isAxisVertical(mode) ? "Y" : "X";
|
|
2097
1839
|
const sign = mode === "bottom" || mode === "right" ? -1 : 1;
|
|
2098
1840
|
const coordOf = (e) => axis === "Y" ? e.clientY : e.clientX;
|
|
2099
|
-
const
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
1841
|
+
const capture = (pointerId) => {
|
|
1842
|
+
try {
|
|
1843
|
+
handle.setPointerCapture(pointerId);
|
|
1844
|
+
} catch {
|
|
1845
|
+
}
|
|
1846
|
+
};
|
|
1847
|
+
const releaseTracking = () => {
|
|
1848
|
+
activePointerId = null;
|
|
1849
|
+
pendingStart = false;
|
|
1850
|
+
samples.reset();
|
|
1851
|
+
};
|
|
1852
|
+
const onPointerDown = (e) => {
|
|
1853
|
+
if (activePointerId !== null) return;
|
|
1854
|
+
if (e.button !== void 0 && e.button !== 0) return;
|
|
1855
|
+
if (options.shouldStart && !options.shouldStart(e)) return;
|
|
1856
|
+
activePointerId = e.pointerId;
|
|
1857
|
+
activePointerType = e.pointerType || "touch";
|
|
1858
|
+
startCoord = coordOf(e);
|
|
2105
1859
|
lastCoord = startCoord;
|
|
2106
1860
|
samples.reset();
|
|
2107
1861
|
samples.push(e.timeStamp, startCoord);
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
1862
|
+
if (options.deferStart) {
|
|
1863
|
+
pendingStart = true;
|
|
1864
|
+
return;
|
|
2111
1865
|
}
|
|
1866
|
+
capture(e.pointerId);
|
|
2112
1867
|
callbacks.onStart(startCoord, activePointerType);
|
|
2113
1868
|
};
|
|
2114
1869
|
const onPointerMove = (e) => {
|
|
@@ -2116,6 +1871,22 @@ var installGestures = (handle, mode, callbacks) => {
|
|
|
2116
1871
|
const coord = coordOf(e);
|
|
2117
1872
|
const rawDelta = coord - startCoord;
|
|
2118
1873
|
const delta = rawDelta * sign;
|
|
1874
|
+
if (pendingStart) {
|
|
1875
|
+
const verdict = options.deferStart(e, delta);
|
|
1876
|
+
if (verdict === false) {
|
|
1877
|
+
releaseTracking();
|
|
1878
|
+
return;
|
|
1879
|
+
}
|
|
1880
|
+
if (verdict !== true) return;
|
|
1881
|
+
pendingStart = false;
|
|
1882
|
+
startCoord = coord;
|
|
1883
|
+
lastCoord = coord;
|
|
1884
|
+
samples.reset();
|
|
1885
|
+
samples.push(e.timeStamp, coord);
|
|
1886
|
+
capture(e.pointerId);
|
|
1887
|
+
callbacks.onStart(startCoord, activePointerType);
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
2119
1890
|
lastCoord = coord;
|
|
2120
1891
|
samples.push(e.timeStamp, coord);
|
|
2121
1892
|
const cutoff = e.timeStamp - VELOCITY_WINDOW_MS(activePointerType);
|
|
@@ -2124,6 +1895,10 @@ var installGestures = (handle, mode, callbacks) => {
|
|
|
2124
1895
|
};
|
|
2125
1896
|
const finishGesture = (e) => {
|
|
2126
1897
|
if (e.pointerId !== activePointerId) return;
|
|
1898
|
+
if (pendingStart) {
|
|
1899
|
+
releaseTracking();
|
|
1900
|
+
return;
|
|
1901
|
+
}
|
|
2127
1902
|
const rawDelta = lastCoord - startCoord;
|
|
2128
1903
|
const delta = rawDelta * sign;
|
|
2129
1904
|
let velocity = 0;
|
|
@@ -2146,22 +1921,26 @@ var installGestures = (handle, mode, callbacks) => {
|
|
|
2146
1921
|
};
|
|
2147
1922
|
const onPointerCancel = (e) => {
|
|
2148
1923
|
if (e.pointerId !== activePointerId) return;
|
|
2149
|
-
|
|
2150
|
-
|
|
1924
|
+
const wasPending = pendingStart;
|
|
1925
|
+
releaseTracking();
|
|
1926
|
+
if (wasPending) return;
|
|
2151
1927
|
callbacks.onCancel?.();
|
|
2152
1928
|
};
|
|
2153
1929
|
handle.addEventListener("pointerdown", onPointerDown);
|
|
2154
1930
|
handle.addEventListener("pointermove", onPointerMove);
|
|
2155
1931
|
handle.addEventListener("pointerup", finishGesture);
|
|
2156
1932
|
handle.addEventListener("pointercancel", onPointerCancel);
|
|
1933
|
+
const managesTouchAction = options.manageTouchAction !== false;
|
|
2157
1934
|
const prevTouchAction = handle.style.touchAction;
|
|
2158
|
-
|
|
1935
|
+
if (managesTouchAction) {
|
|
1936
|
+
handle.style.touchAction = isAxisVertical(mode) ? "pan-x" : "pan-y";
|
|
1937
|
+
}
|
|
2159
1938
|
return () => {
|
|
2160
1939
|
handle.removeEventListener("pointerdown", onPointerDown);
|
|
2161
1940
|
handle.removeEventListener("pointermove", onPointerMove);
|
|
2162
1941
|
handle.removeEventListener("pointerup", finishGesture);
|
|
2163
1942
|
handle.removeEventListener("pointercancel", onPointerCancel);
|
|
2164
|
-
handle.style.touchAction = prevTouchAction;
|
|
1943
|
+
if (managesTouchAction) handle.style.touchAction = prevTouchAction;
|
|
2165
1944
|
if (activePointerId !== null && handle.hasPointerCapture(activePointerId)) {
|
|
2166
1945
|
handle.releasePointerCapture(activePointerId);
|
|
2167
1946
|
}
|
|
@@ -2280,7 +2059,7 @@ var GestureController = class {
|
|
|
2280
2059
|
const restoreTo = this.dragStartSize;
|
|
2281
2060
|
void this.deps.animateTo(restoreTo, 0);
|
|
2282
2061
|
}
|
|
2283
|
-
});
|
|
2062
|
+
}, this.deps.gestureOptions);
|
|
2284
2063
|
return this.detach;
|
|
2285
2064
|
}
|
|
2286
2065
|
forceClearDragState() {
|
|
@@ -2292,6 +2071,41 @@ var GestureController = class {
|
|
|
2292
2071
|
}
|
|
2293
2072
|
};
|
|
2294
2073
|
|
|
2074
|
+
// src/core/primitives/drag-zones.ts
|
|
2075
|
+
var DRAG_ZONE_SELECTOR = "[data-bs-drag]";
|
|
2076
|
+
var NO_DRAG_SELECTOR = "[data-bs-no-drag]";
|
|
2077
|
+
var asElement = (target) => {
|
|
2078
|
+
const candidate = target;
|
|
2079
|
+
return candidate && typeof candidate.closest === "function" ? candidate : null;
|
|
2080
|
+
};
|
|
2081
|
+
function isDragAllowedFrom(target, mode) {
|
|
2082
|
+
const el = asElement(target);
|
|
2083
|
+
if (!el) return mode !== "zones";
|
|
2084
|
+
if (el.closest(NO_DRAG_SELECTOR)) return false;
|
|
2085
|
+
if (mode === "zones") return el.closest(DRAG_ZONE_SELECTOR) !== null;
|
|
2086
|
+
return true;
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
// src/core/primitives/content-gesture.ts
|
|
2090
|
+
var CONTENT_DRAG_SLOP = 6;
|
|
2091
|
+
function decideContentGesture(input) {
|
|
2092
|
+
const slop = input.slop ?? CONTENT_DRAG_SLOP;
|
|
2093
|
+
if (Math.abs(input.delta) < slop) return "pending";
|
|
2094
|
+
if (input.scrollTop > 0) return "scroll";
|
|
2095
|
+
if (input.delta > 0 && input.atMaxSnap) return "scroll";
|
|
2096
|
+
return "drag";
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
// src/core/primitives/touch-scroll-guard.ts
|
|
2100
|
+
function installTouchScrollGuard(surface, isDragging) {
|
|
2101
|
+
const onTouchMove = (e) => {
|
|
2102
|
+
if (!isDragging()) return;
|
|
2103
|
+
if (e.cancelable) e.preventDefault();
|
|
2104
|
+
};
|
|
2105
|
+
surface.addEventListener("touchmove", onTouchMove, { passive: false });
|
|
2106
|
+
return () => surface.removeEventListener("touchmove", onTouchMove);
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2295
2109
|
// src/core/primitives/aria-slider-writer.ts
|
|
2296
2110
|
var AriaSliderWriter = class {
|
|
2297
2111
|
constructor(handle, mode) {
|
|
@@ -2638,7 +2452,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2638
2452
|
const initialAllowed = opts.allowed ?? opts.snapPoints.map((p) => p.id);
|
|
2639
2453
|
let initialId = opts.initial ?? initialAllowed[0] ?? opts.snapPoints[0]?.id ?? "default";
|
|
2640
2454
|
if (opts.persistKey) {
|
|
2641
|
-
const restored =
|
|
2455
|
+
const restored = readPersistedIdSafe(opts.persistKey);
|
|
2642
2456
|
if (restored && initialAllowed.includes(restored)) {
|
|
2643
2457
|
initialId = restored;
|
|
2644
2458
|
}
|
|
@@ -2647,6 +2461,8 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2647
2461
|
mode: opts.mode ?? "bottom",
|
|
2648
2462
|
flickVelocity: opts.flickVelocity ?? DEFAULT_FLICK_VELOCITY,
|
|
2649
2463
|
dragThreshold: opts.dragThreshold ?? DEFAULT_DRAG_THRESHOLD,
|
|
2464
|
+
dragFrom: opts.dragFrom ?? (opts.handle ? "handle" : "sheet"),
|
|
2465
|
+
dragFromContent: opts.dragFromContent ?? true,
|
|
2650
2466
|
rubberBandEnabled: opts.rubberBand ?? true,
|
|
2651
2467
|
closeOnBack: opts.closeOnBack ?? false,
|
|
2652
2468
|
persistent: opts.persistent ?? false,
|
|
@@ -2669,6 +2485,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2669
2485
|
},
|
|
2670
2486
|
animation: {
|
|
2671
2487
|
animation: opts.animation,
|
|
2488
|
+
settleAnimation: opts.settleAnimation,
|
|
2672
2489
|
duration: opts.duration,
|
|
2673
2490
|
easing: opts.easing,
|
|
2674
2491
|
spring: opts.spring,
|
|
@@ -2686,6 +2503,15 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2686
2503
|
}
|
|
2687
2504
|
};
|
|
2688
2505
|
}
|
|
2506
|
+
var readPersistedIdSafe = (key) => {
|
|
2507
|
+
if (typeof window === "undefined") return null;
|
|
2508
|
+
if (typeof localStorage === "undefined") return null;
|
|
2509
|
+
try {
|
|
2510
|
+
return localStorage.getItem(key);
|
|
2511
|
+
} catch {
|
|
2512
|
+
return null;
|
|
2513
|
+
}
|
|
2514
|
+
};
|
|
2689
2515
|
|
|
2690
2516
|
// src/core/primitives/teardown-stack.ts
|
|
2691
2517
|
var TeardownStack = class {
|
|
@@ -2708,9 +2534,9 @@ var TeardownStack = class {
|
|
|
2708
2534
|
}
|
|
2709
2535
|
};
|
|
2710
2536
|
|
|
2711
|
-
// src/core/
|
|
2537
|
+
// src/core/BottomSheetCore.ts
|
|
2712
2538
|
var HAPTIC_DURATION_MS = 8;
|
|
2713
|
-
var
|
|
2539
|
+
var BottomSheetCore = class {
|
|
2714
2540
|
constructor(opts) {
|
|
2715
2541
|
__publicField(this, "id", nextInstanceId("bs"));
|
|
2716
2542
|
__publicField(this, "element");
|
|
@@ -2722,6 +2548,8 @@ var BottomSheetEngine = class {
|
|
|
2722
2548
|
__publicField(this, "mode");
|
|
2723
2549
|
__publicField(this, "flickVelocity");
|
|
2724
2550
|
__publicField(this, "dragThreshold");
|
|
2551
|
+
__publicField(this, "dragFromMode");
|
|
2552
|
+
__publicField(this, "dragFromContentDefault");
|
|
2725
2553
|
__publicField(this, "rubberBandEnabled");
|
|
2726
2554
|
__publicField(this, "scrim");
|
|
2727
2555
|
__publicField(this, "aria");
|
|
@@ -2739,8 +2567,11 @@ var BottomSheetEngine = class {
|
|
|
2739
2567
|
__publicField(this, "activeId");
|
|
2740
2568
|
__publicField(this, "size", 0);
|
|
2741
2569
|
__publicField(this, "gesture");
|
|
2570
|
+
__publicField(this, "contentGesture");
|
|
2571
|
+
__publicField(this, "detachSheetGesture", null);
|
|
2742
2572
|
__publicField(this, "rootEl", null);
|
|
2743
2573
|
__publicField(this, "destroyed", false);
|
|
2574
|
+
__publicField(this, "restClosed", false);
|
|
2744
2575
|
__publicField(this, "currentViewTransition", null);
|
|
2745
2576
|
__publicField(this, "currentAbort", new AbortController());
|
|
2746
2577
|
__publicField(this, "sizeWriteSentinel", new WriteSentinel());
|
|
@@ -2771,6 +2602,8 @@ var BottomSheetEngine = class {
|
|
|
2771
2602
|
__publicField(this, "stackEffectPrimed", false);
|
|
2772
2603
|
__publicField(this, "fitDeps");
|
|
2773
2604
|
__publicField(this, "transformTemplate");
|
|
2605
|
+
__publicField(this, "featureList", []);
|
|
2606
|
+
__publicField(this, "featureCtx");
|
|
2774
2607
|
const resolved = resolveEngineOptions(opts, {
|
|
2775
2608
|
shouldApplyInertSiblings: () => {
|
|
2776
2609
|
if (typeof document === "undefined") return false;
|
|
@@ -2791,6 +2624,8 @@ var BottomSheetEngine = class {
|
|
|
2791
2624
|
this.aria = new AriaSliderWriter(this.handle, this.mode);
|
|
2792
2625
|
this.flickVelocity = resolved.flickVelocity;
|
|
2793
2626
|
this.dragThreshold = resolved.dragThreshold;
|
|
2627
|
+
this.dragFromMode = resolved.dragFrom;
|
|
2628
|
+
this.dragFromContentDefault = resolved.dragFromContent;
|
|
2794
2629
|
this.rubberBandEnabled = resolved.rubberBandEnabled;
|
|
2795
2630
|
this.scrim = new ScrimController(
|
|
2796
2631
|
{
|
|
@@ -2817,7 +2652,9 @@ var BottomSheetEngine = class {
|
|
|
2817
2652
|
getRootEl: () => this.rootEl,
|
|
2818
2653
|
applySize: (size) => this.applySize(size),
|
|
2819
2654
|
getSize: () => this.size,
|
|
2820
|
-
isDragging: () => this.
|
|
2655
|
+
isDragging: () => this.isDraggingAny(),
|
|
2656
|
+
applyAux: (size) => this.applySize(size, true),
|
|
2657
|
+
getTransformFor: (size) => this.transformTemplate(this.snaps.getMaxAxisSize() - size)
|
|
2821
2658
|
},
|
|
2822
2659
|
resolved.animation
|
|
2823
2660
|
);
|
|
@@ -2840,6 +2677,11 @@ var BottomSheetEngine = class {
|
|
|
2840
2677
|
if (opts.linkedSheets) {
|
|
2841
2678
|
this.linkedSheets = opts.linkedSheets;
|
|
2842
2679
|
}
|
|
2680
|
+
const byName = /* @__PURE__ */ new Map();
|
|
2681
|
+
for (const feature of opts.features ?? []) {
|
|
2682
|
+
byName.set(feature.name, feature);
|
|
2683
|
+
}
|
|
2684
|
+
this.featureList = Array.from(byName.values());
|
|
2843
2685
|
this.activeId = resolved.initialId;
|
|
2844
2686
|
auditVhUsage(this.snapPointsRaw);
|
|
2845
2687
|
this.auditDuplicateSnapIds(this.snapPointsRaw);
|
|
@@ -2871,11 +2713,13 @@ var BottomSheetEngine = class {
|
|
|
2871
2713
|
const initial = this.snaps.findById(this.activeId);
|
|
2872
2714
|
if (initial) this.size = initial.size;
|
|
2873
2715
|
this.applySize(this.size);
|
|
2716
|
+
this.setRestClosed(this.size === 0);
|
|
2874
2717
|
this.updateAriaSlider();
|
|
2875
2718
|
this.scrollCache = createScrollCache({
|
|
2876
2719
|
scrollContainer: this.scrollContainer,
|
|
2877
2720
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize()
|
|
2878
2721
|
});
|
|
2722
|
+
this.featureCtx = this.buildFeatureContext(opts.autoCollapseAfter);
|
|
2879
2723
|
this.attach();
|
|
2880
2724
|
this.registerInStack();
|
|
2881
2725
|
if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
|
|
@@ -2900,60 +2744,92 @@ var BottomSheetEngine = class {
|
|
|
2900
2744
|
(p) => p.size === "fit" || p.size === "content"
|
|
2901
2745
|
),
|
|
2902
2746
|
isDestroyed: () => this.destroyed,
|
|
2903
|
-
isDragging: () => this.
|
|
2747
|
+
isDragging: () => this.isDraggingAny(),
|
|
2904
2748
|
recompute: () => this.recompute()
|
|
2905
2749
|
})
|
|
2906
2750
|
);
|
|
2907
2751
|
if (resolved.radius !== void 0) this.setRadius(resolved.radius);
|
|
2908
2752
|
if (resolved.maxHeight !== void 0) this.setMaxHeight(resolved.maxHeight);
|
|
2909
2753
|
this.applyAutoAriaLabelledBy();
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
getSize: () => this.size,
|
|
2915
|
-
close: () => this.close()
|
|
2916
|
-
})
|
|
2917
|
-
);
|
|
2918
|
-
}
|
|
2919
|
-
if (this.persistKey) {
|
|
2920
|
-
this.teardowns.add(installPersist(this, this.persistKey));
|
|
2754
|
+
this.runFeatureStage("post");
|
|
2755
|
+
this.warnOrphanFeatureOptions();
|
|
2756
|
+
if (this.size > 0) {
|
|
2757
|
+
this.handleOpen();
|
|
2921
2758
|
}
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
resolveSnap: (id) => this.snaps.findById(id),
|
|
2930
|
-
snapTo: (id) => {
|
|
2931
|
-
void this.snapTo(id);
|
|
2932
|
-
},
|
|
2933
|
-
on: (event, fn) => this.on(event, fn)
|
|
2934
|
-
})
|
|
2935
|
-
);
|
|
2936
|
-
this.teardowns.add(
|
|
2937
|
-
installRoute({
|
|
2759
|
+
}
|
|
2760
|
+
buildFeatureContext(autoCollapseAfter) {
|
|
2761
|
+
return {
|
|
2762
|
+
element: this.element,
|
|
2763
|
+
scrollContainer: this.scrollContainer,
|
|
2764
|
+
sheetId: this.id,
|
|
2765
|
+
options: {
|
|
2938
2766
|
routedTo: this.routedTo,
|
|
2939
2767
|
closeOnBack: this.closeOnBack,
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
this.
|
|
2768
|
+
closeOnRouteChange: this.closeOnRouteChange,
|
|
2769
|
+
persistKey: this.persistKey,
|
|
2770
|
+
autoCollapseAfter
|
|
2771
|
+
},
|
|
2772
|
+
isDestroyed: () => this.destroyed,
|
|
2773
|
+
isDragging: () => this.isDraggingAny(),
|
|
2774
|
+
isAnimating: () => this.animation.isAnimating,
|
|
2775
|
+
isTopSheet: () => this.isTopSheet,
|
|
2776
|
+
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
2777
|
+
getSize: () => this.size,
|
|
2778
|
+
getActiveId: () => this.activeId,
|
|
2779
|
+
getAllowedIds: () => this.snaps.getAllowedIds().slice(),
|
|
2780
|
+
allowedIdsBySize: () => this.allowedIdsBySize(),
|
|
2781
|
+
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
2782
|
+
resolveSnap: (id) => this.snaps.findById(id),
|
|
2783
|
+
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
2784
|
+
setSize: (size) => {
|
|
2785
|
+
this.size = size;
|
|
2786
|
+
},
|
|
2787
|
+
setMaxAxisSize: (size) => {
|
|
2788
|
+
this.snaps.setMaxAxisSize(size);
|
|
2789
|
+
},
|
|
2790
|
+
applySize: (size) => this.applySize(size),
|
|
2791
|
+
recomputeSnaps: () => this.recomputeSnaps(),
|
|
2792
|
+
newCycle: () => {
|
|
2793
|
+
this.newCycle();
|
|
2794
|
+
},
|
|
2795
|
+
cancelInFlight: () => {
|
|
2796
|
+
this.animation.cancel();
|
|
2797
|
+
},
|
|
2798
|
+
resyncAfterResize: () => this.resyncAfterResize(),
|
|
2799
|
+
snapTo: (id) => {
|
|
2800
|
+
void this.snapTo(id);
|
|
2801
|
+
},
|
|
2802
|
+
close: (reason) => this.close(reason),
|
|
2803
|
+
attachDragSurface: (surface, kind) => this.attachDragSurface(surface, kind),
|
|
2804
|
+
on: (event, fn) => this.on(event, fn),
|
|
2805
|
+
addTeardown: (fn) => this.teardowns.add(fn)
|
|
2806
|
+
};
|
|
2807
|
+
}
|
|
2808
|
+
runFeatureStage(stage) {
|
|
2809
|
+
for (const feature of this.featureList) {
|
|
2810
|
+
if ((feature.stage ?? "post") !== stage) continue;
|
|
2811
|
+
const teardown = feature.install(this.featureCtx);
|
|
2812
|
+
if (teardown) this.teardowns.add(teardown);
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
warnOrphanFeatureOptions() {
|
|
2816
|
+
const names = new Set(this.featureList.map((f) => f.name));
|
|
2817
|
+
if ((this.closeOnBack || this.routedTo !== void 0 || this.closeOnRouteChange) && !names.has("route")) {
|
|
2818
|
+
devWarn(
|
|
2819
|
+
"[BottomSheet] closeOnBack/routedTo/closeOnRouteChange need routeFeature() \u2014 option ignored"
|
|
2820
|
+
);
|
|
2821
|
+
}
|
|
2822
|
+
if (this.persistKey && !names.has("persist")) {
|
|
2823
|
+
devWarn(
|
|
2824
|
+
"[BottomSheet] persistKey needs persistFeature() \u2014 snaps will not be saved"
|
|
2825
|
+
);
|
|
2950
2826
|
}
|
|
2951
2827
|
}
|
|
2952
2828
|
get state() {
|
|
2953
2829
|
return {
|
|
2954
2830
|
size: this.size,
|
|
2955
2831
|
activeId: this.activeId,
|
|
2956
|
-
isDragging: this.
|
|
2832
|
+
isDragging: this.isDraggingAny(),
|
|
2957
2833
|
isAnimating: this.animation.isAnimating,
|
|
2958
2834
|
progress: this.computeProgress(this.size)
|
|
2959
2835
|
};
|
|
@@ -3073,9 +2949,16 @@ var BottomSheetEngine = class {
|
|
|
3073
2949
|
progress: this.computeProgress(this.size)
|
|
3074
2950
|
});
|
|
3075
2951
|
if (withHaptic) this.haptic();
|
|
2952
|
+
this.setRestClosed(targetSize === 0);
|
|
3076
2953
|
if (wasClosed && targetSize > 0) this.emitOpenSequence(id);
|
|
3077
2954
|
if (targetSize === 0) this.emitCloseSequence();
|
|
3078
2955
|
}
|
|
2956
|
+
setRestClosed(closed) {
|
|
2957
|
+
if (closed === this.restClosed) return;
|
|
2958
|
+
this.restClosed = closed;
|
|
2959
|
+
if (closed) this.element.setAttribute("data-bs-rest", "closed");
|
|
2960
|
+
else this.element.removeAttribute("data-bs-rest");
|
|
2961
|
+
}
|
|
3079
2962
|
emitOpenSequence(id) {
|
|
3080
2963
|
this.emit("open", { id });
|
|
3081
2964
|
this.handleOpen();
|
|
@@ -3131,6 +3014,20 @@ var BottomSheetEngine = class {
|
|
|
3131
3014
|
if (this.destroyed) return;
|
|
3132
3015
|
this.disableDragFlag = value;
|
|
3133
3016
|
}
|
|
3017
|
+
setDragFromContent(value) {
|
|
3018
|
+
if (this.destroyed) return;
|
|
3019
|
+
this.dragFromContentDefault = value;
|
|
3020
|
+
}
|
|
3021
|
+
setDragFrom(mode) {
|
|
3022
|
+
if (this.destroyed || mode === this.dragFromMode) return;
|
|
3023
|
+
this.gesture?.forceClearDragState();
|
|
3024
|
+
this.detachSheetGesture?.();
|
|
3025
|
+
this.dragFromMode = mode;
|
|
3026
|
+
this.mountSheetGesture();
|
|
3027
|
+
}
|
|
3028
|
+
getDragFrom() {
|
|
3029
|
+
return this.dragFromMode;
|
|
3030
|
+
}
|
|
3134
3031
|
isTop() {
|
|
3135
3032
|
return this.isTopSheet;
|
|
3136
3033
|
}
|
|
@@ -3285,12 +3182,24 @@ var BottomSheetEngine = class {
|
|
|
3285
3182
|
auditVhUsage(points);
|
|
3286
3183
|
this.auditDuplicateSnapIds(points);
|
|
3287
3184
|
this.snaps.setRaw(points);
|
|
3288
|
-
if (allowed)
|
|
3185
|
+
if (allowed) {
|
|
3186
|
+
this.snaps.setAllowedIds(allowed);
|
|
3187
|
+
} else {
|
|
3188
|
+
const present = this.snaps.getResolvedSnaps().map((s) => s.id);
|
|
3189
|
+
const kept = this.snaps.getAllowedIds().filter((id) => present.includes(id));
|
|
3190
|
+
this.snaps.setAllowedIds(kept.length ? kept : present);
|
|
3191
|
+
}
|
|
3289
3192
|
this.scrollCache.clear();
|
|
3290
3193
|
this.scrim.invalidateOpacityCache();
|
|
3291
3194
|
const current = this.snaps.findById(this.activeId);
|
|
3292
3195
|
if (current) {
|
|
3293
3196
|
this.applySize(current.size);
|
|
3197
|
+
} else {
|
|
3198
|
+
const fallback = this.snaps.getResolvedSnaps().find((s) => this.snaps.getAllowedIds().includes(s.id)) ?? this.snaps.getResolvedSnaps()[0];
|
|
3199
|
+
if (fallback) {
|
|
3200
|
+
this.activeId = fallback.id;
|
|
3201
|
+
this.applySize(fallback.size);
|
|
3202
|
+
}
|
|
3294
3203
|
}
|
|
3295
3204
|
this.updateAriaSlider();
|
|
3296
3205
|
}
|
|
@@ -3300,7 +3209,7 @@ var BottomSheetEngine = class {
|
|
|
3300
3209
|
this.snaps.recompute();
|
|
3301
3210
|
this.maxHeight.clampTo();
|
|
3302
3211
|
this.scrim.invalidateOpacityCache();
|
|
3303
|
-
if (this.
|
|
3212
|
+
if (this.isDraggingAny()) return;
|
|
3304
3213
|
this.healActiveSnap();
|
|
3305
3214
|
}
|
|
3306
3215
|
healActiveSnap() {
|
|
@@ -3322,6 +3231,8 @@ var BottomSheetEngine = class {
|
|
|
3322
3231
|
this.bus.clear();
|
|
3323
3232
|
this.animation.cancel();
|
|
3324
3233
|
this.gesture?.forceClearDragState();
|
|
3234
|
+
this.contentGesture?.forceClearDragState();
|
|
3235
|
+
this.setRestClosed(false);
|
|
3325
3236
|
this.teardowns.drain();
|
|
3326
3237
|
this.scrim.destroy();
|
|
3327
3238
|
this.animation.destroy();
|
|
@@ -3434,11 +3345,12 @@ var BottomSheetEngine = class {
|
|
|
3434
3345
|
const scale = Math.max(1 - depth * 0.04, 0.86);
|
|
3435
3346
|
this.element.style.scale = scale === 1 ? "" : String(scale);
|
|
3436
3347
|
}
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
handle:
|
|
3348
|
+
buildGestureDeps(surface, gestureOptions) {
|
|
3349
|
+
return {
|
|
3350
|
+
handle: surface,
|
|
3440
3351
|
element: this.element,
|
|
3441
3352
|
mode: this.mode,
|
|
3353
|
+
gestureOptions,
|
|
3442
3354
|
getRoot: () => this.rootEl,
|
|
3443
3355
|
getDragContext: () => {
|
|
3444
3356
|
const buf = this.dragContextBuf;
|
|
@@ -3457,8 +3369,88 @@ var BottomSheetEngine = class {
|
|
|
3457
3369
|
settleAfterDrag: (delta, velocity, kind) => this.settleAfterDrag(delta, velocity, kind),
|
|
3458
3370
|
emit: (event, payload) => this.emit(event, payload),
|
|
3459
3371
|
listenerCount: (event) => this.bus.listenerCount(event)
|
|
3372
|
+
};
|
|
3373
|
+
}
|
|
3374
|
+
isContentDragAllowed() {
|
|
3375
|
+
if (this.disableDragFlag) return false;
|
|
3376
|
+
const point = this.snapPointsRaw.find((p) => p.id === this.activeId);
|
|
3377
|
+
return point?.dragFromContent ?? this.dragFromContentDefault;
|
|
3378
|
+
}
|
|
3379
|
+
decideContentDrag(surface, e, delta) {
|
|
3380
|
+
if (this.destroyed) return false;
|
|
3381
|
+
if (e.pointerType === "mouse") return false;
|
|
3382
|
+
if (this.gesture?.isDragging) return false;
|
|
3383
|
+
if (!this.isContentDragAllowed()) return false;
|
|
3384
|
+
if (!isDragAllowedFrom(e.target, "sheet")) return false;
|
|
3385
|
+
const decision = decideContentGesture({
|
|
3386
|
+
delta,
|
|
3387
|
+
scrollTop: surface.scrollTop,
|
|
3388
|
+
atMaxSnap: this.size >= this.getAllowedRange().max - 0.5
|
|
3389
|
+
});
|
|
3390
|
+
if (decision === "pending") return null;
|
|
3391
|
+
return decision === "drag";
|
|
3392
|
+
}
|
|
3393
|
+
attachDragSurface(surface, kind) {
|
|
3394
|
+
if (this.destroyed || kind !== "content") return;
|
|
3395
|
+
if (this.contentGesture) return;
|
|
3396
|
+
const controller = new GestureController(
|
|
3397
|
+
this.buildGestureDeps(surface, {
|
|
3398
|
+
manageTouchAction: false,
|
|
3399
|
+
deferStart: (e, delta) => this.decideContentDrag(surface, e, delta)
|
|
3400
|
+
})
|
|
3401
|
+
);
|
|
3402
|
+
this.contentGesture = controller;
|
|
3403
|
+
const detachGestures = controller.install();
|
|
3404
|
+
const detachGuard = installTouchScrollGuard(
|
|
3405
|
+
surface,
|
|
3406
|
+
() => controller.isDragging
|
|
3407
|
+
);
|
|
3408
|
+
return () => {
|
|
3409
|
+
detachGuard();
|
|
3410
|
+
detachGestures();
|
|
3411
|
+
if (this.contentGesture === controller) this.contentGesture = void 0;
|
|
3412
|
+
};
|
|
3413
|
+
}
|
|
3414
|
+
sheetDragSurface() {
|
|
3415
|
+
return this.dragFromMode === "handle" ? this.handle : this.element;
|
|
3416
|
+
}
|
|
3417
|
+
canStartSheetDrag(e) {
|
|
3418
|
+
if (this.contentGesture?.isDragging) return false;
|
|
3419
|
+
const target = e.target;
|
|
3420
|
+
const scoped = typeof target?.closest === "function";
|
|
3421
|
+
if (scoped && target.closest(NO_DRAG_SELECTOR)) return false;
|
|
3422
|
+
if (this.handle !== this.element && scoped && this.handle.contains(target)) {
|
|
3423
|
+
return true;
|
|
3424
|
+
}
|
|
3425
|
+
if (!isDragAllowedFrom(e.target, this.dragFromMode)) return false;
|
|
3426
|
+
if (this.dragFromMode === "handle") return true;
|
|
3427
|
+
if (this.scrollContainer && scoped && this.scrollContainer.contains(target) && !target.closest(DRAG_ZONE_SELECTOR)) {
|
|
3428
|
+
return false;
|
|
3429
|
+
}
|
|
3430
|
+
return true;
|
|
3431
|
+
}
|
|
3432
|
+
mountSheetGesture() {
|
|
3433
|
+
const surface = this.sheetDragSurface();
|
|
3434
|
+
const controller = new GestureController(
|
|
3435
|
+
this.buildGestureDeps(surface, {
|
|
3436
|
+
shouldStart: (e) => this.canStartSheetDrag(e),
|
|
3437
|
+
manageTouchAction: this.dragFromMode === "handle"
|
|
3438
|
+
})
|
|
3439
|
+
);
|
|
3440
|
+
this.gesture = controller;
|
|
3441
|
+
const detachGestures = controller.install();
|
|
3442
|
+
const detachGuard = this.dragFromMode === "handle" ? null : installTouchScrollGuard(surface, () => controller.isDragging);
|
|
3443
|
+
this.detachSheetGesture = () => {
|
|
3444
|
+
detachGuard?.();
|
|
3445
|
+
detachGestures();
|
|
3446
|
+
};
|
|
3447
|
+
}
|
|
3448
|
+
attach() {
|
|
3449
|
+
this.mountSheetGesture();
|
|
3450
|
+
this.teardowns.add(() => {
|
|
3451
|
+
this.detachSheetGesture?.();
|
|
3452
|
+
this.detachSheetGesture = null;
|
|
3460
3453
|
});
|
|
3461
|
-
this.teardowns.add(this.gesture.install());
|
|
3462
3454
|
try {
|
|
3463
3455
|
this.attachFeatures();
|
|
3464
3456
|
} catch (err) {
|
|
@@ -3489,24 +3481,13 @@ var BottomSheetEngine = class {
|
|
|
3489
3481
|
}
|
|
3490
3482
|
}
|
|
3491
3483
|
attachFeatures() {
|
|
3492
|
-
|
|
3493
|
-
this.teardowns.add(installContentSwipe({
|
|
3494
|
-
container: this.scrollContainer,
|
|
3495
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3496
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3497
|
-
getAllowedIds: () => this.allowedIdsBySize(),
|
|
3498
|
-
getActiveId: () => this.activeId,
|
|
3499
|
-
snapTo: (id) => {
|
|
3500
|
-
void this.snapTo(id);
|
|
3501
|
-
}
|
|
3502
|
-
}));
|
|
3503
|
-
}
|
|
3484
|
+
this.runFeatureStage("attach");
|
|
3504
3485
|
if (typeof window !== "undefined") {
|
|
3505
3486
|
this.teardowns.add(installResizeObserver({
|
|
3506
3487
|
element: this.element,
|
|
3507
3488
|
getMode: () => this.mode,
|
|
3508
3489
|
isDestroyed: () => this.destroyed,
|
|
3509
|
-
isDragging: () => this.
|
|
3490
|
+
isDragging: () => this.isDraggingAny(),
|
|
3510
3491
|
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3511
3492
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
3512
3493
|
getSize: () => this.size,
|
|
@@ -3540,31 +3521,6 @@ var BottomSheetEngine = class {
|
|
|
3540
3521
|
() => document.removeEventListener("keydown", onKey)
|
|
3541
3522
|
);
|
|
3542
3523
|
}
|
|
3543
|
-
this.teardowns.add(installVisualViewport({
|
|
3544
|
-
element: this.element,
|
|
3545
|
-
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
3546
|
-
isDestroyed: () => this.destroyed,
|
|
3547
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3548
|
-
recomputeSnaps: () => this.recomputeSnaps(),
|
|
3549
|
-
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3550
|
-
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
3551
|
-
getSize: () => this.size,
|
|
3552
|
-
setMaxAxisSize: (size) => {
|
|
3553
|
-
this.snaps.setMaxAxisSize(size);
|
|
3554
|
-
},
|
|
3555
|
-
setSize: (size) => {
|
|
3556
|
-
this.size = size;
|
|
3557
|
-
},
|
|
3558
|
-
applySize: (size) => this.applySize(size),
|
|
3559
|
-
cancelInFlight: () => {
|
|
3560
|
-
this.animation.cancel();
|
|
3561
|
-
},
|
|
3562
|
-
newCycle: () => {
|
|
3563
|
-
this.newCycle();
|
|
3564
|
-
},
|
|
3565
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3566
|
-
resyncAfterCancel: () => this.resyncAfterResize()
|
|
3567
|
-
}));
|
|
3568
3524
|
}
|
|
3569
3525
|
this.teardowns.add(installSliderKeyboard({
|
|
3570
3526
|
handle: this.handle,
|
|
@@ -3605,123 +3561,591 @@ var BottomSheetEngine = class {
|
|
|
3605
3561
|
}
|
|
3606
3562
|
return;
|
|
3607
3563
|
}
|
|
3608
|
-
const previousSize = this.size;
|
|
3609
|
-
const previousSnapSize = this.snaps.findById(previousId)?.size;
|
|
3610
|
-
this.scrollCache.cache(previousId, previousSize, target.size);
|
|
3611
|
-
this.activeId = target.id;
|
|
3612
|
-
if (previousSnapSize === 0 && target.size > 0) {
|
|
3613
|
-
this.opening = true;
|
|
3614
|
-
sheetStack.promote(this.id);
|
|
3564
|
+
const previousSize = this.size;
|
|
3565
|
+
const previousSnapSize = this.snaps.findById(previousId)?.size;
|
|
3566
|
+
this.scrollCache.cache(previousId, previousSize, target.size);
|
|
3567
|
+
this.activeId = target.id;
|
|
3568
|
+
if (previousSnapSize === 0 && target.size > 0) {
|
|
3569
|
+
this.opening = true;
|
|
3570
|
+
sheetStack.promote(this.id);
|
|
3571
|
+
}
|
|
3572
|
+
const settleCap = this.snaps.getMaxAxisSize();
|
|
3573
|
+
const settleSize = settleCap > 0 ? Math.min(target.size, settleCap) : target.size;
|
|
3574
|
+
this.allowOvershoot = true;
|
|
3575
|
+
void this.animation.animateTo(settleSize, velocity).then(() => {
|
|
3576
|
+
if (signal.aborted) return;
|
|
3577
|
+
this.allowOvershoot = false;
|
|
3578
|
+
this.opening = false;
|
|
3579
|
+
this.completeSnap(
|
|
3580
|
+
target.id,
|
|
3581
|
+
target.size,
|
|
3582
|
+
previousSize,
|
|
3583
|
+
previousSnapSize === 0,
|
|
3584
|
+
true
|
|
3585
|
+
);
|
|
3586
|
+
});
|
|
3587
|
+
}
|
|
3588
|
+
isDraggingAny() {
|
|
3589
|
+
return (this.gesture?.isDragging ?? false) || (this.contentGesture?.isDragging ?? false);
|
|
3590
|
+
}
|
|
3591
|
+
clearWillChangeIfIdle() {
|
|
3592
|
+
if (this.animation.isAnimating || this.isDraggingAny()) return;
|
|
3593
|
+
this.element.style.willChange = "";
|
|
3594
|
+
}
|
|
3595
|
+
haptic() {
|
|
3596
|
+
if (typeof navigator !== "undefined" && "vibrate" in navigator) {
|
|
3597
|
+
try {
|
|
3598
|
+
navigator.vibrate(HAPTIC_DURATION_MS);
|
|
3599
|
+
} catch {
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
applySize(size, skipTransform = false) {
|
|
3604
|
+
const cap = this.snaps.getMaxAxisSize();
|
|
3605
|
+
const clamped = cap > 0 && size > cap && !this.isDraggingAny() && !this.allowOvershoot ? cap : size;
|
|
3606
|
+
this.size = clamped;
|
|
3607
|
+
if (clamped > 0) this.setRestClosed(false);
|
|
3608
|
+
const offset = cap - clamped;
|
|
3609
|
+
const style = this.element.style;
|
|
3610
|
+
if (!skipTransform) style.transform = this.transformTemplate(offset);
|
|
3611
|
+
if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
|
|
3612
|
+
style.setProperty("--bs-size", `${clamped}px`);
|
|
3613
|
+
if (this.scrimParent) {
|
|
3614
|
+
this.scrimParent.style.setProperty("--bs-size", `${clamped}px`);
|
|
3615
|
+
}
|
|
3616
|
+
if (this.anchorHost && this.anchorHost !== this.scrimParent) {
|
|
3617
|
+
this.anchorHost.style.setProperty("--bs-size", `${clamped}px`);
|
|
3618
|
+
}
|
|
3619
|
+
if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
|
|
3620
|
+
this.rootEl.style.setProperty("--bs-size", `${clamped}px`);
|
|
3621
|
+
}
|
|
3622
|
+
}
|
|
3623
|
+
const progress = this.computeProgress(clamped);
|
|
3624
|
+
const progressChanged = this.progressWriteSentinel.shouldWrite(
|
|
3625
|
+
progress,
|
|
3626
|
+
OPACITY_WRITE_EPSILON
|
|
3627
|
+
);
|
|
3628
|
+
if (progressChanged) {
|
|
3629
|
+
style.setProperty("--bs-progress", String(progress));
|
|
3630
|
+
if (this.anchorHost) {
|
|
3631
|
+
this.anchorHost.style.setProperty("--bs-progress", String(progress));
|
|
3632
|
+
}
|
|
3633
|
+
if (this.rootEl && this.rootEl !== this.anchorHost) {
|
|
3634
|
+
this.rootEl.style.setProperty("--bs-progress", String(progress));
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
this.scrim.applyOpacity(progress, progressChanged);
|
|
3638
|
+
if (progressChanged && this.bus.listenerCount("progress") > 0) {
|
|
3639
|
+
this.progressPayload.value = progress;
|
|
3640
|
+
this.progressPayload.size = clamped;
|
|
3641
|
+
this.emit("progress", this.progressPayload);
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3644
|
+
computeProgress(size) {
|
|
3645
|
+
const { min, max } = this.getAllowedRange();
|
|
3646
|
+
const reachableMax = Math.min(max, this.snaps.getMaxAxisSize());
|
|
3647
|
+
if (reachableMax <= min) return 0;
|
|
3648
|
+
return Math.min(Math.max((size - min) / (reachableMax - min), 0), 1);
|
|
3649
|
+
}
|
|
3650
|
+
handleOpen() {
|
|
3651
|
+
sheetStack.promote(this.id);
|
|
3652
|
+
try {
|
|
3653
|
+
this.lifecycle.install();
|
|
3654
|
+
} catch (err) {
|
|
3655
|
+
if (!this.destroyed) this.newCycle();
|
|
3656
|
+
this.handleClose();
|
|
3657
|
+
this.applySize(0);
|
|
3658
|
+
this.activeId = this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.activeId;
|
|
3659
|
+
this.size = 0;
|
|
3660
|
+
queueMicrotask(() => {
|
|
3661
|
+
throw err;
|
|
3662
|
+
});
|
|
3663
|
+
}
|
|
3664
|
+
}
|
|
3665
|
+
resyncAfterResize() {
|
|
3666
|
+
if (this.destroyed) return;
|
|
3667
|
+
const target = this.snaps.findById(this.activeId);
|
|
3668
|
+
if (!target) return;
|
|
3669
|
+
this.updateAriaSlider();
|
|
3670
|
+
this.emit("snap", {
|
|
3671
|
+
id: target.id,
|
|
3672
|
+
size: this.size,
|
|
3673
|
+
progress: this.computeProgress(this.size)
|
|
3674
|
+
});
|
|
3675
|
+
if (target.size > 0 && !this.lifecycle.isInstalled) {
|
|
3676
|
+
this.emitOpenSequence(target.id);
|
|
3677
|
+
} else if (target.size === 0 && this.lifecycle.isInstalled) {
|
|
3678
|
+
this.emitCloseSequence();
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
handleClose() {
|
|
3682
|
+
this.opening = false;
|
|
3683
|
+
this.lifecycle.release();
|
|
3684
|
+
sheetStack.update();
|
|
3685
|
+
}
|
|
3686
|
+
};
|
|
3687
|
+
|
|
3688
|
+
// src/core/features/history-coordinator.ts
|
|
3689
|
+
var entries = [];
|
|
3690
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
3691
|
+
var suppress = 0;
|
|
3692
|
+
var internalDepth = 0;
|
|
3693
|
+
var pendingRebrands = [];
|
|
3694
|
+
var listenerInstalled = false;
|
|
3695
|
+
var patchInstalled = false;
|
|
3696
|
+
var origPushState = null;
|
|
3697
|
+
var origReplaceState = null;
|
|
3698
|
+
var patchedPushState = null;
|
|
3699
|
+
var patchedReplaceState = null;
|
|
3700
|
+
var hasWindow = () => typeof window !== "undefined";
|
|
3701
|
+
var hasHistory = () => typeof history !== "undefined";
|
|
3702
|
+
var brandMarker = (surface) => ({
|
|
3703
|
+
...surface.markerState(),
|
|
3704
|
+
__bs: true
|
|
3705
|
+
});
|
|
3706
|
+
var runInternal = (fn) => {
|
|
3707
|
+
internalDepth += 1;
|
|
3708
|
+
try {
|
|
3709
|
+
fn();
|
|
3710
|
+
} finally {
|
|
3711
|
+
internalDepth -= 1;
|
|
3712
|
+
}
|
|
3713
|
+
};
|
|
3714
|
+
var notifyRouteChange = () => {
|
|
3715
|
+
const snapshot = Array.from(subscribers);
|
|
3716
|
+
for (const fn of snapshot) fn();
|
|
3717
|
+
};
|
|
3718
|
+
var ensureListener = () => {
|
|
3719
|
+
if (listenerInstalled || !hasWindow()) return;
|
|
3720
|
+
window.addEventListener("popstate", onPopState);
|
|
3721
|
+
listenerInstalled = true;
|
|
3722
|
+
};
|
|
3723
|
+
var maybeTeardownListener = () => {
|
|
3724
|
+
if (!listenerInstalled) return;
|
|
3725
|
+
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
3726
|
+
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
3727
|
+
listenerInstalled = false;
|
|
3728
|
+
};
|
|
3729
|
+
var installPatch = () => {
|
|
3730
|
+
if (patchInstalled || !hasHistory()) return;
|
|
3731
|
+
origPushState = history.pushState;
|
|
3732
|
+
origReplaceState = history.replaceState;
|
|
3733
|
+
patchedPushState = function(...args) {
|
|
3734
|
+
origPushState.apply(this, args);
|
|
3735
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3736
|
+
};
|
|
3737
|
+
patchedReplaceState = function(...args) {
|
|
3738
|
+
origReplaceState.apply(this, args);
|
|
3739
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3740
|
+
};
|
|
3741
|
+
history.pushState = patchedPushState;
|
|
3742
|
+
history.replaceState = patchedReplaceState;
|
|
3743
|
+
patchInstalled = true;
|
|
3744
|
+
};
|
|
3745
|
+
var removePatch = () => {
|
|
3746
|
+
if (!patchInstalled) return;
|
|
3747
|
+
if (history.pushState === patchedPushState && origPushState) {
|
|
3748
|
+
history.pushState = origPushState;
|
|
3749
|
+
}
|
|
3750
|
+
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
3751
|
+
history.replaceState = origReplaceState;
|
|
3752
|
+
}
|
|
3753
|
+
origPushState = null;
|
|
3754
|
+
origReplaceState = null;
|
|
3755
|
+
patchedPushState = null;
|
|
3756
|
+
patchedReplaceState = null;
|
|
3757
|
+
patchInstalled = false;
|
|
3758
|
+
};
|
|
3759
|
+
function onPopState() {
|
|
3760
|
+
if (suppress > 0) {
|
|
3761
|
+
suppress -= 1;
|
|
3762
|
+
const rebrand = pendingRebrands.shift();
|
|
3763
|
+
if (rebrand) rebrand();
|
|
3764
|
+
maybeTeardownListener();
|
|
3765
|
+
return;
|
|
3766
|
+
}
|
|
3767
|
+
if (entries.length === 0) {
|
|
3768
|
+
notifyRouteChange();
|
|
3769
|
+
maybeTeardownListener();
|
|
3770
|
+
return;
|
|
3771
|
+
}
|
|
3772
|
+
let target = null;
|
|
3773
|
+
let targetIdx = -1;
|
|
3774
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
3775
|
+
const entry = entries[i];
|
|
3776
|
+
if (!entry.surface.isOpen()) continue;
|
|
3777
|
+
if (!target) {
|
|
3778
|
+
target = entry;
|
|
3779
|
+
targetIdx = i;
|
|
3780
|
+
}
|
|
3781
|
+
if (entry.surface.isTop()) {
|
|
3782
|
+
target = entry;
|
|
3783
|
+
targetIdx = i;
|
|
3784
|
+
break;
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
if (!target) {
|
|
3788
|
+
const removed = entries.pop();
|
|
3789
|
+
if (removed) removed.live = false;
|
|
3790
|
+
maybeTeardownListener();
|
|
3791
|
+
return;
|
|
3792
|
+
}
|
|
3793
|
+
target.live = false;
|
|
3794
|
+
entries.splice(targetIdx, 1);
|
|
3795
|
+
const settled = target;
|
|
3796
|
+
void Promise.resolve(settled.surface.close()).then(() => {
|
|
3797
|
+
if (settled.surface.isOpen()) restore(settled);
|
|
3798
|
+
});
|
|
3799
|
+
maybeTeardownListener();
|
|
3800
|
+
}
|
|
3801
|
+
function restore(entry) {
|
|
3802
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3803
|
+
entry.live = true;
|
|
3804
|
+
runInternal(() => {
|
|
3805
|
+
try {
|
|
3806
|
+
history.pushState(brandMarker(entry.surface), "", entry.surface.url);
|
|
3807
|
+
} catch {
|
|
3808
|
+
entry.live = false;
|
|
3809
|
+
}
|
|
3810
|
+
});
|
|
3811
|
+
if (entry.live) {
|
|
3812
|
+
entries.push(entry);
|
|
3813
|
+
ensureListener();
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
function pushBackMarker(surface) {
|
|
3817
|
+
const entry = { surface, priorUrl: void 0, live: false };
|
|
3818
|
+
if (!hasWindow() || !hasHistory()) {
|
|
3819
|
+
return entry;
|
|
3820
|
+
}
|
|
3821
|
+
entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
|
|
3822
|
+
runInternal(() => {
|
|
3823
|
+
try {
|
|
3824
|
+
history.pushState(brandMarker(surface), "", surface.url);
|
|
3825
|
+
entry.live = true;
|
|
3826
|
+
} catch {
|
|
3827
|
+
entry.live = false;
|
|
3828
|
+
}
|
|
3829
|
+
});
|
|
3830
|
+
if (entry.live) {
|
|
3831
|
+
entries.push(entry);
|
|
3832
|
+
ensureListener();
|
|
3833
|
+
}
|
|
3834
|
+
return entry;
|
|
3835
|
+
}
|
|
3836
|
+
function popBackMarker(handle) {
|
|
3837
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3838
|
+
const entry = handle;
|
|
3839
|
+
const idx = entries.indexOf(entry);
|
|
3840
|
+
if (idx === -1 || !entry.live) return;
|
|
3841
|
+
const last = entries.length - 1;
|
|
3842
|
+
entry.live = false;
|
|
3843
|
+
entries.splice(idx, 1);
|
|
3844
|
+
let rebrand = null;
|
|
3845
|
+
if (idx !== last) {
|
|
3846
|
+
const rebrandSurface = entries[entries.length - 1].surface;
|
|
3847
|
+
const rebrandUrl = entry.priorUrl;
|
|
3848
|
+
rebrand = () => {
|
|
3849
|
+
runInternal(() => {
|
|
3850
|
+
history.replaceState(
|
|
3851
|
+
brandMarker(rebrandSurface),
|
|
3852
|
+
"",
|
|
3853
|
+
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
3854
|
+
);
|
|
3855
|
+
});
|
|
3856
|
+
};
|
|
3857
|
+
}
|
|
3858
|
+
pendingRebrands.push(rebrand);
|
|
3859
|
+
suppress += 1;
|
|
3860
|
+
runInternal(() => {
|
|
3861
|
+
try {
|
|
3862
|
+
history.back();
|
|
3863
|
+
} catch {
|
|
3864
|
+
suppress = Math.max(0, suppress - 1);
|
|
3865
|
+
pendingRebrands.pop();
|
|
3866
|
+
}
|
|
3867
|
+
});
|
|
3868
|
+
maybeTeardownListener();
|
|
3869
|
+
}
|
|
3870
|
+
function subscribeRouteChange(fn) {
|
|
3871
|
+
if (!hasWindow() || !hasHistory()) return () => {
|
|
3872
|
+
};
|
|
3873
|
+
subscribers.add(fn);
|
|
3874
|
+
if (subscribers.size === 1) installPatch();
|
|
3875
|
+
ensureListener();
|
|
3876
|
+
return () => {
|
|
3877
|
+
if (!subscribers.has(fn)) return;
|
|
3878
|
+
subscribers.delete(fn);
|
|
3879
|
+
if (subscribers.size === 0) removePatch();
|
|
3880
|
+
maybeTeardownListener();
|
|
3881
|
+
};
|
|
3882
|
+
}
|
|
3883
|
+
|
|
3884
|
+
// src/core/features/route.ts
|
|
3885
|
+
function installRoute(deps) {
|
|
3886
|
+
if (typeof window === "undefined") {
|
|
3887
|
+
return () => {
|
|
3888
|
+
};
|
|
3889
|
+
}
|
|
3890
|
+
if (!deps.routedTo && !deps.closeOnBack) {
|
|
3891
|
+
return () => {
|
|
3892
|
+
};
|
|
3893
|
+
}
|
|
3894
|
+
let handle = null;
|
|
3895
|
+
const onOpen = () => {
|
|
3896
|
+
if (handle) return;
|
|
3897
|
+
handle = pushBackMarker({
|
|
3898
|
+
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
3899
|
+
isTop: deps.isTopSheet,
|
|
3900
|
+
close: deps.close,
|
|
3901
|
+
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
3902
|
+
url: deps.routedTo
|
|
3903
|
+
});
|
|
3904
|
+
};
|
|
3905
|
+
const onClose = () => {
|
|
3906
|
+
if (!handle) return;
|
|
3907
|
+
popBackMarker(handle);
|
|
3908
|
+
handle = null;
|
|
3909
|
+
};
|
|
3910
|
+
const unsubscribeOpen = deps.on("open", onOpen);
|
|
3911
|
+
const unsubscribeClose = deps.on("close", onClose);
|
|
3912
|
+
if (deps.getSize() > 0) onOpen();
|
|
3913
|
+
return () => {
|
|
3914
|
+
unsubscribeOpen();
|
|
3915
|
+
unsubscribeClose();
|
|
3916
|
+
if (handle) {
|
|
3917
|
+
popBackMarker(handle);
|
|
3918
|
+
handle = null;
|
|
3919
|
+
}
|
|
3920
|
+
};
|
|
3921
|
+
}
|
|
3922
|
+
function installRouteChange(deps) {
|
|
3923
|
+
return subscribeRouteChange(() => {
|
|
3924
|
+
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
3925
|
+
void deps.close();
|
|
3926
|
+
});
|
|
3927
|
+
}
|
|
3928
|
+
|
|
3929
|
+
// src/core/features/persist.ts
|
|
3930
|
+
function installPersist(engine, key) {
|
|
3931
|
+
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
3932
|
+
if (typeof window === "undefined") return;
|
|
3933
|
+
if (typeof localStorage === "undefined") return;
|
|
3934
|
+
try {
|
|
3935
|
+
localStorage.setItem(key, id);
|
|
3936
|
+
} catch {
|
|
3615
3937
|
}
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
previousSize,
|
|
3627
|
-
previousSnapSize === 0,
|
|
3628
|
-
true
|
|
3629
|
-
);
|
|
3630
|
-
});
|
|
3631
|
-
}
|
|
3632
|
-
clearWillChangeIfIdle() {
|
|
3633
|
-
if (this.animation.isAnimating || this.gesture?.isDragging) return;
|
|
3634
|
-
this.element.style.willChange = "";
|
|
3938
|
+
});
|
|
3939
|
+
return unsubscribe;
|
|
3940
|
+
}
|
|
3941
|
+
|
|
3942
|
+
// src/core/features/auto-collapse.ts
|
|
3943
|
+
function installAutoCollapse(deps) {
|
|
3944
|
+
const { ms } = deps;
|
|
3945
|
+
if (ms === void 0 || ms <= 0) {
|
|
3946
|
+
return () => {
|
|
3947
|
+
};
|
|
3635
3948
|
}
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3949
|
+
let timer = null;
|
|
3950
|
+
const clearTimer = () => {
|
|
3951
|
+
if (timer !== null) {
|
|
3952
|
+
clearTimeout(timer);
|
|
3953
|
+
timer = null;
|
|
3954
|
+
}
|
|
3955
|
+
};
|
|
3956
|
+
const fire = () => {
|
|
3957
|
+
if (deps.isDestroyed()) return;
|
|
3958
|
+
if (deps.isDragging()) return;
|
|
3959
|
+
const active = deps.resolveSnap(deps.getActiveId());
|
|
3960
|
+
if (!active || active.size === 0) return;
|
|
3961
|
+
let target = null;
|
|
3962
|
+
for (const id of deps.getAllowedIds()) {
|
|
3963
|
+
const snap = deps.resolveSnap(id);
|
|
3964
|
+
if (!snap || snap.size <= 0) continue;
|
|
3965
|
+
if (!target || snap.size < target.size) target = snap;
|
|
3642
3966
|
}
|
|
3967
|
+
if (!target) return;
|
|
3968
|
+
if (target.id === active.id || target.size >= active.size) return;
|
|
3969
|
+
deps.snapTo(target.id);
|
|
3970
|
+
};
|
|
3971
|
+
const reset = () => {
|
|
3972
|
+
clearTimer();
|
|
3973
|
+
if (deps.isDestroyed()) return;
|
|
3974
|
+
timer = setTimeout(() => {
|
|
3975
|
+
timer = null;
|
|
3976
|
+
fire();
|
|
3977
|
+
}, ms);
|
|
3978
|
+
};
|
|
3979
|
+
const unsubscribe = deps.on("snap", () => reset());
|
|
3980
|
+
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
|
|
3981
|
+
return () => {
|
|
3982
|
+
clearTimer();
|
|
3983
|
+
unsubscribe();
|
|
3984
|
+
};
|
|
3985
|
+
}
|
|
3986
|
+
|
|
3987
|
+
// src/core/features/content-drag.ts
|
|
3988
|
+
function installContentDrag(deps) {
|
|
3989
|
+
const detach = deps.attachDragSurface(deps.container, "content");
|
|
3990
|
+
return () => detach?.();
|
|
3991
|
+
}
|
|
3992
|
+
|
|
3993
|
+
// src/core/features/visual-viewport.ts
|
|
3994
|
+
var SAFETY_PAD = 8;
|
|
3995
|
+
function installVisualViewport(deps) {
|
|
3996
|
+
if (typeof window === "undefined" || !window.visualViewport) {
|
|
3997
|
+
return () => {
|
|
3998
|
+
};
|
|
3643
3999
|
}
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
4000
|
+
const vv = window.visualViewport;
|
|
4001
|
+
let rafId = null;
|
|
4002
|
+
const onResize = () => {
|
|
4003
|
+
if (rafId !== null) return;
|
|
4004
|
+
rafId = requestAnimationFrame(() => {
|
|
4005
|
+
rafId = null;
|
|
4006
|
+
if (deps.isDestroyed()) return;
|
|
4007
|
+
deps.recomputeSnaps();
|
|
4008
|
+
const isVertical = deps.isVerticalAxis();
|
|
4009
|
+
const visible = isVertical ? vv.height : vv.width;
|
|
4010
|
+
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
4011
|
+
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
4012
|
+
if (clamp < deps.getMaxAxisSize()) {
|
|
4013
|
+
deps.setMaxAxisSize(clamp);
|
|
3655
4014
|
}
|
|
3656
|
-
|
|
3657
|
-
|
|
4015
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
4016
|
+
deps.cancelInFlight();
|
|
4017
|
+
deps.newCycle();
|
|
4018
|
+
const max = deps.getMaxAxisSize();
|
|
4019
|
+
deps.setSize(Math.min(deps.getSize(), max));
|
|
4020
|
+
const current = deps.resolveActiveSnap();
|
|
4021
|
+
if (current && !deps.isDragging()) {
|
|
4022
|
+
deps.applySize(Math.min(current.size, max));
|
|
4023
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
4024
|
+
} else {
|
|
4025
|
+
deps.applySize(deps.getSize());
|
|
3658
4026
|
}
|
|
3659
|
-
|
|
3660
|
-
|
|
4027
|
+
});
|
|
4028
|
+
};
|
|
4029
|
+
vv.addEventListener("resize", onResize);
|
|
4030
|
+
return () => {
|
|
4031
|
+
vv.removeEventListener("resize", onResize);
|
|
4032
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
4033
|
+
};
|
|
4034
|
+
}
|
|
4035
|
+
|
|
4036
|
+
// src/core/features/engine-features.ts
|
|
4037
|
+
function routeFeature() {
|
|
4038
|
+
return {
|
|
4039
|
+
name: "route",
|
|
4040
|
+
install: (ctx) => {
|
|
4041
|
+
const teardowns = new TeardownStack();
|
|
4042
|
+
if (ctx.options.closeOnRouteChange) {
|
|
4043
|
+
teardowns.add(
|
|
4044
|
+
installRouteChange({
|
|
4045
|
+
isDestroyed: ctx.isDestroyed,
|
|
4046
|
+
getSize: ctx.getSize,
|
|
4047
|
+
close: () => ctx.close()
|
|
4048
|
+
})
|
|
4049
|
+
);
|
|
3661
4050
|
}
|
|
4051
|
+
teardowns.add(
|
|
4052
|
+
installRoute({
|
|
4053
|
+
routedTo: ctx.options.routedTo,
|
|
4054
|
+
closeOnBack: ctx.options.closeOnBack,
|
|
4055
|
+
isTopSheet: ctx.isTopSheet,
|
|
4056
|
+
getSize: ctx.getSize,
|
|
4057
|
+
isDestroyed: ctx.isDestroyed,
|
|
4058
|
+
close: () => ctx.close("back"),
|
|
4059
|
+
on: ctx.on,
|
|
4060
|
+
sheetId: ctx.sheetId
|
|
4061
|
+
})
|
|
4062
|
+
);
|
|
4063
|
+
return () => teardowns.drain();
|
|
3662
4064
|
}
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
if (
|
|
3671
|
-
|
|
3672
|
-
}
|
|
3673
|
-
if (this.rootEl && this.rootEl !== this.anchorHost) {
|
|
3674
|
-
this.rootEl.style.setProperty("--bs-progress", String(progress));
|
|
3675
|
-
}
|
|
4065
|
+
};
|
|
4066
|
+
}
|
|
4067
|
+
function persistFeature() {
|
|
4068
|
+
return {
|
|
4069
|
+
name: "persist",
|
|
4070
|
+
install: (ctx) => {
|
|
4071
|
+
const key = ctx.options.persistKey;
|
|
4072
|
+
if (!key) return;
|
|
4073
|
+
return installPersist({ on: ctx.on }, key);
|
|
3676
4074
|
}
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
4075
|
+
};
|
|
4076
|
+
}
|
|
4077
|
+
function autoCollapseFeature() {
|
|
4078
|
+
return {
|
|
4079
|
+
name: "auto-collapse",
|
|
4080
|
+
install: (ctx) => installAutoCollapse({
|
|
4081
|
+
ms: ctx.options.autoCollapseAfter,
|
|
4082
|
+
isDestroyed: ctx.isDestroyed,
|
|
4083
|
+
isDragging: ctx.isDragging,
|
|
4084
|
+
getAllowedIds: ctx.getAllowedIds,
|
|
4085
|
+
getActiveId: ctx.getActiveId,
|
|
4086
|
+
resolveSnap: ctx.resolveSnap,
|
|
4087
|
+
snapTo: ctx.snapTo,
|
|
4088
|
+
on: ctx.on
|
|
4089
|
+
})
|
|
4090
|
+
};
|
|
4091
|
+
}
|
|
4092
|
+
function contentSwipeFeature() {
|
|
4093
|
+
return {
|
|
4094
|
+
name: "content-swipe",
|
|
4095
|
+
stage: "attach",
|
|
4096
|
+
install: (ctx) => {
|
|
4097
|
+
if (!ctx.scrollContainer) return;
|
|
4098
|
+
return installContentDrag({
|
|
4099
|
+
container: ctx.scrollContainer,
|
|
4100
|
+
attachDragSurface: ctx.attachDragSurface
|
|
4101
|
+
});
|
|
3682
4102
|
}
|
|
3683
|
-
}
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
4103
|
+
};
|
|
4104
|
+
}
|
|
4105
|
+
function visualViewportFeature() {
|
|
4106
|
+
return {
|
|
4107
|
+
name: "visual-viewport",
|
|
4108
|
+
install: (ctx) => {
|
|
4109
|
+
if (typeof window === "undefined") return;
|
|
4110
|
+
return installVisualViewport({
|
|
4111
|
+
element: ctx.element,
|
|
4112
|
+
isVerticalAxis: ctx.isVerticalAxis,
|
|
4113
|
+
isDestroyed: ctx.isDestroyed,
|
|
4114
|
+
isDragging: ctx.isDragging,
|
|
4115
|
+
recomputeSnaps: ctx.recomputeSnaps,
|
|
4116
|
+
resolveActiveSnap: ctx.resolveActiveSnap,
|
|
4117
|
+
getMaxAxisSize: ctx.getMaxAxisSize,
|
|
4118
|
+
getSize: ctx.getSize,
|
|
4119
|
+
setMaxAxisSize: ctx.setMaxAxisSize,
|
|
4120
|
+
setSize: ctx.setSize,
|
|
4121
|
+
applySize: ctx.applySize,
|
|
4122
|
+
cancelInFlight: ctx.cancelInFlight,
|
|
4123
|
+
newCycle: ctx.newCycle,
|
|
4124
|
+
isAnimating: ctx.isAnimating,
|
|
4125
|
+
resyncAfterCancel: ctx.resyncAfterResize
|
|
3702
4126
|
});
|
|
3703
4127
|
}
|
|
3704
|
-
}
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
4128
|
+
};
|
|
4129
|
+
}
|
|
4130
|
+
|
|
4131
|
+
// src/core/default-features.ts
|
|
4132
|
+
function defaultEngineFeatures() {
|
|
4133
|
+
return [
|
|
4134
|
+
contentSwipeFeature(),
|
|
4135
|
+
visualViewportFeature(),
|
|
4136
|
+
persistFeature(),
|
|
4137
|
+
autoCollapseFeature(),
|
|
4138
|
+
routeFeature()
|
|
4139
|
+
];
|
|
4140
|
+
}
|
|
4141
|
+
|
|
4142
|
+
// src/core/BottomSheetEngine.ts
|
|
4143
|
+
var BottomSheetEngine = class extends BottomSheetCore {
|
|
4144
|
+
constructor(opts) {
|
|
4145
|
+
super({
|
|
4146
|
+
...opts,
|
|
4147
|
+
features: [...defaultEngineFeatures(), ...opts.features ?? []]
|
|
3714
4148
|
});
|
|
3715
|
-
if (target.size > 0 && !this.lifecycle.isInstalled) {
|
|
3716
|
-
this.emitOpenSequence(target.id);
|
|
3717
|
-
} else if (target.size === 0 && this.lifecycle.isInstalled) {
|
|
3718
|
-
this.emitCloseSequence();
|
|
3719
|
-
}
|
|
3720
|
-
}
|
|
3721
|
-
handleClose() {
|
|
3722
|
-
this.opening = false;
|
|
3723
|
-
this.lifecycle.release();
|
|
3724
|
-
sheetStack.update();
|
|
3725
4149
|
}
|
|
3726
4150
|
};
|
|
3727
4151
|
function useEnginePropSync(engineRef, opts) {
|
|
@@ -3789,6 +4213,16 @@ function useEnginePropSync(engineRef, opts) {
|
|
|
3789
4213
|
engineRef.current?.setDisableDrag(opts.disableDrag);
|
|
3790
4214
|
}
|
|
3791
4215
|
}, [opts.disableDrag]);
|
|
4216
|
+
react.useEffect(() => {
|
|
4217
|
+
if (opts.dragFrom !== void 0) {
|
|
4218
|
+
engineRef.current?.setDragFrom(opts.dragFrom);
|
|
4219
|
+
}
|
|
4220
|
+
}, [opts.dragFrom]);
|
|
4221
|
+
react.useEffect(() => {
|
|
4222
|
+
if (opts.dragFromContent !== void 0) {
|
|
4223
|
+
engineRef.current?.setDragFromContent(opts.dragFromContent);
|
|
4224
|
+
}
|
|
4225
|
+
}, [opts.disableDrag]);
|
|
3792
4226
|
}
|
|
3793
4227
|
|
|
3794
4228
|
// src/core/features/teleport.ts
|
|
@@ -3937,7 +4371,9 @@ function useBottomSheet(opts) {
|
|
|
3937
4371
|
maxHeight: opts.maxHeight,
|
|
3938
4372
|
persistent: opts.persistent,
|
|
3939
4373
|
disableClose: opts.disableClose,
|
|
3940
|
-
disableDrag: opts.disableDrag
|
|
4374
|
+
disableDrag: opts.disableDrag,
|
|
4375
|
+
dragFrom: opts.dragFrom,
|
|
4376
|
+
dragFromContent: opts.dragFromContent
|
|
3941
4377
|
});
|
|
3942
4378
|
const subscribe = react.useCallback((fn) => {
|
|
3943
4379
|
subscribersRef.current.add(fn);
|
|
@@ -4005,7 +4441,6 @@ function useBottomSheet(opts) {
|
|
|
4005
4441
|
addAnchor,
|
|
4006
4442
|
setScrimStages,
|
|
4007
4443
|
recompute,
|
|
4008
|
-
engine: engineRef.current,
|
|
4009
4444
|
getEngine
|
|
4010
4445
|
}),
|
|
4011
4446
|
[
|