@sprawlify/primitives 0.0.110 → 0.0.112

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 (221) hide show
  1. package/dist/{aria-hidden-BX4SWNE_.mjs → aria-hidden-C72KtklN.mjs} +1 -1
  2. package/dist/{aria-hidden-BAGrxNHt.cjs → aria-hidden-CIBHXlCy.cjs} +1 -1
  3. package/dist/aria-hidden.cjs +2 -2
  4. package/dist/aria-hidden.mjs +2 -2
  5. package/dist/{auto-resize-B1BDDnp1.cjs → auto-resize-BTTNXiml.cjs} +1 -1
  6. package/dist/{auto-resize-CN2vAzdj.mjs → auto-resize-CbNgN0OO.mjs} +1 -1
  7. package/dist/auto-resize.cjs +2 -2
  8. package/dist/auto-resize.mjs +2 -2
  9. package/dist/{core-BmIEKqtP.mjs → core-Ci9Yu6QI.mjs} +1 -1
  10. package/dist/{core-nBg9RC_y.cjs → core-DwdPztGA.cjs} +1 -1
  11. package/dist/core.cjs +2 -2
  12. package/dist/core.mjs +2 -2
  13. package/dist/{dismissable-DWfZGIA7.mjs → dismissable-B9k5K6f9.mjs} +2 -2
  14. package/dist/{dismissable-ChwcJMHk.cjs → dismissable-DxjbwsOf.cjs} +2 -2
  15. package/dist/dismissable.cjs +3 -3
  16. package/dist/dismissable.mjs +3 -3
  17. package/dist/{dom-query-s2ESLR2U.mjs → dom-query-BFuRs3l4.mjs} +1 -1
  18. package/dist/{dom-query-Bd63cRVF.cjs → dom-query-BUO7rGsg.cjs} +1 -1
  19. package/dist/dom-query.cjs +1 -1
  20. package/dist/dom-query.mjs +1 -1
  21. package/dist/{focus-trap-fucc6OU_.cjs → focus-trap-BewqTQFt.cjs} +1 -1
  22. package/dist/{focus-trap-DzBvBlTH.mjs → focus-trap-Do8IUXYh.mjs} +1 -1
  23. package/dist/focus-trap.cjs +2 -2
  24. package/dist/focus-trap.mjs +2 -2
  25. package/dist/{focus-visible-D5qBaAOn.mjs → focus-visible-BuLf8M9F.mjs} +10 -9
  26. package/dist/{focus-visible-75XTctXf.cjs → focus-visible-Co_9bW09.cjs} +15 -8
  27. package/dist/focus-visible.cjs +3 -2
  28. package/dist/focus-visible.d.cts +2 -1
  29. package/dist/focus-visible.d.mts +2 -1
  30. package/dist/focus-visible.mjs +3 -3
  31. package/dist/{i18n-utils-DB-lUfrr.cjs → i18n-utils-BRLqoCq8.cjs} +1 -1
  32. package/dist/{i18n-utils-oWZyUib_.mjs → i18n-utils-DZs1CPj8.mjs} +1 -1
  33. package/dist/i18n-utils.cjs +2 -2
  34. package/dist/i18n-utils.mjs +2 -2
  35. package/dist/{interact-outside-2qkUnl4N.mjs → interact-outside-Ba50N1a5.mjs} +1 -1
  36. package/dist/{interact-outside-Cx4J0EBf.cjs → interact-outside-Bg-QSXqp.cjs} +1 -1
  37. package/dist/interact-outside.cjs +2 -2
  38. package/dist/interact-outside.mjs +2 -2
  39. package/dist/machines/accordion/index.cjs +2 -2
  40. package/dist/machines/accordion/index.d.cts +1 -1
  41. package/dist/machines/accordion/index.d.mts +1 -1
  42. package/dist/machines/accordion/index.mjs +2 -2
  43. package/dist/machines/angle-slider/index.cjs +2 -2
  44. package/dist/machines/angle-slider/index.d.cts +1 -1
  45. package/dist/machines/angle-slider/index.d.mts +1 -1
  46. package/dist/machines/angle-slider/index.mjs +2 -2
  47. package/dist/machines/aspect-ratio/index.cjs +2 -2
  48. package/dist/machines/aspect-ratio/index.mjs +2 -2
  49. package/dist/machines/async-list/index.cjs +2 -2
  50. package/dist/machines/async-list/index.mjs +2 -2
  51. package/dist/machines/avatar/index.cjs +2 -2
  52. package/dist/machines/avatar/index.mjs +2 -2
  53. package/dist/machines/carousel/index.cjs +3 -3
  54. package/dist/machines/carousel/index.d.cts +1 -1
  55. package/dist/machines/carousel/index.d.mts +1 -1
  56. package/dist/machines/carousel/index.mjs +3 -3
  57. package/dist/machines/cascade-select/index.cjs +12 -7
  58. package/dist/machines/cascade-select/index.d.cts +2 -2
  59. package/dist/machines/cascade-select/index.d.mts +2 -2
  60. package/dist/machines/cascade-select/index.mjs +12 -7
  61. package/dist/machines/checkbox/index.cjs +3 -3
  62. package/dist/machines/checkbox/index.d.cts +1 -1
  63. package/dist/machines/checkbox/index.d.mts +1 -1
  64. package/dist/machines/checkbox/index.mjs +3 -3
  65. package/dist/machines/clipboard/index.cjs +2 -2
  66. package/dist/machines/clipboard/index.d.cts +1 -1
  67. package/dist/machines/clipboard/index.d.mts +1 -1
  68. package/dist/machines/clipboard/index.mjs +2 -2
  69. package/dist/machines/collapsible/index.cjs +2 -2
  70. package/dist/machines/collapsible/index.d.cts +1 -1
  71. package/dist/machines/collapsible/index.d.mts +1 -1
  72. package/dist/machines/collapsible/index.mjs +2 -2
  73. package/dist/machines/color-picker/index.cjs +5 -5
  74. package/dist/machines/color-picker/index.d.cts +1 -1
  75. package/dist/machines/color-picker/index.d.mts +1 -1
  76. package/dist/machines/color-picker/index.mjs +5 -5
  77. package/dist/machines/combobox/index.cjs +14 -8
  78. package/dist/machines/combobox/index.d.cts +1 -1
  79. package/dist/machines/combobox/index.d.mts +1 -1
  80. package/dist/machines/combobox/index.mjs +14 -8
  81. package/dist/machines/date-picker/index.cjs +5 -5
  82. package/dist/machines/date-picker/index.d.cts +1 -1
  83. package/dist/machines/date-picker/index.d.mts +1 -1
  84. package/dist/machines/date-picker/index.mjs +5 -5
  85. package/dist/machines/dialog/index.cjs +7 -7
  86. package/dist/machines/dialog/index.d.cts +1 -1
  87. package/dist/machines/dialog/index.d.mts +1 -1
  88. package/dist/machines/dialog/index.mjs +7 -7
  89. package/dist/machines/drawer/index.cjs +1574 -307
  90. package/dist/machines/drawer/index.d.cts +217 -35
  91. package/dist/machines/drawer/index.d.mts +217 -35
  92. package/dist/machines/drawer/index.mjs +1574 -309
  93. package/dist/machines/dropdown-menu/index.cjs +12 -7
  94. package/dist/machines/dropdown-menu/index.d.cts +1 -1
  95. package/dist/machines/dropdown-menu/index.d.mts +1 -1
  96. package/dist/machines/dropdown-menu/index.mjs +12 -7
  97. package/dist/machines/editable/index.cjs +3 -3
  98. package/dist/machines/editable/index.mjs +3 -3
  99. package/dist/machines/file-upload/index.cjs +3 -3
  100. package/dist/machines/file-upload/index.d.cts +1 -1
  101. package/dist/machines/file-upload/index.d.mts +1 -1
  102. package/dist/machines/file-upload/index.mjs +3 -3
  103. package/dist/machines/floating-panel/index.cjs +2 -2
  104. package/dist/machines/floating-panel/index.d.cts +1 -1
  105. package/dist/machines/floating-panel/index.d.mts +1 -1
  106. package/dist/machines/floating-panel/index.mjs +2 -2
  107. package/dist/machines/hover-card/index.cjs +5 -5
  108. package/dist/machines/hover-card/index.mjs +5 -5
  109. package/dist/machines/image-cropper/index.cjs +2 -2
  110. package/dist/machines/image-cropper/index.d.cts +1 -1
  111. package/dist/machines/image-cropper/index.d.mts +1 -1
  112. package/dist/machines/image-cropper/index.mjs +2 -2
  113. package/dist/machines/listbox/index.cjs +3 -3
  114. package/dist/machines/listbox/index.d.cts +1 -1
  115. package/dist/machines/listbox/index.d.mts +1 -1
  116. package/dist/machines/listbox/index.mjs +3 -3
  117. package/dist/machines/marquee/index.cjs +2 -2
  118. package/dist/machines/marquee/index.d.cts +3 -3
  119. package/dist/machines/marquee/index.d.mts +3 -3
  120. package/dist/machines/marquee/index.mjs +2 -2
  121. package/dist/machines/navigation-menu/index.cjs +4 -4
  122. package/dist/machines/navigation-menu/index.d.cts +1 -1
  123. package/dist/machines/navigation-menu/index.d.mts +1 -1
  124. package/dist/machines/navigation-menu/index.mjs +4 -4
  125. package/dist/machines/number-input/index.cjs +2 -2
  126. package/dist/machines/number-input/index.mjs +2 -2
  127. package/dist/machines/pagination/index.cjs +2 -2
  128. package/dist/machines/pagination/index.d.cts +1 -1
  129. package/dist/machines/pagination/index.d.mts +1 -1
  130. package/dist/machines/pagination/index.mjs +2 -2
  131. package/dist/machines/password-input/index.cjs +2 -2
  132. package/dist/machines/password-input/index.d.cts +1 -1
  133. package/dist/machines/password-input/index.d.mts +1 -1
  134. package/dist/machines/password-input/index.mjs +2 -2
  135. package/dist/machines/pin-input/index.cjs +2 -2
  136. package/dist/machines/pin-input/index.mjs +2 -2
  137. package/dist/machines/popover/index.cjs +8 -8
  138. package/dist/machines/popover/index.d.cts +1 -1
  139. package/dist/machines/popover/index.d.mts +1 -1
  140. package/dist/machines/popover/index.mjs +8 -8
  141. package/dist/machines/presence/index.cjs +2 -2
  142. package/dist/machines/presence/index.mjs +2 -2
  143. package/dist/machines/progress/index.cjs +2 -2
  144. package/dist/machines/progress/index.d.cts +1 -1
  145. package/dist/machines/progress/index.d.mts +1 -1
  146. package/dist/machines/progress/index.mjs +2 -2
  147. package/dist/machines/qr-code/index.cjs +2 -2
  148. package/dist/machines/qr-code/index.mjs +2 -2
  149. package/dist/machines/radio-group/index.cjs +3 -3
  150. package/dist/machines/radio-group/index.d.cts +1 -1
  151. package/dist/machines/radio-group/index.d.mts +1 -1
  152. package/dist/machines/radio-group/index.mjs +3 -3
  153. package/dist/machines/rating-group/index.cjs +2 -2
  154. package/dist/machines/rating-group/index.mjs +2 -2
  155. package/dist/machines/scroll-area/index.cjs +2 -2
  156. package/dist/machines/scroll-area/index.d.cts +1 -1
  157. package/dist/machines/scroll-area/index.d.mts +1 -1
  158. package/dist/machines/scroll-area/index.mjs +2 -2
  159. package/dist/machines/select/index.cjs +13 -8
  160. package/dist/machines/select/index.d.cts +1 -1
  161. package/dist/machines/select/index.d.mts +1 -1
  162. package/dist/machines/select/index.mjs +13 -8
  163. package/dist/machines/separator/index.cjs +2 -2
  164. package/dist/machines/separator/index.mjs +2 -2
  165. package/dist/machines/signature-pad/index.cjs +2 -2
  166. package/dist/machines/signature-pad/index.mjs +2 -2
  167. package/dist/machines/slider/index.cjs +2 -2
  168. package/dist/machines/slider/index.d.cts +1 -1
  169. package/dist/machines/slider/index.d.mts +1 -1
  170. package/dist/machines/slider/index.mjs +2 -2
  171. package/dist/machines/splitter/index.cjs +2 -2
  172. package/dist/machines/splitter/index.d.cts +1 -1
  173. package/dist/machines/splitter/index.d.mts +1 -1
  174. package/dist/machines/splitter/index.mjs +2 -2
  175. package/dist/machines/steps/index.cjs +2 -2
  176. package/dist/machines/steps/index.d.cts +1 -1
  177. package/dist/machines/steps/index.d.mts +1 -1
  178. package/dist/machines/steps/index.mjs +2 -2
  179. package/dist/machines/switch/index.cjs +3 -3
  180. package/dist/machines/switch/index.mjs +3 -3
  181. package/dist/machines/tabs/index.cjs +2 -2
  182. package/dist/machines/tabs/index.d.cts +1 -1
  183. package/dist/machines/tabs/index.d.mts +1 -1
  184. package/dist/machines/tabs/index.mjs +2 -2
  185. package/dist/machines/tags-input/index.cjs +4 -4
  186. package/dist/machines/tags-input/index.d.cts +1 -1
  187. package/dist/machines/tags-input/index.d.mts +1 -1
  188. package/dist/machines/tags-input/index.mjs +4 -4
  189. package/dist/machines/timer/index.cjs +2 -2
  190. package/dist/machines/timer/index.d.cts +1 -1
  191. package/dist/machines/timer/index.d.mts +1 -1
  192. package/dist/machines/timer/index.mjs +2 -2
  193. package/dist/machines/toast/index.cjs +4 -4
  194. package/dist/machines/toast/index.d.cts +3 -3
  195. package/dist/machines/toast/index.d.mts +3 -3
  196. package/dist/machines/toast/index.mjs +4 -4
  197. package/dist/machines/toggle/index.cjs +2 -2
  198. package/dist/machines/toggle/index.mjs +2 -2
  199. package/dist/machines/toggle-group/index.cjs +2 -2
  200. package/dist/machines/toggle-group/index.mjs +2 -2
  201. package/dist/machines/tooltip/index.cjs +9 -9
  202. package/dist/machines/tooltip/index.mjs +10 -10
  203. package/dist/machines/tour/index.cjs +6 -6
  204. package/dist/machines/tour/index.d.cts +1 -1
  205. package/dist/machines/tour/index.d.mts +1 -1
  206. package/dist/machines/tour/index.mjs +6 -6
  207. package/dist/machines/tree-view/index.cjs +2 -2
  208. package/dist/machines/tree-view/index.d.cts +1 -1
  209. package/dist/machines/tree-view/index.d.mts +1 -1
  210. package/dist/machines/tree-view/index.mjs +2 -2
  211. package/dist/{popper-BDy37WA0.mjs → popper-BlgbmdAn.mjs} +1 -1
  212. package/dist/{popper-Cx3KHzeT.cjs → popper-viCrafLC.cjs} +1 -1
  213. package/dist/popper.cjs +2 -2
  214. package/dist/popper.mjs +2 -2
  215. package/dist/{remove-scroll-D9FAOapi.cjs → remove-scroll-D4CMJmU2.cjs} +1 -1
  216. package/dist/{remove-scroll-HcSiTbd5.mjs → remove-scroll-D55GZoBb.mjs} +1 -1
  217. package/dist/{scroll-snap-DfSwN3As.mjs → scroll-snap-CdneVP31.mjs} +1 -1
  218. package/dist/{scroll-snap-Dp_2adEa.cjs → scroll-snap-vZ2q6dcN.cjs} +1 -1
  219. package/dist/scroll-snap.cjs +2 -2
  220. package/dist/scroll-snap.mjs +2 -2
  221. package/package.json +1 -1
@@ -1,48 +1,849 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_create_anatomy = require("../../create-anatomy-BnwEmNnc.cjs");
3
- const require_dom_query = require("../../dom-query-Bd63cRVF.cjs");
3
+ const require_dom_query = require("../../dom-query-BUO7rGsg.cjs");
4
4
  const require_defineProperty = require("../../defineProperty-8IOBQ1i_.cjs");
5
- const require_aria_hidden = require("../../aria-hidden-BAGrxNHt.cjs");
5
+ const require_aria_hidden = require("../../aria-hidden-CIBHXlCy.cjs");
6
6
  const require_utils = require("../../utils-ByNiZU8f.cjs");
7
- const require_core = require("../../core-nBg9RC_y.cjs");
8
- require("../../interact-outside-Cx4J0EBf.cjs");
9
- const require_dismissable = require("../../dismissable-ChwcJMHk.cjs");
10
- const require_focus_trap = require("../../focus-trap-fucc6OU_.cjs");
7
+ const require_core = require("../../core-DwdPztGA.cjs");
8
+ require("../../interact-outside-Bg-QSXqp.cjs");
9
+ const require_dismissable = require("../../dismissable-DxjbwsOf.cjs");
10
+ const require_focus_trap = require("../../focus-trap-BewqTQFt.cjs");
11
11
  const require_create_props = require("../../create-props-DP39rHnH.cjs");
12
- const require_remove_scroll = require("../../remove-scroll-D9FAOapi.cjs");
12
+ const require_remove_scroll = require("../../remove-scroll-D4CMJmU2.cjs");
13
13
  //#region src/machines/drawer/drawer.anatomy.ts
14
- const anatomy = require_create_anatomy.createAnatomy("drawer").parts("content", "title", "trigger", "backdrop", "grabber", "grabberIndicator", "closeTrigger");
14
+ const anatomy = require_create_anatomy.createAnatomy("drawer").parts("positioner", "content", "title", "description", "trigger", "backdrop", "grabber", "grabberIndicator", "closeTrigger", "swipeArea");
15
15
  const parts = anatomy.build();
16
16
  //#endregion
17
17
  //#region src/machines/drawer/drawer.dom.ts
18
18
  const getContentId = (ctx) => ctx.ids?.content ?? `drawer:${ctx.id}:content`;
19
+ const getPositionerId = (ctx) => ctx.ids?.positioner ?? `drawer:${ctx.id}:positioner`;
19
20
  const getTitleId = (ctx) => ctx.ids?.title ?? `drawer:${ctx.id}:title`;
21
+ const getDescriptionId = (ctx) => ctx.ids?.description ?? `drawer:${ctx.id}:description`;
20
22
  const getTriggerId = (ctx) => ctx.ids?.trigger ?? `drawer:${ctx.id}:trigger`;
21
23
  const getBackdropId = (ctx) => ctx.ids?.backdrop ?? `drawer:${ctx.id}:backdrop`;
22
24
  const getGrabberId = (ctx) => ctx.ids?.grabber ?? `drawer:${ctx.id}:grabber`;
23
25
  const getGrabberIndicatorId = (ctx) => ctx.ids?.grabberIndicator ?? `drawer:${ctx.id}:grabber-indicator`;
24
26
  const getCloseTriggerId = (ctx) => ctx.ids?.closeTrigger ?? `drawer:${ctx.id}:close-trigger`;
27
+ const getSwipeAreaId = (ctx) => ctx.ids?.swipeArea ?? `drawer:${ctx.id}:swipe-area`;
25
28
  const getContentEl = (ctx) => ctx.getById(getContentId(ctx));
29
+ const getTitleEl = (ctx) => ctx.getById(getTitleId(ctx));
30
+ const getDescriptionEl = (ctx) => ctx.getById(getDescriptionId(ctx));
26
31
  const getTriggerEl = (ctx) => ctx.getById(getTriggerId(ctx));
32
+ const getBackdropEl = (ctx) => ctx.getById(getBackdropId(ctx));
27
33
  const getCloseTriggerEl = (ctx) => ctx.getById(getCloseTriggerId(ctx));
34
+ const getSwipeAreaEl = (ctx) => ctx.getById(getSwipeAreaId(ctx));
35
+ //#endregion
36
+ //#region src/machines/drawer/utils/snap-point.ts
37
+ function resolveSnapPointValue(snapPoint, viewportSize, rootFontSize) {
38
+ if (!Number.isFinite(viewportSize) || viewportSize <= 0) return null;
39
+ if (typeof snapPoint === "number") {
40
+ if (!Number.isFinite(snapPoint)) return null;
41
+ if (snapPoint <= 1) return require_utils.clampValue(snapPoint, 0, 1) * viewportSize;
42
+ return snapPoint;
43
+ }
44
+ const trimmed = snapPoint.trim();
45
+ if (trimmed.endsWith("px")) {
46
+ const value = Number.parseFloat(trimmed);
47
+ return Number.isFinite(value) ? value : null;
48
+ }
49
+ if (trimmed.endsWith("rem")) {
50
+ const value = Number.parseFloat(trimmed);
51
+ return Number.isFinite(value) ? value * rootFontSize : null;
52
+ }
53
+ return null;
54
+ }
55
+ function resolveSnapPoint(snapPoint, options) {
56
+ const { contentSize, viewportSize, rootFontSize } = options;
57
+ const maxSize = Math.min(contentSize, viewportSize);
58
+ if (!Number.isFinite(maxSize) || maxSize <= 0) return null;
59
+ const resolvedSize = resolveSnapPointValue(snapPoint, viewportSize, rootFontSize);
60
+ if (resolvedSize === null || !Number.isFinite(resolvedSize)) return null;
61
+ const height = require_utils.clampValue(resolvedSize, 0, maxSize);
62
+ return {
63
+ value: snapPoint,
64
+ height,
65
+ offset: Math.max(0, contentSize - height)
66
+ };
67
+ }
68
+ const HEIGHT_DEDUP_EPSILON_PX = 1;
69
+ function dedupeSnapPoints(points) {
70
+ if (points.length <= 1) return points;
71
+ const deduped = [];
72
+ const seenHeights = [];
73
+ for (let index = points.length - 1; index >= 0; index -= 1) {
74
+ const point = points[index];
75
+ if (seenHeights.some((height) => Math.abs(height - point.height) <= HEIGHT_DEDUP_EPSILON_PX)) continue;
76
+ seenHeights.push(point.height);
77
+ deduped.push(point);
78
+ }
79
+ deduped.reverse();
80
+ return deduped;
81
+ }
82
+ function findClosestSnapPoint(offset, snapPoints) {
83
+ return snapPoints.reduce((acc, curr) => {
84
+ const closestDiff = Math.abs(offset - acc.offset);
85
+ return Math.abs(offset - curr.offset) < closestDiff ? curr : acc;
86
+ });
87
+ }
88
+ //#endregion
89
+ //#region src/machines/drawer/utils/session.ts
90
+ const VELOCITY_WINDOW_MS = 100;
91
+ const MAX_RELEASE_VELOCITY_AGE_MS = 80;
92
+ const MIN_GESTURE_DURATION_MS = 50;
93
+ const MIN_VELOCITY_SAMPLES = 2;
94
+ const SAMPLE_BUFFER_COMPACT_THRESHOLD = 8;
95
+ const DEFERRED_DRAG_MIN_MAIN_AXIS_PX = 6;
96
+ const DEFERRED_DRAG_MAIN_OVER_CROSS_RATIO = 1.35;
97
+ function isVerticalSwipeDirection(direction) {
98
+ return direction === "down" || direction === "up";
99
+ }
100
+ function isNegativeSwipeDirection(direction) {
101
+ return direction === "up" || direction === "left";
102
+ }
103
+ var SwipeSession = class {
104
+ constructor() {
105
+ require_defineProperty._defineProperty(this, "startPoint", null);
106
+ require_defineProperty._defineProperty(this, "velocity", null);
107
+ require_defineProperty._defineProperty(this, "samples", []);
108
+ require_defineProperty._defineProperty(this, "sampleStartIndex", 0);
109
+ require_defineProperty._defineProperty(this, "gestureStartAxis", null);
110
+ require_defineProperty._defineProperty(this, "gestureStartTime", null);
111
+ require_defineProperty._defineProperty(this, "gestureSign", 1);
112
+ require_defineProperty._defineProperty(this, "pendingSwipe", null);
113
+ }
114
+ setStartPoint(point) {
115
+ this.startPoint = point;
116
+ }
117
+ clearStartPoint() {
118
+ this.startPoint = null;
119
+ }
120
+ getStartPoint() {
121
+ return this.startPoint;
122
+ }
123
+ getGestureAxis(direction) {
124
+ return direction === "left" || direction === "right" ? "x" : "y";
125
+ }
126
+ getGestureSign(direction) {
127
+ return isNegativeSwipeDirection(direction) ? -1 : 1;
128
+ }
129
+ getAxisValue(point, axis) {
130
+ return point[axis];
131
+ }
132
+ getMainAxisDisplacement(point, axis, sign) {
133
+ if (!this.startPoint) return 0;
134
+ return (this.getAxisValue(this.startPoint, axis) - this.getAxisValue(point, axis)) * sign;
135
+ }
136
+ getCrossAxisDisplacement(point, axis) {
137
+ if (!this.startPoint) return 0;
138
+ const crossAxis = axis === "x" ? "y" : "x";
139
+ const startAxis = this.getAxisValue(this.startPoint, crossAxis);
140
+ return this.getAxisValue(point, crossAxis) - startAxis;
141
+ }
142
+ track(point, axis, sign) {
143
+ const axisValue = this.getAxisValue(point, axis);
144
+ const now = performance.now();
145
+ if (this.gestureStartAxis === null) {
146
+ this.gestureStartAxis = axisValue;
147
+ this.gestureStartTime = now;
148
+ this.gestureSign = sign;
149
+ }
150
+ this.samples.push({
151
+ axis: axisValue,
152
+ time: now
153
+ });
154
+ const cutoff = now - VELOCITY_WINDOW_MS;
155
+ while (this.sampleStartIndex < this.samples.length && this.samples[this.sampleStartIndex].time < cutoff) this.sampleStartIndex += 1;
156
+ if (this.sampleStartIndex >= SAMPLE_BUFFER_COMPACT_THRESHOLD) {
157
+ this.samples = this.samples.slice(this.sampleStartIndex);
158
+ this.sampleStartIndex = 0;
159
+ }
160
+ if (this.samples.length - this.sampleStartIndex < MIN_VELOCITY_SAMPLES) {
161
+ this.velocity = 0;
162
+ return;
163
+ }
164
+ const oldest = this.samples[this.sampleStartIndex];
165
+ const newest = this.samples[this.samples.length - 1];
166
+ const dt = newest.time - oldest.time;
167
+ if (dt <= 0) {
168
+ this.velocity = 0;
169
+ return;
170
+ }
171
+ const velocity = (newest.axis - oldest.axis) * sign / dt * 1e3;
172
+ this.velocity = Number.isFinite(velocity) ? velocity : 0;
173
+ }
174
+ getReleaseVelocity() {
175
+ const now = performance.now();
176
+ if (this.samples.length - this.sampleStartIndex >= MIN_VELOCITY_SAMPLES) {
177
+ if (now - this.samples[this.samples.length - 1].time <= MAX_RELEASE_VELOCITY_AGE_MS) return this.velocity ?? 0;
178
+ }
179
+ if (this.gestureStartAxis !== null && this.gestureStartTime !== null) {
180
+ const lastSample = this.samples[this.samples.length - 1];
181
+ if (lastSample) {
182
+ const dt = Math.max(lastSample.time - this.gestureStartTime, MIN_GESTURE_DURATION_MS);
183
+ const velocity = (lastSample.axis - this.gestureStartAxis) * this.gestureSign / dt * 1e3;
184
+ return Number.isFinite(velocity) ? velocity : 0;
185
+ }
186
+ }
187
+ return this.velocity ?? 0;
188
+ }
189
+ clearVelocityTracking() {
190
+ this.samples = [];
191
+ this.sampleStartIndex = 0;
192
+ this.velocity = null;
193
+ this.gestureStartAxis = null;
194
+ this.gestureStartTime = null;
195
+ this.gestureSign = 1;
196
+ }
197
+ clear() {
198
+ this.cancelDeferredSwipe();
199
+ this.clearStartPoint();
200
+ this.clearVelocityTracking();
201
+ }
202
+ startDeferredSwipe(options) {
203
+ const { getWin, pointerId, startPoint, swipeDirection, onCommit, canCommit, onCancel } = options;
204
+ this.cancelDeferredSwipe();
205
+ const win = getWin();
206
+ const vertical = isVerticalSwipeDirection(swipeDirection);
207
+ const onMove = (event) => {
208
+ if (event.pointerId !== pointerId) return;
209
+ const dx = event.clientX - startPoint.x;
210
+ const dy = event.clientY - startPoint.y;
211
+ const mainDelta = vertical ? dy : dx;
212
+ const crossDelta = vertical ? dx : dy;
213
+ const absMain = Math.abs(mainDelta);
214
+ if (absMain >= DEFERRED_DRAG_MIN_MAIN_AXIS_PX && absMain >= Math.abs(crossDelta) * DEFERRED_DRAG_MAIN_OVER_CROSS_RATIO) {
215
+ if (!canCommit || canCommit()) onCommit(startPoint);
216
+ this.cancelDeferredSwipe();
217
+ }
218
+ };
219
+ const onEnd = (event) => {
220
+ if (event.pointerId !== pointerId) return;
221
+ onCancel?.();
222
+ this.cancelDeferredSwipe();
223
+ };
224
+ this.pendingSwipe = {
225
+ pointerId,
226
+ startPoint,
227
+ cleanups: [
228
+ require_dom_query.addDomEvent(win, "pointermove", onMove, { capture: true }),
229
+ require_dom_query.addDomEvent(win, "pointerup", onEnd, { capture: true }),
230
+ require_dom_query.addDomEvent(win, "pointercancel", onEnd, { capture: true }),
231
+ require_dom_query.addDomEvent(win, "lostpointercapture", onEnd, { capture: true })
232
+ ]
233
+ };
234
+ }
235
+ cancelDeferredSwipe() {
236
+ if (!this.pendingSwipe) return;
237
+ this.pendingSwipe.cleanups.forEach((cleanup) => cleanup());
238
+ this.pendingSwipe = null;
239
+ }
240
+ bind(options) {
241
+ const { getDoc, getSelectionTarget, swipeDirection, onStart, onMove, onEnd, onCancel, preventDefault, cancelOnInterrupt } = options;
242
+ const doc = getDoc();
243
+ let usingTouchEvents = false;
244
+ let restoreSelection;
245
+ const axis = this.getGestureAxis(swipeDirection);
246
+ const sign = this.getGestureSign(swipeDirection);
247
+ const trackPoint = (point) => {
248
+ this.track(point, axis, sign);
249
+ };
250
+ const startSelectionGuard = () => {
251
+ restoreSelection ?? (restoreSelection = require_dom_query.disableTextSelection({
252
+ doc,
253
+ target: getSelectionTarget?.()
254
+ }));
255
+ };
256
+ const stopSelectionGuard = () => {
257
+ restoreSelection?.();
258
+ restoreSelection = void 0;
259
+ };
260
+ function onPointerMove(event) {
261
+ if (event.pointerType === "touch" && usingTouchEvents) return;
262
+ const point = require_dom_query.getEventPoint(event);
263
+ const target = require_dom_query.getEventTarget(event);
264
+ startSelectionGuard();
265
+ trackPoint(point);
266
+ onMove({
267
+ point,
268
+ target,
269
+ event,
270
+ pointerType: event.pointerType,
271
+ axis,
272
+ swipeDirection
273
+ });
274
+ }
275
+ function onPointerUp(event) {
276
+ if (event.pointerType === "touch" && usingTouchEvents) {
277
+ usingTouchEvents = false;
278
+ return;
279
+ }
280
+ stopSelectionGuard();
281
+ onEnd({
282
+ point: require_dom_query.getEventPoint(event),
283
+ swipeDirection
284
+ });
285
+ }
286
+ function onPointerCancel(event) {
287
+ if (event.pointerType === "touch" && usingTouchEvents) {
288
+ usingTouchEvents = false;
289
+ return;
290
+ }
291
+ stopSelectionGuard();
292
+ onCancel();
293
+ }
294
+ function onTouchStartEvent(event) {
295
+ if (!event.touches[0]) return;
296
+ usingTouchEvents = true;
297
+ const point = require_dom_query.getEventPoint(event);
298
+ const target = require_dom_query.getEventTarget(event);
299
+ onStart?.({
300
+ point,
301
+ target,
302
+ event,
303
+ pointerType: "touch",
304
+ axis,
305
+ swipeDirection
306
+ });
307
+ }
308
+ function onTouchMoveEvent(event) {
309
+ if (!event.touches[0]) return;
310
+ usingTouchEvents = true;
311
+ const point = require_dom_query.getEventPoint(event);
312
+ const details = {
313
+ point,
314
+ target: require_dom_query.getEventTarget(event),
315
+ event,
316
+ pointerType: "touch",
317
+ axis,
318
+ swipeDirection
319
+ };
320
+ if (preventDefault?.(details) && event.cancelable) event.preventDefault();
321
+ startSelectionGuard();
322
+ trackPoint(point);
323
+ onMove(details);
324
+ }
325
+ function onTouchEnd(event) {
326
+ if (event.touches.length !== 0) return;
327
+ stopSelectionGuard();
328
+ onEnd({
329
+ point: require_dom_query.getEventPoint(event),
330
+ swipeDirection
331
+ });
332
+ }
333
+ function onTouchCancel() {
334
+ stopSelectionGuard();
335
+ onCancel();
336
+ }
337
+ function onVisibilityChange() {
338
+ if (doc.visibilityState !== "hidden") return;
339
+ if (cancelOnInterrupt?.({
340
+ reason: "visibility-hidden",
341
+ event: doc,
342
+ target: null,
343
+ pointerType: null
344
+ }) === false) return;
345
+ stopSelectionGuard();
346
+ onCancel();
347
+ }
348
+ function onLostPointerCapture(event) {
349
+ if (event.pointerType === "touch") return;
350
+ const target = require_dom_query.getEventTarget(event);
351
+ if (cancelOnInterrupt?.({
352
+ reason: "lost-pointer-capture",
353
+ event,
354
+ target,
355
+ pointerType: event.pointerType
356
+ }) === false) return;
357
+ onCancel();
358
+ }
359
+ const cleanups = [
360
+ require_dom_query.addDomEvent(doc, "pointermove", onPointerMove),
361
+ require_dom_query.addDomEvent(doc, "pointerup", onPointerUp),
362
+ require_dom_query.addDomEvent(doc, "pointercancel", onPointerCancel),
363
+ require_dom_query.addDomEvent(doc, "touchstart", onTouchStartEvent, {
364
+ capture: true,
365
+ passive: false
366
+ }),
367
+ require_dom_query.addDomEvent(doc, "touchmove", onTouchMoveEvent, {
368
+ capture: true,
369
+ passive: false
370
+ }),
371
+ require_dom_query.addDomEvent(doc, "touchend", onTouchEnd, { capture: true }),
372
+ require_dom_query.addDomEvent(doc, "touchcancel", onTouchCancel, { capture: true }),
373
+ require_dom_query.addDomEvent(doc, "visibilitychange", onVisibilityChange),
374
+ require_dom_query.addDomEvent(doc, "lostpointercapture", onLostPointerCapture, true)
375
+ ];
376
+ return () => {
377
+ stopSelectionGuard();
378
+ cleanups.forEach((cleanup) => cleanup());
379
+ };
380
+ }
381
+ };
382
+ //#endregion
383
+ //#region src/machines/drawer/utils/drawer-session.ts
384
+ const RELEASE_DISPLACEMENT_TRUST_PX = 24;
385
+ const OPEN_SWIPE_HIDDEN_VISIBLE_RATIO = .22;
386
+ const OPEN_SWIPE_HIDDEN_VELOCITY_MULTIPLIER = 1.25;
387
+ const OPEN_SWIPE_REVEALED_VISIBLE_RATIO = .5;
388
+ const OPEN_SWIPE_REVEALED_OPPOSING_MAX_ABS_VELOCITY = 650;
389
+ const DRAG_START_THRESHOLD = .3;
390
+ const CROSS_AXIS_BIAS = .58;
391
+ const SCROLL_SLACK_GATE = .5;
392
+ const SCROLL_SLACK_EPSILON = 1;
393
+ const SEQUENTIAL_THRESHOLD = 24;
394
+ const SNAP_VELOCITY_THRESHOLD = 400;
395
+ const SNAP_VELOCITY_MULTIPLIER = .4;
396
+ const MAX_SNAP_VELOCITY = 4e3;
397
+ const SWIPE_STRENGTH_MAX_DURATION_MS = 360;
398
+ const SWIPE_STRENGTH_MIN_SCALAR = .1;
399
+ const SWIPE_STRENGTH_MAX_SCALAR = 1;
400
+ const SWIPE_AREA_OPEN_INTENT_MIN_PX = 5;
401
+ const NO_DRAG_DATA_ATTR = "data-no-drag";
402
+ const NO_DRAG_SELECTOR = `[${NO_DRAG_DATA_ATTR}]`;
403
+ var DrawerSwipeSession = class {
404
+ constructor(options) {
405
+ require_defineProperty._defineProperty(this, "session", new SwipeSession());
406
+ require_defineProperty._defineProperty(this, "dragOffset", null);
407
+ require_defineProperty._defineProperty(this, "preventDragOnScroll", void 0);
408
+ this.preventDragOnScroll = options.preventDragOnScroll;
409
+ }
410
+ contentPointerDown(options) {
411
+ const { event, getDoc, getContentEl, getWin, swipeDirection, canCommit, onCommit } = options;
412
+ if (shouldIgnorePointerDownForDrag(event)) return;
413
+ if (isTextSelectionInDrawer(getDoc(), getContentEl())) return;
414
+ if (!canCommit()) return;
415
+ const point = require_dom_query.getEventPoint(event);
416
+ if (!(event.pointerType === "mouse" || event.pointerType === "pen")) {
417
+ onCommit(point);
418
+ return;
419
+ }
420
+ this.session.startDeferredSwipe({
421
+ getWin,
422
+ pointerId: event.pointerId,
423
+ startPoint: point,
424
+ swipeDirection,
425
+ onCommit,
426
+ canCommit
427
+ });
428
+ }
429
+ grabberPointerDown(options) {
430
+ const { event, point, canCommit, onCommit } = options;
431
+ if (shouldIgnorePointerDownForDrag(event)) return;
432
+ this.session.cancelDeferredSwipe();
433
+ if (!canCommit()) return;
434
+ onCommit(point);
435
+ }
436
+ adjustReleaseVelocityAgainstDisplacement(velocity, displacementFromSnap) {
437
+ const displacementSign = Math.sign(displacementFromSnap);
438
+ const velocitySign = Math.sign(velocity);
439
+ if (displacementSign !== 0 && Math.abs(displacementFromSnap) >= RELEASE_DISPLACEMENT_TRUST_PX && velocitySign !== 0 && velocitySign !== displacementSign) return 0;
440
+ return velocity;
441
+ }
442
+ adjustReleaseVelocityForOpenSwipe(velocity, visibleRatio, swipeVelocityThreshold) {
443
+ if (visibleRatio < OPEN_SWIPE_HIDDEN_VISIBLE_RATIO && velocity < 0 && Math.abs(velocity) < swipeVelocityThreshold * OPEN_SWIPE_HIDDEN_VELOCITY_MULTIPLIER) return 0;
444
+ if (visibleRatio > OPEN_SWIPE_REVEALED_VISIBLE_RATIO && velocity > 0 && Math.abs(velocity) < OPEN_SWIPE_REVEALED_OPPOSING_MAX_ABS_VELOCITY) return 0;
445
+ return velocity;
446
+ }
447
+ beginSwipe(point) {
448
+ this.session.setStartPoint(point);
449
+ }
450
+ clearSwipeStart() {
451
+ this.session.clearStartPoint();
452
+ }
453
+ getSwipeStart() {
454
+ return this.session.getStartPoint();
455
+ }
456
+ getDragOffset() {
457
+ return this.dragOffset;
458
+ }
459
+ resetDragOffset() {
460
+ this.dragOffset = null;
461
+ }
462
+ resetVelocity() {
463
+ this.session.clearVelocityTracking();
464
+ }
465
+ reset() {
466
+ this.dragOffset = null;
467
+ this.session.clear();
468
+ }
469
+ setDragOffset(point, resolvedActiveSnapPointOffset, direction) {
470
+ if (!this.session.getStartPoint()) {
471
+ this.dragOffset = null;
472
+ return;
473
+ }
474
+ const axis = this.session.getGestureAxis(direction);
475
+ const sign = this.session.getGestureSign(direction);
476
+ let delta = this.session.getMainAxisDisplacement(point, axis, sign) - resolvedActiveSnapPointOffset;
477
+ if (delta > 0) delta = Math.sqrt(delta);
478
+ this.dragOffset = -delta;
479
+ }
480
+ setSwipeOpenOffset(point, contentSize, direction) {
481
+ if (!this.session.getStartPoint()) {
482
+ this.dragOffset = null;
483
+ return;
484
+ }
485
+ const axis = this.session.getGestureAxis(direction);
486
+ const sign = this.session.getGestureSign(direction);
487
+ const openDisplacement = this.session.getMainAxisDisplacement(point, axis, sign);
488
+ let dragOffset = contentSize - Math.max(0, openDisplacement);
489
+ if (dragOffset < 0) dragOffset = -Math.sqrt(Math.abs(dragOffset));
490
+ this.dragOffset = dragOffset;
491
+ }
492
+ canStartDrag(point, target, container, preventDragOnScroll, direction) {
493
+ if (!require_dom_query.isHTMLElement(target)) return false;
494
+ if (isDragExemptElement(target)) return false;
495
+ if (!this.session.getStartPoint() || !container) return false;
496
+ if (!preventDragOnScroll) return true;
497
+ const axis = this.session.getGestureAxis(direction);
498
+ const sign = this.session.getGestureSign(direction);
499
+ const delta = this.session.getMainAxisDisplacement(point, axis, sign);
500
+ if (Math.abs(delta) < DRAG_START_THRESHOLD) return false;
501
+ if (Math.abs(this.session.getCrossAxisDisplacement(point, axis)) > Math.abs(delta) * CROSS_AXIS_BIAS) {
502
+ const crossScroll = getScrollInfo(target, container, isVerticalSwipeDirection(direction) ? "right" : "down");
503
+ if (crossScroll.availableForwardScroll > SCROLL_SLACK_GATE || crossScroll.availableBackwardScroll > SCROLL_SLACK_GATE) return false;
504
+ }
505
+ const { availableForwardScroll, availableBackwardScroll } = getScrollInfo(target, container, direction);
506
+ if (delta > 0 && availableForwardScroll > SCROLL_SLACK_GATE || delta < 0 && availableBackwardScroll > SCROLL_SLACK_GATE) return false;
507
+ return true;
508
+ }
509
+ resolveSnapPointOnRelease(snapPoints, snapPoint, snapToSequentialPoints, contentSize) {
510
+ const dragOffset = this.dragOffset;
511
+ if (dragOffset === null) return snapPoints[0]?.value ?? 1;
512
+ const releaseVelocity = this.session.getReleaseVelocity();
513
+ if (snapToSequentialPoints && snapPoint) {
514
+ const ordered = [...snapPoints].sort((a, b) => a.offset - b.offset);
515
+ let currentIndex = 0;
516
+ let closestDist = Math.abs(snapPoint.offset - ordered[0].offset);
517
+ for (let i = 1; i < ordered.length; i++) {
518
+ const dist = Math.abs(snapPoint.offset - ordered[i].offset);
519
+ if (dist < closestDist) {
520
+ closestDist = dist;
521
+ currentIndex = i;
522
+ }
523
+ }
524
+ const currentPoint = ordered[currentIndex];
525
+ const delta = dragOffset - currentPoint.offset;
526
+ const dragDirection = Math.sign(delta);
527
+ const velocityAdjusted = this.adjustReleaseVelocityAgainstDisplacement(releaseVelocity, delta);
528
+ const velocityDirection = Math.sign(velocityAdjusted);
529
+ let targetSnapPoint = currentPoint;
530
+ let effectiveTargetOffset = dragOffset;
531
+ if (dragDirection !== 0 && velocityDirection === dragDirection && Math.abs(velocityAdjusted) >= SNAP_VELOCITY_THRESHOLD) {
532
+ const adjacentIndex = Math.min(Math.max(currentIndex + dragDirection, 0), ordered.length - 1);
533
+ if (adjacentIndex !== currentIndex) {
534
+ targetSnapPoint = ordered[adjacentIndex];
535
+ effectiveTargetOffset = targetSnapPoint.offset;
536
+ } else if (dragDirection > 0) return null;
537
+ } else if (delta > SEQUENTIAL_THRESHOLD) {
538
+ const nextPoint = ordered[Math.min(currentIndex + 1, ordered.length - 1)];
539
+ if (nextPoint) {
540
+ targetSnapPoint = nextPoint;
541
+ effectiveTargetOffset = nextPoint.offset;
542
+ }
543
+ } else if (delta < -SEQUENTIAL_THRESHOLD) {
544
+ const prevPoint = ordered[Math.max(currentIndex - 1, 0)];
545
+ if (prevPoint) {
546
+ targetSnapPoint = prevPoint;
547
+ effectiveTargetOffset = prevPoint.offset;
548
+ }
549
+ }
550
+ if (Math.abs(effectiveTargetOffset - contentSize) < Math.abs(effectiveTargetOffset - targetSnapPoint.offset)) return null;
551
+ return targetSnapPoint.value;
552
+ }
553
+ const snapRestOffset = snapPoint?.offset ?? 0;
554
+ const velocity = this.adjustReleaseVelocityAgainstDisplacement(releaseVelocity, dragOffset - snapRestOffset);
555
+ let targetOffset = dragOffset;
556
+ if (Math.abs(velocity) >= SNAP_VELOCITY_THRESHOLD) {
557
+ const clamped = require_utils.clampValue(velocity, -MAX_SNAP_VELOCITY, MAX_SNAP_VELOCITY);
558
+ targetOffset += clamped * SNAP_VELOCITY_MULTIPLIER;
559
+ targetOffset = Math.max(0, targetOffset);
560
+ }
561
+ return findClosestSnapPoint(targetOffset, snapPoints).value;
562
+ }
563
+ shouldOpenOnRelease(contentSize, swipeVelocityThreshold, openThreshold) {
564
+ const dragOffset = this.dragOffset;
565
+ if (dragOffset === null || contentSize === null) return false;
566
+ const visibleSize = contentSize - dragOffset;
567
+ const visibleRatio = visibleSize / contentSize;
568
+ const velocity = this.adjustReleaseVelocityForOpenSwipe(this.session.getReleaseVelocity(), visibleRatio, swipeVelocityThreshold);
569
+ return velocity < 0 && Math.abs(velocity) >= swipeVelocityThreshold || visibleSize >= contentSize * openThreshold;
570
+ }
571
+ shouldDismissOnRelease(contentSize, snapPoints, resolvedSnapOffset) {
572
+ const dragOffset = this.dragOffset;
573
+ if (dragOffset === null || contentSize === null) return false;
574
+ const velocity = this.adjustReleaseVelocityAgainstDisplacement(this.session.getReleaseVelocity(), dragOffset - resolvedSnapOffset);
575
+ if (contentSize - dragOffset <= 0) return true;
576
+ let targetOffset = dragOffset;
577
+ if (Math.abs(velocity) >= SNAP_VELOCITY_THRESHOLD) {
578
+ const clamped = require_utils.clampValue(velocity, -MAX_SNAP_VELOCITY, MAX_SNAP_VELOCITY);
579
+ targetOffset += clamped * SNAP_VELOCITY_MULTIPLIER;
580
+ targetOffset = Math.max(0, targetOffset);
581
+ }
582
+ const closeDistance = Math.abs(targetOffset - contentSize);
583
+ const closest = findClosestSnapPoint(targetOffset, snapPoints);
584
+ return closeDistance < Math.abs(targetOffset - closest.offset);
585
+ }
586
+ getSwipeStrength(targetOffset, resolvedSnapOffset = null) {
587
+ const dragOffset = this.dragOffset;
588
+ if (dragOffset === null) return SWIPE_STRENGTH_MAX_SCALAR;
589
+ let velocity = this.session.getReleaseVelocity();
590
+ if (resolvedSnapOffset != null) velocity = this.adjustReleaseVelocityAgainstDisplacement(velocity, dragOffset - resolvedSnapOffset);
591
+ const distance = Math.abs(dragOffset - targetOffset);
592
+ const absVelocity = Math.abs(velocity);
593
+ if (absVelocity <= 0 || distance <= 0) return SWIPE_STRENGTH_MAX_SCALAR;
594
+ return SWIPE_STRENGTH_MIN_SCALAR + require_utils.clampValue(distance / absVelocity * 1e3 / SWIPE_STRENGTH_MAX_DURATION_MS, 0, 1) * (SWIPE_STRENGTH_MAX_SCALAR - SWIPE_STRENGTH_MIN_SCALAR);
595
+ }
596
+ bindDragTracking(options) {
597
+ const { getDoc, getContentEl, getSwipeAreaEl, swipeDirection, onMove, onEnd, onCancel } = options;
598
+ const preventDragOnScroll = this.preventDragOnScroll;
599
+ const isVertical = isVerticalSwipeDirection(swipeDirection);
600
+ let lastAxis = 0;
601
+ return this.session.bind({
602
+ getDoc,
603
+ getSelectionTarget: getContentEl,
604
+ swipeDirection,
605
+ onMove,
606
+ onEnd,
607
+ onCancel,
608
+ cancelOnInterrupt: ({ reason, target }) => {
609
+ if (reason !== "lost-pointer-capture") return true;
610
+ return isWithinDrawerInteractionSurface(target, getContentEl(), getSwipeAreaEl());
611
+ },
612
+ onStart({ pointerType, point }) {
613
+ if (pointerType !== "touch") return;
614
+ lastAxis = isVertical ? point.y : point.x;
615
+ },
616
+ preventDefault({ event, pointerType, point, target }) {
617
+ if (pointerType !== "touch") return false;
618
+ const contentEl = getContentEl();
619
+ const resolvedTarget = target ?? event.target;
620
+ if (!preventDragOnScroll()) return false;
621
+ if (!contentEl || !resolvedTarget || isDragExemptElement(resolvedTarget)) return false;
622
+ const scrollParent = findClosestScrollableAncestorOnSwipeAxis(resolvedTarget, contentEl, swipeDirection);
623
+ if (scrollParent) {
624
+ const currentAxis = isVertical ? point.y : point.x;
625
+ const shouldPrevent = shouldPreventTouchScroll({
626
+ scrollParent,
627
+ swipeDirection,
628
+ lastMainAxis: lastAxis,
629
+ currentMainAxis: currentAxis
630
+ });
631
+ lastAxis = currentAxis;
632
+ return shouldPrevent;
633
+ }
634
+ lastAxis = isVertical ? point.y : point.x;
635
+ return false;
636
+ }
637
+ });
638
+ }
639
+ bindSwipeOpenTracking(options) {
640
+ const { getDoc, getContentEl, getSwipeAreaEl, swipeDirection, onMove, onEnd, onCancel } = options;
641
+ return this.session.bind({
642
+ getDoc,
643
+ getSelectionTarget: getSwipeAreaEl,
644
+ swipeDirection,
645
+ onMove({ point }) {
646
+ onMove({ point });
647
+ },
648
+ onEnd,
649
+ onCancel,
650
+ cancelOnInterrupt: ({ reason, target }) => {
651
+ if (reason !== "lost-pointer-capture") return true;
652
+ return isWithinDrawerInteractionSurface(target, getContentEl(), getSwipeAreaEl());
653
+ }
654
+ });
655
+ }
656
+ };
657
+ function isWithinDrawerInteractionSurface(target, contentEl, swipeAreaEl) {
658
+ if (!target) return false;
659
+ return require_dom_query.contains(contentEl, target) || require_dom_query.contains(swipeAreaEl, target);
660
+ }
661
+ const oppositeSwipeDirection = {
662
+ up: "down",
663
+ down: "up",
664
+ start: "end",
665
+ end: "start"
666
+ };
667
+ function resolveSwipeDirection(direction, dir) {
668
+ if (direction === "start") return dir === "rtl" ? "right" : "left";
669
+ if (direction === "end") return dir === "rtl" ? "left" : "right";
670
+ return direction;
671
+ }
672
+ function getSwipeDirectionSize(rect, direction) {
673
+ return isVerticalSwipeDirection(direction) ? rect.height : rect.width;
674
+ }
675
+ function resolveSwipeProgress(contentSize, dragOffset, snapPointOffset) {
676
+ if (!contentSize || contentSize <= 0) return 0;
677
+ return require_utils.clampValue(1 - (dragOffset ?? snapPointOffset) / contentSize, 0, 1);
678
+ }
679
+ function hasOpeningSwipeIntent(start, current, direction) {
680
+ const axis = isVerticalSwipeDirection(direction) ? "y" : "x";
681
+ const sign = isNegativeSwipeDirection(direction) ? -1 : 1;
682
+ return (start[axis] - current[axis]) * sign > SWIPE_AREA_OPEN_INTENT_MIN_PX;
683
+ }
684
+ function overflowAllowsScroll(overflow) {
685
+ return overflow === "auto" || overflow === "scroll" || overflow === "overlay";
686
+ }
687
+ function canScrollAlongY(el) {
688
+ if (!overflowAllowsScroll(require_dom_query.getComputedStyle(el).overflowY)) return false;
689
+ return el.scrollHeight > el.clientHeight + SCROLL_SLACK_EPSILON;
690
+ }
691
+ function canScrollAlongX(el) {
692
+ if (!overflowAllowsScroll(require_dom_query.getComputedStyle(el).overflowX)) return false;
693
+ return el.scrollWidth > el.clientWidth + SCROLL_SLACK_EPSILON;
694
+ }
695
+ function canScrollOnSwipeAxis(el, direction) {
696
+ return isVerticalSwipeDirection(direction) ? canScrollAlongY(el) : canScrollAlongX(el);
697
+ }
698
+ function findClosestScrollableAncestorOnSwipeAxis(target, container, direction) {
699
+ if (!container) return null;
700
+ let el = target;
701
+ while (el && el !== container) {
702
+ if (canScrollOnSwipeAxis(el, direction)) return el;
703
+ el = el.parentElement;
704
+ }
705
+ return null;
706
+ }
707
+ function getScrollInfo(target, container, direction) {
708
+ let availableForwardScroll = 0;
709
+ let availableBackwardScroll = 0;
710
+ if (!container) return {
711
+ availableForwardScroll,
712
+ availableBackwardScroll
713
+ };
714
+ const vertical = isVerticalSwipeDirection(direction);
715
+ let element = target;
716
+ while (element) {
717
+ if (vertical ? canScrollAlongY(element) : canScrollAlongX(element)) {
718
+ const clientSize = vertical ? element.clientHeight : element.clientWidth;
719
+ const scrollPos = vertical ? element.scrollTop : element.scrollLeft;
720
+ const scrolled = (vertical ? element.scrollHeight : element.scrollWidth) - scrollPos - clientSize;
721
+ availableForwardScroll += scrolled;
722
+ availableBackwardScroll += scrollPos;
723
+ }
724
+ if (element === container || element === element.ownerDocument.documentElement) break;
725
+ element = element.parentElement;
726
+ }
727
+ return {
728
+ availableForwardScroll,
729
+ availableBackwardScroll
730
+ };
731
+ }
732
+ function shouldPreventTouchScroll(options) {
733
+ const { scrollParent, swipeDirection, lastMainAxis, currentMainAxis } = options;
734
+ const vertical = isVerticalSwipeDirection(swipeDirection);
735
+ const movingPositive = currentMainAxis > lastMainAxis;
736
+ if (vertical) {
737
+ const scrollPos = scrollParent.scrollTop;
738
+ const maxScroll = Math.max(0, scrollParent.scrollHeight - scrollParent.clientHeight);
739
+ if (swipeDirection === "down") return scrollPos <= SCROLL_SLACK_EPSILON && movingPositive;
740
+ if (swipeDirection === "up") return scrollPos >= maxScroll - SCROLL_SLACK_EPSILON && !movingPositive;
741
+ } else {
742
+ const scrollPos = scrollParent.scrollLeft;
743
+ const maxScroll = Math.max(0, scrollParent.scrollWidth - scrollParent.clientWidth);
744
+ if (swipeDirection === "right") return scrollPos <= SCROLL_SLACK_EPSILON && movingPositive;
745
+ if (swipeDirection === "left") return scrollPos >= maxScroll - SCROLL_SLACK_EPSILON && !movingPositive;
746
+ }
747
+ return false;
748
+ }
749
+ function isDragExemptElement(el) {
750
+ if (!require_dom_query.isHTMLElement(el)) return false;
751
+ if (el.closest(NO_DRAG_SELECTOR)) return true;
752
+ let node = el;
753
+ while (node) {
754
+ if (require_dom_query.isEditableElement(node)) return true;
755
+ node = node.parentElement;
756
+ }
757
+ const input = el.closest("input");
758
+ if (require_dom_query.isInputElement(input)) {
759
+ const type = input.type;
760
+ if (type === "range" || type === "file") return true;
761
+ }
762
+ return false;
763
+ }
764
+ function isTextSelectionInDrawer(doc, contentEl) {
765
+ if (!contentEl) return false;
766
+ const selection = doc.getSelection();
767
+ if (!selection || selection.rangeCount === 0 || selection.isCollapsed) return false;
768
+ try {
769
+ const range = selection.getRangeAt(0);
770
+ if (require_dom_query.contains(contentEl, range.commonAncestorContainer)) return true;
771
+ if (require_dom_query.contains(contentEl, selection.anchorNode)) return true;
772
+ if (require_dom_query.contains(contentEl, selection.focusNode)) return true;
773
+ if (typeof range.intersectsNode === "function" && range.intersectsNode(contentEl)) return true;
774
+ } catch {
775
+ return false;
776
+ }
777
+ return false;
778
+ }
779
+ function isDragExemptFromComposedPath(event) {
780
+ const path = typeof event.composedPath === "function" ? event.composedPath() : [];
781
+ for (const node of path) if (isDragExemptElement(node)) return true;
782
+ return isDragExemptElement(event.target);
783
+ }
784
+ function shouldIgnorePointerDownForDrag(event) {
785
+ if (!require_dom_query.isLeftClick(event)) return true;
786
+ const target = require_dom_query.getEventTarget(event);
787
+ if (target?.hasAttribute(NO_DRAG_DATA_ATTR) || target?.closest(NO_DRAG_SELECTOR)) return true;
788
+ return isDragExemptFromComposedPath(event);
789
+ }
28
790
  //#endregion
29
791
  //#region src/machines/drawer/drawer.connect.ts
792
+ const SWIPE_OPEN_HIDDEN_OFFSET = 9999;
793
+ function getSwipeOpenOffset(swipingOpen, dragOffset, contentSize) {
794
+ if (!swipingOpen || dragOffset !== null) return null;
795
+ return contentSize ?? SWIPE_OPEN_HIDDEN_OFFSET;
796
+ }
30
797
  function connect(service, normalize) {
31
- const { state, send, context, scope, prop } = service;
798
+ const { state, send, context, scope, prop, refs } = service;
32
799
  const open = state.hasTag("open");
800
+ const closed = state.matches("closed");
801
+ const swipingOpen = state.matches("swiping-open");
33
802
  const dragOffset = context.get("dragOffset");
34
803
  const dragging = dragOffset !== null;
35
- const activeSnapPoint = context.get("activeSnapPoint");
804
+ const snapPoint = context.get("snapPoint");
805
+ const swipeDirection = prop("swipeDirection");
806
+ const physicalDirection = resolveSwipeDirection(swipeDirection, prop("dir"));
807
+ const contentSize = context.get("contentSize");
808
+ const swipeStrength = context.get("swipeStrength");
36
809
  const resolvedActiveSnapPoint = context.get("resolvedActiveSnapPoint");
37
- const translate = dragOffset ?? resolvedActiveSnapPoint?.offset;
38
- function onPointerDown(event) {
39
- if (!require_dom_query.isLeftClick(event)) return;
40
- const target = require_dom_query.getEventTarget(event);
41
- if (target?.hasAttribute("data-no-drag") || target?.closest("[data-no-drag]")) return;
42
- if (state.matches("closing")) return;
43
- send({
44
- type: "POINTER_DOWN",
45
- point: require_dom_query.getEventPoint(event)
810
+ const snapPointOffset = resolvedActiveSnapPoint?.offset ?? 0;
811
+ const currentOffset = getSwipeOpenOffset(swipingOpen, dragOffset, contentSize) ?? dragOffset ?? snapPointOffset;
812
+ const signedSnapPointOffset = isNegativeSwipeDirection(physicalDirection) ? -snapPointOffset : snapPointOffset;
813
+ const isActivelySwiping = dragging || swipingOpen;
814
+ const swipeMovement = dragging || swipingOpen ? currentOffset - snapPointOffset : 0;
815
+ const signedMovement = isNegativeSwipeDirection(physicalDirection) ? -swipeMovement : swipeMovement;
816
+ const swipeProgress = isActivelySwiping && contentSize && contentSize > 0 ? require_utils.clampValue(Math.abs(signedMovement) / contentSize, 0, 1) : swipingOpen ? 1 : 0;
817
+ const signedCurrentOffset = isNegativeSwipeDirection(physicalDirection) ? -currentOffset : currentOffset;
818
+ const translateX = isVerticalSwipeDirection(physicalDirection) ? 0 : signedCurrentOffset;
819
+ const translateY = isVerticalSwipeDirection(physicalDirection) ? signedCurrentOffset : 0;
820
+ function onContentPointerDown(event) {
821
+ refs.get("swipeSession").contentPointerDown({
822
+ event,
823
+ getDoc: () => scope.getDoc(),
824
+ getContentEl: () => getContentEl(scope),
825
+ getWin: () => scope.getWin(),
826
+ swipeDirection: physicalDirection,
827
+ canCommit: () => state.hasTag("open") && !state.matches("closing"),
828
+ onCommit(point) {
829
+ send({
830
+ type: "POINTER_DOWN",
831
+ point
832
+ });
833
+ }
834
+ });
835
+ }
836
+ function onGrabberPointerDown(event) {
837
+ refs.get("swipeSession").grabberPointerDown({
838
+ event,
839
+ point: require_dom_query.getEventPoint(event),
840
+ canCommit: () => state.hasTag("open") && !state.matches("closing"),
841
+ onCommit(point) {
842
+ send({
843
+ type: "POINTER_DOWN",
844
+ point
845
+ });
846
+ }
46
847
  });
47
848
  }
48
849
  return {
@@ -53,47 +854,74 @@ function connect(service, normalize) {
53
854
  send({ type: nextOpen ? "OPEN" : "CLOSE" });
54
855
  },
55
856
  snapPoints: prop("snapPoints"),
56
- activeSnapPoint,
57
- setActiveSnapPoint(snapPoint) {
58
- if (context.get("activeSnapPoint") === snapPoint) return;
857
+ swipeDirection,
858
+ snapPoint,
859
+ setSnapPoint(snapPoint) {
860
+ if (context.get("snapPoint") === snapPoint) return;
59
861
  send({
60
- type: "ACTIVE_SNAP_POINT.SET",
862
+ type: "SNAP_POINT.SET",
61
863
  snapPoint
62
864
  });
63
865
  },
64
866
  getOpenPercentage() {
65
- if (!open) return 0;
66
- const contentHeight = context.get("contentHeight");
67
- if (!contentHeight) return 0;
68
- const currentOffset = translate ?? 0;
69
- return Math.max(0, Math.min(1, 1 - currentOffset / contentHeight));
867
+ if (!open || !contentSize) return 0;
868
+ return require_utils.clampValue(1 - currentOffset / contentSize, 0, 1);
70
869
  },
71
- getActiveSnapIndex() {
72
- return prop("snapPoints").indexOf(activeSnapPoint);
870
+ getSnapPointIndex() {
871
+ if (snapPoint === null) return -1;
872
+ return prop("snapPoints").indexOf(snapPoint);
73
873
  },
74
- getContentHeight() {
75
- return context.get("contentHeight");
874
+ getContentSize() {
875
+ return contentSize;
876
+ },
877
+ getPositionerProps() {
878
+ return normalize.element({
879
+ ...parts.positioner.attrs,
880
+ id: getPositionerId(scope),
881
+ dir: prop("dir"),
882
+ hidden: closed,
883
+ "data-state": open ? "open" : "closed",
884
+ "data-swipe-direction": physicalDirection,
885
+ style: require_utils.compact({ pointerEvents: prop("modal") ? void 0 : "none" })
886
+ });
76
887
  },
77
888
  getContentProps(props = { draggable: true }) {
889
+ const movementX = isVerticalSwipeDirection(physicalDirection) ? 0 : signedMovement;
890
+ const movementY = isVerticalSwipeDirection(physicalDirection) ? signedMovement : 0;
891
+ const rendered = context.get("rendered");
78
892
  return normalize.element({
79
893
  ...parts.content.attrs,
80
894
  dir: prop("dir"),
81
895
  id: getContentId(scope),
82
896
  tabIndex: -1,
83
- role: "dialog",
897
+ role: prop("role"),
84
898
  "aria-modal": prop("modal"),
85
- "aria-labelledby": getTitleId(scope),
899
+ "aria-labelledby": rendered.title ? getTitleId(scope) : void 0,
900
+ "aria-describedby": rendered.description ? getDescriptionId(scope) : void 0,
86
901
  hidden: !open,
87
902
  "data-state": open ? "open" : "closed",
88
- style: {
89
- transform: "translate3d(0, var(--drawer-translate, 0), 0)",
90
- transitionDuration: dragging ? "0s" : void 0,
91
- "--drawer-translate": require_utils.toPx(translate),
903
+ "data-expanded": resolvedActiveSnapPoint?.offset === 0 ? "" : void 0,
904
+ "data-swipe-direction": physicalDirection,
905
+ "data-swiping": dragging || swipingOpen ? "" : void 0,
906
+ "data-dragging": dragging ? "" : void 0,
907
+ style: require_utils.compact({
908
+ pointerEvents: prop("modal") ? void 0 : "auto",
909
+ visibility: swipingOpen && dragOffset === null ? "hidden" : void 0,
910
+ transform: "translate3d(var(--drawer-translate-x, 0px), var(--drawer-translate-y, 0px), 0)",
911
+ transitionDuration: dragging || swipingOpen ? "0s" : void 0,
912
+ "--drawer-translate": require_utils.toPx(translateY),
913
+ "--drawer-translate-x": require_utils.toPx(translateX),
914
+ "--drawer-translate-y": require_utils.toPx(translateY),
915
+ "--drawer-snap-point-offset-x": isVerticalSwipeDirection(physicalDirection) ? "0px" : require_utils.toPx(signedSnapPointOffset),
916
+ "--drawer-snap-point-offset-y": isVerticalSwipeDirection(physicalDirection) ? require_utils.toPx(signedSnapPointOffset) : "0px",
917
+ "--drawer-swipe-movement-x": require_utils.toPx(movementX),
918
+ "--drawer-swipe-movement-y": require_utils.toPx(movementY),
919
+ "--drawer-swipe-strength": `${swipeStrength}`,
92
920
  willChange: "transform"
93
- },
921
+ }),
94
922
  onPointerDown(event) {
95
923
  if (!props.draggable) return;
96
- onPointerDown(event);
924
+ onContentPointerDown(event);
97
925
  }
98
926
  });
99
927
  },
@@ -104,6 +932,13 @@ function connect(service, normalize) {
104
932
  dir: prop("dir")
105
933
  });
106
934
  },
935
+ getDescriptionProps() {
936
+ return normalize.element({
937
+ ...parts.description.attrs,
938
+ id: getDescriptionId(scope),
939
+ dir: prop("dir")
940
+ });
941
+ },
107
942
  getTriggerProps() {
108
943
  return normalize.button({
109
944
  ...parts.trigger.attrs,
@@ -118,9 +953,14 @@ function connect(service, normalize) {
118
953
  return normalize.element({
119
954
  ...parts.backdrop.attrs,
120
955
  id: getBackdropId(scope),
121
- hidden: !open,
956
+ hidden: !open || swipingOpen && dragOffset === null,
122
957
  "data-state": open ? "open" : "closed",
123
- style: { willChange: "opacity" }
958
+ "data-swiping": dragging || swipingOpen ? "" : void 0,
959
+ style: {
960
+ willChange: "opacity",
961
+ "--drawer-swipe-progress": `${swipeProgress}`,
962
+ "--drawer-swipe-strength": `${swipeStrength}`
963
+ }
124
964
  });
125
965
  },
126
966
  getGrabberProps() {
@@ -128,7 +968,7 @@ function connect(service, normalize) {
128
968
  ...parts.grabber.attrs,
129
969
  id: getGrabberId(scope),
130
970
  onPointerDown(event) {
131
- onPointerDown(event);
971
+ onGrabberPointerDown(event);
132
972
  },
133
973
  style: { touchAction: "none" }
134
974
  });
@@ -147,143 +987,121 @@ function connect(service, normalize) {
147
987
  send({ type: "CLOSE" });
148
988
  }
149
989
  });
990
+ },
991
+ getSwipeAreaProps(props = {}) {
992
+ const disabled = props.disabled ?? false;
993
+ const physicalOpenDirection = resolveSwipeDirection(props.swipeDirection ?? oppositeSwipeDirection[swipeDirection], prop("dir"));
994
+ return normalize.element({
995
+ ...parts.swipeArea.attrs,
996
+ id: getSwipeAreaId(scope),
997
+ role: "presentation",
998
+ "aria-hidden": true,
999
+ "data-state": open ? "open" : "closed",
1000
+ "data-swiping": swipingOpen ? "" : void 0,
1001
+ "data-swipe-direction": physicalOpenDirection,
1002
+ "data-disabled": disabled ? "" : void 0,
1003
+ style: {
1004
+ touchAction: isVerticalSwipeDirection(physicalOpenDirection) ? "pan-x" : "pan-y",
1005
+ pointerEvents: disabled || open && !swipingOpen ? "none" : void 0
1006
+ },
1007
+ onPointerDown(event) {
1008
+ if (disabled) return;
1009
+ if (!require_dom_query.isLeftClick(event)) return;
1010
+ if (event.pointerType === "touch") return;
1011
+ if (open && !swipingOpen) return;
1012
+ send({
1013
+ type: "SWIPE_AREA.START",
1014
+ point: require_dom_query.getEventPoint(event)
1015
+ });
1016
+ if (event.cancelable) event.preventDefault();
1017
+ },
1018
+ onTouchStart(event) {
1019
+ if (disabled) return;
1020
+ if (open && !swipingOpen) return;
1021
+ const touch = event.touches[0];
1022
+ if (!touch) return;
1023
+ send({
1024
+ type: "SWIPE_AREA.START",
1025
+ point: {
1026
+ x: touch.clientX,
1027
+ y: touch.clientY
1028
+ }
1029
+ });
1030
+ }
1031
+ });
150
1032
  }
151
1033
  };
152
1034
  }
153
1035
  //#endregion
154
- //#region src/machines/drawer/utils/find-closest-snap-point.ts
155
- function findClosestSnapPoint(offset, snapPoints) {
156
- return snapPoints.reduce((acc, curr) => {
157
- const closestDiff = Math.abs(offset - acc.offset);
158
- return Math.abs(offset - curr.offset) < closestDiff ? curr : acc;
159
- });
160
- }
161
- //#endregion
162
- //#region src/machines/drawer/utils/get-scroll-info.ts
163
- function isScrollContainer(element) {
164
- const overflow = getComputedStyle(element).overflowY;
165
- return overflow === "auto" || overflow === "scroll";
166
- }
167
- function getScrollInfo(target, container) {
168
- let element = target;
169
- let availableScroll = 0;
170
- let availableScrollTop = 0;
171
- while (element) {
172
- const { clientHeight, scrollTop, scrollHeight } = element;
173
- const scrolled = scrollHeight - scrollTop - clientHeight;
174
- if ((scrollTop !== 0 || scrolled !== 0) && isScrollContainer(element)) {
175
- availableScroll += scrolled;
176
- availableScrollTop += scrollTop;
177
- }
178
- if (element === container || element === document.documentElement) break;
179
- element = element.parentNode;
180
- }
181
- return {
182
- availableScroll,
183
- availableScrollTop
184
- };
185
- }
186
- //#endregion
187
- //#region src/machines/drawer/utils/drag-manager.ts
188
- const DRAG_START_THRESHOLD = .3;
189
- var DragManager = class {
1036
+ //#region src/machines/drawer/drawer.registry.ts
1037
+ var DrawerRegistry = class {
190
1038
  constructor() {
191
- require_defineProperty._defineProperty(this, "pointerStart", null);
192
- require_defineProperty._defineProperty(this, "dragOffset", null);
193
- require_defineProperty._defineProperty(this, "lastPoint", null);
194
- require_defineProperty._defineProperty(this, "lastTimestamp", null);
195
- require_defineProperty._defineProperty(this, "velocity", null);
1039
+ require_defineProperty._defineProperty(this, "elements", /* @__PURE__ */ new Map());
1040
+ require_defineProperty._defineProperty(this, "swipingIds", /* @__PURE__ */ new Set());
1041
+ require_defineProperty._defineProperty(this, "swipeProgress", /* @__PURE__ */ new Map());
1042
+ require_defineProperty._defineProperty(this, "listeners", /* @__PURE__ */ new Set());
196
1043
  }
197
- setPointerStart(point) {
198
- this.pointerStart = point;
199
- }
200
- clearPointerStart() {
201
- this.pointerStart = null;
202
- }
203
- getPointerStart() {
204
- return this.pointerStart;
205
- }
206
- setDragOffset(point, resolvedActiveSnapPointOffset) {
207
- if (!this.pointerStart) return;
208
- const currentTimestamp = (/* @__PURE__ */ new Date()).getTime();
209
- if (this.lastPoint) {
210
- const dy = point.y - this.lastPoint.y;
211
- if (this.lastTimestamp) {
212
- const dt = currentTimestamp - this.lastTimestamp;
213
- if (dt > 0) {
214
- const calculatedVelocity = dy / dt * 1e3;
215
- this.velocity = Number.isFinite(calculatedVelocity) ? calculatedVelocity : 0;
216
- }
217
- }
218
- }
219
- this.lastPoint = point;
220
- this.lastTimestamp = currentTimestamp;
221
- let delta = this.pointerStart.y - point.y - resolvedActiveSnapPointOffset;
222
- if (delta > 0) delta = 0;
223
- this.dragOffset = -delta;
1044
+ notify() {
1045
+ this.listeners.forEach((fn) => fn());
224
1046
  }
225
- getDragOffset() {
226
- return this.dragOffset;
1047
+ register(id, el) {
1048
+ this.elements.set(id, el);
1049
+ this.notify();
227
1050
  }
228
- clearDragOffset() {
229
- this.dragOffset = null;
1051
+ unregister(id) {
1052
+ this.swipingIds.delete(id);
1053
+ this.swipeProgress.delete(id);
1054
+ if (!this.elements.delete(id)) return;
1055
+ this.notify();
230
1056
  }
231
- getVelocity() {
232
- return this.velocity;
1057
+ setSwiping(id, swiping) {
1058
+ if (!(swiping ? !this.swipingIds.has(id) : this.swipingIds.has(id)) && swiping) return;
1059
+ if (swiping) this.swipingIds.add(id);
1060
+ else {
1061
+ this.swipingIds.delete(id);
1062
+ this.swipeProgress.delete(id);
1063
+ }
1064
+ this.notify();
233
1065
  }
234
- clearVelocityTracking() {
235
- this.lastPoint = null;
236
- this.lastTimestamp = null;
237
- this.velocity = null;
1066
+ setSwipeProgress(id, progress) {
1067
+ this.swipeProgress.set(id, progress);
1068
+ this.notify();
238
1069
  }
239
- clear() {
240
- this.clearPointerStart();
241
- this.clearDragOffset();
242
- this.clearVelocityTracking();
1070
+ getSwipeProgressAfter(id) {
1071
+ const keys = [...this.elements.keys()];
1072
+ const myIndex = keys.indexOf(id);
1073
+ if (myIndex === -1) return 0;
1074
+ for (let i = keys.length - 1; i > myIndex; i -= 1) if (this.swipingIds.has(keys[i])) return this.swipeProgress.get(keys[i]) ?? 0;
1075
+ return 0;
243
1076
  }
244
- shouldStartDragging(point, target, container, preventDragOnScroll) {
245
- if (!this.pointerStart || !container) return false;
246
- if (preventDragOnScroll) {
247
- const delta = this.pointerStart.y - point.y;
248
- if (Math.abs(delta) < DRAG_START_THRESHOLD) return false;
249
- const { availableScroll, availableScrollTop } = getScrollInfo(target, container);
250
- if (delta > 0 && Math.abs(availableScroll) > 1 || delta < 0 && Math.abs(availableScrollTop) > 0) return false;
251
- }
252
- return true;
1077
+ hasSwipingAfter(id) {
1078
+ const keys = [...this.elements.keys()];
1079
+ const myIndex = keys.indexOf(id);
1080
+ if (myIndex === -1) return false;
1081
+ return keys.slice(myIndex + 1).some((key) => this.swipingIds.has(key));
253
1082
  }
254
- findClosestSnapPoint(snapPoints) {
255
- if (this.dragOffset === null) return snapPoints[0]?.value ?? 1;
256
- return findClosestSnapPoint(this.dragOffset, snapPoints).value;
1083
+ getEntries() {
1084
+ return this.elements;
257
1085
  }
258
- shouldDismiss(contentHeight, snapPoints, swipeVelocityThreshold, closeThreshold) {
259
- if (this.dragOffset === null || this.velocity === null || contentHeight === null) return false;
260
- const visibleHeight = contentHeight - this.dragOffset;
261
- const smallestSnapPoint = snapPoints.reduce((acc, curr) => curr.offset > acc.offset ? curr : acc);
262
- const isFastSwipe = this.velocity > 0 && this.velocity >= swipeVelocityThreshold;
263
- const closeThresholdInPixels = contentHeight * (1 - closeThreshold);
264
- const isBelowSmallestSnapPoint = visibleHeight < contentHeight - smallestSnapPoint.offset;
265
- return isFastSwipe || visibleHeight < closeThresholdInPixels && isBelowSmallestSnapPoint || visibleHeight === 0;
1086
+ subscribe(fn) {
1087
+ this.listeners.add(fn);
1088
+ return () => {
1089
+ this.listeners.delete(fn);
1090
+ };
266
1091
  }
267
1092
  };
268
- //#endregion
269
- //#region src/machines/drawer/utils/resolve-snap-point.ts
270
- function resolveSnapPoint(snapPoint, containerHeight) {
271
- if (typeof snapPoint === "number") return {
272
- value: snapPoint,
273
- offset: containerHeight - snapPoint * containerHeight
274
- };
275
- if (typeof snapPoint === "string") return {
276
- value: snapPoint,
277
- offset: containerHeight - parseFloat(snapPoint)
278
- };
279
- throw new Error(`Invalid snap point: ${snapPoint}`);
280
- }
1093
+ const drawerRegistry = new DrawerRegistry();
281
1094
  //#endregion
282
1095
  //#region src/machines/drawer/drawer.machine.ts
1096
+ const { and } = require_core.createGuards();
1097
+ const getActiveSnapOffset = (context) => context.get("resolvedActiveSnapPoint")?.offset ?? 0;
1098
+ const hasRemSnapPoints = (snapPoints) => snapPoints.some((snapPoint) => typeof snapPoint === "string" && snapPoint.trim().endsWith("rem"));
1099
+ const DEFAULT_SNAP_POINTS = [1];
283
1100
  const machine = require_core.createMachine({
284
1101
  props({ props, scope }) {
285
1102
  const initialFocusEl = props.role === "alertdialog" ? () => getCloseTriggerEl(scope) : void 0;
286
1103
  const modal = typeof props.modal === "boolean" ? props.modal : true;
1104
+ const snapPoints = props.snapPoints ?? DEFAULT_SNAP_POINTS;
287
1105
  return {
288
1106
  modal,
289
1107
  trapFocus: modal,
@@ -291,11 +1109,14 @@ const machine = require_core.createMachine({
291
1109
  closeOnInteractOutside: true,
292
1110
  closeOnEscape: true,
293
1111
  restoreFocus: true,
1112
+ role: "dialog",
294
1113
  initialFocusEl,
295
- snapPoints: [1],
296
- defaultActiveSnapPoint: 1,
297
- swipeVelocityThreshold: 700,
298
- closeThreshold: .25,
1114
+ snapPoints,
1115
+ defaultSnapPoint: props.defaultSnapPoint ?? snapPoints[0] ?? null,
1116
+ swipeDirection: "down",
1117
+ snapToSequentialPoints: false,
1118
+ swipeVelocityThreshold: 500,
1119
+ closeThreshold: .5,
299
1120
  preventDragOnScroll: true,
300
1121
  ...props
301
1122
  };
@@ -303,88 +1124,198 @@ const machine = require_core.createMachine({
303
1124
  context({ bindable, prop }) {
304
1125
  return {
305
1126
  dragOffset: bindable(() => ({ defaultValue: null })),
306
- activeSnapPoint: bindable(() => ({
307
- defaultValue: prop("defaultActiveSnapPoint"),
308
- value: prop("activeSnapPoint"),
309
- onChange(value) {
310
- return prop("onActiveSnapPointChange")?.({ snapPoint: value });
1127
+ snapPoint: bindable(() => ({
1128
+ defaultValue: prop("defaultSnapPoint"),
1129
+ value: prop("snapPoint"),
1130
+ onChange(snapPoint) {
1131
+ return prop("onSnapPointChange")?.({ snapPoint });
311
1132
  }
312
1133
  })),
313
1134
  resolvedActiveSnapPoint: bindable(() => ({ defaultValue: null })),
314
- contentHeight: bindable(() => ({ defaultValue: null }))
1135
+ contentSize: bindable(() => ({ defaultValue: null })),
1136
+ viewportSize: bindable(() => ({ defaultValue: 0 })),
1137
+ rootFontSize: bindable(() => ({ defaultValue: 16 })),
1138
+ swipeStrength: bindable(() => ({ defaultValue: 1 })),
1139
+ rendered: bindable(() => ({ defaultValue: {
1140
+ title: true,
1141
+ description: true
1142
+ } }))
315
1143
  };
316
1144
  },
317
- refs() {
318
- return { dragManager: new DragManager() };
1145
+ refs({ prop }) {
1146
+ return { swipeSession: new DrawerSwipeSession({ preventDragOnScroll: () => prop("preventDragOnScroll") }) };
319
1147
  },
320
- computed: { resolvedSnapPoints({ context, prop }) {
321
- const contentHeight = context.get("contentHeight");
322
- if (contentHeight === null) return [];
323
- return prop("snapPoints").map((snapPoint) => resolveSnapPoint(snapPoint, contentHeight));
324
- } },
325
- watch({ track, context, prop, action }) {
326
- track([() => context.get("activeSnapPoint"), () => context.get("contentHeight")], () => {
327
- const activeSnapPoint = context.get("activeSnapPoint");
328
- const contentHeight = context.get("contentHeight");
329
- if (contentHeight === null) return;
330
- const resolvedActiveSnapPoint = resolveSnapPoint(activeSnapPoint, contentHeight);
331
- context.set("resolvedActiveSnapPoint", resolvedActiveSnapPoint);
1148
+ computed: {
1149
+ drawerId({ prop, scope }) {
1150
+ return String(prop("id") ?? scope.id);
1151
+ },
1152
+ physicalSwipeDirection({ prop }) {
1153
+ return resolveSwipeDirection(prop("swipeDirection"), prop("dir"));
1154
+ },
1155
+ resolvedSnapPoints({ context, prop }) {
1156
+ const contentSize = context.get("contentSize");
1157
+ const viewportSize = context.get("viewportSize");
1158
+ const rootFontSize = context.get("rootFontSize");
1159
+ if (contentSize === null) return [];
1160
+ return dedupeSnapPoints(prop("snapPoints").map((snapPoint) => resolveSnapPoint(snapPoint, {
1161
+ contentSize,
1162
+ viewportSize,
1163
+ rootFontSize
1164
+ })).filter((point) => point !== null));
1165
+ }
1166
+ },
1167
+ watch({ track, context, prop, action, computed }) {
1168
+ track([
1169
+ () => context.get("snapPoint"),
1170
+ () => context.get("contentSize"),
1171
+ () => context.get("viewportSize"),
1172
+ () => context.get("rootFontSize"),
1173
+ () => prop("snapPoints").join("|")
1174
+ ], () => {
1175
+ const snapPoint = context.get("snapPoint");
1176
+ const contentSize = context.get("contentSize");
1177
+ const viewportSize = context.get("viewportSize");
1178
+ const rootFontSize = context.get("rootFontSize");
1179
+ if (snapPoint === null || contentSize === null) {
1180
+ context.set("resolvedActiveSnapPoint", null);
1181
+ return;
1182
+ }
1183
+ const resolvedPoints = computed("resolvedSnapPoints");
1184
+ const matchedPoint = resolvedPoints.find((point) => Object.is(point.value, snapPoint));
1185
+ if (matchedPoint) {
1186
+ context.set("resolvedActiveSnapPoint", matchedPoint);
1187
+ return;
1188
+ }
1189
+ const resolvedActiveSnapPoint = resolveSnapPoint(snapPoint, {
1190
+ contentSize,
1191
+ viewportSize,
1192
+ rootFontSize
1193
+ });
1194
+ if (resolvedActiveSnapPoint) {
1195
+ context.set("resolvedActiveSnapPoint", resolvedActiveSnapPoint);
1196
+ return;
1197
+ }
1198
+ const fallbackPoint = resolvedPoints[0];
1199
+ if (!fallbackPoint) {
1200
+ context.set("resolvedActiveSnapPoint", null);
1201
+ return;
1202
+ }
1203
+ context.set("snapPoint", fallbackPoint.value);
1204
+ context.set("resolvedActiveSnapPoint", fallbackPoint);
332
1205
  });
333
1206
  track([() => prop("open")], () => {
334
1207
  action(["toggleVisibility"]);
335
1208
  });
1209
+ track([
1210
+ () => context.get("dragOffset"),
1211
+ () => context.get("contentSize"),
1212
+ () => getActiveSnapOffset(context)
1213
+ ], () => {
1214
+ action(["syncDrawerStack"]);
1215
+ });
336
1216
  },
337
1217
  initialState({ prop }) {
338
1218
  return prop("open") || prop("defaultOpen") ? "open" : "closed";
339
1219
  },
340
- on: { "ACTIVE_SNAP_POINT.SET": { actions: ["setActiveSnapPoint"] } },
1220
+ on: { "SNAP_POINT.SET": { actions: ["setSnapPoint"] } },
341
1221
  states: {
342
1222
  open: {
343
1223
  tags: ["open"],
1224
+ entry: [
1225
+ "checkRenderedElements",
1226
+ "setInitialFocus",
1227
+ "deferClearDragOffset"
1228
+ ],
344
1229
  effects: [
345
1230
  "trackDismissableElement",
346
1231
  "preventScroll",
347
1232
  "trapFocus",
348
1233
  "hideContentBelow",
349
1234
  "trackPointerMove",
350
- "trackContentHeight"
1235
+ "trackSizeMeasurements",
1236
+ "trackNestedDrawerMetrics",
1237
+ "trackDrawerStack"
351
1238
  ],
352
1239
  on: {
353
- "CONTROLLED.CLOSE": { target: "closed" },
1240
+ "CONTROLLED.CLOSE": {
1241
+ target: "closing",
1242
+ actions: ["clearSwipeOpenAnimation", "resetSwipeStrength"]
1243
+ },
354
1244
  POINTER_DOWN: { actions: ["setPointerStart"] },
355
1245
  POINTER_MOVE: [{
356
1246
  guard: "isDragging",
357
1247
  actions: ["setDragOffset"]
358
1248
  }, {
359
1249
  guard: "shouldStartDragging",
360
- actions: ["setDragOffset"]
1250
+ actions: ["setRegistrySwiping", "setDragOffset"]
361
1251
  }],
362
1252
  POINTER_UP: [
1253
+ {
1254
+ guard: and("shouldCloseOnSwipe", "isOpenControlled"),
1255
+ actions: [
1256
+ "clearSwipeOpenAnimation",
1257
+ "clearRegistrySwiping",
1258
+ "clearPointerStart",
1259
+ "clearDragOffset",
1260
+ "invokeOnClose"
1261
+ ]
1262
+ },
363
1263
  {
364
1264
  guard: "shouldCloseOnSwipe",
365
- target: "closing"
1265
+ target: "closing",
1266
+ actions: [
1267
+ "clearSwipeOpenAnimation",
1268
+ "clearRegistrySwiping",
1269
+ "setDismissSwipeStrength"
1270
+ ]
366
1271
  },
367
1272
  {
368
1273
  guard: "isDragging",
369
1274
  actions: [
1275
+ "clearRegistrySwiping",
1276
+ "suppressBackdropAnimation",
1277
+ "setSnapSwipeStrength",
370
1278
  "setClosestSnapPoint",
371
1279
  "clearPointerStart",
372
- "clearDragOffset"
1280
+ "clearDragOffset",
1281
+ "clearVelocityTracking"
373
1282
  ]
374
1283
  },
375
- { actions: ["clearPointerStart", "clearDragOffset"] }
1284
+ { actions: [
1285
+ "clearRegistrySwiping",
1286
+ "clearPointerStart",
1287
+ "clearDragOffset",
1288
+ "clearVelocityTracking"
1289
+ ] }
376
1290
  ],
1291
+ POINTER_CANCEL: [{
1292
+ guard: "isDragging",
1293
+ actions: [
1294
+ "clearRegistrySwiping",
1295
+ "clearPointerStart",
1296
+ "clearDragOffset",
1297
+ "clearVelocityTracking"
1298
+ ]
1299
+ }, { actions: [
1300
+ "clearRegistrySwiping",
1301
+ "clearPointerStart",
1302
+ "clearVelocityTracking"
1303
+ ] }],
377
1304
  CLOSE: [{
378
1305
  guard: "isOpenControlled",
379
- actions: ["invokeOnClose"]
1306
+ actions: ["clearSwipeOpenAnimation", "invokeOnClose"]
380
1307
  }, {
381
1308
  target: "closing",
382
- actions: ["invokeOnClose"]
1309
+ actions: [
1310
+ "clearSwipeOpenAnimation",
1311
+ "resetSwipeStrength",
1312
+ "invokeOnClose"
1313
+ ]
383
1314
  }]
384
1315
  }
385
1316
  },
386
1317
  closing: {
387
- effects: ["trackExitAnimation"],
1318
+ effects: ["trackExitAnimation", "trackDrawerStack"],
388
1319
  on: { ANIMATION_END: {
389
1320
  target: "closed",
390
1321
  actions: [
@@ -393,11 +1324,73 @@ const machine = require_core.createMachine({
393
1324
  "clearDragOffset",
394
1325
  "clearActiveSnapPoint",
395
1326
  "clearResolvedActiveSnapPoint",
396
- "clearContentHeight",
1327
+ "clearSizeMeasurements",
397
1328
  "clearVelocityTracking"
398
1329
  ]
399
1330
  } }
400
1331
  },
1332
+ "swipe-area-dragging": {
1333
+ tags: ["closed"],
1334
+ effects: ["trackSwipeOpenPointerMove"],
1335
+ on: {
1336
+ POINTER_MOVE: {
1337
+ guard: "hasSwipeIntent",
1338
+ target: "swiping-open"
1339
+ },
1340
+ POINTER_UP: {
1341
+ target: "closed",
1342
+ actions: ["clearPointerStart", "clearVelocityTracking"]
1343
+ },
1344
+ POINTER_CANCEL: {
1345
+ target: "closed",
1346
+ actions: ["clearPointerStart", "clearVelocityTracking"]
1347
+ }
1348
+ }
1349
+ },
1350
+ "swiping-open": {
1351
+ tags: ["open"],
1352
+ effects: ["trackSwipeOpenPointerMove", "trackSizeMeasurements"],
1353
+ on: {
1354
+ POINTER_MOVE: { actions: ["setSwipeOpenDragOffset"] },
1355
+ POINTER_UP: [
1356
+ {
1357
+ guard: and("shouldOpenOnSwipe", "isOpenControlled"),
1358
+ actions: ["clearPointerStart", "invokeOnOpen"]
1359
+ },
1360
+ {
1361
+ guard: "shouldOpenOnSwipe",
1362
+ target: "open",
1363
+ actions: ["clearPointerStart", "invokeOnOpen"]
1364
+ },
1365
+ {
1366
+ target: "closed",
1367
+ actions: [
1368
+ "clearPointerStart",
1369
+ "clearDragOffset",
1370
+ "clearSizeMeasurements"
1371
+ ]
1372
+ }
1373
+ ],
1374
+ POINTER_CANCEL: {
1375
+ target: "closed",
1376
+ actions: [
1377
+ "clearPointerStart",
1378
+ "clearDragOffset",
1379
+ "clearSizeMeasurements",
1380
+ "clearVelocityTracking"
1381
+ ]
1382
+ },
1383
+ "CONTROLLED.OPEN": { target: "open" },
1384
+ CLOSE: {
1385
+ target: "closed",
1386
+ actions: [
1387
+ "clearPointerStart",
1388
+ "clearDragOffset",
1389
+ "clearSizeMeasurements"
1390
+ ]
1391
+ }
1392
+ }
1393
+ },
401
1394
  closed: {
402
1395
  tags: ["closed"],
403
1396
  on: {
@@ -408,7 +1401,11 @@ const machine = require_core.createMachine({
408
1401
  }, {
409
1402
  target: "open",
410
1403
  actions: ["invokeOnOpen"]
411
- }]
1404
+ }],
1405
+ "SWIPE_AREA.START": {
1406
+ target: "swipe-area-dragging",
1407
+ actions: ["setPointerStart"]
1408
+ }
412
1409
  }
413
1410
  }
414
1411
  },
@@ -418,71 +1415,204 @@ const machine = require_core.createMachine({
418
1415
  isDragging({ context }) {
419
1416
  return context.get("dragOffset") !== null;
420
1417
  },
421
- shouldStartDragging({ prop, refs, event, scope }) {
422
- return refs.get("dragManager").shouldStartDragging(event.point, event.target, getContentEl(scope), prop("preventDragOnScroll"));
1418
+ shouldStartDragging({ computed, prop, refs, event, scope }) {
1419
+ return refs.get("swipeSession").canStartDrag(event.point, event.target, getContentEl(scope), prop("preventDragOnScroll"), computed("physicalSwipeDirection"));
423
1420
  },
424
1421
  shouldCloseOnSwipe({ prop, context, computed, refs }) {
425
- return refs.get("dragManager").shouldDismiss(context.get("contentHeight"), computed("resolvedSnapPoints"), prop("swipeVelocityThreshold"), prop("closeThreshold"));
1422
+ if (prop("snapToSequentialPoints")) return false;
1423
+ return refs.get("swipeSession").shouldDismissOnRelease(context.get("contentSize"), computed("resolvedSnapPoints"), getActiveSnapOffset(context));
1424
+ },
1425
+ hasSwipeIntent({ refs, computed, event }) {
1426
+ const start = refs.get("swipeSession").getSwipeStart();
1427
+ if (!start || !event.point) return false;
1428
+ return hasOpeningSwipeIntent(start, event.point, computed("physicalSwipeDirection"));
1429
+ },
1430
+ shouldOpenOnSwipe({ context, refs, prop }) {
1431
+ return refs.get("swipeSession").shouldOpenOnRelease(context.get("contentSize"), prop("swipeVelocityThreshold"), prop("closeThreshold"));
426
1432
  }
427
1433
  },
428
1434
  actions: {
1435
+ setInitialFocus({ prop, scope }) {
1436
+ if (prop("trapFocus")) return;
1437
+ require_dom_query.raf(() => {
1438
+ require_dom_query.getInitialFocus({
1439
+ root: getContentEl(scope),
1440
+ getInitialEl: prop("initialFocusEl")
1441
+ })?.focus({ preventScroll: true });
1442
+ });
1443
+ },
1444
+ checkRenderedElements({ context, scope }) {
1445
+ require_dom_query.raf(() => {
1446
+ context.set("rendered", {
1447
+ title: !!getTitleEl(scope),
1448
+ description: !!getDescriptionEl(scope)
1449
+ });
1450
+ });
1451
+ },
1452
+ deferClearDragOffset({ context, refs, scope }) {
1453
+ if (context.get("dragOffset") === null) return;
1454
+ const contentEl = getContentEl(scope);
1455
+ const backdropEl = getBackdropEl(scope);
1456
+ if (contentEl) contentEl.style.setProperty("animation", "none", "important");
1457
+ if (backdropEl) backdropEl.style.setProperty("animation", "none", "important");
1458
+ require_dom_query.raf(() => {
1459
+ refs.get("swipeSession").resetDragOffset();
1460
+ context.set("dragOffset", null);
1461
+ });
1462
+ },
1463
+ suppressBackdropAnimation({ scope }) {
1464
+ const backdropEl = getBackdropEl(scope);
1465
+ if (!backdropEl) return;
1466
+ backdropEl.style.setProperty("animation", "none", "important");
1467
+ },
1468
+ clearSwipeOpenAnimation({ scope }) {
1469
+ const contentEl = getContentEl(scope);
1470
+ const backdropEl = getBackdropEl(scope);
1471
+ if (contentEl) contentEl.style.removeProperty("animation");
1472
+ if (backdropEl) backdropEl.style.removeProperty("animation");
1473
+ },
429
1474
  invokeOnOpen({ prop }) {
430
1475
  prop("onOpenChange")?.({ open: true });
431
1476
  },
432
1477
  invokeOnClose({ prop }) {
433
1478
  prop("onOpenChange")?.({ open: false });
434
1479
  },
435
- setActiveSnapPoint({ context, event }) {
436
- context.set("activeSnapPoint", event.snapPoint);
1480
+ setSnapPoint({ context, event }) {
1481
+ context.set("snapPoint", event.snapPoint);
437
1482
  },
438
1483
  setPointerStart({ event, refs }) {
439
- refs.get("dragManager").setPointerStart(event.point);
1484
+ refs.get("swipeSession").beginSwipe(event.point);
440
1485
  },
441
- setDragOffset({ context, event, refs }) {
442
- const dragManager = refs.get("dragManager");
443
- dragManager.setDragOffset(event.point, context.get("resolvedActiveSnapPoint")?.offset || 0);
444
- context.set("dragOffset", dragManager.getDragOffset());
1486
+ setDragOffset({ context, event, refs, computed }) {
1487
+ const swipeSession = refs.get("swipeSession");
1488
+ const physicalSwipeDirection = event.swipeDirection ?? computed("physicalSwipeDirection");
1489
+ swipeSession.setDragOffset(event.point, getActiveSnapOffset(context), physicalSwipeDirection);
1490
+ context.set("dragOffset", swipeSession.getDragOffset());
445
1491
  },
446
- setClosestSnapPoint({ computed, context, refs }) {
1492
+ setSwipeOpenDragOffset({ context, event, refs, computed }) {
1493
+ const swipeSession = refs.get("swipeSession");
1494
+ const contentSize = context.get("contentSize");
1495
+ if (!contentSize) return;
1496
+ swipeSession.setSwipeOpenOffset(event.point, contentSize, computed("physicalSwipeDirection"));
1497
+ context.set("dragOffset", swipeSession.getDragOffset());
1498
+ },
1499
+ setClosestSnapPoint({ computed, context, refs, prop, send }) {
447
1500
  const snapPoints = computed("resolvedSnapPoints");
448
- const contentHeight = context.get("contentHeight");
449
- if (!snapPoints.length || contentHeight === null) return;
450
- const closestSnapPoint = refs.get("dragManager").findClosestSnapPoint(snapPoints);
451
- context.set("activeSnapPoint", closestSnapPoint);
452
- const resolved = resolveSnapPoint(closestSnapPoint, contentHeight);
1501
+ const contentSize = context.get("contentSize");
1502
+ const viewportSize = context.get("viewportSize");
1503
+ const rootFontSize = context.get("rootFontSize");
1504
+ if (!snapPoints.length || contentSize === null) return;
1505
+ const closestSnapPoint = refs.get("swipeSession").resolveSnapPointOnRelease(snapPoints, context.get("resolvedActiveSnapPoint"), prop("snapToSequentialPoints"), contentSize);
1506
+ if (closestSnapPoint === null) {
1507
+ send({ type: "CLOSE" });
1508
+ return;
1509
+ }
1510
+ context.set("snapPoint", closestSnapPoint);
1511
+ const resolved = resolveSnapPoint(closestSnapPoint, {
1512
+ contentSize,
1513
+ viewportSize,
1514
+ rootFontSize
1515
+ });
453
1516
  context.set("resolvedActiveSnapPoint", resolved);
454
1517
  },
455
1518
  clearDragOffset({ context, refs }) {
456
- refs.get("dragManager").clearDragOffset();
1519
+ refs.get("swipeSession").resetDragOffset();
457
1520
  context.set("dragOffset", null);
458
1521
  },
459
- clearActiveSnapPoint({ context, prop }) {
460
- context.set("activeSnapPoint", prop("defaultActiveSnapPoint"));
1522
+ clearActiveSnapPoint({ context }) {
1523
+ context.set("snapPoint", context.initial("snapPoint"));
1524
+ },
1525
+ clearSizeMeasurements({ context }) {
1526
+ context.set("contentSize", null);
1527
+ context.set("viewportSize", 0);
1528
+ context.set("rootFontSize", 16);
461
1529
  },
462
1530
  clearResolvedActiveSnapPoint({ context }) {
463
1531
  context.set("resolvedActiveSnapPoint", null);
464
1532
  },
465
1533
  clearPointerStart({ refs }) {
466
- refs.get("dragManager").clearPointerStart();
467
- },
468
- clearContentHeight({ context }) {
469
- context.set("contentHeight", null);
1534
+ refs.get("swipeSession").clearSwipeStart();
470
1535
  },
471
1536
  clearVelocityTracking({ refs }) {
472
- refs.get("dragManager").clearVelocityTracking();
1537
+ refs.get("swipeSession").resetVelocity();
1538
+ },
1539
+ setSnapSwipeStrength({ context, refs, computed, prop }) {
1540
+ const swipeSession = refs.get("swipeSession");
1541
+ const snapPoints = computed("resolvedSnapPoints");
1542
+ const contentSize = context.get("contentSize");
1543
+ const closestSnapPoint = swipeSession.resolveSnapPointOnRelease(snapPoints, context.get("resolvedActiveSnapPoint"), prop("snapToSequentialPoints"), contentSize ?? 0);
1544
+ if (closestSnapPoint === null) return;
1545
+ const viewportSize = context.get("viewportSize");
1546
+ const rootFontSize = context.get("rootFontSize");
1547
+ const resolved = resolveSnapPoint(closestSnapPoint, {
1548
+ contentSize: contentSize ?? 0,
1549
+ viewportSize,
1550
+ rootFontSize
1551
+ });
1552
+ const restOffset = getActiveSnapOffset(context);
1553
+ context.set("swipeStrength", swipeSession.getSwipeStrength(resolved?.offset ?? 0, restOffset));
1554
+ },
1555
+ setDismissSwipeStrength({ context, refs }) {
1556
+ const swipeSession = refs.get("swipeSession");
1557
+ const contentSize = context.get("contentSize");
1558
+ const restOffset = getActiveSnapOffset(context);
1559
+ context.set("swipeStrength", swipeSession.getSwipeStrength(contentSize ?? 0, restOffset));
1560
+ },
1561
+ resetSwipeStrength({ context }) {
1562
+ context.set("swipeStrength", 1);
1563
+ },
1564
+ setRegistrySwiping({ computed }) {
1565
+ drawerRegistry.setSwiping(computed("drawerId"), true);
1566
+ },
1567
+ clearRegistrySwiping({ computed }) {
1568
+ drawerRegistry.setSwiping(computed("drawerId"), false);
473
1569
  },
474
1570
  toggleVisibility({ event, send, prop }) {
475
1571
  send({
476
1572
  type: prop("open") ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE",
477
1573
  previousEvent: event
478
1574
  });
1575
+ },
1576
+ syncDrawerStack({ context, prop, computed }) {
1577
+ const contentSize = context.get("contentSize");
1578
+ if (contentSize === null) return;
1579
+ const dragOffset = context.get("dragOffset");
1580
+ const progress = resolveSwipeProgress(contentSize, dragOffset, getActiveSnapOffset(context));
1581
+ const id = computed("drawerId");
1582
+ if (dragOffset !== null) drawerRegistry.setSwipeProgress(id, progress);
1583
+ const stack = prop("stack");
1584
+ if (!stack) return;
1585
+ stack.setHeight(id, contentSize);
1586
+ stack.setSwipe(id, dragOffset !== null, progress);
479
1587
  }
480
1588
  },
481
1589
  effects: {
1590
+ trackDrawerStack({ context, prop, computed }) {
1591
+ const stack = prop("stack");
1592
+ if (!stack) return;
1593
+ const id = computed("drawerId");
1594
+ stack.register(id);
1595
+ stack.setOpen(id, true);
1596
+ const sync = () => {
1597
+ const contentSize = context.get("contentSize");
1598
+ const dragOffset = context.get("dragOffset");
1599
+ const snapPointOffset = getActiveSnapOffset(context);
1600
+ stack.setHeight(id, contentSize ?? 0);
1601
+ stack.setSwipe(id, dragOffset !== null, resolveSwipeProgress(contentSize, dragOffset, snapPointOffset));
1602
+ };
1603
+ sync();
1604
+ return () => {
1605
+ stack.setSwipe(id, false, 0);
1606
+ stack.setOpen(id, false);
1607
+ stack.unregister(id);
1608
+ };
1609
+ },
482
1610
  trackDismissableElement({ scope, prop, send }) {
483
1611
  const getContentEl$1 = () => getContentEl(scope);
484
1612
  return require_dismissable.trackDismissableElement(getContentEl$1, {
1613
+ type: "drawer",
485
1614
  defer: true,
1615
+ pointerBlocking: prop("modal"),
486
1616
  exclude: [getTriggerEl(scope)],
487
1617
  onInteractOutside(event) {
488
1618
  prop("onInteractOutside")?.(event);
@@ -514,7 +1644,7 @@ const machine = require_core.createMachine({
514
1644
  preventScroll: true,
515
1645
  returnFocusOnDeactivate: !!prop("restoreFocus"),
516
1646
  initialFocus: prop("initialFocusEl"),
517
- setReturnFocus: (el) => prop("finalFocusEl")?.() || el,
1647
+ setReturnFocus: (el) => prop("finalFocusEl")?.() ?? getTriggerEl(scope) ?? el,
518
1648
  getShadowRoot: true
519
1649
  });
520
1650
  },
@@ -523,105 +1653,115 @@ const machine = require_core.createMachine({
523
1653
  const getElements = () => [getContentEl(scope)];
524
1654
  return require_aria_hidden.ariaHidden(getElements, { defer: true });
525
1655
  },
526
- trackPointerMove({ scope, send, prop }) {
527
- let lastY = 0;
528
- function onPointerMove(event) {
529
- send({
530
- type: "POINTER_MOVE",
531
- point: require_dom_query.getEventPoint(event),
532
- target: require_dom_query.getEventTarget(event)
533
- });
534
- }
535
- function onPointerUp(event) {
536
- if (event.pointerType === "touch") return;
537
- send({
538
- type: "POINTER_UP",
539
- point: require_dom_query.getEventPoint(event)
540
- });
541
- }
542
- function onTouchStart(event) {
543
- if (!event.touches[0]) return;
544
- lastY = event.touches[0].clientY;
545
- }
546
- function onTouchMove(event) {
547
- if (!event.touches[0]) return;
548
- const point = require_dom_query.getEventPoint(event);
549
- const target = event.target;
550
- if (!prop("preventDragOnScroll")) {
1656
+ trackPointerMove({ scope, send, refs, computed }) {
1657
+ return refs.get("swipeSession").bindDragTracking({
1658
+ getDoc: () => scope.getDoc(),
1659
+ getContentEl: () => getContentEl(scope),
1660
+ getSwipeAreaEl: () => getSwipeAreaEl(scope),
1661
+ swipeDirection: computed("physicalSwipeDirection"),
1662
+ onMove(details) {
551
1663
  send({
552
1664
  type: "POINTER_MOVE",
553
- point,
554
- target
1665
+ ...details
555
1666
  });
556
- return;
1667
+ },
1668
+ onEnd(details) {
1669
+ send({
1670
+ type: "POINTER_UP",
1671
+ ...details
1672
+ });
1673
+ },
1674
+ onCancel() {
1675
+ send({ type: "POINTER_CANCEL" });
557
1676
  }
558
- const contentEl = getContentEl(scope);
559
- if (!contentEl) return;
560
- let el = target;
561
- while (el && el !== contentEl && el.scrollHeight <= el.clientHeight) el = el.parentElement;
562
- if (el && el !== contentEl) {
563
- const scrollTop = el.scrollTop;
564
- const y = event.touches[0].clientY;
565
- if (scrollTop <= 0 && y > lastY) event.preventDefault();
566
- lastY = y;
1677
+ });
1678
+ },
1679
+ trackSizeMeasurements({ context, scope, computed, prop }) {
1680
+ const contentEl = getContentEl(scope);
1681
+ if (!contentEl) return;
1682
+ const html = scope.getDoc().documentElement;
1683
+ const shouldMeasureRootFontSize = hasRemSnapPoints(prop("snapPoints"));
1684
+ const updateSize = () => {
1685
+ const direction = computed("physicalSwipeDirection");
1686
+ const rect = contentEl.getBoundingClientRect();
1687
+ const viewportSize = isVerticalSwipeDirection(direction) ? html.clientHeight : html.clientWidth;
1688
+ context.set("contentSize", getSwipeDirectionSize(rect, direction));
1689
+ context.set("viewportSize", viewportSize);
1690
+ if (shouldMeasureRootFontSize) {
1691
+ const rootFontSize = Number.parseFloat(getComputedStyle(html).fontSize);
1692
+ if (Number.isFinite(rootFontSize)) context.set("rootFontSize", rootFontSize);
567
1693
  }
568
- send({
569
- type: "POINTER_MOVE",
570
- point,
571
- target
572
- });
573
- }
574
- function onTouchEnd(event) {
575
- if (event.touches.length !== 0) return;
576
- send({
577
- type: "POINTER_UP",
578
- point: require_dom_query.getEventPoint(event)
579
- });
580
- }
581
- const doc = scope.getDoc();
582
- const cleanups = [
583
- require_dom_query.addDomEvent(doc, "pointermove", onPointerMove),
584
- require_dom_query.addDomEvent(doc, "pointerup", onPointerUp),
585
- require_dom_query.addDomEvent(doc, "touchstart", onTouchStart, { passive: false }),
586
- require_dom_query.addDomEvent(doc, "touchmove", onTouchMove, { passive: false }),
587
- require_dom_query.addDomEvent(doc, "touchend", onTouchEnd)
588
- ];
1694
+ };
1695
+ updateSize();
1696
+ const cleanups = [require_dom_query.resizeObserverBorderBox.observe(contentEl, updateSize), require_dom_query.addDomEvent(scope.getWin(), "resize", updateSize)];
589
1697
  return () => {
590
- cleanups.forEach((cleanup) => cleanup());
1698
+ cleanups.forEach((cleanup) => cleanup?.());
591
1699
  };
592
1700
  },
593
- trackContentHeight({ context, scope }) {
1701
+ trackNestedDrawerMetrics({ scope, computed }) {
594
1702
  const contentEl = getContentEl(scope);
595
1703
  if (!contentEl) return;
596
- const updateHeight = () => {
597
- const rect = contentEl.getBoundingClientRect();
598
- context.set("contentHeight", rect.height);
1704
+ const id = computed("drawerId");
1705
+ drawerRegistry.register(id, contentEl);
1706
+ const sync = () => {
1707
+ const entries = [...drawerRegistry.getEntries().entries()];
1708
+ const myIndex = entries.findIndex(([entryId]) => entryId === id);
1709
+ if (myIndex === -1) return;
1710
+ const nestedCount = entries.length - 1 - myIndex;
1711
+ const frontmostHeight = (entries[entries.length - 1]?.[1])?.getBoundingClientRect().height ?? 0;
1712
+ const myHeight = contentEl.getBoundingClientRect().height;
1713
+ contentEl.style.setProperty("--nested-drawers", `${nestedCount}`);
1714
+ contentEl.style.setProperty("--drawer-height", `${myHeight}px`);
1715
+ contentEl.style.setProperty("--drawer-frontmost-height", `${frontmostHeight}px`);
1716
+ if (nestedCount > 0 && frontmostHeight > 0) contentEl.setAttribute("data-nested-drawer-open", "");
1717
+ else if (nestedCount === 0) contentEl.removeAttribute("data-nested-drawer-open");
1718
+ if (drawerRegistry.hasSwipingAfter(id)) contentEl.setAttribute("data-nested-drawer-swiping", "");
1719
+ else contentEl.removeAttribute("data-nested-drawer-swiping");
1720
+ };
1721
+ sync();
1722
+ const cleanups = [
1723
+ drawerRegistry.subscribe(sync),
1724
+ require_dom_query.resizeObserverBorderBox.observe(contentEl, () => drawerRegistry.notify()),
1725
+ require_dom_query.addDomEvent(scope.getWin(), "resize", () => drawerRegistry.notify())
1726
+ ];
1727
+ return () => {
1728
+ cleanups.forEach((cleanup) => cleanup?.());
1729
+ contentEl.removeAttribute("data-nested-drawer-open");
1730
+ contentEl.removeAttribute("data-nested-drawer-swiping");
1731
+ contentEl.style.setProperty("--nested-drawers", "0");
1732
+ contentEl.style.removeProperty("--drawer-frontmost-height");
1733
+ drawerRegistry.unregister(id);
599
1734
  };
600
- updateHeight();
601
- return require_dom_query.resizeObserverBorderBox.observe(contentEl, updateHeight);
602
1735
  },
603
- trackExitAnimation({ send, scope }) {
604
- let cleanup;
605
- const rafCleanup = require_dom_query.raf(() => {
606
- const contentEl = getContentEl(scope);
607
- if (!contentEl) return;
608
- const animationName = getComputedStyle(contentEl).animationName;
609
- if (!animationName || animationName === "none") {
610
- send({ type: "ANIMATION_END" });
611
- return;
1736
+ trackSwipeOpenPointerMove({ scope, send, refs, computed }) {
1737
+ return refs.get("swipeSession").bindSwipeOpenTracking({
1738
+ getDoc: () => scope.getDoc(),
1739
+ getContentEl: () => getContentEl(scope),
1740
+ getSwipeAreaEl: () => getSwipeAreaEl(scope),
1741
+ swipeDirection: computed("physicalSwipeDirection"),
1742
+ onMove(details) {
1743
+ send({
1744
+ type: "POINTER_MOVE",
1745
+ ...details
1746
+ });
1747
+ },
1748
+ onEnd(details) {
1749
+ send({
1750
+ type: "POINTER_UP",
1751
+ ...details
1752
+ });
1753
+ },
1754
+ onCancel() {
1755
+ send({ type: "POINTER_CANCEL" });
612
1756
  }
613
- const onEnd = (event) => {
614
- if (require_dom_query.getEventTarget(event) === contentEl) send({ type: "ANIMATION_END" });
615
- };
616
- contentEl.addEventListener("animationend", onEnd);
617
- cleanup = () => {
618
- contentEl.removeEventListener("animationend", onEnd);
619
- };
620
1757
  });
621
- return () => {
622
- rafCleanup();
623
- cleanup?.();
624
- };
1758
+ },
1759
+ trackExitAnimation({ send, scope }) {
1760
+ const contentEl = getContentEl(scope);
1761
+ if (!contentEl) return;
1762
+ return require_dom_query.addDomEvent(contentEl, "exitcomplete", () => {
1763
+ send({ type: "ANIMATION_END" });
1764
+ });
625
1765
  }
626
1766
  }
627
1767
  }
@@ -639,6 +1779,8 @@ const props = require_create_props.createProps()([
639
1779
  "defaultOpen",
640
1780
  "getRootNode",
641
1781
  "snapPoints",
1782
+ "swipeDirection",
1783
+ "snapToSequentialPoints",
642
1784
  "swipeVelocityThreshold",
643
1785
  "closeThreshold",
644
1786
  "preventDragOnScroll",
@@ -654,14 +1796,139 @@ const props = require_create_props.createProps()([
654
1796
  "restoreFocus",
655
1797
  "role",
656
1798
  "trapFocus",
657
- "defaultActiveSnapPoint",
658
- "activeSnapPoint",
659
- "onActiveSnapPointChange"
1799
+ "defaultSnapPoint",
1800
+ "snapPoint",
1801
+ "onSnapPointChange",
1802
+ "stack"
660
1803
  ]);
661
1804
  const splitProps = require_utils.createSplitProps(props);
662
1805
  //#endregion
1806
+ //#region src/machines/drawer/drawer.stack.ts
1807
+ function resolveSnapshot(entries) {
1808
+ let openCount = 0;
1809
+ let frontmostHeight = 0;
1810
+ let swipeProgress = 0;
1811
+ let frontmostOrder = -1;
1812
+ entries.forEach((entry) => {
1813
+ if (!entry.open) return;
1814
+ openCount += 1;
1815
+ if (entry.order < frontmostOrder) return;
1816
+ frontmostOrder = entry.order;
1817
+ frontmostHeight = entry.height > 0 ? entry.height : 0;
1818
+ swipeProgress = entry.swiping ? require_utils.clampValue(entry.swipeProgress, 0, 1) : 0;
1819
+ });
1820
+ return {
1821
+ active: openCount > 0,
1822
+ openCount,
1823
+ swipeProgress,
1824
+ frontmostHeight
1825
+ };
1826
+ }
1827
+ function createStack() {
1828
+ const entries = /* @__PURE__ */ new Map();
1829
+ const listeners = /* @__PURE__ */ new Set();
1830
+ let order = 0;
1831
+ let pendingNotify = false;
1832
+ let snapshot = Object.freeze({
1833
+ active: false,
1834
+ openCount: 0,
1835
+ swipeProgress: 0,
1836
+ frontmostHeight: 0
1837
+ });
1838
+ const scheduleNotify = () => {
1839
+ if (pendingNotify) return;
1840
+ pendingNotify = true;
1841
+ queueMicrotask(() => {
1842
+ pendingNotify = false;
1843
+ listeners.forEach((listener) => listener());
1844
+ });
1845
+ };
1846
+ const notify = () => {
1847
+ const nextSnapshot = resolveSnapshot(entries);
1848
+ if (snapshot.active === nextSnapshot.active && snapshot.openCount === nextSnapshot.openCount && snapshot.swipeProgress === nextSnapshot.swipeProgress && snapshot.frontmostHeight === nextSnapshot.frontmostHeight) return;
1849
+ snapshot = Object.freeze(nextSnapshot);
1850
+ scheduleNotify();
1851
+ };
1852
+ const ensureEntry = (id) => {
1853
+ let entry = entries.get(id);
1854
+ if (!entry) {
1855
+ entry = {
1856
+ order: ++order,
1857
+ open: false,
1858
+ height: 0,
1859
+ swiping: false,
1860
+ swipeProgress: 0
1861
+ };
1862
+ entries.set(id, entry);
1863
+ }
1864
+ return entry;
1865
+ };
1866
+ return {
1867
+ getSnapshot() {
1868
+ return snapshot;
1869
+ },
1870
+ subscribe(listener) {
1871
+ listeners.add(listener);
1872
+ return () => {
1873
+ listeners.delete(listener);
1874
+ };
1875
+ },
1876
+ register(id) {
1877
+ ensureEntry(id);
1878
+ notify();
1879
+ },
1880
+ unregister(id) {
1881
+ if (!entries.delete(id)) return;
1882
+ notify();
1883
+ },
1884
+ setOpen(id, open) {
1885
+ const entry = ensureEntry(id);
1886
+ if (entry.open === open) return;
1887
+ entry.open = open;
1888
+ if (!open) {
1889
+ entry.swiping = false;
1890
+ entry.swipeProgress = 0;
1891
+ }
1892
+ notify();
1893
+ },
1894
+ setHeight(id, height) {
1895
+ const entry = ensureEntry(id);
1896
+ const nextHeight = Number.isFinite(height) && height > 0 ? height : 0;
1897
+ if (entry.height === nextHeight) return;
1898
+ entry.height = nextHeight;
1899
+ notify();
1900
+ },
1901
+ setSwipe(id, swiping, progress) {
1902
+ const entry = ensureEntry(id);
1903
+ const nextProgress = swiping ? require_utils.clampValue(Number.isFinite(progress) ? progress : 0, 0, 1) : 0;
1904
+ if (entry.swiping === swiping && entry.swipeProgress === nextProgress) return;
1905
+ entry.swiping = swiping;
1906
+ entry.swipeProgress = nextProgress;
1907
+ notify();
1908
+ }
1909
+ };
1910
+ }
1911
+ function connectStack(snapshot, normalize) {
1912
+ const getIndentProps = () => {
1913
+ return normalize.element({
1914
+ "data-active": snapshot.active ? "" : void 0,
1915
+ "data-inactive": snapshot.active ? void 0 : "",
1916
+ style: {
1917
+ "--drawer-swipe-progress": `${require_utils.clampValue(snapshot.swipeProgress, 0, 1)}`,
1918
+ "--drawer-frontmost-height": snapshot.frontmostHeight > 0 ? `${snapshot.frontmostHeight}px` : void 0
1919
+ }
1920
+ });
1921
+ };
1922
+ return {
1923
+ getIndentProps,
1924
+ getIndentBackgroundProps: getIndentProps
1925
+ };
1926
+ }
1927
+ //#endregion
663
1928
  exports.anatomy = anatomy;
664
1929
  exports.connect = connect;
1930
+ exports.connectStack = connectStack;
1931
+ exports.createStack = createStack;
665
1932
  exports.machine = machine;
666
1933
  exports.props = props;
667
1934
  exports.splitProps = splitProps;