@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.js CHANGED
@@ -440,46 +440,198 @@ function notifyLinkedSheets(sheets, self) {
440
440
  }
441
441
  }
442
442
 
443
- // src/core/features/route.ts
444
- var closers = [];
445
- var handlerInstalled = false;
443
+ // src/core/features/history-coordinator.ts
444
+ var entries = [];
445
+ var subscribers = /* @__PURE__ */ new Set();
446
446
  var suppress = 0;
447
- var ensureHandler = () => {
448
- if (handlerInstalled || typeof window === "undefined") return;
449
- handlerInstalled = true;
450
- window.addEventListener("popstate", () => {
451
- if (suppress > 0) {
452
- suppress -= 1;
453
- return;
447
+ var internalDepth = 0;
448
+ var pendingRebrand = null;
449
+ var listenerInstalled = false;
450
+ var patchInstalled = false;
451
+ var origPushState = null;
452
+ var origReplaceState = null;
453
+ var patchedPushState = null;
454
+ var patchedReplaceState = null;
455
+ var hasWindow = () => typeof window !== "undefined";
456
+ var hasHistory = () => typeof history !== "undefined";
457
+ var runInternal = (fn) => {
458
+ internalDepth += 1;
459
+ try {
460
+ fn();
461
+ } finally {
462
+ internalDepth -= 1;
463
+ }
464
+ };
465
+ var notifyRouteChange = () => {
466
+ const snapshot = Array.from(subscribers);
467
+ for (const fn of snapshot) fn();
468
+ };
469
+ var ensureListener = () => {
470
+ if (listenerInstalled || !hasWindow()) return;
471
+ window.addEventListener("popstate", onPopState);
472
+ listenerInstalled = true;
473
+ };
474
+ var maybeTeardownListener = () => {
475
+ if (!listenerInstalled) return;
476
+ if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
477
+ if (hasWindow()) window.removeEventListener("popstate", onPopState);
478
+ listenerInstalled = false;
479
+ };
480
+ var installPatch = () => {
481
+ if (patchInstalled || !hasHistory()) return;
482
+ origPushState = history.pushState;
483
+ origReplaceState = history.replaceState;
484
+ patchedPushState = function(...args) {
485
+ origPushState.apply(this, args);
486
+ if (internalDepth === 0) notifyRouteChange();
487
+ };
488
+ patchedReplaceState = function(...args) {
489
+ origReplaceState.apply(this, args);
490
+ if (internalDepth === 0) notifyRouteChange();
491
+ };
492
+ history.pushState = patchedPushState;
493
+ history.replaceState = patchedReplaceState;
494
+ patchInstalled = true;
495
+ };
496
+ var removePatch = () => {
497
+ if (!patchInstalled) return;
498
+ if (history.pushState === patchedPushState && origPushState) {
499
+ history.pushState = origPushState;
500
+ }
501
+ if (history.replaceState === patchedReplaceState && origReplaceState) {
502
+ history.replaceState = origReplaceState;
503
+ }
504
+ origPushState = null;
505
+ origReplaceState = null;
506
+ patchedPushState = null;
507
+ patchedReplaceState = null;
508
+ patchInstalled = false;
509
+ };
510
+ function onPopState() {
511
+ if (suppress > 0) {
512
+ suppress -= 1;
513
+ const rebrand = pendingRebrand;
514
+ pendingRebrand = null;
515
+ if (rebrand) rebrand();
516
+ maybeTeardownListener();
517
+ return;
518
+ }
519
+ if (entries.length === 0) {
520
+ notifyRouteChange();
521
+ maybeTeardownListener();
522
+ return;
523
+ }
524
+ let target = null;
525
+ let targetIdx = -1;
526
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
527
+ const entry = entries[i];
528
+ if (!entry.surface.isOpen()) continue;
529
+ if (!target) {
530
+ target = entry;
531
+ targetIdx = i;
454
532
  }
455
- let target = null;
456
- for (let i = closers.length - 1; i >= 0; i -= 1) {
457
- const c = closers[i];
458
- if (!c.isOpen()) continue;
459
- if (!target) target = c;
460
- if (c.isTop()) {
461
- target = c;
462
- break;
463
- }
533
+ if (entry.surface.isTop()) {
534
+ target = entry;
535
+ targetIdx = i;
536
+ break;
464
537
  }
465
- if (!target) return;
466
- target.consumed = true;
467
- const idx = closers.indexOf(target);
468
- if (idx !== -1) closers.splice(idx, 1);
469
- const settled = target;
470
- void Promise.resolve(settled.close()).then(() => {
471
- if (settled.isOpen()) settled.restore();
472
- });
538
+ }
539
+ if (!target) {
540
+ const removed = entries.pop();
541
+ if (removed) removed.live = false;
542
+ maybeTeardownListener();
543
+ return;
544
+ }
545
+ target.live = false;
546
+ entries.splice(targetIdx, 1);
547
+ const settled = target;
548
+ void Promise.resolve(settled.surface.close()).then(() => {
549
+ if (settled.surface.isOpen()) restore(settled);
473
550
  });
474
- };
475
- var programmaticBack = () => {
476
- suppress += 1;
477
- try {
478
- history.back();
479
- } catch {
480
- suppress = Math.max(0, suppress - 1);
551
+ maybeTeardownListener();
552
+ }
553
+ function restore(entry) {
554
+ if (!hasWindow() || !hasHistory()) return;
555
+ entry.live = true;
556
+ runInternal(() => {
557
+ try {
558
+ history.pushState(entry.surface.markerState(), "", entry.surface.url);
559
+ } catch {
560
+ entry.live = false;
561
+ }
562
+ });
563
+ if (entry.live) {
564
+ entries.push(entry);
565
+ ensureListener();
481
566
  }
482
- };
567
+ }
568
+ function pushBackMarker(surface) {
569
+ const entry = { surface, priorUrl: void 0, live: false };
570
+ if (!hasWindow() || !hasHistory()) {
571
+ return entry;
572
+ }
573
+ entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
574
+ runInternal(() => {
575
+ try {
576
+ history.pushState(surface.markerState(), "", surface.url);
577
+ entry.live = true;
578
+ } catch {
579
+ entry.live = false;
580
+ }
581
+ });
582
+ if (entry.live) {
583
+ entries.push(entry);
584
+ ensureListener();
585
+ }
586
+ return entry;
587
+ }
588
+ function popBackMarker(handle) {
589
+ if (!hasWindow() || !hasHistory()) return;
590
+ const entry = handle;
591
+ const idx = entries.indexOf(entry);
592
+ if (idx === -1 || !entry.live) return;
593
+ const last = entries.length - 1;
594
+ entry.live = false;
595
+ entries.splice(idx, 1);
596
+ if (idx !== last) {
597
+ const rebrandSurface = entries[entries.length - 1].surface;
598
+ const rebrandUrl = entry.priorUrl;
599
+ pendingRebrand = () => {
600
+ runInternal(() => {
601
+ history.replaceState(
602
+ rebrandSurface.markerState(),
603
+ "",
604
+ rebrandUrl !== void 0 ? rebrandUrl : location.href
605
+ );
606
+ });
607
+ };
608
+ }
609
+ suppress += 1;
610
+ runInternal(() => {
611
+ try {
612
+ history.back();
613
+ } catch {
614
+ suppress = Math.max(0, suppress - 1);
615
+ pendingRebrand = null;
616
+ }
617
+ });
618
+ maybeTeardownListener();
619
+ }
620
+ function subscribeRouteChange(fn) {
621
+ if (!hasWindow() || !hasHistory()) return () => {
622
+ };
623
+ subscribers.add(fn);
624
+ if (subscribers.size === 1) installPatch();
625
+ ensureListener();
626
+ return () => {
627
+ if (!subscribers.has(fn)) return;
628
+ subscribers.delete(fn);
629
+ if (subscribers.size === 0) removePatch();
630
+ maybeTeardownListener();
631
+ };
632
+ }
633
+
634
+ // src/core/features/route.ts
483
635
  function installRoute(deps) {
484
636
  if (typeof window === "undefined") {
485
637
  return () => {
@@ -489,92 +641,39 @@ function installRoute(deps) {
489
641
  return () => {
490
642
  };
491
643
  }
492
- let pushed = false;
493
- let closer = null;
494
- const teardownEntry = () => {
495
- if (closer) {
496
- const idx = closers.indexOf(closer);
497
- if (idx !== -1) closers.splice(idx, 1);
498
- }
499
- const wasConsumed = closer?.consumed ?? false;
500
- closer = null;
501
- if (pushed && !wasConsumed) {
502
- pushed = false;
503
- programmaticBack();
504
- } else {
505
- pushed = false;
506
- }
507
- };
508
- const pushEntry = () => {
509
- try {
510
- if (deps.routedTo !== void 0) {
511
- history.pushState({ __bsRouted: deps.sheetId }, "", deps.routedTo);
512
- } else {
513
- history.pushState({ __bsSheet: deps.sheetId }, "");
514
- }
515
- pushed = true;
516
- } catch {
517
- pushed = false;
518
- }
519
- };
644
+ let handle = null;
520
645
  const onOpen = () => {
521
- if (closer) return;
522
- const self = {
646
+ if (handle) return;
647
+ handle = pushBackMarker({
523
648
  isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
524
- isTop: () => deps.isTopSheet(),
525
- close: () => deps.close(),
526
- restore: () => {
527
- if (deps.isDestroyed() || closer !== self) return;
528
- self.consumed = false;
529
- if (!closers.includes(self)) closers.push(self);
530
- pushEntry();
531
- },
532
- consumed: false
533
- };
534
- closer = self;
535
- ensureHandler();
536
- closers.push(self);
537
- pushEntry();
649
+ isTop: deps.isTopSheet,
650
+ close: deps.close,
651
+ markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
652
+ url: deps.routedTo
653
+ });
654
+ };
655
+ const onClose = () => {
656
+ if (!handle) return;
657
+ popBackMarker(handle);
658
+ handle = null;
538
659
  };
539
660
  const unsubscribeOpen = deps.on("open", onOpen);
540
- const unsubscribeClose = deps.on("close", teardownEntry);
661
+ const unsubscribeClose = deps.on("close", onClose);
541
662
  if (deps.getSize() > 0) onOpen();
542
663
  return () => {
543
664
  unsubscribeOpen();
544
665
  unsubscribeClose();
545
- teardownEntry();
666
+ if (handle) {
667
+ popBackMarker(handle);
668
+ handle = null;
669
+ }
546
670
  };
547
671
  }
548
672
  function installRouteChange(deps) {
549
- if (typeof window === "undefined" || typeof history === "undefined") {
550
- return () => {
551
- };
552
- }
553
- const onChange = () => {
673
+ return subscribeRouteChange(() => {
554
674
  if (deps.isDestroyed() || deps.getSize() <= 0) return;
555
675
  void deps.close();
556
- };
557
- const wrap = (key) => {
558
- const original = history[key];
559
- const patched = function(...args) {
560
- original.apply(this, args);
561
- onChange();
562
- };
563
- history[key] = patched;
564
- return () => {
565
- if (history[key] === patched) {
566
- history[key] = original;
567
- }
568
- };
569
- };
570
- window.addEventListener("popstate", onChange);
571
- const restorePush = wrap("pushState");
572
- const restoreReplace = wrap("replaceState");
573
- return () => {
574
- window.removeEventListener("popstate", onChange);
575
- restorePush();
576
- restoreReplace();
577
- };
676
+ });
578
677
  }
579
678
 
580
679
  // src/core/features/content-swipe.ts
@@ -2427,7 +2526,7 @@ var matchesRange = (def, progress) => {
2427
2526
  };
2428
2527
  function installScrimStages(deps, opts) {
2429
2528
  const doc = deps.host.ownerDocument;
2430
- const entries = opts.stages.map((def) => {
2529
+ const entries2 = opts.stages.map((def) => {
2431
2530
  const wrapper = doc.createElement("div");
2432
2531
  wrapper.className = "bs-scrim-stage";
2433
2532
  const ws = wrapper.style;
@@ -2448,9 +2547,9 @@ function installScrimStages(deps, opts) {
2448
2547
  const resolveActive = () => {
2449
2548
  const state2 = deps.getState();
2450
2549
  if (state2.size === 0) {
2451
- return entries.find((e) => matchesId(e.def, state2.activeId)) ?? null;
2550
+ return entries2.find((e) => matchesId(e.def, state2.activeId)) ?? null;
2452
2551
  }
2453
- return entries.find((e) => matchesId(e.def, state2.activeId)) ?? entries.find((e) => matchesRange(e.def, state2.progress)) ?? null;
2552
+ return entries2.find((e) => matchesId(e.def, state2.activeId)) ?? entries2.find((e) => matchesRange(e.def, state2.progress)) ?? null;
2454
2553
  };
2455
2554
  const hide = (entry, animate) => {
2456
2555
  entry.inFlight?.cancel();
@@ -2499,13 +2598,13 @@ function installScrimStages(deps, opts) {
2499
2598
  deps.on("open", () => update(true)),
2500
2599
  deps.on("close", () => update(true))
2501
2600
  ];
2502
- if (entries.some((e) => e.def.forRange)) {
2601
+ if (entries2.some((e) => e.def.forRange)) {
2503
2602
  offs.push(deps.on("progress", () => update(true)));
2504
2603
  }
2505
2604
  update(false);
2506
2605
  return () => {
2507
2606
  offs.forEach((off) => off());
2508
- for (const entry of entries) {
2607
+ for (const entry of entries2) {
2509
2608
  entry.inFlight?.cancel();
2510
2609
  entry.inFlight = null;
2511
2610
  if (entry.wrapper.parentNode) {
@@ -2764,8 +2863,8 @@ var BottomSheetEngine = class {
2764
2863
  this.attach();
2765
2864
  this.registerInStack();
2766
2865
  if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
2767
- const io = new IntersectionObserver((entries) => {
2768
- for (const entry of entries) {
2866
+ const io = new IntersectionObserver((entries2) => {
2867
+ for (const entry of entries2) {
2769
2868
  if (!entry.isIntersecting) continue;
2770
2869
  if (this.destroyed) return;
2771
2870
  this.snaps.recompute();
@@ -3482,9 +3581,9 @@ var BottomSheetEngine = class {
3482
3581
  return;
3483
3582
  }
3484
3583
  if (this.emitBeforeSnap(target, previousId)) {
3485
- const restore = this.snaps.findById(previousId);
3486
- if (restore) {
3487
- void this.animation.animateTo(restore.size, 0);
3584
+ const restore2 = this.snaps.findById(previousId);
3585
+ if (restore2) {
3586
+ void this.animation.animateTo(restore2.size, 0);
3488
3587
  }
3489
3588
  return;
3490
3589
  }
@@ -3722,12 +3821,12 @@ function createBottomSheet(opts) {
3722
3821
  getEngine: () => engine
3723
3822
  };
3724
3823
  }
3725
- var root_1 = $2.from_html(`<div class="bs-backdrop" aria-hidden="true"></div>`);
3726
- var root_3 = $2.from_html(`<div class="bs-header"><!></div>`);
3727
- var root_5 = $2.from_html(`<div class="bs-footer"><!></div>`);
3728
- var root_6 = $2.from_html(`<div class="bs-button-slot" data-side="left"><!></div>`);
3729
- var root_7 = $2.from_html(`<div class="bs-button-slot" data-side="right"><!></div>`);
3730
- var root = $2.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>`);
3824
+ var root = $2.from_html(`<div class="bs-backdrop" aria-hidden="true"></div>`);
3825
+ var root_1 = $2.from_html(`<div class="bs-header"><!></div>`);
3826
+ var root_2 = $2.from_html(`<div class="bs-footer"><!></div>`);
3827
+ var root_3 = $2.from_html(`<div class="bs-button-slot" data-side="left"><!></div>`);
3828
+ var root_4 = $2.from_html(`<div class="bs-button-slot" data-side="right"><!></div>`);
3829
+ var root_5 = $2.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>`);
3731
3830
  function BottomSheet($$anchor, $$props) {
3732
3831
  $2.push($$props, true);
3733
3832
  let mode = $2.prop($$props, "mode", 3, "bottom"), animation = $2.prop($$props, "animation", 3, "spring"), focusTrap = $2.prop($$props, "focusTrap", 3, false), closeOnEscape = $2.prop($$props, "closeOnEscape", 3, true), closeOnBack = $2.prop($$props, "closeOnBack", 3, false), lockBodyScroll2 = $2.prop($$props, "lockBodyScroll", 3, true), rubberBand2 = $2.prop($$props, "rubberBand", 3, true), backdrop = $2.prop($$props, "backdrop", 3, true), closeOnBackdrop = $2.prop($$props, "closeOnBackdrop", 3, true), persistent = $2.prop($$props, "persistent", 3, false), disableClose = $2.prop($$props, "disableClose", 3, false), disableDrag = $2.prop($$props, "disableDrag", 3, false), closeOnRouteChange = $2.prop($$props, "closeOnRouteChange", 3, false), stackEffect = $2.prop($$props, "stackEffect", 3, false), teleport = $2.prop($$props, "teleport", 3, false), openProp = $2.prop($$props, "open", 15), snap = $2.prop($$props, "snap", 15), ariaLabel = $2.prop($$props, "ariaLabel", 3, "Bottom sheet");
@@ -3909,11 +4008,11 @@ function BottomSheet($$anchor, $$props) {
3909
4008
  getState,
3910
4009
  getEngine
3911
4010
  };
3912
- var div = root();
4011
+ var div = root_5();
3913
4012
  var node = $2.child(div);
3914
4013
  {
3915
4014
  var consequent = ($$anchor2) => {
3916
- var div_1 = root_1();
4015
+ var div_1 = root();
3917
4016
  $2.bind_this(div_1, ($$value) => $2.set(backdropEl, $$value), () => $2.get(backdropEl));
3918
4017
  $2.delegated("click", div_1, function(...$$args) {
3919
4018
  (closeOnBackdrop() ? () => {
@@ -3947,7 +4046,7 @@ function BottomSheet($$anchor, $$props) {
3947
4046
  var node_3 = $2.sibling(div_3, 2);
3948
4047
  {
3949
4048
  var consequent_2 = ($$anchor2) => {
3950
- var div_4 = root_3();
4049
+ var div_4 = root_1();
3951
4050
  var node_4 = $2.child(div_4);
3952
4051
  $2.snippet(node_4, () => $$props.header, () => $2.get(viewState));
3953
4052
  $2.reset(div_4);
@@ -3975,7 +4074,7 @@ function BottomSheet($$anchor, $$props) {
3975
4074
  var node_7 = $2.sibling(div_5, 2);
3976
4075
  {
3977
4076
  var consequent_4 = ($$anchor2) => {
3978
- var div_6 = root_5();
4077
+ var div_6 = root_2();
3979
4078
  var node_8 = $2.child(div_6);
3980
4079
  $2.snippet(node_8, () => $$props.footer, () => $2.get(viewState));
3981
4080
  $2.reset(div_6);
@@ -3993,7 +4092,7 @@ function BottomSheet($$anchor, $$props) {
3993
4092
  var node_9 = $2.sibling(section, 2);
3994
4093
  {
3995
4094
  var consequent_5 = ($$anchor2) => {
3996
- var div_7 = root_6();
4095
+ var div_7 = root_3();
3997
4096
  var node_10 = $2.child(div_7);
3998
4097
  $2.snippet(node_10, () => $$props.leftButton);
3999
4098
  $2.reset(div_7);
@@ -4007,7 +4106,7 @@ function BottomSheet($$anchor, $$props) {
4007
4106
  var node_11 = $2.sibling(node_9, 2);
4008
4107
  {
4009
4108
  var consequent_6 = ($$anchor2) => {
4010
- var div_8 = root_7();
4109
+ var div_8 = root_4();
4011
4110
  var node_12 = $2.child(div_8);
4012
4111
  $2.snippet(node_12, () => $$props.rightButton);
4013
4112
  $2.reset(div_8);