@surdeddd/bottom-sheet 0.8.2 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BottomSheetEngine-7BDK2OWX.d.cts → BottomSheetEngine-BcyruNP1.d.cts} +12 -6
- package/dist/{BottomSheetEngine-BFTb0-4Z.d.ts → BottomSheetEngine-CBRcBwV-.d.ts} +12 -6
- package/dist/element.cjs +530 -349
- 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 +530 -349
- package/dist/index.cjs +438 -294
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +438 -294
- 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 +160 -96
- package/dist/overlay.d.cts +2 -0
- package/dist/overlay.d.ts +2 -0
- package/dist/overlay.js +160 -96
- package/dist/preact.d.cts +1 -1
- package/dist/preact.d.ts +1 -1
- package/dist/qwik.cjs +387 -211
- package/dist/qwik.d.cts +4 -3
- package/dist/qwik.d.ts +4 -3
- package/dist/qwik.js +387 -211
- package/dist/react.cjs +472 -296
- package/dist/react.d.cts +3 -2
- package/dist/react.d.ts +3 -2
- package/dist/react.js +472 -296
- package/dist/solid.cjs +417 -215
- package/dist/solid.d.cts +21 -7
- package/dist/solid.d.ts +21 -7
- package/dist/solid.js +417 -215
- package/dist/solid.source.jsx +412 -209
- package/dist/svelte-core.cjs +328 -209
- package/dist/svelte-core.js +328 -209
- package/dist/svelte-src/BottomSheet.svelte +56 -0
- package/dist/svelte.cjs +365 -210
- package/dist/svelte.d.cts +4 -0
- package/dist/svelte.d.ts +4 -0
- package/dist/svelte.js +365 -210
- package/dist/vue.cjs +358 -211
- package/dist/vue.d.cts +6 -0
- package/dist/vue.d.ts +6 -0
- package/dist/vue.js +358 -211
- package/package.json +6 -6
package/dist/react.js
CHANGED
|
@@ -272,18 +272,25 @@ var SnapResolver = class {
|
|
|
272
272
|
__publicField(this, "resolved", []);
|
|
273
273
|
__publicField(this, "maxAxisSize", 0);
|
|
274
274
|
__publicField(this, "rangeCache", null);
|
|
275
|
+
__publicField(this, "notified", false);
|
|
275
276
|
this.raw = raw;
|
|
276
277
|
this.allowedIds = allowed ?? raw.map((p) => p.id);
|
|
277
278
|
this.recompute();
|
|
278
279
|
}
|
|
279
280
|
recompute() {
|
|
280
|
-
|
|
281
|
-
|
|
281
|
+
const measure = this.measureFit;
|
|
282
|
+
let measured;
|
|
283
|
+
const measureOnce = measure ? () => measured ?? (measured = measure()) : void 0;
|
|
284
|
+
this.resolved = resolveSnapList(this.raw, this.mode, measureOnce);
|
|
285
|
+
const nextMax = this.resolved.reduce(
|
|
282
286
|
(m, s) => s.size > m ? s.size : m,
|
|
283
287
|
0
|
|
284
288
|
);
|
|
285
289
|
this.rangeCache = null;
|
|
286
|
-
this.
|
|
290
|
+
const changed = nextMax !== this.maxAxisSize || !this.notified;
|
|
291
|
+
this.maxAxisSize = nextMax;
|
|
292
|
+
this.notified = true;
|
|
293
|
+
if (changed) this.onMaxAxisSizeChange?.(this.maxAxisSize);
|
|
287
294
|
}
|
|
288
295
|
setRaw(raw) {
|
|
289
296
|
this.raw = raw;
|
|
@@ -436,7 +443,10 @@ var ensureHandler = () => {
|
|
|
436
443
|
target.consumed = true;
|
|
437
444
|
const idx = closers.indexOf(target);
|
|
438
445
|
if (idx !== -1) closers.splice(idx, 1);
|
|
439
|
-
target
|
|
446
|
+
const settled = target;
|
|
447
|
+
void Promise.resolve(settled.close()).then(() => {
|
|
448
|
+
if (settled.isOpen()) settled.restore();
|
|
449
|
+
});
|
|
440
450
|
});
|
|
441
451
|
};
|
|
442
452
|
var programmaticBack = () => {
|
|
@@ -472,16 +482,7 @@ function installRoute(deps) {
|
|
|
472
482
|
pushed = false;
|
|
473
483
|
}
|
|
474
484
|
};
|
|
475
|
-
const
|
|
476
|
-
if (closer) return;
|
|
477
|
-
closer = {
|
|
478
|
-
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
479
|
-
isTop: () => deps.isTopSheet(),
|
|
480
|
-
close: () => void deps.close(),
|
|
481
|
-
consumed: false
|
|
482
|
-
};
|
|
483
|
-
ensureHandler();
|
|
484
|
-
closers.push(closer);
|
|
485
|
+
const pushEntry = () => {
|
|
485
486
|
try {
|
|
486
487
|
if (deps.routedTo !== void 0) {
|
|
487
488
|
history.pushState({ __bsRouted: deps.sheetId }, "", deps.routedTo);
|
|
@@ -493,6 +494,25 @@ function installRoute(deps) {
|
|
|
493
494
|
pushed = false;
|
|
494
495
|
}
|
|
495
496
|
};
|
|
497
|
+
const onOpen = () => {
|
|
498
|
+
if (closer) return;
|
|
499
|
+
const self = {
|
|
500
|
+
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
501
|
+
isTop: () => deps.isTopSheet(),
|
|
502
|
+
close: () => deps.close(),
|
|
503
|
+
restore: () => {
|
|
504
|
+
if (deps.isDestroyed() || closer !== self) return;
|
|
505
|
+
self.consumed = false;
|
|
506
|
+
if (!closers.includes(self)) closers.push(self);
|
|
507
|
+
pushEntry();
|
|
508
|
+
},
|
|
509
|
+
consumed: false
|
|
510
|
+
};
|
|
511
|
+
closer = self;
|
|
512
|
+
ensureHandler();
|
|
513
|
+
closers.push(self);
|
|
514
|
+
pushEntry();
|
|
515
|
+
};
|
|
496
516
|
const unsubscribeOpen = deps.on("open", onOpen);
|
|
497
517
|
const unsubscribeClose = deps.on("close", teardownEntry);
|
|
498
518
|
if (deps.getSize() > 0) onOpen();
|
|
@@ -539,11 +559,13 @@ var CONTENT_PULL_THRESHOLD = 60;
|
|
|
539
559
|
function installContentSwipe(deps) {
|
|
540
560
|
const { container } = deps;
|
|
541
561
|
let startY = 0;
|
|
562
|
+
let startScrollTop = 0;
|
|
542
563
|
let moved = false;
|
|
543
564
|
const onTouchStart = (e) => {
|
|
544
565
|
const t = e.touches[0];
|
|
545
566
|
if (!t) return;
|
|
546
567
|
startY = t.clientY;
|
|
568
|
+
startScrollTop = container.scrollTop;
|
|
547
569
|
moved = false;
|
|
548
570
|
};
|
|
549
571
|
const onTouchMove = (e) => {
|
|
@@ -554,6 +576,7 @@ function installContentSwipe(deps) {
|
|
|
554
576
|
const onTouchEnd = (e) => {
|
|
555
577
|
if (!moved) return;
|
|
556
578
|
if (deps.isDragging() || deps.isAnimating()) return;
|
|
579
|
+
if (container.scrollTop !== startScrollTop) return;
|
|
557
580
|
const t = e.changedTouches[0];
|
|
558
581
|
if (!t) return;
|
|
559
582
|
const deltaY = t.clientY - startY;
|
|
@@ -665,6 +688,131 @@ function installResizeObserver(deps) {
|
|
|
665
688
|
};
|
|
666
689
|
}
|
|
667
690
|
|
|
691
|
+
// src/core/features/fit-observer.ts
|
|
692
|
+
var contentTargets = (scroller) => {
|
|
693
|
+
if (!scroller) return [];
|
|
694
|
+
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
695
|
+
const out = [];
|
|
696
|
+
for (const child of Array.from(scroller.children)) {
|
|
697
|
+
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
698
|
+
for (const el of child.assignedElements()) out.push(el);
|
|
699
|
+
} else {
|
|
700
|
+
out.push(child);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return out;
|
|
704
|
+
};
|
|
705
|
+
function installFitObserver(deps) {
|
|
706
|
+
if (typeof ResizeObserver === "undefined") return () => {
|
|
707
|
+
};
|
|
708
|
+
if (!deps.hasFitSnap()) return () => {
|
|
709
|
+
};
|
|
710
|
+
let raf = 0;
|
|
711
|
+
const schedule = () => {
|
|
712
|
+
if (raf) return;
|
|
713
|
+
raf = requestAnimationFrame(() => {
|
|
714
|
+
raf = 0;
|
|
715
|
+
if (deps.isDestroyed() || deps.isDragging()) return;
|
|
716
|
+
deps.recompute();
|
|
717
|
+
});
|
|
718
|
+
};
|
|
719
|
+
const ro = new ResizeObserver(schedule);
|
|
720
|
+
ro.observe(deps.handle);
|
|
721
|
+
const scroller = deps.scrollContainer;
|
|
722
|
+
const observed = /* @__PURE__ */ new Set();
|
|
723
|
+
const slots = /* @__PURE__ */ new Set();
|
|
724
|
+
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
725
|
+
const onSlotChange = () => resync();
|
|
726
|
+
const trackSlots = () => {
|
|
727
|
+
if (!scroller || !hasSlot) return;
|
|
728
|
+
for (const child of Array.from(scroller.children)) {
|
|
729
|
+
if (child instanceof HTMLSlotElement && !slots.has(child)) {
|
|
730
|
+
child.addEventListener("slotchange", onSlotChange);
|
|
731
|
+
slots.add(child);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
const resync = () => {
|
|
736
|
+
trackSlots();
|
|
737
|
+
const targets = contentTargets(scroller);
|
|
738
|
+
for (const el of observed) {
|
|
739
|
+
if (!targets.includes(el)) {
|
|
740
|
+
ro.unobserve(el);
|
|
741
|
+
observed.delete(el);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
for (const el of targets) {
|
|
745
|
+
if (!observed.has(el)) {
|
|
746
|
+
ro.observe(el);
|
|
747
|
+
observed.add(el);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
schedule();
|
|
751
|
+
};
|
|
752
|
+
let mo;
|
|
753
|
+
if (scroller) {
|
|
754
|
+
resync();
|
|
755
|
+
if (typeof MutationObserver !== "undefined") {
|
|
756
|
+
mo = new MutationObserver(resync);
|
|
757
|
+
mo.observe(scroller, { childList: true });
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
return () => {
|
|
761
|
+
ro.disconnect();
|
|
762
|
+
mo?.disconnect();
|
|
763
|
+
for (const slot of slots) {
|
|
764
|
+
slot.removeEventListener("slotchange", onSlotChange);
|
|
765
|
+
}
|
|
766
|
+
if (raf) cancelAnimationFrame(raf);
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// src/core/features/fit-measurement.ts
|
|
771
|
+
var measureSheetNatural = (element, content, vertical) => {
|
|
772
|
+
if (!content) {
|
|
773
|
+
return vertical ? element.offsetHeight : element.offsetWidth;
|
|
774
|
+
}
|
|
775
|
+
const axis = vertical ? "height" : "width";
|
|
776
|
+
const sheetStyle = element.style;
|
|
777
|
+
const cs = content.style;
|
|
778
|
+
const prevSheet = sheetStyle[axis];
|
|
779
|
+
const prevFlex = cs.flex;
|
|
780
|
+
const prevContent = vertical ? cs.height : cs.width;
|
|
781
|
+
sheetStyle[axis] = "auto";
|
|
782
|
+
cs.flex = "none";
|
|
783
|
+
if (vertical) cs.height = "auto";
|
|
784
|
+
else cs.width = "auto";
|
|
785
|
+
const poked = vertical ? element.offsetHeight : element.offsetWidth;
|
|
786
|
+
const contentBox = vertical ? content.clientHeight : content.clientWidth;
|
|
787
|
+
const contentScroll = vertical ? content.scrollHeight : content.scrollWidth;
|
|
788
|
+
const natural = Math.max(poked, poked - contentBox + contentScroll);
|
|
789
|
+
sheetStyle[axis] = prevSheet;
|
|
790
|
+
cs.flex = prevFlex;
|
|
791
|
+
if (vertical) cs.height = prevContent;
|
|
792
|
+
else cs.width = prevContent;
|
|
793
|
+
return natural;
|
|
794
|
+
};
|
|
795
|
+
var containingExtent = (element, vertical) => {
|
|
796
|
+
const op = element.offsetParent;
|
|
797
|
+
if (op && op !== document.body && op !== document.documentElement) {
|
|
798
|
+
return vertical ? op.clientHeight : op.clientWidth;
|
|
799
|
+
}
|
|
800
|
+
return vertical ? window.innerHeight : window.innerWidth;
|
|
801
|
+
};
|
|
802
|
+
var measureFitSize = (deps) => {
|
|
803
|
+
const vertical = layoutAxis(deps.mode) === "height";
|
|
804
|
+
const natural = measureSheetNatural(
|
|
805
|
+
deps.element,
|
|
806
|
+
deps.scrollContainer,
|
|
807
|
+
vertical
|
|
808
|
+
);
|
|
809
|
+
const cap = deps.getMaxHeightCap();
|
|
810
|
+
const capped = cap !== void 0 ? Math.min(natural, cap) : natural;
|
|
811
|
+
if (typeof window === "undefined") return capped;
|
|
812
|
+
const viewport = containingExtent(deps.element, vertical);
|
|
813
|
+
return viewport > 0 ? Math.min(capped, viewport) : capped;
|
|
814
|
+
};
|
|
815
|
+
|
|
668
816
|
// src/core/features/slider-keyboard.ts
|
|
669
817
|
function installSliderKeyboard(deps) {
|
|
670
818
|
const isVerticalAxis = deps.mode === "bottom" || deps.mode === "top";
|
|
@@ -1151,6 +1299,9 @@ var ScrimController = class {
|
|
|
1151
1299
|
const s = this.screenComponent.style;
|
|
1152
1300
|
s.opacity = "";
|
|
1153
1301
|
s.display = "";
|
|
1302
|
+
s.position = "";
|
|
1303
|
+
s.inset = "";
|
|
1304
|
+
s.pointerEvents = "";
|
|
1154
1305
|
}
|
|
1155
1306
|
if (this.backdrop) {
|
|
1156
1307
|
this.backdrop.style.opacity = "";
|
|
@@ -1399,7 +1550,12 @@ var AnimationRunner = class {
|
|
|
1399
1550
|
this.currentSpring?.cancel();
|
|
1400
1551
|
}
|
|
1401
1552
|
async animateTo(target, velocityPxPerMs) {
|
|
1402
|
-
if (target === this.getSize())
|
|
1553
|
+
if (target === this.getSize()) {
|
|
1554
|
+
if (!this.isAnimating && !this.isDragging()) {
|
|
1555
|
+
this.element.style.willChange = "";
|
|
1556
|
+
}
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1403
1559
|
this.currentTween?.cancel();
|
|
1404
1560
|
this.currentSpring?.cancel();
|
|
1405
1561
|
this.getRootEl()?.setAttribute("data-animating", "true");
|
|
@@ -1407,7 +1563,7 @@ var AnimationRunner = class {
|
|
|
1407
1563
|
if (this.reducedMotion) {
|
|
1408
1564
|
this.applySizeFn(target);
|
|
1409
1565
|
this.getRootEl()?.removeAttribute("data-animating");
|
|
1410
|
-
if (!this.isDragging()) this.element.style.willChange = "
|
|
1566
|
+
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1411
1567
|
return;
|
|
1412
1568
|
}
|
|
1413
1569
|
if (this.animationKind === "spring") {
|
|
@@ -1435,7 +1591,7 @@ var AnimationRunner = class {
|
|
|
1435
1591
|
}
|
|
1436
1592
|
if (!this.isAnimating) {
|
|
1437
1593
|
this.getRootEl()?.removeAttribute("data-animating");
|
|
1438
|
-
if (!this.isDragging()) this.element.style.willChange = "
|
|
1594
|
+
if (!this.isDragging()) this.element.style.willChange = "";
|
|
1439
1595
|
}
|
|
1440
1596
|
}
|
|
1441
1597
|
destroy() {
|
|
@@ -1466,9 +1622,35 @@ var isVisible = (el) => {
|
|
|
1466
1622
|
}
|
|
1467
1623
|
return el.offsetParent !== null;
|
|
1468
1624
|
};
|
|
1469
|
-
var
|
|
1625
|
+
var collectFocusables = (root) => {
|
|
1626
|
+
const out = Array.from(root.querySelectorAll(FOCUSABLE));
|
|
1627
|
+
if (typeof HTMLSlotElement !== "undefined") {
|
|
1628
|
+
for (const slot of Array.from(root.querySelectorAll("slot"))) {
|
|
1629
|
+
for (const assigned of slot.assignedElements()) {
|
|
1630
|
+
if (assigned.matches(FOCUSABLE)) out.push(assigned);
|
|
1631
|
+
out.push(...collectFocusables(assigned));
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
return out;
|
|
1636
|
+
};
|
|
1637
|
+
var focusables = (root) => collectFocusables(root).filter(
|
|
1470
1638
|
(el) => !el.hasAttribute("inert") && isVisible(el) && !el.matches("[aria-hidden='true']")
|
|
1471
1639
|
);
|
|
1640
|
+
var containsComposed = (container, node) => {
|
|
1641
|
+
let n = node;
|
|
1642
|
+
while (n) {
|
|
1643
|
+
if (n === container) return true;
|
|
1644
|
+
const slot = n.assignedSlot;
|
|
1645
|
+
if (slot) {
|
|
1646
|
+
n = slot;
|
|
1647
|
+
continue;
|
|
1648
|
+
}
|
|
1649
|
+
const parent = n.parentNode;
|
|
1650
|
+
n = parent instanceof ShadowRoot ? parent.host : parent;
|
|
1651
|
+
}
|
|
1652
|
+
return false;
|
|
1653
|
+
};
|
|
1472
1654
|
var trapStack = [];
|
|
1473
1655
|
var installFocusTrap = (container, options = {}) => {
|
|
1474
1656
|
if (typeof document === "undefined") return () => {
|
|
@@ -1478,7 +1660,13 @@ var installFocusTrap = (container, options = {}) => {
|
|
|
1478
1660
|
const isActive = () => trapStack[trapStack.length - 1] === token;
|
|
1479
1661
|
const previouslyFocused = document.activeElement;
|
|
1480
1662
|
const focusInitial = () => {
|
|
1481
|
-
const
|
|
1663
|
+
const spec = options.initialFocus;
|
|
1664
|
+
if (spec === false) {
|
|
1665
|
+
if (!container.hasAttribute("tabindex")) container.tabIndex = -1;
|
|
1666
|
+
container.focus({ preventScroll: true });
|
|
1667
|
+
return;
|
|
1668
|
+
}
|
|
1669
|
+
const initial = typeof spec === "string" ? container.querySelector(spec) : spec ?? focusables(container)[0] ?? container;
|
|
1482
1670
|
initial?.focus({ preventScroll: true });
|
|
1483
1671
|
};
|
|
1484
1672
|
focusInitial();
|
|
@@ -1508,7 +1696,7 @@ var installFocusTrap = (container, options = {}) => {
|
|
|
1508
1696
|
const handleFocusIn = (e) => {
|
|
1509
1697
|
if (!isActive()) return;
|
|
1510
1698
|
const target = e.target;
|
|
1511
|
-
if (target && !container
|
|
1699
|
+
if (target && !containsComposed(container, target)) {
|
|
1512
1700
|
const list = focusables(container);
|
|
1513
1701
|
list[0]?.focus({ preventScroll: true });
|
|
1514
1702
|
}
|
|
@@ -1545,8 +1733,14 @@ var lockBodyScroll = () => {
|
|
|
1545
1733
|
position: body.style.position,
|
|
1546
1734
|
top: body.style.top,
|
|
1547
1735
|
width: body.style.width,
|
|
1736
|
+
paddingRight: body.style.paddingRight,
|
|
1548
1737
|
scrollY: window.scrollY
|
|
1549
1738
|
};
|
|
1739
|
+
const scrollbarGap = window.innerWidth - document.documentElement.clientWidth;
|
|
1740
|
+
if (scrollbarGap > 0) {
|
|
1741
|
+
const current = parseFloat(getComputedStyle(body).paddingRight) || 0;
|
|
1742
|
+
body.style.paddingRight = `${current + scrollbarGap}px`;
|
|
1743
|
+
}
|
|
1550
1744
|
body.style.overflow = "hidden";
|
|
1551
1745
|
body.style.position = "fixed";
|
|
1552
1746
|
body.style.top = `-${savedStyles.scrollY}px`;
|
|
@@ -1564,6 +1758,7 @@ var lockBodyScroll = () => {
|
|
|
1564
1758
|
body.style.position = savedStyles.position;
|
|
1565
1759
|
body.style.top = savedStyles.top;
|
|
1566
1760
|
body.style.width = savedStyles.width;
|
|
1761
|
+
body.style.paddingRight = savedStyles.paddingRight;
|
|
1567
1762
|
window.scrollTo(0, savedStyles.scrollY);
|
|
1568
1763
|
savedStyles = null;
|
|
1569
1764
|
}
|
|
@@ -1776,12 +1971,14 @@ var installGestures = (handle, mode, callbacks) => {
|
|
|
1776
1971
|
handle.addEventListener("pointermove", onPointerMove);
|
|
1777
1972
|
handle.addEventListener("pointerup", finishGesture);
|
|
1778
1973
|
handle.addEventListener("pointercancel", onPointerCancel);
|
|
1974
|
+
const prevTouchAction = handle.style.touchAction;
|
|
1779
1975
|
handle.style.touchAction = isAxisVertical(mode) ? "pan-x" : "pan-y";
|
|
1780
1976
|
return () => {
|
|
1781
1977
|
handle.removeEventListener("pointerdown", onPointerDown);
|
|
1782
1978
|
handle.removeEventListener("pointermove", onPointerMove);
|
|
1783
1979
|
handle.removeEventListener("pointerup", finishGesture);
|
|
1784
1980
|
handle.removeEventListener("pointercancel", onPointerCancel);
|
|
1981
|
+
handle.style.touchAction = prevTouchAction;
|
|
1785
1982
|
if (activePointerId !== null && handle.hasPointerCapture(activePointerId)) {
|
|
1786
1983
|
handle.releasePointerCapture(activePointerId);
|
|
1787
1984
|
}
|
|
@@ -1908,7 +2105,7 @@ var GestureController = class {
|
|
|
1908
2105
|
this.isDragging_ = false;
|
|
1909
2106
|
this.keyboardDismissed = false;
|
|
1910
2107
|
this.deps.getRoot()?.removeAttribute("data-dragging");
|
|
1911
|
-
this.deps.element.style.willChange = "
|
|
2108
|
+
this.deps.element.style.willChange = "";
|
|
1912
2109
|
}
|
|
1913
2110
|
};
|
|
1914
2111
|
|
|
@@ -2307,8 +2504,7 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2307
2504
|
};
|
|
2308
2505
|
}
|
|
2309
2506
|
|
|
2310
|
-
// src/core/
|
|
2311
|
-
var HAPTIC_DURATION_MS = 8;
|
|
2507
|
+
// src/core/primitives/teardown-stack.ts
|
|
2312
2508
|
var TeardownStack = class {
|
|
2313
2509
|
constructor() {
|
|
2314
2510
|
__publicField(this, "fns", []);
|
|
@@ -2328,6 +2524,9 @@ var TeardownStack = class {
|
|
|
2328
2524
|
}
|
|
2329
2525
|
}
|
|
2330
2526
|
};
|
|
2527
|
+
|
|
2528
|
+
// src/core/BottomSheetEngine.ts
|
|
2529
|
+
var HAPTIC_DURATION_MS = 8;
|
|
2331
2530
|
var BottomSheetEngine = class {
|
|
2332
2531
|
constructor(opts) {
|
|
2333
2532
|
__publicField(this, "id", nextInstanceId("bs"));
|
|
@@ -2352,6 +2551,7 @@ var BottomSheetEngine = class {
|
|
|
2352
2551
|
__publicField(this, "disableDragFlag");
|
|
2353
2552
|
__publicField(this, "closeOnRouteChange");
|
|
2354
2553
|
__publicField(this, "maxHeightCap");
|
|
2554
|
+
__publicField(this, "maxHeightRaw");
|
|
2355
2555
|
__publicField(this, "snapPointsRaw");
|
|
2356
2556
|
__publicField(this, "snaps");
|
|
2357
2557
|
__publicField(this, "activeId");
|
|
@@ -2387,6 +2587,7 @@ var BottomSheetEngine = class {
|
|
|
2387
2587
|
__publicField(this, "detachScrimStages", null);
|
|
2388
2588
|
__publicField(this, "stackEffectEnabled", false);
|
|
2389
2589
|
__publicField(this, "stackEffectPrimed", false);
|
|
2590
|
+
__publicField(this, "fitDeps");
|
|
2390
2591
|
__publicField(this, "transformTemplate");
|
|
2391
2592
|
const resolved = resolveEngineOptions(opts, {
|
|
2392
2593
|
shouldApplyInertSiblings: () => {
|
|
@@ -2459,12 +2660,19 @@ var BottomSheetEngine = class {
|
|
|
2459
2660
|
}
|
|
2460
2661
|
this.activeId = resolved.initialId;
|
|
2461
2662
|
auditVhUsage(this.snapPointsRaw);
|
|
2663
|
+
this.auditDuplicateSnapIds(this.snapPointsRaw);
|
|
2462
2664
|
this.rootEl = this.element.closest(".bs-root");
|
|
2665
|
+
this.fitDeps = {
|
|
2666
|
+
element: this.element,
|
|
2667
|
+
scrollContainer: this.scrollContainer,
|
|
2668
|
+
mode: this.mode,
|
|
2669
|
+
getMaxHeightCap: () => this.maxHeightCap
|
|
2670
|
+
};
|
|
2463
2671
|
this.snaps = new SnapResolver(
|
|
2464
2672
|
this.snapPointsRaw,
|
|
2465
2673
|
resolved.initialAllowed,
|
|
2466
2674
|
this.mode,
|
|
2467
|
-
() => this.
|
|
2675
|
+
() => measureFitSize(this.fitDeps),
|
|
2468
2676
|
(maxAxisSize) => {
|
|
2469
2677
|
this.element.style[layoutAxis(this.mode)] = `${maxAxisSize}px`;
|
|
2470
2678
|
}
|
|
@@ -2498,7 +2706,18 @@ var BottomSheetEngine = class {
|
|
|
2498
2706
|
io.observe(this.element);
|
|
2499
2707
|
this.teardowns.add(() => io.disconnect());
|
|
2500
2708
|
}
|
|
2501
|
-
this.
|
|
2709
|
+
this.teardowns.add(
|
|
2710
|
+
installFitObserver({
|
|
2711
|
+
handle: this.handle,
|
|
2712
|
+
scrollContainer: this.scrollContainer,
|
|
2713
|
+
hasFitSnap: () => this.snapPointsRaw.some(
|
|
2714
|
+
(p) => p.size === "fit" || p.size === "content"
|
|
2715
|
+
),
|
|
2716
|
+
isDestroyed: () => this.destroyed,
|
|
2717
|
+
isDragging: () => this.gesture?.isDragging ?? false,
|
|
2718
|
+
recompute: () => this.recompute()
|
|
2719
|
+
})
|
|
2720
|
+
);
|
|
2502
2721
|
if (resolved.radius !== void 0) this.setRadius(resolved.radius);
|
|
2503
2722
|
if (resolved.maxHeight !== void 0) this.setMaxHeight(resolved.maxHeight);
|
|
2504
2723
|
this.applyAutoAriaLabelledBy();
|
|
@@ -2649,27 +2868,33 @@ var BottomSheetEngine = class {
|
|
|
2649
2868
|
} else {
|
|
2650
2869
|
await this.animation.animateTo(target.size, velocityPxPerMs);
|
|
2651
2870
|
}
|
|
2652
|
-
this.opening = false;
|
|
2653
2871
|
externalSignal?.removeEventListener("abort", onExternalAbort);
|
|
2654
2872
|
if (signal.aborted) return;
|
|
2655
|
-
this.
|
|
2873
|
+
this.opening = false;
|
|
2874
|
+
this.completeSnap(id, target.size, previousSize, wasClosed, false);
|
|
2875
|
+
}
|
|
2876
|
+
completeSnap(id, targetSize, previousSize, wasClosed, withHaptic) {
|
|
2877
|
+
this.scrollCache.restore(id, previousSize, targetSize);
|
|
2656
2878
|
this.updateAriaSlider();
|
|
2657
2879
|
this.emit("snap", {
|
|
2658
2880
|
id,
|
|
2659
2881
|
size: this.size,
|
|
2660
2882
|
progress: this.computeProgress(this.size)
|
|
2661
2883
|
});
|
|
2662
|
-
if (
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
}
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2884
|
+
if (withHaptic) this.haptic();
|
|
2885
|
+
if (wasClosed && targetSize > 0) this.emitOpenSequence(id);
|
|
2886
|
+
if (targetSize === 0) this.emitCloseSequence();
|
|
2887
|
+
}
|
|
2888
|
+
emitOpenSequence(id) {
|
|
2889
|
+
this.emit("open", { id });
|
|
2890
|
+
this.handleOpen();
|
|
2891
|
+
notifyLinkedSheets(this.linkedSheets, this);
|
|
2892
|
+
this.emit("opened", { id });
|
|
2893
|
+
}
|
|
2894
|
+
emitCloseSequence() {
|
|
2895
|
+
this.emit("close", void 0);
|
|
2896
|
+
this.handleClose();
|
|
2897
|
+
this.emit("closed", void 0);
|
|
2673
2898
|
}
|
|
2674
2899
|
async dragTo(targetSize, velocityOrOpts = 0) {
|
|
2675
2900
|
if (this.destroyed) return;
|
|
@@ -2690,19 +2915,31 @@ var BottomSheetEngine = class {
|
|
|
2690
2915
|
}
|
|
2691
2916
|
open(id) {
|
|
2692
2917
|
if (this.destroyed) return Promise.resolve();
|
|
2693
|
-
const target = id ?? this.snaps.getAllowedIds().find((a) => a
|
|
2918
|
+
const target = id ?? this.snaps.getAllowedIds().find((a) => (this.snaps.findById(a)?.size ?? 0) > 0) ?? this.activeId;
|
|
2694
2919
|
return this.snapTo(target);
|
|
2695
2920
|
}
|
|
2696
2921
|
close(reason = "programmatic") {
|
|
2697
2922
|
if (this.destroyed) return Promise.resolve();
|
|
2698
2923
|
if (this.disableCloseFlag) return Promise.resolve();
|
|
2699
2924
|
if (this.size > 0 && this.emitBeforeClose(reason)) return Promise.resolve();
|
|
2700
|
-
const closedId = this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.snaps.getAllowedIds()[0];
|
|
2925
|
+
const closedId = this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.snaps.getAllowedIds().find((a) => this.snaps.findById(a)?.size === 0) ?? this.snaps.getAllowedIds()[0];
|
|
2701
2926
|
return this.snapTo(closedId ?? this.activeId);
|
|
2702
2927
|
}
|
|
2703
2928
|
canDismiss() {
|
|
2704
2929
|
return !this.persistent && !this.disableCloseFlag && !this.destroyed;
|
|
2705
2930
|
}
|
|
2931
|
+
setPersistent(value) {
|
|
2932
|
+
if (this.destroyed) return;
|
|
2933
|
+
this.persistent = value;
|
|
2934
|
+
}
|
|
2935
|
+
setDisableClose(value) {
|
|
2936
|
+
if (this.destroyed) return;
|
|
2937
|
+
this.disableCloseFlag = value;
|
|
2938
|
+
}
|
|
2939
|
+
setDisableDrag(value) {
|
|
2940
|
+
if (this.destroyed) return;
|
|
2941
|
+
this.disableDragFlag = value;
|
|
2942
|
+
}
|
|
2706
2943
|
isTop() {
|
|
2707
2944
|
return this.isTopSheet;
|
|
2708
2945
|
}
|
|
@@ -2739,18 +2976,23 @@ var BottomSheetEngine = class {
|
|
|
2739
2976
|
axis === "height" ? "max-height" : "max-width",
|
|
2740
2977
|
value
|
|
2741
2978
|
);
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
this.maxHeightCap = measured > 0 ? measured : void 0;
|
|
2752
|
-
this.recompute();
|
|
2979
|
+
this.maxHeightRaw = h;
|
|
2980
|
+
this.resolveMaxHeightCap();
|
|
2981
|
+
this.recompute();
|
|
2982
|
+
}
|
|
2983
|
+
resolveMaxHeightCap() {
|
|
2984
|
+
const raw = this.maxHeightRaw;
|
|
2985
|
+
if (raw === void 0) {
|
|
2986
|
+
this.maxHeightCap = void 0;
|
|
2987
|
+
return;
|
|
2753
2988
|
}
|
|
2989
|
+
if (typeof raw === "number") {
|
|
2990
|
+
this.maxHeightCap = raw;
|
|
2991
|
+
return;
|
|
2992
|
+
}
|
|
2993
|
+
if (typeof window === "undefined") return;
|
|
2994
|
+
const measured = resolveSnap(raw, this.mode);
|
|
2995
|
+
this.maxHeightCap = measured > 0 ? measured : void 0;
|
|
2754
2996
|
}
|
|
2755
2997
|
clampToMaxHeight() {
|
|
2756
2998
|
if (this.maxHeightCap === void 0) return;
|
|
@@ -2881,6 +3123,7 @@ var BottomSheetEngine = class {
|
|
|
2881
3123
|
this.newCycle();
|
|
2882
3124
|
this.snapPointsRaw = points;
|
|
2883
3125
|
auditVhUsage(points);
|
|
3126
|
+
this.auditDuplicateSnapIds(points);
|
|
2884
3127
|
this.snaps.setRaw(points);
|
|
2885
3128
|
if (allowed) this.snaps.setAllowedIds(allowed);
|
|
2886
3129
|
this.scrollCache.clear();
|
|
@@ -2893,6 +3136,7 @@ var BottomSheetEngine = class {
|
|
|
2893
3136
|
}
|
|
2894
3137
|
recompute() {
|
|
2895
3138
|
if (this.destroyed) return;
|
|
3139
|
+
this.resolveMaxHeightCap();
|
|
2896
3140
|
this.snaps.recompute();
|
|
2897
3141
|
this.clampToMaxHeight();
|
|
2898
3142
|
this.scrim.invalidateOpacityCache();
|
|
@@ -2904,129 +3148,6 @@ var BottomSheetEngine = class {
|
|
|
2904
3148
|
this.updateAriaSlider();
|
|
2905
3149
|
}
|
|
2906
3150
|
}
|
|
2907
|
-
contentTargets() {
|
|
2908
|
-
const scroller = this.scrollContainer;
|
|
2909
|
-
if (!scroller) return [];
|
|
2910
|
-
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
2911
|
-
const out = [];
|
|
2912
|
-
for (const child of Array.from(scroller.children)) {
|
|
2913
|
-
if (hasSlot && child instanceof HTMLSlotElement) {
|
|
2914
|
-
for (const el of child.assignedElements()) out.push(el);
|
|
2915
|
-
} else {
|
|
2916
|
-
out.push(child);
|
|
2917
|
-
}
|
|
2918
|
-
}
|
|
2919
|
-
return out;
|
|
2920
|
-
}
|
|
2921
|
-
measureSheetNatural(vertical) {
|
|
2922
|
-
const el = this.element;
|
|
2923
|
-
const content = this.scrollContainer;
|
|
2924
|
-
if (!content) {
|
|
2925
|
-
return vertical ? el.offsetHeight : el.offsetWidth;
|
|
2926
|
-
}
|
|
2927
|
-
const axis = vertical ? "height" : "width";
|
|
2928
|
-
const sheetStyle = el.style;
|
|
2929
|
-
const cs = content.style;
|
|
2930
|
-
const prevSheet = sheetStyle[axis];
|
|
2931
|
-
const prevFlex = cs.flex;
|
|
2932
|
-
const prevContent = vertical ? cs.height : cs.width;
|
|
2933
|
-
sheetStyle[axis] = "auto";
|
|
2934
|
-
cs.flex = "none";
|
|
2935
|
-
if (vertical) cs.height = "auto";
|
|
2936
|
-
else cs.width = "auto";
|
|
2937
|
-
const poked = vertical ? el.offsetHeight : el.offsetWidth;
|
|
2938
|
-
const contentBox = vertical ? content.clientHeight : content.clientWidth;
|
|
2939
|
-
const contentScroll = vertical ? content.scrollHeight : content.scrollWidth;
|
|
2940
|
-
const natural = Math.max(poked, poked - contentBox + contentScroll);
|
|
2941
|
-
sheetStyle[axis] = prevSheet;
|
|
2942
|
-
cs.flex = prevFlex;
|
|
2943
|
-
if (vertical) cs.height = prevContent;
|
|
2944
|
-
else cs.width = prevContent;
|
|
2945
|
-
return natural;
|
|
2946
|
-
}
|
|
2947
|
-
measureFitSize() {
|
|
2948
|
-
const vertical = layoutAxis(this.mode) === "height";
|
|
2949
|
-
const natural = this.measureSheetNatural(vertical);
|
|
2950
|
-
const capped = this.maxHeightCap !== void 0 ? Math.min(natural, this.maxHeightCap) : natural;
|
|
2951
|
-
if (typeof window === "undefined") return capped;
|
|
2952
|
-
const viewport = this.containingExtent(vertical);
|
|
2953
|
-
return viewport > 0 ? Math.min(capped, viewport) : capped;
|
|
2954
|
-
}
|
|
2955
|
-
// The fit cap is the sheet's containing block, not always the window: a
|
|
2956
|
-
// position:fixed sheet nested under a transform/filter/will-change ancestor
|
|
2957
|
-
// is clipped to that ancestor, so capping by window.innerHeight oversizes the
|
|
2958
|
-
// sheet and the content/footer get clipped. offsetParent resolves to that
|
|
2959
|
-
// ancestor when present, and is null (→ viewport) for a plain fixed sheet.
|
|
2960
|
-
containingExtent(vertical) {
|
|
2961
|
-
const op = this.element.offsetParent;
|
|
2962
|
-
if (op && op !== document.body && op !== document.documentElement) {
|
|
2963
|
-
return vertical ? op.clientHeight : op.clientWidth;
|
|
2964
|
-
}
|
|
2965
|
-
return vertical ? window.innerHeight : window.innerWidth;
|
|
2966
|
-
}
|
|
2967
|
-
installFitObserver() {
|
|
2968
|
-
if (typeof ResizeObserver === "undefined") return;
|
|
2969
|
-
if (!this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"))
|
|
2970
|
-
return;
|
|
2971
|
-
let raf = 0;
|
|
2972
|
-
const schedule = () => {
|
|
2973
|
-
if (raf) return;
|
|
2974
|
-
raf = requestAnimationFrame(() => {
|
|
2975
|
-
raf = 0;
|
|
2976
|
-
if (this.destroyed || this.gesture?.isDragging) return;
|
|
2977
|
-
this.recompute();
|
|
2978
|
-
});
|
|
2979
|
-
};
|
|
2980
|
-
const ro = new ResizeObserver(schedule);
|
|
2981
|
-
ro.observe(this.handle);
|
|
2982
|
-
const scroller = this.scrollContainer;
|
|
2983
|
-
const observed = /* @__PURE__ */ new Set();
|
|
2984
|
-
const slots = /* @__PURE__ */ new Set();
|
|
2985
|
-
const hasSlot = typeof HTMLSlotElement !== "undefined";
|
|
2986
|
-
const onSlotChange = () => resync();
|
|
2987
|
-
const trackSlots = () => {
|
|
2988
|
-
if (!scroller || !hasSlot) return;
|
|
2989
|
-
for (const child of Array.from(scroller.children)) {
|
|
2990
|
-
if (child instanceof HTMLSlotElement && !slots.has(child)) {
|
|
2991
|
-
child.addEventListener("slotchange", onSlotChange);
|
|
2992
|
-
slots.add(child);
|
|
2993
|
-
}
|
|
2994
|
-
}
|
|
2995
|
-
};
|
|
2996
|
-
const resync = () => {
|
|
2997
|
-
trackSlots();
|
|
2998
|
-
const targets = this.contentTargets();
|
|
2999
|
-
for (const el of observed) {
|
|
3000
|
-
if (!targets.includes(el)) {
|
|
3001
|
-
ro.unobserve(el);
|
|
3002
|
-
observed.delete(el);
|
|
3003
|
-
}
|
|
3004
|
-
}
|
|
3005
|
-
for (const el of targets) {
|
|
3006
|
-
if (!observed.has(el)) {
|
|
3007
|
-
ro.observe(el);
|
|
3008
|
-
observed.add(el);
|
|
3009
|
-
}
|
|
3010
|
-
}
|
|
3011
|
-
schedule();
|
|
3012
|
-
};
|
|
3013
|
-
let mo;
|
|
3014
|
-
if (scroller) {
|
|
3015
|
-
resync();
|
|
3016
|
-
if (typeof MutationObserver !== "undefined") {
|
|
3017
|
-
mo = new MutationObserver(resync);
|
|
3018
|
-
mo.observe(scroller, { childList: true });
|
|
3019
|
-
}
|
|
3020
|
-
}
|
|
3021
|
-
this.teardowns.add(() => {
|
|
3022
|
-
ro.disconnect();
|
|
3023
|
-
mo?.disconnect();
|
|
3024
|
-
for (const slot of slots) {
|
|
3025
|
-
slot.removeEventListener("slotchange", onSlotChange);
|
|
3026
|
-
}
|
|
3027
|
-
if (raf) cancelAnimationFrame(raf);
|
|
3028
|
-
});
|
|
3029
|
-
}
|
|
3030
3151
|
destroy() {
|
|
3031
3152
|
this.destroyed = true;
|
|
3032
3153
|
this.opening = false;
|
|
@@ -3044,9 +3165,10 @@ var BottomSheetEngine = class {
|
|
|
3044
3165
|
this.backdrop.style.opacity = "";
|
|
3045
3166
|
this.backdrop.style.pointerEvents = "";
|
|
3046
3167
|
}
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3168
|
+
for (const host of [this.anchorHost, this.scrimParent, this.rootEl]) {
|
|
3169
|
+
if (!host) continue;
|
|
3170
|
+
host.style.removeProperty("--bs-size");
|
|
3171
|
+
host.style.removeProperty("--bs-progress");
|
|
3050
3172
|
}
|
|
3051
3173
|
if (this.screenComponent) {
|
|
3052
3174
|
this.screenComponent.style.opacity = "";
|
|
@@ -3060,6 +3182,7 @@ var BottomSheetEngine = class {
|
|
|
3060
3182
|
}
|
|
3061
3183
|
newCycle() {
|
|
3062
3184
|
this.allowOvershoot = false;
|
|
3185
|
+
this.opening = false;
|
|
3063
3186
|
this.currentAbort.abort();
|
|
3064
3187
|
this.currentAbort = new AbortController();
|
|
3065
3188
|
return this.currentAbort.signal;
|
|
@@ -3115,8 +3238,14 @@ var BottomSheetEngine = class {
|
|
|
3115
3238
|
this.element.setAttribute("aria-labelledby", titled.id);
|
|
3116
3239
|
}
|
|
3117
3240
|
recomputeSnaps() {
|
|
3241
|
+
this.resolveMaxHeightCap();
|
|
3242
|
+
this.snaps.setRaw(this.snapPointsRaw);
|
|
3243
|
+
this.clampToMaxHeight();
|
|
3244
|
+
this.scrim.invalidateOpacityCache();
|
|
3245
|
+
}
|
|
3246
|
+
auditDuplicateSnapIds(points) {
|
|
3118
3247
|
const seen = /* @__PURE__ */ new Set();
|
|
3119
|
-
for (const p of
|
|
3248
|
+
for (const p of points) {
|
|
3120
3249
|
if (seen.has(p.id)) {
|
|
3121
3250
|
console.warn(
|
|
3122
3251
|
`[BottomSheet] duplicate snap id "${p.id}" \u2014 only the first occurrence is reachable.`
|
|
@@ -3124,9 +3253,6 @@ var BottomSheetEngine = class {
|
|
|
3124
3253
|
}
|
|
3125
3254
|
seen.add(p.id);
|
|
3126
3255
|
}
|
|
3127
|
-
this.snaps.setRaw(this.snapPointsRaw);
|
|
3128
|
-
this.clampToMaxHeight();
|
|
3129
|
-
this.scrim.invalidateOpacityCache();
|
|
3130
3256
|
}
|
|
3131
3257
|
getAllowedRange() {
|
|
3132
3258
|
return this.snaps.getAllowedRange();
|
|
@@ -3314,9 +3440,15 @@ var BottomSheetEngine = class {
|
|
|
3314
3440
|
flickVelocity: this.flickVelocity,
|
|
3315
3441
|
dragThreshold: this.dragThreshold
|
|
3316
3442
|
});
|
|
3317
|
-
if (!target)
|
|
3443
|
+
if (!target) {
|
|
3444
|
+
this.clearWillChangeIfIdle();
|
|
3445
|
+
return;
|
|
3446
|
+
}
|
|
3318
3447
|
const previousId = this.activeId;
|
|
3319
|
-
if (target.id === previousId && target.size === this.size)
|
|
3448
|
+
if (target.id === previousId && target.size === this.size) {
|
|
3449
|
+
this.clearWillChangeIfIdle();
|
|
3450
|
+
return;
|
|
3451
|
+
}
|
|
3320
3452
|
if (this.emitBeforeSnap(target, previousId)) {
|
|
3321
3453
|
const restore = this.snaps.findById(previousId);
|
|
3322
3454
|
if (restore) {
|
|
@@ -3339,27 +3471,19 @@ var BottomSheetEngine = class {
|
|
|
3339
3471
|
if (signal.aborted) return;
|
|
3340
3472
|
this.allowOvershoot = false;
|
|
3341
3473
|
this.opening = false;
|
|
3342
|
-
this.
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
this.haptic();
|
|
3350
|
-
if (previousSnapSize === 0 && target.size > 0) {
|
|
3351
|
-
this.emit("open", { id: target.id });
|
|
3352
|
-
this.handleOpen();
|
|
3353
|
-
notifyLinkedSheets(this.linkedSheets, this);
|
|
3354
|
-
this.emit("opened", { id: target.id });
|
|
3355
|
-
}
|
|
3356
|
-
if (target.size === 0) {
|
|
3357
|
-
this.emit("close", void 0);
|
|
3358
|
-
this.handleClose();
|
|
3359
|
-
this.emit("closed", void 0);
|
|
3360
|
-
}
|
|
3474
|
+
this.completeSnap(
|
|
3475
|
+
target.id,
|
|
3476
|
+
target.size,
|
|
3477
|
+
previousSize,
|
|
3478
|
+
previousSnapSize === 0,
|
|
3479
|
+
true
|
|
3480
|
+
);
|
|
3361
3481
|
});
|
|
3362
3482
|
}
|
|
3483
|
+
clearWillChangeIfIdle() {
|
|
3484
|
+
if (this.animation.isAnimating || this.gesture?.isDragging) return;
|
|
3485
|
+
this.element.style.willChange = "";
|
|
3486
|
+
}
|
|
3363
3487
|
haptic() {
|
|
3364
3488
|
if (typeof navigator !== "undefined" && "vibrate" in navigator) {
|
|
3365
3489
|
try {
|
|
@@ -3440,14 +3564,9 @@ var BottomSheetEngine = class {
|
|
|
3440
3564
|
progress: this.computeProgress(this.size)
|
|
3441
3565
|
});
|
|
3442
3566
|
if (target.size > 0 && !this.lifecycle.isInstalled) {
|
|
3443
|
-
this.
|
|
3444
|
-
this.handleOpen();
|
|
3445
|
-
notifyLinkedSheets(this.linkedSheets, this);
|
|
3446
|
-
this.emit("opened", { id: target.id });
|
|
3567
|
+
this.emitOpenSequence(target.id);
|
|
3447
3568
|
} else if (target.size === 0 && this.lifecycle.isInstalled) {
|
|
3448
|
-
this.
|
|
3449
|
-
this.handleClose();
|
|
3450
|
-
this.emit("closed", void 0);
|
|
3569
|
+
this.emitCloseSequence();
|
|
3451
3570
|
}
|
|
3452
3571
|
}
|
|
3453
3572
|
handleClose() {
|
|
@@ -3544,6 +3663,9 @@ function useBottomSheet(opts) {
|
|
|
3544
3663
|
refresh();
|
|
3545
3664
|
optsRef.current.onSnap?.(payload.id);
|
|
3546
3665
|
}),
|
|
3666
|
+
engine.on("before-snap", (payload) => {
|
|
3667
|
+
optsRef.current.onBeforeSnap?.(payload);
|
|
3668
|
+
}),
|
|
3547
3669
|
engine.on("before-close", (payload) => {
|
|
3548
3670
|
optsRef.current.onBeforeClose?.(payload);
|
|
3549
3671
|
}),
|
|
@@ -3574,12 +3696,26 @@ function useBottomSheet(opts) {
|
|
|
3574
3696
|
const allowedKey = (opts.allowed ?? opts.snapPoints.map((p) => p.id)).join(
|
|
3575
3697
|
"\0"
|
|
3576
3698
|
);
|
|
3577
|
-
const
|
|
3699
|
+
const defKey = opts.snapPoints.map((p) => `${p.id}${String(p.size)}`).join("\0");
|
|
3700
|
+
const defApplied = useRef(false);
|
|
3701
|
+
useEffect(() => {
|
|
3702
|
+
if (!defApplied.current) {
|
|
3703
|
+
defApplied.current = true;
|
|
3704
|
+
return;
|
|
3705
|
+
}
|
|
3706
|
+
const engine = engineRef.current;
|
|
3707
|
+
if (!engine) return;
|
|
3708
|
+
const current = optsRef.current;
|
|
3709
|
+
engine.setSnapPoints(
|
|
3710
|
+
current.snapPoints,
|
|
3711
|
+
current.allowed ? Array.from(current.allowed) : void 0
|
|
3712
|
+
);
|
|
3713
|
+
}, [defKey]);
|
|
3578
3714
|
useEffect(() => {
|
|
3579
3715
|
if (!engineRef.current) return;
|
|
3580
3716
|
const ids = opts.allowed ? Array.from(opts.allowed) : opts.snapPoints.map((p) => p.id);
|
|
3581
3717
|
engineRef.current.setAllowed(ids);
|
|
3582
|
-
}, [allowedKey
|
|
3718
|
+
}, [allowedKey]);
|
|
3583
3719
|
useEffect(() => {
|
|
3584
3720
|
if (!engineRef.current) return;
|
|
3585
3721
|
if (opts.backdropColor !== void 0) {
|
|
@@ -3604,6 +3740,21 @@ function useBottomSheet(opts) {
|
|
|
3604
3740
|
engineRef.current.setMaxHeight(opts.maxHeight);
|
|
3605
3741
|
}
|
|
3606
3742
|
}, [opts.maxHeight]);
|
|
3743
|
+
useEffect(() => {
|
|
3744
|
+
if (opts.persistent !== void 0) {
|
|
3745
|
+
engineRef.current?.setPersistent(opts.persistent);
|
|
3746
|
+
}
|
|
3747
|
+
}, [opts.persistent]);
|
|
3748
|
+
useEffect(() => {
|
|
3749
|
+
if (opts.disableClose !== void 0) {
|
|
3750
|
+
engineRef.current?.setDisableClose(opts.disableClose);
|
|
3751
|
+
}
|
|
3752
|
+
}, [opts.disableClose]);
|
|
3753
|
+
useEffect(() => {
|
|
3754
|
+
if (opts.disableDrag !== void 0) {
|
|
3755
|
+
engineRef.current?.setDisableDrag(opts.disableDrag);
|
|
3756
|
+
}
|
|
3757
|
+
}, [opts.disableDrag]);
|
|
3607
3758
|
const subscribe = useCallback((fn) => {
|
|
3608
3759
|
subscribersRef.current.add(fn);
|
|
3609
3760
|
return () => subscribersRef.current.delete(fn);
|
|
@@ -3939,6 +4090,95 @@ var BottomSheet = forwardRef(
|
|
|
3939
4090
|
}
|
|
3940
4091
|
);
|
|
3941
4092
|
|
|
4093
|
+
// src/core/primitives/overlay-transforms.ts
|
|
4094
|
+
var closedTransform = (edge) => CLOSED_TRANSFORM[edge];
|
|
4095
|
+
var closedTransformFor = (edge, animation, peekPx) => {
|
|
4096
|
+
switch (animation) {
|
|
4097
|
+
case "fade":
|
|
4098
|
+
return "translate3d(0, 0, 0)";
|
|
4099
|
+
case "scale":
|
|
4100
|
+
return "translate3d(0, 0, 0) scale(0.94)";
|
|
4101
|
+
case "slide":
|
|
4102
|
+
default:
|
|
4103
|
+
if (peekPx !== void 0 && edge === "bottom") {
|
|
4104
|
+
return `translate3d(0, calc(100% - ${peekPx}px), 0)`;
|
|
4105
|
+
}
|
|
4106
|
+
return closedTransform(edge);
|
|
4107
|
+
}
|
|
4108
|
+
};
|
|
4109
|
+
var openTransformFor = (animation) => animation === "scale" ? "translate3d(0, 0, 0) scale(1)" : "translate3d(0, 0, 0)";
|
|
4110
|
+
|
|
4111
|
+
// src/core/features/overlay-swipe.ts
|
|
4112
|
+
function installOverlaySwipe(deps) {
|
|
4113
|
+
const el = deps.element;
|
|
4114
|
+
const edge = deps.edge;
|
|
4115
|
+
const isVertical = edge === "bottom" || edge === "top";
|
|
4116
|
+
const sign = edge === "bottom" || edge === "right" ? 1 : -1;
|
|
4117
|
+
const SLOP = 8;
|
|
4118
|
+
let startX = 0;
|
|
4119
|
+
let startY = 0;
|
|
4120
|
+
let startT = 0;
|
|
4121
|
+
let tracking = false;
|
|
4122
|
+
let dragging = false;
|
|
4123
|
+
let pointerId = null;
|
|
4124
|
+
const previousTouchAction = el.style.touchAction;
|
|
4125
|
+
el.style.touchAction = isVertical ? "pan-x" : "pan-y";
|
|
4126
|
+
const onDown = (e) => {
|
|
4127
|
+
if (e.button !== void 0 && e.button !== 0) return;
|
|
4128
|
+
pointerId = e.pointerId;
|
|
4129
|
+
startX = e.clientX;
|
|
4130
|
+
startY = e.clientY;
|
|
4131
|
+
startT = performance.now();
|
|
4132
|
+
tracking = true;
|
|
4133
|
+
dragging = false;
|
|
4134
|
+
};
|
|
4135
|
+
const onMove = (e) => {
|
|
4136
|
+
if (!tracking || e.pointerId !== pointerId) return;
|
|
4137
|
+
const delta = isVertical ? e.clientY - startY : e.clientX - startX;
|
|
4138
|
+
if (!dragging) {
|
|
4139
|
+
if (Math.abs(delta) < SLOP) return;
|
|
4140
|
+
dragging = true;
|
|
4141
|
+
el.style.transition = "none";
|
|
4142
|
+
try {
|
|
4143
|
+
el.setPointerCapture(e.pointerId);
|
|
4144
|
+
} catch {
|
|
4145
|
+
}
|
|
4146
|
+
}
|
|
4147
|
+
const offset = Math.max(0, sign * delta);
|
|
4148
|
+
el.style.transform = isVertical ? `translate3d(0, ${sign * offset}px, 0)` : `translate3d(${sign * offset}px, 0, 0)`;
|
|
4149
|
+
};
|
|
4150
|
+
const finish = (e) => {
|
|
4151
|
+
if (!tracking || e.pointerId !== pointerId) return;
|
|
4152
|
+
tracking = false;
|
|
4153
|
+
pointerId = null;
|
|
4154
|
+
if (!dragging) return;
|
|
4155
|
+
dragging = false;
|
|
4156
|
+
const dt = performance.now() - startT || 1;
|
|
4157
|
+
const delta = isVertical ? e.clientY - startY : e.clientX - startX;
|
|
4158
|
+
const offset = Math.max(0, sign * delta);
|
|
4159
|
+
const velocity = sign * delta / dt;
|
|
4160
|
+
const size = isVertical ? el.offsetHeight : el.offsetWidth;
|
|
4161
|
+
const past = offset > size * deps.getThreshold() || velocity > deps.getVelocityThreshold();
|
|
4162
|
+
el.style.transition = deps.getExitTransition();
|
|
4163
|
+
if (past) {
|
|
4164
|
+
deps.close();
|
|
4165
|
+
} else {
|
|
4166
|
+
el.style.transform = deps.getOpenTransform();
|
|
4167
|
+
}
|
|
4168
|
+
};
|
|
4169
|
+
el.addEventListener("pointerdown", onDown);
|
|
4170
|
+
el.addEventListener("pointermove", onMove);
|
|
4171
|
+
el.addEventListener("pointerup", finish);
|
|
4172
|
+
el.addEventListener("pointercancel", finish);
|
|
4173
|
+
return () => {
|
|
4174
|
+
el.style.touchAction = previousTouchAction;
|
|
4175
|
+
el.removeEventListener("pointerdown", onDown);
|
|
4176
|
+
el.removeEventListener("pointermove", onMove);
|
|
4177
|
+
el.removeEventListener("pointerup", finish);
|
|
4178
|
+
el.removeEventListener("pointercancel", finish);
|
|
4179
|
+
};
|
|
4180
|
+
}
|
|
4181
|
+
|
|
3942
4182
|
// src/core/overlay.ts
|
|
3943
4183
|
var OVERLAY_PRESETS = Object.freeze({
|
|
3944
4184
|
sheet: Object.freeze({
|
|
@@ -3970,22 +4210,6 @@ var OVERLAY_PRESETS = Object.freeze({
|
|
|
3970
4210
|
swipeToClose: false
|
|
3971
4211
|
})
|
|
3972
4212
|
});
|
|
3973
|
-
var closedTransform = (edge) => CLOSED_TRANSFORM[edge];
|
|
3974
|
-
var closedTransformFor = (edge, animation, peekPx) => {
|
|
3975
|
-
switch (animation) {
|
|
3976
|
-
case "fade":
|
|
3977
|
-
return "translate3d(0, 0, 0)";
|
|
3978
|
-
case "scale":
|
|
3979
|
-
return "translate3d(0, 0, 0) scale(0.94)";
|
|
3980
|
-
case "slide":
|
|
3981
|
-
default:
|
|
3982
|
-
if (peekPx !== void 0 && edge === "bottom") {
|
|
3983
|
-
return `translate3d(0, calc(100% - ${peekPx}px), 0)`;
|
|
3984
|
-
}
|
|
3985
|
-
return closedTransform(edge);
|
|
3986
|
-
}
|
|
3987
|
-
};
|
|
3988
|
-
var openTransformFor = (animation) => animation === "scale" ? "translate3d(0, 0, 0) scale(1)" : "translate3d(0, 0, 0)";
|
|
3989
4213
|
var OverlayEngine = class {
|
|
3990
4214
|
constructor(opts) {
|
|
3991
4215
|
__publicField(this, "id", nextInstanceId("ovl"));
|
|
@@ -4118,6 +4342,7 @@ var OverlayEngine = class {
|
|
|
4118
4342
|
if (this.backdrop) {
|
|
4119
4343
|
this.backdrop.style.transition = `opacity ${dur}ms ease-out`;
|
|
4120
4344
|
}
|
|
4345
|
+
this.setWillChange(true);
|
|
4121
4346
|
const cycle = ++this.cycleNonce;
|
|
4122
4347
|
return new Promise((resolve) => {
|
|
4123
4348
|
requestAnimationFrame(() => {
|
|
@@ -4140,6 +4365,7 @@ var OverlayEngine = class {
|
|
|
4140
4365
|
this.releaseInteractiveListeners();
|
|
4141
4366
|
this.isOpen_ = false;
|
|
4142
4367
|
this.isAnimating_ = false;
|
|
4368
|
+
this.setWillChange(false);
|
|
4143
4369
|
this.element.style.transform = closedTransformFor(
|
|
4144
4370
|
this.edge,
|
|
4145
4371
|
this.enterAnimation,
|
|
@@ -4170,6 +4396,7 @@ var OverlayEngine = class {
|
|
|
4170
4396
|
).then(() => {
|
|
4171
4397
|
if (this.destroyed || cycle !== this.cycleNonce) return resolve();
|
|
4172
4398
|
this.isAnimating_ = false;
|
|
4399
|
+
this.setWillChange(false);
|
|
4173
4400
|
this.element.setAttribute("data-state", "open");
|
|
4174
4401
|
this.emit("open", void 0);
|
|
4175
4402
|
this.onOpenCb?.();
|
|
@@ -4193,6 +4420,7 @@ var OverlayEngine = class {
|
|
|
4193
4420
|
if (this.backdrop) {
|
|
4194
4421
|
this.backdrop.style.transition = `opacity ${dur}ms ease-in`;
|
|
4195
4422
|
}
|
|
4423
|
+
this.setWillChange(true);
|
|
4196
4424
|
const cycle = ++this.cycleNonce;
|
|
4197
4425
|
return new Promise((resolve) => {
|
|
4198
4426
|
requestAnimationFrame(() => {
|
|
@@ -4218,6 +4446,7 @@ var OverlayEngine = class {
|
|
|
4218
4446
|
).then(() => {
|
|
4219
4447
|
if (this.destroyed || cycle !== this.cycleNonce) return resolve();
|
|
4220
4448
|
this.isAnimating_ = false;
|
|
4449
|
+
this.setWillChange(false);
|
|
4221
4450
|
if (this.peekPx === void 0) {
|
|
4222
4451
|
this.element.setAttribute("hidden", "");
|
|
4223
4452
|
}
|
|
@@ -4240,6 +4469,7 @@ var OverlayEngine = class {
|
|
|
4240
4469
|
this.destroyed = true;
|
|
4241
4470
|
this.cycleNonce++;
|
|
4242
4471
|
this.bus.clear();
|
|
4472
|
+
this.setWillChange(false);
|
|
4243
4473
|
this.releaseInteractiveListeners();
|
|
4244
4474
|
this.releaseStackEntry?.();
|
|
4245
4475
|
this.releaseStackEntry = null;
|
|
@@ -4465,7 +4695,6 @@ var OverlayEngine = class {
|
|
|
4465
4695
|
this.originalNextSibling = null;
|
|
4466
4696
|
}
|
|
4467
4697
|
applyClosedStyles() {
|
|
4468
|
-
this.element.style.willChange = "transform, opacity";
|
|
4469
4698
|
this.element.style.transform = closedTransformFor(
|
|
4470
4699
|
this.edge,
|
|
4471
4700
|
this.enterAnimation,
|
|
@@ -4479,7 +4708,12 @@ var OverlayEngine = class {
|
|
|
4479
4708
|
if (this.backdrop) {
|
|
4480
4709
|
this.backdrop.style.opacity = "0";
|
|
4481
4710
|
this.backdrop.style.pointerEvents = "none";
|
|
4482
|
-
|
|
4711
|
+
}
|
|
4712
|
+
}
|
|
4713
|
+
setWillChange(on) {
|
|
4714
|
+
this.element.style.willChange = on ? "transform, opacity" : "";
|
|
4715
|
+
if (this.backdrop) {
|
|
4716
|
+
this.backdrop.style.willChange = on ? "opacity" : "";
|
|
4483
4717
|
}
|
|
4484
4718
|
}
|
|
4485
4719
|
awaitTransition(cycle, property = "transform") {
|
|
@@ -4565,73 +4799,15 @@ var OverlayEngine = class {
|
|
|
4565
4799
|
this.lifecycle.release();
|
|
4566
4800
|
}
|
|
4567
4801
|
installSwipeToClose() {
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
let dragging = false;
|
|
4578
|
-
let pointerId = null;
|
|
4579
|
-
const previousTouchAction = el.style.touchAction;
|
|
4580
|
-
el.style.touchAction = isVertical ? "pan-x" : "pan-y";
|
|
4581
|
-
const onDown = (e) => {
|
|
4582
|
-
if (e.button !== void 0 && e.button !== 0) return;
|
|
4583
|
-
pointerId = e.pointerId;
|
|
4584
|
-
startX = e.clientX;
|
|
4585
|
-
startY = e.clientY;
|
|
4586
|
-
startT = performance.now();
|
|
4587
|
-
tracking = true;
|
|
4588
|
-
dragging = false;
|
|
4589
|
-
};
|
|
4590
|
-
const onMove = (e) => {
|
|
4591
|
-
if (!tracking || e.pointerId !== pointerId) return;
|
|
4592
|
-
const delta = isVertical ? e.clientY - startY : e.clientX - startX;
|
|
4593
|
-
if (!dragging) {
|
|
4594
|
-
if (Math.abs(delta) < SLOP) return;
|
|
4595
|
-
dragging = true;
|
|
4596
|
-
el.style.transition = "none";
|
|
4597
|
-
try {
|
|
4598
|
-
el.setPointerCapture(e.pointerId);
|
|
4599
|
-
} catch {
|
|
4600
|
-
}
|
|
4601
|
-
}
|
|
4602
|
-
const offset = Math.max(0, sign * delta);
|
|
4603
|
-
el.style.transform = isVertical ? `translate3d(0, ${sign * offset}px, 0)` : `translate3d(${sign * offset}px, 0, 0)`;
|
|
4604
|
-
};
|
|
4605
|
-
const finish = (e) => {
|
|
4606
|
-
if (!tracking || e.pointerId !== pointerId) return;
|
|
4607
|
-
tracking = false;
|
|
4608
|
-
pointerId = null;
|
|
4609
|
-
if (!dragging) return;
|
|
4610
|
-
dragging = false;
|
|
4611
|
-
const dt = performance.now() - startT || 1;
|
|
4612
|
-
const delta = isVertical ? e.clientY - startY : e.clientX - startX;
|
|
4613
|
-
const offset = Math.max(0, sign * delta);
|
|
4614
|
-
const velocity = sign * delta / dt;
|
|
4615
|
-
const size = isVertical ? el.offsetHeight : el.offsetWidth;
|
|
4616
|
-
const past = offset > size * this.swipeThreshold || velocity > this.swipeVelocityThreshold;
|
|
4617
|
-
el.style.transition = `transform ${this.effectiveDuration()}ms ${this.exitEasing}`;
|
|
4618
|
-
if (past) {
|
|
4619
|
-
void this.close("swipe");
|
|
4620
|
-
} else {
|
|
4621
|
-
el.style.transform = openTransformFor(this.enterAnimation);
|
|
4622
|
-
}
|
|
4623
|
-
};
|
|
4624
|
-
el.addEventListener("pointerdown", onDown);
|
|
4625
|
-
el.addEventListener("pointermove", onMove);
|
|
4626
|
-
el.addEventListener("pointerup", finish);
|
|
4627
|
-
el.addEventListener("pointercancel", finish);
|
|
4628
|
-
return () => {
|
|
4629
|
-
el.style.touchAction = previousTouchAction;
|
|
4630
|
-
el.removeEventListener("pointerdown", onDown);
|
|
4631
|
-
el.removeEventListener("pointermove", onMove);
|
|
4632
|
-
el.removeEventListener("pointerup", finish);
|
|
4633
|
-
el.removeEventListener("pointercancel", finish);
|
|
4634
|
-
};
|
|
4802
|
+
return installOverlaySwipe({
|
|
4803
|
+
element: this.element,
|
|
4804
|
+
edge: this.edge,
|
|
4805
|
+
getThreshold: () => this.swipeThreshold,
|
|
4806
|
+
getVelocityThreshold: () => this.swipeVelocityThreshold,
|
|
4807
|
+
getExitTransition: () => `transform ${this.effectiveDuration()}ms ${this.exitEasing}`,
|
|
4808
|
+
getOpenTransform: () => openTransformFor(this.enterAnimation),
|
|
4809
|
+
close: () => void this.close("swipe")
|
|
4810
|
+
});
|
|
4635
4811
|
}
|
|
4636
4812
|
registerInStack() {
|
|
4637
4813
|
this.releaseStackEntry = sheetStack.push({
|