@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/solid.cjs CHANGED
@@ -441,46 +441,198 @@ function notifyLinkedSheets(sheets, self) {
441
441
  }
442
442
  }
443
443
 
444
- // src/core/features/route.ts
445
- var closers = [];
446
- var handlerInstalled = false;
444
+ // src/core/features/history-coordinator.ts
445
+ var entries = [];
446
+ var subscribers = /* @__PURE__ */ new Set();
447
447
  var suppress = 0;
448
- var ensureHandler = () => {
449
- if (handlerInstalled || typeof window === "undefined") return;
450
- handlerInstalled = true;
451
- window.addEventListener("popstate", () => {
452
- if (suppress > 0) {
453
- suppress -= 1;
454
- return;
448
+ var internalDepth = 0;
449
+ var pendingRebrand = null;
450
+ var listenerInstalled = false;
451
+ var patchInstalled = false;
452
+ var origPushState = null;
453
+ var origReplaceState = null;
454
+ var patchedPushState = null;
455
+ var patchedReplaceState = null;
456
+ var hasWindow = () => typeof window !== "undefined";
457
+ var hasHistory = () => typeof history !== "undefined";
458
+ var runInternal = (fn) => {
459
+ internalDepth += 1;
460
+ try {
461
+ fn();
462
+ } finally {
463
+ internalDepth -= 1;
464
+ }
465
+ };
466
+ var notifyRouteChange = () => {
467
+ const snapshot = Array.from(subscribers);
468
+ for (const fn of snapshot) fn();
469
+ };
470
+ var ensureListener = () => {
471
+ if (listenerInstalled || !hasWindow()) return;
472
+ window.addEventListener("popstate", onPopState);
473
+ listenerInstalled = true;
474
+ };
475
+ var maybeTeardownListener = () => {
476
+ if (!listenerInstalled) return;
477
+ if (entries.length > 0 || subscribers.size > 0 || suppress > 0) return;
478
+ if (hasWindow()) window.removeEventListener("popstate", onPopState);
479
+ listenerInstalled = false;
480
+ };
481
+ var installPatch = () => {
482
+ if (patchInstalled || !hasHistory()) return;
483
+ origPushState = history.pushState;
484
+ origReplaceState = history.replaceState;
485
+ patchedPushState = function(...args) {
486
+ origPushState.apply(this, args);
487
+ if (internalDepth === 0) notifyRouteChange();
488
+ };
489
+ patchedReplaceState = function(...args) {
490
+ origReplaceState.apply(this, args);
491
+ if (internalDepth === 0) notifyRouteChange();
492
+ };
493
+ history.pushState = patchedPushState;
494
+ history.replaceState = patchedReplaceState;
495
+ patchInstalled = true;
496
+ };
497
+ var removePatch = () => {
498
+ if (!patchInstalled) return;
499
+ if (history.pushState === patchedPushState && origPushState) {
500
+ history.pushState = origPushState;
501
+ }
502
+ if (history.replaceState === patchedReplaceState && origReplaceState) {
503
+ history.replaceState = origReplaceState;
504
+ }
505
+ origPushState = null;
506
+ origReplaceState = null;
507
+ patchedPushState = null;
508
+ patchedReplaceState = null;
509
+ patchInstalled = false;
510
+ };
511
+ function onPopState() {
512
+ if (suppress > 0) {
513
+ suppress -= 1;
514
+ const rebrand = pendingRebrand;
515
+ pendingRebrand = null;
516
+ if (rebrand) rebrand();
517
+ maybeTeardownListener();
518
+ return;
519
+ }
520
+ if (entries.length === 0) {
521
+ notifyRouteChange();
522
+ maybeTeardownListener();
523
+ return;
524
+ }
525
+ let target = null;
526
+ let targetIdx = -1;
527
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
528
+ const entry = entries[i];
529
+ if (!entry.surface.isOpen()) continue;
530
+ if (!target) {
531
+ target = entry;
532
+ targetIdx = i;
455
533
  }
456
- let target = null;
457
- for (let i = closers.length - 1; i >= 0; i -= 1) {
458
- const c = closers[i];
459
- if (!c.isOpen()) continue;
460
- if (!target) target = c;
461
- if (c.isTop()) {
462
- target = c;
463
- break;
464
- }
534
+ if (entry.surface.isTop()) {
535
+ target = entry;
536
+ targetIdx = i;
537
+ break;
465
538
  }
466
- if (!target) return;
467
- target.consumed = true;
468
- const idx = closers.indexOf(target);
469
- if (idx !== -1) closers.splice(idx, 1);
470
- const settled = target;
471
- void Promise.resolve(settled.close()).then(() => {
472
- if (settled.isOpen()) settled.restore();
473
- });
539
+ }
540
+ if (!target) {
541
+ const removed = entries.pop();
542
+ if (removed) removed.live = false;
543
+ maybeTeardownListener();
544
+ return;
545
+ }
546
+ target.live = false;
547
+ entries.splice(targetIdx, 1);
548
+ const settled = target;
549
+ void Promise.resolve(settled.surface.close()).then(() => {
550
+ if (settled.surface.isOpen()) restore(settled);
474
551
  });
475
- };
476
- var programmaticBack = () => {
477
- suppress += 1;
478
- try {
479
- history.back();
480
- } catch {
481
- suppress = Math.max(0, suppress - 1);
552
+ maybeTeardownListener();
553
+ }
554
+ function restore(entry) {
555
+ if (!hasWindow() || !hasHistory()) return;
556
+ entry.live = true;
557
+ runInternal(() => {
558
+ try {
559
+ history.pushState(entry.surface.markerState(), "", entry.surface.url);
560
+ } catch {
561
+ entry.live = false;
562
+ }
563
+ });
564
+ if (entry.live) {
565
+ entries.push(entry);
566
+ ensureListener();
482
567
  }
483
- };
568
+ }
569
+ function pushBackMarker(surface) {
570
+ const entry = { surface, priorUrl: void 0, live: false };
571
+ if (!hasWindow() || !hasHistory()) {
572
+ return entry;
573
+ }
574
+ entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
575
+ runInternal(() => {
576
+ try {
577
+ history.pushState(surface.markerState(), "", surface.url);
578
+ entry.live = true;
579
+ } catch {
580
+ entry.live = false;
581
+ }
582
+ });
583
+ if (entry.live) {
584
+ entries.push(entry);
585
+ ensureListener();
586
+ }
587
+ return entry;
588
+ }
589
+ function popBackMarker(handle) {
590
+ if (!hasWindow() || !hasHistory()) return;
591
+ const entry = handle;
592
+ const idx = entries.indexOf(entry);
593
+ if (idx === -1 || !entry.live) return;
594
+ const last = entries.length - 1;
595
+ entry.live = false;
596
+ entries.splice(idx, 1);
597
+ if (idx !== last) {
598
+ const rebrandSurface = entries[entries.length - 1].surface;
599
+ const rebrandUrl = entry.priorUrl;
600
+ pendingRebrand = () => {
601
+ runInternal(() => {
602
+ history.replaceState(
603
+ rebrandSurface.markerState(),
604
+ "",
605
+ rebrandUrl !== void 0 ? rebrandUrl : location.href
606
+ );
607
+ });
608
+ };
609
+ }
610
+ suppress += 1;
611
+ runInternal(() => {
612
+ try {
613
+ history.back();
614
+ } catch {
615
+ suppress = Math.max(0, suppress - 1);
616
+ pendingRebrand = null;
617
+ }
618
+ });
619
+ maybeTeardownListener();
620
+ }
621
+ function subscribeRouteChange(fn) {
622
+ if (!hasWindow() || !hasHistory()) return () => {
623
+ };
624
+ subscribers.add(fn);
625
+ if (subscribers.size === 1) installPatch();
626
+ ensureListener();
627
+ return () => {
628
+ if (!subscribers.has(fn)) return;
629
+ subscribers.delete(fn);
630
+ if (subscribers.size === 0) removePatch();
631
+ maybeTeardownListener();
632
+ };
633
+ }
634
+
635
+ // src/core/features/route.ts
484
636
  function installRoute(deps) {
485
637
  if (typeof window === "undefined") {
486
638
  return () => {
@@ -490,92 +642,39 @@ function installRoute(deps) {
490
642
  return () => {
491
643
  };
492
644
  }
493
- let pushed = false;
494
- let closer = null;
495
- const teardownEntry = () => {
496
- if (closer) {
497
- const idx = closers.indexOf(closer);
498
- if (idx !== -1) closers.splice(idx, 1);
499
- }
500
- const wasConsumed = closer?.consumed ?? false;
501
- closer = null;
502
- if (pushed && !wasConsumed) {
503
- pushed = false;
504
- programmaticBack();
505
- } else {
506
- pushed = false;
507
- }
508
- };
509
- const pushEntry = () => {
510
- try {
511
- if (deps.routedTo !== void 0) {
512
- history.pushState({ __bsRouted: deps.sheetId }, "", deps.routedTo);
513
- } else {
514
- history.pushState({ __bsSheet: deps.sheetId }, "");
515
- }
516
- pushed = true;
517
- } catch {
518
- pushed = false;
519
- }
520
- };
645
+ let handle = null;
521
646
  const onOpen = () => {
522
- if (closer) return;
523
- const self = {
647
+ if (handle) return;
648
+ handle = pushBackMarker({
524
649
  isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
525
- isTop: () => deps.isTopSheet(),
526
- close: () => deps.close(),
527
- restore: () => {
528
- if (deps.isDestroyed() || closer !== self) return;
529
- self.consumed = false;
530
- if (!closers.includes(self)) closers.push(self);
531
- pushEntry();
532
- },
533
- consumed: false
534
- };
535
- closer = self;
536
- ensureHandler();
537
- closers.push(self);
538
- pushEntry();
650
+ isTop: deps.isTopSheet,
651
+ close: deps.close,
652
+ markerState: () => deps.routedTo !== void 0 ? { __bsRouted: deps.sheetId } : { __bsSheet: deps.sheetId },
653
+ url: deps.routedTo
654
+ });
655
+ };
656
+ const onClose = () => {
657
+ if (!handle) return;
658
+ popBackMarker(handle);
659
+ handle = null;
539
660
  };
540
661
  const unsubscribeOpen = deps.on("open", onOpen);
541
- const unsubscribeClose = deps.on("close", teardownEntry);
662
+ const unsubscribeClose = deps.on("close", onClose);
542
663
  if (deps.getSize() > 0) onOpen();
543
664
  return () => {
544
665
  unsubscribeOpen();
545
666
  unsubscribeClose();
546
- teardownEntry();
667
+ if (handle) {
668
+ popBackMarker(handle);
669
+ handle = null;
670
+ }
547
671
  };
548
672
  }
549
673
  function installRouteChange(deps) {
550
- if (typeof window === "undefined" || typeof history === "undefined") {
551
- return () => {
552
- };
553
- }
554
- const onChange = () => {
674
+ return subscribeRouteChange(() => {
555
675
  if (deps.isDestroyed() || deps.getSize() <= 0) return;
556
676
  void deps.close();
557
- };
558
- const wrap = (key) => {
559
- const original = history[key];
560
- const patched = function(...args) {
561
- original.apply(this, args);
562
- onChange();
563
- };
564
- history[key] = patched;
565
- return () => {
566
- if (history[key] === patched) {
567
- history[key] = original;
568
- }
569
- };
570
- };
571
- window.addEventListener("popstate", onChange);
572
- const restorePush = wrap("pushState");
573
- const restoreReplace = wrap("replaceState");
574
- return () => {
575
- window.removeEventListener("popstate", onChange);
576
- restorePush();
577
- restoreReplace();
578
- };
677
+ });
579
678
  }
580
679
 
581
680
  // src/core/features/content-swipe.ts
@@ -2428,7 +2527,7 @@ var matchesRange = (def, progress) => {
2428
2527
  };
2429
2528
  function installScrimStages(deps, opts) {
2430
2529
  const doc = deps.host.ownerDocument;
2431
- const entries = opts.stages.map((def) => {
2530
+ const entries2 = opts.stages.map((def) => {
2432
2531
  const wrapper = doc.createElement("div");
2433
2532
  wrapper.className = "bs-scrim-stage";
2434
2533
  const ws = wrapper.style;
@@ -2449,9 +2548,9 @@ function installScrimStages(deps, opts) {
2449
2548
  const resolveActive = () => {
2450
2549
  const state = deps.getState();
2451
2550
  if (state.size === 0) {
2452
- return entries.find((e) => matchesId(e.def, state.activeId)) ?? null;
2551
+ return entries2.find((e) => matchesId(e.def, state.activeId)) ?? null;
2453
2552
  }
2454
- return entries.find((e) => matchesId(e.def, state.activeId)) ?? entries.find((e) => matchesRange(e.def, state.progress)) ?? null;
2553
+ return entries2.find((e) => matchesId(e.def, state.activeId)) ?? entries2.find((e) => matchesRange(e.def, state.progress)) ?? null;
2455
2554
  };
2456
2555
  const hide = (entry, animate) => {
2457
2556
  entry.inFlight?.cancel();
@@ -2500,13 +2599,13 @@ function installScrimStages(deps, opts) {
2500
2599
  deps.on("open", () => update(true)),
2501
2600
  deps.on("close", () => update(true))
2502
2601
  ];
2503
- if (entries.some((e) => e.def.forRange)) {
2602
+ if (entries2.some((e) => e.def.forRange)) {
2504
2603
  offs.push(deps.on("progress", () => update(true)));
2505
2604
  }
2506
2605
  update(false);
2507
2606
  return () => {
2508
2607
  offs.forEach((off) => off());
2509
- for (const entry of entries) {
2608
+ for (const entry of entries2) {
2510
2609
  entry.inFlight?.cancel();
2511
2610
  entry.inFlight = null;
2512
2611
  if (entry.wrapper.parentNode) {
@@ -2765,8 +2864,8 @@ var BottomSheetEngine = class {
2765
2864
  this.attach();
2766
2865
  this.registerInStack();
2767
2866
  if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
2768
- const io = new IntersectionObserver((entries) => {
2769
- for (const entry of entries) {
2867
+ const io = new IntersectionObserver((entries2) => {
2868
+ for (const entry of entries2) {
2770
2869
  if (!entry.isIntersecting) continue;
2771
2870
  if (this.destroyed) return;
2772
2871
  this.snaps.recompute();
@@ -3483,9 +3582,9 @@ var BottomSheetEngine = class {
3483
3582
  return;
3484
3583
  }
3485
3584
  if (this.emitBeforeSnap(target, previousId)) {
3486
- const restore = this.snaps.findById(previousId);
3487
- if (restore) {
3488
- void this.animation.animateTo(restore.size, 0);
3585
+ const restore2 = this.snaps.findById(previousId);
3586
+ if (restore2) {
3587
+ void this.animation.animateTo(restore2.size, 0);
3489
3588
  }
3490
3589
  return;
3491
3590
  }