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