@surdeddd/bottom-sheet 0.3.0 → 0.4.1

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 (45) hide show
  1. package/dist/{BottomSheetEngine-CAymrH-P.d.cts → BottomSheetEngine-BJrH7qY3.d.cts} +39 -3
  2. package/dist/{BottomSheetEngine-DcqcuudN.d.ts → BottomSheetEngine-L05jGZvU.d.ts} +39 -3
  3. package/dist/element.cjs +490 -91
  4. package/dist/element.d.cts +23 -4
  5. package/dist/element.d.ts +23 -4
  6. package/dist/element.iife.global.js +2 -2
  7. package/dist/element.js +490 -91
  8. package/dist/index.cjs +347 -80
  9. package/dist/index.d.cts +3 -2
  10. package/dist/index.d.ts +3 -2
  11. package/dist/index.js +347 -80
  12. package/dist/integrations/formik.d.cts +1 -1
  13. package/dist/integrations/formik.d.ts +1 -1
  14. package/dist/integrations/react-hook-form.d.cts +1 -1
  15. package/dist/integrations/react-hook-form.d.ts +1 -1
  16. package/dist/overlay.cjs +13 -2
  17. package/dist/overlay.js +13 -2
  18. package/dist/preact.d.cts +1 -1
  19. package/dist/preact.d.ts +1 -1
  20. package/dist/qwik.cjs +358 -81
  21. package/dist/qwik.d.cts +4 -2
  22. package/dist/qwik.d.ts +4 -2
  23. package/dist/qwik.js +358 -81
  24. package/dist/react.cjs +451 -89
  25. package/dist/react.d.cts +29 -4
  26. package/dist/react.d.ts +29 -4
  27. package/dist/react.js +451 -89
  28. package/dist/solid.cjs +347 -80
  29. package/dist/solid.d.cts +38 -2
  30. package/dist/solid.d.ts +38 -2
  31. package/dist/solid.js +347 -80
  32. package/dist/solid.source.jsx +347 -80
  33. package/dist/styles.css +68 -55
  34. package/dist/svelte-core.cjs +352 -80
  35. package/dist/svelte-core.js +352 -80
  36. package/dist/svelte-src/BottomSheet.svelte +113 -15
  37. package/dist/svelte.cjs +474 -133
  38. package/dist/svelte.d.cts +21 -0
  39. package/dist/svelte.d.ts +21 -0
  40. package/dist/svelte.js +474 -133
  41. package/dist/vue.cjs +610 -109
  42. package/dist/vue.d.cts +51 -2
  43. package/dist/vue.d.ts +51 -2
  44. package/dist/vue.js +611 -110
  45. package/package.json +8 -8
package/dist/qwik.cjs CHANGED
@@ -40,6 +40,15 @@ var SheetStack = class {
40
40
  size() {
41
41
  return this.entries.length;
42
42
  }
43
+ depthOf(id) {
44
+ const open = [];
45
+ for (const entry of this.entries) {
46
+ if (!entry.isOpen || entry.isOpen()) open.push(entry);
47
+ }
48
+ const idx = open.findIndex((e) => e.id === id);
49
+ if (idx === -1) return 0;
50
+ return open.length - 1 - idx;
51
+ }
43
52
  clear() {
44
53
  this.entries = [];
45
54
  }
@@ -158,7 +167,9 @@ var PERCENT = /^(-?\d+(?:\.\d+)?)%$/;
158
167
  var resolveSnap = (point, mode, measureFit) => {
159
168
  if (typeof point === "number") return Math.max(0, point);
160
169
  if (point === "full") return viewportSize(mode);
161
- if (point === "fit") return Math.max(0, measureFit?.() ?? 0);
170
+ if (point === "fit" || point === "content") {
171
+ return Math.max(0, measureFit?.() ?? 0);
172
+ }
162
173
  const pctMatch = point.match(PERCENT);
163
174
  if (pctMatch) {
164
175
  const pct = parseFloat(pctMatch[1]) / 100;
@@ -395,6 +406,42 @@ function notifyLinkedSheets(sheets, self) {
395
406
  }
396
407
 
397
408
  // src/core/features/route.ts
409
+ var closers = [];
410
+ var handlerInstalled = false;
411
+ var suppress = 0;
412
+ var ensureHandler = () => {
413
+ if (handlerInstalled || typeof window === "undefined") return;
414
+ handlerInstalled = true;
415
+ window.addEventListener("popstate", () => {
416
+ if (suppress > 0) {
417
+ suppress -= 1;
418
+ return;
419
+ }
420
+ let target = null;
421
+ for (let i = closers.length - 1; i >= 0; i -= 1) {
422
+ const c = closers[i];
423
+ if (!c.isOpen()) continue;
424
+ if (!target) target = c;
425
+ if (c.isTop()) {
426
+ target = c;
427
+ break;
428
+ }
429
+ }
430
+ if (!target) return;
431
+ target.consumed = true;
432
+ const idx = closers.indexOf(target);
433
+ if (idx !== -1) closers.splice(idx, 1);
434
+ target.close();
435
+ });
436
+ };
437
+ var programmaticBack = () => {
438
+ suppress += 1;
439
+ try {
440
+ history.back();
441
+ } catch {
442
+ suppress = Math.max(0, suppress - 1);
443
+ }
444
+ };
398
445
  function installRoute(deps) {
399
446
  if (typeof window === "undefined") {
400
447
  return () => {
@@ -404,82 +451,81 @@ function installRoute(deps) {
404
451
  return () => {
405
452
  };
406
453
  }
407
- let routePushed = false;
408
- let closeOnBackPushed = false;
409
- let detachPopstate = null;
410
- const popOurMarker = (key, expected) => {
411
- const state = history.state;
412
- if (state && state[key] === expected) {
413
- try {
414
- history.back();
415
- } catch {
416
- }
454
+ let pushed = false;
455
+ let closer = null;
456
+ const teardownEntry = () => {
457
+ if (closer) {
458
+ const idx = closers.indexOf(closer);
459
+ if (idx !== -1) closers.splice(idx, 1);
460
+ }
461
+ const wasConsumed = closer?.consumed ?? false;
462
+ closer = null;
463
+ if (pushed && !wasConsumed) {
464
+ pushed = false;
465
+ programmaticBack();
466
+ } else {
467
+ pushed = false;
417
468
  }
418
469
  };
419
470
  const onOpen = () => {
420
- if (deps.routedTo && !detachPopstate) {
421
- const target = deps.routedTo;
422
- try {
423
- history.pushState({ __bsRouted: target }, "", target);
424
- routePushed = true;
425
- } catch {
426
- }
427
- const onPop = (event) => {
428
- if (deps.isDestroyed()) return;
429
- const state = event.state;
430
- if ((!state || state.__bsRouted !== target) && deps.getSize() > 0) {
431
- routePushed = false;
432
- void deps.close();
433
- }
434
- };
435
- window.addEventListener("popstate", onPop);
436
- detachPopstate = () => window.removeEventListener("popstate", onPop);
437
- } else if (deps.closeOnBack && !detachPopstate) {
438
- try {
471
+ if (closer) return;
472
+ closer = {
473
+ isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
474
+ isTop: () => deps.isTopSheet(),
475
+ close: () => void deps.close(),
476
+ consumed: false
477
+ };
478
+ ensureHandler();
479
+ closers.push(closer);
480
+ try {
481
+ if (deps.routedTo !== void 0) {
482
+ history.pushState({ __bsRouted: deps.sheetId }, "", deps.routedTo);
483
+ } else {
439
484
  history.pushState({ __bsSheet: deps.sheetId }, "");
440
- closeOnBackPushed = true;
441
- } catch {
442
485
  }
443
- const onPop = () => {
444
- if (deps.isDestroyed()) return;
445
- if (deps.getSize() > 0 && deps.isTopSheet()) {
446
- const state = history.state;
447
- if (state?.__bsSheet !== deps.sheetId) closeOnBackPushed = false;
448
- void deps.close();
449
- }
450
- };
451
- window.addEventListener("popstate", onPop);
452
- detachPopstate = () => window.removeEventListener("popstate", onPop);
453
- }
454
- };
455
- const onClose = () => {
456
- detachPopstate?.();
457
- detachPopstate = null;
458
- if (routePushed) {
459
- routePushed = false;
460
- if (deps.routedTo !== void 0) popOurMarker("__bsRouted", deps.routedTo);
461
- }
462
- if (closeOnBackPushed) {
463
- closeOnBackPushed = false;
464
- popOurMarker("__bsSheet", deps.sheetId);
486
+ pushed = true;
487
+ } catch {
488
+ pushed = false;
465
489
  }
466
490
  };
467
491
  const unsubscribeOpen = deps.on("open", onOpen);
468
- const unsubscribeClose = deps.on("close", onClose);
492
+ const unsubscribeClose = deps.on("close", teardownEntry);
469
493
  if (deps.getSize() > 0) onOpen();
470
494
  return () => {
471
495
  unsubscribeOpen();
472
496
  unsubscribeClose();
473
- detachPopstate?.();
474
- detachPopstate = null;
475
- if (routePushed) {
476
- routePushed = false;
477
- if (deps.routedTo !== void 0) popOurMarker("__bsRouted", deps.routedTo);
478
- }
479
- if (closeOnBackPushed) {
480
- closeOnBackPushed = false;
481
- popOurMarker("__bsSheet", deps.sheetId);
482
- }
497
+ teardownEntry();
498
+ };
499
+ }
500
+ function installRouteChange(deps) {
501
+ if (typeof window === "undefined" || typeof history === "undefined") {
502
+ return () => {
503
+ };
504
+ }
505
+ const onChange = () => {
506
+ if (deps.isDestroyed() || deps.getSize() <= 0) return;
507
+ void deps.close();
508
+ };
509
+ const wrap = (key) => {
510
+ const original = history[key];
511
+ const patched = function(...args) {
512
+ original.apply(this, args);
513
+ onChange();
514
+ };
515
+ history[key] = patched;
516
+ return () => {
517
+ if (history[key] === patched) {
518
+ history[key] = original;
519
+ }
520
+ };
521
+ };
522
+ window.addEventListener("popstate", onChange);
523
+ const restorePush = wrap("pushState");
524
+ const restoreReplace = wrap("replaceState");
525
+ return () => {
526
+ window.removeEventListener("popstate", onChange);
527
+ restorePush();
528
+ restoreReplace();
483
529
  };
484
530
  }
485
531
 
@@ -787,6 +833,7 @@ function applyOverlayPosition(ws, mode, position, inset) {
787
833
 
788
834
  // src/core/controllers/scrim-controller.ts
789
835
  var VALID_CSS_LENGTH = /^-?\d+(?:\.\d+)?(?:px|em|rem|%)$/;
836
+ var DEFAULT_SCRIM_DIM = "rgba(0, 0, 0, 0.4)";
790
837
  var ScrimController = class {
791
838
  constructor(deps, opts) {
792
839
  __publicField(this, "screenComponent");
@@ -825,9 +872,11 @@ var ScrimController = class {
825
872
  this.backdropRange = opts.backdropRange ?? preset?.range ?? [0, 1];
826
873
  this.screenRange = opts.screenRange ?? preset?.range ?? [0, 1];
827
874
  this.scrimTapToCloseEnabled = opts.scrimTapToClose ?? false;
875
+ const explicitColor = opts.scrimColor ?? preset?.color;
876
+ const effectiveColor = explicitColor ?? (this.scrimMode !== "off" && !this.backdrop ? DEFAULT_SCRIM_DIM : void 0);
828
877
  if (this.screenComponent) {
829
878
  this.applyScrimStyles({
830
- color: opts.scrimColor ?? preset?.color,
879
+ color: effectiveColor,
831
880
  blur: opts.scrimBlur ?? preset?.blur,
832
881
  interactive: opts.scrimInteractive ?? preset?.interactive ?? false
833
882
  });
@@ -1601,7 +1650,7 @@ var LifecycleController = class {
1601
1650
  this.releaseScrollLock = null;
1602
1651
  this.inertSiblings.remove();
1603
1652
  if (this.returnFocus) {
1604
- const target = typeof this.returnFocus === "function" ? this.returnFocus() : this.returnFocus;
1653
+ const target = typeof this.returnFocus === "function" ? this.returnFocus() : typeof this.returnFocus === "string" ? typeof document !== "undefined" ? document.querySelector(this.returnFocus) : null : this.returnFocus;
1605
1654
  target?.focus?.();
1606
1655
  }
1607
1656
  }
@@ -1768,6 +1817,7 @@ var GestureController = class {
1768
1817
  __publicField(this, "dragStartSize", 0);
1769
1818
  __publicField(this, "currentPointerKind", "touch");
1770
1819
  __publicField(this, "keyboardDismissed", false);
1820
+ __publicField(this, "dragSuppressed", false);
1771
1821
  __publicField(this, "dragPayload", { size: 0, delta: 0 });
1772
1822
  this.deps = deps;
1773
1823
  }
@@ -1778,6 +1828,11 @@ var GestureController = class {
1778
1828
  if (this.detach) return this.detach;
1779
1829
  this.detach = installGestures(this.deps.handle, this.deps.mode, {
1780
1830
  onStart: (_coord, kind) => {
1831
+ if (this.deps.getDisableDrag?.()) {
1832
+ this.dragSuppressed = true;
1833
+ return;
1834
+ }
1835
+ this.dragSuppressed = false;
1781
1836
  this.deps.cancelAnimation();
1782
1837
  this.isDragging_ = true;
1783
1838
  this.dragStartSize = this.deps.getDragContext().size;
@@ -1788,6 +1843,7 @@ var GestureController = class {
1788
1843
  this.deps.emit("dragstart", { size: this.dragStartSize });
1789
1844
  },
1790
1845
  onMove: (delta) => {
1846
+ if (this.dragSuppressed) return;
1791
1847
  const ctx = this.deps.getDragContext();
1792
1848
  const { min, max } = ctx.range;
1793
1849
  const maxAxis = ctx.maxAxisSize;
@@ -1811,6 +1867,10 @@ var GestureController = class {
1811
1867
  }
1812
1868
  },
1813
1869
  onEnd: (delta, velocity, kind) => {
1870
+ if (this.dragSuppressed) {
1871
+ this.dragSuppressed = false;
1872
+ return;
1873
+ }
1814
1874
  this.isDragging_ = false;
1815
1875
  this.keyboardDismissed = false;
1816
1876
  this.deps.getRoot()?.removeAttribute("data-dragging");
@@ -1821,6 +1881,10 @@ var GestureController = class {
1821
1881
  this.deps.settleAfterDrag(delta, velocity, kind);
1822
1882
  },
1823
1883
  onCancel: () => {
1884
+ if (this.dragSuppressed) {
1885
+ this.dragSuppressed = false;
1886
+ return;
1887
+ }
1824
1888
  this.isDragging_ = false;
1825
1889
  this.keyboardDismissed = false;
1826
1890
  this.deps.getRoot()?.removeAttribute("data-dragging");
@@ -2200,6 +2264,12 @@ function resolveEngineOptions(opts, extras) {
2200
2264
  dragThreshold: opts.dragThreshold ?? DEFAULT_DRAG_THRESHOLD,
2201
2265
  rubberBandEnabled: opts.rubberBand ?? true,
2202
2266
  closeOnBack: opts.closeOnBack ?? false,
2267
+ persistent: opts.persistent ?? false,
2268
+ disableClose: opts.disableClose ?? false,
2269
+ disableDrag: opts.disableDrag ?? false,
2270
+ closeOnRouteChange: opts.closeOnRouteChange ?? false,
2271
+ radius: opts.radius,
2272
+ maxHeight: opts.maxHeight,
2203
2273
  initialAllowed,
2204
2274
  initialId,
2205
2275
  scrim: {
@@ -2226,7 +2296,8 @@ function resolveEngineOptions(opts, extras) {
2226
2296
  closeOnEscape: opts.closeOnEscape,
2227
2297
  lockBodyScroll: opts.lockBodyScroll,
2228
2298
  inertSiblings: opts.inertSiblings,
2229
- shouldApplyInertSiblings: extras?.shouldApplyInertSiblings
2299
+ shouldApplyInertSiblings: extras?.shouldApplyInertSiblings,
2300
+ returnFocus: opts.returnFocusTo
2230
2301
  }
2231
2302
  };
2232
2303
  }
@@ -2271,6 +2342,11 @@ var BottomSheetEngine = class {
2271
2342
  __publicField(this, "lifecycle");
2272
2343
  __publicField(this, "closeOnBack");
2273
2344
  __publicField(this, "routedTo");
2345
+ __publicField(this, "persistent");
2346
+ __publicField(this, "disableCloseFlag");
2347
+ __publicField(this, "disableDragFlag");
2348
+ __publicField(this, "closeOnRouteChange");
2349
+ __publicField(this, "maxHeightCap");
2274
2350
  __publicField(this, "snapPointsRaw");
2275
2351
  __publicField(this, "snaps");
2276
2352
  __publicField(this, "activeId");
@@ -2283,6 +2359,7 @@ var BottomSheetEngine = class {
2283
2359
  __publicField(this, "sizeWriteSentinel", new WriteSentinel());
2284
2360
  __publicField(this, "progressWriteSentinel", new WriteSentinel());
2285
2361
  __publicField(this, "isTopSheet", true);
2362
+ __publicField(this, "opening", false);
2286
2363
  __publicField(this, "progressPayload", {
2287
2364
  value: 0,
2288
2365
  size: 0
@@ -2339,7 +2416,8 @@ var BottomSheetEngine = class {
2339
2416
  void this.snapTo(id);
2340
2417
  },
2341
2418
  close: () => {
2342
- void this.close();
2419
+ if (!this.canDismiss()) return;
2420
+ void this.close("backdrop");
2343
2421
  }
2344
2422
  },
2345
2423
  resolved.scrim
@@ -2363,6 +2441,10 @@ var BottomSheetEngine = class {
2363
2441
  );
2364
2442
  this.closeOnBack = resolved.closeOnBack;
2365
2443
  this.routedTo = opts.routedTo;
2444
+ this.persistent = resolved.persistent;
2445
+ this.disableCloseFlag = resolved.disableClose;
2446
+ this.disableDragFlag = resolved.disableDrag;
2447
+ this.closeOnRouteChange = resolved.closeOnRouteChange;
2366
2448
  this.stackEffectEnabled = opts.stackEffect ?? false;
2367
2449
  this.snapPointsRaw = opts.snapPoints;
2368
2450
  this.persistKey = opts.persistKey;
@@ -2376,7 +2458,7 @@ var BottomSheetEngine = class {
2376
2458
  this.snapPointsRaw,
2377
2459
  resolved.initialAllowed,
2378
2460
  this.mode,
2379
- () => layoutAxis(this.mode) === "width" ? this.handle.offsetWidth : this.handle.offsetHeight,
2461
+ () => this.measureFitSize(),
2380
2462
  (maxAxisSize) => {
2381
2463
  this.element.style[layoutAxis(this.mode)] = `${maxAxisSize}px`;
2382
2464
  }
@@ -2410,6 +2492,19 @@ var BottomSheetEngine = class {
2410
2492
  io.observe(this.element);
2411
2493
  this.teardowns.add(() => io.disconnect());
2412
2494
  }
2495
+ this.installFitObserver();
2496
+ if (resolved.radius !== void 0) this.setRadius(resolved.radius);
2497
+ if (resolved.maxHeight !== void 0) this.setMaxHeight(resolved.maxHeight);
2498
+ this.applyAutoAriaLabelledBy();
2499
+ if (this.closeOnRouteChange) {
2500
+ this.teardowns.add(
2501
+ installRouteChange({
2502
+ isDestroyed: () => this.destroyed,
2503
+ getSize: () => this.size,
2504
+ close: () => this.close()
2505
+ })
2506
+ );
2507
+ }
2413
2508
  if (this.persistKey) {
2414
2509
  this.teardowns.add(installPersist(this, this.persistKey));
2415
2510
  }
@@ -2434,7 +2529,7 @@ var BottomSheetEngine = class {
2434
2529
  isTopSheet: () => this.isTopSheet,
2435
2530
  getSize: () => this.size,
2436
2531
  isDestroyed: () => this.destroyed,
2437
- close: () => this.close(),
2532
+ close: () => this.close("back"),
2438
2533
  on: (event, fn) => this.on(event, fn),
2439
2534
  sheetId: this.id
2440
2535
  })
@@ -2528,6 +2623,10 @@ var BottomSheetEngine = class {
2528
2623
  const previousSize = this.size;
2529
2624
  this.scrollCache.cache(previousId, previousSize, target.size);
2530
2625
  this.activeId = id;
2626
+ if (wasClosed && target.size > 0) {
2627
+ this.opening = true;
2628
+ sheetStack.promote(this.id);
2629
+ }
2531
2630
  if (this.animation.viewTransitionsAvailable) {
2532
2631
  this.currentViewTransition?.skipTransition?.();
2533
2632
  const vt = document.startViewTransition(() => {
@@ -2542,19 +2641,26 @@ var BottomSheetEngine = class {
2542
2641
  } else {
2543
2642
  await this.animation.animateTo(target.size, velocityPxPerMs);
2544
2643
  }
2644
+ this.opening = false;
2545
2645
  externalSignal?.removeEventListener("abort", onExternalAbort);
2546
2646
  if (signal.aborted) return;
2547
2647
  this.scrollCache.restore(id, previousSize, target.size);
2548
2648
  this.updateAriaSlider();
2549
- this.emit("snap", { id, size: target.size });
2649
+ this.emit("snap", {
2650
+ id,
2651
+ size: target.size,
2652
+ progress: this.computeProgress(target.size)
2653
+ });
2550
2654
  if (wasClosed && target.size > 0) {
2551
2655
  this.emit("open", { id });
2552
2656
  this.handleOpen();
2553
2657
  notifyLinkedSheets(this.linkedSheets, this);
2658
+ this.emit("opened", { id });
2554
2659
  }
2555
2660
  if (target.size === 0) {
2556
2661
  this.emit("close", void 0);
2557
2662
  this.handleClose();
2663
+ this.emit("closed", void 0);
2558
2664
  }
2559
2665
  }
2560
2666
  async dragTo(targetSize, velocityOrOpts = 0) {
@@ -2579,11 +2685,74 @@ var BottomSheetEngine = class {
2579
2685
  const target = id ?? this.snaps.getAllowedIds().find((a) => a !== "closed") ?? this.activeId;
2580
2686
  return this.snapTo(target);
2581
2687
  }
2582
- close() {
2688
+ close(reason = "programmatic") {
2583
2689
  if (this.destroyed) return Promise.resolve();
2690
+ if (this.disableCloseFlag) return Promise.resolve();
2691
+ if (this.size > 0 && this.emitBeforeClose(reason)) return Promise.resolve();
2584
2692
  const closedId = this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.snaps.getAllowedIds()[0];
2585
2693
  return this.snapTo(closedId ?? this.activeId);
2586
2694
  }
2695
+ canDismiss() {
2696
+ return !this.persistent && !this.disableCloseFlag && !this.destroyed;
2697
+ }
2698
+ isTop() {
2699
+ return this.isTopSheet;
2700
+ }
2701
+ depth() {
2702
+ return sheetStack.depthOf(this.id);
2703
+ }
2704
+ expand() {
2705
+ if (this.destroyed) return Promise.resolve();
2706
+ const ids = this.allowedIdsBySize();
2707
+ const target = ids[ids.length - 1];
2708
+ if (!target) return Promise.resolve();
2709
+ return this.snapTo(target);
2710
+ }
2711
+ collapse() {
2712
+ if (this.destroyed) return Promise.resolve();
2713
+ const ids = this.allowedIdsBySize();
2714
+ const nonZero = ids.find((id) => (this.snaps.findById(id)?.size ?? 0) > 0);
2715
+ const target = nonZero ?? ids[0];
2716
+ if (!target) return Promise.resolve();
2717
+ return this.snapTo(target);
2718
+ }
2719
+ setRadius(r) {
2720
+ if (this.destroyed) return;
2721
+ this.element.style.setProperty(
2722
+ "--bs-radius",
2723
+ typeof r === "number" ? `${r}px` : r
2724
+ );
2725
+ }
2726
+ setMaxHeight(h) {
2727
+ if (this.destroyed) return;
2728
+ const value = typeof h === "number" ? `${h}px` : h;
2729
+ const axis = layoutAxis(this.mode);
2730
+ this.element.style.setProperty(
2731
+ axis === "height" ? "maxHeight" : "maxWidth",
2732
+ value
2733
+ );
2734
+ if (typeof h === "number") {
2735
+ this.maxHeightCap = h;
2736
+ this.clampToMaxHeight();
2737
+ } else if (typeof window !== "undefined") {
2738
+ const probe2 = document.createElement("div");
2739
+ probe2.style.cssText = `position:absolute;visibility:hidden;pointer-events:none;${axis === "height" ? "height" : "width"}:${value};`;
2740
+ document.body.appendChild(probe2);
2741
+ const measured = axis === "height" ? probe2.offsetHeight : probe2.offsetWidth;
2742
+ probe2.remove();
2743
+ this.maxHeightCap = measured > 0 ? measured : void 0;
2744
+ this.clampToMaxHeight();
2745
+ }
2746
+ }
2747
+ clampToMaxHeight() {
2748
+ if (this.maxHeightCap === void 0) return;
2749
+ if (this.snaps.getMaxAxisSize() > this.maxHeightCap) {
2750
+ this.snaps.setMaxAxisSize(this.maxHeightCap);
2751
+ }
2752
+ if (this.size > this.maxHeightCap && !this.gesture?.isDragging) {
2753
+ this.applySize(this.maxHeightCap);
2754
+ }
2755
+ }
2587
2756
  setAllowed(ids, snap) {
2588
2757
  if (this.destroyed) return;
2589
2758
  this.snaps.setAllowedIds(ids);
@@ -2717,8 +2886,53 @@ var BottomSheetEngine = class {
2717
2886
  }
2718
2887
  this.updateAriaSlider();
2719
2888
  }
2889
+ recompute() {
2890
+ if (this.destroyed) return;
2891
+ this.snaps.recompute();
2892
+ this.scrim.invalidateOpacityCache();
2893
+ if (this.gesture?.isDragging) return;
2894
+ const current = this.snaps.findById(this.activeId);
2895
+ if (current) {
2896
+ this.size = current.size;
2897
+ this.applySize(this.size);
2898
+ this.updateAriaSlider();
2899
+ }
2900
+ }
2901
+ measureFitSize() {
2902
+ const vertical = layoutAxis(this.mode) === "height";
2903
+ const handleSize = vertical ? this.handle.offsetHeight : this.handle.offsetWidth;
2904
+ const content = this.scrollContainer;
2905
+ const natural = content ? handleSize + (vertical ? content.scrollHeight : content.scrollWidth) : handleSize;
2906
+ if (typeof window === "undefined") return natural;
2907
+ const viewport = vertical ? window.innerHeight : window.innerWidth;
2908
+ return viewport > 0 ? Math.min(natural, viewport) : natural;
2909
+ }
2910
+ installFitObserver() {
2911
+ if (typeof ResizeObserver === "undefined") return;
2912
+ if (!this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"))
2913
+ return;
2914
+ const targets = [this.handle];
2915
+ if (this.scrollContainer && this.scrollContainer !== this.handle) {
2916
+ targets.push(this.scrollContainer);
2917
+ }
2918
+ let raf = 0;
2919
+ const ro = new ResizeObserver(() => {
2920
+ if (raf) return;
2921
+ raf = requestAnimationFrame(() => {
2922
+ raf = 0;
2923
+ if (this.destroyed || this.gesture?.isDragging) return;
2924
+ this.recompute();
2925
+ });
2926
+ });
2927
+ for (const t of targets) ro.observe(t);
2928
+ this.teardowns.add(() => {
2929
+ ro.disconnect();
2930
+ if (raf) cancelAnimationFrame(raf);
2931
+ });
2932
+ }
2720
2933
  destroy() {
2721
2934
  this.destroyed = true;
2935
+ this.opening = false;
2722
2936
  this.currentAbort.abort();
2723
2937
  this.currentViewTransition?.skipTransition?.();
2724
2938
  this.currentViewTransition = null;
@@ -2768,6 +2982,36 @@ var BottomSheetEngine = class {
2768
2982
  frozen = true;
2769
2983
  return cancelled;
2770
2984
  }
2985
+ emitBeforeClose(reason) {
2986
+ let cancelled = false;
2987
+ let frozen = false;
2988
+ this.emit("before-close", {
2989
+ reason,
2990
+ cancel: () => {
2991
+ if (frozen) {
2992
+ console.warn(
2993
+ "[BottomSheet] before-close.cancel() called asynchronously \u2014 ignored. cancel() must be invoked synchronously inside the listener."
2994
+ );
2995
+ return;
2996
+ }
2997
+ cancelled = true;
2998
+ }
2999
+ });
3000
+ frozen = true;
3001
+ return cancelled;
3002
+ }
3003
+ applyAutoAriaLabelledBy() {
3004
+ if (typeof document === "undefined") return;
3005
+ if (!this.lifecycle.focusTrapEnabled) return;
3006
+ if (this.element.getAttribute("aria-labelledby")) return;
3007
+ const scope = this.handle ?? this.element;
3008
+ const titled = scope.querySelector("[data-bs-title]") ?? scope.querySelector("h1,h2,h3,h4,h5,h6");
3009
+ if (!titled) return;
3010
+ if (!titled.id) {
3011
+ titled.id = nextInstanceId("bs-title");
3012
+ }
3013
+ this.element.setAttribute("aria-labelledby", titled.id);
3014
+ }
2771
3015
  recomputeSnaps() {
2772
3016
  const seen = /* @__PURE__ */ new Set();
2773
3017
  for (const p of this.snapPointsRaw) {
@@ -2803,11 +3047,8 @@ var BottomSheetEngine = class {
2803
3047
  },
2804
3048
  setIsTop: (isTop) => {
2805
3049
  this.isTopSheet = isTop;
2806
- if (this.backdrop) {
2807
- this.backdrop.style.display = isTop ? "" : "none";
2808
- }
2809
3050
  },
2810
- isOpen: () => this.size > 0,
3051
+ isOpen: () => this.size > 0 || this.opening,
2811
3052
  setDepth: (depth) => this.applyStackDepth(depth)
2812
3053
  }));
2813
3054
  }
@@ -2839,6 +3080,7 @@ var BottomSheetEngine = class {
2839
3080
  buf.rubberBandEnabled = this.rubberBandEnabled;
2840
3081
  return buf;
2841
3082
  },
3083
+ getDisableDrag: () => this.disableDragFlag,
2842
3084
  cancelAnimation: () => this.animation.cancel(),
2843
3085
  applySize: (size) => this.applySize(size),
2844
3086
  animateTo: (size, velocity) => this.animation.animateTo(size, velocity),
@@ -2918,8 +3160,9 @@ var BottomSheetEngine = class {
2918
3160
  if (this.lifecycle.closeOnEscape) {
2919
3161
  const onKey = (e) => {
2920
3162
  if (this.destroyed || e.defaultPrevented) return;
3163
+ if (!this.canDismiss()) return;
2921
3164
  if (e.key === "Escape" && this.isTopSheet && this.size > 0) {
2922
- void this.close();
3165
+ void this.close("escape");
2923
3166
  }
2924
3167
  };
2925
3168
  document.addEventListener("keydown", onKey);
@@ -2982,20 +3225,31 @@ var BottomSheetEngine = class {
2982
3225
  const previousSnapSize = this.snaps.findById(previousId)?.size;
2983
3226
  this.scrollCache.cache(previousId, previousSize, target.size);
2984
3227
  this.activeId = target.id;
3228
+ if (previousSnapSize === 0 && target.size > 0) {
3229
+ this.opening = true;
3230
+ sheetStack.promote(this.id);
3231
+ }
2985
3232
  void this.animation.animateTo(target.size, velocity).then(() => {
3233
+ this.opening = false;
2986
3234
  if (signal.aborted) return;
2987
3235
  this.scrollCache.restore(target.id, previousSize, target.size);
2988
3236
  this.updateAriaSlider();
2989
- this.emit("snap", { id: target.id, size: target.size });
3237
+ this.emit("snap", {
3238
+ id: target.id,
3239
+ size: target.size,
3240
+ progress: this.computeProgress(target.size)
3241
+ });
2990
3242
  this.haptic();
2991
3243
  if (previousSnapSize === 0 && target.size > 0) {
2992
3244
  this.emit("open", { id: target.id });
2993
3245
  this.handleOpen();
2994
3246
  notifyLinkedSheets(this.linkedSheets, this);
3247
+ this.emit("opened", { id: target.id });
2995
3248
  }
2996
3249
  if (target.size === 0) {
2997
3250
  this.emit("close", void 0);
2998
3251
  this.handleClose();
3252
+ this.emit("closed", void 0);
2999
3253
  }
3000
3254
  });
3001
3255
  }
@@ -3020,6 +3274,9 @@ var BottomSheetEngine = class {
3020
3274
  if (this.anchorHost && this.anchorHost !== this.scrimParent) {
3021
3275
  this.anchorHost.style.setProperty("--bs-size", `${size}px`);
3022
3276
  }
3277
+ if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
3278
+ this.rootEl.style.setProperty("--bs-size", `${size}px`);
3279
+ }
3023
3280
  }
3024
3281
  const progress = this.computeProgress(size);
3025
3282
  const progressChanged = this.progressWriteSentinel.shouldWrite(
@@ -3031,6 +3288,9 @@ var BottomSheetEngine = class {
3031
3288
  if (this.anchorHost) {
3032
3289
  this.anchorHost.style.setProperty("--bs-progress", String(progress));
3033
3290
  }
3291
+ if (this.rootEl && this.rootEl !== this.anchorHost) {
3292
+ this.rootEl.style.setProperty("--bs-progress", String(progress));
3293
+ }
3034
3294
  }
3035
3295
  this.scrim.applyOpacity(progress, progressChanged);
3036
3296
  if (progressChanged && this.bus.listenerCount("progress") > 0) {
@@ -3064,17 +3324,24 @@ var BottomSheetEngine = class {
3064
3324
  const target = this.snaps.findById(this.activeId);
3065
3325
  if (!target) return;
3066
3326
  this.updateAriaSlider();
3067
- this.emit("snap", { id: target.id, size: target.size });
3327
+ this.emit("snap", {
3328
+ id: target.id,
3329
+ size: target.size,
3330
+ progress: this.computeProgress(target.size)
3331
+ });
3068
3332
  if (target.size > 0 && !this.lifecycle.isInstalled) {
3069
3333
  this.emit("open", { id: target.id });
3070
3334
  this.handleOpen();
3071
3335
  notifyLinkedSheets(this.linkedSheets, this);
3336
+ this.emit("opened", { id: target.id });
3072
3337
  } else if (target.size === 0 && this.lifecycle.isInstalled) {
3073
3338
  this.emit("close", void 0);
3074
3339
  this.handleClose();
3340
+ this.emit("closed", void 0);
3075
3341
  }
3076
3342
  }
3077
3343
  handleClose() {
3344
+ this.opening = false;
3078
3345
  this.lifecycle.release();
3079
3346
  sheetStack.update();
3080
3347
  }
@@ -3118,7 +3385,9 @@ var BottomSheet = qwik.component$((props) => {
3118
3385
  closeOnBack: props.closeOnBack,
3119
3386
  lockBodyScroll: props.lockBodyScroll,
3120
3387
  rubberBand: props.rubberBand,
3121
- backdropRange: props.backdropRange
3388
+ backdropRange: props.backdropRange,
3389
+ radius: props.radius,
3390
+ maxHeight: props.maxHeight
3122
3391
  };
3123
3392
  const engine = new BottomSheetEngine(engineOpts);
3124
3393
  engineStore.engine = qwik.noSerialize(engine);
@@ -3153,6 +3422,14 @@ var BottomSheet = qwik.component$((props) => {
3153
3422
  allowed
3154
3423
  );
3155
3424
  });
3425
+ qwik.useTask$(({ track }) => {
3426
+ const radius = track(() => props.radius);
3427
+ const maxHeight = track(() => props.maxHeight);
3428
+ const engine = engineStore.engine;
3429
+ if (!engine) return;
3430
+ if (radius !== void 0) engine.setRadius(radius);
3431
+ if (maxHeight !== void 0) engine.setMaxHeight(maxHeight);
3432
+ });
3156
3433
  const showBackdrop = props.backdrop !== false;
3157
3434
  const mode = props.mode ?? "bottom";
3158
3435
  const ariaLabel = props.ariaLabel ?? "Bottom sheet";