@surdeddd/bottom-sheet 0.2.0 → 0.4.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.
Files changed (49) hide show
  1. package/README.md +51 -21
  2. package/dist/{BottomSheetEngine-CIT9Htti.d.cts → BottomSheetEngine-BJrH7qY3.d.cts} +105 -3
  3. package/dist/{BottomSheetEngine-Df9MwBbm.d.ts → BottomSheetEngine-L05jGZvU.d.ts} +105 -3
  4. package/dist/element.cjs +1170 -196
  5. package/dist/element.d.cts +29 -5
  6. package/dist/element.d.ts +29 -5
  7. package/dist/element.iife.global.js +2 -2
  8. package/dist/element.js +1170 -196
  9. package/dist/index.cjs +1051 -220
  10. package/dist/index.d.cts +18 -3
  11. package/dist/index.d.ts +18 -3
  12. package/dist/index.js +1049 -221
  13. package/dist/integrations/formik.d.cts +1 -1
  14. package/dist/integrations/formik.d.ts +1 -1
  15. package/dist/integrations/react-hook-form.d.cts +1 -1
  16. package/dist/integrations/react-hook-form.d.ts +1 -1
  17. package/dist/overlay.cjs +181 -37
  18. package/dist/overlay.d.cts +13 -0
  19. package/dist/overlay.d.ts +13 -0
  20. package/dist/overlay.js +181 -37
  21. package/dist/preact.d.cts +1 -1
  22. package/dist/preact.d.ts +1 -1
  23. package/dist/qwik.cjs +966 -195
  24. package/dist/qwik.d.cts +4 -2
  25. package/dist/qwik.d.ts +4 -2
  26. package/dist/qwik.js +967 -196
  27. package/dist/react.cjs +1242 -272
  28. package/dist/react.d.cts +47 -5
  29. package/dist/react.d.ts +47 -5
  30. package/dist/react.js +1242 -272
  31. package/dist/solid.cjs +992 -236
  32. package/dist/solid.d.cts +299 -4
  33. package/dist/solid.d.ts +299 -4
  34. package/dist/solid.js +993 -237
  35. package/dist/solid.source.jsx +3476 -0
  36. package/dist/styles.css +67 -66
  37. package/dist/svelte-core.cjs +3415 -0
  38. package/dist/svelte-core.js +3413 -0
  39. package/dist/svelte-src/BottomSheet.svelte +308 -0
  40. package/dist/svelte-src/index.js +2 -0
  41. package/dist/svelte.cjs +1034 -207
  42. package/dist/svelte.d.cts +121 -0
  43. package/dist/svelte.d.ts +28 -3
  44. package/dist/svelte.js +1035 -208
  45. package/dist/vue.cjs +1191 -205
  46. package/dist/vue.d.cts +127 -0
  47. package/dist/vue.d.ts +57 -4
  48. package/dist/vue.js +1192 -206
  49. package/package.json +105 -45
@@ -1,4 +1,4 @@
1
- import { d as SheetEventMap } from '../BottomSheetEngine-CIT9Htti.cjs';
1
+ import { e as SheetEventMap } from '../BottomSheetEngine-BJrH7qY3.cjs';
2
2
  import '../transform-jVfAikE9.cjs';
3
3
 
4
4
  type FormikStateLike = {
@@ -1,4 +1,4 @@
1
- import { d as SheetEventMap } from '../BottomSheetEngine-Df9MwBbm.js';
1
+ import { e as SheetEventMap } from '../BottomSheetEngine-L05jGZvU.js';
2
2
  import '../transform-jVfAikE9.js';
3
3
 
4
4
  type FormikStateLike = {
@@ -1,4 +1,4 @@
1
- import { d as SheetEventMap } from '../BottomSheetEngine-CIT9Htti.cjs';
1
+ import { e as SheetEventMap } from '../BottomSheetEngine-BJrH7qY3.cjs';
2
2
  import '../transform-jVfAikE9.cjs';
3
3
 
4
4
  type RhfFormStateLike = {
@@ -1,4 +1,4 @@
1
- import { d as SheetEventMap } from '../BottomSheetEngine-Df9MwBbm.js';
1
+ import { e as SheetEventMap } from '../BottomSheetEngine-L05jGZvU.js';
2
2
  import '../transform-jVfAikE9.js';
3
3
 
4
4
  type RhfFormStateLike = {
package/dist/overlay.cjs CHANGED
@@ -22,16 +22,52 @@ var SheetStack = class {
22
22
  this.entries.splice(idx, 1);
23
23
  this.recompute();
24
24
  }
25
+ promote(id) {
26
+ const idx = this.entries.findIndex((e) => e.id === id);
27
+ if (idx === -1) return;
28
+ if (idx !== this.entries.length - 1) {
29
+ const [entry] = this.entries.splice(idx, 1);
30
+ this.entries.push(entry);
31
+ }
32
+ this.recompute();
33
+ }
34
+ update() {
35
+ this.recompute();
36
+ }
25
37
  size() {
26
38
  return this.entries.length;
27
39
  }
40
+ depthOf(id) {
41
+ const open = [];
42
+ for (const entry of this.entries) {
43
+ if (!entry.isOpen || entry.isOpen()) open.push(entry);
44
+ }
45
+ const idx = open.findIndex((e) => e.id === id);
46
+ if (idx === -1) return 0;
47
+ return open.length - 1 - idx;
48
+ }
28
49
  clear() {
29
50
  this.entries = [];
30
51
  }
31
52
  recompute() {
53
+ let top = null;
54
+ const open = [];
55
+ for (const entry of this.entries) {
56
+ if (!entry.isOpen || entry.isOpen()) {
57
+ top = entry;
58
+ open.push(entry);
59
+ }
60
+ }
61
+ if (!top && this.entries.length > 0) {
62
+ top = this.entries[this.entries.length - 1];
63
+ }
32
64
  this.entries.forEach((entry, i) => {
33
65
  entry.setZIndex(BASE_Z + i * STEP);
34
- entry.setIsTop(i === this.entries.length - 1);
66
+ entry.setIsTop(entry === top);
67
+ if (entry.setDepth) {
68
+ const openIdx = open.indexOf(entry);
69
+ entry.setDepth(openIdx === -1 ? 0 : open.length - 1 - openIdx);
70
+ }
35
71
  });
36
72
  }
37
73
  };
@@ -76,7 +112,9 @@ var PERCENT = /^(-?\d+(?:\.\d+)?)%$/;
76
112
  var resolveSnap = (point, mode, measureFit) => {
77
113
  if (typeof point === "number") return Math.max(0, point);
78
114
  if (point === "full") return viewportSize();
79
- if (point === "fit") return Math.max(0, 0);
115
+ if (point === "fit" || point === "content") {
116
+ return Math.max(0, 0);
117
+ }
80
118
  const pctMatch = point.match(PERCENT);
81
119
  if (pctMatch) {
82
120
  const pct = parseFloat(pctMatch[1]) / 100;
@@ -154,9 +192,13 @@ var isVisible = (el) => {
154
192
  var focusables = (root) => Array.from(root.querySelectorAll(FOCUSABLE)).filter(
155
193
  (el) => !el.hasAttribute("inert") && isVisible(el) && !el.matches("[aria-hidden='true']")
156
194
  );
195
+ var trapStack = [];
157
196
  var installFocusTrap = (container, options = {}) => {
158
197
  if (typeof document === "undefined") return () => {
159
198
  };
199
+ const token = {};
200
+ trapStack.push(token);
201
+ const isActive = () => trapStack[trapStack.length - 1] === token;
160
202
  const previouslyFocused = document.activeElement;
161
203
  const focusInitial = () => {
162
204
  const initial = typeof options.initialFocus === "string" ? container.querySelector(options.initialFocus) : options.initialFocus ?? focusables(container)[0] ?? container;
@@ -164,6 +206,7 @@ var installFocusTrap = (container, options = {}) => {
164
206
  };
165
207
  focusInitial();
166
208
  const handleKey = (e) => {
209
+ if (!isActive()) return;
167
210
  if (e.key === "Escape" && options.onEscape) {
168
211
  options.onEscape();
169
212
  return;
@@ -186,6 +229,7 @@ var installFocusTrap = (container, options = {}) => {
186
229
  }
187
230
  };
188
231
  const handleFocusIn = (e) => {
232
+ if (!isActive()) return;
189
233
  const target = e.target;
190
234
  if (target && !container.contains(target)) {
191
235
  const list = focusables(container);
@@ -198,6 +242,8 @@ var installFocusTrap = (container, options = {}) => {
198
242
  return () => {
199
243
  if (released) return;
200
244
  released = true;
245
+ const idx = trapStack.indexOf(token);
246
+ if (idx !== -1) trapStack.splice(idx, 1);
201
247
  document.removeEventListener("keydown", handleKey, true);
202
248
  document.removeEventListener("focusin", handleFocusIn, true);
203
249
  if (previouslyFocused && document.contains(previouslyFocused)) {
@@ -253,11 +299,17 @@ function createInertSiblings(rootProvider) {
253
299
  return {
254
300
  apply() {
255
301
  if (typeof document === "undefined") return;
256
- const root = rootProvider();
257
- const parent = root.parentElement ?? document.body;
302
+ let top = rootProvider();
303
+ while (top.parentElement && top.parentElement !== document.body) {
304
+ top = top.parentElement;
305
+ }
306
+ const parent = top.parentElement ?? document.body;
258
307
  for (const child of Array.from(parent.children)) {
259
- if (child === root) continue;
308
+ if (child === top) continue;
260
309
  if (child.hasAttribute("inert")) continue;
310
+ if (child.classList.contains("bs-backdrop") || child.classList.contains("bs-screen") || child.classList.contains("bs-root")) {
311
+ continue;
312
+ }
261
313
  child.setAttribute("inert", "");
262
314
  tracked.push(child);
263
315
  }
@@ -273,7 +325,6 @@ function createInertSiblings(rootProvider) {
273
325
  var LifecycleController = class {
274
326
  constructor(deps, opts) {
275
327
  __publicField(this, "element");
276
- __publicField(this, "closeFn");
277
328
  __publicField(this, "focusTrapEnabled");
278
329
  __publicField(this, "initialFocus");
279
330
  __publicField(this, "closeOnEscape");
@@ -287,7 +338,6 @@ var LifecycleController = class {
287
338
  __publicField(this, "installed", false);
288
339
  __publicField(this, "destroyed", false);
289
340
  this.element = deps.element;
290
- this.closeFn = deps.close;
291
341
  this.focusTrapEnabled = opts.focusTrap ?? false;
292
342
  this.initialFocus = opts.initialFocus;
293
343
  this.closeOnEscape = opts.closeOnEscape ?? true;
@@ -297,6 +347,9 @@ var LifecycleController = class {
297
347
  this.returnFocus = opts.returnFocus;
298
348
  this.inertSiblings = createInertSiblings(() => this.element);
299
349
  }
350
+ get isInstalled() {
351
+ return this.installed;
352
+ }
300
353
  install() {
301
354
  if (this.destroyed) return;
302
355
  this.installed = true;
@@ -305,8 +358,7 @@ var LifecycleController = class {
305
358
  }
306
359
  if (this.focusTrapEnabled && !this.releaseFocusTrap) {
307
360
  this.releaseFocusTrap = installFocusTrap(this.element, {
308
- initialFocus: this.initialFocus,
309
- onEscape: this.closeOnEscape ? () => void this.closeFn() : void 0
361
+ initialFocus: this.initialFocus
310
362
  });
311
363
  }
312
364
  if (this.inertSiblingsEnabled && this.shouldApplyInertSiblings()) {
@@ -326,7 +378,7 @@ var LifecycleController = class {
326
378
  this.releaseScrollLock = null;
327
379
  this.inertSiblings.remove();
328
380
  if (this.returnFocus) {
329
- const target = typeof this.returnFocus === "function" ? this.returnFocus() : this.returnFocus;
381
+ const target = typeof this.returnFocus === "function" ? this.returnFocus() : typeof this.returnFocus === "string" ? typeof document !== "undefined" ? document.querySelector(this.returnFocus) : null : this.returnFocus;
330
382
  target?.focus?.();
331
383
  }
332
384
  }
@@ -336,6 +388,12 @@ var LifecycleController = class {
336
388
  }
337
389
  };
338
390
 
391
+ // src/core/animation/animation.ts
392
+ var prefersReducedMotion = () => {
393
+ if (typeof window === "undefined" || !window.matchMedia) return false;
394
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
395
+ };
396
+
339
397
  // src/core/overlay.ts
340
398
  var OVERLAY_PRESETS = Object.freeze({
341
399
  sheet: Object.freeze({
@@ -415,6 +473,10 @@ var OverlayEngine = class {
415
473
  __publicField(this, "closeOnOutsidePointerEnabled");
416
474
  __publicField(this, "detachOutsidePointer", null);
417
475
  __publicField(this, "detachSwipe", null);
476
+ __publicField(this, "respectReducedMotionEnabled");
477
+ __publicField(this, "isTop", true);
478
+ __publicField(this, "backPushed", false);
479
+ __publicField(this, "movedToTarget", false);
418
480
  __publicField(this, "onOpenCb");
419
481
  __publicField(this, "onCloseCb");
420
482
  __publicField(this, "isOpen_", false);
@@ -451,6 +513,7 @@ var OverlayEngine = class {
451
513
  this.mountTarget = opts.mountTo;
452
514
  this.peekRaw = opts.peek;
453
515
  this.closeOnOutsidePointerEnabled = opts.closeOnOutsidePointer ?? false;
516
+ this.respectReducedMotionEnabled = opts.respectReducedMotion ?? true;
454
517
  this.onOpenCb = opts.onOpen;
455
518
  this.onCloseCb = opts.onClose;
456
519
  if (this.peekRaw !== void 0 && this.edge !== "bottom") {
@@ -498,15 +561,17 @@ var OverlayEngine = class {
498
561
  this.emit("before-open", void 0);
499
562
  this.isOpen_ = true;
500
563
  this.isAnimating_ = true;
564
+ sheetStack.promote(this.id);
501
565
  this.element.removeAttribute("hidden");
502
566
  this.element.setAttribute("data-state", "entering");
503
567
  if (this.focusTrapEnabled) {
504
568
  this.element.setAttribute("aria-modal", "true");
505
569
  }
506
- const transitionStr = `transform ${this.duration}ms ${this.enterEasing}, opacity ${this.duration}ms ease-out`;
570
+ const dur = this.effectiveDuration();
571
+ const transitionStr = `transform ${dur}ms ${this.enterEasing}, opacity ${dur}ms ease-out`;
507
572
  this.element.style.transition = transitionStr;
508
573
  if (this.backdrop) {
509
- this.backdrop.style.transition = `opacity ${this.duration}ms ease-out`;
574
+ this.backdrop.style.transition = `opacity ${dur}ms ease-out`;
510
575
  }
511
576
  const cycle = ++this.cycleNonce;
512
577
  return new Promise((resolve) => {
@@ -518,7 +583,7 @@ var OverlayEngine = class {
518
583
  this.element.style.opacity = "1";
519
584
  if (this.backdrop) {
520
585
  this.backdrop.style.opacity = String(this.backdropOpacity);
521
- this.backdrop.style.pointerEvents = "auto";
586
+ this.backdrop.style.pointerEvents = this.backdropOpacity > 0 ? "auto" : "none";
522
587
  if (this.backdropFilter) {
523
588
  this.backdrop.style.backdropFilter = this.backdropFilter;
524
589
  this.backdrop.style.webkitBackdropFilter = this.backdropFilter;
@@ -554,7 +619,10 @@ var OverlayEngine = class {
554
619
  });
555
620
  return resolve();
556
621
  }
557
- this.awaitTransition(cycle).then(() => {
622
+ this.awaitTransition(
623
+ cycle,
624
+ this.enterAnimation === "fade" ? "opacity" : "transform"
625
+ ).then(() => {
558
626
  if (this.destroyed || cycle !== this.cycleNonce) return resolve();
559
627
  this.isAnimating_ = false;
560
628
  this.element.setAttribute("data-state", "open");
@@ -571,11 +639,14 @@ var OverlayEngine = class {
571
639
  this.emit("before-close", void 0);
572
640
  this.isOpen_ = false;
573
641
  this.isAnimating_ = true;
642
+ sheetStack.update();
643
+ this.popBackMarker(reason);
574
644
  this.element.setAttribute("data-state", "exiting");
575
- const transitionStr = `transform ${this.duration}ms ${this.exitEasing}, opacity ${this.duration}ms ease-in`;
645
+ const dur = this.effectiveDuration();
646
+ const transitionStr = `transform ${dur}ms ${this.exitEasing}, opacity ${dur}ms ease-in`;
576
647
  this.element.style.transition = transitionStr;
577
648
  if (this.backdrop) {
578
- this.backdrop.style.transition = `opacity ${this.duration}ms ease-in`;
649
+ this.backdrop.style.transition = `opacity ${dur}ms ease-in`;
579
650
  }
580
651
  const cycle = ++this.cycleNonce;
581
652
  return new Promise((resolve) => {
@@ -586,7 +657,7 @@ var OverlayEngine = class {
586
657
  this.exitAnimation,
587
658
  this.peekPx
588
659
  );
589
- this.element.style.opacity = "0";
660
+ this.element.style.opacity = this.peekPx !== void 0 ? "1" : "0";
590
661
  if (this.backdrop) {
591
662
  this.backdrop.style.opacity = "0";
592
663
  this.backdrop.style.pointerEvents = "none";
@@ -596,7 +667,10 @@ var OverlayEngine = class {
596
667
  }
597
668
  }
598
669
  this.releaseInteractiveListeners();
599
- this.awaitTransition(cycle).then(() => {
670
+ this.awaitTransition(
671
+ cycle,
672
+ this.exitAnimation === "fade" ? "opacity" : "transform"
673
+ ).then(() => {
600
674
  if (this.destroyed || cycle !== this.cycleNonce) return resolve();
601
675
  this.isAnimating_ = false;
602
676
  if (this.peekPx === void 0) {
@@ -624,7 +698,11 @@ var OverlayEngine = class {
624
698
  this.releaseInteractiveListeners();
625
699
  this.releaseStackEntry?.();
626
700
  this.releaseStackEntry = null;
701
+ const hadOriginalParent = this.originalParent !== null;
627
702
  this.restoreMount();
703
+ if (this.movedToTarget && !hadOriginalParent && this.element.parentNode) {
704
+ this.element.parentNode.removeChild(this.element);
705
+ }
628
706
  }
629
707
  setBackdropOpacity(opacity) {
630
708
  if (this.destroyed) return;
@@ -725,6 +803,36 @@ var OverlayEngine = class {
725
803
  }
726
804
  }
727
805
  }
806
+ if (opts.duration !== void 0) this.duration = opts.duration;
807
+ if (opts.enterEasing !== void 0) this.enterEasing = opts.enterEasing;
808
+ if (opts.exitEasing !== void 0) this.exitEasing = opts.exitEasing;
809
+ if (opts.closeOnEscape !== void 0) {
810
+ this.closeOnEscape = opts.closeOnEscape;
811
+ if (!opts.closeOnEscape) {
812
+ this.detachEscape?.();
813
+ this.detachEscape = null;
814
+ } else if (this.isOpen_) {
815
+ this.installInteractiveListeners();
816
+ }
817
+ }
818
+ if (opts.closeOnBackdrop !== void 0) {
819
+ this.closeOnBackdropEnabled = opts.closeOnBackdrop;
820
+ if (!opts.closeOnBackdrop) {
821
+ this.detachBackdrop?.();
822
+ this.detachBackdrop = null;
823
+ } else if (this.isOpen_) {
824
+ this.installInteractiveListeners();
825
+ }
826
+ }
827
+ if (opts.closeOnOutsidePointer !== void 0) {
828
+ this.closeOnOutsidePointerEnabled = opts.closeOnOutsidePointer;
829
+ if (!opts.closeOnOutsidePointer) {
830
+ this.detachOutsidePointer?.();
831
+ this.detachOutsidePointer = null;
832
+ } else if (this.isOpen_) {
833
+ this.installInteractiveListeners();
834
+ }
835
+ }
728
836
  if (opts.children !== void 0) {
729
837
  if (opts.children === null) {
730
838
  this.clearOverlayChildren();
@@ -758,6 +866,22 @@ var OverlayEngine = class {
758
866
  emit(event, payload) {
759
867
  this.bus.emit(event, payload);
760
868
  }
869
+ effectiveDuration() {
870
+ return this.respectReducedMotionEnabled && prefersReducedMotion() ? 0 : this.duration;
871
+ }
872
+ popBackMarker(reason) {
873
+ if (!this.backPushed) return;
874
+ this.backPushed = false;
875
+ if (reason === "back") return;
876
+ const state = history.state;
877
+ if (state && state.__bsOverlay === this.id) {
878
+ try {
879
+ history.back();
880
+ } catch {
881
+ return;
882
+ }
883
+ }
884
+ }
761
885
  resolvePeekPx(raw) {
762
886
  if (typeof raw === "number") return Math.max(0, raw);
763
887
  try {
@@ -779,6 +903,7 @@ var OverlayEngine = class {
779
903
  this.originalParent = this.element.parentNode;
780
904
  this.originalNextSibling = this.element.nextSibling;
781
905
  target.appendChild(this.element);
906
+ this.movedToTarget = true;
782
907
  this.mounted = true;
783
908
  }
784
909
  restoreMount() {
@@ -812,7 +937,7 @@ var OverlayEngine = class {
812
937
  this.backdrop.style.willChange = "opacity";
813
938
  }
814
939
  }
815
- awaitTransition(cycle) {
940
+ awaitTransition(cycle, property = "transform") {
816
941
  return new Promise((resolve) => {
817
942
  let done = false;
818
943
  const finish = () => {
@@ -827,10 +952,10 @@ var OverlayEngine = class {
827
952
  finish();
828
953
  return;
829
954
  }
830
- if (e.propertyName === "transform") finish();
955
+ if (e.target === this.element && e.propertyName === property) finish();
831
956
  };
832
957
  this.element.addEventListener("transitionend", onEnd);
833
- const timer = window.setTimeout(finish, this.duration + 50);
958
+ const timer = window.setTimeout(finish, this.effectiveDuration() + 50);
834
959
  });
835
960
  }
836
961
  installInteractiveListeners() {
@@ -840,7 +965,10 @@ var OverlayEngine = class {
840
965
  }
841
966
  if (this.closeOnEscape && !this.detachEscape) {
842
967
  const handler = (e) => {
843
- if (e.key === "Escape" && this.isOpen_) void this.close("escape");
968
+ if (e.defaultPrevented) return;
969
+ if (e.key === "Escape" && this.isOpen_ && this.isTop) {
970
+ void this.close("escape");
971
+ }
844
972
  };
845
973
  document.addEventListener("keydown", handler);
846
974
  this.detachEscape = () => document.removeEventListener("keydown", handler);
@@ -853,10 +981,14 @@ var OverlayEngine = class {
853
981
  if (this.closeOnBackEnabled && typeof window !== "undefined" && !this.detachHardwareBack) {
854
982
  try {
855
983
  history.pushState({ __bsOverlay: this.id }, "");
984
+ this.backPushed = true;
856
985
  } catch {
857
986
  }
858
987
  const onPop = () => {
859
- if (this.isOpen_) void this.close("back");
988
+ if (this.isOpen_ && this.isTop) {
989
+ this.backPushed = false;
990
+ void this.close("back");
991
+ }
860
992
  };
861
993
  window.addEventListener("popstate", onPop);
862
994
  this.detachHardwareBack = () => window.removeEventListener("popstate", onPop);
@@ -892,43 +1024,52 @@ var OverlayEngine = class {
892
1024
  const edge = this.edge;
893
1025
  const isVertical = edge === "bottom" || edge === "top";
894
1026
  const sign = edge === "bottom" || edge === "right" ? 1 : -1;
895
- const threshold = this.swipeThreshold;
896
- const velocityThreshold = this.swipeVelocityThreshold;
1027
+ const SLOP = 8;
897
1028
  let startX = 0;
898
1029
  let startY = 0;
899
1030
  let startT = 0;
1031
+ let tracking = false;
900
1032
  let dragging = false;
901
1033
  let pointerId = null;
1034
+ const previousTouchAction = el.style.touchAction;
1035
+ el.style.touchAction = isVertical ? "pan-x" : "pan-y";
902
1036
  const onDown = (e) => {
903
1037
  if (e.button !== void 0 && e.button !== 0) return;
904
1038
  pointerId = e.pointerId;
905
1039
  startX = e.clientX;
906
1040
  startY = e.clientY;
907
1041
  startT = performance.now();
908
- dragging = true;
909
- el.style.transition = "none";
910
- try {
911
- el.setPointerCapture(e.pointerId);
912
- } catch {
913
- }
1042
+ tracking = true;
1043
+ dragging = false;
914
1044
  };
915
1045
  const onMove = (e) => {
916
- if (!dragging || e.pointerId !== pointerId) return;
1046
+ if (!tracking || e.pointerId !== pointerId) return;
917
1047
  const delta = isVertical ? e.clientY - startY : e.clientX - startX;
1048
+ if (!dragging) {
1049
+ if (Math.abs(delta) < SLOP) return;
1050
+ dragging = true;
1051
+ el.style.transition = "none";
1052
+ try {
1053
+ el.setPointerCapture(e.pointerId);
1054
+ } catch {
1055
+ }
1056
+ }
918
1057
  const offset = Math.max(0, sign * delta);
919
1058
  el.style.transform = isVertical ? `translate3d(0, ${sign * offset}px, 0)` : `translate3d(${sign * offset}px, 0, 0)`;
920
1059
  };
921
1060
  const finish = (e) => {
922
- if (!dragging || e.pointerId !== pointerId) return;
923
- dragging = false;
1061
+ if (!tracking || e.pointerId !== pointerId) return;
1062
+ tracking = false;
924
1063
  pointerId = null;
1064
+ if (!dragging) return;
1065
+ dragging = false;
925
1066
  const dt = performance.now() - startT || 1;
926
1067
  const delta = isVertical ? e.clientY - startY : e.clientX - startX;
927
1068
  const offset = Math.max(0, sign * delta);
928
1069
  const velocity = sign * delta / dt;
929
1070
  const size = isVertical ? el.offsetHeight : el.offsetWidth;
930
- const past = offset > size * threshold || velocity > velocityThreshold;
931
- el.style.transition = `transform ${this.duration}ms ${this.exitEasing}`;
1071
+ const past = offset > size * this.swipeThreshold || velocity > this.swipeVelocityThreshold;
1072
+ el.style.transition = `transform ${this.effectiveDuration()}ms ${this.exitEasing}`;
932
1073
  if (past) {
933
1074
  void this.close("swipe");
934
1075
  } else {
@@ -940,6 +1081,7 @@ var OverlayEngine = class {
940
1081
  el.addEventListener("pointerup", finish);
941
1082
  el.addEventListener("pointercancel", finish);
942
1083
  return () => {
1084
+ el.style.touchAction = previousTouchAction;
943
1085
  el.removeEventListener("pointerdown", onDown);
944
1086
  el.removeEventListener("pointermove", onMove);
945
1087
  el.removeEventListener("pointerup", finish);
@@ -954,10 +1096,12 @@ var OverlayEngine = class {
954
1096
  if (this.backdrop) this.backdrop.style.zIndex = String(z - 1);
955
1097
  },
956
1098
  setIsTop: (isTop) => {
1099
+ this.isTop = isTop;
957
1100
  if (this.backdrop) {
958
1101
  this.backdrop.style.display = isTop ? "" : "none";
959
1102
  }
960
- }
1103
+ },
1104
+ isOpen: () => this.isOpen_
961
1105
  });
962
1106
  }
963
1107
  };
@@ -25,6 +25,12 @@ type OverlayUpdate = {
25
25
  enterAnimation?: OverlayAnimation;
26
26
  exitAnimation?: OverlayAnimation;
27
27
  preset?: OverlayPreset;
28
+ duration?: number;
29
+ enterEasing?: string;
30
+ exitEasing?: string;
31
+ closeOnEscape?: boolean;
32
+ closeOnBackdrop?: boolean;
33
+ closeOnOutsidePointer?: boolean;
28
34
  children?: HTMLElement | DocumentFragment | (() => HTMLElement | DocumentFragment) | null;
29
35
  };
30
36
  type OverlayOptions = {
@@ -52,6 +58,7 @@ type OverlayOptions = {
52
58
  peek?: number | string;
53
59
  closeOnOutsidePointer?: boolean;
54
60
  preset?: OverlayPreset;
61
+ respectReducedMotion?: boolean;
55
62
  onOpen?: () => void;
56
63
  onClose?: () => void;
57
64
  };
@@ -99,6 +106,10 @@ declare class OverlayEngine {
99
106
  private closeOnOutsidePointerEnabled;
100
107
  private detachOutsidePointer;
101
108
  private detachSwipe;
109
+ private respectReducedMotionEnabled;
110
+ private isTop;
111
+ private backPushed;
112
+ private movedToTarget;
102
113
  private onOpenCb?;
103
114
  private onCloseCb?;
104
115
  private isOpen_;
@@ -130,6 +141,8 @@ declare class OverlayEngine {
130
141
  clearOverlayChildren(): void;
131
142
  private assignSwipeFromConfig;
132
143
  private emit;
144
+ private effectiveDuration;
145
+ private popBackMarker;
133
146
  private resolvePeekPx;
134
147
  private maybeMount;
135
148
  private restoreMount;
package/dist/overlay.d.ts CHANGED
@@ -25,6 +25,12 @@ type OverlayUpdate = {
25
25
  enterAnimation?: OverlayAnimation;
26
26
  exitAnimation?: OverlayAnimation;
27
27
  preset?: OverlayPreset;
28
+ duration?: number;
29
+ enterEasing?: string;
30
+ exitEasing?: string;
31
+ closeOnEscape?: boolean;
32
+ closeOnBackdrop?: boolean;
33
+ closeOnOutsidePointer?: boolean;
28
34
  children?: HTMLElement | DocumentFragment | (() => HTMLElement | DocumentFragment) | null;
29
35
  };
30
36
  type OverlayOptions = {
@@ -52,6 +58,7 @@ type OverlayOptions = {
52
58
  peek?: number | string;
53
59
  closeOnOutsidePointer?: boolean;
54
60
  preset?: OverlayPreset;
61
+ respectReducedMotion?: boolean;
55
62
  onOpen?: () => void;
56
63
  onClose?: () => void;
57
64
  };
@@ -99,6 +106,10 @@ declare class OverlayEngine {
99
106
  private closeOnOutsidePointerEnabled;
100
107
  private detachOutsidePointer;
101
108
  private detachSwipe;
109
+ private respectReducedMotionEnabled;
110
+ private isTop;
111
+ private backPushed;
112
+ private movedToTarget;
102
113
  private onOpenCb?;
103
114
  private onCloseCb?;
104
115
  private isOpen_;
@@ -130,6 +141,8 @@ declare class OverlayEngine {
130
141
  clearOverlayChildren(): void;
131
142
  private assignSwipeFromConfig;
132
143
  private emit;
144
+ private effectiveDuration;
145
+ private popBackMarker;
133
146
  private resolvePeekPx;
134
147
  private maybeMount;
135
148
  private restoreMount;