@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/svelte.cjs CHANGED
@@ -462,46 +462,198 @@ function notifyLinkedSheets(sheets, self) {
462
462
  }
463
463
  }
464
464
 
465
- // src/core/features/route.ts
466
- var closers = [];
467
- var handlerInstalled = false;
465
+ // src/core/features/history-coordinator.ts
466
+ var entries = [];
467
+ var subscribers = /* @__PURE__ */ new Set();
468
468
  var suppress = 0;
469
- var ensureHandler = () => {
470
- if (handlerInstalled || typeof window === "undefined") return;
471
- handlerInstalled = true;
472
- window.addEventListener("popstate", () => {
473
- if (suppress > 0) {
474
- suppress -= 1;
475
- return;
469
+ var internalDepth = 0;
470
+ var pendingRebrand = null;
471
+ var listenerInstalled = false;
472
+ var patchInstalled = false;
473
+ var origPushState = null;
474
+ var origReplaceState = null;
475
+ var patchedPushState = null;
476
+ var patchedReplaceState = null;
477
+ var hasWindow = () => typeof window !== "undefined";
478
+ var hasHistory = () => typeof history !== "undefined";
479
+ var runInternal = (fn) => {
480
+ internalDepth += 1;
481
+ try {
482
+ fn();
483
+ } finally {
484
+ internalDepth -= 1;
485
+ }
486
+ };
487
+ var notifyRouteChange = () => {
488
+ const snapshot = Array.from(subscribers);
489
+ for (const fn of snapshot) fn();
490
+ };
491
+ var ensureListener = () => {
492
+ if (listenerInstalled || !hasWindow()) return;
493
+ window.addEventListener("popstate", onPopState);
494
+ listenerInstalled = true;
495
+ };
496
+ var maybeTeardownListener = () => {
497
+ if (!listenerInstalled) return;
498
+ if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
499
+ if (hasWindow()) window.removeEventListener("popstate", onPopState);
500
+ listenerInstalled = false;
501
+ };
502
+ var installPatch = () => {
503
+ if (patchInstalled || !hasHistory()) return;
504
+ origPushState = history.pushState;
505
+ origReplaceState = history.replaceState;
506
+ patchedPushState = function(...args) {
507
+ origPushState.apply(this, args);
508
+ if (internalDepth === 0) notifyRouteChange();
509
+ };
510
+ patchedReplaceState = function(...args) {
511
+ origReplaceState.apply(this, args);
512
+ if (internalDepth === 0) notifyRouteChange();
513
+ };
514
+ history.pushState = patchedPushState;
515
+ history.replaceState = patchedReplaceState;
516
+ patchInstalled = true;
517
+ };
518
+ var removePatch = () => {
519
+ if (!patchInstalled) return;
520
+ if (history.pushState === patchedPushState && origPushState) {
521
+ history.pushState = origPushState;
522
+ }
523
+ if (history.replaceState === patchedReplaceState && origReplaceState) {
524
+ history.replaceState = origReplaceState;
525
+ }
526
+ origPushState = null;
527
+ origReplaceState = null;
528
+ patchedPushState = null;
529
+ patchedReplaceState = null;
530
+ patchInstalled = false;
531
+ };
532
+ function onPopState() {
533
+ if (suppress > 0) {
534
+ suppress -= 1;
535
+ const rebrand = pendingRebrand;
536
+ pendingRebrand = null;
537
+ if (rebrand) rebrand();
538
+ maybeTeardownListener();
539
+ return;
540
+ }
541
+ if (entries.length === 0) {
542
+ notifyRouteChange();
543
+ maybeTeardownListener();
544
+ return;
545
+ }
546
+ let target = null;
547
+ let targetIdx = -1;
548
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
549
+ const entry = entries[i];
550
+ if (!entry.surface.isOpen()) continue;
551
+ if (!target) {
552
+ target = entry;
553
+ targetIdx = i;
476
554
  }
477
- let target = null;
478
- for (let i = closers.length - 1; i >= 0; i -= 1) {
479
- const c = closers[i];
480
- if (!c.isOpen()) continue;
481
- if (!target) target = c;
482
- if (c.isTop()) {
483
- target = c;
484
- break;
485
- }
555
+ if (entry.surface.isTop()) {
556
+ target = entry;
557
+ targetIdx = i;
558
+ break;
486
559
  }
487
- if (!target) return;
488
- target.consumed = true;
489
- const idx = closers.indexOf(target);
490
- if (idx !== -1) closers.splice(idx, 1);
491
- const settled = target;
492
- void Promise.resolve(settled.close()).then(() => {
493
- if (settled.isOpen()) settled.restore();
494
- });
560
+ }
561
+ if (!target) {
562
+ const removed = entries.pop();
563
+ if (removed) removed.live = false;
564
+ maybeTeardownListener();
565
+ return;
566
+ }
567
+ target.live = false;
568
+ entries.splice(targetIdx, 1);
569
+ const settled = target;
570
+ void Promise.resolve(settled.surface.close()).then(() => {
571
+ if (settled.surface.isOpen()) restore(settled);
495
572
  });
496
- };
497
- var programmaticBack = () => {
498
- suppress += 1;
499
- try {
500
- history.back();
501
- } catch {
502
- suppress = Math.max(0, suppress - 1);
573
+ maybeTeardownListener();
574
+ }
575
+ function restore(entry) {
576
+ if (!hasWindow() || !hasHistory()) return;
577
+ entry.live = true;
578
+ runInternal(() => {
579
+ try {
580
+ history.pushState(entry.surface.markerState(), "", entry.surface.url);
581
+ } catch {
582
+ entry.live = false;
583
+ }
584
+ });
585
+ if (entry.live) {
586
+ entries.push(entry);
587
+ ensureListener();
503
588
  }
504
- };
589
+ }
590
+ function pushBackMarker(surface) {
591
+ const entry = { surface, priorUrl: void 0, live: false };
592
+ if (!hasWindow() || !hasHistory()) {
593
+ return entry;
594
+ }
595
+ entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
596
+ runInternal(() => {
597
+ try {
598
+ history.pushState(surface.markerState(), "", surface.url);
599
+ entry.live = true;
600
+ } catch {
601
+ entry.live = false;
602
+ }
603
+ });
604
+ if (entry.live) {
605
+ entries.push(entry);
606
+ ensureListener();
607
+ }
608
+ return entry;
609
+ }
610
+ function popBackMarker(handle) {
611
+ if (!hasWindow() || !hasHistory()) return;
612
+ const entry = handle;
613
+ const idx = entries.indexOf(entry);
614
+ if (idx === -1 || !entry.live) return;
615
+ const last = entries.length - 1;
616
+ entry.live = false;
617
+ entries.splice(idx, 1);
618
+ if (idx !== last) {
619
+ const rebrandSurface = entries[entries.length - 1].surface;
620
+ const rebrandUrl = entry.priorUrl;
621
+ pendingRebrand = () => {
622
+ runInternal(() => {
623
+ history.replaceState(
624
+ rebrandSurface.markerState(),
625
+ "",
626
+ rebrandUrl !== void 0 ? rebrandUrl : location.href
627
+ );
628
+ });
629
+ };
630
+ }
631
+ suppress += 1;
632
+ runInternal(() => {
633
+ try {
634
+ history.back();
635
+ } catch {
636
+ suppress = Math.max(0, suppress - 1);
637
+ pendingRebrand = null;
638
+ }
639
+ });
640
+ maybeTeardownListener();
641
+ }
642
+ function subscribeRouteChange(fn) {
643
+ if (!hasWindow() || !hasHistory()) return () => {
644
+ };
645
+ subscribers.add(fn);
646
+ if (subscribers.size === 1) installPatch();
647
+ ensureListener();
648
+ return () => {
649
+ if (!subscribers.has(fn)) return;
650
+ subscribers.delete(fn);
651
+ if (subscribers.size === 0) removePatch();
652
+ maybeTeardownListener();
653
+ };
654
+ }
655
+
656
+ // src/core/features/route.ts
505
657
  function installRoute(deps) {
506
658
  if (typeof window === "undefined") {
507
659
  return () => {
@@ -511,92 +663,39 @@ function installRoute(deps) {
511
663
  return () => {
512
664
  };
513
665
  }
514
- let pushed = false;
515
- let closer = null;
516
- const teardownEntry = () => {
517
- if (closer) {
518
- const idx = closers.indexOf(closer);
519
- if (idx !== -1) closers.splice(idx, 1);
520
- }
521
- const wasConsumed = closer?.consumed ?? false;
522
- closer = null;
523
- if (pushed && !wasConsumed) {
524
- pushed = false;
525
- programmaticBack();
526
- } else {
527
- pushed = false;
528
- }
529
- };
530
- const pushEntry = () => {
531
- try {
532
- if (deps.routedTo !== void 0) {
533
- history.pushState({ __bsRouted: deps.sheetId }, "", deps.routedTo);
534
- } else {
535
- history.pushState({ __bsSheet: deps.sheetId }, "");
536
- }
537
- pushed = true;
538
- } catch {
539
- pushed = false;
540
- }
541
- };
666
+ let handle = null;
542
667
  const onOpen = () => {
543
- if (closer) return;
544
- const self = {
668
+ if (handle) return;
669
+ handle = pushBackMarker({
545
670
  isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
546
- isTop: () => deps.isTopSheet(),
547
- close: () => deps.close(),
548
- restore: () => {
549
- if (deps.isDestroyed() || closer !== self) return;
550
- self.consumed = false;
551
- if (!closers.includes(self)) closers.push(self);
552
- pushEntry();
553
- },
554
- consumed: false
555
- };
556
- closer = self;
557
- ensureHandler();
558
- closers.push(self);
559
- pushEntry();
671
+ isTop: deps.isTopSheet,
672
+ close: deps.close,
673
+ markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
674
+ url: deps.routedTo
675
+ });
676
+ };
677
+ const onClose = () => {
678
+ if (!handle) return;
679
+ popBackMarker(handle);
680
+ handle = null;
560
681
  };
561
682
  const unsubscribeOpen = deps.on("open", onOpen);
562
- const unsubscribeClose = deps.on("close", teardownEntry);
683
+ const unsubscribeClose = deps.on("close", onClose);
563
684
  if (deps.getSize() > 0) onOpen();
564
685
  return () => {
565
686
  unsubscribeOpen();
566
687
  unsubscribeClose();
567
- teardownEntry();
688
+ if (handle) {
689
+ popBackMarker(handle);
690
+ handle = null;
691
+ }
568
692
  };
569
693
  }
570
694
  function installRouteChange(deps) {
571
- if (typeof window === "undefined" || typeof history === "undefined") {
572
- return () => {
573
- };
574
- }
575
- const onChange = () => {
695
+ return subscribeRouteChange(() => {
576
696
  if (deps.isDestroyed() || deps.getSize() <= 0) return;
577
697
  void deps.close();
578
- };
579
- const wrap = (key) => {
580
- const original = history[key];
581
- const patched = function(...args) {
582
- original.apply(this, args);
583
- onChange();
584
- };
585
- history[key] = patched;
586
- return () => {
587
- if (history[key] === patched) {
588
- history[key] = original;
589
- }
590
- };
591
- };
592
- window.addEventListener("popstate", onChange);
593
- const restorePush = wrap("pushState");
594
- const restoreReplace = wrap("replaceState");
595
- return () => {
596
- window.removeEventListener("popstate", onChange);
597
- restorePush();
598
- restoreReplace();
599
- };
698
+ });
600
699
  }
601
700
 
602
701
  // src/core/features/content-swipe.ts
@@ -2449,7 +2548,7 @@ var matchesRange = (def, progress) => {
2449
2548
  };
2450
2549
  function installScrimStages(deps, opts) {
2451
2550
  const doc = deps.host.ownerDocument;
2452
- const entries = opts.stages.map((def) => {
2551
+ const entries2 = opts.stages.map((def) => {
2453
2552
  const wrapper = doc.createElement("div");
2454
2553
  wrapper.className = "bs-scrim-stage";
2455
2554
  const ws = wrapper.style;
@@ -2470,9 +2569,9 @@ function installScrimStages(deps, opts) {
2470
2569
  const resolveActive = () => {
2471
2570
  const state2 = deps.getState();
2472
2571
  if (state2.size === 0) {
2473
- return entries.find((e) => matchesId(e.def, state2.activeId)) ?? null;
2572
+ return entries2.find((e) => matchesId(e.def, state2.activeId)) ?? null;
2474
2573
  }
2475
- return entries.find((e) => matchesId(e.def, state2.activeId)) ?? entries.find((e) => matchesRange(e.def, state2.progress)) ?? null;
2574
+ return entries2.find((e) => matchesId(e.def, state2.activeId)) ?? entries2.find((e) => matchesRange(e.def, state2.progress)) ?? null;
2476
2575
  };
2477
2576
  const hide = (entry, animate) => {
2478
2577
  entry.inFlight?.cancel();
@@ -2521,13 +2620,13 @@ function installScrimStages(deps, opts) {
2521
2620
  deps.on("open", () => update(true)),
2522
2621
  deps.on("close", () => update(true))
2523
2622
  ];
2524
- if (entries.some((e) => e.def.forRange)) {
2623
+ if (entries2.some((e) => e.def.forRange)) {
2525
2624
  offs.push(deps.on("progress", () => update(true)));
2526
2625
  }
2527
2626
  update(false);
2528
2627
  return () => {
2529
2628
  offs.forEach((off) => off());
2530
- for (const entry of entries) {
2629
+ for (const entry of entries2) {
2531
2630
  entry.inFlight?.cancel();
2532
2631
  entry.inFlight = null;
2533
2632
  if (entry.wrapper.parentNode) {
@@ -2786,8 +2885,8 @@ var BottomSheetEngine = class {
2786
2885
  this.attach();
2787
2886
  this.registerInStack();
2788
2887
  if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
2789
- const io = new IntersectionObserver((entries) => {
2790
- for (const entry of entries) {
2888
+ const io = new IntersectionObserver((entries2) => {
2889
+ for (const entry of entries2) {
2791
2890
  if (!entry.isIntersecting) continue;
2792
2891
  if (this.destroyed) return;
2793
2892
  this.snaps.recompute();
@@ -3504,9 +3603,9 @@ var BottomSheetEngine = class {
3504
3603
  return;
3505
3604
  }
3506
3605
  if (this.emitBeforeSnap(target, previousId)) {
3507
- const restore = this.snaps.findById(previousId);
3508
- if (restore) {
3509
- void this.animation.animateTo(restore.size, 0);
3606
+ const restore2 = this.snaps.findById(previousId);
3607
+ if (restore2) {
3608
+ void this.animation.animateTo(restore2.size, 0);
3510
3609
  }
3511
3610
  return;
3512
3611
  }
@@ -3744,12 +3843,12 @@ function createBottomSheet(opts) {
3744
3843
  getEngine: () => engine
3745
3844
  };
3746
3845
  }
3747
- var root_1 = $2__namespace.from_html(`<div class="bs-backdrop" aria-hidden="true"></div>`);
3748
- var root_3 = $2__namespace.from_html(`<div class="bs-header"><!></div>`);
3749
- var root_5 = $2__namespace.from_html(`<div class="bs-footer"><!></div>`);
3750
- var root_6 = $2__namespace.from_html(`<div class="bs-button-slot" data-side="left"><!></div>`);
3751
- var root_7 = $2__namespace.from_html(`<div class="bs-button-slot" data-side="right"><!></div>`);
3752
- var root = $2__namespace.from_html(`<div class="bs-root"><!> <div class="bs-screen"><!></div> <section class="bs-sheet" role="dialog"><div class="bs-handle" role="slider" tabindex="0" aria-label="Resize sheet" aria-valuemin="0" aria-valuemax="0" aria-valuenow="0"></div> <!> <div class="bs-content" tabindex="0" role="region" aria-label="Sheet content"><!></div> <!> <span class="bs-sr-only" role="status" aria-live="polite"> </span></section> <!> <!></div>`);
3846
+ var root = $2__namespace.from_html(`<div class="bs-backdrop" aria-hidden="true"></div>`);
3847
+ var root_1 = $2__namespace.from_html(`<div class="bs-header"><!></div>`);
3848
+ var root_2 = $2__namespace.from_html(`<div class="bs-footer"><!></div>`);
3849
+ var root_3 = $2__namespace.from_html(`<div class="bs-button-slot" data-side="left"><!></div>`);
3850
+ var root_4 = $2__namespace.from_html(`<div class="bs-button-slot" data-side="right"><!></div>`);
3851
+ var root_5 = $2__namespace.from_html(`<div class="bs-root"><!> <div class="bs-screen"><!></div> <section class="bs-sheet" role="dialog"><div class="bs-handle" role="slider" tabindex="0" aria-label="Resize sheet" aria-valuemin="0" aria-valuemax="0" aria-valuenow="0"></div> <!> <div class="bs-content" tabindex="0" role="region" aria-label="Sheet content"><!></div> <!> <span class="bs-sr-only" role="status" aria-live="polite"> </span></section> <!> <!></div>`);
3753
3852
  function BottomSheet($$anchor, $$props) {
3754
3853
  $2__namespace.push($$props, true);
3755
3854
  let mode = $2__namespace.prop($$props, "mode", 3, "bottom"), animation = $2__namespace.prop($$props, "animation", 3, "spring"), focusTrap = $2__namespace.prop($$props, "focusTrap", 3, false), closeOnEscape = $2__namespace.prop($$props, "closeOnEscape", 3, true), closeOnBack = $2__namespace.prop($$props, "closeOnBack", 3, false), lockBodyScroll2 = $2__namespace.prop($$props, "lockBodyScroll", 3, true), rubberBand2 = $2__namespace.prop($$props, "rubberBand", 3, true), backdrop = $2__namespace.prop($$props, "backdrop", 3, true), closeOnBackdrop = $2__namespace.prop($$props, "closeOnBackdrop", 3, true), persistent = $2__namespace.prop($$props, "persistent", 3, false), disableClose = $2__namespace.prop($$props, "disableClose", 3, false), disableDrag = $2__namespace.prop($$props, "disableDrag", 3, false), closeOnRouteChange = $2__namespace.prop($$props, "closeOnRouteChange", 3, false), stackEffect = $2__namespace.prop($$props, "stackEffect", 3, false), teleport = $2__namespace.prop($$props, "teleport", 3, false), openProp = $2__namespace.prop($$props, "open", 15), snap = $2__namespace.prop($$props, "snap", 15), ariaLabel = $2__namespace.prop($$props, "ariaLabel", 3, "Bottom sheet");
@@ -3931,11 +4030,11 @@ function BottomSheet($$anchor, $$props) {
3931
4030
  getState,
3932
4031
  getEngine
3933
4032
  };
3934
- var div = root();
4033
+ var div = root_5();
3935
4034
  var node = $2__namespace.child(div);
3936
4035
  {
3937
4036
  var consequent = ($$anchor2) => {
3938
- var div_1 = root_1();
4037
+ var div_1 = root();
3939
4038
  $2__namespace.bind_this(div_1, ($$value) => $2__namespace.set(backdropEl, $$value), () => $2__namespace.get(backdropEl));
3940
4039
  $2__namespace.delegated("click", div_1, function(...$$args) {
3941
4040
  (closeOnBackdrop() ? () => {
@@ -3969,7 +4068,7 @@ function BottomSheet($$anchor, $$props) {
3969
4068
  var node_3 = $2__namespace.sibling(div_3, 2);
3970
4069
  {
3971
4070
  var consequent_2 = ($$anchor2) => {
3972
- var div_4 = root_3();
4071
+ var div_4 = root_1();
3973
4072
  var node_4 = $2__namespace.child(div_4);
3974
4073
  $2__namespace.snippet(node_4, () => $$props.header, () => $2__namespace.get(viewState));
3975
4074
  $2__namespace.reset(div_4);
@@ -3997,7 +4096,7 @@ function BottomSheet($$anchor, $$props) {
3997
4096
  var node_7 = $2__namespace.sibling(div_5, 2);
3998
4097
  {
3999
4098
  var consequent_4 = ($$anchor2) => {
4000
- var div_6 = root_5();
4099
+ var div_6 = root_2();
4001
4100
  var node_8 = $2__namespace.child(div_6);
4002
4101
  $2__namespace.snippet(node_8, () => $$props.footer, () => $2__namespace.get(viewState));
4003
4102
  $2__namespace.reset(div_6);
@@ -4015,7 +4114,7 @@ function BottomSheet($$anchor, $$props) {
4015
4114
  var node_9 = $2__namespace.sibling(section, 2);
4016
4115
  {
4017
4116
  var consequent_5 = ($$anchor2) => {
4018
- var div_7 = root_6();
4117
+ var div_7 = root_3();
4019
4118
  var node_10 = $2__namespace.child(div_7);
4020
4119
  $2__namespace.snippet(node_10, () => $$props.leftButton);
4021
4120
  $2__namespace.reset(div_7);
@@ -4029,7 +4128,7 @@ function BottomSheet($$anchor, $$props) {
4029
4128
  var node_11 = $2__namespace.sibling(node_9, 2);
4030
4129
  {
4031
4130
  var consequent_6 = ($$anchor2) => {
4032
- var div_8 = root_7();
4131
+ var div_8 = root_4();
4033
4132
  var node_12 = $2__namespace.child(div_8);
4034
4133
  $2__namespace.snippet(node_12, () => $$props.rightButton);
4035
4134
  $2__namespace.reset(div_8);