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