@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/svelte-core.js
CHANGED
|
@@ -4,7 +4,7 @@ var __defProp = Object.defineProperty;
|
|
|
4
4
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
5
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
6
|
|
|
7
|
-
// src/core/lifecycle/
|
|
7
|
+
// src/core/lifecycle/sheet-stack.ts
|
|
8
8
|
var BASE_Z = 100;
|
|
9
9
|
var STEP = 10;
|
|
10
10
|
var SheetStack = class {
|
|
@@ -129,7 +129,7 @@ function createEventBus() {
|
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
// src/core/primitives/
|
|
132
|
+
// src/core/primitives/css-length.ts
|
|
133
133
|
var probe = null;
|
|
134
134
|
var PROBE_ATTR = "data-bs-probe";
|
|
135
135
|
var ensureProbe = (axis) => {
|
|
@@ -183,7 +183,7 @@ var resolveSnap = (point, mode, measureFit) => {
|
|
|
183
183
|
return Math.max(0, el.getBoundingClientRect().width);
|
|
184
184
|
};
|
|
185
185
|
|
|
186
|
-
// src/core/primitives/
|
|
186
|
+
// src/core/primitives/dev-warn.ts
|
|
187
187
|
function devWarn(...args) {
|
|
188
188
|
if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
|
|
189
189
|
console.warn(...args);
|
|
@@ -348,74 +348,6 @@ var SnapResolver = class {
|
|
|
348
348
|
}
|
|
349
349
|
};
|
|
350
350
|
|
|
351
|
-
// src/core/features/persist.ts
|
|
352
|
-
function readPersistedId(key) {
|
|
353
|
-
if (!key) return null;
|
|
354
|
-
if (typeof window === "undefined") return null;
|
|
355
|
-
if (typeof localStorage === "undefined") return null;
|
|
356
|
-
try {
|
|
357
|
-
return localStorage.getItem(key);
|
|
358
|
-
} catch {
|
|
359
|
-
return null;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
function installPersist(engine, key) {
|
|
363
|
-
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
364
|
-
if (typeof window === "undefined") return;
|
|
365
|
-
if (typeof localStorage === "undefined") return;
|
|
366
|
-
try {
|
|
367
|
-
localStorage.setItem(key, id);
|
|
368
|
-
} catch {
|
|
369
|
-
}
|
|
370
|
-
});
|
|
371
|
-
return unsubscribe;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// src/core/features/auto-collapse.ts
|
|
375
|
-
function installAutoCollapse(deps) {
|
|
376
|
-
const { ms } = deps;
|
|
377
|
-
if (ms === void 0 || ms <= 0) {
|
|
378
|
-
return () => {
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
let timer = null;
|
|
382
|
-
const clearTimer = () => {
|
|
383
|
-
if (timer !== null) {
|
|
384
|
-
clearTimeout(timer);
|
|
385
|
-
timer = null;
|
|
386
|
-
}
|
|
387
|
-
};
|
|
388
|
-
const fire = () => {
|
|
389
|
-
if (deps.isDestroyed()) return;
|
|
390
|
-
if (deps.isDragging()) return;
|
|
391
|
-
const active = deps.resolveSnap(deps.getActiveId());
|
|
392
|
-
if (!active || active.size === 0) return;
|
|
393
|
-
let target = null;
|
|
394
|
-
for (const id of deps.getAllowedIds()) {
|
|
395
|
-
const snap = deps.resolveSnap(id);
|
|
396
|
-
if (!snap || snap.size <= 0) continue;
|
|
397
|
-
if (!target || snap.size < target.size) target = snap;
|
|
398
|
-
}
|
|
399
|
-
if (!target) return;
|
|
400
|
-
if (target.id === active.id || target.size >= active.size) return;
|
|
401
|
-
deps.snapTo(target.id);
|
|
402
|
-
};
|
|
403
|
-
const reset = () => {
|
|
404
|
-
clearTimer();
|
|
405
|
-
if (deps.isDestroyed()) return;
|
|
406
|
-
timer = setTimeout(() => {
|
|
407
|
-
timer = null;
|
|
408
|
-
fire();
|
|
409
|
-
}, ms);
|
|
410
|
-
};
|
|
411
|
-
const unsubscribe = deps.on("snap", () => reset());
|
|
412
|
-
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
|
|
413
|
-
return () => {
|
|
414
|
-
clearTimer();
|
|
415
|
-
unsubscribe();
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
|
|
419
351
|
// src/core/features/linked-sheets.ts
|
|
420
352
|
function notifyLinkedSheets(sheets, self) {
|
|
421
353
|
if (sheets.length === 0) return;
|
|
@@ -438,394 +370,65 @@ function notifyLinkedSheets(sheets, self) {
|
|
|
438
370
|
}
|
|
439
371
|
}
|
|
440
372
|
|
|
441
|
-
// src/core/features/
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
var pendingRebrand = null;
|
|
447
|
-
var listenerInstalled = false;
|
|
448
|
-
var patchInstalled = false;
|
|
449
|
-
var origPushState = null;
|
|
450
|
-
var origReplaceState = null;
|
|
451
|
-
var patchedPushState = null;
|
|
452
|
-
var patchedReplaceState = null;
|
|
453
|
-
var hasWindow = () => typeof window !== "undefined";
|
|
454
|
-
var hasHistory = () => typeof history !== "undefined";
|
|
455
|
-
var brandMarker = (surface) => ({
|
|
456
|
-
...surface.markerState(),
|
|
457
|
-
__bs: true
|
|
458
|
-
});
|
|
459
|
-
var runInternal = (fn) => {
|
|
460
|
-
internalDepth += 1;
|
|
461
|
-
try {
|
|
462
|
-
fn();
|
|
463
|
-
} finally {
|
|
464
|
-
internalDepth -= 1;
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
var notifyRouteChange = () => {
|
|
468
|
-
const snapshot = Array.from(subscribers);
|
|
469
|
-
for (const fn of snapshot) fn();
|
|
470
|
-
};
|
|
471
|
-
var ensureListener = () => {
|
|
472
|
-
if (listenerInstalled || !hasWindow()) return;
|
|
473
|
-
window.addEventListener("popstate", onPopState);
|
|
474
|
-
listenerInstalled = true;
|
|
475
|
-
};
|
|
476
|
-
var maybeTeardownListener = () => {
|
|
477
|
-
if (!listenerInstalled) return;
|
|
478
|
-
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
479
|
-
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
480
|
-
listenerInstalled = false;
|
|
481
|
-
};
|
|
482
|
-
var installPatch = () => {
|
|
483
|
-
if (patchInstalled || !hasHistory()) return;
|
|
484
|
-
origPushState = history.pushState;
|
|
485
|
-
origReplaceState = history.replaceState;
|
|
486
|
-
patchedPushState = function(...args) {
|
|
487
|
-
origPushState.apply(this, args);
|
|
488
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
489
|
-
};
|
|
490
|
-
patchedReplaceState = function(...args) {
|
|
491
|
-
origReplaceState.apply(this, args);
|
|
492
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
493
|
-
};
|
|
494
|
-
history.pushState = patchedPushState;
|
|
495
|
-
history.replaceState = patchedReplaceState;
|
|
496
|
-
patchInstalled = true;
|
|
497
|
-
};
|
|
498
|
-
var removePatch = () => {
|
|
499
|
-
if (!patchInstalled) return;
|
|
500
|
-
if (history.pushState === patchedPushState && origPushState) {
|
|
501
|
-
history.pushState = origPushState;
|
|
502
|
-
}
|
|
503
|
-
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
504
|
-
history.replaceState = origReplaceState;
|
|
505
|
-
}
|
|
506
|
-
origPushState = null;
|
|
507
|
-
origReplaceState = null;
|
|
508
|
-
patchedPushState = null;
|
|
509
|
-
patchedReplaceState = null;
|
|
510
|
-
patchInstalled = false;
|
|
511
|
-
};
|
|
512
|
-
function onPopState() {
|
|
513
|
-
if (suppress > 0) {
|
|
514
|
-
suppress -= 1;
|
|
515
|
-
const rebrand = pendingRebrand;
|
|
516
|
-
pendingRebrand = null;
|
|
517
|
-
if (rebrand) rebrand();
|
|
518
|
-
maybeTeardownListener();
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
if (entries.length === 0) {
|
|
522
|
-
notifyRouteChange();
|
|
523
|
-
maybeTeardownListener();
|
|
524
|
-
return;
|
|
373
|
+
// src/core/features/resize-observer.ts
|
|
374
|
+
function installResizeObserver(deps) {
|
|
375
|
+
if (typeof window === "undefined") {
|
|
376
|
+
return () => {
|
|
377
|
+
};
|
|
525
378
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
const
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
379
|
+
const onResize = () => {
|
|
380
|
+
if (deps.isDestroyed()) return;
|
|
381
|
+
deps.recomputeSnaps();
|
|
382
|
+
const mode = deps.getMode();
|
|
383
|
+
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
384
|
+
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
385
|
+
const max = deps.getMaxAxisSize();
|
|
386
|
+
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
387
|
+
deps.setMaxAxisSize(viewportSize2);
|
|
534
388
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
389
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
390
|
+
deps.cancelInFlight();
|
|
391
|
+
deps.newCycle();
|
|
392
|
+
const current = deps.resolveActiveSnap();
|
|
393
|
+
const newMax = deps.getMaxAxisSize();
|
|
394
|
+
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
395
|
+
deps.setSize(targetSize);
|
|
396
|
+
if (current && !deps.isDragging()) {
|
|
397
|
+
deps.applySize(targetSize);
|
|
398
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
539
399
|
}
|
|
400
|
+
};
|
|
401
|
+
let resizeObserver = null;
|
|
402
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
403
|
+
resizeObserver = new ResizeObserver(onResize);
|
|
404
|
+
resizeObserver.observe(document.documentElement);
|
|
405
|
+
} else {
|
|
406
|
+
window.addEventListener("resize", onResize);
|
|
540
407
|
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
if (
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
}
|
|
553
|
-
maybeTeardownListener();
|
|
408
|
+
window.addEventListener("orientationchange", onResize);
|
|
409
|
+
const onVisibility = () => {
|
|
410
|
+
if (deps.isDestroyed()) return;
|
|
411
|
+
if (document.hidden) deps.cancelInFlight();
|
|
412
|
+
};
|
|
413
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
414
|
+
return () => {
|
|
415
|
+
resizeObserver?.disconnect();
|
|
416
|
+
window.removeEventListener("resize", onResize);
|
|
417
|
+
window.removeEventListener("orientationchange", onResize);
|
|
418
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
419
|
+
};
|
|
554
420
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
entries.push(entry);
|
|
567
|
-
ensureListener();
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
function pushBackMarker(surface) {
|
|
571
|
-
const entry = { surface, priorUrl: void 0, live: false };
|
|
572
|
-
if (!hasWindow() || !hasHistory()) {
|
|
573
|
-
return entry;
|
|
574
|
-
}
|
|
575
|
-
entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
|
|
576
|
-
runInternal(() => {
|
|
577
|
-
try {
|
|
578
|
-
history.pushState(brandMarker(surface), "", surface.url);
|
|
579
|
-
entry.live = true;
|
|
580
|
-
} catch {
|
|
581
|
-
entry.live = false;
|
|
582
|
-
}
|
|
583
|
-
});
|
|
584
|
-
if (entry.live) {
|
|
585
|
-
entries.push(entry);
|
|
586
|
-
ensureListener();
|
|
587
|
-
}
|
|
588
|
-
return entry;
|
|
589
|
-
}
|
|
590
|
-
function popBackMarker(handle) {
|
|
591
|
-
if (!hasWindow() || !hasHistory()) return;
|
|
592
|
-
const entry = handle;
|
|
593
|
-
const idx = entries.indexOf(entry);
|
|
594
|
-
if (idx === -1 || !entry.live) return;
|
|
595
|
-
const last = entries.length - 1;
|
|
596
|
-
entry.live = false;
|
|
597
|
-
entries.splice(idx, 1);
|
|
598
|
-
if (idx !== last) {
|
|
599
|
-
const rebrandSurface = entries[entries.length - 1].surface;
|
|
600
|
-
const rebrandUrl = entry.priorUrl;
|
|
601
|
-
pendingRebrand = () => {
|
|
602
|
-
runInternal(() => {
|
|
603
|
-
history.replaceState(
|
|
604
|
-
brandMarker(rebrandSurface),
|
|
605
|
-
"",
|
|
606
|
-
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
607
|
-
);
|
|
608
|
-
});
|
|
609
|
-
};
|
|
610
|
-
}
|
|
611
|
-
suppress += 1;
|
|
612
|
-
runInternal(() => {
|
|
613
|
-
try {
|
|
614
|
-
history.back();
|
|
615
|
-
} catch {
|
|
616
|
-
suppress = Math.max(0, suppress - 1);
|
|
617
|
-
pendingRebrand = null;
|
|
618
|
-
}
|
|
619
|
-
});
|
|
620
|
-
maybeTeardownListener();
|
|
621
|
-
}
|
|
622
|
-
function subscribeRouteChange(fn) {
|
|
623
|
-
if (!hasWindow() || !hasHistory()) return () => {
|
|
624
|
-
};
|
|
625
|
-
subscribers.add(fn);
|
|
626
|
-
if (subscribers.size === 1) installPatch();
|
|
627
|
-
ensureListener();
|
|
628
|
-
return () => {
|
|
629
|
-
if (!subscribers.has(fn)) return;
|
|
630
|
-
subscribers.delete(fn);
|
|
631
|
-
if (subscribers.size === 0) removePatch();
|
|
632
|
-
maybeTeardownListener();
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
// src/core/features/route.ts
|
|
637
|
-
function installRoute(deps) {
|
|
638
|
-
if (typeof window === "undefined") {
|
|
639
|
-
return () => {
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
|
-
if (!deps.routedTo && !deps.closeOnBack) {
|
|
643
|
-
return () => {
|
|
644
|
-
};
|
|
645
|
-
}
|
|
646
|
-
let handle = null;
|
|
647
|
-
const onOpen = () => {
|
|
648
|
-
if (handle) return;
|
|
649
|
-
handle = pushBackMarker({
|
|
650
|
-
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
651
|
-
isTop: deps.isTopSheet,
|
|
652
|
-
close: deps.close,
|
|
653
|
-
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
654
|
-
url: deps.routedTo
|
|
655
|
-
});
|
|
656
|
-
};
|
|
657
|
-
const onClose = () => {
|
|
658
|
-
if (!handle) return;
|
|
659
|
-
popBackMarker(handle);
|
|
660
|
-
handle = null;
|
|
661
|
-
};
|
|
662
|
-
const unsubscribeOpen = deps.on("open", onOpen);
|
|
663
|
-
const unsubscribeClose = deps.on("close", onClose);
|
|
664
|
-
if (deps.getSize() > 0) onOpen();
|
|
665
|
-
return () => {
|
|
666
|
-
unsubscribeOpen();
|
|
667
|
-
unsubscribeClose();
|
|
668
|
-
if (handle) {
|
|
669
|
-
popBackMarker(handle);
|
|
670
|
-
handle = null;
|
|
671
|
-
}
|
|
672
|
-
};
|
|
673
|
-
}
|
|
674
|
-
function installRouteChange(deps) {
|
|
675
|
-
return subscribeRouteChange(() => {
|
|
676
|
-
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
677
|
-
void deps.close();
|
|
678
|
-
});
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
// src/core/features/content-swipe.ts
|
|
682
|
-
var CONTENT_PULL_THRESHOLD = 60;
|
|
683
|
-
function installContentSwipe(deps) {
|
|
684
|
-
const { container } = deps;
|
|
685
|
-
let startY = 0;
|
|
686
|
-
let startScrollTop = 0;
|
|
687
|
-
let moved = false;
|
|
688
|
-
const onTouchStart = (e) => {
|
|
689
|
-
const t = e.touches[0];
|
|
690
|
-
if (!t) return;
|
|
691
|
-
startY = t.clientY;
|
|
692
|
-
startScrollTop = container.scrollTop;
|
|
693
|
-
moved = false;
|
|
694
|
-
};
|
|
695
|
-
const onTouchMove = (e) => {
|
|
696
|
-
const t = e.touches[0];
|
|
697
|
-
if (!t) return;
|
|
698
|
-
if (Math.abs(t.clientY - startY) > CONTENT_PULL_THRESHOLD) moved = true;
|
|
699
|
-
};
|
|
700
|
-
const onTouchEnd = (e) => {
|
|
701
|
-
if (!moved) return;
|
|
702
|
-
if (deps.isDragging() || deps.isAnimating()) return;
|
|
703
|
-
if (container.scrollTop !== startScrollTop) return;
|
|
704
|
-
const t = e.changedTouches[0];
|
|
705
|
-
if (!t) return;
|
|
706
|
-
const deltaY = t.clientY - startY;
|
|
707
|
-
const atTop = container.scrollTop <= 0;
|
|
708
|
-
const allowed = deps.getAllowedIds();
|
|
709
|
-
const idx = allowed.indexOf(deps.getActiveId());
|
|
710
|
-
if (idx === -1) return;
|
|
711
|
-
if (atTop && deltaY > CONTENT_PULL_THRESHOLD && idx > 0) {
|
|
712
|
-
deps.snapTo(allowed[idx - 1]);
|
|
713
|
-
} else if (deltaY < -CONTENT_PULL_THRESHOLD && idx < allowed.length - 1) {
|
|
714
|
-
deps.snapTo(allowed[idx + 1]);
|
|
715
|
-
}
|
|
716
|
-
};
|
|
717
|
-
container.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
718
|
-
container.addEventListener("touchmove", onTouchMove, { passive: true });
|
|
719
|
-
container.addEventListener("touchend", onTouchEnd, { passive: true });
|
|
720
|
-
return () => {
|
|
721
|
-
container.removeEventListener("touchstart", onTouchStart);
|
|
722
|
-
container.removeEventListener("touchmove", onTouchMove);
|
|
723
|
-
container.removeEventListener("touchend", onTouchEnd);
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
// src/core/features/visual-viewport.ts
|
|
728
|
-
var SAFETY_PAD = 8;
|
|
729
|
-
function installVisualViewport(deps) {
|
|
730
|
-
if (typeof window === "undefined" || !window.visualViewport) {
|
|
731
|
-
return () => {
|
|
732
|
-
};
|
|
733
|
-
}
|
|
734
|
-
const vv = window.visualViewport;
|
|
735
|
-
let rafId = null;
|
|
736
|
-
const onResize = () => {
|
|
737
|
-
if (rafId !== null) return;
|
|
738
|
-
rafId = requestAnimationFrame(() => {
|
|
739
|
-
rafId = null;
|
|
740
|
-
if (deps.isDestroyed()) return;
|
|
741
|
-
deps.recomputeSnaps();
|
|
742
|
-
const isVertical = deps.isVerticalAxis();
|
|
743
|
-
const visible = isVertical ? vv.height : vv.width;
|
|
744
|
-
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
745
|
-
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
746
|
-
if (clamp < deps.getMaxAxisSize()) {
|
|
747
|
-
deps.setMaxAxisSize(clamp);
|
|
748
|
-
}
|
|
749
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
750
|
-
deps.cancelInFlight();
|
|
751
|
-
deps.newCycle();
|
|
752
|
-
const max = deps.getMaxAxisSize();
|
|
753
|
-
deps.setSize(Math.min(deps.getSize(), max));
|
|
754
|
-
const current = deps.resolveActiveSnap();
|
|
755
|
-
if (current && !deps.isDragging()) {
|
|
756
|
-
deps.applySize(Math.min(current.size, max));
|
|
757
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
758
|
-
} else {
|
|
759
|
-
deps.applySize(deps.getSize());
|
|
760
|
-
}
|
|
761
|
-
});
|
|
762
|
-
};
|
|
763
|
-
vv.addEventListener("resize", onResize);
|
|
764
|
-
return () => {
|
|
765
|
-
vv.removeEventListener("resize", onResize);
|
|
766
|
-
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
// src/core/features/resize-observer.ts
|
|
771
|
-
function installResizeObserver(deps) {
|
|
772
|
-
if (typeof window === "undefined") {
|
|
773
|
-
return () => {
|
|
774
|
-
};
|
|
775
|
-
}
|
|
776
|
-
const onResize = () => {
|
|
777
|
-
if (deps.isDestroyed()) return;
|
|
778
|
-
deps.recomputeSnaps();
|
|
779
|
-
const mode = deps.getMode();
|
|
780
|
-
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
781
|
-
const viewportSize2 = isVerticalAxis ? window.innerHeight : window.innerWidth;
|
|
782
|
-
const max = deps.getMaxAxisSize();
|
|
783
|
-
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
784
|
-
deps.setMaxAxisSize(viewportSize2);
|
|
785
|
-
}
|
|
786
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
787
|
-
deps.cancelInFlight();
|
|
788
|
-
deps.newCycle();
|
|
789
|
-
const current = deps.resolveActiveSnap();
|
|
790
|
-
const newMax = deps.getMaxAxisSize();
|
|
791
|
-
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
792
|
-
deps.setSize(targetSize);
|
|
793
|
-
if (current && !deps.isDragging()) {
|
|
794
|
-
deps.applySize(targetSize);
|
|
795
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
796
|
-
}
|
|
797
|
-
};
|
|
798
|
-
let resizeObserver = null;
|
|
799
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
800
|
-
resizeObserver = new ResizeObserver(onResize);
|
|
801
|
-
resizeObserver.observe(document.documentElement);
|
|
802
|
-
} else {
|
|
803
|
-
window.addEventListener("resize", onResize);
|
|
804
|
-
}
|
|
805
|
-
window.addEventListener("orientationchange", onResize);
|
|
806
|
-
const onVisibility = () => {
|
|
807
|
-
if (deps.isDestroyed()) return;
|
|
808
|
-
if (document.hidden) deps.cancelInFlight();
|
|
809
|
-
};
|
|
810
|
-
document.addEventListener("visibilitychange", onVisibility);
|
|
811
|
-
return () => {
|
|
812
|
-
resizeObserver?.disconnect();
|
|
813
|
-
window.removeEventListener("resize", onResize);
|
|
814
|
-
window.removeEventListener("orientationchange", onResize);
|
|
815
|
-
document.removeEventListener("visibilitychange", onVisibility);
|
|
816
|
-
};
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
// src/core/features/fit-observer.ts
|
|
820
|
-
var contentTargets = (scroller) => {
|
|
821
|
-
if (!scroller) return [];
|
|
822
|
-
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
823
|
-
const out = [];
|
|
824
|
-
for (const child of Array.from(scroller.children)) {
|
|
825
|
-
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
826
|
-
for (const el of child.assignedElements()) out.push(el);
|
|
827
|
-
} else {
|
|
828
|
-
out.push(child);
|
|
421
|
+
|
|
422
|
+
// src/core/features/fit-observer.ts
|
|
423
|
+
var contentTargets = (scroller) => {
|
|
424
|
+
if (!scroller) return [];
|
|
425
|
+
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
426
|
+
const out = [];
|
|
427
|
+
for (const child of Array.from(scroller.children)) {
|
|
428
|
+
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
429
|
+
for (const el of child.assignedElements()) out.push(el);
|
|
430
|
+
} else {
|
|
431
|
+
out.push(child);
|
|
829
432
|
}
|
|
830
433
|
}
|
|
831
434
|
return out;
|
|
@@ -1667,6 +1270,52 @@ function resolveAnimationPreset(animation) {
|
|
|
1667
1270
|
}
|
|
1668
1271
|
}
|
|
1669
1272
|
|
|
1273
|
+
// src/core/animation/waapi-settle.ts
|
|
1274
|
+
var SIM_HZ = 240;
|
|
1275
|
+
var SAMPLE_STRIDE = 4;
|
|
1276
|
+
var MAX_SIM_MS = 3e3;
|
|
1277
|
+
function sampleSpringSettle(from, to, velocityPxPerS, config) {
|
|
1278
|
+
const cfg = { ...DEFAULT_SPRING, ...config };
|
|
1279
|
+
const subDt = 1 / SIM_HZ;
|
|
1280
|
+
const stepMs = SAMPLE_STRIDE / SIM_HZ * 1e3;
|
|
1281
|
+
const maxSteps = Math.ceil(MAX_SIM_MS / 1e3 * SIM_HZ);
|
|
1282
|
+
const values = [from];
|
|
1283
|
+
let x = from;
|
|
1284
|
+
let v = velocityPxPerS;
|
|
1285
|
+
for (let i = 1; i <= maxSteps; i += 1) {
|
|
1286
|
+
const force = -cfg.stiffness * (x - to) - cfg.damping * v;
|
|
1287
|
+
v += force / cfg.mass * subDt;
|
|
1288
|
+
x += v * subDt;
|
|
1289
|
+
if (!Number.isFinite(x) || !Number.isFinite(v)) {
|
|
1290
|
+
values.push(to);
|
|
1291
|
+
break;
|
|
1292
|
+
}
|
|
1293
|
+
if (i % SAMPLE_STRIDE === 0) values.push(x);
|
|
1294
|
+
const atRest = Math.abs(to - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
|
|
1295
|
+
if (atRest) break;
|
|
1296
|
+
}
|
|
1297
|
+
if (values[values.length - 1] !== to) values.push(to);
|
|
1298
|
+
return {
|
|
1299
|
+
values,
|
|
1300
|
+
stepMs,
|
|
1301
|
+
durationMs: (values.length - 1) * stepMs
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
function sampleTweenSettle(from, to, durationMs, easing) {
|
|
1305
|
+
const count = Math.max(2, Math.min(60, Math.round(durationMs / 16)));
|
|
1306
|
+
const values = [];
|
|
1307
|
+
for (let i = 0; i <= count; i += 1) {
|
|
1308
|
+
const t = i / count;
|
|
1309
|
+
values.push(from + (to - from) * easing(t));
|
|
1310
|
+
}
|
|
1311
|
+
values[values.length - 1] = to;
|
|
1312
|
+
return {
|
|
1313
|
+
values,
|
|
1314
|
+
stepMs: durationMs / count,
|
|
1315
|
+
durationMs
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1670
1319
|
// src/core/controllers/animation-runner.ts
|
|
1671
1320
|
var DEFAULT_DURATION2 = 220;
|
|
1672
1321
|
var VELOCITY_PX_PER_S = 1e3;
|
|
@@ -1677,6 +1326,10 @@ var AnimationRunner = class {
|
|
|
1677
1326
|
__publicField(this, "applySizeFn");
|
|
1678
1327
|
__publicField(this, "getSize");
|
|
1679
1328
|
__publicField(this, "isDragging");
|
|
1329
|
+
__publicField(this, "applyAux");
|
|
1330
|
+
__publicField(this, "getTransformFor");
|
|
1331
|
+
__publicField(this, "settleWaapi");
|
|
1332
|
+
__publicField(this, "currentWaapi", null);
|
|
1680
1333
|
__publicField(this, "animationKind");
|
|
1681
1334
|
__publicField(this, "springConfig");
|
|
1682
1335
|
__publicField(this, "duration");
|
|
@@ -1692,6 +1345,9 @@ var AnimationRunner = class {
|
|
|
1692
1345
|
this.applySizeFn = deps.applySize;
|
|
1693
1346
|
this.getSize = deps.getSize;
|
|
1694
1347
|
this.isDragging = deps.isDragging;
|
|
1348
|
+
this.applyAux = deps.applyAux;
|
|
1349
|
+
this.getTransformFor = deps.getTransformFor;
|
|
1350
|
+
this.settleWaapi = opts.settleAnimation === "waapi";
|
|
1695
1351
|
const preset = resolveAnimationPreset(opts.animation);
|
|
1696
1352
|
this.animationKind = preset.kind;
|
|
1697
1353
|
this.duration = opts.duration ?? preset.duration ?? DEFAULT_DURATION2;
|
|
@@ -1716,11 +1372,20 @@ var AnimationRunner = class {
|
|
|
1716
1372
|
}
|
|
1717
1373
|
}
|
|
1718
1374
|
get isAnimating() {
|
|
1719
|
-
return this.currentTween !== null || this.currentSpring !== null;
|
|
1375
|
+
return this.currentTween !== null || this.currentSpring !== null || this.currentWaapi !== null;
|
|
1720
1376
|
}
|
|
1721
1377
|
cancel() {
|
|
1722
1378
|
this.currentTween?.cancel();
|
|
1723
1379
|
this.currentSpring?.cancel();
|
|
1380
|
+
if (this.currentWaapi) {
|
|
1381
|
+
const entry = this.currentWaapi;
|
|
1382
|
+
this.currentWaapi = null;
|
|
1383
|
+
entry.stop();
|
|
1384
|
+
try {
|
|
1385
|
+
entry.anim.cancel();
|
|
1386
|
+
} catch {
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1724
1389
|
}
|
|
1725
1390
|
async animateTo(target, velocityPxPerMs) {
|
|
1726
1391
|
if (target === this.getSize()) {
|
|
@@ -1739,6 +1404,27 @@ var AnimationRunner = class {
|
|
|
1739
1404
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1740
1405
|
return;
|
|
1741
1406
|
}
|
|
1407
|
+
if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
|
|
1408
|
+
const samples = this.animationKind === "spring" ? sampleSpringSettle(
|
|
1409
|
+
this.getSize(),
|
|
1410
|
+
target,
|
|
1411
|
+
velocityPxPerMs * VELOCITY_PX_PER_S,
|
|
1412
|
+
this.springConfig
|
|
1413
|
+
) : sampleTweenSettle(
|
|
1414
|
+
this.getSize(),
|
|
1415
|
+
target,
|
|
1416
|
+
this.duration,
|
|
1417
|
+
this.easing
|
|
1418
|
+
);
|
|
1419
|
+
if (samples.values.length >= 2 && samples.durationMs > 0) {
|
|
1420
|
+
await this.runWaapiSettle(samples, target);
|
|
1421
|
+
if (!this.isAnimating) {
|
|
1422
|
+
this.getRootEl()?.removeAttribute("data-animating");
|
|
1423
|
+
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1424
|
+
}
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1742
1428
|
if (this.animationKind === "spring") {
|
|
1743
1429
|
const spring = runSpring({
|
|
1744
1430
|
from: this.getSize(),
|
|
@@ -1767,15 +1453,70 @@ var AnimationRunner = class {
|
|
|
1767
1453
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1768
1454
|
}
|
|
1769
1455
|
}
|
|
1456
|
+
async runWaapiSettle(samples, target) {
|
|
1457
|
+
const applyAux = this.applyAux;
|
|
1458
|
+
const getTransformFor = this.getTransformFor;
|
|
1459
|
+
const frames = samples.values.map((v) => ({
|
|
1460
|
+
transform: getTransformFor(v)
|
|
1461
|
+
}));
|
|
1462
|
+
const anim = this.element.animate(frames, {
|
|
1463
|
+
duration: samples.durationMs,
|
|
1464
|
+
easing: "linear",
|
|
1465
|
+
fill: "forwards"
|
|
1466
|
+
});
|
|
1467
|
+
let stopped = false;
|
|
1468
|
+
let auxRaf = 0;
|
|
1469
|
+
const start = performance.now();
|
|
1470
|
+
const lastIdx = samples.values.length - 1;
|
|
1471
|
+
const auxTick = () => {
|
|
1472
|
+
if (stopped) return;
|
|
1473
|
+
const elapsed = performance.now() - start;
|
|
1474
|
+
const idx = Math.min(Math.floor(elapsed / samples.stepMs), lastIdx);
|
|
1475
|
+
applyAux(samples.values[idx]);
|
|
1476
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1477
|
+
};
|
|
1478
|
+
auxRaf = requestAnimationFrame(auxTick);
|
|
1479
|
+
const entry = {
|
|
1480
|
+
anim,
|
|
1481
|
+
stop: () => {
|
|
1482
|
+
stopped = true;
|
|
1483
|
+
cancelAnimationFrame(auxRaf);
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
this.currentWaapi = entry;
|
|
1487
|
+
try {
|
|
1488
|
+
await anim.finished;
|
|
1489
|
+
} catch {
|
|
1490
|
+
}
|
|
1491
|
+
entry.stop();
|
|
1492
|
+
const wasCurrent = this.currentWaapi === entry;
|
|
1493
|
+
if (wasCurrent) this.currentWaapi = null;
|
|
1494
|
+
if (wasCurrent && anim.playState === "finished") {
|
|
1495
|
+
this.applySizeFn(target);
|
|
1496
|
+
try {
|
|
1497
|
+
anim.cancel();
|
|
1498
|
+
} catch {
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1770
1502
|
destroy() {
|
|
1771
1503
|
this.detachReducedMotion?.();
|
|
1772
1504
|
this.detachReducedMotion = null;
|
|
1773
1505
|
this.currentTween = null;
|
|
1774
1506
|
this.currentSpring = null;
|
|
1507
|
+
if (this.currentWaapi) {
|
|
1508
|
+
const entry = this.currentWaapi;
|
|
1509
|
+
this.currentWaapi = null;
|
|
1510
|
+
entry.stop();
|
|
1511
|
+
try {
|
|
1512
|
+
entry.anim.cancel();
|
|
1513
|
+
} catch {
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1775
1516
|
}
|
|
1776
1517
|
};
|
|
1777
1518
|
|
|
1778
|
-
// src/core/lifecycle/
|
|
1519
|
+
// src/core/lifecycle/focus-trap.ts
|
|
1779
1520
|
var FOCUSABLE = [
|
|
1780
1521
|
"a[href]",
|
|
1781
1522
|
"area[href]",
|
|
@@ -1893,7 +1634,7 @@ var installFocusTrap = (container, options = {}) => {
|
|
|
1893
1634
|
};
|
|
1894
1635
|
};
|
|
1895
1636
|
|
|
1896
|
-
// src/core/lifecycle/
|
|
1637
|
+
// src/core/lifecycle/scroll-lock.ts
|
|
1897
1638
|
var lockCount = 0;
|
|
1898
1639
|
var savedStyles = null;
|
|
1899
1640
|
var lockBodyScroll = () => {
|
|
@@ -2075,30 +1816,44 @@ var SampleRing = class {
|
|
|
2075
1816
|
this.size = 0;
|
|
2076
1817
|
}
|
|
2077
1818
|
};
|
|
2078
|
-
var installGestures = (handle, mode, callbacks) => {
|
|
1819
|
+
var installGestures = (handle, mode, callbacks, options = {}) => {
|
|
2079
1820
|
let activePointerId = null;
|
|
2080
1821
|
let activePointerType = "touch";
|
|
2081
1822
|
let startCoord = 0;
|
|
2082
1823
|
let lastCoord = 0;
|
|
1824
|
+
let pendingStart = false;
|
|
2083
1825
|
const VELOCITY_WINDOW_MS = (kind) => kind === "mouse" ? 160 : 120;
|
|
2084
1826
|
const MAX_SAMPLES = 32;
|
|
2085
1827
|
const samples = new SampleRing(MAX_SAMPLES);
|
|
2086
1828
|
const axis = isAxisVertical(mode) ? "Y" : "X";
|
|
2087
1829
|
const sign = mode === "bottom" || mode === "right" ? -1 : 1;
|
|
2088
1830
|
const coordOf = (e) => axis === "Y" ? e.clientY : e.clientX;
|
|
1831
|
+
const capture = (pointerId) => {
|
|
1832
|
+
try {
|
|
1833
|
+
handle.setPointerCapture(pointerId);
|
|
1834
|
+
} catch {
|
|
1835
|
+
}
|
|
1836
|
+
};
|
|
1837
|
+
const releaseTracking = () => {
|
|
1838
|
+
activePointerId = null;
|
|
1839
|
+
pendingStart = false;
|
|
1840
|
+
samples.reset();
|
|
1841
|
+
};
|
|
2089
1842
|
const onPointerDown = (e) => {
|
|
2090
1843
|
if (activePointerId !== null) return;
|
|
2091
1844
|
if (e.button !== void 0 && e.button !== 0) return;
|
|
1845
|
+
if (options.shouldStart && !options.shouldStart(e)) return;
|
|
2092
1846
|
activePointerId = e.pointerId;
|
|
2093
1847
|
activePointerType = e.pointerType || "touch";
|
|
2094
1848
|
startCoord = coordOf(e);
|
|
2095
1849
|
lastCoord = startCoord;
|
|
2096
1850
|
samples.reset();
|
|
2097
1851
|
samples.push(e.timeStamp, startCoord);
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
1852
|
+
if (options.deferStart) {
|
|
1853
|
+
pendingStart = true;
|
|
1854
|
+
return;
|
|
2101
1855
|
}
|
|
1856
|
+
capture(e.pointerId);
|
|
2102
1857
|
callbacks.onStart(startCoord, activePointerType);
|
|
2103
1858
|
};
|
|
2104
1859
|
const onPointerMove = (e) => {
|
|
@@ -2106,6 +1861,22 @@ var installGestures = (handle, mode, callbacks) => {
|
|
|
2106
1861
|
const coord = coordOf(e);
|
|
2107
1862
|
const rawDelta = coord - startCoord;
|
|
2108
1863
|
const delta = rawDelta * sign;
|
|
1864
|
+
if (pendingStart) {
|
|
1865
|
+
const verdict = options.deferStart(e, delta);
|
|
1866
|
+
if (verdict === false) {
|
|
1867
|
+
releaseTracking();
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
if (verdict !== true) return;
|
|
1871
|
+
pendingStart = false;
|
|
1872
|
+
startCoord = coord;
|
|
1873
|
+
lastCoord = coord;
|
|
1874
|
+
samples.reset();
|
|
1875
|
+
samples.push(e.timeStamp, coord);
|
|
1876
|
+
capture(e.pointerId);
|
|
1877
|
+
callbacks.onStart(startCoord, activePointerType);
|
|
1878
|
+
return;
|
|
1879
|
+
}
|
|
2109
1880
|
lastCoord = coord;
|
|
2110
1881
|
samples.push(e.timeStamp, coord);
|
|
2111
1882
|
const cutoff = e.timeStamp - VELOCITY_WINDOW_MS(activePointerType);
|
|
@@ -2114,6 +1885,10 @@ var installGestures = (handle, mode, callbacks) => {
|
|
|
2114
1885
|
};
|
|
2115
1886
|
const finishGesture = (e) => {
|
|
2116
1887
|
if (e.pointerId !== activePointerId) return;
|
|
1888
|
+
if (pendingStart) {
|
|
1889
|
+
releaseTracking();
|
|
1890
|
+
return;
|
|
1891
|
+
}
|
|
2117
1892
|
const rawDelta = lastCoord - startCoord;
|
|
2118
1893
|
const delta = rawDelta * sign;
|
|
2119
1894
|
let velocity = 0;
|
|
@@ -2136,22 +1911,26 @@ var installGestures = (handle, mode, callbacks) => {
|
|
|
2136
1911
|
};
|
|
2137
1912
|
const onPointerCancel = (e) => {
|
|
2138
1913
|
if (e.pointerId !== activePointerId) return;
|
|
2139
|
-
|
|
2140
|
-
|
|
1914
|
+
const wasPending = pendingStart;
|
|
1915
|
+
releaseTracking();
|
|
1916
|
+
if (wasPending) return;
|
|
2141
1917
|
callbacks.onCancel?.();
|
|
2142
1918
|
};
|
|
2143
1919
|
handle.addEventListener("pointerdown", onPointerDown);
|
|
2144
1920
|
handle.addEventListener("pointermove", onPointerMove);
|
|
2145
1921
|
handle.addEventListener("pointerup", finishGesture);
|
|
2146
1922
|
handle.addEventListener("pointercancel", onPointerCancel);
|
|
1923
|
+
const managesTouchAction = options.manageTouchAction !== false;
|
|
2147
1924
|
const prevTouchAction = handle.style.touchAction;
|
|
2148
|
-
|
|
1925
|
+
if (managesTouchAction) {
|
|
1926
|
+
handle.style.touchAction = isAxisVertical(mode) ? "pan-x" : "pan-y";
|
|
1927
|
+
}
|
|
2149
1928
|
return () => {
|
|
2150
1929
|
handle.removeEventListener("pointerdown", onPointerDown);
|
|
2151
1930
|
handle.removeEventListener("pointermove", onPointerMove);
|
|
2152
1931
|
handle.removeEventListener("pointerup", finishGesture);
|
|
2153
1932
|
handle.removeEventListener("pointercancel", onPointerCancel);
|
|
2154
|
-
handle.style.touchAction = prevTouchAction;
|
|
1933
|
+
if (managesTouchAction) handle.style.touchAction = prevTouchAction;
|
|
2155
1934
|
if (activePointerId !== null && handle.hasPointerCapture(activePointerId)) {
|
|
2156
1935
|
handle.releasePointerCapture(activePointerId);
|
|
2157
1936
|
}
|
|
@@ -2270,7 +2049,7 @@ var GestureController = class {
|
|
|
2270
2049
|
const restoreTo = this.dragStartSize;
|
|
2271
2050
|
void this.deps.animateTo(restoreTo, 0);
|
|
2272
2051
|
}
|
|
2273
|
-
});
|
|
2052
|
+
}, this.deps.gestureOptions);
|
|
2274
2053
|
return this.detach;
|
|
2275
2054
|
}
|
|
2276
2055
|
forceClearDragState() {
|
|
@@ -2282,6 +2061,41 @@ var GestureController = class {
|
|
|
2282
2061
|
}
|
|
2283
2062
|
};
|
|
2284
2063
|
|
|
2064
|
+
// src/core/primitives/drag-zones.ts
|
|
2065
|
+
var DRAG_ZONE_SELECTOR = "[data-bs-drag]";
|
|
2066
|
+
var NO_DRAG_SELECTOR = "[data-bs-no-drag]";
|
|
2067
|
+
var asElement = (target) => {
|
|
2068
|
+
const candidate = target;
|
|
2069
|
+
return candidate && typeof candidate.closest === "function" ? candidate : null;
|
|
2070
|
+
};
|
|
2071
|
+
function isDragAllowedFrom(target, mode) {
|
|
2072
|
+
const el = asElement(target);
|
|
2073
|
+
if (!el) return mode !== "zones";
|
|
2074
|
+
if (el.closest(NO_DRAG_SELECTOR)) return false;
|
|
2075
|
+
if (mode === "zones") return el.closest(DRAG_ZONE_SELECTOR) !== null;
|
|
2076
|
+
return true;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
// src/core/primitives/content-gesture.ts
|
|
2080
|
+
var CONTENT_DRAG_SLOP = 6;
|
|
2081
|
+
function decideContentGesture(input) {
|
|
2082
|
+
const slop = input.slop ?? CONTENT_DRAG_SLOP;
|
|
2083
|
+
if (Math.abs(input.delta) < slop) return "pending";
|
|
2084
|
+
if (input.scrollTop > 0) return "scroll";
|
|
2085
|
+
if (input.delta > 0 && input.atMaxSnap) return "scroll";
|
|
2086
|
+
return "drag";
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
// src/core/primitives/touch-scroll-guard.ts
|
|
2090
|
+
function installTouchScrollGuard(surface, isDragging) {
|
|
2091
|
+
const onTouchMove = (e) => {
|
|
2092
|
+
if (!isDragging()) return;
|
|
2093
|
+
if (e.cancelable) e.preventDefault();
|
|
2094
|
+
};
|
|
2095
|
+
surface.addEventListener("touchmove", onTouchMove, { passive: false });
|
|
2096
|
+
return () => surface.removeEventListener("touchmove", onTouchMove);
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2285
2099
|
// src/core/primitives/aria-slider-writer.ts
|
|
2286
2100
|
var AriaSliderWriter = class {
|
|
2287
2101
|
constructor(handle, mode) {
|
|
@@ -2628,7 +2442,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2628
2442
|
const initialAllowed = opts.allowed ?? opts.snapPoints.map((p) => p.id);
|
|
2629
2443
|
let initialId = opts.initial ?? initialAllowed[0] ?? opts.snapPoints[0]?.id ?? "default";
|
|
2630
2444
|
if (opts.persistKey) {
|
|
2631
|
-
const restored =
|
|
2445
|
+
const restored = readPersistedIdSafe(opts.persistKey);
|
|
2632
2446
|
if (restored && initialAllowed.includes(restored)) {
|
|
2633
2447
|
initialId = restored;
|
|
2634
2448
|
}
|
|
@@ -2637,6 +2451,8 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2637
2451
|
mode: opts.mode ?? "bottom",
|
|
2638
2452
|
flickVelocity: opts.flickVelocity ?? DEFAULT_FLICK_VELOCITY,
|
|
2639
2453
|
dragThreshold: opts.dragThreshold ?? DEFAULT_DRAG_THRESHOLD,
|
|
2454
|
+
dragFrom: opts.dragFrom ?? (opts.handle ? "handle" : "sheet"),
|
|
2455
|
+
dragFromContent: opts.dragFromContent ?? true,
|
|
2640
2456
|
rubberBandEnabled: opts.rubberBand ?? true,
|
|
2641
2457
|
closeOnBack: opts.closeOnBack ?? false,
|
|
2642
2458
|
persistent: opts.persistent ?? false,
|
|
@@ -2659,6 +2475,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2659
2475
|
},
|
|
2660
2476
|
animation: {
|
|
2661
2477
|
animation: opts.animation,
|
|
2478
|
+
settleAnimation: opts.settleAnimation,
|
|
2662
2479
|
duration: opts.duration,
|
|
2663
2480
|
easing: opts.easing,
|
|
2664
2481
|
spring: opts.spring,
|
|
@@ -2676,6 +2493,15 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2676
2493
|
}
|
|
2677
2494
|
};
|
|
2678
2495
|
}
|
|
2496
|
+
var readPersistedIdSafe = (key) => {
|
|
2497
|
+
if (typeof window === "undefined") return null;
|
|
2498
|
+
if (typeof localStorage === "undefined") return null;
|
|
2499
|
+
try {
|
|
2500
|
+
return localStorage.getItem(key);
|
|
2501
|
+
} catch {
|
|
2502
|
+
return null;
|
|
2503
|
+
}
|
|
2504
|
+
};
|
|
2679
2505
|
|
|
2680
2506
|
// src/core/primitives/teardown-stack.ts
|
|
2681
2507
|
var TeardownStack = class {
|
|
@@ -2698,9 +2524,9 @@ var TeardownStack = class {
|
|
|
2698
2524
|
}
|
|
2699
2525
|
};
|
|
2700
2526
|
|
|
2701
|
-
// src/core/
|
|
2527
|
+
// src/core/BottomSheetCore.ts
|
|
2702
2528
|
var HAPTIC_DURATION_MS = 8;
|
|
2703
|
-
var
|
|
2529
|
+
var BottomSheetCore = class {
|
|
2704
2530
|
constructor(opts) {
|
|
2705
2531
|
__publicField(this, "id", nextInstanceId("bs"));
|
|
2706
2532
|
__publicField(this, "element");
|
|
@@ -2712,6 +2538,8 @@ var BottomSheetEngine = class {
|
|
|
2712
2538
|
__publicField(this, "mode");
|
|
2713
2539
|
__publicField(this, "flickVelocity");
|
|
2714
2540
|
__publicField(this, "dragThreshold");
|
|
2541
|
+
__publicField(this, "dragFromMode");
|
|
2542
|
+
__publicField(this, "dragFromContentDefault");
|
|
2715
2543
|
__publicField(this, "rubberBandEnabled");
|
|
2716
2544
|
__publicField(this, "scrim");
|
|
2717
2545
|
__publicField(this, "aria");
|
|
@@ -2729,8 +2557,11 @@ var BottomSheetEngine = class {
|
|
|
2729
2557
|
__publicField(this, "activeId");
|
|
2730
2558
|
__publicField(this, "size", 0);
|
|
2731
2559
|
__publicField(this, "gesture");
|
|
2560
|
+
__publicField(this, "contentGesture");
|
|
2561
|
+
__publicField(this, "detachSheetGesture", null);
|
|
2732
2562
|
__publicField(this, "rootEl", null);
|
|
2733
2563
|
__publicField(this, "destroyed", false);
|
|
2564
|
+
__publicField(this, "restClosed", false);
|
|
2734
2565
|
__publicField(this, "currentViewTransition", null);
|
|
2735
2566
|
__publicField(this, "currentAbort", new AbortController());
|
|
2736
2567
|
__publicField(this, "sizeWriteSentinel", new WriteSentinel());
|
|
@@ -2761,6 +2592,8 @@ var BottomSheetEngine = class {
|
|
|
2761
2592
|
__publicField(this, "stackEffectPrimed", false);
|
|
2762
2593
|
__publicField(this, "fitDeps");
|
|
2763
2594
|
__publicField(this, "transformTemplate");
|
|
2595
|
+
__publicField(this, "featureList", []);
|
|
2596
|
+
__publicField(this, "featureCtx");
|
|
2764
2597
|
const resolved = resolveEngineOptions(opts, {
|
|
2765
2598
|
shouldApplyInertSiblings: () => {
|
|
2766
2599
|
if (typeof document === "undefined") return false;
|
|
@@ -2781,6 +2614,8 @@ var BottomSheetEngine = class {
|
|
|
2781
2614
|
this.aria = new AriaSliderWriter(this.handle, this.mode);
|
|
2782
2615
|
this.flickVelocity = resolved.flickVelocity;
|
|
2783
2616
|
this.dragThreshold = resolved.dragThreshold;
|
|
2617
|
+
this.dragFromMode = resolved.dragFrom;
|
|
2618
|
+
this.dragFromContentDefault = resolved.dragFromContent;
|
|
2784
2619
|
this.rubberBandEnabled = resolved.rubberBandEnabled;
|
|
2785
2620
|
this.scrim = new ScrimController(
|
|
2786
2621
|
{
|
|
@@ -2807,7 +2642,9 @@ var BottomSheetEngine = class {
|
|
|
2807
2642
|
getRootEl: () => this.rootEl,
|
|
2808
2643
|
applySize: (size) => this.applySize(size),
|
|
2809
2644
|
getSize: () => this.size,
|
|
2810
|
-
isDragging: () => this.
|
|
2645
|
+
isDragging: () => this.isDraggingAny(),
|
|
2646
|
+
applyAux: (size) => this.applySize(size, true),
|
|
2647
|
+
getTransformFor: (size) => this.transformTemplate(this.snaps.getMaxAxisSize() - size)
|
|
2811
2648
|
},
|
|
2812
2649
|
resolved.animation
|
|
2813
2650
|
);
|
|
@@ -2830,6 +2667,11 @@ var BottomSheetEngine = class {
|
|
|
2830
2667
|
if (opts.linkedSheets) {
|
|
2831
2668
|
this.linkedSheets = opts.linkedSheets;
|
|
2832
2669
|
}
|
|
2670
|
+
const byName = /* @__PURE__ */ new Map();
|
|
2671
|
+
for (const feature of opts.features ?? []) {
|
|
2672
|
+
byName.set(feature.name, feature);
|
|
2673
|
+
}
|
|
2674
|
+
this.featureList = Array.from(byName.values());
|
|
2833
2675
|
this.activeId = resolved.initialId;
|
|
2834
2676
|
auditVhUsage(this.snapPointsRaw);
|
|
2835
2677
|
this.auditDuplicateSnapIds(this.snapPointsRaw);
|
|
@@ -2861,11 +2703,13 @@ var BottomSheetEngine = class {
|
|
|
2861
2703
|
const initial = this.snaps.findById(this.activeId);
|
|
2862
2704
|
if (initial) this.size = initial.size;
|
|
2863
2705
|
this.applySize(this.size);
|
|
2706
|
+
this.setRestClosed(this.size === 0);
|
|
2864
2707
|
this.updateAriaSlider();
|
|
2865
2708
|
this.scrollCache = createScrollCache({
|
|
2866
2709
|
scrollContainer: this.scrollContainer,
|
|
2867
2710
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize()
|
|
2868
2711
|
});
|
|
2712
|
+
this.featureCtx = this.buildFeatureContext(opts.autoCollapseAfter);
|
|
2869
2713
|
this.attach();
|
|
2870
2714
|
this.registerInStack();
|
|
2871
2715
|
if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
|
|
@@ -2890,60 +2734,92 @@ var BottomSheetEngine = class {
|
|
|
2890
2734
|
(p) => p.size === "fit" || p.size === "content"
|
|
2891
2735
|
),
|
|
2892
2736
|
isDestroyed: () => this.destroyed,
|
|
2893
|
-
isDragging: () => this.
|
|
2737
|
+
isDragging: () => this.isDraggingAny(),
|
|
2894
2738
|
recompute: () => this.recompute()
|
|
2895
2739
|
})
|
|
2896
2740
|
);
|
|
2897
2741
|
if (resolved.radius !== void 0) this.setRadius(resolved.radius);
|
|
2898
2742
|
if (resolved.maxHeight !== void 0) this.setMaxHeight(resolved.maxHeight);
|
|
2899
2743
|
this.applyAutoAriaLabelledBy();
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
getSize: () => this.size,
|
|
2905
|
-
close: () => this.close()
|
|
2906
|
-
})
|
|
2907
|
-
);
|
|
2908
|
-
}
|
|
2909
|
-
if (this.persistKey) {
|
|
2910
|
-
this.teardowns.add(installPersist(this, this.persistKey));
|
|
2744
|
+
this.runFeatureStage("post");
|
|
2745
|
+
this.warnOrphanFeatureOptions();
|
|
2746
|
+
if (this.size > 0) {
|
|
2747
|
+
this.handleOpen();
|
|
2911
2748
|
}
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
resolveSnap: (id) => this.snaps.findById(id),
|
|
2920
|
-
snapTo: (id) => {
|
|
2921
|
-
void this.snapTo(id);
|
|
2922
|
-
},
|
|
2923
|
-
on: (event, fn) => this.on(event, fn)
|
|
2924
|
-
})
|
|
2925
|
-
);
|
|
2926
|
-
this.teardowns.add(
|
|
2927
|
-
installRoute({
|
|
2749
|
+
}
|
|
2750
|
+
buildFeatureContext(autoCollapseAfter) {
|
|
2751
|
+
return {
|
|
2752
|
+
element: this.element,
|
|
2753
|
+
scrollContainer: this.scrollContainer,
|
|
2754
|
+
sheetId: this.id,
|
|
2755
|
+
options: {
|
|
2928
2756
|
routedTo: this.routedTo,
|
|
2929
2757
|
closeOnBack: this.closeOnBack,
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
this.
|
|
2758
|
+
closeOnRouteChange: this.closeOnRouteChange,
|
|
2759
|
+
persistKey: this.persistKey,
|
|
2760
|
+
autoCollapseAfter
|
|
2761
|
+
},
|
|
2762
|
+
isDestroyed: () => this.destroyed,
|
|
2763
|
+
isDragging: () => this.isDraggingAny(),
|
|
2764
|
+
isAnimating: () => this.animation.isAnimating,
|
|
2765
|
+
isTopSheet: () => this.isTopSheet,
|
|
2766
|
+
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
2767
|
+
getSize: () => this.size,
|
|
2768
|
+
getActiveId: () => this.activeId,
|
|
2769
|
+
getAllowedIds: () => this.snaps.getAllowedIds().slice(),
|
|
2770
|
+
allowedIdsBySize: () => this.allowedIdsBySize(),
|
|
2771
|
+
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
2772
|
+
resolveSnap: (id) => this.snaps.findById(id),
|
|
2773
|
+
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
2774
|
+
setSize: (size) => {
|
|
2775
|
+
this.size = size;
|
|
2776
|
+
},
|
|
2777
|
+
setMaxAxisSize: (size) => {
|
|
2778
|
+
this.snaps.setMaxAxisSize(size);
|
|
2779
|
+
},
|
|
2780
|
+
applySize: (size) => this.applySize(size),
|
|
2781
|
+
recomputeSnaps: () => this.recomputeSnaps(),
|
|
2782
|
+
newCycle: () => {
|
|
2783
|
+
this.newCycle();
|
|
2784
|
+
},
|
|
2785
|
+
cancelInFlight: () => {
|
|
2786
|
+
this.animation.cancel();
|
|
2787
|
+
},
|
|
2788
|
+
resyncAfterResize: () => this.resyncAfterResize(),
|
|
2789
|
+
snapTo: (id) => {
|
|
2790
|
+
void this.snapTo(id);
|
|
2791
|
+
},
|
|
2792
|
+
close: (reason) => this.close(reason),
|
|
2793
|
+
attachDragSurface: (surface, kind) => this.attachDragSurface(surface, kind),
|
|
2794
|
+
on: (event, fn) => this.on(event, fn),
|
|
2795
|
+
addTeardown: (fn) => this.teardowns.add(fn)
|
|
2796
|
+
};
|
|
2797
|
+
}
|
|
2798
|
+
runFeatureStage(stage) {
|
|
2799
|
+
for (const feature of this.featureList) {
|
|
2800
|
+
if ((feature.stage ?? "post") !== stage) continue;
|
|
2801
|
+
const teardown = feature.install(this.featureCtx);
|
|
2802
|
+
if (teardown) this.teardowns.add(teardown);
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
warnOrphanFeatureOptions() {
|
|
2806
|
+
const names = new Set(this.featureList.map((f) => f.name));
|
|
2807
|
+
if ((this.closeOnBack || this.routedTo !== void 0 || this.closeOnRouteChange) && !names.has("route")) {
|
|
2808
|
+
devWarn(
|
|
2809
|
+
"[BottomSheet] closeOnBack/routedTo/closeOnRouteChange need routeFeature() \u2014 option ignored"
|
|
2810
|
+
);
|
|
2811
|
+
}
|
|
2812
|
+
if (this.persistKey && !names.has("persist")) {
|
|
2813
|
+
devWarn(
|
|
2814
|
+
"[BottomSheet] persistKey needs persistFeature() \u2014 snaps will not be saved"
|
|
2815
|
+
);
|
|
2940
2816
|
}
|
|
2941
2817
|
}
|
|
2942
2818
|
get state() {
|
|
2943
2819
|
return {
|
|
2944
2820
|
size: this.size,
|
|
2945
2821
|
activeId: this.activeId,
|
|
2946
|
-
isDragging: this.
|
|
2822
|
+
isDragging: this.isDraggingAny(),
|
|
2947
2823
|
isAnimating: this.animation.isAnimating,
|
|
2948
2824
|
progress: this.computeProgress(this.size)
|
|
2949
2825
|
};
|
|
@@ -3063,9 +2939,16 @@ var BottomSheetEngine = class {
|
|
|
3063
2939
|
progress: this.computeProgress(this.size)
|
|
3064
2940
|
});
|
|
3065
2941
|
if (withHaptic) this.haptic();
|
|
2942
|
+
this.setRestClosed(targetSize === 0);
|
|
3066
2943
|
if (wasClosed && targetSize > 0) this.emitOpenSequence(id);
|
|
3067
2944
|
if (targetSize === 0) this.emitCloseSequence();
|
|
3068
2945
|
}
|
|
2946
|
+
setRestClosed(closed) {
|
|
2947
|
+
if (closed === this.restClosed) return;
|
|
2948
|
+
this.restClosed = closed;
|
|
2949
|
+
if (closed) this.element.setAttribute("data-bs-rest", "closed");
|
|
2950
|
+
else this.element.removeAttribute("data-bs-rest");
|
|
2951
|
+
}
|
|
3069
2952
|
emitOpenSequence(id) {
|
|
3070
2953
|
this.emit("open", { id });
|
|
3071
2954
|
this.handleOpen();
|
|
@@ -3121,6 +3004,20 @@ var BottomSheetEngine = class {
|
|
|
3121
3004
|
if (this.destroyed) return;
|
|
3122
3005
|
this.disableDragFlag = value;
|
|
3123
3006
|
}
|
|
3007
|
+
setDragFromContent(value) {
|
|
3008
|
+
if (this.destroyed) return;
|
|
3009
|
+
this.dragFromContentDefault = value;
|
|
3010
|
+
}
|
|
3011
|
+
setDragFrom(mode) {
|
|
3012
|
+
if (this.destroyed || mode === this.dragFromMode) return;
|
|
3013
|
+
this.gesture?.forceClearDragState();
|
|
3014
|
+
this.detachSheetGesture?.();
|
|
3015
|
+
this.dragFromMode = mode;
|
|
3016
|
+
this.mountSheetGesture();
|
|
3017
|
+
}
|
|
3018
|
+
getDragFrom() {
|
|
3019
|
+
return this.dragFromMode;
|
|
3020
|
+
}
|
|
3124
3021
|
isTop() {
|
|
3125
3022
|
return this.isTopSheet;
|
|
3126
3023
|
}
|
|
@@ -3275,12 +3172,24 @@ var BottomSheetEngine = class {
|
|
|
3275
3172
|
auditVhUsage(points);
|
|
3276
3173
|
this.auditDuplicateSnapIds(points);
|
|
3277
3174
|
this.snaps.setRaw(points);
|
|
3278
|
-
if (allowed)
|
|
3175
|
+
if (allowed) {
|
|
3176
|
+
this.snaps.setAllowedIds(allowed);
|
|
3177
|
+
} else {
|
|
3178
|
+
const present = this.snaps.getResolvedSnaps().map((s) => s.id);
|
|
3179
|
+
const kept = this.snaps.getAllowedIds().filter((id) => present.includes(id));
|
|
3180
|
+
this.snaps.setAllowedIds(kept.length ? kept : present);
|
|
3181
|
+
}
|
|
3279
3182
|
this.scrollCache.clear();
|
|
3280
3183
|
this.scrim.invalidateOpacityCache();
|
|
3281
3184
|
const current = this.snaps.findById(this.activeId);
|
|
3282
3185
|
if (current) {
|
|
3283
3186
|
this.applySize(current.size);
|
|
3187
|
+
} else {
|
|
3188
|
+
const fallback = this.snaps.getResolvedSnaps().find((s) => this.snaps.getAllowedIds().includes(s.id)) ?? this.snaps.getResolvedSnaps()[0];
|
|
3189
|
+
if (fallback) {
|
|
3190
|
+
this.activeId = fallback.id;
|
|
3191
|
+
this.applySize(fallback.size);
|
|
3192
|
+
}
|
|
3284
3193
|
}
|
|
3285
3194
|
this.updateAriaSlider();
|
|
3286
3195
|
}
|
|
@@ -3290,7 +3199,7 @@ var BottomSheetEngine = class {
|
|
|
3290
3199
|
this.snaps.recompute();
|
|
3291
3200
|
this.maxHeight.clampTo();
|
|
3292
3201
|
this.scrim.invalidateOpacityCache();
|
|
3293
|
-
if (this.
|
|
3202
|
+
if (this.isDraggingAny()) return;
|
|
3294
3203
|
this.healActiveSnap();
|
|
3295
3204
|
}
|
|
3296
3205
|
healActiveSnap() {
|
|
@@ -3312,6 +3221,8 @@ var BottomSheetEngine = class {
|
|
|
3312
3221
|
this.bus.clear();
|
|
3313
3222
|
this.animation.cancel();
|
|
3314
3223
|
this.gesture?.forceClearDragState();
|
|
3224
|
+
this.contentGesture?.forceClearDragState();
|
|
3225
|
+
this.setRestClosed(false);
|
|
3315
3226
|
this.teardowns.drain();
|
|
3316
3227
|
this.scrim.destroy();
|
|
3317
3228
|
this.animation.destroy();
|
|
@@ -3424,11 +3335,12 @@ var BottomSheetEngine = class {
|
|
|
3424
3335
|
const scale = Math.max(1 - depth * 0.04, 0.86);
|
|
3425
3336
|
this.element.style.scale = scale === 1 ? "" : String(scale);
|
|
3426
3337
|
}
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
handle:
|
|
3338
|
+
buildGestureDeps(surface, gestureOptions) {
|
|
3339
|
+
return {
|
|
3340
|
+
handle: surface,
|
|
3430
3341
|
element: this.element,
|
|
3431
3342
|
mode: this.mode,
|
|
3343
|
+
gestureOptions,
|
|
3432
3344
|
getRoot: () => this.rootEl,
|
|
3433
3345
|
getDragContext: () => {
|
|
3434
3346
|
const buf = this.dragContextBuf;
|
|
@@ -3447,8 +3359,88 @@ var BottomSheetEngine = class {
|
|
|
3447
3359
|
settleAfterDrag: (delta, velocity, kind) => this.settleAfterDrag(delta, velocity, kind),
|
|
3448
3360
|
emit: (event, payload) => this.emit(event, payload),
|
|
3449
3361
|
listenerCount: (event) => this.bus.listenerCount(event)
|
|
3362
|
+
};
|
|
3363
|
+
}
|
|
3364
|
+
isContentDragAllowed() {
|
|
3365
|
+
if (this.disableDragFlag) return false;
|
|
3366
|
+
const point = this.snapPointsRaw.find((p) => p.id === this.activeId);
|
|
3367
|
+
return point?.dragFromContent ?? this.dragFromContentDefault;
|
|
3368
|
+
}
|
|
3369
|
+
decideContentDrag(surface, e, delta) {
|
|
3370
|
+
if (this.destroyed) return false;
|
|
3371
|
+
if (e.pointerType === "mouse") return false;
|
|
3372
|
+
if (this.gesture?.isDragging) return false;
|
|
3373
|
+
if (!this.isContentDragAllowed()) return false;
|
|
3374
|
+
if (!isDragAllowedFrom(e.target, "sheet")) return false;
|
|
3375
|
+
const decision = decideContentGesture({
|
|
3376
|
+
delta,
|
|
3377
|
+
scrollTop: surface.scrollTop,
|
|
3378
|
+
atMaxSnap: this.size >= this.getAllowedRange().max - 0.5
|
|
3379
|
+
});
|
|
3380
|
+
if (decision === "pending") return null;
|
|
3381
|
+
return decision === "drag";
|
|
3382
|
+
}
|
|
3383
|
+
attachDragSurface(surface, kind) {
|
|
3384
|
+
if (this.destroyed || kind !== "content") return;
|
|
3385
|
+
if (this.contentGesture) return;
|
|
3386
|
+
const controller = new GestureController(
|
|
3387
|
+
this.buildGestureDeps(surface, {
|
|
3388
|
+
manageTouchAction: false,
|
|
3389
|
+
deferStart: (e, delta) => this.decideContentDrag(surface, e, delta)
|
|
3390
|
+
})
|
|
3391
|
+
);
|
|
3392
|
+
this.contentGesture = controller;
|
|
3393
|
+
const detachGestures = controller.install();
|
|
3394
|
+
const detachGuard = installTouchScrollGuard(
|
|
3395
|
+
surface,
|
|
3396
|
+
() => controller.isDragging
|
|
3397
|
+
);
|
|
3398
|
+
return () => {
|
|
3399
|
+
detachGuard();
|
|
3400
|
+
detachGestures();
|
|
3401
|
+
if (this.contentGesture === controller) this.contentGesture = void 0;
|
|
3402
|
+
};
|
|
3403
|
+
}
|
|
3404
|
+
sheetDragSurface() {
|
|
3405
|
+
return this.dragFromMode === "handle" ? this.handle : this.element;
|
|
3406
|
+
}
|
|
3407
|
+
canStartSheetDrag(e) {
|
|
3408
|
+
if (this.contentGesture?.isDragging) return false;
|
|
3409
|
+
const target = e.target;
|
|
3410
|
+
const scoped = typeof target?.closest === "function";
|
|
3411
|
+
if (scoped && target.closest(NO_DRAG_SELECTOR)) return false;
|
|
3412
|
+
if (this.handle !== this.element && scoped && this.handle.contains(target)) {
|
|
3413
|
+
return true;
|
|
3414
|
+
}
|
|
3415
|
+
if (!isDragAllowedFrom(e.target, this.dragFromMode)) return false;
|
|
3416
|
+
if (this.dragFromMode === "handle") return true;
|
|
3417
|
+
if (this.scrollContainer && scoped && this.scrollContainer.contains(target) && !target.closest(DRAG_ZONE_SELECTOR)) {
|
|
3418
|
+
return false;
|
|
3419
|
+
}
|
|
3420
|
+
return true;
|
|
3421
|
+
}
|
|
3422
|
+
mountSheetGesture() {
|
|
3423
|
+
const surface = this.sheetDragSurface();
|
|
3424
|
+
const controller = new GestureController(
|
|
3425
|
+
this.buildGestureDeps(surface, {
|
|
3426
|
+
shouldStart: (e) => this.canStartSheetDrag(e),
|
|
3427
|
+
manageTouchAction: this.dragFromMode === "handle"
|
|
3428
|
+
})
|
|
3429
|
+
);
|
|
3430
|
+
this.gesture = controller;
|
|
3431
|
+
const detachGestures = controller.install();
|
|
3432
|
+
const detachGuard = this.dragFromMode === "handle" ? null : installTouchScrollGuard(surface, () => controller.isDragging);
|
|
3433
|
+
this.detachSheetGesture = () => {
|
|
3434
|
+
detachGuard?.();
|
|
3435
|
+
detachGestures();
|
|
3436
|
+
};
|
|
3437
|
+
}
|
|
3438
|
+
attach() {
|
|
3439
|
+
this.mountSheetGesture();
|
|
3440
|
+
this.teardowns.add(() => {
|
|
3441
|
+
this.detachSheetGesture?.();
|
|
3442
|
+
this.detachSheetGesture = null;
|
|
3450
3443
|
});
|
|
3451
|
-
this.teardowns.add(this.gesture.install());
|
|
3452
3444
|
try {
|
|
3453
3445
|
this.attachFeatures();
|
|
3454
3446
|
} catch (err) {
|
|
@@ -3479,24 +3471,13 @@ var BottomSheetEngine = class {
|
|
|
3479
3471
|
}
|
|
3480
3472
|
}
|
|
3481
3473
|
attachFeatures() {
|
|
3482
|
-
|
|
3483
|
-
this.teardowns.add(installContentSwipe({
|
|
3484
|
-
container: this.scrollContainer,
|
|
3485
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3486
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3487
|
-
getAllowedIds: () => this.allowedIdsBySize(),
|
|
3488
|
-
getActiveId: () => this.activeId,
|
|
3489
|
-
snapTo: (id) => {
|
|
3490
|
-
void this.snapTo(id);
|
|
3491
|
-
}
|
|
3492
|
-
}));
|
|
3493
|
-
}
|
|
3474
|
+
this.runFeatureStage("attach");
|
|
3494
3475
|
if (typeof window !== "undefined") {
|
|
3495
3476
|
this.teardowns.add(installResizeObserver({
|
|
3496
3477
|
element: this.element,
|
|
3497
3478
|
getMode: () => this.mode,
|
|
3498
3479
|
isDestroyed: () => this.destroyed,
|
|
3499
|
-
isDragging: () => this.
|
|
3480
|
+
isDragging: () => this.isDraggingAny(),
|
|
3500
3481
|
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3501
3482
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
3502
3483
|
getSize: () => this.size,
|
|
@@ -3530,31 +3511,6 @@ var BottomSheetEngine = class {
|
|
|
3530
3511
|
() => document.removeEventListener("keydown", onKey)
|
|
3531
3512
|
);
|
|
3532
3513
|
}
|
|
3533
|
-
this.teardowns.add(installVisualViewport({
|
|
3534
|
-
element: this.element,
|
|
3535
|
-
isVerticalAxis: () => this.mode === "bottom" || this.mode === "top",
|
|
3536
|
-
isDestroyed: () => this.destroyed,
|
|
3537
|
-
isDragging: () => this.gesture?.isDragging ?? false,
|
|
3538
|
-
recomputeSnaps: () => this.recomputeSnaps(),
|
|
3539
|
-
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3540
|
-
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
3541
|
-
getSize: () => this.size,
|
|
3542
|
-
setMaxAxisSize: (size) => {
|
|
3543
|
-
this.snaps.setMaxAxisSize(size);
|
|
3544
|
-
},
|
|
3545
|
-
setSize: (size) => {
|
|
3546
|
-
this.size = size;
|
|
3547
|
-
},
|
|
3548
|
-
applySize: (size) => this.applySize(size),
|
|
3549
|
-
cancelInFlight: () => {
|
|
3550
|
-
this.animation.cancel();
|
|
3551
|
-
},
|
|
3552
|
-
newCycle: () => {
|
|
3553
|
-
this.newCycle();
|
|
3554
|
-
},
|
|
3555
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3556
|
-
resyncAfterCancel: () => this.resyncAfterResize()
|
|
3557
|
-
}));
|
|
3558
3514
|
}
|
|
3559
3515
|
this.teardowns.add(installSliderKeyboard({
|
|
3560
3516
|
handle: this.handle,
|
|
@@ -3619,8 +3575,11 @@ var BottomSheetEngine = class {
|
|
|
3619
3575
|
);
|
|
3620
3576
|
});
|
|
3621
3577
|
}
|
|
3578
|
+
isDraggingAny() {
|
|
3579
|
+
return (this.gesture?.isDragging ?? false) || (this.contentGesture?.isDragging ?? false);
|
|
3580
|
+
}
|
|
3622
3581
|
clearWillChangeIfIdle() {
|
|
3623
|
-
if (this.animation.isAnimating || this.
|
|
3582
|
+
if (this.animation.isAnimating || this.isDraggingAny()) return;
|
|
3624
3583
|
this.element.style.willChange = "";
|
|
3625
3584
|
}
|
|
3626
3585
|
haptic() {
|
|
@@ -3631,13 +3590,14 @@ var BottomSheetEngine = class {
|
|
|
3631
3590
|
}
|
|
3632
3591
|
}
|
|
3633
3592
|
}
|
|
3634
|
-
applySize(size) {
|
|
3593
|
+
applySize(size, skipTransform = false) {
|
|
3635
3594
|
const cap = this.snaps.getMaxAxisSize();
|
|
3636
|
-
const clamped = cap > 0 && size > cap && !this.
|
|
3595
|
+
const clamped = cap > 0 && size > cap && !this.isDraggingAny() && !this.allowOvershoot ? cap : size;
|
|
3637
3596
|
this.size = clamped;
|
|
3597
|
+
if (clamped > 0) this.setRestClosed(false);
|
|
3638
3598
|
const offset = cap - clamped;
|
|
3639
3599
|
const style = this.element.style;
|
|
3640
|
-
style.transform = this.transformTemplate(offset);
|
|
3600
|
+
if (!skipTransform) style.transform = this.transformTemplate(offset);
|
|
3641
3601
|
if (this.sizeWriteSentinel.shouldWrite(clamped, SIZE_WRITE_EPSILON)) {
|
|
3642
3602
|
style.setProperty("--bs-size", `${clamped}px`);
|
|
3643
3603
|
if (this.scrimParent) {
|
|
@@ -3715,6 +3675,470 @@ var BottomSheetEngine = class {
|
|
|
3715
3675
|
}
|
|
3716
3676
|
};
|
|
3717
3677
|
|
|
3678
|
+
// src/core/features/history-coordinator.ts
|
|
3679
|
+
var entries = [];
|
|
3680
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
3681
|
+
var suppress = 0;
|
|
3682
|
+
var internalDepth = 0;
|
|
3683
|
+
var pendingRebrands = [];
|
|
3684
|
+
var listenerInstalled = false;
|
|
3685
|
+
var patchInstalled = false;
|
|
3686
|
+
var origPushState = null;
|
|
3687
|
+
var origReplaceState = null;
|
|
3688
|
+
var patchedPushState = null;
|
|
3689
|
+
var patchedReplaceState = null;
|
|
3690
|
+
var hasWindow = () => typeof window !== "undefined";
|
|
3691
|
+
var hasHistory = () => typeof history !== "undefined";
|
|
3692
|
+
var brandMarker = (surface) => ({
|
|
3693
|
+
...surface.markerState(),
|
|
3694
|
+
__bs: true
|
|
3695
|
+
});
|
|
3696
|
+
var runInternal = (fn) => {
|
|
3697
|
+
internalDepth += 1;
|
|
3698
|
+
try {
|
|
3699
|
+
fn();
|
|
3700
|
+
} finally {
|
|
3701
|
+
internalDepth -= 1;
|
|
3702
|
+
}
|
|
3703
|
+
};
|
|
3704
|
+
var notifyRouteChange = () => {
|
|
3705
|
+
const snapshot = Array.from(subscribers);
|
|
3706
|
+
for (const fn of snapshot) fn();
|
|
3707
|
+
};
|
|
3708
|
+
var ensureListener = () => {
|
|
3709
|
+
if (listenerInstalled || !hasWindow()) return;
|
|
3710
|
+
window.addEventListener("popstate", onPopState);
|
|
3711
|
+
listenerInstalled = true;
|
|
3712
|
+
};
|
|
3713
|
+
var maybeTeardownListener = () => {
|
|
3714
|
+
if (!listenerInstalled) return;
|
|
3715
|
+
if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
|
|
3716
|
+
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
3717
|
+
listenerInstalled = false;
|
|
3718
|
+
};
|
|
3719
|
+
var installPatch = () => {
|
|
3720
|
+
if (patchInstalled || !hasHistory()) return;
|
|
3721
|
+
origPushState = history.pushState;
|
|
3722
|
+
origReplaceState = history.replaceState;
|
|
3723
|
+
patchedPushState = function(...args) {
|
|
3724
|
+
origPushState.apply(this, args);
|
|
3725
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3726
|
+
};
|
|
3727
|
+
patchedReplaceState = function(...args) {
|
|
3728
|
+
origReplaceState.apply(this, args);
|
|
3729
|
+
if (internalDepth === 0) notifyRouteChange();
|
|
3730
|
+
};
|
|
3731
|
+
history.pushState = patchedPushState;
|
|
3732
|
+
history.replaceState = patchedReplaceState;
|
|
3733
|
+
patchInstalled = true;
|
|
3734
|
+
};
|
|
3735
|
+
var removePatch = () => {
|
|
3736
|
+
if (!patchInstalled) return;
|
|
3737
|
+
if (history.pushState === patchedPushState && origPushState) {
|
|
3738
|
+
history.pushState = origPushState;
|
|
3739
|
+
}
|
|
3740
|
+
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
3741
|
+
history.replaceState = origReplaceState;
|
|
3742
|
+
}
|
|
3743
|
+
origPushState = null;
|
|
3744
|
+
origReplaceState = null;
|
|
3745
|
+
patchedPushState = null;
|
|
3746
|
+
patchedReplaceState = null;
|
|
3747
|
+
patchInstalled = false;
|
|
3748
|
+
};
|
|
3749
|
+
function onPopState() {
|
|
3750
|
+
if (suppress > 0) {
|
|
3751
|
+
suppress -= 1;
|
|
3752
|
+
const rebrand = pendingRebrands.shift();
|
|
3753
|
+
if (rebrand) rebrand();
|
|
3754
|
+
maybeTeardownListener();
|
|
3755
|
+
return;
|
|
3756
|
+
}
|
|
3757
|
+
if (entries.length === 0) {
|
|
3758
|
+
notifyRouteChange();
|
|
3759
|
+
maybeTeardownListener();
|
|
3760
|
+
return;
|
|
3761
|
+
}
|
|
3762
|
+
let target = null;
|
|
3763
|
+
let targetIdx = -1;
|
|
3764
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
3765
|
+
const entry = entries[i];
|
|
3766
|
+
if (!entry.surface.isOpen()) continue;
|
|
3767
|
+
if (!target) {
|
|
3768
|
+
target = entry;
|
|
3769
|
+
targetIdx = i;
|
|
3770
|
+
}
|
|
3771
|
+
if (entry.surface.isTop()) {
|
|
3772
|
+
target = entry;
|
|
3773
|
+
targetIdx = i;
|
|
3774
|
+
break;
|
|
3775
|
+
}
|
|
3776
|
+
}
|
|
3777
|
+
if (!target) {
|
|
3778
|
+
const removed = entries.pop();
|
|
3779
|
+
if (removed) removed.live = false;
|
|
3780
|
+
maybeTeardownListener();
|
|
3781
|
+
return;
|
|
3782
|
+
}
|
|
3783
|
+
target.live = false;
|
|
3784
|
+
entries.splice(targetIdx, 1);
|
|
3785
|
+
const settled = target;
|
|
3786
|
+
void Promise.resolve(settled.surface.close()).then(() => {
|
|
3787
|
+
if (settled.surface.isOpen()) restore(settled);
|
|
3788
|
+
});
|
|
3789
|
+
maybeTeardownListener();
|
|
3790
|
+
}
|
|
3791
|
+
function restore(entry) {
|
|
3792
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3793
|
+
entry.live = true;
|
|
3794
|
+
runInternal(() => {
|
|
3795
|
+
try {
|
|
3796
|
+
history.pushState(brandMarker(entry.surface), "", entry.surface.url);
|
|
3797
|
+
} catch {
|
|
3798
|
+
entry.live = false;
|
|
3799
|
+
}
|
|
3800
|
+
});
|
|
3801
|
+
if (entry.live) {
|
|
3802
|
+
entries.push(entry);
|
|
3803
|
+
ensureListener();
|
|
3804
|
+
}
|
|
3805
|
+
}
|
|
3806
|
+
function pushBackMarker(surface) {
|
|
3807
|
+
const entry = { surface, priorUrl: void 0, live: false };
|
|
3808
|
+
if (!hasWindow() || !hasHistory()) {
|
|
3809
|
+
return entry;
|
|
3810
|
+
}
|
|
3811
|
+
entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
|
|
3812
|
+
runInternal(() => {
|
|
3813
|
+
try {
|
|
3814
|
+
history.pushState(brandMarker(surface), "", surface.url);
|
|
3815
|
+
entry.live = true;
|
|
3816
|
+
} catch {
|
|
3817
|
+
entry.live = false;
|
|
3818
|
+
}
|
|
3819
|
+
});
|
|
3820
|
+
if (entry.live) {
|
|
3821
|
+
entries.push(entry);
|
|
3822
|
+
ensureListener();
|
|
3823
|
+
}
|
|
3824
|
+
return entry;
|
|
3825
|
+
}
|
|
3826
|
+
function popBackMarker(handle) {
|
|
3827
|
+
if (!hasWindow() || !hasHistory()) return;
|
|
3828
|
+
const entry = handle;
|
|
3829
|
+
const idx = entries.indexOf(entry);
|
|
3830
|
+
if (idx === -1 || !entry.live) return;
|
|
3831
|
+
const last = entries.length - 1;
|
|
3832
|
+
entry.live = false;
|
|
3833
|
+
entries.splice(idx, 1);
|
|
3834
|
+
let rebrand = null;
|
|
3835
|
+
if (idx !== last) {
|
|
3836
|
+
const rebrandSurface = entries[entries.length - 1].surface;
|
|
3837
|
+
const rebrandUrl = entry.priorUrl;
|
|
3838
|
+
rebrand = () => {
|
|
3839
|
+
runInternal(() => {
|
|
3840
|
+
history.replaceState(
|
|
3841
|
+
brandMarker(rebrandSurface),
|
|
3842
|
+
"",
|
|
3843
|
+
rebrandUrl !== void 0 ? rebrandUrl : location.href
|
|
3844
|
+
);
|
|
3845
|
+
});
|
|
3846
|
+
};
|
|
3847
|
+
}
|
|
3848
|
+
pendingRebrands.push(rebrand);
|
|
3849
|
+
suppress += 1;
|
|
3850
|
+
runInternal(() => {
|
|
3851
|
+
try {
|
|
3852
|
+
history.back();
|
|
3853
|
+
} catch {
|
|
3854
|
+
suppress = Math.max(0, suppress - 1);
|
|
3855
|
+
pendingRebrands.pop();
|
|
3856
|
+
}
|
|
3857
|
+
});
|
|
3858
|
+
maybeTeardownListener();
|
|
3859
|
+
}
|
|
3860
|
+
function subscribeRouteChange(fn) {
|
|
3861
|
+
if (!hasWindow() || !hasHistory()) return () => {
|
|
3862
|
+
};
|
|
3863
|
+
subscribers.add(fn);
|
|
3864
|
+
if (subscribers.size === 1) installPatch();
|
|
3865
|
+
ensureListener();
|
|
3866
|
+
return () => {
|
|
3867
|
+
if (!subscribers.has(fn)) return;
|
|
3868
|
+
subscribers.delete(fn);
|
|
3869
|
+
if (subscribers.size === 0) removePatch();
|
|
3870
|
+
maybeTeardownListener();
|
|
3871
|
+
};
|
|
3872
|
+
}
|
|
3873
|
+
|
|
3874
|
+
// src/core/features/route.ts
|
|
3875
|
+
function installRoute(deps) {
|
|
3876
|
+
if (typeof window === "undefined") {
|
|
3877
|
+
return () => {
|
|
3878
|
+
};
|
|
3879
|
+
}
|
|
3880
|
+
if (!deps.routedTo && !deps.closeOnBack) {
|
|
3881
|
+
return () => {
|
|
3882
|
+
};
|
|
3883
|
+
}
|
|
3884
|
+
let handle = null;
|
|
3885
|
+
const onOpen = () => {
|
|
3886
|
+
if (handle) return;
|
|
3887
|
+
handle = pushBackMarker({
|
|
3888
|
+
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
3889
|
+
isTop: deps.isTopSheet,
|
|
3890
|
+
close: deps.close,
|
|
3891
|
+
markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
|
|
3892
|
+
url: deps.routedTo
|
|
3893
|
+
});
|
|
3894
|
+
};
|
|
3895
|
+
const onClose = () => {
|
|
3896
|
+
if (!handle) return;
|
|
3897
|
+
popBackMarker(handle);
|
|
3898
|
+
handle = null;
|
|
3899
|
+
};
|
|
3900
|
+
const unsubscribeOpen = deps.on("open", onOpen);
|
|
3901
|
+
const unsubscribeClose = deps.on("close", onClose);
|
|
3902
|
+
if (deps.getSize() > 0) onOpen();
|
|
3903
|
+
return () => {
|
|
3904
|
+
unsubscribeOpen();
|
|
3905
|
+
unsubscribeClose();
|
|
3906
|
+
if (handle) {
|
|
3907
|
+
popBackMarker(handle);
|
|
3908
|
+
handle = null;
|
|
3909
|
+
}
|
|
3910
|
+
};
|
|
3911
|
+
}
|
|
3912
|
+
function installRouteChange(deps) {
|
|
3913
|
+
return subscribeRouteChange(() => {
|
|
3914
|
+
if (deps.isDestroyed() || deps.getSize() <= 0) return;
|
|
3915
|
+
void deps.close();
|
|
3916
|
+
});
|
|
3917
|
+
}
|
|
3918
|
+
|
|
3919
|
+
// src/core/features/persist.ts
|
|
3920
|
+
function installPersist(engine, key) {
|
|
3921
|
+
const unsubscribe = engine.on("snap", ({ id }) => {
|
|
3922
|
+
if (typeof window === "undefined") return;
|
|
3923
|
+
if (typeof localStorage === "undefined") return;
|
|
3924
|
+
try {
|
|
3925
|
+
localStorage.setItem(key, id);
|
|
3926
|
+
} catch {
|
|
3927
|
+
}
|
|
3928
|
+
});
|
|
3929
|
+
return unsubscribe;
|
|
3930
|
+
}
|
|
3931
|
+
|
|
3932
|
+
// src/core/features/auto-collapse.ts
|
|
3933
|
+
function installAutoCollapse(deps) {
|
|
3934
|
+
const { ms } = deps;
|
|
3935
|
+
if (ms === void 0 || ms <= 0) {
|
|
3936
|
+
return () => {
|
|
3937
|
+
};
|
|
3938
|
+
}
|
|
3939
|
+
let timer = null;
|
|
3940
|
+
const clearTimer = () => {
|
|
3941
|
+
if (timer !== null) {
|
|
3942
|
+
clearTimeout(timer);
|
|
3943
|
+
timer = null;
|
|
3944
|
+
}
|
|
3945
|
+
};
|
|
3946
|
+
const fire = () => {
|
|
3947
|
+
if (deps.isDestroyed()) return;
|
|
3948
|
+
if (deps.isDragging()) return;
|
|
3949
|
+
const active = deps.resolveSnap(deps.getActiveId());
|
|
3950
|
+
if (!active || active.size === 0) return;
|
|
3951
|
+
let target = null;
|
|
3952
|
+
for (const id of deps.getAllowedIds()) {
|
|
3953
|
+
const snap = deps.resolveSnap(id);
|
|
3954
|
+
if (!snap || snap.size <= 0) continue;
|
|
3955
|
+
if (!target || snap.size < target.size) target = snap;
|
|
3956
|
+
}
|
|
3957
|
+
if (!target) return;
|
|
3958
|
+
if (target.id === active.id || target.size >= active.size) return;
|
|
3959
|
+
deps.snapTo(target.id);
|
|
3960
|
+
};
|
|
3961
|
+
const reset = () => {
|
|
3962
|
+
clearTimer();
|
|
3963
|
+
if (deps.isDestroyed()) return;
|
|
3964
|
+
timer = setTimeout(() => {
|
|
3965
|
+
timer = null;
|
|
3966
|
+
fire();
|
|
3967
|
+
}, ms);
|
|
3968
|
+
};
|
|
3969
|
+
const unsubscribe = deps.on("snap", () => reset());
|
|
3970
|
+
if ((deps.resolveSnap(deps.getActiveId())?.size ?? 0) > 0) reset();
|
|
3971
|
+
return () => {
|
|
3972
|
+
clearTimer();
|
|
3973
|
+
unsubscribe();
|
|
3974
|
+
};
|
|
3975
|
+
}
|
|
3976
|
+
|
|
3977
|
+
// src/core/features/content-drag.ts
|
|
3978
|
+
function installContentDrag(deps) {
|
|
3979
|
+
const detach = deps.attachDragSurface(deps.container, "content");
|
|
3980
|
+
return () => detach?.();
|
|
3981
|
+
}
|
|
3982
|
+
|
|
3983
|
+
// src/core/features/visual-viewport.ts
|
|
3984
|
+
var SAFETY_PAD = 8;
|
|
3985
|
+
function installVisualViewport(deps) {
|
|
3986
|
+
if (typeof window === "undefined" || !window.visualViewport) {
|
|
3987
|
+
return () => {
|
|
3988
|
+
};
|
|
3989
|
+
}
|
|
3990
|
+
const vv = window.visualViewport;
|
|
3991
|
+
let rafId = null;
|
|
3992
|
+
const onResize = () => {
|
|
3993
|
+
if (rafId !== null) return;
|
|
3994
|
+
rafId = requestAnimationFrame(() => {
|
|
3995
|
+
rafId = null;
|
|
3996
|
+
if (deps.isDestroyed()) return;
|
|
3997
|
+
deps.recomputeSnaps();
|
|
3998
|
+
const isVertical = deps.isVerticalAxis();
|
|
3999
|
+
const visible = isVertical ? vv.height : vv.width;
|
|
4000
|
+
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
4001
|
+
const clamp = Math.max(0, Math.min(windowSize, visible) - SAFETY_PAD);
|
|
4002
|
+
if (clamp < deps.getMaxAxisSize()) {
|
|
4003
|
+
deps.setMaxAxisSize(clamp);
|
|
4004
|
+
}
|
|
4005
|
+
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
4006
|
+
deps.cancelInFlight();
|
|
4007
|
+
deps.newCycle();
|
|
4008
|
+
const max = deps.getMaxAxisSize();
|
|
4009
|
+
deps.setSize(Math.min(deps.getSize(), max));
|
|
4010
|
+
const current = deps.resolveActiveSnap();
|
|
4011
|
+
if (current && !deps.isDragging()) {
|
|
4012
|
+
deps.applySize(Math.min(current.size, max));
|
|
4013
|
+
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
4014
|
+
} else {
|
|
4015
|
+
deps.applySize(deps.getSize());
|
|
4016
|
+
}
|
|
4017
|
+
});
|
|
4018
|
+
};
|
|
4019
|
+
vv.addEventListener("resize", onResize);
|
|
4020
|
+
return () => {
|
|
4021
|
+
vv.removeEventListener("resize", onResize);
|
|
4022
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
4023
|
+
};
|
|
4024
|
+
}
|
|
4025
|
+
|
|
4026
|
+
// src/core/features/engine-features.ts
|
|
4027
|
+
function routeFeature() {
|
|
4028
|
+
return {
|
|
4029
|
+
name: "route",
|
|
4030
|
+
install: (ctx) => {
|
|
4031
|
+
const teardowns = new TeardownStack();
|
|
4032
|
+
if (ctx.options.closeOnRouteChange) {
|
|
4033
|
+
teardowns.add(
|
|
4034
|
+
installRouteChange({
|
|
4035
|
+
isDestroyed: ctx.isDestroyed,
|
|
4036
|
+
getSize: ctx.getSize,
|
|
4037
|
+
close: () => ctx.close()
|
|
4038
|
+
})
|
|
4039
|
+
);
|
|
4040
|
+
}
|
|
4041
|
+
teardowns.add(
|
|
4042
|
+
installRoute({
|
|
4043
|
+
routedTo: ctx.options.routedTo,
|
|
4044
|
+
closeOnBack: ctx.options.closeOnBack,
|
|
4045
|
+
isTopSheet: ctx.isTopSheet,
|
|
4046
|
+
getSize: ctx.getSize,
|
|
4047
|
+
isDestroyed: ctx.isDestroyed,
|
|
4048
|
+
close: () => ctx.close("back"),
|
|
4049
|
+
on: ctx.on,
|
|
4050
|
+
sheetId: ctx.sheetId
|
|
4051
|
+
})
|
|
4052
|
+
);
|
|
4053
|
+
return () => teardowns.drain();
|
|
4054
|
+
}
|
|
4055
|
+
};
|
|
4056
|
+
}
|
|
4057
|
+
function persistFeature() {
|
|
4058
|
+
return {
|
|
4059
|
+
name: "persist",
|
|
4060
|
+
install: (ctx) => {
|
|
4061
|
+
const key = ctx.options.persistKey;
|
|
4062
|
+
if (!key) return;
|
|
4063
|
+
return installPersist({ on: ctx.on }, key);
|
|
4064
|
+
}
|
|
4065
|
+
};
|
|
4066
|
+
}
|
|
4067
|
+
function autoCollapseFeature() {
|
|
4068
|
+
return {
|
|
4069
|
+
name: "auto-collapse",
|
|
4070
|
+
install: (ctx) => installAutoCollapse({
|
|
4071
|
+
ms: ctx.options.autoCollapseAfter,
|
|
4072
|
+
isDestroyed: ctx.isDestroyed,
|
|
4073
|
+
isDragging: ctx.isDragging,
|
|
4074
|
+
getAllowedIds: ctx.getAllowedIds,
|
|
4075
|
+
getActiveId: ctx.getActiveId,
|
|
4076
|
+
resolveSnap: ctx.resolveSnap,
|
|
4077
|
+
snapTo: ctx.snapTo,
|
|
4078
|
+
on: ctx.on
|
|
4079
|
+
})
|
|
4080
|
+
};
|
|
4081
|
+
}
|
|
4082
|
+
function contentSwipeFeature() {
|
|
4083
|
+
return {
|
|
4084
|
+
name: "content-swipe",
|
|
4085
|
+
stage: "attach",
|
|
4086
|
+
install: (ctx) => {
|
|
4087
|
+
if (!ctx.scrollContainer) return;
|
|
4088
|
+
return installContentDrag({
|
|
4089
|
+
container: ctx.scrollContainer,
|
|
4090
|
+
attachDragSurface: ctx.attachDragSurface
|
|
4091
|
+
});
|
|
4092
|
+
}
|
|
4093
|
+
};
|
|
4094
|
+
}
|
|
4095
|
+
function visualViewportFeature() {
|
|
4096
|
+
return {
|
|
4097
|
+
name: "visual-viewport",
|
|
4098
|
+
install: (ctx) => {
|
|
4099
|
+
if (typeof window === "undefined") return;
|
|
4100
|
+
return installVisualViewport({
|
|
4101
|
+
element: ctx.element,
|
|
4102
|
+
isVerticalAxis: ctx.isVerticalAxis,
|
|
4103
|
+
isDestroyed: ctx.isDestroyed,
|
|
4104
|
+
isDragging: ctx.isDragging,
|
|
4105
|
+
recomputeSnaps: ctx.recomputeSnaps,
|
|
4106
|
+
resolveActiveSnap: ctx.resolveActiveSnap,
|
|
4107
|
+
getMaxAxisSize: ctx.getMaxAxisSize,
|
|
4108
|
+
getSize: ctx.getSize,
|
|
4109
|
+
setMaxAxisSize: ctx.setMaxAxisSize,
|
|
4110
|
+
setSize: ctx.setSize,
|
|
4111
|
+
applySize: ctx.applySize,
|
|
4112
|
+
cancelInFlight: ctx.cancelInFlight,
|
|
4113
|
+
newCycle: ctx.newCycle,
|
|
4114
|
+
isAnimating: ctx.isAnimating,
|
|
4115
|
+
resyncAfterCancel: ctx.resyncAfterResize
|
|
4116
|
+
});
|
|
4117
|
+
}
|
|
4118
|
+
};
|
|
4119
|
+
}
|
|
4120
|
+
|
|
4121
|
+
// src/core/default-features.ts
|
|
4122
|
+
function defaultEngineFeatures() {
|
|
4123
|
+
return [
|
|
4124
|
+
contentSwipeFeature(),
|
|
4125
|
+
visualViewportFeature(),
|
|
4126
|
+
persistFeature(),
|
|
4127
|
+
autoCollapseFeature(),
|
|
4128
|
+
routeFeature()
|
|
4129
|
+
];
|
|
4130
|
+
}
|
|
4131
|
+
|
|
4132
|
+
// src/core/BottomSheetEngine.ts
|
|
4133
|
+
var BottomSheetEngine = class extends BottomSheetCore {
|
|
4134
|
+
constructor(opts) {
|
|
4135
|
+
super({
|
|
4136
|
+
...opts,
|
|
4137
|
+
features: [...defaultEngineFeatures(), ...opts.features ?? []]
|
|
4138
|
+
});
|
|
4139
|
+
}
|
|
4140
|
+
};
|
|
4141
|
+
|
|
3718
4142
|
// src/core/features/teleport.ts
|
|
3719
4143
|
var resolveTeleportTarget = (target) => {
|
|
3720
4144
|
if (!target) return null;
|