@surdeddd/bottom-sheet 0.10.0 → 0.12.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.
Files changed (42) hide show
  1. package/README.md +52 -35
  2. package/dist/{BottomSheetEngine-DzsIwD28.d.cts → BottomSheetEngine-D6oiEfZ4.d.cts} +1 -0
  3. package/dist/{BottomSheetEngine-DRjCU73e.d.ts → BottomSheetEngine-Dhy0X_e9.d.ts} +1 -0
  4. package/dist/element.cjs +250 -136
  5. package/dist/element.d.cts +1 -1
  6. package/dist/element.d.ts +1 -1
  7. package/dist/element.iife.global.js +2 -2
  8. package/dist/element.js +250 -136
  9. package/dist/index.cjs +257 -164
  10. package/dist/index.d.cts +2 -2
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +257 -164
  13. package/dist/integrations/formik.d.cts +1 -1
  14. package/dist/integrations/formik.d.ts +1 -1
  15. package/dist/integrations/react-hook-form.d.cts +1 -1
  16. package/dist/integrations/react-hook-form.d.ts +1 -1
  17. package/dist/overlay.cjs +161 -33
  18. package/dist/overlay.d.cts +1 -3
  19. package/dist/overlay.d.ts +1 -3
  20. package/dist/overlay.js +161 -33
  21. package/dist/preact.d.cts +1 -1
  22. package/dist/preact.d.ts +1 -1
  23. package/dist/qwik.cjs +240 -131
  24. package/dist/qwik.d.cts +2 -2
  25. package/dist/qwik.d.ts +2 -2
  26. package/dist/qwik.js +240 -131
  27. package/dist/react.cjs +257 -164
  28. package/dist/react.d.cts +2 -2
  29. package/dist/react.d.ts +2 -2
  30. package/dist/react.js +257 -164
  31. package/dist/solid.cjs +240 -131
  32. package/dist/solid.d.cts +1 -0
  33. package/dist/solid.d.ts +1 -0
  34. package/dist/solid.js +240 -131
  35. package/dist/solid.source.jsx +240 -131
  36. package/dist/svelte-core.cjs +240 -131
  37. package/dist/svelte-core.js +240 -131
  38. package/dist/svelte.cjs +252 -143
  39. package/dist/svelte.js +252 -143
  40. package/dist/vue.cjs +240 -131
  41. package/dist/vue.js +240 -131
  42. package/package.json +10 -8
@@ -444,46 +444,202 @@ function notifyLinkedSheets(sheets, self) {
444
444
  }
445
445
  }
446
446
 
447
- // src/core/features/route.ts
448
- var closers = [];
449
- var handlerInstalled = false;
447
+ // src/core/features/history-coordinator.ts
448
+ var entries = [];
449
+ var subscribers = /* @__PURE__ */ new Set();
450
450
  var suppress = 0;
451
- var ensureHandler = () => {
452
- if (handlerInstalled || typeof window === "undefined") return;
453
- handlerInstalled = true;
454
- window.addEventListener("popstate", () => {
455
- if (suppress > 0) {
456
- suppress -= 1;
457
- return;
451
+ var internalDepth = 0;
452
+ var pendingRebrand = null;
453
+ var listenerInstalled = false;
454
+ var patchInstalled = false;
455
+ var origPushState = null;
456
+ var origReplaceState = null;
457
+ var patchedPushState = null;
458
+ var patchedReplaceState = null;
459
+ var hasWindow = () => typeof window !== "undefined";
460
+ var hasHistory = () => typeof history !== "undefined";
461
+ var brandMarker = (surface) => ({
462
+ ...surface.markerState(),
463
+ __bs: true
464
+ });
465
+ var runInternal = (fn) => {
466
+ internalDepth += 1;
467
+ try {
468
+ fn();
469
+ } finally {
470
+ internalDepth -= 1;
471
+ }
472
+ };
473
+ var notifyRouteChange = () => {
474
+ const snapshot = Array.from(subscribers);
475
+ for (const fn of snapshot) fn();
476
+ };
477
+ var ensureListener = () => {
478
+ if (listenerInstalled || !hasWindow()) return;
479
+ window.addEventListener("popstate", onPopState);
480
+ listenerInstalled = true;
481
+ };
482
+ var maybeTeardownListener = () => {
483
+ if (!listenerInstalled) return;
484
+ if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
485
+ if (hasWindow()) window.removeEventListener("popstate", onPopState);
486
+ listenerInstalled = false;
487
+ };
488
+ var installPatch = () => {
489
+ if (patchInstalled || !hasHistory()) return;
490
+ origPushState = history.pushState;
491
+ origReplaceState = history.replaceState;
492
+ patchedPushState = function(...args) {
493
+ origPushState.apply(this, args);
494
+ if (internalDepth === 0) notifyRouteChange();
495
+ };
496
+ patchedReplaceState = function(...args) {
497
+ origReplaceState.apply(this, args);
498
+ if (internalDepth === 0) notifyRouteChange();
499
+ };
500
+ history.pushState = patchedPushState;
501
+ history.replaceState = patchedReplaceState;
502
+ patchInstalled = true;
503
+ };
504
+ var removePatch = () => {
505
+ if (!patchInstalled) return;
506
+ if (history.pushState === patchedPushState && origPushState) {
507
+ history.pushState = origPushState;
508
+ }
509
+ if (history.replaceState === patchedReplaceState && origReplaceState) {
510
+ history.replaceState = origReplaceState;
511
+ }
512
+ origPushState = null;
513
+ origReplaceState = null;
514
+ patchedPushState = null;
515
+ patchedReplaceState = null;
516
+ patchInstalled = false;
517
+ };
518
+ function onPopState() {
519
+ if (suppress > 0) {
520
+ suppress -= 1;
521
+ const rebrand = pendingRebrand;
522
+ pendingRebrand = null;
523
+ if (rebrand) rebrand();
524
+ maybeTeardownListener();
525
+ return;
526
+ }
527
+ if (entries.length === 0) {
528
+ notifyRouteChange();
529
+ maybeTeardownListener();
530
+ return;
531
+ }
532
+ let target = null;
533
+ let targetIdx = -1;
534
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
535
+ const entry = entries[i];
536
+ if (!entry.surface.isOpen()) continue;
537
+ if (!target) {
538
+ target = entry;
539
+ targetIdx = i;
458
540
  }
459
- let target = null;
460
- for (let i = closers.length - 1; i >= 0; i -= 1) {
461
- const c = closers[i];
462
- if (!c.isOpen()) continue;
463
- if (!target) target = c;
464
- if (c.isTop()) {
465
- target = c;
466
- break;
467
- }
541
+ if (entry.surface.isTop()) {
542
+ target = entry;
543
+ targetIdx = i;
544
+ break;
468
545
  }
469
- if (!target) return;
470
- target.consumed = true;
471
- const idx = closers.indexOf(target);
472
- if (idx !== -1) closers.splice(idx, 1);
473
- const settled = target;
474
- void Promise.resolve(settled.close()).then(() => {
475
- if (settled.isOpen()) settled.restore();
476
- });
546
+ }
547
+ if (!target) {
548
+ const removed = entries.pop();
549
+ if (removed) removed.live = false;
550
+ maybeTeardownListener();
551
+ return;
552
+ }
553
+ target.live = false;
554
+ entries.splice(targetIdx, 1);
555
+ const settled = target;
556
+ void Promise.resolve(settled.surface.close()).then(() => {
557
+ if (settled.surface.isOpen()) restore(settled);
477
558
  });
478
- };
479
- var programmaticBack = () => {
480
- suppress += 1;
481
- try {
482
- history.back();
483
- } catch {
484
- suppress = Math.max(0, suppress - 1);
559
+ maybeTeardownListener();
560
+ }
561
+ function restore(entry) {
562
+ if (!hasWindow() || !hasHistory()) return;
563
+ entry.live = true;
564
+ runInternal(() => {
565
+ try {
566
+ history.pushState(brandMarker(entry.surface), "", entry.surface.url);
567
+ } catch {
568
+ entry.live = false;
569
+ }
570
+ });
571
+ if (entry.live) {
572
+ entries.push(entry);
573
+ ensureListener();
485
574
  }
486
- };
575
+ }
576
+ function pushBackMarker(surface) {
577
+ const entry = { surface, priorUrl: void 0, live: false };
578
+ if (!hasWindow() || !hasHistory()) {
579
+ return entry;
580
+ }
581
+ entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
582
+ runInternal(() => {
583
+ try {
584
+ history.pushState(brandMarker(surface), "", surface.url);
585
+ entry.live = true;
586
+ } catch {
587
+ entry.live = false;
588
+ }
589
+ });
590
+ if (entry.live) {
591
+ entries.push(entry);
592
+ ensureListener();
593
+ }
594
+ return entry;
595
+ }
596
+ function popBackMarker(handle) {
597
+ if (!hasWindow() || !hasHistory()) return;
598
+ const entry = handle;
599
+ const idx = entries.indexOf(entry);
600
+ if (idx === -1 || !entry.live) return;
601
+ const last = entries.length - 1;
602
+ entry.live = false;
603
+ entries.splice(idx, 1);
604
+ if (idx !== last) {
605
+ const rebrandSurface = entries[entries.length - 1].surface;
606
+ const rebrandUrl = entry.priorUrl;
607
+ pendingRebrand = () => {
608
+ runInternal(() => {
609
+ history.replaceState(
610
+ brandMarker(rebrandSurface),
611
+ "",
612
+ rebrandUrl !== void 0 ? rebrandUrl : location.href
613
+ );
614
+ });
615
+ };
616
+ }
617
+ suppress += 1;
618
+ runInternal(() => {
619
+ try {
620
+ history.back();
621
+ } catch {
622
+ suppress = Math.max(0, suppress - 1);
623
+ pendingRebrand = null;
624
+ }
625
+ });
626
+ maybeTeardownListener();
627
+ }
628
+ function subscribeRouteChange(fn) {
629
+ if (!hasWindow() || !hasHistory()) return () => {
630
+ };
631
+ subscribers.add(fn);
632
+ if (subscribers.size === 1) installPatch();
633
+ ensureListener();
634
+ return () => {
635
+ if (!subscribers.has(fn)) return;
636
+ subscribers.delete(fn);
637
+ if (subscribers.size === 0) removePatch();
638
+ maybeTeardownListener();
639
+ };
640
+ }
641
+
642
+ // src/core/features/route.ts
487
643
  function installRoute(deps) {
488
644
  if (typeof window === "undefined") {
489
645
  return () => {
@@ -493,92 +649,39 @@ function installRoute(deps) {
493
649
  return () => {
494
650
  };
495
651
  }
496
- let pushed = false;
497
- let closer = null;
498
- const teardownEntry = () => {
499
- if (closer) {
500
- const idx = closers.indexOf(closer);
501
- if (idx !== -1) closers.splice(idx, 1);
502
- }
503
- const wasConsumed = closer?.consumed ?? false;
504
- closer = null;
505
- if (pushed && !wasConsumed) {
506
- pushed = false;
507
- programmaticBack();
508
- } else {
509
- pushed = false;
510
- }
511
- };
512
- const pushEntry = () => {
513
- try {
514
- if (deps.routedTo !== void 0) {
515
- history.pushState({ __bsRouted: deps.sheetId }, "", deps.routedTo);
516
- } else {
517
- history.pushState({ __bsSheet: deps.sheetId }, "");
518
- }
519
- pushed = true;
520
- } catch {
521
- pushed = false;
522
- }
523
- };
652
+ let handle = null;
524
653
  const onOpen = () => {
525
- if (closer) return;
526
- const self = {
654
+ if (handle) return;
655
+ handle = pushBackMarker({
527
656
  isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
528
- isTop: () => deps.isTopSheet(),
529
- close: () => deps.close(),
530
- restore: () => {
531
- if (deps.isDestroyed() || closer !== self) return;
532
- self.consumed = false;
533
- if (!closers.includes(self)) closers.push(self);
534
- pushEntry();
535
- },
536
- consumed: false
537
- };
538
- closer = self;
539
- ensureHandler();
540
- closers.push(self);
541
- pushEntry();
657
+ isTop: deps.isTopSheet,
658
+ close: deps.close,
659
+ markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
660
+ url: deps.routedTo
661
+ });
662
+ };
663
+ const onClose = () => {
664
+ if (!handle) return;
665
+ popBackMarker(handle);
666
+ handle = null;
542
667
  };
543
668
  const unsubscribeOpen = deps.on("open", onOpen);
544
- const unsubscribeClose = deps.on("close", teardownEntry);
669
+ const unsubscribeClose = deps.on("close", onClose);
545
670
  if (deps.getSize() > 0) onOpen();
546
671
  return () => {
547
672
  unsubscribeOpen();
548
673
  unsubscribeClose();
549
- teardownEntry();
674
+ if (handle) {
675
+ popBackMarker(handle);
676
+ handle = null;
677
+ }
550
678
  };
551
679
  }
552
680
  function installRouteChange(deps) {
553
- if (typeof window === "undefined" || typeof history === "undefined") {
554
- return () => {
555
- };
556
- }
557
- const onChange = () => {
681
+ return subscribeRouteChange(() => {
558
682
  if (deps.isDestroyed() || deps.getSize() <= 0) return;
559
683
  void deps.close();
560
- };
561
- const wrap = (key) => {
562
- const original = history[key];
563
- const patched = function(...args) {
564
- original.apply(this, args);
565
- onChange();
566
- };
567
- history[key] = patched;
568
- return () => {
569
- if (history[key] === patched) {
570
- history[key] = original;
571
- }
572
- };
573
- };
574
- window.addEventListener("popstate", onChange);
575
- const restorePush = wrap("pushState");
576
- const restoreReplace = wrap("replaceState");
577
- return () => {
578
- window.removeEventListener("popstate", onChange);
579
- restorePush();
580
- restoreReplace();
581
- };
684
+ });
582
685
  }
583
686
 
584
687
  // src/core/features/content-swipe.ts
@@ -848,11 +951,15 @@ function createMaxHeightController(deps) {
848
951
 
849
952
  // src/core/features/fit-measurement.ts
850
953
  var measureSheetNatural = (element, content, vertical) => {
851
- if (!content) {
852
- return vertical ? element.offsetHeight : element.offsetWidth;
853
- }
854
954
  const axis = vertical ? "height" : "width";
855
955
  const sheetStyle = element.style;
956
+ if (!content) {
957
+ const prev = sheetStyle[axis];
958
+ sheetStyle[axis] = "auto";
959
+ const poked2 = vertical ? element.offsetHeight : element.offsetWidth;
960
+ sheetStyle[axis] = prev;
961
+ return poked2;
962
+ }
856
963
  const cs = content.style;
857
964
  const prevSheet = sheetStyle[axis];
858
965
  const prevFlex = cs.flex;
@@ -2430,7 +2537,7 @@ var matchesRange = (def, progress) => {
2430
2537
  };
2431
2538
  function installScrimStages(deps, opts) {
2432
2539
  const doc = deps.host.ownerDocument;
2433
- const entries = opts.stages.map((def) => {
2540
+ const entries2 = opts.stages.map((def) => {
2434
2541
  const wrapper = doc.createElement("div");
2435
2542
  wrapper.className = "bs-scrim-stage";
2436
2543
  const ws = wrapper.style;
@@ -2451,9 +2558,9 @@ function installScrimStages(deps, opts) {
2451
2558
  const resolveActive = () => {
2452
2559
  const state = deps.getState();
2453
2560
  if (state.size === 0) {
2454
- return entries.find((e) => matchesId(e.def, state.activeId)) ?? null;
2561
+ return entries2.find((e) => matchesId(e.def, state.activeId)) ?? null;
2455
2562
  }
2456
- return entries.find((e) => matchesId(e.def, state.activeId)) ?? entries.find((e) => matchesRange(e.def, state.progress)) ?? null;
2563
+ return entries2.find((e) => matchesId(e.def, state.activeId)) ?? entries2.find((e) => matchesRange(e.def, state.progress)) ?? null;
2457
2564
  };
2458
2565
  const hide = (entry, animate) => {
2459
2566
  entry.inFlight?.cancel();
@@ -2502,13 +2609,13 @@ function installScrimStages(deps, opts) {
2502
2609
  deps.on("open", () => update(true)),
2503
2610
  deps.on("close", () => update(true))
2504
2611
  ];
2505
- if (entries.some((e) => e.def.forRange)) {
2612
+ if (entries2.some((e) => e.def.forRange)) {
2506
2613
  offs.push(deps.on("progress", () => update(true)));
2507
2614
  }
2508
2615
  update(false);
2509
2616
  return () => {
2510
2617
  offs.forEach((off) => off());
2511
- for (const entry of entries) {
2618
+ for (const entry of entries2) {
2512
2619
  entry.inFlight?.cancel();
2513
2620
  entry.inFlight = null;
2514
2621
  if (entry.wrapper.parentNode) {
@@ -2765,17 +2872,12 @@ var BottomSheetEngine = class {
2765
2872
  this.attach();
2766
2873
  this.registerInStack();
2767
2874
  if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
2768
- const io = new IntersectionObserver((entries) => {
2769
- for (const entry of entries) {
2875
+ const io = new IntersectionObserver((entries2) => {
2876
+ for (const entry of entries2) {
2770
2877
  if (!entry.isIntersecting) continue;
2771
2878
  if (this.destroyed) return;
2772
2879
  this.snaps.recompute();
2773
- const current = this.snaps.findById(this.activeId);
2774
- if (current) {
2775
- this.size = current.size;
2776
- this.applySize(this.size);
2777
- this.updateAriaSlider();
2778
- }
2880
+ this.healActiveSnap();
2779
2881
  io.disconnect();
2780
2882
  return;
2781
2883
  }
@@ -2939,6 +3041,8 @@ var BottomSheetEngine = class {
2939
3041
  const vt = document.startViewTransition(() => {
2940
3042
  this.applySize(target.size);
2941
3043
  });
3044
+ vt.ready?.catch(() => {
3045
+ });
2942
3046
  this.currentViewTransition = vt;
2943
3047
  try {
2944
3048
  await vt.finished;
@@ -3190,11 +3294,16 @@ var BottomSheetEngine = class {
3190
3294
  this.maxHeight.clampTo();
3191
3295
  this.scrim.invalidateOpacityCache();
3192
3296
  if (this.gesture?.isDragging) return;
3297
+ this.healActiveSnap();
3298
+ }
3299
+ healActiveSnap() {
3193
3300
  const current = this.snaps.findById(this.activeId);
3194
- if (current) {
3195
- this.size = current.size;
3196
- this.applySize(this.size);
3197
- this.updateAriaSlider();
3301
+ if (!current) return;
3302
+ this.size = current.size;
3303
+ this.applySize(this.size);
3304
+ this.updateAriaSlider();
3305
+ if (this.size > 0 && !this.lifecycle.isInstalled && !this.opening && !this.animation.isAnimating) {
3306
+ this.emitOpenSequence(this.activeId);
3198
3307
  }
3199
3308
  }
3200
3309
  destroy() {
@@ -3483,9 +3592,9 @@ var BottomSheetEngine = class {
3483
3592
  return;
3484
3593
  }
3485
3594
  if (this.emitBeforeSnap(target, previousId)) {
3486
- const restore = this.snaps.findById(previousId);
3487
- if (restore) {
3488
- void this.animation.animateTo(restore.size, 0);
3595
+ const restore2 = this.snaps.findById(previousId);
3596
+ if (restore2) {
3597
+ void this.animation.animateTo(restore2.size, 0);
3489
3598
  }
3490
3599
  return;
3491
3600
  }