@surdeddd/bottom-sheet 0.10.0 → 0.11.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/element.js CHANGED
@@ -502,6 +502,202 @@ var init_linked_sheets = __esm({
502
502
  }
503
503
  });
504
504
 
505
+ // src/core/features/history-coordinator.ts
506
+ function onPopState() {
507
+ if (suppress > 0) {
508
+ suppress -= 1;
509
+ const rebrand = pendingRebrand;
510
+ pendingRebrand = null;
511
+ if (rebrand) rebrand();
512
+ maybeTeardownListener();
513
+ return;
514
+ }
515
+ if (entries.length === 0) {
516
+ notifyRouteChange();
517
+ maybeTeardownListener();
518
+ return;
519
+ }
520
+ let target = null;
521
+ let targetIdx = -1;
522
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
523
+ const entry = entries[i];
524
+ if (!entry.surface.isOpen()) continue;
525
+ if (!target) {
526
+ target = entry;
527
+ targetIdx = i;
528
+ }
529
+ if (entry.surface.isTop()) {
530
+ target = entry;
531
+ targetIdx = i;
532
+ break;
533
+ }
534
+ }
535
+ if (!target) {
536
+ const removed = entries.pop();
537
+ if (removed) removed.live = false;
538
+ maybeTeardownListener();
539
+ return;
540
+ }
541
+ target.live = false;
542
+ entries.splice(targetIdx, 1);
543
+ const settled = target;
544
+ void Promise.resolve(settled.surface.close()).then(() => {
545
+ if (settled.surface.isOpen()) restore(settled);
546
+ });
547
+ maybeTeardownListener();
548
+ }
549
+ function restore(entry) {
550
+ if (!hasWindow() || !hasHistory()) return;
551
+ entry.live = true;
552
+ runInternal(() => {
553
+ try {
554
+ history.pushState(entry.surface.markerState(), "", entry.surface.url);
555
+ } catch {
556
+ entry.live = false;
557
+ }
558
+ });
559
+ if (entry.live) {
560
+ entries.push(entry);
561
+ ensureListener();
562
+ }
563
+ }
564
+ function pushBackMarker(surface) {
565
+ const entry = { surface, priorUrl: void 0, live: false };
566
+ if (!hasWindow() || !hasHistory()) {
567
+ return entry;
568
+ }
569
+ entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
570
+ runInternal(() => {
571
+ try {
572
+ history.pushState(surface.markerState(), "", surface.url);
573
+ entry.live = true;
574
+ } catch {
575
+ entry.live = false;
576
+ }
577
+ });
578
+ if (entry.live) {
579
+ entries.push(entry);
580
+ ensureListener();
581
+ }
582
+ return entry;
583
+ }
584
+ function popBackMarker(handle) {
585
+ if (!hasWindow() || !hasHistory()) return;
586
+ const entry = handle;
587
+ const idx = entries.indexOf(entry);
588
+ if (idx === -1 || !entry.live) return;
589
+ const last = entries.length - 1;
590
+ entry.live = false;
591
+ entries.splice(idx, 1);
592
+ if (idx !== last) {
593
+ const rebrandSurface = entries[entries.length - 1].surface;
594
+ const rebrandUrl = entry.priorUrl;
595
+ pendingRebrand = () => {
596
+ runInternal(() => {
597
+ history.replaceState(
598
+ rebrandSurface.markerState(),
599
+ "",
600
+ rebrandUrl !== void 0 ? rebrandUrl : location.href
601
+ );
602
+ });
603
+ };
604
+ }
605
+ suppress += 1;
606
+ runInternal(() => {
607
+ try {
608
+ history.back();
609
+ } catch {
610
+ suppress = Math.max(0, suppress - 1);
611
+ pendingRebrand = null;
612
+ }
613
+ });
614
+ maybeTeardownListener();
615
+ }
616
+ function subscribeRouteChange(fn) {
617
+ if (!hasWindow() || !hasHistory()) return () => {
618
+ };
619
+ subscribers.add(fn);
620
+ if (subscribers.size === 1) installPatch();
621
+ ensureListener();
622
+ return () => {
623
+ if (!subscribers.has(fn)) return;
624
+ subscribers.delete(fn);
625
+ if (subscribers.size === 0) removePatch();
626
+ maybeTeardownListener();
627
+ };
628
+ }
629
+ var entries, subscribers, suppress, internalDepth, pendingRebrand, listenerInstalled, patchInstalled, origPushState, origReplaceState, patchedPushState, patchedReplaceState, hasWindow, hasHistory, runInternal, notifyRouteChange, ensureListener, maybeTeardownListener, installPatch, removePatch;
630
+ var init_history_coordinator = __esm({
631
+ "src/core/features/history-coordinator.ts"() {
632
+ entries = [];
633
+ subscribers = /* @__PURE__ */ new Set();
634
+ suppress = 0;
635
+ internalDepth = 0;
636
+ pendingRebrand = null;
637
+ listenerInstalled = false;
638
+ patchInstalled = false;
639
+ origPushState = null;
640
+ origReplaceState = null;
641
+ patchedPushState = null;
642
+ patchedReplaceState = null;
643
+ hasWindow = () => typeof window !== "undefined";
644
+ hasHistory = () => typeof history !== "undefined";
645
+ runInternal = (fn) => {
646
+ internalDepth += 1;
647
+ try {
648
+ fn();
649
+ } finally {
650
+ internalDepth -= 1;
651
+ }
652
+ };
653
+ notifyRouteChange = () => {
654
+ const snapshot = Array.from(subscribers);
655
+ for (const fn of snapshot) fn();
656
+ };
657
+ ensureListener = () => {
658
+ if (listenerInstalled || !hasWindow()) return;
659
+ window.addEventListener("popstate", onPopState);
660
+ listenerInstalled = true;
661
+ };
662
+ maybeTeardownListener = () => {
663
+ if (!listenerInstalled) return;
664
+ if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
665
+ if (hasWindow()) window.removeEventListener("popstate", onPopState);
666
+ listenerInstalled = false;
667
+ };
668
+ installPatch = () => {
669
+ if (patchInstalled || !hasHistory()) return;
670
+ origPushState = history.pushState;
671
+ origReplaceState = history.replaceState;
672
+ patchedPushState = function(...args) {
673
+ origPushState.apply(this, args);
674
+ if (internalDepth === 0) notifyRouteChange();
675
+ };
676
+ patchedReplaceState = function(...args) {
677
+ origReplaceState.apply(this, args);
678
+ if (internalDepth === 0) notifyRouteChange();
679
+ };
680
+ history.pushState = patchedPushState;
681
+ history.replaceState = patchedReplaceState;
682
+ patchInstalled = true;
683
+ };
684
+ removePatch = () => {
685
+ if (!patchInstalled) return;
686
+ if (history.pushState === patchedPushState && origPushState) {
687
+ history.pushState = origPushState;
688
+ }
689
+ if (history.replaceState === patchedReplaceState && origReplaceState) {
690
+ history.replaceState = origReplaceState;
691
+ }
692
+ origPushState = null;
693
+ origReplaceState = null;
694
+ patchedPushState = null;
695
+ patchedReplaceState = null;
696
+ patchInstalled = false;
697
+ };
698
+ }
699
+ });
700
+
505
701
  // src/core/features/route.ts
506
702
  function installRoute(deps) {
507
703
  if (typeof window === "undefined") {
@@ -512,135 +708,43 @@ function installRoute(deps) {
512
708
  return () => {
513
709
  };
514
710
  }
515
- let pushed = false;
516
- let closer = null;
517
- const teardownEntry = () => {
518
- if (closer) {
519
- const idx = closers.indexOf(closer);
520
- if (idx !== -1) closers.splice(idx, 1);
521
- }
522
- const wasConsumed = closer?.consumed ?? false;
523
- closer = null;
524
- if (pushed && !wasConsumed) {
525
- pushed = false;
526
- programmaticBack();
527
- } else {
528
- pushed = false;
529
- }
530
- };
531
- const pushEntry = () => {
532
- try {
533
- if (deps.routedTo !== void 0) {
534
- history.pushState({ __bsRouted: deps.sheetId }, "", deps.routedTo);
535
- } else {
536
- history.pushState({ __bsSheet: deps.sheetId }, "");
537
- }
538
- pushed = true;
539
- } catch {
540
- pushed = false;
541
- }
542
- };
711
+ let handle = null;
543
712
  const onOpen = () => {
544
- if (closer) return;
545
- const self = {
713
+ if (handle) return;
714
+ handle = pushBackMarker({
546
715
  isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
547
- isTop: () => deps.isTopSheet(),
548
- close: () => deps.close(),
549
- restore: () => {
550
- if (deps.isDestroyed() || closer !== self) return;
551
- self.consumed = false;
552
- if (!closers.includes(self)) closers.push(self);
553
- pushEntry();
554
- },
555
- consumed: false
556
- };
557
- closer = self;
558
- ensureHandler();
559
- closers.push(self);
560
- pushEntry();
716
+ isTop: deps.isTopSheet,
717
+ close: deps.close,
718
+ markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
719
+ url: deps.routedTo
720
+ });
721
+ };
722
+ const onClose = () => {
723
+ if (!handle) return;
724
+ popBackMarker(handle);
725
+ handle = null;
561
726
  };
562
727
  const unsubscribeOpen = deps.on("open", onOpen);
563
- const unsubscribeClose = deps.on("close", teardownEntry);
728
+ const unsubscribeClose = deps.on("close", onClose);
564
729
  if (deps.getSize() > 0) onOpen();
565
730
  return () => {
566
731
  unsubscribeOpen();
567
732
  unsubscribeClose();
568
- teardownEntry();
733
+ if (handle) {
734
+ popBackMarker(handle);
735
+ handle = null;
736
+ }
569
737
  };
570
738
  }
571
739
  function installRouteChange(deps) {
572
- if (typeof window === "undefined" || typeof history === "undefined") {
573
- return () => {
574
- };
575
- }
576
- const onChange = () => {
740
+ return subscribeRouteChange(() => {
577
741
  if (deps.isDestroyed() || deps.getSize() <= 0) return;
578
742
  void deps.close();
579
- };
580
- const wrap = (key) => {
581
- const original = history[key];
582
- const patched = function(...args) {
583
- original.apply(this, args);
584
- onChange();
585
- };
586
- history[key] = patched;
587
- return () => {
588
- if (history[key] === patched) {
589
- history[key] = original;
590
- }
591
- };
592
- };
593
- window.addEventListener("popstate", onChange);
594
- const restorePush = wrap("pushState");
595
- const restoreReplace = wrap("replaceState");
596
- return () => {
597
- window.removeEventListener("popstate", onChange);
598
- restorePush();
599
- restoreReplace();
600
- };
743
+ });
601
744
  }
602
- var closers, handlerInstalled, suppress, ensureHandler, programmaticBack;
603
745
  var init_route = __esm({
604
746
  "src/core/features/route.ts"() {
605
- closers = [];
606
- handlerInstalled = false;
607
- suppress = 0;
608
- ensureHandler = () => {
609
- if (handlerInstalled || typeof window === "undefined") return;
610
- handlerInstalled = true;
611
- window.addEventListener("popstate", () => {
612
- if (suppress > 0) {
613
- suppress -= 1;
614
- return;
615
- }
616
- let target = null;
617
- for (let i = closers.length - 1; i >= 0; i -= 1) {
618
- const c = closers[i];
619
- if (!c.isOpen()) continue;
620
- if (!target) target = c;
621
- if (c.isTop()) {
622
- target = c;
623
- break;
624
- }
625
- }
626
- if (!target) return;
627
- target.consumed = true;
628
- const idx = closers.indexOf(target);
629
- if (idx !== -1) closers.splice(idx, 1);
630
- const settled = target;
631
- void Promise.resolve(settled.close()).then(() => {
632
- if (settled.isOpen()) settled.restore();
633
- });
634
- });
635
- };
636
- programmaticBack = () => {
637
- suppress += 1;
638
- try {
639
- history.back();
640
- } catch {
641
- suppress = Math.max(0, suppress - 1);
642
- }
643
- };
747
+ init_history_coordinator();
644
748
  }
645
749
  });
646
750
 
@@ -2638,7 +2742,7 @@ var init_sheet_anchors = __esm({
2638
2742
  // src/core/features/scrim-stages.ts
2639
2743
  function installScrimStages(deps, opts) {
2640
2744
  const doc = deps.host.ownerDocument;
2641
- const entries = opts.stages.map((def) => {
2745
+ const entries2 = opts.stages.map((def) => {
2642
2746
  const wrapper = doc.createElement("div");
2643
2747
  wrapper.className = "bs-scrim-stage";
2644
2748
  const ws = wrapper.style;
@@ -2659,9 +2763,9 @@ function installScrimStages(deps, opts) {
2659
2763
  const resolveActive = () => {
2660
2764
  const state = deps.getState();
2661
2765
  if (state.size === 0) {
2662
- return entries.find((e) => matchesId(e.def, state.activeId)) ?? null;
2766
+ return entries2.find((e) => matchesId(e.def, state.activeId)) ?? null;
2663
2767
  }
2664
- return entries.find((e) => matchesId(e.def, state.activeId)) ?? entries.find((e) => matchesRange(e.def, state.progress)) ?? null;
2768
+ return entries2.find((e) => matchesId(e.def, state.activeId)) ?? entries2.find((e) => matchesRange(e.def, state.progress)) ?? null;
2665
2769
  };
2666
2770
  const hide = (entry, animate) => {
2667
2771
  entry.inFlight?.cancel();
@@ -2710,13 +2814,13 @@ function installScrimStages(deps, opts) {
2710
2814
  deps.on("open", () => update(true)),
2711
2815
  deps.on("close", () => update(true))
2712
2816
  ];
2713
- if (entries.some((e) => e.def.forRange)) {
2817
+ if (entries2.some((e) => e.def.forRange)) {
2714
2818
  offs.push(deps.on("progress", () => update(true)));
2715
2819
  }
2716
2820
  update(false);
2717
2821
  return () => {
2718
2822
  offs.forEach((off) => off());
2719
- for (const entry of entries) {
2823
+ for (const entry of entries2) {
2720
2824
  entry.inFlight?.cancel();
2721
2825
  entry.inFlight = null;
2722
2826
  if (entry.wrapper.parentNode) {
@@ -3036,8 +3140,8 @@ var init_BottomSheetEngine = __esm({
3036
3140
  this.attach();
3037
3141
  this.registerInStack();
3038
3142
  if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
3039
- const io = new IntersectionObserver((entries) => {
3040
- for (const entry of entries) {
3143
+ const io = new IntersectionObserver((entries2) => {
3144
+ for (const entry of entries2) {
3041
3145
  if (!entry.isIntersecting) continue;
3042
3146
  if (this.destroyed) return;
3043
3147
  this.snaps.recompute();
@@ -3754,9 +3858,9 @@ var init_BottomSheetEngine = __esm({
3754
3858
  return;
3755
3859
  }
3756
3860
  if (this.emitBeforeSnap(target, previousId)) {
3757
- const restore = this.snaps.findById(previousId);
3758
- if (restore) {
3759
- void this.animation.animateTo(restore.size, 0);
3861
+ const restore2 = this.snaps.findById(previousId);
3862
+ if (restore2) {
3863
+ void this.animation.animateTo(restore2.size, 0);
3760
3864
  }
3761
3865
  return;
3762
3866
  }