@surdeddd/bottom-sheet 0.14.0 → 0.20.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 (56) hide show
  1. package/README.md +13 -0
  2. package/dist/{BottomSheetCore-DJYwWOqt.d.ts → BottomSheetCore-Cgn8b_6A.d.ts} +11 -2
  3. package/dist/{BottomSheetCore-Cp7dWy91.d.cts → BottomSheetCore-VPJZcKcg.d.cts} +11 -2
  4. package/dist/{BottomSheetEngine-Lm7HIVHv.d.cts → BottomSheetEngine-B8C2CwF9.d.cts} +1 -1
  5. package/dist/{BottomSheetEngine-O5PbeKfe.d.ts → BottomSheetEngine-DwYR_ygJ.d.ts} +1 -1
  6. package/dist/core.cjs +100 -9
  7. package/dist/core.d.cts +2 -2
  8. package/dist/core.d.ts +2 -2
  9. package/dist/core.js +100 -9
  10. package/dist/debug.d.cts +1 -1
  11. package/dist/debug.d.ts +1 -1
  12. package/dist/element.cjs +107 -9
  13. package/dist/element.d.cts +2 -2
  14. package/dist/element.d.ts +2 -2
  15. package/dist/element.iife.global.js +2 -2
  16. package/dist/element.js +107 -9
  17. package/dist/features.d.cts +4 -4
  18. package/dist/features.d.ts +4 -4
  19. package/dist/{index-Bb5TRmyg.d.cts → index-CnfbOKx0.d.cts} +1 -1
  20. package/dist/{index-Cl9ebCP2.d.ts → index-DcMkhXAy.d.ts} +1 -1
  21. package/dist/index.cjs +100 -9
  22. package/dist/index.d.cts +8 -8
  23. package/dist/index.d.ts +8 -8
  24. package/dist/index.js +100 -9
  25. package/dist/integrations/formik.d.cts +1 -1
  26. package/dist/integrations/formik.d.ts +1 -1
  27. package/dist/integrations/react-hook-form.d.cts +1 -1
  28. package/dist/integrations/react-hook-form.d.ts +1 -1
  29. package/dist/preact.d.cts +2 -2
  30. package/dist/preact.d.ts +2 -2
  31. package/dist/qwik-lib/index.qwik.cjs +98 -9
  32. package/dist/qwik-lib/index.qwik.mjs +98 -9
  33. package/dist/qwik.cjs +100 -9
  34. package/dist/qwik.d.cts +2 -2
  35. package/dist/qwik.d.ts +2 -2
  36. package/dist/qwik.js +100 -9
  37. package/dist/react.cjs +100 -9
  38. package/dist/react.d.cts +3 -3
  39. package/dist/react.d.ts +3 -3
  40. package/dist/react.js +100 -9
  41. package/dist/solid.cjs +100 -9
  42. package/dist/solid.d.cts +10 -1
  43. package/dist/solid.d.ts +10 -1
  44. package/dist/solid.js +100 -9
  45. package/dist/solid.source.jsx +100 -9
  46. package/dist/svelte-core.cjs +100 -9
  47. package/dist/svelte-core.js +100 -9
  48. package/dist/svelte.cjs +100 -9
  49. package/dist/svelte.js +100 -9
  50. package/dist/vue.cjs +101 -10
  51. package/dist/vue.js +101 -10
  52. package/dist/webgl.cjs +154 -34
  53. package/dist/webgl.d.cts +1 -1
  54. package/dist/webgl.d.ts +1 -1
  55. package/dist/webgl.js +154 -34
  56. package/package.json +39 -39
package/README.md CHANGED
@@ -552,6 +552,19 @@ The editorial demo showcases the adapters, every gesture, every mode
552
552
  (`bottom · top · left · right · overlay`), and live engine readouts (active
553
553
  snap, progress, velocity, FPS). EN/RU and light/dark toggles in the corner.
554
554
 
555
+ ## Right-to-left
556
+
557
+ `left` and `right` are physical edges and stay physical. For interfaces that
558
+ flip with the writing direction, use the logical modes — `start` and `end`
559
+ resolve against the direction that applies to the sheet, so `start` is the left
560
+ edge in English and the right edge in Arabic:
561
+
562
+ ```ts
563
+ new BottomSheetEngine({ element, handle, mode: 'start', snapPoints });
564
+ ```
565
+
566
+ [Full RTL docs →](docs/rtl.md)
567
+
555
568
  ## Browser support
556
569
 
557
570
  Baseline: Chrome/Edge 80, Safari 13.1 (iOS 13.4), Firefox 72 — set by the
@@ -2,6 +2,8 @@ import { T as TransformAxis } from './transform-jVfAikE9.js';
2
2
 
3
3
  type DragFrom$1 = "handle" | "sheet" | "zones";
4
4
 
5
+ type LogicalAxis = "start" | "end";
6
+
5
7
  type SnapPoint = number | `${number}%` | "fit" | "content" | "full" | (string & {});
6
8
  type SnapPointDef<Id extends string = string> = {
7
9
  id: Id;
@@ -13,7 +15,9 @@ type SnapId<T extends readonly SnapPointDef<string>[] | {
13
15
  }> = T extends {
14
16
  snapPoints: readonly SnapPointDef<infer U>[];
15
17
  } ? U : T extends readonly SnapPointDef<infer U>[] ? U : never;
16
- type SheetMode = TransformAxis;
18
+ type PhysicalSheetMode = TransformAxis;
19
+ type LogicalSheetMode = LogicalAxis;
20
+ type SheetMode = PhysicalSheetMode | LogicalSheetMode;
17
21
  type DragFrom = DragFrom$1;
18
22
  type DragSurfaceKind = "content";
19
23
  type ScrimPreset = "subtle" | "standard" | "monitoring" | "cinematic";
@@ -283,6 +287,7 @@ declare class BottomSheetCore {
283
287
  private disableDragFlag;
284
288
  private closeOnRouteChange;
285
289
  private maxHeight;
290
+ private maxHeightDeps;
286
291
  private snapPointsRaw;
287
292
  private snaps;
288
293
  private activeId;
@@ -290,6 +295,7 @@ declare class BottomSheetCore {
290
295
  private gesture;
291
296
  private contentGesture;
292
297
  private detachSheetGesture;
298
+ private detachSliderKeyboard;
293
299
  private rootEl;
294
300
  private destroyed;
295
301
  private restClosed;
@@ -351,6 +357,8 @@ declare class BottomSheetCore {
351
357
  setDragFromContent(value: boolean): void;
352
358
  setDragFrom(mode: DragFrom$1): void;
353
359
  getDragFrom(): DragFrom$1;
360
+ setMode(mode: SheetMode): void;
361
+ getMode(): PhysicalSheetMode;
354
362
  isTop(): boolean;
355
363
  depth(): number;
356
364
  expand(): Promise<void>;
@@ -399,6 +407,7 @@ declare class BottomSheetCore {
399
407
  private mountSheetGesture;
400
408
  private attach;
401
409
  private attachFeatures;
410
+ private mountSliderKeyboard;
402
411
  private settleAfterDrag;
403
412
  private isDraggingAny;
404
413
  private clearWillChangeIfIdle;
@@ -410,4 +419,4 @@ declare class BottomSheetCore {
410
419
  private handleClose;
411
420
  }
412
421
 
413
- export { type AnchorOptions as A, BottomSheetCore as B, type CloseReason as C, type EngineState as E, type Plugin as P, type ScrimStagesOptions as S, type TeardownScope as T, type EngineOptions as a, type SnapPointDef as b, type SheetMode as c, type SheetEventMap as d, type SnapPoint as e, type EngineFeature as f, type ScrimOverlayPosition as g, type AnchorAnimationPreset as h, type AnchorAnimationSpec as i, type AnchorHandle as j, type AnchorPosition as k, type AnchorState as l, type EngineFeatureContext as m, type EngineFeatureOptions as n, type EngineFeatureStage as o, SCRIM_PRESETS as p, type ScrimOverlayOptions as q, type ScrimPreset as r, type ScrimPresetConfig as s, type ScrimStageDef as t, type ScrimUpdate as u, type SnapId as v, runAnchorTransition as w };
422
+ export { type AnchorOptions as A, BottomSheetCore as B, type CloseReason as C, type EngineState as E, type LogicalSheetMode as L, type PhysicalSheetMode as P, type SheetEventMap as S, type TeardownScope as T, type SnapPointDef as a, type SheetMode as b, type EngineOptions as c, type SnapPoint as d, type ScrimStagesOptions as e, type EngineFeature as f, type ScrimOverlayPosition as g, type AnchorAnimationPreset as h, type AnchorAnimationSpec as i, type AnchorHandle as j, type AnchorPosition as k, type AnchorState as l, type EngineFeatureContext as m, type EngineFeatureOptions as n, type EngineFeatureStage as o, type Plugin as p, SCRIM_PRESETS as q, type ScrimOverlayOptions as r, type ScrimPreset as s, type ScrimPresetConfig as t, type ScrimStageDef as u, type ScrimUpdate as v, type SnapId as w, runAnchorTransition as x };
@@ -2,6 +2,8 @@ import { T as TransformAxis } from './transform-jVfAikE9.cjs';
2
2
 
3
3
  type DragFrom$1 = "handle" | "sheet" | "zones";
4
4
 
5
+ type LogicalAxis = "start" | "end";
6
+
5
7
  type SnapPoint = number | `${number}%` | "fit" | "content" | "full" | (string & {});
6
8
  type SnapPointDef<Id extends string = string> = {
7
9
  id: Id;
@@ -13,7 +15,9 @@ type SnapId<T extends readonly SnapPointDef<string>[] | {
13
15
  }> = T extends {
14
16
  snapPoints: readonly SnapPointDef<infer U>[];
15
17
  } ? U : T extends readonly SnapPointDef<infer U>[] ? U : never;
16
- type SheetMode = TransformAxis;
18
+ type PhysicalSheetMode = TransformAxis;
19
+ type LogicalSheetMode = LogicalAxis;
20
+ type SheetMode = PhysicalSheetMode | LogicalSheetMode;
17
21
  type DragFrom = DragFrom$1;
18
22
  type DragSurfaceKind = "content";
19
23
  type ScrimPreset = "subtle" | "standard" | "monitoring" | "cinematic";
@@ -283,6 +287,7 @@ declare class BottomSheetCore {
283
287
  private disableDragFlag;
284
288
  private closeOnRouteChange;
285
289
  private maxHeight;
290
+ private maxHeightDeps;
286
291
  private snapPointsRaw;
287
292
  private snaps;
288
293
  private activeId;
@@ -290,6 +295,7 @@ declare class BottomSheetCore {
290
295
  private gesture;
291
296
  private contentGesture;
292
297
  private detachSheetGesture;
298
+ private detachSliderKeyboard;
293
299
  private rootEl;
294
300
  private destroyed;
295
301
  private restClosed;
@@ -351,6 +357,8 @@ declare class BottomSheetCore {
351
357
  setDragFromContent(value: boolean): void;
352
358
  setDragFrom(mode: DragFrom$1): void;
353
359
  getDragFrom(): DragFrom$1;
360
+ setMode(mode: SheetMode): void;
361
+ getMode(): PhysicalSheetMode;
354
362
  isTop(): boolean;
355
363
  depth(): number;
356
364
  expand(): Promise<void>;
@@ -399,6 +407,7 @@ declare class BottomSheetCore {
399
407
  private mountSheetGesture;
400
408
  private attach;
401
409
  private attachFeatures;
410
+ private mountSliderKeyboard;
402
411
  private settleAfterDrag;
403
412
  private isDraggingAny;
404
413
  private clearWillChangeIfIdle;
@@ -410,4 +419,4 @@ declare class BottomSheetCore {
410
419
  private handleClose;
411
420
  }
412
421
 
413
- export { type AnchorOptions as A, BottomSheetCore as B, type CloseReason as C, type EngineState as E, type Plugin as P, type ScrimStagesOptions as S, type TeardownScope as T, type EngineOptions as a, type SnapPointDef as b, type SheetMode as c, type SheetEventMap as d, type SnapPoint as e, type EngineFeature as f, type ScrimOverlayPosition as g, type AnchorAnimationPreset as h, type AnchorAnimationSpec as i, type AnchorHandle as j, type AnchorPosition as k, type AnchorState as l, type EngineFeatureContext as m, type EngineFeatureOptions as n, type EngineFeatureStage as o, SCRIM_PRESETS as p, type ScrimOverlayOptions as q, type ScrimPreset as r, type ScrimPresetConfig as s, type ScrimStageDef as t, type ScrimUpdate as u, type SnapId as v, runAnchorTransition as w };
422
+ export { type AnchorOptions as A, BottomSheetCore as B, type CloseReason as C, type EngineState as E, type LogicalSheetMode as L, type PhysicalSheetMode as P, type SheetEventMap as S, type TeardownScope as T, type SnapPointDef as a, type SheetMode as b, type EngineOptions as c, type SnapPoint as d, type ScrimStagesOptions as e, type EngineFeature as f, type ScrimOverlayPosition as g, type AnchorAnimationPreset as h, type AnchorAnimationSpec as i, type AnchorHandle as j, type AnchorPosition as k, type AnchorState as l, type EngineFeatureContext as m, type EngineFeatureOptions as n, type EngineFeatureStage as o, type Plugin as p, SCRIM_PRESETS as q, type ScrimOverlayOptions as r, type ScrimPreset as s, type ScrimPresetConfig as t, type ScrimStageDef as u, type ScrimUpdate as v, type SnapId as w, runAnchorTransition as x };
@@ -1,4 +1,4 @@
1
- import { B as BottomSheetCore, a as EngineOptions } from './BottomSheetCore-Cp7dWy91.cjs';
1
+ import { B as BottomSheetCore, c as EngineOptions } from './BottomSheetCore-VPJZcKcg.cjs';
2
2
 
3
3
  declare class BottomSheetEngine extends BottomSheetCore {
4
4
  constructor(opts: EngineOptions);
@@ -1,4 +1,4 @@
1
- import { B as BottomSheetCore, a as EngineOptions } from './BottomSheetCore-DJYwWOqt.js';
1
+ import { B as BottomSheetCore, c as EngineOptions } from './BottomSheetCore-Cgn8b_6A.js';
2
2
 
3
3
  declare class BottomSheetEngine extends BottomSheetCore {
4
4
  constructor(opts: EngineOptions);
package/dist/core.cjs CHANGED
@@ -315,6 +315,11 @@ var SnapResolver = class {
315
315
  this.raw = raw;
316
316
  this.recompute();
317
317
  }
318
+ setMode(mode) {
319
+ if (mode === this.mode) return;
320
+ this.mode = mode;
321
+ this.recompute();
322
+ }
318
323
  setAllowedIds(ids) {
319
324
  this.allowedIds = ids;
320
325
  this.rangeCache = null;
@@ -898,6 +903,11 @@ var ScrimController = class {
898
903
  if (this.isDestroyed()) return;
899
904
  this.applyScrimStyles({ interactive });
900
905
  }
906
+ setSheetMode(mode) {
907
+ if (this.isDestroyed() || mode === this.mode) return;
908
+ this.mode = mode;
909
+ this.invalidateOpacityCache();
910
+ }
901
911
  setScrimMode(mode, applySize) {
902
912
  if (this.isDestroyed()) return;
903
913
  if (mode === this.scrimMode) return;
@@ -1820,6 +1830,7 @@ var installGestures = (handle, mode, callbacks, options = {}) => {
1820
1830
  let activePointerId = null;
1821
1831
  let activePointerType = "touch";
1822
1832
  let startCoord = 0;
1833
+ let startCross = 0;
1823
1834
  let lastCoord = 0;
1824
1835
  let pendingStart = false;
1825
1836
  const VELOCITY_WINDOW_MS = (kind) => kind === "mouse" ? 160 : 120;
@@ -1828,6 +1839,7 @@ var installGestures = (handle, mode, callbacks, options = {}) => {
1828
1839
  const axis = isAxisVertical(mode) ? "Y" : "X";
1829
1840
  const sign = mode === "bottom" || mode === "right" ? -1 : 1;
1830
1841
  const coordOf = (e) => axis === "Y" ? e.clientY : e.clientX;
1842
+ const crossOf = (e) => axis === "Y" ? e.clientX : e.clientY;
1831
1843
  const capture = (pointerId) => {
1832
1844
  try {
1833
1845
  handle.setPointerCapture(pointerId);
@@ -1846,6 +1858,7 @@ var installGestures = (handle, mode, callbacks, options = {}) => {
1846
1858
  activePointerId = e.pointerId;
1847
1859
  activePointerType = e.pointerType || "touch";
1848
1860
  startCoord = coordOf(e);
1861
+ startCross = crossOf(e);
1849
1862
  lastCoord = startCoord;
1850
1863
  samples.reset();
1851
1864
  samples.push(e.timeStamp, startCoord);
@@ -1862,7 +1875,7 @@ var installGestures = (handle, mode, callbacks, options = {}) => {
1862
1875
  const rawDelta = coord - startCoord;
1863
1876
  const delta = rawDelta * sign;
1864
1877
  if (pendingStart) {
1865
- const verdict = options.deferStart(e, delta);
1878
+ const verdict = options.deferStart(e, delta, crossOf(e) - startCross);
1866
1879
  if (verdict === false) {
1867
1880
  releaseTracking();
1868
1881
  return;
@@ -2080,12 +2093,45 @@ function isDragAllowedFrom(target, mode) {
2080
2093
  var CONTENT_DRAG_SLOP = 6;
2081
2094
  function decideContentGesture(input) {
2082
2095
  const slop = input.slop ?? CONTENT_DRAG_SLOP;
2096
+ const cross = input.crossDelta ?? 0;
2097
+ const sharesScrollAxis = input.sharesScrollAxis ?? true;
2098
+ if (!sharesScrollAxis) {
2099
+ if (Math.abs(input.delta) < slop && Math.abs(cross) < slop) return "pending";
2100
+ if (Math.abs(input.delta) <= Math.abs(cross)) return "scroll";
2101
+ return "drag";
2102
+ }
2083
2103
  if (Math.abs(input.delta) < slop) return "pending";
2084
2104
  if (input.scrollTop > 0) return "scroll";
2085
2105
  if (input.delta > 0 && input.atMaxSnap) return "scroll";
2086
2106
  return "drag";
2087
2107
  }
2088
2108
 
2109
+ // src/core/primitives/logical-mode.ts
2110
+ var isLogicalMode = (mode) => mode === "start" || mode === "end";
2111
+ var readDirection = (el) => {
2112
+ if (!el) return "ltr";
2113
+ if (typeof getComputedStyle === "function") {
2114
+ try {
2115
+ if (getComputedStyle(el).direction === "rtl") return "rtl";
2116
+ } catch {
2117
+ }
2118
+ }
2119
+ try {
2120
+ const marked = el.closest?.("[dir]");
2121
+ if (marked) {
2122
+ return marked.getAttribute("dir")?.toLowerCase() === "rtl" ? "rtl" : "ltr";
2123
+ }
2124
+ } catch {
2125
+ }
2126
+ return "ltr";
2127
+ };
2128
+ var resolveMode = (mode, el) => {
2129
+ if (!isLogicalMode(mode)) return mode;
2130
+ const rtl = readDirection(el) === "rtl";
2131
+ if (mode === "start") return rtl ? "right" : "left";
2132
+ return rtl ? "left" : "right";
2133
+ };
2134
+
2089
2135
  // src/core/primitives/touch-scroll-guard.ts
2090
2136
  function installTouchScrollGuard(surface, isDragging) {
2091
2137
  const onTouchMove = (e) => {
@@ -2448,7 +2494,7 @@ function resolveEngineOptions(opts, extras) {
2448
2494
  }
2449
2495
  }
2450
2496
  return {
2451
- mode: opts.mode ?? "bottom",
2497
+ mode: resolveMode(opts.mode ?? "bottom", opts.element),
2452
2498
  flickVelocity: opts.flickVelocity ?? DEFAULT_FLICK_VELOCITY,
2453
2499
  dragThreshold: opts.dragThreshold ?? DEFAULT_DRAG_THRESHOLD,
2454
2500
  dragFrom: opts.dragFrom ?? (opts.handle ? "handle" : "sheet"),
@@ -2552,6 +2598,7 @@ var BottomSheetCore = class {
2552
2598
  __publicField(this, "disableDragFlag");
2553
2599
  __publicField(this, "closeOnRouteChange");
2554
2600
  __publicField(this, "maxHeight");
2601
+ __publicField(this, "maxHeightDeps");
2555
2602
  __publicField(this, "snapPointsRaw");
2556
2603
  __publicField(this, "snaps");
2557
2604
  __publicField(this, "activeId");
@@ -2559,6 +2606,7 @@ var BottomSheetCore = class {
2559
2606
  __publicField(this, "gesture");
2560
2607
  __publicField(this, "contentGesture");
2561
2608
  __publicField(this, "detachSheetGesture", null);
2609
+ __publicField(this, "detachSliderKeyboard", null);
2562
2610
  __publicField(this, "rootEl", null);
2563
2611
  __publicField(this, "destroyed", false);
2564
2612
  __publicField(this, "restClosed", false);
@@ -2610,6 +2658,7 @@ var BottomSheetCore = class {
2610
2658
  this.screenComponent = opts.scrim ?? opts.screenComponent;
2611
2659
  this.scrimParent = this.screenComponent?.parentElement ?? null;
2612
2660
  this.mode = resolved.mode;
2661
+ this.element.dataset.mode = this.mode;
2613
2662
  this.transformTemplate = buildTransformTemplate(this.mode);
2614
2663
  this.aria = new AriaSliderWriter(this.handle, this.mode);
2615
2664
  this.flickVelocity = resolved.flickVelocity;
@@ -2676,7 +2725,7 @@ var BottomSheetCore = class {
2676
2725
  auditVhUsage(this.snapPointsRaw);
2677
2726
  this.auditDuplicateSnapIds(this.snapPointsRaw);
2678
2727
  this.rootEl = this.element.closest(".bs-root");
2679
- this.maxHeight = createMaxHeightController({
2728
+ this.maxHeightDeps = {
2680
2729
  element: this.element,
2681
2730
  mode: this.mode,
2682
2731
  getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
@@ -2684,7 +2733,8 @@ var BottomSheetCore = class {
2684
2733
  this.snaps.setMaxAxisSize(size);
2685
2734
  },
2686
2735
  recompute: () => this.recompute()
2687
- });
2736
+ };
2737
+ this.maxHeight = createMaxHeightController(this.maxHeightDeps);
2688
2738
  this.fitDeps = {
2689
2739
  element: this.element,
2690
2740
  scrollContainer: this.scrollContainer,
@@ -3018,6 +3068,37 @@ var BottomSheetCore = class {
3018
3068
  getDragFrom() {
3019
3069
  return this.dragFromMode;
3020
3070
  }
3071
+ setMode(mode) {
3072
+ if (this.destroyed) return;
3073
+ const next = resolveMode(mode, this.element);
3074
+ if (next === this.mode) return;
3075
+ const wasVertical = this.mode === "bottom" || this.mode === "top";
3076
+ const nowVertical = next === "bottom" || next === "top";
3077
+ this.gesture?.forceClearDragState();
3078
+ this.detachSheetGesture?.();
3079
+ this.animation.cancel();
3080
+ this.element.style.removeProperty(layoutAxis(this.mode));
3081
+ this.mode = next;
3082
+ this.element.dataset.mode = next;
3083
+ this.transformTemplate = buildTransformTemplate(next);
3084
+ this.maxHeightDeps.mode = next;
3085
+ this.fitDeps.mode = next;
3086
+ this.snaps.setMode(next);
3087
+ this.scrim.setSheetMode(next);
3088
+ if (wasVertical !== nowVertical) {
3089
+ this.aria = new AriaSliderWriter(this.handle, next);
3090
+ }
3091
+ this.detachSliderKeyboard?.();
3092
+ this.mountSliderKeyboard();
3093
+ this.mountSheetGesture();
3094
+ this.recompute();
3095
+ const active = this.snaps.findById(this.activeId);
3096
+ if (active) this.applySize(active.size);
3097
+ this.updateAriaSlider();
3098
+ }
3099
+ getMode() {
3100
+ return this.mode;
3101
+ }
3021
3102
  isTop() {
3022
3103
  return this.isTopSheet;
3023
3104
  }
@@ -3366,7 +3447,7 @@ var BottomSheetCore = class {
3366
3447
  const point = this.snapPointsRaw.find((p) => p.id === this.activeId);
3367
3448
  return point?.dragFromContent ?? this.dragFromContentDefault;
3368
3449
  }
3369
- decideContentDrag(surface, e, delta) {
3450
+ decideContentDrag(surface, e, delta, crossDelta) {
3370
3451
  if (this.destroyed) return false;
3371
3452
  if (e.pointerType === "mouse") return false;
3372
3453
  if (this.gesture?.isDragging) return false;
@@ -3374,6 +3455,8 @@ var BottomSheetCore = class {
3374
3455
  if (!isDragAllowedFrom(e.target, "sheet")) return false;
3375
3456
  const decision = decideContentGesture({
3376
3457
  delta,
3458
+ crossDelta,
3459
+ sharesScrollAxis: this.mode === "bottom" || this.mode === "top",
3377
3460
  scrollTop: surface.scrollTop,
3378
3461
  atMaxSnap: this.size >= this.getAllowedRange().max - 0.5
3379
3462
  });
@@ -3386,7 +3469,7 @@ var BottomSheetCore = class {
3386
3469
  const controller = new GestureController(
3387
3470
  this.buildGestureDeps(surface, {
3388
3471
  manageTouchAction: false,
3389
- deferStart: (e, delta) => this.decideContentDrag(surface, e, delta)
3472
+ deferStart: (e, delta, crossDelta) => this.decideContentDrag(surface, e, delta, crossDelta)
3390
3473
  })
3391
3474
  );
3392
3475
  this.contentGesture = controller;
@@ -3512,7 +3595,11 @@ var BottomSheetCore = class {
3512
3595
  );
3513
3596
  }
3514
3597
  }
3515
- this.teardowns.add(installSliderKeyboard({
3598
+ this.mountSliderKeyboard();
3599
+ this.scrim.attach();
3600
+ }
3601
+ mountSliderKeyboard() {
3602
+ const detach = installSliderKeyboard({
3516
3603
  handle: this.handle,
3517
3604
  mode: this.mode,
3518
3605
  isDestroyed: () => this.destroyed,
@@ -3521,8 +3608,12 @@ var BottomSheetCore = class {
3521
3608
  snapTo: (id) => {
3522
3609
  void this.snapTo(id);
3523
3610
  }
3524
- }));
3525
- this.scrim.attach();
3611
+ });
3612
+ this.detachSliderKeyboard = detach;
3613
+ this.teardowns.add(() => {
3614
+ this.detachSliderKeyboard?.();
3615
+ this.detachSliderKeyboard = null;
3616
+ });
3526
3617
  }
3527
3618
  settleAfterDrag(delta, velocity, kind = "touch") {
3528
3619
  const signal = this.newCycle();
package/dist/core.d.cts CHANGED
@@ -1,3 +1,3 @@
1
- export { B as BottomSheetCore, C as CloseReason, f as EngineFeature, m as EngineFeatureContext, n as EngineFeatureOptions, o as EngineFeatureStage, a as EngineOptions, E as EngineState, d as SheetEventMap, c as SheetMode, v as SnapId, e as SnapPoint, b as SnapPointDef } from './BottomSheetCore-Cp7dWy91.cjs';
2
- export { R as ResolvedSnap } from './index-Bb5TRmyg.cjs';
1
+ export { B as BottomSheetCore, C as CloseReason, f as EngineFeature, m as EngineFeatureContext, n as EngineFeatureOptions, o as EngineFeatureStage, c as EngineOptions, E as EngineState, S as SheetEventMap, b as SheetMode, w as SnapId, d as SnapPoint, a as SnapPointDef } from './BottomSheetCore-VPJZcKcg.cjs';
2
+ export { R as ResolvedSnap } from './index-CnfbOKx0.cjs';
3
3
  import './transform-jVfAikE9.cjs';
package/dist/core.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { B as BottomSheetCore, C as CloseReason, f as EngineFeature, m as EngineFeatureContext, n as EngineFeatureOptions, o as EngineFeatureStage, a as EngineOptions, E as EngineState, d as SheetEventMap, c as SheetMode, v as SnapId, e as SnapPoint, b as SnapPointDef } from './BottomSheetCore-DJYwWOqt.js';
2
- export { R as ResolvedSnap } from './index-Cl9ebCP2.js';
1
+ export { B as BottomSheetCore, C as CloseReason, f as EngineFeature, m as EngineFeatureContext, n as EngineFeatureOptions, o as EngineFeatureStage, c as EngineOptions, E as EngineState, S as SheetEventMap, b as SheetMode, w as SnapId, d as SnapPoint, a as SnapPointDef } from './BottomSheetCore-Cgn8b_6A.js';
2
+ export { R as ResolvedSnap } from './index-DcMkhXAy.js';
3
3
  import './transform-jVfAikE9.js';
package/dist/core.js CHANGED
@@ -313,6 +313,11 @@ var SnapResolver = class {
313
313
  this.raw = raw;
314
314
  this.recompute();
315
315
  }
316
+ setMode(mode) {
317
+ if (mode === this.mode) return;
318
+ this.mode = mode;
319
+ this.recompute();
320
+ }
316
321
  setAllowedIds(ids) {
317
322
  this.allowedIds = ids;
318
323
  this.rangeCache = null;
@@ -896,6 +901,11 @@ var ScrimController = class {
896
901
  if (this.isDestroyed()) return;
897
902
  this.applyScrimStyles({ interactive });
898
903
  }
904
+ setSheetMode(mode) {
905
+ if (this.isDestroyed() || mode === this.mode) return;
906
+ this.mode = mode;
907
+ this.invalidateOpacityCache();
908
+ }
899
909
  setScrimMode(mode, applySize) {
900
910
  if (this.isDestroyed()) return;
901
911
  if (mode === this.scrimMode) return;
@@ -1818,6 +1828,7 @@ var installGestures = (handle, mode, callbacks, options = {}) => {
1818
1828
  let activePointerId = null;
1819
1829
  let activePointerType = "touch";
1820
1830
  let startCoord = 0;
1831
+ let startCross = 0;
1821
1832
  let lastCoord = 0;
1822
1833
  let pendingStart = false;
1823
1834
  const VELOCITY_WINDOW_MS = (kind) => kind === "mouse" ? 160 : 120;
@@ -1826,6 +1837,7 @@ var installGestures = (handle, mode, callbacks, options = {}) => {
1826
1837
  const axis = isAxisVertical(mode) ? "Y" : "X";
1827
1838
  const sign = mode === "bottom" || mode === "right" ? -1 : 1;
1828
1839
  const coordOf = (e) => axis === "Y" ? e.clientY : e.clientX;
1840
+ const crossOf = (e) => axis === "Y" ? e.clientX : e.clientY;
1829
1841
  const capture = (pointerId) => {
1830
1842
  try {
1831
1843
  handle.setPointerCapture(pointerId);
@@ -1844,6 +1856,7 @@ var installGestures = (handle, mode, callbacks, options = {}) => {
1844
1856
  activePointerId = e.pointerId;
1845
1857
  activePointerType = e.pointerType || "touch";
1846
1858
  startCoord = coordOf(e);
1859
+ startCross = crossOf(e);
1847
1860
  lastCoord = startCoord;
1848
1861
  samples.reset();
1849
1862
  samples.push(e.timeStamp, startCoord);
@@ -1860,7 +1873,7 @@ var installGestures = (handle, mode, callbacks, options = {}) => {
1860
1873
  const rawDelta = coord - startCoord;
1861
1874
  const delta = rawDelta * sign;
1862
1875
  if (pendingStart) {
1863
- const verdict = options.deferStart(e, delta);
1876
+ const verdict = options.deferStart(e, delta, crossOf(e) - startCross);
1864
1877
  if (verdict === false) {
1865
1878
  releaseTracking();
1866
1879
  return;
@@ -2078,12 +2091,45 @@ function isDragAllowedFrom(target, mode) {
2078
2091
  var CONTENT_DRAG_SLOP = 6;
2079
2092
  function decideContentGesture(input) {
2080
2093
  const slop = input.slop ?? CONTENT_DRAG_SLOP;
2094
+ const cross = input.crossDelta ?? 0;
2095
+ const sharesScrollAxis = input.sharesScrollAxis ?? true;
2096
+ if (!sharesScrollAxis) {
2097
+ if (Math.abs(input.delta) < slop && Math.abs(cross) < slop) return "pending";
2098
+ if (Math.abs(input.delta) <= Math.abs(cross)) return "scroll";
2099
+ return "drag";
2100
+ }
2081
2101
  if (Math.abs(input.delta) < slop) return "pending";
2082
2102
  if (input.scrollTop > 0) return "scroll";
2083
2103
  if (input.delta > 0 && input.atMaxSnap) return "scroll";
2084
2104
  return "drag";
2085
2105
  }
2086
2106
 
2107
+ // src/core/primitives/logical-mode.ts
2108
+ var isLogicalMode = (mode) => mode === "start" || mode === "end";
2109
+ var readDirection = (el) => {
2110
+ if (!el) return "ltr";
2111
+ if (typeof getComputedStyle === "function") {
2112
+ try {
2113
+ if (getComputedStyle(el).direction === "rtl") return "rtl";
2114
+ } catch {
2115
+ }
2116
+ }
2117
+ try {
2118
+ const marked = el.closest?.("[dir]");
2119
+ if (marked) {
2120
+ return marked.getAttribute("dir")?.toLowerCase() === "rtl" ? "rtl" : "ltr";
2121
+ }
2122
+ } catch {
2123
+ }
2124
+ return "ltr";
2125
+ };
2126
+ var resolveMode = (mode, el) => {
2127
+ if (!isLogicalMode(mode)) return mode;
2128
+ const rtl = readDirection(el) === "rtl";
2129
+ if (mode === "start") return rtl ? "right" : "left";
2130
+ return rtl ? "left" : "right";
2131
+ };
2132
+
2087
2133
  // src/core/primitives/touch-scroll-guard.ts
2088
2134
  function installTouchScrollGuard(surface, isDragging) {
2089
2135
  const onTouchMove = (e) => {
@@ -2446,7 +2492,7 @@ function resolveEngineOptions(opts, extras) {
2446
2492
  }
2447
2493
  }
2448
2494
  return {
2449
- mode: opts.mode ?? "bottom",
2495
+ mode: resolveMode(opts.mode ?? "bottom", opts.element),
2450
2496
  flickVelocity: opts.flickVelocity ?? DEFAULT_FLICK_VELOCITY,
2451
2497
  dragThreshold: opts.dragThreshold ?? DEFAULT_DRAG_THRESHOLD,
2452
2498
  dragFrom: opts.dragFrom ?? (opts.handle ? "handle" : "sheet"),
@@ -2550,6 +2596,7 @@ var BottomSheetCore = class {
2550
2596
  __publicField(this, "disableDragFlag");
2551
2597
  __publicField(this, "closeOnRouteChange");
2552
2598
  __publicField(this, "maxHeight");
2599
+ __publicField(this, "maxHeightDeps");
2553
2600
  __publicField(this, "snapPointsRaw");
2554
2601
  __publicField(this, "snaps");
2555
2602
  __publicField(this, "activeId");
@@ -2557,6 +2604,7 @@ var BottomSheetCore = class {
2557
2604
  __publicField(this, "gesture");
2558
2605
  __publicField(this, "contentGesture");
2559
2606
  __publicField(this, "detachSheetGesture", null);
2607
+ __publicField(this, "detachSliderKeyboard", null);
2560
2608
  __publicField(this, "rootEl", null);
2561
2609
  __publicField(this, "destroyed", false);
2562
2610
  __publicField(this, "restClosed", false);
@@ -2608,6 +2656,7 @@ var BottomSheetCore = class {
2608
2656
  this.screenComponent = opts.scrim ?? opts.screenComponent;
2609
2657
  this.scrimParent = this.screenComponent?.parentElement ?? null;
2610
2658
  this.mode = resolved.mode;
2659
+ this.element.dataset.mode = this.mode;
2611
2660
  this.transformTemplate = buildTransformTemplate(this.mode);
2612
2661
  this.aria = new AriaSliderWriter(this.handle, this.mode);
2613
2662
  this.flickVelocity = resolved.flickVelocity;
@@ -2674,7 +2723,7 @@ var BottomSheetCore = class {
2674
2723
  auditVhUsage(this.snapPointsRaw);
2675
2724
  this.auditDuplicateSnapIds(this.snapPointsRaw);
2676
2725
  this.rootEl = this.element.closest(".bs-root");
2677
- this.maxHeight = createMaxHeightController({
2726
+ this.maxHeightDeps = {
2678
2727
  element: this.element,
2679
2728
  mode: this.mode,
2680
2729
  getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
@@ -2682,7 +2731,8 @@ var BottomSheetCore = class {
2682
2731
  this.snaps.setMaxAxisSize(size);
2683
2732
  },
2684
2733
  recompute: () => this.recompute()
2685
- });
2734
+ };
2735
+ this.maxHeight = createMaxHeightController(this.maxHeightDeps);
2686
2736
  this.fitDeps = {
2687
2737
  element: this.element,
2688
2738
  scrollContainer: this.scrollContainer,
@@ -3016,6 +3066,37 @@ var BottomSheetCore = class {
3016
3066
  getDragFrom() {
3017
3067
  return this.dragFromMode;
3018
3068
  }
3069
+ setMode(mode) {
3070
+ if (this.destroyed) return;
3071
+ const next = resolveMode(mode, this.element);
3072
+ if (next === this.mode) return;
3073
+ const wasVertical = this.mode === "bottom" || this.mode === "top";
3074
+ const nowVertical = next === "bottom" || next === "top";
3075
+ this.gesture?.forceClearDragState();
3076
+ this.detachSheetGesture?.();
3077
+ this.animation.cancel();
3078
+ this.element.style.removeProperty(layoutAxis(this.mode));
3079
+ this.mode = next;
3080
+ this.element.dataset.mode = next;
3081
+ this.transformTemplate = buildTransformTemplate(next);
3082
+ this.maxHeightDeps.mode = next;
3083
+ this.fitDeps.mode = next;
3084
+ this.snaps.setMode(next);
3085
+ this.scrim.setSheetMode(next);
3086
+ if (wasVertical !== nowVertical) {
3087
+ this.aria = new AriaSliderWriter(this.handle, next);
3088
+ }
3089
+ this.detachSliderKeyboard?.();
3090
+ this.mountSliderKeyboard();
3091
+ this.mountSheetGesture();
3092
+ this.recompute();
3093
+ const active = this.snaps.findById(this.activeId);
3094
+ if (active) this.applySize(active.size);
3095
+ this.updateAriaSlider();
3096
+ }
3097
+ getMode() {
3098
+ return this.mode;
3099
+ }
3019
3100
  isTop() {
3020
3101
  return this.isTopSheet;
3021
3102
  }
@@ -3364,7 +3445,7 @@ var BottomSheetCore = class {
3364
3445
  const point = this.snapPointsRaw.find((p) => p.id === this.activeId);
3365
3446
  return point?.dragFromContent ?? this.dragFromContentDefault;
3366
3447
  }
3367
- decideContentDrag(surface, e, delta) {
3448
+ decideContentDrag(surface, e, delta, crossDelta) {
3368
3449
  if (this.destroyed) return false;
3369
3450
  if (e.pointerType === "mouse") return false;
3370
3451
  if (this.gesture?.isDragging) return false;
@@ -3372,6 +3453,8 @@ var BottomSheetCore = class {
3372
3453
  if (!isDragAllowedFrom(e.target, "sheet")) return false;
3373
3454
  const decision = decideContentGesture({
3374
3455
  delta,
3456
+ crossDelta,
3457
+ sharesScrollAxis: this.mode === "bottom" || this.mode === "top",
3375
3458
  scrollTop: surface.scrollTop,
3376
3459
  atMaxSnap: this.size >= this.getAllowedRange().max - 0.5
3377
3460
  });
@@ -3384,7 +3467,7 @@ var BottomSheetCore = class {
3384
3467
  const controller = new GestureController(
3385
3468
  this.buildGestureDeps(surface, {
3386
3469
  manageTouchAction: false,
3387
- deferStart: (e, delta) => this.decideContentDrag(surface, e, delta)
3470
+ deferStart: (e, delta, crossDelta) => this.decideContentDrag(surface, e, delta, crossDelta)
3388
3471
  })
3389
3472
  );
3390
3473
  this.contentGesture = controller;
@@ -3510,7 +3593,11 @@ var BottomSheetCore = class {
3510
3593
  );
3511
3594
  }
3512
3595
  }
3513
- this.teardowns.add(installSliderKeyboard({
3596
+ this.mountSliderKeyboard();
3597
+ this.scrim.attach();
3598
+ }
3599
+ mountSliderKeyboard() {
3600
+ const detach = installSliderKeyboard({
3514
3601
  handle: this.handle,
3515
3602
  mode: this.mode,
3516
3603
  isDestroyed: () => this.destroyed,
@@ -3519,8 +3606,12 @@ var BottomSheetCore = class {
3519
3606
  snapTo: (id) => {
3520
3607
  void this.snapTo(id);
3521
3608
  }
3522
- }));
3523
- this.scrim.attach();
3609
+ });
3610
+ this.detachSliderKeyboard = detach;
3611
+ this.teardowns.add(() => {
3612
+ this.detachSliderKeyboard?.();
3613
+ this.detachSliderKeyboard = null;
3614
+ });
3524
3615
  }
3525
3616
  settleAfterDrag(delta, velocity, kind = "touch") {
3526
3617
  const signal = this.newCycle();
package/dist/debug.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { E as EngineState, d as SheetEventMap } from './BottomSheetCore-Cp7dWy91.cjs';
1
+ import { E as EngineState, S as SheetEventMap } from './BottomSheetCore-VPJZcKcg.cjs';
2
2
  import './transform-jVfAikE9.cjs';
3
3
 
4
4
  type DebugOverlayPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right";
package/dist/debug.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { E as EngineState, d as SheetEventMap } from './BottomSheetCore-DJYwWOqt.js';
1
+ import { E as EngineState, S as SheetEventMap } from './BottomSheetCore-Cgn8b_6A.js';
2
2
  import './transform-jVfAikE9.js';
3
3
 
4
4
  type DebugOverlayPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right";