@patternmode/stacksheet 1.3.4 → 1.3.6

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 (122) hide show
  1. package/README.md +1 -5
  2. package/dist/Drag/{DragConstants.d.ts → drag-constants.d.ts} +1 -1
  3. package/dist/Drag/drag-constants.d.ts.map +1 -0
  4. package/dist/Drag/drag-geometry.d.ts +22 -0
  5. package/dist/Drag/drag-geometry.d.ts.map +1 -0
  6. package/dist/Drag/{DragTypes.d.ts → drag-types.d.ts} +1 -1
  7. package/dist/Drag/drag-types.d.ts.map +1 -0
  8. package/dist/Drag/{useDrag.d.ts → use-drag.d.ts} +4 -4
  9. package/dist/Drag/use-drag.d.ts.map +1 -0
  10. package/dist/SheetPanel/default-header.d.ts +5 -0
  11. package/dist/SheetPanel/default-header.d.ts.map +1 -0
  12. package/dist/SheetPanel/sheet-panel-content.d.ts +15 -0
  13. package/dist/SheetPanel/sheet-panel-content.d.ts.map +1 -0
  14. package/dist/SheetPanel/sheet-panel-focus.d.ts +8 -0
  15. package/dist/SheetPanel/sheet-panel-focus.d.ts.map +1 -0
  16. package/dist/SheetPanel/sheet-panel-handles.d.ts +10 -0
  17. package/dist/SheetPanel/sheet-panel-handles.d.ts.map +1 -0
  18. package/dist/SheetPanel/sheet-panel-layout.d.ts +4 -0
  19. package/dist/SheetPanel/sheet-panel-layout.d.ts.map +1 -0
  20. package/dist/SheetPanel/{SheetPanelTypes.d.ts → sheet-panel-types.d.ts} +2 -2
  21. package/dist/SheetPanel/sheet-panel-types.d.ts.map +1 -0
  22. package/dist/SheetPanel/sheet-panel.d.ts +3 -0
  23. package/dist/SheetPanel/sheet-panel.d.ts.map +1 -0
  24. package/dist/SheetParts/sheet-back.d.ts +3 -0
  25. package/dist/SheetParts/sheet-back.d.ts.map +1 -0
  26. package/dist/SheetParts/sheet-body.d.ts +3 -0
  27. package/dist/SheetParts/sheet-body.d.ts.map +1 -0
  28. package/dist/SheetParts/sheet-close.d.ts +3 -0
  29. package/dist/SheetParts/sheet-close.d.ts.map +1 -0
  30. package/dist/SheetParts/sheet-description.d.ts +3 -0
  31. package/dist/SheetParts/sheet-description.d.ts.map +1 -0
  32. package/dist/SheetParts/sheet-footer.d.ts +3 -0
  33. package/dist/SheetParts/sheet-footer.d.ts.map +1 -0
  34. package/dist/SheetParts/sheet-handle.d.ts +3 -0
  35. package/dist/SheetParts/sheet-handle.d.ts.map +1 -0
  36. package/dist/SheetParts/sheet-header.d.ts +3 -0
  37. package/dist/SheetParts/sheet-header.d.ts.map +1 -0
  38. package/dist/SheetParts/{SheetPartTypes.d.ts → sheet-part-types.d.ts} +1 -1
  39. package/dist/SheetParts/sheet-part-types.d.ts.map +1 -0
  40. package/dist/SheetParts/sheet-parts.d.ts +20 -0
  41. package/dist/SheetParts/sheet-parts.d.ts.map +1 -0
  42. package/dist/SheetParts/sheet-title.d.ts +3 -0
  43. package/dist/SheetParts/sheet-title.d.ts.map +1 -0
  44. package/dist/Store/{createSheetStore.d.ts → create-sheet-store.d.ts} +3 -3
  45. package/dist/Store/create-sheet-store.d.ts.map +1 -0
  46. package/dist/Store/store-args.d.ts +15 -0
  47. package/dist/Store/store-args.d.ts.map +1 -0
  48. package/dist/Store/{StoreTypes.d.ts → store-types.d.ts} +3 -4
  49. package/dist/Store/store-types.d.ts.map +1 -0
  50. package/dist/config.d.ts +1 -1
  51. package/dist/config.d.ts.map +1 -1
  52. package/dist/create.d.ts +1 -1
  53. package/dist/create.d.ts.map +1 -1
  54. package/dist/icons.d.ts +2 -2
  55. package/dist/icons.d.ts.map +1 -1
  56. package/dist/index.mjs +640 -650
  57. package/dist/index.mjs.map +1 -1
  58. package/dist/media.d.ts +2 -2
  59. package/dist/media.d.ts.map +1 -1
  60. package/dist/panel-context.d.ts +1 -1
  61. package/dist/panel-context.d.ts.map +1 -1
  62. package/dist/parts.d.ts +10 -10
  63. package/dist/parts.d.ts.map +1 -1
  64. package/dist/renderer-effects.d.ts +4 -4
  65. package/dist/renderer-effects.d.ts.map +1 -1
  66. package/dist/renderer-helpers.d.ts +19 -19
  67. package/dist/renderer-helpers.d.ts.map +1 -1
  68. package/dist/renderer.d.ts +7 -6
  69. package/dist/renderer.d.ts.map +1 -1
  70. package/dist/sheet-panel.d.ts +2 -2
  71. package/dist/sheet-panel.d.ts.map +1 -1
  72. package/dist/snap-points.d.ts +3 -3
  73. package/dist/snap-points.d.ts.map +1 -1
  74. package/dist/springs.d.ts +7 -7
  75. package/dist/stacking.d.ts +6 -6
  76. package/dist/stacking.d.ts.map +1 -1
  77. package/dist/store.d.ts +2 -2
  78. package/dist/store.d.ts.map +1 -1
  79. package/dist/types.d.ts +5 -3
  80. package/dist/types.d.ts.map +1 -1
  81. package/package.json +29 -30
  82. package/dist/Drag/DragConstants.d.ts.map +0 -1
  83. package/dist/Drag/DragGeometry.d.ts +0 -22
  84. package/dist/Drag/DragGeometry.d.ts.map +0 -1
  85. package/dist/Drag/DragTypes.d.ts.map +0 -1
  86. package/dist/Drag/useDrag.d.ts.map +0 -1
  87. package/dist/SheetPanel/DefaultHeader.d.ts +0 -5
  88. package/dist/SheetPanel/DefaultHeader.d.ts.map +0 -1
  89. package/dist/SheetPanel/SheetPanel.d.ts +0 -3
  90. package/dist/SheetPanel/SheetPanel.d.ts.map +0 -1
  91. package/dist/SheetPanel/SheetPanelContent.d.ts +0 -12
  92. package/dist/SheetPanel/SheetPanelContent.d.ts.map +0 -1
  93. package/dist/SheetPanel/SheetPanelFocus.d.ts +0 -8
  94. package/dist/SheetPanel/SheetPanelFocus.d.ts.map +0 -1
  95. package/dist/SheetPanel/SheetPanelHandles.d.ts +0 -10
  96. package/dist/SheetPanel/SheetPanelHandles.d.ts.map +0 -1
  97. package/dist/SheetPanel/SheetPanelLayout.d.ts +0 -4
  98. package/dist/SheetPanel/SheetPanelLayout.d.ts.map +0 -1
  99. package/dist/SheetPanel/SheetPanelTypes.d.ts.map +0 -1
  100. package/dist/SheetParts/SheetBack.d.ts +0 -3
  101. package/dist/SheetParts/SheetBack.d.ts.map +0 -1
  102. package/dist/SheetParts/SheetBody.d.ts +0 -3
  103. package/dist/SheetParts/SheetBody.d.ts.map +0 -1
  104. package/dist/SheetParts/SheetClose.d.ts +0 -3
  105. package/dist/SheetParts/SheetClose.d.ts.map +0 -1
  106. package/dist/SheetParts/SheetDescription.d.ts +0 -3
  107. package/dist/SheetParts/SheetDescription.d.ts.map +0 -1
  108. package/dist/SheetParts/SheetFooter.d.ts +0 -3
  109. package/dist/SheetParts/SheetFooter.d.ts.map +0 -1
  110. package/dist/SheetParts/SheetHandle.d.ts +0 -3
  111. package/dist/SheetParts/SheetHandle.d.ts.map +0 -1
  112. package/dist/SheetParts/SheetHeader.d.ts +0 -3
  113. package/dist/SheetParts/SheetHeader.d.ts.map +0 -1
  114. package/dist/SheetParts/SheetPartTypes.d.ts.map +0 -1
  115. package/dist/SheetParts/SheetParts.d.ts +0 -28
  116. package/dist/SheetParts/SheetParts.d.ts.map +0 -1
  117. package/dist/SheetParts/SheetTitle.d.ts +0 -3
  118. package/dist/SheetParts/SheetTitle.d.ts.map +0 -1
  119. package/dist/Store/StoreArgs.d.ts +0 -15
  120. package/dist/Store/StoreArgs.d.ts.map +0 -1
  121. package/dist/Store/StoreTypes.d.ts.map +0 -1
  122. package/dist/Store/createSheetStore.d.ts.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { Portal } from "@radix-ui/react-portal";
3
- import { createContext, memo, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
3
+ import { createContext, use, useEffect, useRef, useState, useSyncExternalStore } from "react";
4
4
  import { createStore, useStore } from "zustand";
5
5
  import { useShallow } from "zustand/react/shallow";
6
6
  import { AnimatePresence, LazyMotion, domMax, m, useReducedMotion } from "motion/react";
@@ -19,37 +19,58 @@ import { Root, Scrollbar, Thumb, Viewport } from "@radix-ui/react-scroll-area";
19
19
  * - `stiff` — Very quick, controlled. Panels, drawers. **(default)**
20
20
  */
21
21
  const springs = {
22
- subtle: {
23
- stiffness: 300,
24
- damping: 30,
25
- mass: 1
26
- },
27
22
  snappy: {
28
- stiffness: 400,
29
23
  damping: 28,
30
- mass: .8
24
+ mass: .8,
25
+ stiffness: 400
31
26
  },
32
27
  stiff: {
33
- stiffness: 400,
34
28
  damping: 40,
35
- mass: 1
29
+ mass: 1,
30
+ stiffness: 400
31
+ },
32
+ subtle: {
33
+ damping: 30,
34
+ mass: 1,
35
+ stiffness: 300
36
36
  }
37
37
  };
38
38
  //#endregion
39
39
  //#region src/config.ts
40
40
  const DEFAULT_STACKING = {
41
- scaleStep: .04,
42
41
  offsetStep: 16,
43
42
  opacityStep: 0,
44
43
  radius: 12,
45
- renderThreshold: 3
44
+ renderThreshold: 3,
45
+ scaleStep: .04
46
46
  };
47
47
  const DEFAULT_SIDE = {
48
48
  desktop: "right",
49
49
  mobile: "bottom"
50
50
  };
51
+ const DEFAULT_CONFIG = {
52
+ ariaLabel: "Sheet dialog",
53
+ breakpoint: 768,
54
+ closeOnBackdrop: true,
55
+ closeOnEscape: true,
56
+ closeThreshold: .25,
57
+ dismissible: true,
58
+ drag: true,
59
+ lockScroll: true,
60
+ maxDepth: Number.POSITIVE_INFINITY,
61
+ maxWidth: "90vw",
62
+ modal: true,
63
+ scaleBackgroundAmount: .97,
64
+ shouldScaleBackground: false,
65
+ showOverlay: true,
66
+ snapPoints: [],
67
+ snapToSequentialPoints: false,
68
+ velocityThreshold: .5,
69
+ width: 420,
70
+ zIndex: 100
71
+ };
51
72
  /** Normalize a string side to a responsive object, merging with defaults. */
52
- function resolveSide(side) {
73
+ const resolveSide = (side) => {
53
74
  if (typeof side === "string") return {
54
75
  desktop: side,
55
76
  mobile: side
@@ -58,56 +79,37 @@ function resolveSide(side) {
58
79
  ...DEFAULT_SIDE,
59
80
  ...side
60
81
  };
61
- }
82
+ };
62
83
  /** Resolve a preset name to a SpringConfig, or merge partial config with defaults. */
63
- function resolveSpring(spring) {
84
+ const resolveSpring = (spring) => {
64
85
  if (typeof spring === "string") return springs[spring];
65
86
  return {
66
87
  ...springs.stiff,
67
88
  ...spring
68
89
  };
69
- }
90
+ };
70
91
  /** Merge user-provided config with defaults. Resolves union types (side, spring) to concrete values. */
71
- function resolveConfig(config = {}) {
92
+ const resolveConfig = (config = {}) => {
93
+ const { side, spring, stacking, ...scalarConfig } = config;
94
+ const definedConfig = Object.fromEntries(Object.entries(scalarConfig).filter(([, value]) => value !== void 0));
72
95
  return {
73
- maxDepth: config.maxDepth ?? Number.POSITIVE_INFINITY,
74
- closeOnEscape: config.closeOnEscape ?? true,
75
- closeOnBackdrop: config.closeOnBackdrop ?? true,
76
- showOverlay: config.showOverlay ?? true,
77
- lockScroll: config.lockScroll ?? true,
78
- width: config.width ?? 420,
79
- maxWidth: config.maxWidth ?? "90vw",
80
- breakpoint: config.breakpoint ?? 768,
81
- side: resolveSide(config.side),
96
+ ...DEFAULT_CONFIG,
97
+ ...definedConfig,
98
+ side: resolveSide(side),
99
+ spring: resolveSpring(spring),
82
100
  stacking: {
83
101
  ...DEFAULT_STACKING,
84
- ...config.stacking
85
- },
86
- spring: resolveSpring(config.spring),
87
- zIndex: config.zIndex ?? 100,
88
- ariaLabel: config.ariaLabel ?? "Sheet dialog",
89
- onOpenComplete: config.onOpenComplete,
90
- onCloseComplete: config.onCloseComplete,
91
- snapPoints: config.snapPoints ?? [],
92
- snapPointIndex: config.snapPointIndex,
93
- onSnapPointChange: config.onSnapPointChange,
94
- snapToSequentialPoints: config.snapToSequentialPoints ?? false,
95
- drag: config.drag ?? true,
96
- closeThreshold: config.closeThreshold ?? .25,
97
- velocityThreshold: config.velocityThreshold ?? .5,
98
- dismissible: config.dismissible ?? true,
99
- modal: config.modal ?? true,
100
- shouldScaleBackground: config.shouldScaleBackground ?? false,
101
- scaleBackgroundAmount: config.scaleBackgroundAmount ?? .97
102
+ ...stacking
103
+ }
102
104
  };
103
- }
105
+ };
104
106
  //#endregion
105
107
  //#region src/media.ts
106
108
  /**
107
109
  * Returns true when viewport width is at or below the breakpoint.
108
110
  * SSR-safe: defaults to false (desktop).
109
111
  */
110
- function useIsMobile(breakpoint) {
112
+ const useIsMobile = (breakpoint) => {
111
113
  const [isMobile, setIsMobile] = useState(false);
112
114
  useEffect(() => {
113
115
  const mql = window.matchMedia(`(max-width: ${breakpoint - 1}px)`);
@@ -117,14 +119,14 @@ function useIsMobile(breakpoint) {
117
119
  return () => mql.removeEventListener("change", handler);
118
120
  }, [breakpoint]);
119
121
  return isMobile;
120
- }
122
+ };
121
123
  /** Resolve the current side from config + viewport. */
122
- function useResolvedSide(config) {
124
+ const useResolvedSide = (config) => {
123
125
  return useIsMobile(config.breakpoint) ? config.side.mobile : config.side.desktop;
124
- }
126
+ };
125
127
  //#endregion
126
128
  //#region src/renderer-effects.ts
127
- function usePanelHeight(panelRef, hasSnapPoints) {
129
+ const usePanelHeight = (panelRef, hasSnapPoints) => {
128
130
  const [height, setHeight] = useState(0);
129
131
  useEffect(() => {
130
132
  const el = panelRef.current;
@@ -137,24 +139,23 @@ function usePanelHeight(panelRef, hasSnapPoints) {
137
139
  return () => observer.disconnect();
138
140
  }, [panelRef, hasSnapPoints]);
139
141
  return height;
140
- }
141
- function useViewportHeight(active) {
142
- const getHeight = useCallback(() => typeof window === "undefined" ? 0 : window.visualViewport?.height ?? window.innerHeight, []);
143
- const [height, setHeight] = useState(() => getHeight());
142
+ };
143
+ const getViewportHeight = () => typeof window === "undefined" ? 0 : window.visualViewport?.height ?? window.innerHeight;
144
+ const useViewportHeight = (active) => {
145
+ const [height, setHeight] = useState(() => typeof window === "undefined" ? void 0 : getViewportHeight());
144
146
  useEffect(() => {
145
147
  if (typeof window === "undefined") return;
146
- const update = () => setHeight(getHeight());
147
- update();
148
+ const update = () => setHeight(getViewportHeight());
148
149
  window.addEventListener("resize", update);
149
150
  window.visualViewport?.addEventListener("resize", update);
150
151
  return () => {
151
152
  window.removeEventListener("resize", update);
152
153
  window.visualViewport?.removeEventListener("resize", update);
153
154
  };
154
- }, [getHeight]);
155
- return active ? height : 0;
156
- }
157
- function useBodyScale(config, isOpen, prefersReducedMotion) {
155
+ }, []);
156
+ return active ? height ?? 0 : 0;
157
+ };
158
+ const useBodyScale = (config, isOpen, prefersReducedMotion) => {
158
159
  useEffect(() => {
159
160
  if (!config.shouldScaleBackground || prefersReducedMotion) return;
160
161
  const wrapper = document.querySelector("[data-stacksheet-wrapper]");
@@ -183,23 +184,24 @@ function useBodyScale(config, isOpen, prefersReducedMotion) {
183
184
  config.scaleBackgroundAmount,
184
185
  prefersReducedMotion
185
186
  ]);
186
- }
187
+ };
187
188
  //#endregion
188
189
  //#region src/snap-points.ts
189
- const SNAP_POINT_RE = /^(\d+(?:\.\d+)?)(px|rem|em|vh|%)$/;
190
+ const SNAP_POINT_RE = /^(\d+(?:\.\d+)?)(px|rem|em|vh|%)$/u;
190
191
  /**
191
192
  * Resolve a snap point value to pixels given the viewport height.
192
193
  * - number 0-1: fraction of viewport (0.5 → 50% of vh)
193
194
  * - number > 1: pixel value (300 → 300px)
194
195
  * - string: parsed via regex for CSS unit support
195
196
  */
196
- function resolveSnapPointPx(point, viewportHeight) {
197
+ const resolveSnapPointPx = (point, viewportHeight) => {
197
198
  if (typeof point === "number") return point <= 1 ? point * viewportHeight : point;
198
199
  if (typeof point === "string") {
199
200
  const match = point.match(SNAP_POINT_RE);
200
201
  if (!match?.[1]) return 0;
201
- const value = Number.parseFloat(match[1]);
202
- switch (match[2]) {
202
+ const [, rawValue, unit] = match;
203
+ const value = Number.parseFloat(rawValue);
204
+ switch (unit) {
203
205
  case "px": return value;
204
206
  case "rem":
205
207
  case "em": return value * (typeof document === "undefined" ? 16 : Number.parseFloat(getComputedStyle(document.documentElement).fontSize));
@@ -209,12 +211,12 @@ function resolveSnapPointPx(point, viewportHeight) {
209
211
  }
210
212
  }
211
213
  return 0;
212
- }
214
+ };
213
215
  /**
214
216
  * Resolve all snap points to sorted pixel heights (ascending).
215
217
  * Returns an array of heights in px that the drawer should snap to.
216
218
  */
217
- function resolveSnapPoints(points, viewportHeight) {
219
+ const resolveSnapPoints = (points, viewportHeight) => {
218
220
  if (points.length === 0) return [];
219
221
  const resolved = [];
220
222
  for (const point of points) {
@@ -228,7 +230,7 @@ function resolveSnapPoints(points, viewportHeight) {
228
230
  if (last === void 0 || Math.abs(px - last) > 1) deduped.push(px);
229
231
  }
230
232
  return deduped;
231
- }
233
+ };
232
234
  /** Velocity threshold (px/ms) for skipping intermediate snap points */
233
235
  const SNAP_VELOCITY_THRESHOLD = .4;
234
236
  /** Max velocity to consider for snap offset calculation */
@@ -244,7 +246,7 @@ const SNAP_VELOCITY_MULTIPLIER = 150;
244
246
  *
245
247
  * Returns -1 if the gesture indicates full dismissal.
246
248
  */
247
- function findSnapTarget(dragOffset, panelHeight, snapHeights, velocity, currentIndex, sequential) {
249
+ const findSnapTarget = (dragOffset, panelHeight, snapHeights, velocity, currentIndex, sequential) => {
248
250
  if (snapHeights.length === 0) return -1;
249
251
  const snapOffsets = snapHeights.map((h) => panelHeight - h);
250
252
  const currentPos = dragOffset;
@@ -258,7 +260,7 @@ function findSnapTarget(dragOffset, panelHeight, snapHeights, velocity, currentI
258
260
  const first = snapOffsets[0] ?? 0;
259
261
  let bestIndex = 0;
260
262
  let bestDist = Math.abs(projectedPos - first);
261
- for (let i = 1; i < snapOffsets.length; i++) {
263
+ for (let i = 1; i < snapOffsets.length; i += 1) {
262
264
  const offset = snapOffsets[i] ?? 0;
263
265
  const dist = Math.abs(projectedPos - offset);
264
266
  if (dist < bestDist) {
@@ -268,31 +270,31 @@ function findSnapTarget(dragOffset, panelHeight, snapHeights, velocity, currentI
268
270
  }
269
271
  if (Math.abs(projectedPos - panelHeight) <= bestDist) return -1;
270
272
  return bestIndex;
271
- }
273
+ };
272
274
  /**
273
275
  * Get the Y offset for a snap point relative to fully open (0 offset).
274
276
  * Returns the number of pixels the drawer should be translated down from fully open.
275
277
  */
276
- function getSnapOffset(snapIndex, snapHeights, panelHeight) {
278
+ const getSnapOffset = (snapIndex, snapHeights, panelHeight) => {
277
279
  if (snapIndex < 0 || snapIndex >= snapHeights.length) return 0;
278
280
  return panelHeight - (snapHeights[snapIndex] ?? 0);
279
- }
281
+ };
280
282
  //#endregion
281
283
  //#region src/renderer-helpers.ts
282
284
  const EMPTY_CLASSNAMES = {
283
285
  backdrop: "",
284
- panel: "",
285
- header: ""
286
+ header: "",
287
+ panel: ""
286
288
  };
287
- function resolveClassNames(cn) {
289
+ const resolveClassNames = (cn) => {
288
290
  if (!cn) return EMPTY_CLASSNAMES;
289
291
  return {
290
292
  backdrop: cn.backdrop ?? "",
291
- panel: cn.panel ?? "",
292
- header: cn.header ?? ""
293
+ header: cn.header ?? "",
294
+ panel: cn.panel ?? ""
293
295
  };
294
- }
295
- function buildAriaProps(isTop, isModal, isComposable, ariaLabel, panelId, hasDescription) {
296
+ };
297
+ const buildAriaProps = (isTop, isModal, isComposable, ariaLabel, panelId, hasDescription) => {
296
298
  if (!isTop) return {};
297
299
  const props = { role: "dialog" };
298
300
  if (isModal) props["aria-modal"] = "true";
@@ -301,8 +303,8 @@ function buildAriaProps(isTop, isModal, isComposable, ariaLabel, panelId, hasDes
301
303
  if (hasDescription) props["aria-describedby"] = `${panelId}-desc`;
302
304
  } else props["aria-label"] = ariaLabel;
303
305
  return props;
304
- }
305
- function getDragTransform(side, offset) {
306
+ };
307
+ const getDragTransform = (side, offset) => {
306
308
  if (offset === 0) return {};
307
309
  switch (side) {
308
310
  case "right": return { x: offset };
@@ -310,57 +312,58 @@ function getDragTransform(side, offset) {
310
312
  case "bottom": return { y: offset };
311
313
  default: return {};
312
314
  }
313
- }
315
+ };
314
316
  const VISUAL_TWEEN = {
315
- type: "tween",
316
317
  duration: .25,
317
- ease: "easeOut"
318
+ ease: "easeOut",
319
+ type: "tween"
318
320
  };
319
- function buildPanelStyle(panelStyles, isTop, hasPanelClass, isDragging) {
320
- return {
321
- ...panelStyles,
322
- pointerEvents: isTop ? "auto" : "none",
323
- ...isTop ? {} : { contain: "layout style paint" },
324
- ...isDragging ? { transition: "none" } : {},
325
- ...hasPanelClass ? {} : {
326
- background: "var(--background, #fff)",
327
- borderColor: "var(--border, transparent)"
328
- }
329
- };
330
- }
331
- function buildPanelTransition(isDragging, isTop, spring, stackSpring) {
321
+ const SHADOW_SM = "0px 1px 3px 0px rgba(0,0,0,0.06), 0px 6px 12px 0px rgba(0,0,0,0.06)";
322
+ const SHADOW_LG = "0px 8px 24px 0px rgba(0,0,0,0.06), 0px 24px 48px 0px rgba(0,0,0,0.04), 0px 48px 96px 0px rgba(0,0,0,0.03)";
323
+ const getShadow = (isNested) => isNested ? SHADOW_SM : SHADOW_LG;
324
+ const buildPanelStyle = (panelStyles, isTop, hasPanelClass, isDragging) => ({
325
+ ...panelStyles,
326
+ pointerEvents: isTop ? "auto" : "none",
327
+ ...isTop ? {} : { contain: "layout style paint" },
328
+ ...isDragging ? { transition: "none" } : {},
329
+ ...hasPanelClass ? {} : {
330
+ background: "var(--background, #fff)",
331
+ borderColor: "var(--border, transparent)"
332
+ }
333
+ });
334
+ const buildPanelTransition = (isDragging, isTop, spring, stackSpring) => {
332
335
  if (isDragging) return {
333
- type: "tween",
334
- duration: 0
336
+ duration: 0,
337
+ type: "tween"
335
338
  };
336
339
  return {
337
340
  ...isTop ? spring : stackSpring,
338
341
  borderRadius: VISUAL_TWEEN,
339
342
  boxShadow: VISUAL_TWEEN
340
343
  };
341
- }
342
- function computeSnapYOffset(side, snapHeights, activeSnapIndex, measuredHeight) {
344
+ };
345
+ const computeSnapYOffset = (side, snapHeights, activeSnapIndex, measuredHeight) => {
343
346
  if (side !== "bottom" || snapHeights.length === 0 || measuredHeight <= 0) return 0;
344
347
  return getSnapOffset(activeSnapIndex, snapHeights, measuredHeight);
345
- }
346
- function getBottomSlideDistance(measuredHeight) {
348
+ };
349
+ const getBottomSlideDistance = (measuredHeight) => {
347
350
  if (measuredHeight > 0) return measuredHeight;
348
351
  if (typeof window !== "undefined") return window.innerHeight;
349
352
  return 1e3;
350
- }
351
- function resolveSlideFrom(side, slideFrom, measuredHeight) {
353
+ };
354
+ const resolveSlideFrom = (side, slideFrom, measuredHeight) => {
352
355
  if (side !== "bottom") return slideFrom;
353
356
  return { y: getBottomSlideDistance(measuredHeight) };
354
- }
355
- function buildAnimateTarget(slideTarget, stackOffset, dragOffset, transform, animatedRadius, transition, snapYOffset, isTop) {
357
+ };
358
+ const buildAnimateTarget = (slideTarget, stackOffset, dragOffset, transform, animatedRadius, transition, snapYOffset, isTop) => {
356
359
  const base = {
357
360
  ...slideTarget,
358
361
  ...stackOffset,
359
362
  ...dragOffset,
360
- scale: transform.scale,
361
- opacity: transform.opacity,
362
363
  ...animatedRadius,
363
364
  boxShadow: getShadow(!isTop),
365
+ opacity: transform.opacity,
366
+ scale: transform.scale,
364
367
  transition
365
368
  };
366
369
  if (snapYOffset > 0) return {
@@ -368,23 +371,18 @@ function buildAnimateTarget(slideTarget, stackOffset, dragOffset, transform, ani
368
371
  y: (dragOffset.y ?? 0) + snapYOffset
369
372
  };
370
373
  return base;
371
- }
372
- function getInitialRadius(side) {
374
+ };
375
+ const getInitialRadius = (side) => {
373
376
  if (side === "bottom") return {
374
- borderTopLeftRadius: 0,
375
- borderTopRightRadius: 0,
376
377
  borderBottomLeftRadius: 0,
377
- borderBottomRightRadius: 0
378
+ borderBottomRightRadius: 0,
379
+ borderTopLeftRadius: 0,
380
+ borderTopRightRadius: 0
378
381
  };
379
382
  return { borderRadius: 0 };
380
- }
381
- const SHADOW_SM = "0px 1px 3px 0px rgba(0,0,0,0.06), 0px 6px 12px 0px rgba(0,0,0,0.06)";
382
- const SHADOW_LG = "0px 8px 24px 0px rgba(0,0,0,0.06), 0px 24px 48px 0px rgba(0,0,0,0.04), 0px 48px 96px 0px rgba(0,0,0,0.03)";
383
- function getShadow(isNested) {
384
- return isNested ? SHADOW_SM : SHADOW_LG;
385
- }
383
+ };
386
384
  //#endregion
387
- //#region src/Drag/DragConstants.ts
385
+ //#region src/Drag/drag-constants.ts
388
386
  /** Elements that should never initiate a drag */
389
387
  const INTERACTIVE_TAGS = new Set([
390
388
  "INPUT",
@@ -396,19 +394,19 @@ const INTERACTIVE_TAGS = new Set([
396
394
  /** Rubber-band resistance factor for dragging past resting position */
397
395
  const RUBBER_BAND_FACTOR = .6;
398
396
  //#endregion
399
- //#region src/Drag/DragGeometry.ts
400
- function isInteractiveElement(el) {
397
+ //#region src/Drag/drag-geometry.ts
398
+ const isInteractiveElement = (el) => {
401
399
  if (INTERACTIVE_TAGS.has(el.tagName)) return true;
402
400
  if (el.isContentEditable) return true;
403
401
  if (el.closest("button, a, input, textarea, select, [contenteditable]")) return true;
404
402
  if (el.closest("[data-stacksheet-no-drag]")) return true;
405
403
  return false;
406
- }
404
+ };
407
405
  /**
408
406
  * Walk up from `el` to find the nearest scrollable ancestor.
409
407
  * Returns null if nothing is scrollable in the dismiss axis.
410
408
  */
411
- function findScrollableAncestor(el, axis) {
409
+ const findScrollableAncestor = (el, axis) => {
412
410
  let current = el;
413
411
  while (current) {
414
412
  if (current instanceof HTMLElement) {
@@ -421,23 +419,23 @@ function findScrollableAncestor(el, axis) {
421
419
  current = current.parentElement;
422
420
  }
423
421
  return null;
424
- }
422
+ };
425
423
  /**
426
424
  * Check if a scrollable element is at its edge in the dismiss direction.
427
425
  * For bottom sheets (sign=1, axis=y), "at edge" means scrolled to top.
428
426
  * For left panels (sign=-1, axis=x), "at edge" means scrolled to right end.
429
427
  */
430
- function isAtScrollEdge(el, axis, sign) {
428
+ const isAtScrollEdge = (el, axis, sign) => {
431
429
  if (axis === "y") return sign === 1 ? el.scrollTop <= 0 : el.scrollTop + el.clientHeight >= el.scrollHeight - 1;
432
430
  return sign === 1 ? el.scrollLeft <= 0 : el.scrollLeft + el.clientWidth >= el.scrollWidth - 1;
433
- }
431
+ };
434
432
  /**
435
433
  * Get the dismiss direction axis and sign for a given side.
436
434
  * - right panel → dismiss by dragging right (+x)
437
435
  * - left panel → dismiss by dragging left (-x)
438
436
  * - bottom panel → dismiss by dragging down (+y)
439
437
  */
440
- function getDismissAxis(side) {
438
+ const getDismissAxis = (side) => {
441
439
  switch (side) {
442
440
  case "right": return {
443
441
  axis: "x",
@@ -456,13 +454,13 @@ function getDismissAxis(side) {
456
454
  sign: 1
457
455
  };
458
456
  }
459
- }
457
+ };
460
458
  /**
461
459
  * Decide whether a gesture past the dead zone qualifies as a dismiss drag.
462
460
  * Returns "drag" if it's a valid dismiss gesture, "none" if it's off-axis
463
461
  * or moving in the wrong direction.
464
462
  */
465
- function classifyGesture(dx, dy, axis, sign) {
463
+ const classifyGesture = (dx, dy, axis, sign) => {
466
464
  const absDx = Math.abs(dx);
467
465
  const absDy = Math.abs(dy);
468
466
  let angleDeg;
@@ -471,19 +469,19 @@ function classifyGesture(dx, dy, axis, sign) {
471
469
  if (angleDeg > 35) return "none";
472
470
  if ((axis === "x" ? dx : dy) * sign < 0) return "none";
473
471
  return "drag";
474
- }
472
+ };
475
473
  /** Decide whether a pointer gesture commits as a drag or should be ignored. */
476
- function commitGesture(dx, dy, axis, sign, scrollEl) {
474
+ const commitGesture = (dx, dy, axis, sign, scrollEl) => {
477
475
  if (classifyGesture(dx, dy, axis, sign) === "none") return "none";
478
476
  if (scrollEl && !isAtScrollEdge(scrollEl, axis, sign)) return "none";
479
477
  return "drag";
480
- }
481
- function getPanelDimension(panel, axis) {
478
+ };
479
+ const getPanelDimension = (panel, axis) => {
482
480
  if (!panel) return 300;
483
481
  return axis === "x" ? panel.offsetWidth : panel.offsetHeight;
484
- }
482
+ };
485
483
  //#endregion
486
- //#region src/Drag/useDrag.ts
484
+ //#region src/Drag/use-drag.ts
487
485
  /**
488
486
  * Hook that manages drag gestures that can dismiss a sheet panel.
489
487
  *
@@ -500,13 +498,13 @@ function getPanelDimension(panel, axis) {
500
498
  * When `snapHeights` is provided, release targeting uses
501
499
  * `findSnapTarget()` instead of the simple threshold check.
502
500
  */
503
- function useDrag(panelRef, config, onDragUpdate) {
501
+ const useDrag = (panelRef, config, onDragUpdate) => {
504
502
  const startRef = useRef(null);
505
503
  const committedRef = useRef(null);
506
504
  const offsetRef = useRef(0);
507
505
  const scrollTargetRef = useRef(null);
508
506
  const { axis, sign } = getDismissAxis(config.side);
509
- const handlePointerDown = useCallback((e) => {
507
+ const handlePointerDown = (e) => {
510
508
  if (!config.enabled) return;
511
509
  if (e.button !== 0) return;
512
510
  const target = e.target;
@@ -515,19 +513,19 @@ function useDrag(panelRef, config, onDragUpdate) {
515
513
  if (!isHandle && isInteractiveElement(target)) return;
516
514
  scrollTargetRef.current = isHandle ? null : findScrollableAncestor(target, axis);
517
515
  startRef.current = {
516
+ time: Date.now(),
518
517
  x: e.clientX,
519
- y: e.clientY,
520
- time: Date.now()
518
+ y: e.clientY
521
519
  };
522
520
  committedRef.current = null;
523
521
  offsetRef.current = 0;
524
522
  e.currentTarget?.setPointerCapture?.(e.pointerId);
525
- }, [config.enabled, axis]);
526
- const handlePointerMove = useCallback((e) => {
523
+ };
524
+ const handlePointerMove = (e) => {
527
525
  if (!startRef.current) return;
528
526
  const dx = e.clientX - startRef.current.x;
529
527
  const dy = e.clientY - startRef.current.y;
530
- const dist = Math.sqrt(dx * dx + dy * dy);
528
+ const dist = Math.hypot(dx, dy);
531
529
  if (committedRef.current === null && dist < 10) return;
532
530
  if (committedRef.current === null) {
533
531
  committedRef.current = commitGesture(dx, dy, axis, sign, scrollTargetRef.current);
@@ -541,20 +539,16 @@ function useDrag(panelRef, config, onDragUpdate) {
541
539
  const clampedOffset = directional >= 0 ? directional : -Math.sqrt(Math.abs(directional)) * RUBBER_BAND_FACTOR;
542
540
  offsetRef.current = clampedOffset;
543
541
  onDragUpdate({
544
- offset: clampedOffset,
545
- isDragging: true
542
+ isDragging: true,
543
+ offset: clampedOffset
546
544
  });
547
545
  e.preventDefault();
548
- }, [
549
- axis,
550
- sign,
551
- onDragUpdate
552
- ]);
553
- const dismiss = useCallback(() => {
546
+ };
547
+ const dismiss = () => {
554
548
  if (config.isNested) config.onPop();
555
549
  else config.onClose();
556
- }, [config]);
557
- const handlePointerUp = useCallback((_e) => {
550
+ };
551
+ const handlePointerUp = (_e) => {
558
552
  if (!startRef.current || committedRef.current !== "drag") {
559
553
  startRef.current = null;
560
554
  committedRef.current = null;
@@ -575,8 +569,8 @@ function useDrag(panelRef, config, onDragUpdate) {
575
569
  else {
576
570
  config.onSnap(targetIndex);
577
571
  onDragUpdate({
578
- offset: 0,
579
- isDragging: false
572
+ isDragging: false,
573
+ offset: 0
580
574
  });
581
575
  }
582
576
  return;
@@ -585,26 +579,20 @@ function useDrag(panelRef, config, onDragUpdate) {
585
579
  const fastEnough = velocity > config.velocityThreshold;
586
580
  if (pastThreshold || fastEnough) dismiss();
587
581
  else onDragUpdate({
588
- offset: 0,
589
- isDragging: false
582
+ isDragging: false,
583
+ offset: 0
590
584
  });
591
- }, [
592
- panelRef,
593
- axis,
594
- config,
595
- onDragUpdate,
596
- dismiss
597
- ]);
598
- const handlePointerCancel = useCallback(() => {
585
+ };
586
+ const handlePointerCancel = () => {
599
587
  startRef.current = null;
600
588
  committedRef.current = null;
601
589
  offsetRef.current = 0;
602
590
  scrollTargetRef.current = null;
603
591
  onDragUpdate({
604
- offset: 0,
605
- isDragging: false
592
+ isDragging: false,
593
+ offset: 0
606
594
  });
607
- }, [onDragUpdate]);
595
+ };
608
596
  const handlersRef = useRef({
609
597
  handlePointerCancel,
610
598
  handlePointerDown,
@@ -635,7 +623,7 @@ function useDrag(panelRef, config, onDragUpdate) {
635
623
  el.removeEventListener("pointercancel", onPointerCancel);
636
624
  };
637
625
  }, [panelRef, config.enabled]);
638
- }
626
+ };
639
627
  //#endregion
640
628
  //#region src/panel-context.tsx
641
629
  const SheetPanelContext = createContext(null);
@@ -643,11 +631,11 @@ const SheetPanelContext = createContext(null);
643
631
  * Access the current sheet panel's context.
644
632
  * Must be called inside a component rendered by the sheet stack.
645
633
  */
646
- function useSheetPanel() {
647
- const ctx = useContext(SheetPanelContext);
634
+ const useSheetPanel = () => {
635
+ const ctx = use(SheetPanelContext);
648
636
  if (!ctx) throw new Error("Sheet.* components must be used inside a sheet panel. They should be rendered by a component opened via actions.open(), push(), etc.");
649
637
  return ctx;
650
- }
638
+ };
651
639
  //#endregion
652
640
  //#region src/stacking.ts
653
641
  /**
@@ -655,58 +643,56 @@ function useSheetPanel() {
655
643
  * depth=0 is the top (foreground) panel.
656
644
  * Panels beyond renderThreshold are clamped to the edge position and faded out.
657
645
  */
658
- function getStackTransform(depth, stacking) {
646
+ const getStackTransform = (depth, stacking) => {
659
647
  if (depth <= 0) return {
660
- scale: 1,
648
+ borderRadius: 0,
661
649
  offset: 0,
662
650
  opacity: 1,
663
- borderRadius: 0
651
+ scale: 1
664
652
  };
665
653
  const beyondThreshold = depth >= stacking.renderThreshold;
666
654
  const visualDepth = beyondThreshold ? stacking.renderThreshold - 1 : depth;
667
655
  return {
668
- scale: Math.max(.5, 1 - visualDepth * stacking.scaleStep),
656
+ borderRadius: stacking.radius,
669
657
  offset: visualDepth * stacking.offsetStep,
670
658
  opacity: beyondThreshold ? 0 : Math.max(0, 1 - visualDepth * stacking.opacityStep),
671
- borderRadius: stacking.radius
659
+ scale: Math.max(.5, 1 - visualDepth * stacking.scaleStep)
672
660
  };
673
- }
661
+ };
674
662
  /**
675
663
  * Border radius values for the animate target.
676
664
  * Must be animated (not static CSS) so Motion applies scale correction
677
665
  * when panels are scaled. See: https://motion.dev/docs/react-layout-animations#scale-correction
678
666
  */
679
- function getAnimatedBorderRadius(side, depth, stacking) {
667
+ const getAnimatedBorderRadius = (side, depth, stacking) => {
680
668
  if (side === "bottom") {
681
669
  const radius = depth > 0 ? stacking.radius : 16;
682
670
  return {
683
- borderTopLeftRadius: radius,
684
- borderTopRightRadius: radius,
685
671
  borderBottomLeftRadius: 0,
686
- borderBottomRightRadius: 0
672
+ borderBottomRightRadius: 0,
673
+ borderTopLeftRadius: radius,
674
+ borderTopRightRadius: radius
687
675
  };
688
676
  }
689
677
  if (depth > 0) return { borderRadius: stacking.radius };
690
678
  return { borderRadius: 0 };
691
- }
679
+ };
692
680
  /** Motion initial/exit values for sliding from the given side. */
693
- function getSlideFrom(side) {
681
+ const getSlideFrom = (side) => {
694
682
  switch (side) {
695
683
  case "right": return { x: "100%" };
696
684
  case "left": return { x: "-100%" };
697
685
  case "bottom": return { y: "100%" };
698
686
  default: return { x: "100%" };
699
687
  }
700
- }
688
+ };
701
689
  /** Motion animate target — the resting position. */
702
- function getSlideTarget() {
703
- return {
704
- x: 0,
705
- y: 0
706
- };
707
- }
690
+ const getSlideTarget = () => ({
691
+ x: 0,
692
+ y: 0
693
+ });
708
694
  /** Translate offset that pushes stacked panels away from the stack edge. */
709
- function getStackOffset(side, offset) {
695
+ const getStackOffset = (side, offset) => {
710
696
  if (offset === 0) return {};
711
697
  switch (side) {
712
698
  case "right": return { x: -offset };
@@ -714,107 +700,101 @@ function getStackOffset(side, offset) {
714
700
  case "bottom": return { y: -offset };
715
701
  default: return {};
716
702
  }
717
- }
703
+ };
718
704
  /** Opposite-side origin so stacked panels recede away from the stack edge. */
719
- function getTransformOrigin(side) {
705
+ const getTransformOrigin = (side) => {
720
706
  if (side === "right") return "left center";
721
707
  if (side === "left") return "right center";
722
708
  return "center top";
723
- }
709
+ };
724
710
  /**
725
711
  * Fixed-position styles for a panel, accounting for side, width, and depth.
726
712
  */
727
- function getPanelStyles(side, config, index) {
713
+ const getPanelStyles = (side, config, index) => {
728
714
  const { width, maxWidth, zIndex } = config;
729
715
  const base = {
730
- position: "fixed",
731
- zIndex: zIndex + 10 + index,
732
716
  display: "flex",
733
717
  flexDirection: "column",
718
+ position: "fixed",
719
+ transformOrigin: getTransformOrigin(side),
734
720
  willChange: "transform",
735
- transformOrigin: getTransformOrigin(side)
721
+ zIndex: zIndex + 10 + index
736
722
  };
737
723
  if (side === "bottom") return {
738
724
  ...base,
739
- left: 0,
740
- right: 0,
741
725
  bottom: 0,
742
726
  height: "85dvh",
743
- maxHeight: "85dvh"
727
+ left: 0,
728
+ maxHeight: "85dvh",
729
+ right: 0
744
730
  };
745
731
  const sideStyles = side === "right" ? {
746
- top: 0,
732
+ bottom: 0,
747
733
  right: 0,
748
- bottom: 0
734
+ top: 0
749
735
  } : {
750
- top: 0,
736
+ bottom: 0,
751
737
  left: 0,
752
- bottom: 0
738
+ top: 0
753
739
  };
754
740
  return {
755
741
  ...base,
756
742
  ...sideStyles,
757
- width,
758
- maxWidth
743
+ maxWidth,
744
+ width
759
745
  };
760
- }
746
+ };
761
747
  //#endregion
762
748
  //#region src/icons.tsx
763
749
  /** Inline SVG icons — no external dependency */
764
- function ArrowLeftIcon() {
765
- return /* @__PURE__ */ jsx("svg", {
766
- "aria-hidden": "true",
767
- fill: "none",
768
- height: 16,
769
- stroke: "currentColor",
770
- strokeLinecap: "round",
771
- strokeLinejoin: "round",
772
- strokeWidth: 2,
773
- viewBox: "0 0 24 24",
774
- width: 16,
775
- children: /* @__PURE__ */ jsx("path", { d: "M19 12H5M12 19l-7-7 7-7" })
776
- });
777
- }
778
- function XIcon() {
779
- return /* @__PURE__ */ jsx("svg", {
780
- "aria-hidden": "true",
781
- fill: "none",
782
- height: 16,
783
- stroke: "currentColor",
784
- strokeLinecap: "round",
785
- strokeLinejoin: "round",
786
- strokeWidth: 2,
787
- viewBox: "0 0 24 24",
788
- width: 16,
789
- children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
790
- });
791
- }
750
+ const ArrowLeftIcon = () => /* @__PURE__ */ jsx("svg", {
751
+ "aria-hidden": "true",
752
+ fill: "none",
753
+ height: 16,
754
+ stroke: "currentColor",
755
+ strokeLinecap: "round",
756
+ strokeLinejoin: "round",
757
+ strokeWidth: 2,
758
+ viewBox: "0 0 24 24",
759
+ width: 16,
760
+ children: /* @__PURE__ */ jsx("path", { d: "M19 12H5M12 19l-7-7 7-7" })
761
+ });
762
+ const XIcon = () => /* @__PURE__ */ jsx("svg", {
763
+ "aria-hidden": "true",
764
+ fill: "none",
765
+ height: 16,
766
+ stroke: "currentColor",
767
+ strokeLinecap: "round",
768
+ strokeLinejoin: "round",
769
+ strokeWidth: 2,
770
+ viewBox: "0 0 24 24",
771
+ width: 16,
772
+ children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
773
+ });
792
774
  //#endregion
793
- //#region src/SheetPanel/DefaultHeader.tsx
794
- function DefaultHeader({ isNested, onBack, onClose, className }) {
795
- return /* @__PURE__ */ jsxs("div", {
796
- className: `flex shrink-0 items-center justify-between px-4 pt-4 pb-2 ${className ?? ""}`,
797
- children: [/* @__PURE__ */ jsx("div", {
798
- className: "flex items-center gap-2",
799
- children: isNested && /* @__PURE__ */ jsx("button", {
800
- "aria-label": "Back",
801
- className: "flex min-h-11 min-w-11 shrink-0 cursor-pointer items-center justify-center rounded-full border-none bg-black/5 p-0 text-inherit opacity-70 transition-opacity duration-150 hover:opacity-100",
802
- onClick: onBack,
803
- type: "button",
804
- children: /* @__PURE__ */ jsx(ArrowLeftIcon, {})
805
- })
806
- }), /* @__PURE__ */ jsx("button", {
807
- "aria-label": "Close",
775
+ //#region src/SheetPanel/default-header.tsx
776
+ const DefaultHeader = ({ isNested, onBack, onClose, className }) => /* @__PURE__ */ jsxs("div", {
777
+ className: `flex shrink-0 items-center justify-between px-4 pt-4 pb-2 ${className ?? ""}`,
778
+ children: [/* @__PURE__ */ jsx("div", {
779
+ className: "flex items-center gap-2",
780
+ children: isNested && /* @__PURE__ */ jsx("button", {
781
+ "aria-label": "Back",
808
782
  className: "flex min-h-11 min-w-11 shrink-0 cursor-pointer items-center justify-center rounded-full border-none bg-black/5 p-0 text-inherit opacity-70 transition-opacity duration-150 hover:opacity-100",
809
- onClick: onClose,
783
+ onClick: onBack,
810
784
  type: "button",
811
- children: /* @__PURE__ */ jsx(XIcon, {})
812
- })]
813
- });
814
- }
785
+ children: /* @__PURE__ */ jsx(ArrowLeftIcon, {})
786
+ })
787
+ }), /* @__PURE__ */ jsx("button", {
788
+ "aria-label": "Close",
789
+ className: "flex min-h-11 min-w-11 shrink-0 cursor-pointer items-center justify-center rounded-full border-none bg-black/5 p-0 text-inherit opacity-70 transition-opacity duration-150 hover:opacity-100",
790
+ onClick: onClose,
791
+ type: "button",
792
+ children: /* @__PURE__ */ jsx(XIcon, {})
793
+ })]
794
+ });
815
795
  //#endregion
816
- //#region src/SheetPanel/SheetPanelContent.tsx
817
- const PanelInnerContent = memo(function PanelInnerContent({ isComposable, shouldRender, Content, data, renderHeader, headerProps, headerClassName }) {
796
+ //#region src/SheetPanel/sheet-panel-content.tsx
797
+ const PanelInnerContent = ({ isComposable, shouldRender, Content, data, renderHeader, headerProps, headerClassName }) => {
818
798
  if (isComposable) return shouldRender && Content ? /* @__PURE__ */ jsx(Content, { ...data }) : null;
819
799
  return /* @__PURE__ */ jsxs(Fragment, { children: [renderHeader ? renderHeader(headerProps) : /* @__PURE__ */ jsx(DefaultHeader, {
820
800
  ...headerProps,
@@ -824,176 +804,188 @@ const PanelInnerContent = memo(function PanelInnerContent({ isComposable, should
824
804
  "data-stacksheet-no-drag": "",
825
805
  children: /* @__PURE__ */ jsx(Content, { ...data })
826
806
  })] });
827
- });
807
+ };
828
808
  PanelInnerContent.displayName = "PanelInnerContent";
829
809
  //#endregion
830
- //#region src/SheetPanel/SheetPanelFocus.tsx
810
+ //#region src/SheetPanel/sheet-panel-focus.tsx
831
811
  const LAYERED_MODAL_SELECTORS = [
832
812
  "[role=\"dialog\"][data-state=\"open\"]",
833
813
  "[role=\"alertdialog\"][data-state=\"open\"]",
834
814
  "[data-radix-popper-content-wrapper]",
835
815
  "[data-radix-focus-guard]"
836
816
  ].join(", ");
837
- function ModalFocusTrap({ enabled, active, fallbackRef, children }) {
817
+ const subscribeToFocusTarget = (onStoreChange) => {
818
+ document.addEventListener("focusin", onStoreChange, true);
819
+ return () => document.removeEventListener("focusin", onStoreChange, true);
820
+ };
821
+ const getServerLayeredModalFocused = () => false;
822
+ const getLayeredModalFocused = () => {
823
+ if (typeof document === "undefined") return false;
824
+ const target = document.activeElement;
825
+ return !!target && target !== document.body && target instanceof Element && target.closest(LAYERED_MODAL_SELECTORS) !== null;
826
+ };
827
+ const useLayeredModalFocused = (active) => {
828
+ const layered = useSyncExternalStore(subscribeToFocusTarget, getLayeredModalFocused, getServerLayeredModalFocused);
829
+ return active && layered;
830
+ };
831
+ const ModalFocusTrap = ({ enabled, active, fallbackRef, children }) => {
838
832
  const paused = useLayeredModalFocused(enabled && active);
839
833
  if (!enabled) return children;
840
834
  return /* @__PURE__ */ jsx(FocusTrap, {
841
835
  active,
842
836
  focusTrapOptions: {
843
- initialFocus: false,
844
- returnFocusOnDeactivate: true,
845
- escapeDeactivates: false,
846
837
  allowOutsideClick: true,
847
- checkCanFocusTrap: () => new Promise((resolve) => requestAnimationFrame(() => resolve())),
838
+ escapeDeactivates: false,
848
839
  fallbackFocus: () => {
849
840
  if (fallbackRef.current) return fallbackRef.current;
850
841
  return document.body;
851
- }
842
+ },
843
+ initialFocus: false,
844
+ returnFocusOnDeactivate: true
852
845
  },
853
846
  paused,
854
847
  children
855
848
  });
856
- }
857
- function useLayeredModalFocused(active) {
858
- const layered = useSyncExternalStore(subscribeToFocusTarget, getLayeredModalFocused, getServerLayeredModalFocused);
859
- return active && layered;
860
- }
861
- function subscribeToFocusTarget(onStoreChange) {
862
- document.addEventListener("focusin", onStoreChange, true);
863
- return () => document.removeEventListener("focusin", onStoreChange, true);
864
- }
865
- function getServerLayeredModalFocused() {
866
- return false;
867
- }
868
- function getLayeredModalFocused() {
869
- if (typeof document === "undefined") return false;
870
- const target = document.activeElement;
871
- return !!target && target !== document.body && target instanceof Element && target.closest(LAYERED_MODAL_SELECTORS) !== null;
872
- }
849
+ };
873
850
  //#endregion
874
- //#region src/SheetPanel/SheetPanelHandles.tsx
875
- function BottomHandle({ onDismiss }) {
876
- return /* @__PURE__ */ jsx("button", {
877
- "aria-label": "Dismiss",
878
- className: "absolute inset-x-0 top-0 z-10 flex w-full cursor-grab touch-none items-center justify-center border-none bg-transparent pt-2.5 pb-2",
879
- "data-stacksheet-handle": "",
880
- onClick: onDismiss,
881
- type: "button",
882
- children: /* @__PURE__ */ jsx("div", {
883
- "aria-hidden": "true",
884
- className: "h-[5px] w-9 rounded-full bg-current/15"
885
- })
886
- });
887
- }
888
- function SideHandle({ side, isHovered, onDismiss }) {
851
+ //#region src/SheetPanel/sheet-panel-handles.tsx
852
+ const BottomHandle = ({ onDismiss }) => /* @__PURE__ */ jsx("button", {
853
+ "aria-label": "Dismiss",
854
+ className: "absolute inset-x-0 top-0 z-10 flex w-full cursor-grab touch-none items-center justify-center border-none bg-transparent pt-2.5 pb-2",
855
+ "data-stacksheet-handle": "",
856
+ onClick: onDismiss,
857
+ type: "button",
858
+ children: /* @__PURE__ */ jsx("div", {
859
+ "aria-hidden": "true",
860
+ className: "h-[5px] w-9 rounded-full bg-current/15"
861
+ })
862
+ });
863
+ const SideHandle = ({ side, isHovered, onDismiss }) => {
889
864
  const position = side === "right" ? { right: "100%" } : { left: "100%" };
890
- return /* @__PURE__ */ jsx(m.div, {
865
+ return /* @__PURE__ */ jsx(m.button, {
891
866
  animate: { opacity: isHovered ? 1 : 0 },
892
867
  "aria-label": "Dismiss",
893
- className: "absolute top-0 bottom-0 flex w-6 cursor-grab touch-none items-center justify-center",
868
+ className: "absolute top-0 bottom-0 flex w-6 cursor-grab touch-none items-center justify-center border-none bg-transparent p-0 text-inherit",
894
869
  "data-stacksheet-handle": "",
895
870
  onClick: onDismiss,
896
- onKeyDown: (e) => {
897
- if (e.key === "Enter" || e.key === " ") {
898
- e.preventDefault();
899
- onDismiss?.();
900
- }
901
- },
902
- role: "button",
903
871
  style: position,
904
- tabIndex: 0,
905
872
  transition: {
906
873
  duration: isHovered ? .15 : .4,
907
874
  ease: "easeOut"
908
875
  },
876
+ type: "button",
909
877
  children: /* @__PURE__ */ jsx("div", {
910
878
  "aria-hidden": "true",
911
879
  className: "h-8 w-1 rounded-full bg-current/20"
912
880
  })
913
881
  });
914
- }
882
+ };
915
883
  //#endregion
916
- //#region src/SheetPanel/SheetPanelLayout.ts
917
- function resolvePanelLayout(layout, renderHeader) {
884
+ //#region src/SheetPanel/sheet-panel-layout.ts
885
+ const resolvePanelLayout = (layout, renderHeader) => {
918
886
  if (layout) return layout;
919
887
  return renderHeader === false ? "composable" : "classic";
920
- }
888
+ };
921
889
  //#endregion
922
- //#region src/SheetPanel/SheetPanel.tsx
923
- const SheetPanel = memo(function SheetPanel({ item, index, depth, isTop, isNested, side, config, classNames, Content, shouldRender, pop, close, swipeClose, swipePop, snapHeights, activeSnapIndex, onSnap, layout, renderHeader, slideFrom, slideTarget, spring, stackSpring, prefersReducedMotion }) {
890
+ //#region src/SheetPanel/sheet-panel.tsx
891
+ const getPanelAriaLabel = (item, fallbackLabel) => item.ariaLabel ?? (typeof item.data?.__ariaLabel === "string" ? item.data.__ariaLabel : void 0) ?? fallbackLabel;
892
+ const getPanelHoverProps = (enabled, setIsHovered) => enabled ? {
893
+ onBlur: () => setIsHovered(false),
894
+ onFocus: () => setIsHovered(true),
895
+ onMouseEnter: () => setIsHovered(true),
896
+ onMouseLeave: () => setIsHovered(false)
897
+ } : {};
898
+ const getInactivePanelProps = (isTop) => isTop ? {} : {
899
+ "aria-hidden": "true",
900
+ inert: true
901
+ };
902
+ const getHeaderProps = ({ close, isNested, pop, side }) => ({
903
+ isNested,
904
+ onBack: pop,
905
+ onClose: close,
906
+ side
907
+ });
908
+ const getPanelContext = ({ close, hasDescription, isNested, isTop, panelId, pop, registerDescription, side }) => ({
909
+ back: pop,
910
+ close,
911
+ hasDescription,
912
+ isNested,
913
+ isTop,
914
+ panelId,
915
+ registerDescription,
916
+ side
917
+ });
918
+ const getOptionalSideHandle = ({ isHovered, onDismiss, show, side }) => show ? /* @__PURE__ */ jsx(SideHandle, {
919
+ isHovered,
920
+ onDismiss,
921
+ side
922
+ }) : null;
923
+ const getOptionalBottomHandle = (show, onDismiss) => show ? /* @__PURE__ */ jsx(BottomHandle, { onDismiss }) : null;
924
+ const completeOpeningAnimation = (hasEnteredRef, isTop, onOpenCompleteRef) => {
925
+ if (isTop && !hasEnteredRef.current) {
926
+ hasEnteredRef.current = true;
927
+ onOpenCompleteRef.current?.();
928
+ }
929
+ };
930
+ const SheetPanel = ({ item, index, depth, isTop, isNested, side, config, classNames, Content, shouldRender, pop, close, swipeClose, swipePop, snapHeights, activeSnapIndex, onSnap, layout, renderHeader, slideFrom, slideTarget, spring, stackSpring, prefersReducedMotion }) => {
924
931
  const panelRef = useRef(null);
925
932
  const hasEnteredRef = useRef(false);
933
+ const onOpenCompleteRef = useRef(config.onOpenComplete);
926
934
  const [dragState, setDragState] = useState({
927
- offset: 0,
928
- isDragging: false
935
+ isDragging: false,
936
+ offset: 0
929
937
  });
930
938
  const [isHovered, setIsHovered] = useState(false);
931
939
  const measuredHeight = usePanelHeight(panelRef, snapHeights.length > 0);
932
940
  const transform = getStackTransform(depth, config.stacking);
933
941
  const panelStyles = getPanelStyles(side, config, index);
942
+ if (!isTop && hasEnteredRef.current) hasEnteredRef.current = false;
934
943
  useEffect(() => {
935
- if (!isTop) hasEnteredRef.current = false;
936
- }, [isTop]);
937
- const handleAnimationComplete = useCallback(() => {
938
- if (isTop && !hasEnteredRef.current) {
939
- hasEnteredRef.current = true;
940
- config.onOpenComplete?.();
941
- }
942
- }, [isTop, config]);
944
+ onOpenCompleteRef.current = config.onOpenComplete;
945
+ }, [config.onOpenComplete]);
946
+ const handleAnimationComplete = () => {
947
+ completeOpeningAnimation(hasEnteredRef, isTop, onOpenCompleteRef);
948
+ };
943
949
  useDrag(panelRef, {
944
- enabled: isTop && config.drag && config.dismissible && !prefersReducedMotion,
950
+ activeSnapIndex,
945
951
  closeThreshold: config.closeThreshold,
946
- velocityThreshold: config.velocityThreshold,
947
- side,
952
+ enabled: isTop && config.drag && config.dismissible && !prefersReducedMotion,
953
+ isNested,
948
954
  onClose: swipeClose,
949
955
  onPop: swipePop,
950
- isNested,
951
- snapHeights,
952
- activeSnapIndex,
953
956
  onSnap,
954
- sequential: config.snapToSequentialPoints
957
+ sequential: config.snapToSequentialPoints,
958
+ side,
959
+ snapHeights,
960
+ velocityThreshold: config.velocityThreshold
955
961
  }, setDragState);
956
- const ariaLabel = item.ariaLabel ?? (typeof item.data?.__ariaLabel === "string" ? item.data.__ariaLabel : void 0) ?? config.ariaLabel;
962
+ const ariaLabel = getPanelAriaLabel(item, config.ariaLabel);
957
963
  const panelId = `stacksheet-${item.id}`;
958
964
  const [hasDescription, setHasDescription] = useState(false);
959
- const registerDescription = useCallback(() => {
965
+ const registerDescription = () => {
960
966
  setHasDescription(true);
961
967
  return () => setHasDescription(false);
962
- }, []);
963
- const panelContext = useMemo(() => ({
968
+ };
969
+ const panelContext = getPanelContext({
964
970
  close,
965
- back: pop,
966
- isNested,
967
- isTop,
968
- panelId,
969
- side,
970
971
  hasDescription,
971
- registerDescription
972
- }), [
973
- close,
974
- pop,
975
972
  isNested,
976
973
  isTop,
977
974
  panelId,
978
- side,
979
- hasDescription,
980
- registerDescription
981
- ]);
975
+ pop,
976
+ registerDescription,
977
+ side
978
+ });
982
979
  const isComposable = resolvePanelLayout(layout, renderHeader) === "composable";
983
980
  const hasPanelClass = classNames.panel !== "";
984
981
  const dragOffset = getDragTransform(side, dragState.offset);
985
982
  const panelStyle = buildPanelStyle(panelStyles, isTop, hasPanelClass, dragState.isDragging);
986
- const headerProps = useMemo(() => ({
987
- isNested,
988
- onBack: pop,
989
- onClose: close,
990
- side
991
- }), [
983
+ const headerProps = getHeaderProps({
992
984
  close,
993
985
  isNested,
994
986
  pop,
995
987
  side
996
- ]);
988
+ });
997
989
  const ariaProps = buildAriaProps(isTop, config.modal, isComposable, ariaLabel, panelId, hasDescription);
998
990
  const transition = buildPanelTransition(dragState.isDragging, isTop, spring, stackSpring);
999
991
  const animatedRadius = getAnimatedBorderRadius(side, depth, config.stacking);
@@ -1003,18 +995,28 @@ const SheetPanel = memo(function SheetPanel({ item, index, depth, isTop, isNeste
1003
995
  const initialRadius = getInitialRadius(side);
1004
996
  const showSideHandle = isTop && side !== "bottom";
1005
997
  const showBottomHandle = isTop && side === "bottom";
998
+ const dismiss = isNested ? pop : close;
999
+ const sideHandle = getOptionalSideHandle({
1000
+ isHovered,
1001
+ onDismiss: dismiss,
1002
+ show: showSideHandle,
1003
+ side
1004
+ });
1005
+ const bottomHandle = getOptionalBottomHandle(showBottomHandle, dismiss);
1006
+ const hoverProps = getPanelHoverProps(showSideHandle, setIsHovered);
1007
+ const inactivePanelProps = getInactivePanelProps(isTop);
1006
1008
  const panelContent = /* @__PURE__ */ jsxs(m.div, {
1007
1009
  animate: animateTarget,
1008
1010
  className: classNames.panel || void 0,
1009
1011
  exit: {
1010
1012
  ...resolvedSlideFrom,
1011
- opacity: .6,
1012
1013
  boxShadow: getShadow(false),
1014
+ opacity: .6,
1013
1015
  transition: {
1014
- type: "tween",
1016
+ boxShadow: VISUAL_TWEEN,
1015
1017
  duration: prefersReducedMotion ? 0 : .24,
1016
1018
  ease: "easeOut",
1017
- boxShadow: VISUAL_TWEEN
1019
+ type: "tween"
1018
1020
  }
1019
1021
  },
1020
1022
  initial: {
@@ -1024,25 +1026,15 @@ const SheetPanel = memo(function SheetPanel({ item, index, depth, isTop, isNeste
1024
1026
  boxShadow: getShadow(false)
1025
1027
  },
1026
1028
  onAnimationComplete: handleAnimationComplete,
1027
- onBlur: showSideHandle ? () => setIsHovered(false) : void 0,
1028
- onFocus: showSideHandle ? () => setIsHovered(true) : void 0,
1029
- onMouseEnter: showSideHandle ? () => setIsHovered(true) : void 0,
1030
- onMouseLeave: showSideHandle ? () => setIsHovered(false) : void 0,
1031
1029
  ref: panelRef,
1032
1030
  style: panelStyle,
1033
1031
  tabIndex: isTop ? -1 : void 0,
1034
- ...isTop ? {} : {
1035
- "aria-hidden": "true",
1036
- inert: true
1037
- },
1032
+ ...hoverProps,
1033
+ ...inactivePanelProps,
1038
1034
  ...ariaProps,
1039
- children: [showSideHandle && /* @__PURE__ */ jsx(SideHandle, {
1040
- isHovered,
1041
- onDismiss: isNested ? pop : close,
1042
- side
1043
- }), /* @__PURE__ */ jsxs("div", {
1035
+ children: [sideHandle, /* @__PURE__ */ jsxs("div", {
1044
1036
  className: "relative flex min-h-0 flex-1 flex-col overflow-hidden rounded-[inherit]",
1045
- children: [showBottomHandle && /* @__PURE__ */ jsx(BottomHandle, { onDismiss: isNested ? pop : close }), /* @__PURE__ */ jsx(PanelInnerContent, {
1037
+ children: [bottomHandle, /* @__PURE__ */ jsx(PanelInnerContent, {
1046
1038
  Content,
1047
1039
  data: item.data,
1048
1040
  headerClassName: classNames.header || void 0,
@@ -1062,9 +1054,31 @@ const SheetPanel = memo(function SheetPanel({ item, index, depth, isTop, isNeste
1062
1054
  children: panelContent
1063
1055
  })
1064
1056
  });
1065
- });
1057
+ };
1066
1058
  //#endregion
1067
1059
  //#region src/renderer.tsx
1060
+ const handleBackdropExitComplete = () => {
1061
+ requestAnimationFrame(() => {
1062
+ document.body.offsetHeight;
1063
+ });
1064
+ };
1065
+ const getResolvedSnapHeights = (side, snapPoints, viewportHeight) => side === "bottom" && snapPoints.length > 0 ? resolveSnapPoints(snapPoints, viewportHeight) : [];
1066
+ const getActiveInternalSnapIndex = ({ defaultSnapIndex, internalSnap, snapContext, snapHeights }) => internalSnap.context === snapContext && internalSnap.snapCount === snapHeights.length ? internalSnap.index : defaultSnapIndex;
1067
+ const getMotionSpring = (prefersReducedMotion, config) => prefersReducedMotion ? {
1068
+ duration: 0,
1069
+ type: "tween"
1070
+ } : {
1071
+ damping: config.spring.damping,
1072
+ mass: config.spring.mass,
1073
+ stiffness: config.spring.stiffness,
1074
+ type: "spring"
1075
+ };
1076
+ const getBackdropStyle = (config, hasBackdropClass) => ({
1077
+ cursor: config.closeOnBackdrop && config.dismissible ? "pointer" : void 0,
1078
+ willChange: "opacity",
1079
+ zIndex: config.zIndex,
1080
+ ...hasBackdropClass ? {} : { background: "var(--overlay, rgba(0, 0, 0, 0.15))" }
1081
+ });
1068
1082
  /**
1069
1083
  * Root renderer component — manages the backdrop, scroll lock, snap points,
1070
1084
  * close reasons, focus restoration, keyboard/CloseWatcher dismissal, and
@@ -1072,20 +1086,16 @@ const SheetPanel = memo(function SheetPanel({ item, index, depth, isTop, isNeste
1072
1086
  *
1073
1087
  * Mounted inside a Portal by `StacksheetProvider`.
1074
1088
  */
1075
- function SheetRenderer({ store, config, sheets, componentMap, classNames: classNamesProp, layout, renderHeader }) {
1089
+ const SheetRenderer = ({ store, config, sheets, componentMap, classNames: classNamesProp, layout, renderHeader }) => {
1076
1090
  const isOpen = useStore(store, (s) => s.isOpen);
1077
1091
  const stack = useStore(store, (s) => s.stack);
1078
1092
  const rawClose = useStore(store, (s) => s.close);
1079
1093
  const rawPop = useStore(store, (s) => s.pop);
1080
1094
  const side = useResolvedSide(config);
1081
1095
  const prefersReducedMotion = useReducedMotion() ?? false;
1082
- const classNames = useMemo(() => resolveClassNames(classNamesProp), [classNamesProp]);
1096
+ const classNames = resolveClassNames(classNamesProp);
1083
1097
  const viewportHeight = useViewportHeight(isOpen && side === "bottom" && config.snapPoints.length > 0);
1084
- const snapHeights = useMemo(() => side === "bottom" && config.snapPoints.length > 0 ? resolveSnapPoints(config.snapPoints, viewportHeight) : [], [
1085
- side,
1086
- config.snapPoints,
1087
- viewportHeight
1088
- ]);
1098
+ const snapHeights = getResolvedSnapHeights(side, config.snapPoints, viewportHeight);
1089
1099
  const snapContext = isOpen ? stack.map((item) => item.id).join("\0") : "";
1090
1100
  const defaultSnapIndex = snapHeights.length > 0 ? snapHeights.length - 1 : 0;
1091
1101
  const [internalSnap, setInternalSnap] = useState({
@@ -1093,31 +1103,32 @@ function SheetRenderer({ store, config, sheets, componentMap, classNames: classN
1093
1103
  index: defaultSnapIndex,
1094
1104
  snapCount: snapHeights.length
1095
1105
  });
1096
- const internalSnapIndex = internalSnap.context === snapContext && internalSnap.snapCount === snapHeights.length ? internalSnap.index : defaultSnapIndex;
1106
+ const internalSnapIndex = getActiveInternalSnapIndex({
1107
+ defaultSnapIndex,
1108
+ internalSnap,
1109
+ snapContext,
1110
+ snapHeights
1111
+ });
1097
1112
  const activeSnapIndex = config.snapPointIndex ?? internalSnapIndex;
1098
- const handleSnap = useCallback((index) => {
1113
+ const handleSnap = (index) => {
1099
1114
  setInternalSnap({
1100
1115
  context: snapContext,
1101
1116
  index,
1102
1117
  snapCount: snapHeights.length
1103
1118
  });
1104
1119
  config.onSnapPointChange?.(index);
1105
- }, [
1106
- config,
1107
- snapContext,
1108
- snapHeights.length
1109
- ]);
1120
+ };
1110
1121
  const closeReasonRef = useRef("programmatic");
1111
- const closeWith = useCallback((reason) => {
1122
+ const closeWith = (reason) => {
1112
1123
  closeReasonRef.current = reason;
1113
1124
  rawClose();
1114
- }, [rawClose]);
1115
- const popWith = useCallback((reason) => {
1125
+ };
1126
+ const popWith = (reason) => {
1116
1127
  closeReasonRef.current = reason;
1117
1128
  rawPop();
1118
- }, [rawPop]);
1119
- const close = useCallback(() => closeWith("programmatic"), [closeWith]);
1120
- const pop = useCallback(() => popWith("programmatic"), [popWith]);
1129
+ };
1130
+ const close = () => closeWith("programmatic");
1131
+ const pop = () => popWith("programmatic");
1121
1132
  useBodyScale(config, isOpen, prefersReducedMotion);
1122
1133
  const triggerRef = useRef(null);
1123
1134
  const wasOpenRef = useRef(false);
@@ -1136,72 +1147,62 @@ function SheetRenderer({ store, config, sheets, componentMap, classNames: classN
1136
1147
  }, [stack.length]);
1137
1148
  useEffect(() => {
1138
1149
  if (!(isOpen && config.closeOnEscape && config.dismissible)) return;
1139
- function handleKeyDown(e) {
1150
+ const handleKeyDown = (e) => {
1140
1151
  if (e.key === "Escape") {
1141
1152
  e.preventDefault();
1142
- if (stackLengthRef.current > 1) popWith("escape");
1143
- else closeWith("escape");
1153
+ if (stackLengthRef.current > 1) {
1154
+ closeReasonRef.current = "escape";
1155
+ rawPop();
1156
+ } else {
1157
+ closeReasonRef.current = "escape";
1158
+ rawClose();
1159
+ }
1144
1160
  }
1145
- }
1161
+ };
1146
1162
  document.addEventListener("keydown", handleKeyDown);
1147
1163
  return () => document.removeEventListener("keydown", handleKeyDown);
1148
1164
  }, [
1149
1165
  isOpen,
1150
1166
  config.closeOnEscape,
1151
1167
  config.dismissible,
1152
- popWith,
1153
- closeWith
1168
+ rawPop,
1169
+ rawClose
1154
1170
  ]);
1155
1171
  useEffect(() => {
1156
- if (!(isOpen && config.dismissible) || typeof globalThis.CloseWatcher === "undefined") return;
1172
+ if (!(isOpen && config.dismissible) || globalThis.CloseWatcher === void 0) return;
1157
1173
  const watcher = new globalThis.CloseWatcher();
1158
- watcher.onclose = () => {
1159
- if (stackLengthRef.current > 1) popWith("escape");
1160
- else closeWith("escape");
1174
+ const handleClose = () => {
1175
+ if (stackLengthRef.current > 1) {
1176
+ closeReasonRef.current = "escape";
1177
+ rawPop();
1178
+ } else {
1179
+ closeReasonRef.current = "escape";
1180
+ rawClose();
1181
+ }
1182
+ };
1183
+ watcher.addEventListener("close", handleClose);
1184
+ return () => {
1185
+ watcher.removeEventListener("close", handleClose);
1186
+ watcher.destroy();
1161
1187
  };
1162
- return () => watcher.destroy();
1163
1188
  }, [
1164
1189
  isOpen,
1165
1190
  config.dismissible,
1166
- popWith,
1167
- closeWith
1168
- ]);
1169
- const slideFrom = useMemo(() => getSlideFrom(side), [side]);
1170
- const slideTarget = useMemo(() => getSlideTarget(), []);
1171
- const spring = useMemo(() => prefersReducedMotion ? {
1172
- type: "tween",
1173
- duration: 0
1174
- } : {
1175
- type: "spring",
1176
- damping: config.spring.damping,
1177
- stiffness: config.spring.stiffness,
1178
- mass: config.spring.mass
1179
- }, [
1180
- prefersReducedMotion,
1181
- config.spring.damping,
1182
- config.spring.stiffness,
1183
- config.spring.mass
1191
+ rawPop,
1192
+ rawClose
1184
1193
  ]);
1194
+ const slideFrom = getSlideFrom(side);
1195
+ const slideTarget = getSlideTarget();
1196
+ const spring = getMotionSpring(prefersReducedMotion, config);
1185
1197
  const stackSpring = spring;
1186
1198
  const isModal = config.modal;
1187
1199
  const showOverlay = isModal && config.showOverlay;
1188
- const hasBackdropClass = classNames.backdrop !== "";
1189
- const backdropStyle = {
1190
- zIndex: config.zIndex,
1191
- willChange: "opacity",
1192
- cursor: config.closeOnBackdrop && config.dismissible ? "pointer" : void 0,
1193
- ...hasBackdropClass ? {} : { background: "var(--overlay, rgba(0, 0, 0, 0.15))" }
1194
- };
1195
- const handleExitComplete = useCallback(() => {
1200
+ const backdropStyle = getBackdropStyle(config, classNames.backdrop !== "");
1201
+ const handleExitComplete = () => {
1196
1202
  if (stack.length === 0) config.onCloseComplete?.(closeReasonRef.current);
1197
- }, [stack.length, config]);
1198
- const handleBackdropExitComplete = useCallback(() => {
1199
- requestAnimationFrame(() => {
1200
- document.body.offsetHeight;
1201
- });
1202
- }, []);
1203
- const swipeClose = useCallback(() => closeWith("swipe"), [closeWith]);
1204
- const swipePop = useCallback(() => popWith("swipe"), [popWith]);
1203
+ };
1204
+ const swipeClose = () => closeWith("swipe");
1205
+ const swipePop = () => popWith("swipe");
1205
1206
  const shouldLockScroll = isOpen && isModal && config.lockScroll;
1206
1207
  return /* @__PURE__ */ jsxs(LazyMotion, {
1207
1208
  features: domMax,
@@ -1260,22 +1261,22 @@ function SheetRenderer({ store, config, sheets, componentMap, classNames: classN
1260
1261
  })
1261
1262
  })]
1262
1263
  });
1263
- }
1264
+ };
1264
1265
  //#endregion
1265
- //#region src/Store/StoreArgs.ts
1266
- function resolvePresentationOptions(value) {
1266
+ //#region src/Store/store-args.ts
1267
+ const resolvePresentationOptions = (value) => {
1267
1268
  if (!(value && typeof value === "object")) return;
1268
1269
  const candidate = value;
1269
1270
  if (candidate.ariaLabel !== void 0 && typeof candidate.ariaLabel !== "string") return;
1270
1271
  return candidate;
1271
- }
1272
+ };
1272
1273
  /**
1273
1274
  * Dev-mode warning: detect likely inline arrow functions passed as ad-hoc components.
1274
1275
  * When a new component reference has the same displayName/name as an existing one,
1275
1276
  * it's almost always an inline arrow being re-created every render.
1276
1277
  */
1277
- function warnInlineComponent(component, componentRegistry, warnedNames) {
1278
- if (typeof process === "undefined" || process?.env?.NODE_ENV === "production") return;
1278
+ const warnInlineComponent = (component, componentRegistry, warnedNames) => {
1279
+ if (process === void 0 || process?.env?.NODE_ENV === "production") return;
1279
1280
  const name = component.displayName || component.name;
1280
1281
  if (!name) return;
1281
1282
  if (warnedNames.has(name)) return;
@@ -1284,12 +1285,12 @@ function warnInlineComponent(component, componentRegistry, warnedNames) {
1284
1285
  console.warn(`[stacksheet] A new component reference with name "${name}" was registered (key: ${key}), but a different reference with the same name already exists. This usually means you're passing an inline arrow function (e.g. open(() => <MySheet />)). Define the component outside of render to avoid memory leaks and broken navigate() same-type detection.`);
1285
1286
  return;
1286
1287
  }
1287
- }
1288
+ };
1288
1289
  /**
1289
1290
  * If `first` is a function (component), register it and return { type, id, data }.
1290
1291
  * Otherwise, pass through the string-based (type, id, data) args unchanged.
1291
1292
  */
1292
- function resolveArgs(componentRegistry, componentMap, getNextKey, warnedNames, first, second, third, fourth) {
1293
+ const resolveArgs = (componentRegistry, componentMap, getNextKey, warnedNames, first, second, third, fourth) => {
1293
1294
  if (typeof first === "function") {
1294
1295
  const component = first;
1295
1296
  let typeKey = componentRegistry.get(component);
@@ -1301,26 +1302,26 @@ function resolveArgs(componentRegistry, componentMap, getNextKey, warnedNames, f
1301
1302
  }
1302
1303
  if (typeof second === "string") return {
1303
1304
  ariaLabel: resolvePresentationOptions(fourth)?.ariaLabel,
1304
- type: typeKey,
1305
+ data: third ?? {},
1305
1306
  id: second,
1306
- data: third ?? {}
1307
+ type: typeKey
1307
1308
  };
1308
1309
  return {
1309
1310
  ariaLabel: resolvePresentationOptions(third)?.ariaLabel,
1310
- type: typeKey,
1311
+ data: second ?? {},
1311
1312
  id: crypto.randomUUID(),
1312
- data: second ?? {}
1313
+ type: typeKey
1313
1314
  };
1314
1315
  }
1315
1316
  return {
1316
1317
  ariaLabel: resolvePresentationOptions(fourth)?.ariaLabel,
1317
- type: first,
1318
+ data: third ?? {},
1318
1319
  id: second,
1319
- data: third ?? {}
1320
+ type: first
1320
1321
  };
1321
- }
1322
+ };
1322
1323
  //#endregion
1323
- //#region src/Store/createSheetStore.ts
1324
+ //#region src/Store/create-sheet-store.ts
1324
1325
  /**
1325
1326
  * Create an isolated Zustand store for a sheet stack instance.
1326
1327
  *
@@ -1332,119 +1333,86 @@ function resolveArgs(componentRegistry, componentMap, getNextKey, warnedNames, f
1332
1333
  * The ad-hoc counter is scoped per instance to prevent identity leaks across
1333
1334
  * multiple `createStacksheet()` calls or test runs.
1334
1335
  */
1335
- function createSheetStore(config) {
1336
+ const createSheetStore = (config) => {
1336
1337
  const componentRegistry = /* @__PURE__ */ new Map();
1337
1338
  const componentMap = /* @__PURE__ */ new Map();
1338
1339
  let adhocCounter = 0;
1339
- function getNextKey() {
1340
- return `__adhoc_${adhocCounter++}`;
1341
- }
1340
+ const getNextKey = () => {
1341
+ const key = `__adhoc_${adhocCounter}`;
1342
+ adhocCounter += 1;
1343
+ return key;
1344
+ };
1342
1345
  const warnedNames = /* @__PURE__ */ new Set();
1343
- function resolve(first, second, third, fourth) {
1344
- return resolveArgs(componentRegistry, componentMap, getNextKey, warnedNames, first, second, third, fourth);
1345
- }
1346
+ const resolve = (first, second, third, fourth) => resolveArgs(componentRegistry, componentMap, getNextKey, warnedNames, first, second, third, fourth);
1346
1347
  /** Remove registry entries for type keys no longer in the stack */
1347
- function pruneRegistry(remainingStack) {
1348
+ const pruneRegistry = (remainingStack) => {
1348
1349
  const usedTypes = new Set(remainingStack.map((item) => item.type));
1349
1350
  for (const [component, typeKey] of componentRegistry) if (!usedTypes.has(typeKey)) {
1350
1351
  componentRegistry.delete(component);
1351
1352
  componentMap.delete(typeKey);
1352
1353
  }
1353
- }
1354
+ };
1354
1355
  return {
1356
+ componentMap,
1357
+ componentRegistry,
1355
1358
  store: createStore()((set, get) => {
1356
- function _openResolved({ type, id, data, ariaLabel }) {
1359
+ const _openResolved = ({ type, id, data, ariaLabel }) => {
1357
1360
  set({
1361
+ isOpen: true,
1358
1362
  stack: [{
1359
- id,
1360
- type,
1363
+ ariaLabel,
1361
1364
  data,
1362
- ariaLabel
1363
- }],
1364
- isOpen: true
1365
+ id,
1366
+ type
1367
+ }]
1365
1368
  });
1366
- }
1367
- function _pushResolved({ type, id, data, ariaLabel }) {
1369
+ };
1370
+ const _pushResolved = ({ type, id, data, ariaLabel }) => {
1368
1371
  set((state) => {
1369
1372
  const item = {
1370
- id,
1371
- type,
1373
+ ariaLabel,
1372
1374
  data,
1373
- ariaLabel
1375
+ id,
1376
+ type
1374
1377
  };
1375
1378
  if (Number.isFinite(config.maxDepth) && state.stack.length >= config.maxDepth) return {
1376
- stack: [...state.stack.slice(0, -1), item],
1377
- isOpen: true
1379
+ isOpen: true,
1380
+ stack: [...state.stack.slice(0, -1), item]
1378
1381
  };
1379
1382
  return {
1380
- stack: [...state.stack, item],
1381
- isOpen: true
1383
+ isOpen: true,
1384
+ stack: [...state.stack, item]
1382
1385
  };
1383
1386
  });
1384
- }
1385
- function _replaceResolved({ type, id, data, ariaLabel }) {
1387
+ };
1388
+ const _replaceResolved = ({ type, id, data, ariaLabel }) => {
1386
1389
  set((state) => {
1387
1390
  const item = {
1388
- id,
1389
- type,
1391
+ ariaLabel,
1390
1392
  data,
1391
- ariaLabel
1393
+ id,
1394
+ type
1392
1395
  };
1393
1396
  if (state.stack.length === 0) return {
1394
- stack: [item],
1395
- isOpen: true
1397
+ isOpen: true,
1398
+ stack: [item]
1396
1399
  };
1397
1400
  return {
1398
- stack: [...state.stack.slice(0, -1), item],
1399
- isOpen: true
1401
+ isOpen: true,
1402
+ stack: [...state.stack.slice(0, -1), item]
1400
1403
  };
1401
1404
  });
1402
- }
1405
+ };
1403
1406
  return {
1404
- stack: [],
1405
- isOpen: false,
1406
- open(first, second, third, fourth) {
1407
- _openResolved(resolve(first, second, third, fourth));
1408
- },
1409
- push(first, second, third, fourth) {
1410
- _pushResolved(resolve(first, second, third, fourth));
1411
- },
1412
- replace(first, second, third, fourth) {
1413
- _replaceResolved(resolve(first, second, third, fourth));
1414
- },
1415
- swap(first, second, third) {
1416
- let type;
1417
- let data;
1418
- const ariaLabel = resolvePresentationOptions(third)?.ariaLabel;
1419
- if (typeof first === "function") {
1420
- const component = first;
1421
- let typeKey = componentRegistry.get(component);
1422
- if (!typeKey) {
1423
- warnInlineComponent(component, componentRegistry, warnedNames);
1424
- typeKey = getNextKey();
1425
- componentRegistry.set(component, typeKey);
1426
- componentMap.set(typeKey, component);
1427
- }
1428
- type = typeKey;
1429
- data = second ?? {};
1430
- } else {
1431
- type = first;
1432
- data = second ?? {};
1433
- }
1434
- set((state) => {
1435
- const top = state.stack.at(-1);
1436
- if (!top) return state;
1437
- const newStack = [...state.stack];
1438
- newStack[newStack.length - 1] = {
1439
- id: top.id,
1440
- type,
1441
- data,
1442
- ariaLabel: ariaLabel ?? top.ariaLabel
1443
- };
1444
- return { stack: newStack };
1407
+ close: () => {
1408
+ pruneRegistry([]);
1409
+ set({
1410
+ isOpen: false,
1411
+ stack: []
1445
1412
  });
1446
1413
  },
1447
- navigate(first, second, third, fourth) {
1414
+ isOpen: false,
1415
+ navigate: (first, second, third, fourth) => {
1448
1416
  const resolved = resolve(first, second, third, fourth);
1449
1417
  const { stack } = get();
1450
1418
  const top = stack.at(-1);
@@ -1460,61 +1428,94 @@ function createSheetStore(config) {
1460
1428
  }
1461
1429
  _pushResolved(resolved);
1462
1430
  },
1463
- setData(first, second, third) {
1464
- const { id, data } = resolve(first, second, third);
1431
+ open: (first, second, third, fourth) => {
1432
+ _openResolved(resolve(first, second, third, fourth));
1433
+ },
1434
+ pop: () => {
1465
1435
  set((state) => {
1466
- const idx = state.stack.findIndex((item) => item.id === id);
1467
- if (idx === -1) return state;
1468
- const updated = [...state.stack];
1469
- updated[idx] = {
1470
- ...updated[idx],
1471
- data
1436
+ if (state.stack.length <= 1) {
1437
+ pruneRegistry([]);
1438
+ return {
1439
+ isOpen: false,
1440
+ stack: []
1441
+ };
1442
+ }
1443
+ const next = state.stack.slice(0, -1);
1444
+ pruneRegistry(next);
1445
+ return {
1446
+ isOpen: true,
1447
+ stack: next
1472
1448
  };
1473
- return { stack: updated };
1474
1449
  });
1475
1450
  },
1476
- remove(id) {
1451
+ push: (first, second, third, fourth) => {
1452
+ _pushResolved(resolve(first, second, third, fourth));
1453
+ },
1454
+ remove: (id) => {
1477
1455
  set((state) => {
1478
1456
  const next = state.stack.filter((item) => item.id !== id);
1479
1457
  if (next.length === state.stack.length) return state;
1480
1458
  pruneRegistry(next);
1481
1459
  if (next.length === 0) return {
1482
- stack: [],
1483
- isOpen: false
1460
+ isOpen: false,
1461
+ stack: []
1484
1462
  };
1485
1463
  return { stack: next };
1486
1464
  });
1487
1465
  },
1488
- pop() {
1466
+ replace: (first, second, third, fourth) => {
1467
+ _replaceResolved(resolve(first, second, third, fourth));
1468
+ },
1469
+ setData: (first, second, third) => {
1470
+ const { id, data } = resolve(first, second, third);
1489
1471
  set((state) => {
1490
- if (state.stack.length <= 1) {
1491
- pruneRegistry([]);
1492
- return {
1493
- stack: [],
1494
- isOpen: false
1495
- };
1496
- }
1497
- const next = state.stack.slice(0, -1);
1498
- pruneRegistry(next);
1499
- return {
1500
- stack: next,
1501
- isOpen: true
1472
+ const idx = state.stack.findIndex((item) => item.id === id);
1473
+ if (idx === -1) return state;
1474
+ const updated = [...state.stack];
1475
+ updated[idx] = {
1476
+ ...updated[idx],
1477
+ data
1502
1478
  };
1479
+ return { stack: updated };
1503
1480
  });
1504
1481
  },
1505
- close() {
1506
- pruneRegistry([]);
1507
- set({
1508
- stack: [],
1509
- isOpen: false
1482
+ stack: [],
1483
+ swap: (first, second, third) => {
1484
+ let type;
1485
+ let data;
1486
+ const ariaLabel = resolvePresentationOptions(third)?.ariaLabel;
1487
+ if (typeof first === "function") {
1488
+ const component = first;
1489
+ let typeKey = componentRegistry.get(component);
1490
+ if (!typeKey) {
1491
+ warnInlineComponent(component, componentRegistry, warnedNames);
1492
+ typeKey = getNextKey();
1493
+ componentRegistry.set(component, typeKey);
1494
+ componentMap.set(typeKey, component);
1495
+ }
1496
+ type = typeKey;
1497
+ data = second ?? {};
1498
+ } else {
1499
+ type = first;
1500
+ data = second ?? {};
1501
+ }
1502
+ set((state) => {
1503
+ const top = state.stack.at(-1);
1504
+ if (!top) return state;
1505
+ const newStack = [...state.stack];
1506
+ newStack[newStack.length - 1] = {
1507
+ ariaLabel: ariaLabel ?? top.ariaLabel,
1508
+ data,
1509
+ id: top.id,
1510
+ type
1511
+ };
1512
+ return { stack: newStack };
1510
1513
  });
1511
1514
  }
1512
1515
  };
1513
- }),
1514
- componentRegistry,
1515
- componentMap
1516
+ })
1516
1517
  };
1517
- }
1518
+ };
1518
1519
  //#endregion
1519
1520
  //#region src/create.tsx
1520
1521
  /**
@@ -1547,71 +1548,67 @@ function createSheetStore(config) {
1547
1548
  *
1548
1549
  * Use `useSheetPanel()` inside content components to access `close()` and `back()`.
1549
1550
  */
1550
- function createStacksheet(config) {
1551
+ const createStacksheet = (config) => {
1551
1552
  const resolved = resolveConfig(config);
1552
1553
  const { store, componentMap } = createSheetStore(resolved);
1553
1554
  const StoreContext = createContext(null);
1554
- function useStoreContext() {
1555
- const ctx = useContext(StoreContext);
1555
+ const useStoreContext = () => {
1556
+ const ctx = use(StoreContext);
1556
1557
  if (!ctx) throw new Error("useSheet/useStacksheetState must be used within <StacksheetProvider>");
1557
1558
  return ctx;
1558
- }
1559
+ };
1559
1560
  const EMPTY_SHEETS = {};
1560
- function StacksheetProvider({ sheets = EMPTY_SHEETS, children, classNames, layout, renderHeader }) {
1561
- const value = useMemo(() => ({
1562
- store,
1563
- config: resolved
1564
- }), []);
1565
- return /* @__PURE__ */ jsxs(StoreContext.Provider, {
1566
- value,
1567
- children: [children, /* @__PURE__ */ jsx(Portal, {
1568
- asChild: false,
1569
- children: /* @__PURE__ */ jsx(SheetRenderer, {
1570
- classNames,
1571
- componentMap,
1572
- config: resolved,
1573
- layout,
1574
- renderHeader,
1575
- sheets,
1576
- store
1577
- })
1578
- })]
1579
- });
1580
- }
1581
- function useSheet() {
1561
+ const providerValue = {
1562
+ config: resolved,
1563
+ store
1564
+ };
1565
+ const StacksheetProvider = ({ sheets = EMPTY_SHEETS, children, classNames, layout, renderHeader }) => /* @__PURE__ */ jsxs(StoreContext.Provider, {
1566
+ value: providerValue,
1567
+ children: [children, /* @__PURE__ */ jsx(Portal, {
1568
+ asChild: false,
1569
+ children: /* @__PURE__ */ jsx(SheetRenderer, {
1570
+ classNames,
1571
+ componentMap,
1572
+ config: resolved,
1573
+ layout,
1574
+ renderHeader,
1575
+ sheets,
1576
+ store
1577
+ })
1578
+ })]
1579
+ });
1580
+ const useSheet = () => {
1582
1581
  const { store: s } = useStoreContext();
1583
- return useMemo(() => {
1584
- const state = s.getState();
1585
- return {
1586
- open: state.open,
1587
- push: state.push,
1588
- replace: state.replace,
1589
- swap: state.swap,
1590
- navigate: state.navigate,
1591
- setData: state.setData,
1592
- remove: state.remove,
1593
- pop: state.pop,
1594
- close: state.close
1595
- };
1596
- }, [s]);
1597
- }
1598
- function useStacksheetState() {
1582
+ const state = s.getState();
1583
+ return {
1584
+ close: state.close,
1585
+ navigate: state.navigate,
1586
+ open: state.open,
1587
+ pop: state.pop,
1588
+ push: state.push,
1589
+ remove: state.remove,
1590
+ replace: state.replace,
1591
+ setData: state.setData,
1592
+ swap: state.swap
1593
+ };
1594
+ };
1595
+ const useStacksheetState = () => {
1599
1596
  const { store: s } = useStoreContext();
1600
1597
  return useStore(s, useShallow((state) => ({
1601
- stack: state.stack,
1602
- isOpen: state.isOpen
1598
+ isOpen: state.isOpen,
1599
+ stack: state.stack
1603
1600
  })));
1604
- }
1601
+ };
1605
1602
  return {
1606
1603
  StacksheetProvider,
1604
+ store,
1607
1605
  useSheet,
1608
- useStacksheetState,
1609
- store
1606
+ useStacksheetState
1610
1607
  };
1611
- }
1608
+ };
1612
1609
  //#endregion
1613
- //#region src/SheetParts/SheetBack.tsx
1614
- function SheetBack({ asChild, className, style, children }) {
1610
+ //#region src/SheetParts/sheet-back.tsx
1611
+ const SheetBack = ({ asChild, className, style, children }) => {
1615
1612
  const { back, isNested } = useSheetPanel();
1616
1613
  if (!isNested) return null;
1617
1614
  return /* @__PURE__ */ jsx(asChild ? Slot : "button", {
@@ -1622,10 +1619,10 @@ function SheetBack({ asChild, className, style, children }) {
1622
1619
  type: asChild ? void 0 : "button",
1623
1620
  children: children ?? /* @__PURE__ */ jsx(ArrowLeftIcon, {})
1624
1621
  });
1625
- }
1622
+ };
1626
1623
  //#endregion
1627
- //#region src/SheetParts/SheetBody.tsx
1628
- function SheetBody({ asChild, className, style, children }) {
1624
+ //#region src/SheetParts/sheet-body.tsx
1625
+ const SheetBody = ({ asChild, className, style, children }) => {
1629
1626
  if (asChild) return /* @__PURE__ */ jsx(Slot, {
1630
1627
  className: joinClassNames("relative min-h-0 flex-1", className),
1631
1628
  "data-stacksheet-no-drag": "",
@@ -1645,10 +1642,10 @@ function SheetBody({ asChild, className, style, children }) {
1645
1642
  children: /* @__PURE__ */ jsx(Thumb, { className: "relative flex-1 rounded bg-current/15" })
1646
1643
  })]
1647
1644
  });
1648
- }
1645
+ };
1649
1646
  //#endregion
1650
- //#region src/SheetParts/SheetClose.tsx
1651
- function SheetClose({ asChild, className, style, children }) {
1647
+ //#region src/SheetParts/sheet-close.tsx
1648
+ const SheetClose = ({ asChild, className, style, children }) => {
1652
1649
  const { close } = useSheetPanel();
1653
1650
  return /* @__PURE__ */ jsx(asChild ? Slot : "button", {
1654
1651
  "aria-label": children ? void 0 : "Close",
@@ -1658,10 +1655,10 @@ function SheetClose({ asChild, className, style, children }) {
1658
1655
  type: asChild ? void 0 : "button",
1659
1656
  children: children ?? /* @__PURE__ */ jsx(XIcon, {})
1660
1657
  });
1661
- }
1658
+ };
1662
1659
  //#endregion
1663
- //#region src/SheetParts/SheetDescription.tsx
1664
- function SheetDescription({ asChild, className, style, children }) {
1660
+ //#region src/SheetParts/sheet-description.tsx
1661
+ const SheetDescription = ({ asChild, className, style, children }) => {
1665
1662
  const { panelId, registerDescription } = useSheetPanel();
1666
1663
  useEffect(() => registerDescription(), [registerDescription]);
1667
1664
  return /* @__PURE__ */ jsx(asChild ? Slot : "p", {
@@ -1670,53 +1667,46 @@ function SheetDescription({ asChild, className, style, children }) {
1670
1667
  style,
1671
1668
  children
1672
1669
  });
1673
- }
1670
+ };
1674
1671
  //#endregion
1675
- //#region src/SheetParts/SheetFooter.tsx
1676
- function SheetFooter({ asChild, className, style, children }) {
1672
+ //#region src/SheetParts/sheet-footer.tsx
1673
+ const SheetFooter = ({ asChild, className, style, children }) => {
1677
1674
  return /* @__PURE__ */ jsx(asChild ? Slot : "footer", {
1678
1675
  className: joinClassNames(asChild ? "shrink-0" : "flex shrink-0 items-center gap-2 border-t px-6 py-3", className),
1679
1676
  style,
1680
1677
  children
1681
1678
  });
1682
- }
1679
+ };
1683
1680
  //#endregion
1684
- //#region src/SheetParts/SheetHandle.tsx
1685
- function SheetHandle({ asChild, className, style, children }) {
1681
+ //#region src/SheetParts/sheet-handle.tsx
1682
+ const SheetHandle = ({ asChild, className, style, children }) => {
1686
1683
  const { close, back, isNested } = useSheetPanel();
1687
1684
  const dismiss = isNested ? back : close;
1688
- return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
1685
+ return /* @__PURE__ */ jsx(asChild ? Slot : "button", {
1689
1686
  "aria-label": "Dismiss",
1690
- className: joinClassNames(asChild ? void 0 : "flex shrink-0 cursor-grab touch-none items-center justify-center pt-4 pb-1", className),
1687
+ className: joinClassNames(asChild ? void 0 : "flex shrink-0 cursor-grab touch-none items-center justify-center border-none bg-transparent pt-4 pb-1 text-inherit", className),
1691
1688
  "data-stacksheet-handle": "",
1692
1689
  onClick: dismiss,
1693
- onKeyDown: (e) => {
1694
- if (e.key === "Enter" || e.key === " ") {
1695
- e.preventDefault();
1696
- dismiss();
1697
- }
1698
- },
1699
- role: "button",
1700
1690
  style,
1701
- tabIndex: 0,
1691
+ type: asChild ? void 0 : "button",
1702
1692
  children: children ?? /* @__PURE__ */ jsx("div", {
1703
1693
  "aria-hidden": "true",
1704
1694
  className: "h-1 w-9 rounded-sm bg-current/25"
1705
1695
  })
1706
1696
  });
1707
- }
1697
+ };
1708
1698
  //#endregion
1709
- //#region src/SheetParts/SheetHeader.tsx
1710
- function SheetHeader({ asChild, className, style, children }) {
1699
+ //#region src/SheetParts/sheet-header.tsx
1700
+ const SheetHeader = ({ asChild, className, style, children }) => {
1711
1701
  return /* @__PURE__ */ jsx(asChild ? Slot : "header", {
1712
1702
  className: joinClassNames(asChild ? "shrink-0" : "flex h-14 shrink-0 items-center justify-between border-b px-6", className),
1713
1703
  style,
1714
1704
  children
1715
1705
  });
1716
- }
1706
+ };
1717
1707
  //#endregion
1718
- //#region src/SheetParts/SheetTitle.tsx
1719
- function SheetTitle({ asChild, className, style, children }) {
1708
+ //#region src/SheetParts/sheet-title.tsx
1709
+ const SheetTitle = ({ asChild, className, style, children }) => {
1720
1710
  const { panelId } = useSheetPanel();
1721
1711
  return /* @__PURE__ */ jsx(asChild ? Slot : "h2", {
1722
1712
  className: joinClassNames(asChild ? void 0 : "font-semibold text-sm", className),
@@ -1724,9 +1714,9 @@ function SheetTitle({ asChild, className, style, children }) {
1724
1714
  style,
1725
1715
  children
1726
1716
  });
1727
- }
1717
+ };
1728
1718
  //#endregion
1729
- //#region src/SheetParts/SheetParts.ts
1719
+ //#region src/SheetParts/sheet-parts.ts
1730
1720
  /**
1731
1721
  * Composable Sheet Parts for building custom Sheet layouts.
1732
1722
  *