@solid2-aria/vaul 0.0.0-stage → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE.txt +29 -0
- package/README.md +152 -2
- package/VAUL-LICENSE +9 -0
- package/dist/browser/index.d.ts +107 -0
- package/dist/browser/index.js +1004 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/server/index.js +1058 -0
- package/dist/server/index.js.map +1 -0
- package/dist/style.css +216 -0
- package/docs/api.md +76 -0
- package/package.json +75 -4
|
@@ -0,0 +1,1004 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Derived from Vaul (https://github.com/emilkowalski/vaul), src/.
|
|
3
|
+
* Copyright (c) 2023 Emil Kowalski
|
|
4
|
+
* Modified for Solid Aria: native Solid 2 rendering, state, events, and lifecycle.
|
|
5
|
+
* MIT licensed. See LICENSE, VAUL-LICENSE, and NOTICE.txt in the package root.
|
|
6
|
+
*/
|
|
7
|
+
import { Portal as Portal$1, createComponent, getNextElement, insert, memo, ref, runHydrationEvents, scope, spread, template } from "@solidjs/web";
|
|
8
|
+
import { FocusScope } from "@solid2-aria/core/focus/focus-scope";
|
|
9
|
+
import { Show, createContext, createEffect, createMemo, createSignal, createUniqueId, merge, omit, onSettled, untrack, useContext } from "solid-js";
|
|
10
|
+
import { ariaHideOutside } from "@solid2-aria/core/overlays/aria-hide-outside";
|
|
11
|
+
import { createPreventScroll } from "@solid2-aria/core/overlays/create-prevent-scroll";
|
|
12
|
+
// src/context.ts
|
|
13
|
+
const DrawerContext = createContext();
|
|
14
|
+
const PortalContext = createContext(false);
|
|
15
|
+
// src/constants.ts
|
|
16
|
+
const TRANSITIONS = {
|
|
17
|
+
DURATION: .5,
|
|
18
|
+
EASE: [
|
|
19
|
+
.32,
|
|
20
|
+
.72,
|
|
21
|
+
0,
|
|
22
|
+
1
|
|
23
|
+
]
|
|
24
|
+
};
|
|
25
|
+
const DRAG_CLASS = "vaul-dragging";
|
|
26
|
+
// src/helpers.ts
|
|
27
|
+
function isVertical(direction) {
|
|
28
|
+
return direction === "top" || direction === "bottom";
|
|
29
|
+
}
|
|
30
|
+
function directionSign(direction) {
|
|
31
|
+
return direction === "bottom" || direction === "right" ? 1 : -1;
|
|
32
|
+
}
|
|
33
|
+
function translate(distance, direction) {
|
|
34
|
+
return isVertical(direction) ? `translate3d(0, ${distance}px, 0)` : `translate3d(${distance}px, 0, 0)`;
|
|
35
|
+
}
|
|
36
|
+
function dampenValue(value) {
|
|
37
|
+
return Math.max(0, 8 * (Math.log(value + 1) - 2));
|
|
38
|
+
}
|
|
39
|
+
function clamp(value, min = 0, max = 1) {
|
|
40
|
+
return Math.min(max, Math.max(min, value));
|
|
41
|
+
}
|
|
42
|
+
/** Restore only the properties this operation owns, including priorities. */
|
|
43
|
+
function assignStyle(element, styles) {
|
|
44
|
+
const previous = Object.keys(styles).map((property) => ({
|
|
45
|
+
priority: element.style.getPropertyPriority(property),
|
|
46
|
+
property,
|
|
47
|
+
value: element.style.getPropertyValue(property)
|
|
48
|
+
}));
|
|
49
|
+
for (const [property, value] of Object.entries(styles)) element.style.setProperty(property, value);
|
|
50
|
+
return () => {
|
|
51
|
+
for (const { property, value, priority } of previous) if (value) element.style.setProperty(property, value, priority);
|
|
52
|
+
else element.style.removeProperty(property);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function isSafari(view) {
|
|
56
|
+
return /^(?:(?!chrome|android).)*safari/iu.test(view.navigator.userAgent);
|
|
57
|
+
}
|
|
58
|
+
function canScroll(target, content, direction, distance) {
|
|
59
|
+
const vertical = isVertical(direction);
|
|
60
|
+
const forward = distance * directionSign(direction) < 0;
|
|
61
|
+
for (let node = target; node && content.contains(node); node = node.parentElement) {
|
|
62
|
+
const scrollSize = vertical ? node.scrollHeight : node.scrollWidth;
|
|
63
|
+
const size = vertical ? node.clientHeight : node.clientWidth;
|
|
64
|
+
if (scrollSize <= size) continue;
|
|
65
|
+
const position = vertical ? node.scrollTop : node.scrollLeft;
|
|
66
|
+
if (forward && position < scrollSize - size || !forward && position > 0) return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
// src/create-background.ts
|
|
71
|
+
function createBackground(context) {
|
|
72
|
+
let background = null;
|
|
73
|
+
let initialScale = 1;
|
|
74
|
+
let vertical = true;
|
|
75
|
+
createEffect(() => ({
|
|
76
|
+
color: context.props.setBackgroundColorOnScale !== false && context.props.noBodyStyles !== true,
|
|
77
|
+
direction: context.direction,
|
|
78
|
+
element: context.content,
|
|
79
|
+
enabled: context.props.shouldScaleBackground === true,
|
|
80
|
+
nested: context.props.nested === true,
|
|
81
|
+
open: context.isOpen
|
|
82
|
+
}), ({ element, open, enabled, color, direction, nested }) => {
|
|
83
|
+
if (!element || !open || !enabled || nested) return;
|
|
84
|
+
const doc = element.ownerDocument;
|
|
85
|
+
const wrapper = doc.querySelector("[data-vaul-drawer-wrapper], [vaul-drawer-wrapper]");
|
|
86
|
+
const view = doc.defaultView;
|
|
87
|
+
if (!wrapper || !view) return;
|
|
88
|
+
background = wrapper;
|
|
89
|
+
initialScale = (view.innerWidth - 26) / view.innerWidth;
|
|
90
|
+
vertical = isVertical(direction);
|
|
91
|
+
const restoreBody = color ? assignStyle(doc.body, { background: "black" }) : void 0;
|
|
92
|
+
const restoreWrapper = assignStyle(wrapper, {
|
|
93
|
+
"border-radius": `8px`,
|
|
94
|
+
overflow: "hidden",
|
|
95
|
+
transform: `scale(${initialScale}) ${vertical ? "translate3d(0, 14px, 0)" : "translate3d(14px, 0, 0)"}`,
|
|
96
|
+
"transform-origin": vertical ? "top" : "left",
|
|
97
|
+
"transition-duration": `${TRANSITIONS.DURATION}s`,
|
|
98
|
+
"transition-property": "transform, border-radius",
|
|
99
|
+
"transition-timing-function": `cubic-bezier(${TRANSITIONS.EASE.join(",")})`
|
|
100
|
+
});
|
|
101
|
+
return () => {
|
|
102
|
+
background = null;
|
|
103
|
+
restoreWrapper();
|
|
104
|
+
restoreBody?.();
|
|
105
|
+
};
|
|
106
|
+
}, { ssrSource: "client" });
|
|
107
|
+
createEffect(() => ({
|
|
108
|
+
dragging: context.isDragging,
|
|
109
|
+
element: context.content,
|
|
110
|
+
open: context.isOpen,
|
|
111
|
+
progress: context.dragProgress
|
|
112
|
+
}), ({ progress, dragging, open }) => {
|
|
113
|
+
if (!background || !open) return;
|
|
114
|
+
const scale = initialScale + progress * (1 - initialScale);
|
|
115
|
+
const displacement = 14 * (1 - progress);
|
|
116
|
+
background.style.transitionDuration = dragging ? "0s" : `${TRANSITIONS.DURATION}s`;
|
|
117
|
+
background.style.borderRadius = `${8 * (1 - progress)}px`;
|
|
118
|
+
background.style.transform = `scale(${scale}) ${vertical ? `translate3d(0, ${displacement}px, 0)` : `translate3d(${displacement}px, 0, 0)`}`;
|
|
119
|
+
}, { ssrSource: "client" });
|
|
120
|
+
}
|
|
121
|
+
// src/create-snap-points.ts
|
|
122
|
+
function getSnapPointOffsets(points, dimension, direction) {
|
|
123
|
+
return points.map((point) => {
|
|
124
|
+
return (dimension - (typeof point === "number" ? point * dimension : Number(point.replace(/px$/u, "")))) * directionSign(direction);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function getOverlayOpacity(offsets, offset, fadeFromIndex, dimension) {
|
|
128
|
+
const faded = Math.abs(offsets[fadeFromIndex] ?? 0);
|
|
129
|
+
const clear = fadeFromIndex === 0 ? dimension : Math.abs(offsets[fadeFromIndex - 1] ?? faded);
|
|
130
|
+
if (clear === faded) return offset <= faded ? 1 : 0;
|
|
131
|
+
return clamp((clear - offset) / (clear - faded));
|
|
132
|
+
}
|
|
133
|
+
function selectSnapPoint(options) {
|
|
134
|
+
const { offsets, activeIndex, distance, velocity, dimension, dismissible, sequential } = options;
|
|
135
|
+
const [first] = offsets;
|
|
136
|
+
if (first === void 0) return activeIndex;
|
|
137
|
+
const position = Math.abs(offsets[activeIndex] ?? first) + distance;
|
|
138
|
+
if (!sequential && velocity > 2) {
|
|
139
|
+
if (distance <= 0) return offsets.length - 1;
|
|
140
|
+
return dismissible ? "close" : 0;
|
|
141
|
+
}
|
|
142
|
+
if (velocity > .4 && Math.abs(distance) < dimension * .4) {
|
|
143
|
+
if (distance > 0 && activeIndex === 0 && dismissible) return "close";
|
|
144
|
+
return clamp(activeIndex + (distance > 0 ? -1 : 1), 0, offsets.length - 1);
|
|
145
|
+
}
|
|
146
|
+
const remaining = dimension - Math.abs(first);
|
|
147
|
+
if (dismissible && distance > 0 && position > Math.abs(first) + remaining / 2) return "close";
|
|
148
|
+
let closest = 0;
|
|
149
|
+
let difference = Infinity;
|
|
150
|
+
for (const [index, offset] of offsets.entries()) {
|
|
151
|
+
if (sequential && Math.abs(index - activeIndex) > 1) continue;
|
|
152
|
+
const nextDifference = Math.abs(Math.abs(offset) - position);
|
|
153
|
+
if (nextDifference < difference) {
|
|
154
|
+
difference = nextDifference;
|
|
155
|
+
closest = index;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return closest;
|
|
159
|
+
}
|
|
160
|
+
// src/create-drawer.ts
|
|
161
|
+
const transition = `${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(",")})`;
|
|
162
|
+
function createDrawer(props, parent) {
|
|
163
|
+
const [internalOpen, setInternalOpen] = createSignal(untrack(() => props.defaultOpen ?? false));
|
|
164
|
+
const isOpen = createMemo(() => props.open ?? internalOpen());
|
|
165
|
+
const [present, setPresent] = createSignal(untrack(isOpen));
|
|
166
|
+
const [animate, setAnimate] = createSignal(untrack(() => props.defaultOpen !== true));
|
|
167
|
+
const [internalSnap, setInternalSnap] = createSignal(untrack(() => props.snapPoints?.[0] ?? null));
|
|
168
|
+
const activeSnap = createMemo(() => props.activeSnapPoint === void 0 ? internalSnap() : props.activeSnapPoint);
|
|
169
|
+
const [content, setContent] = createSignal(null, { ownedWrite: true });
|
|
170
|
+
const [overlay, setOverlay] = createSignal(null, { ownedWrite: true });
|
|
171
|
+
const [trigger, setTrigger] = createSignal(null, { ownedWrite: true });
|
|
172
|
+
const [dimension, setDimension] = createSignal(0);
|
|
173
|
+
const [dragging, setDragging] = createSignal(false);
|
|
174
|
+
const [dragProgress, setDragProgress] = createSignal(0);
|
|
175
|
+
const [childOpen, setChildOpen] = createSignal(false);
|
|
176
|
+
const [childProgress, setChildProgress] = createSignal(0);
|
|
177
|
+
const direction = () => props.direction ?? "bottom";
|
|
178
|
+
const points = () => props.snapPoints ?? [];
|
|
179
|
+
const offsets = createMemo(() => getSnapPointOffsets(points(), dimension(), direction()));
|
|
180
|
+
const activeIndex = createMemo(() => Math.max(0, points().indexOf(activeSnap() ?? points()[0] ?? 0)));
|
|
181
|
+
const offset = () => offsets()[activeIndex()] ?? 0;
|
|
182
|
+
const fadeFromIndex = () => props.fadeFromIndex ?? Math.max(0, points().length - 1);
|
|
183
|
+
const id = createUniqueId();
|
|
184
|
+
let gesture = null;
|
|
185
|
+
let lastScrollTime = -Infinity;
|
|
186
|
+
let openedAt = -Infinity;
|
|
187
|
+
const onScroll = () => {
|
|
188
|
+
lastScrollTime = Date.now();
|
|
189
|
+
};
|
|
190
|
+
function setOpen(open) {
|
|
191
|
+
if (open === isOpen()) return;
|
|
192
|
+
if (props.open === void 0) setInternalOpen(open);
|
|
193
|
+
props.onOpenChange?.(open);
|
|
194
|
+
}
|
|
195
|
+
function setActiveSnapPoint(point) {
|
|
196
|
+
if (point === activeSnap()) return;
|
|
197
|
+
if (props.activeSnapPoint === void 0) setInternalSnap(point);
|
|
198
|
+
props.setActiveSnapPoint?.(point);
|
|
199
|
+
}
|
|
200
|
+
function resetPosition() {
|
|
201
|
+
const element = content();
|
|
202
|
+
if (!element) return;
|
|
203
|
+
element.classList.remove(DRAG_CLASS);
|
|
204
|
+
element.style.transition = `transform ${transition}`;
|
|
205
|
+
element.style.transform = translate(offset(), direction());
|
|
206
|
+
const backdrop = overlay();
|
|
207
|
+
if (backdrop) {
|
|
208
|
+
backdrop.style.transition = `opacity ${transition}`;
|
|
209
|
+
backdrop.style.opacity = points().length ? `${getOverlayOpacity(offsets(), Math.abs(offset()), fadeFromIndex(), dimension())}` : "1";
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function cancelDrag() {
|
|
213
|
+
if (!gesture) return;
|
|
214
|
+
if (gesture.target.hasPointerCapture?.(gesture.pointerId)) gesture.target.releasePointerCapture(gesture.pointerId);
|
|
215
|
+
gesture = null;
|
|
216
|
+
setDragging(false);
|
|
217
|
+
setDragProgress(0);
|
|
218
|
+
untrack(resetPosition);
|
|
219
|
+
parent?.setChildProgress(0);
|
|
220
|
+
}
|
|
221
|
+
function close() {
|
|
222
|
+
cancelDrag();
|
|
223
|
+
if (props.dismissible !== false) setOpen(false);
|
|
224
|
+
}
|
|
225
|
+
createEffect(isOpen, (open, previous) => {
|
|
226
|
+
if (open) {
|
|
227
|
+
openedAt = Date.now();
|
|
228
|
+
setPresent(true);
|
|
229
|
+
} else {
|
|
230
|
+
cancelDrag();
|
|
231
|
+
if (previous === true) props.onClose?.();
|
|
232
|
+
}
|
|
233
|
+
parent?.setChildOpen(open);
|
|
234
|
+
if (previous === void 0 && !open) return;
|
|
235
|
+
const duration = (untrack(content)?.ownerDocument.defaultView)?.matchMedia("(prefers-reduced-motion: reduce)").matches === true ? 0 : TRANSITIONS.DURATION * 1e3;
|
|
236
|
+
const timer = setTimeout(() => {
|
|
237
|
+
if (!open) {
|
|
238
|
+
setPresent(false);
|
|
239
|
+
setActiveSnapPoint(points()[0] ?? null);
|
|
240
|
+
}
|
|
241
|
+
if (previous !== void 0) props.onAnimationEnd?.(open);
|
|
242
|
+
}, duration);
|
|
243
|
+
return () => {
|
|
244
|
+
clearTimeout(timer);
|
|
245
|
+
};
|
|
246
|
+
}, { ssrSource: "client" });
|
|
247
|
+
createEffect(() => ({
|
|
248
|
+
container: props.container,
|
|
249
|
+
direction: direction(),
|
|
250
|
+
element: content()
|
|
251
|
+
}), ({ element, container, direction: currentDirection }) => {
|
|
252
|
+
if (!element) return;
|
|
253
|
+
const view = element.ownerDocument.defaultView;
|
|
254
|
+
if (!view) return;
|
|
255
|
+
const measure = () => {
|
|
256
|
+
const rect = container?.getBoundingClientRect();
|
|
257
|
+
setDimension(isVertical(currentDirection) ? rect?.height ?? view.innerHeight : rect?.width ?? view.innerWidth);
|
|
258
|
+
};
|
|
259
|
+
measure();
|
|
260
|
+
view.addEventListener("resize", measure);
|
|
261
|
+
const observer = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(measure);
|
|
262
|
+
if (container) observer?.observe(container);
|
|
263
|
+
element.addEventListener("scroll", onScroll, true);
|
|
264
|
+
return () => {
|
|
265
|
+
view.removeEventListener("resize", measure);
|
|
266
|
+
observer?.disconnect();
|
|
267
|
+
element.removeEventListener("scroll", onScroll, true);
|
|
268
|
+
cancelDrag();
|
|
269
|
+
};
|
|
270
|
+
}, { ssrSource: "client" });
|
|
271
|
+
createEffect(() => ({
|
|
272
|
+
animate: animate(),
|
|
273
|
+
backdrop: overlay(),
|
|
274
|
+
child: childOpen(),
|
|
275
|
+
dimension: dimension(),
|
|
276
|
+
direction: direction(),
|
|
277
|
+
element: content(),
|
|
278
|
+
hasSnapPoints: points().length > 0,
|
|
279
|
+
offset: offset(),
|
|
280
|
+
opacity: points().length ? getOverlayOpacity(offsets(), Math.abs(offset()), fadeFromIndex(), dimension()) : 1,
|
|
281
|
+
open: isOpen(),
|
|
282
|
+
progress: childProgress()
|
|
283
|
+
}), ({ animate: shouldAnimate, element, backdrop, dimension: currentDimension, hasSnapPoints, open, offset: currentOffset, child, progress, direction: currentDirection, opacity }) => {
|
|
284
|
+
if (!element || hasSnapPoints && currentDimension === 0) return;
|
|
285
|
+
const sign = directionSign(currentDirection);
|
|
286
|
+
const view = element.ownerDocument.defaultView;
|
|
287
|
+
const size = isVertical(currentDirection) ? view?.innerHeight : view?.innerWidth;
|
|
288
|
+
const scale = child ? 1 - 16 / Math.max(1, size ?? 1) * (1 - progress) : 1;
|
|
289
|
+
const displacement = child ? -16 * (1 - progress) * sign : 0;
|
|
290
|
+
if (hasSnapPoints && shouldAnimate && element.style.transform === "") element.getBoundingClientRect();
|
|
291
|
+
element.style.transition = shouldAnimate ? `transform ${transition}` : "none";
|
|
292
|
+
element.style.transform = `${translate(open ? currentOffset + displacement : sign * (size ?? currentDimension), currentDirection)} scale(${scale})`;
|
|
293
|
+
if (backdrop) {
|
|
294
|
+
backdrop.style.transition = shouldAnimate ? `opacity ${transition}` : "none";
|
|
295
|
+
backdrop.style.opacity = open ? `${opacity}` : "0";
|
|
296
|
+
}
|
|
297
|
+
}, { ssrSource: "client" });
|
|
298
|
+
onSettled(() => {
|
|
299
|
+
const frame = requestAnimationFrame(() => {
|
|
300
|
+
setAnimate(true);
|
|
301
|
+
});
|
|
302
|
+
return () => {
|
|
303
|
+
cancelAnimationFrame(frame);
|
|
304
|
+
parent?.setChildOpen(false);
|
|
305
|
+
};
|
|
306
|
+
});
|
|
307
|
+
function press(event, fromHandle = false) {
|
|
308
|
+
const element = content();
|
|
309
|
+
const { target } = event;
|
|
310
|
+
if (!element || !isOpen() || childOpen() || event.defaultPrevented || event.button > 0) return;
|
|
311
|
+
if (!(target instanceof HTMLElement) || target.closest("[data-vaul-drawer]") !== element) return;
|
|
312
|
+
if (target.closest("[data-vaul-no-drag],select,option") || props.handleOnly === true && !fromHandle) return;
|
|
313
|
+
if (props.dismissible === false && !points().length) return;
|
|
314
|
+
const rect = element.getBoundingClientRect();
|
|
315
|
+
gesture = {
|
|
316
|
+
allowed: false,
|
|
317
|
+
dimension: isVertical(direction()) ? rect.height : rect.width,
|
|
318
|
+
distance: 0,
|
|
319
|
+
fromHandle,
|
|
320
|
+
pointerId: event.pointerId,
|
|
321
|
+
startOffset: Math.abs(offset()),
|
|
322
|
+
startedAt: Date.now(),
|
|
323
|
+
target,
|
|
324
|
+
x: event.clientX,
|
|
325
|
+
y: event.clientY
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function canDrag(target, distance) {
|
|
329
|
+
if (!gesture || target.closest("[data-vaul-no-drag],select,option")) return false;
|
|
330
|
+
if (gesture.fromHandle) return true;
|
|
331
|
+
if ((target.ownerDocument.getSelection()?.toString().length ?? 0) > 0) return false;
|
|
332
|
+
if (Date.now() - openedAt < TRANSITIONS.DURATION * 1e3) return false;
|
|
333
|
+
if (Date.now() - lastScrollTime < (props.scrollLockTimeout ?? 100)) return false;
|
|
334
|
+
const lastOffset = Math.abs(offsets().at(-1) ?? 0);
|
|
335
|
+
if (distance < 0 && gesture.startOffset > lastOffset) return true;
|
|
336
|
+
const element = content();
|
|
337
|
+
return element !== null && !canScroll(target, element, direction(), distance);
|
|
338
|
+
}
|
|
339
|
+
function claimGesture(event, current, axis, cross, distance) {
|
|
340
|
+
if (current.allowed) return true;
|
|
341
|
+
const threshold = event.pointerType === "touch" ? 10 : 2;
|
|
342
|
+
if (Math.abs(axis) < threshold && Math.abs(cross) < threshold) return false;
|
|
343
|
+
if (Math.abs(cross) > Math.abs(axis)) {
|
|
344
|
+
gesture = null;
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
if (!canDrag(current.target, distance)) return false;
|
|
348
|
+
current.allowed = true;
|
|
349
|
+
current.target.setPointerCapture?.(event.pointerId);
|
|
350
|
+
setDragging(true);
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
function drag(event) {
|
|
354
|
+
const current = gesture;
|
|
355
|
+
const element = content();
|
|
356
|
+
if (!current || !element || current.pointerId !== event.pointerId) return;
|
|
357
|
+
const dx = event.clientX - current.x;
|
|
358
|
+
const dy = event.clientY - current.y;
|
|
359
|
+
const vertical = isVertical(direction());
|
|
360
|
+
const axis = vertical ? dy : dx;
|
|
361
|
+
const cross = vertical ? dx : dy;
|
|
362
|
+
const distance = axis * directionSign(direction());
|
|
363
|
+
if (!claimGesture(event, current, axis, cross, distance)) return;
|
|
364
|
+
event.preventDefault();
|
|
365
|
+
const minimum = Math.abs(offsets().at(-1) ?? 0);
|
|
366
|
+
let position = current.startOffset + distance;
|
|
367
|
+
if (position < minimum) position = minimum - dampenValue(minimum - position);
|
|
368
|
+
if (props.dismissible === false) position = Math.min(position, Math.abs(offsets()[0] ?? 0));
|
|
369
|
+
current.distance = position - current.startOffset;
|
|
370
|
+
element.classList.add(DRAG_CLASS);
|
|
371
|
+
element.style.transition = "none";
|
|
372
|
+
element.style.transform = translate(position * directionSign(direction()), direction());
|
|
373
|
+
const percentage = clamp(Math.max(0, distance) / Math.max(1, current.dimension - current.startOffset));
|
|
374
|
+
const backdrop = overlay();
|
|
375
|
+
if (backdrop) {
|
|
376
|
+
backdrop.style.transition = "none";
|
|
377
|
+
backdrop.style.opacity = points().length ? `${getOverlayOpacity(offsets(), position, fadeFromIndex(), dimension())}` : `${1 - percentage}`;
|
|
378
|
+
}
|
|
379
|
+
setDragProgress(percentage);
|
|
380
|
+
props.onDrag?.(event, percentage);
|
|
381
|
+
parent?.setChildProgress(percentage);
|
|
382
|
+
}
|
|
383
|
+
function release(event) {
|
|
384
|
+
const current = gesture;
|
|
385
|
+
if (!current || event.pointerId !== current.pointerId) return;
|
|
386
|
+
const velocity = Math.abs(current.distance) / Math.max(1, Date.now() - current.startedAt);
|
|
387
|
+
let next = activeIndex();
|
|
388
|
+
if (current.allowed && points().length) next = selectSnapPoint({
|
|
389
|
+
activeIndex: activeIndex(),
|
|
390
|
+
dimension: dimension(),
|
|
391
|
+
dismissible: props.dismissible !== false,
|
|
392
|
+
distance: current.distance,
|
|
393
|
+
offsets: offsets(),
|
|
394
|
+
sequential: props.snapToSequentialPoint ?? false,
|
|
395
|
+
velocity
|
|
396
|
+
});
|
|
397
|
+
else if (current.allowed && current.distance > 0 && props.dismissible !== false && (velocity > .4 || current.distance >= current.dimension * (props.closeThreshold ?? .25))) next = "close";
|
|
398
|
+
cancelDrag();
|
|
399
|
+
if (!current.allowed) return;
|
|
400
|
+
if (next === "close") close();
|
|
401
|
+
else if (points().length) setActiveSnapPoint(points()[next] ?? null);
|
|
402
|
+
props.onRelease?.(event, next !== "close");
|
|
403
|
+
}
|
|
404
|
+
return {
|
|
405
|
+
get activeSnapPoint() {
|
|
406
|
+
return activeSnap();
|
|
407
|
+
},
|
|
408
|
+
get activeSnapPointIndex() {
|
|
409
|
+
return activeIndex();
|
|
410
|
+
},
|
|
411
|
+
cancelDrag,
|
|
412
|
+
get childOpen() {
|
|
413
|
+
return childOpen();
|
|
414
|
+
},
|
|
415
|
+
close,
|
|
416
|
+
get content() {
|
|
417
|
+
return content();
|
|
418
|
+
},
|
|
419
|
+
contentId: `vaul-${id}`,
|
|
420
|
+
descriptionId: `vaul-${id}-description`,
|
|
421
|
+
get direction() {
|
|
422
|
+
return direction();
|
|
423
|
+
},
|
|
424
|
+
get dismissible() {
|
|
425
|
+
return props.dismissible ?? true;
|
|
426
|
+
},
|
|
427
|
+
drag,
|
|
428
|
+
get dragProgress() {
|
|
429
|
+
return dragProgress();
|
|
430
|
+
},
|
|
431
|
+
get isDragging() {
|
|
432
|
+
return dragging();
|
|
433
|
+
},
|
|
434
|
+
get isOpen() {
|
|
435
|
+
return isOpen();
|
|
436
|
+
},
|
|
437
|
+
get modal() {
|
|
438
|
+
return props.modal ?? true;
|
|
439
|
+
},
|
|
440
|
+
get overlay() {
|
|
441
|
+
return overlay();
|
|
442
|
+
},
|
|
443
|
+
get present() {
|
|
444
|
+
return present();
|
|
445
|
+
},
|
|
446
|
+
press,
|
|
447
|
+
props,
|
|
448
|
+
release,
|
|
449
|
+
setActiveSnapPoint,
|
|
450
|
+
setChildOpen(open) {
|
|
451
|
+
setChildOpen(open);
|
|
452
|
+
setChildProgress(0);
|
|
453
|
+
},
|
|
454
|
+
setChildProgress(progress) {
|
|
455
|
+
setChildProgress(progress);
|
|
456
|
+
},
|
|
457
|
+
setContent(element) {
|
|
458
|
+
setContent(element);
|
|
459
|
+
},
|
|
460
|
+
setOpen,
|
|
461
|
+
setOverlay(element) {
|
|
462
|
+
setOverlay(element);
|
|
463
|
+
},
|
|
464
|
+
setTrigger(element) {
|
|
465
|
+
setTrigger(element);
|
|
466
|
+
},
|
|
467
|
+
get shouldAnimate() {
|
|
468
|
+
return animate();
|
|
469
|
+
},
|
|
470
|
+
get shouldFade() {
|
|
471
|
+
return !points().length || activeIndex() >= fadeFromIndex();
|
|
472
|
+
},
|
|
473
|
+
get snapPointsOffset() {
|
|
474
|
+
return offsets();
|
|
475
|
+
},
|
|
476
|
+
titleId: `vaul-${id}-title`,
|
|
477
|
+
get trigger() {
|
|
478
|
+
return trigger();
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
// src/create-layer.ts
|
|
483
|
+
const layers = /* @__PURE__ */ new WeakMap();
|
|
484
|
+
function createLayer(context, props) {
|
|
485
|
+
createPreventScroll({ get isDisabled() {
|
|
486
|
+
return !context.isOpen || !context.content || !context.modal || context.props.noBodyStyles === true || !context.overlay && context.props.disablePreventScroll !== true;
|
|
487
|
+
} });
|
|
488
|
+
createEffect(() => ({
|
|
489
|
+
element: context.content,
|
|
490
|
+
modal: context.modal,
|
|
491
|
+
open: context.isOpen,
|
|
492
|
+
overlay: context.overlay
|
|
493
|
+
}), ({ element, overlay, open, modal }) => {
|
|
494
|
+
if (!element || !open || !modal) return;
|
|
495
|
+
return ariaHideOutside(overlay ? [element, overlay] : [element], { shouldUseInert: true });
|
|
496
|
+
}, { ssrSource: "client" });
|
|
497
|
+
createEffect(() => ({
|
|
498
|
+
element: context.content,
|
|
499
|
+
open: context.isOpen
|
|
500
|
+
}), ({ element, open }) => {
|
|
501
|
+
if (!element || !open) return;
|
|
502
|
+
const doc = element.ownerDocument;
|
|
503
|
+
const stack = layers.get(doc) ?? [];
|
|
504
|
+
layers.set(doc, stack);
|
|
505
|
+
stack.push(element);
|
|
506
|
+
const previous = doc.activeElement;
|
|
507
|
+
let interactedOutside = false;
|
|
508
|
+
const autoFocus = new Event("openAutoFocus", { cancelable: true });
|
|
509
|
+
props.onOpenAutoFocus?.(autoFocus);
|
|
510
|
+
if (!autoFocus.defaultPrevented && context.props.autoFocus === true) (element.querySelector("[autofocus],button:not([disabled]),[href],input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex='0']") ?? element).focus({ preventScroll: true });
|
|
511
|
+
const isTop = () => stack.at(-1) === element;
|
|
512
|
+
const isOutside = (event) => !event.composedPath().includes(element);
|
|
513
|
+
function pointerDown(event) {
|
|
514
|
+
if (!isTop() || !isOutside(event)) return;
|
|
515
|
+
const outside = new CustomEvent("pointerDownOutside", {
|
|
516
|
+
cancelable: true,
|
|
517
|
+
detail: { originalEvent: event }
|
|
518
|
+
});
|
|
519
|
+
props.onPointerDownOutside?.(outside);
|
|
520
|
+
props.onInteractOutside?.(outside);
|
|
521
|
+
if (outside.defaultPrevented || !context.modal || event.button > 0 || event.ctrlKey) return;
|
|
522
|
+
interactedOutside = !context.modal;
|
|
523
|
+
context.close();
|
|
524
|
+
}
|
|
525
|
+
function focusIn(event) {
|
|
526
|
+
if (!isTop() || !isOutside(event)) return;
|
|
527
|
+
const outside = new CustomEvent("focusOutside", {
|
|
528
|
+
cancelable: true,
|
|
529
|
+
detail: { originalEvent: event }
|
|
530
|
+
});
|
|
531
|
+
props.onFocusOutside?.(outside);
|
|
532
|
+
props.onInteractOutside?.(outside);
|
|
533
|
+
if (!context.modal) interactedOutside = true;
|
|
534
|
+
}
|
|
535
|
+
function keyDown(event) {
|
|
536
|
+
if (event.key !== "Escape" || !isTop() || event.defaultPrevented) return;
|
|
537
|
+
props.onEscapeKeyDown?.(event);
|
|
538
|
+
if (event.defaultPrevented) return;
|
|
539
|
+
event.preventDefault();
|
|
540
|
+
context.close();
|
|
541
|
+
}
|
|
542
|
+
doc.addEventListener("pointerdown", pointerDown);
|
|
543
|
+
doc.addEventListener("focusin", focusIn);
|
|
544
|
+
doc.addEventListener("keydown", keyDown);
|
|
545
|
+
const touchMove = (event) => {
|
|
546
|
+
if (element.classList.contains("vaul-dragging") && event.cancelable) event.preventDefault();
|
|
547
|
+
};
|
|
548
|
+
element.addEventListener("touchmove", touchMove, { passive: false });
|
|
549
|
+
return () => {
|
|
550
|
+
const index = stack.indexOf(element);
|
|
551
|
+
const wasTop = isTop();
|
|
552
|
+
if (index !== -1) stack.splice(index, 1);
|
|
553
|
+
if (!stack.length) layers.delete(doc);
|
|
554
|
+
doc.removeEventListener("pointerdown", pointerDown);
|
|
555
|
+
doc.removeEventListener("focusin", focusIn);
|
|
556
|
+
doc.removeEventListener("keydown", keyDown);
|
|
557
|
+
element.removeEventListener("touchmove", touchMove);
|
|
558
|
+
const closeAutoFocus = new Event("closeAutoFocus", { cancelable: true });
|
|
559
|
+
props.onCloseAutoFocus?.(closeAutoFocus);
|
|
560
|
+
if (closeAutoFocus.defaultPrevented || interactedOutside || !wasTop) return;
|
|
561
|
+
const target = untrack(() => context.trigger) ?? previous;
|
|
562
|
+
queueMicrotask(() => {
|
|
563
|
+
if (target instanceof HTMLElement && target.isConnected) target.focus({ preventScroll: true });
|
|
564
|
+
});
|
|
565
|
+
};
|
|
566
|
+
}, { ssrSource: "client" });
|
|
567
|
+
}
|
|
568
|
+
// src/create-position.ts
|
|
569
|
+
function createPosition(context) {
|
|
570
|
+
createEffect(() => ({
|
|
571
|
+
element: context.content,
|
|
572
|
+
modal: context.modal,
|
|
573
|
+
nested: context.props.nested === true,
|
|
574
|
+
noBodyStyles: context.props.noBodyStyles === true,
|
|
575
|
+
open: context.isOpen,
|
|
576
|
+
preventScrollRestoration: context.props.preventScrollRestoration === true
|
|
577
|
+
}), ({ element, open, modal, noBodyStyles, nested, preventScrollRestoration }) => {
|
|
578
|
+
if (!element || !open || !modal || noBodyStyles || nested) return;
|
|
579
|
+
const doc = element.ownerDocument;
|
|
580
|
+
const view = doc.defaultView;
|
|
581
|
+
if (!view || !isSafari(view) || view.matchMedia("(display-mode: standalone)").matches) return;
|
|
582
|
+
const { scrollX, scrollY } = view;
|
|
583
|
+
const url = view.location.href;
|
|
584
|
+
const restore = assignStyle(doc.body, {
|
|
585
|
+
height: "auto",
|
|
586
|
+
left: `${-scrollX}px`,
|
|
587
|
+
position: "fixed",
|
|
588
|
+
right: "0",
|
|
589
|
+
top: `${-scrollY}px`
|
|
590
|
+
});
|
|
591
|
+
return () => {
|
|
592
|
+
restore();
|
|
593
|
+
if (!preventScrollRestoration || url === view.location.href) view.scrollTo(scrollX, scrollY);
|
|
594
|
+
};
|
|
595
|
+
}, { ssrSource: "client" });
|
|
596
|
+
createEffect(() => ({
|
|
597
|
+
direction: context.direction,
|
|
598
|
+
element: context.content,
|
|
599
|
+
fixed: context.props.fixed === true,
|
|
600
|
+
open: context.isOpen,
|
|
601
|
+
reposition: context.props.repositionInputs !== false
|
|
602
|
+
}), ({ element, open, reposition, fixed, direction }) => {
|
|
603
|
+
if (!element || !open || !reposition || direction !== "bottom") return;
|
|
604
|
+
const doc = element.ownerDocument;
|
|
605
|
+
const view = doc.defaultView;
|
|
606
|
+
const viewport = view?.visualViewport;
|
|
607
|
+
if (!view || !viewport) return;
|
|
608
|
+
const { height } = element.style;
|
|
609
|
+
const { bottom } = element.style;
|
|
610
|
+
let keyboardOpen = false;
|
|
611
|
+
const initialHeight = element.getBoundingClientRect().height;
|
|
612
|
+
const resize = () => {
|
|
613
|
+
const focused = doc.activeElement;
|
|
614
|
+
if (!keyboardOpen && (!(focused instanceof HTMLElement) || !element.contains(focused) || !focused.matches("input,textarea,[contenteditable]"))) return;
|
|
615
|
+
const diff = Math.max(0, view.innerHeight - viewport.height - viewport.offsetTop);
|
|
616
|
+
keyboardOpen = diff > 60;
|
|
617
|
+
if (!keyboardOpen) {
|
|
618
|
+
element.style.height = height;
|
|
619
|
+
element.style.bottom = bottom;
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
const rect = element.getBoundingClientRect();
|
|
623
|
+
const available = Math.max(0, viewport.height - Math.max(26, rect.top));
|
|
624
|
+
element.style.height = `${fixed ? Math.max(0, initialHeight - diff) : available}px`;
|
|
625
|
+
element.style.bottom = `${diff}px`;
|
|
626
|
+
if (focused instanceof HTMLElement) focused.scrollIntoView({ block: "nearest" });
|
|
627
|
+
};
|
|
628
|
+
viewport.addEventListener("resize", resize);
|
|
629
|
+
viewport.addEventListener("scroll", resize);
|
|
630
|
+
return () => {
|
|
631
|
+
viewport.removeEventListener("resize", resize);
|
|
632
|
+
viewport.removeEventListener("scroll", resize);
|
|
633
|
+
element.style.height = height;
|
|
634
|
+
element.style.bottom = bottom;
|
|
635
|
+
};
|
|
636
|
+
}, { ssrSource: "client" });
|
|
637
|
+
}
|
|
638
|
+
// src/drawer.tsx
|
|
639
|
+
var _tmpl$ = /* @__PURE__ */ template(`<button>`);
|
|
640
|
+
var _tmpl$2 = /* @__PURE__ */ template(`<div>`);
|
|
641
|
+
var _tmpl$3 = /* @__PURE__ */ template(`<h2>`);
|
|
642
|
+
var _tmpl$4 = /* @__PURE__ */ template(`<p>`);
|
|
643
|
+
var _tmpl$5 = /* @__PURE__ */ template(`<div><span data-vaul-handle-hitarea aria-hidden=true>`);
|
|
644
|
+
function Root(props) {
|
|
645
|
+
const context = createDrawer(props);
|
|
646
|
+
createBackground(context);
|
|
647
|
+
createPosition(context);
|
|
648
|
+
return createComponent(DrawerContext, {
|
|
649
|
+
value: context,
|
|
650
|
+
get children() {
|
|
651
|
+
return props.children;
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
function NestedRoot(props) {
|
|
656
|
+
const parent = useContext(DrawerContext);
|
|
657
|
+
const context = createDrawer(merge(props, { nested: true }), parent);
|
|
658
|
+
createPosition(context);
|
|
659
|
+
return createComponent(DrawerContext, {
|
|
660
|
+
value: context,
|
|
661
|
+
get children() {
|
|
662
|
+
return props.children;
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
function Portal(props) {
|
|
667
|
+
const context = useContext(DrawerContext);
|
|
668
|
+
const [mounted, setMounted] = createSignal(false);
|
|
669
|
+
onSettled(() => {
|
|
670
|
+
setMounted(true);
|
|
671
|
+
});
|
|
672
|
+
return createComponent(Show, {
|
|
673
|
+
get when() {
|
|
674
|
+
return memo(() => {
|
|
675
|
+
return !!mounted();
|
|
676
|
+
})() ? context.present || props.forceMount === true : mounted();
|
|
677
|
+
},
|
|
678
|
+
get children() {
|
|
679
|
+
return createComponent(Portal$1, {
|
|
680
|
+
get mount() {
|
|
681
|
+
return props.container ?? context.props.container ?? document.body;
|
|
682
|
+
},
|
|
683
|
+
get children() {
|
|
684
|
+
return createComponent(PortalContext, {
|
|
685
|
+
get value() {
|
|
686
|
+
return props.forceMount ?? false;
|
|
687
|
+
},
|
|
688
|
+
get children() {
|
|
689
|
+
return props.children;
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
function Trigger(props) {
|
|
698
|
+
const context = useContext(DrawerContext);
|
|
699
|
+
const attributes = merge(omit(props, "render", "ref", "onClick"), {
|
|
700
|
+
"aria-controls": context.contentId,
|
|
701
|
+
get "aria-expanded"() {
|
|
702
|
+
return context.isOpen ? "true" : "false";
|
|
703
|
+
},
|
|
704
|
+
"aria-haspopup": "dialog",
|
|
705
|
+
get "data-state"() {
|
|
706
|
+
return context.isOpen ? "open" : "closed";
|
|
707
|
+
},
|
|
708
|
+
onClick(event) {
|
|
709
|
+
callHandler(props.onClick, event);
|
|
710
|
+
if (!event.defaultPrevented) context.setOpen(!context.isOpen);
|
|
711
|
+
},
|
|
712
|
+
get ref() {
|
|
713
|
+
return [props.ref, (element) => {
|
|
714
|
+
context.setTrigger(element);
|
|
715
|
+
}];
|
|
716
|
+
},
|
|
717
|
+
get type() {
|
|
718
|
+
return props.type ?? "button";
|
|
719
|
+
}
|
|
720
|
+
});
|
|
721
|
+
return createComponent(Show, {
|
|
722
|
+
get when() {
|
|
723
|
+
return props.render;
|
|
724
|
+
},
|
|
725
|
+
keyed: true,
|
|
726
|
+
get fallback() {
|
|
727
|
+
var _el$ = getNextElement(_tmpl$);
|
|
728
|
+
spread(_el$, attributes, false);
|
|
729
|
+
runHydrationEvents();
|
|
730
|
+
return _el$;
|
|
731
|
+
},
|
|
732
|
+
children: (render) => render(attributes)
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
function Close(props) {
|
|
736
|
+
const context = useContext(DrawerContext);
|
|
737
|
+
const attributes = merge(omit(props, "render", "onClick"), {
|
|
738
|
+
onClick(event) {
|
|
739
|
+
callHandler(props.onClick, event);
|
|
740
|
+
if (!event.defaultPrevented) context.close();
|
|
741
|
+
},
|
|
742
|
+
get type() {
|
|
743
|
+
return props.type ?? "button";
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
return createComponent(Show, {
|
|
747
|
+
get when() {
|
|
748
|
+
return props.render;
|
|
749
|
+
},
|
|
750
|
+
keyed: true,
|
|
751
|
+
get fallback() {
|
|
752
|
+
var _el$2 = getNextElement(_tmpl$);
|
|
753
|
+
spread(_el$2, attributes, false);
|
|
754
|
+
runHydrationEvents();
|
|
755
|
+
return _el$2;
|
|
756
|
+
},
|
|
757
|
+
children: (render) => render(attributes)
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
function Overlay(props) {
|
|
761
|
+
const context = useContext(DrawerContext);
|
|
762
|
+
const forceMount = useContext(PortalContext);
|
|
763
|
+
return createComponent(Show, {
|
|
764
|
+
get when() {
|
|
765
|
+
return memo(() => {
|
|
766
|
+
return !!context.modal;
|
|
767
|
+
})() ? context.present || props.forceMount === true || forceMount : context.modal;
|
|
768
|
+
},
|
|
769
|
+
get children() {
|
|
770
|
+
return createComponent(OverlayElement, props);
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
function OverlayElement(props) {
|
|
775
|
+
const context = useContext(DrawerContext);
|
|
776
|
+
const rest = omit(props, "forceMount", "ref");
|
|
777
|
+
onSettled(() => () => {
|
|
778
|
+
context.setOverlay(null);
|
|
779
|
+
});
|
|
780
|
+
var _el$3 = getNextElement(_tmpl$2);
|
|
781
|
+
spread(_el$3, [rest, {
|
|
782
|
+
"data-vaul-overlay": "",
|
|
783
|
+
get "data-state"() {
|
|
784
|
+
return context.isOpen ? "open" : "closed";
|
|
785
|
+
},
|
|
786
|
+
get "data-vaul-snap-points"() {
|
|
787
|
+
return (context.props.snapPoints?.length ?? 0) > 0 ? "true" : "false";
|
|
788
|
+
},
|
|
789
|
+
get "data-vaul-snap-points-overlay"() {
|
|
790
|
+
return context.shouldFade ? "true" : "false";
|
|
791
|
+
},
|
|
792
|
+
get "data-vaul-animate"() {
|
|
793
|
+
return context.shouldAnimate ? "true" : "false";
|
|
794
|
+
}
|
|
795
|
+
}], false);
|
|
796
|
+
ref(() => {
|
|
797
|
+
return [props.ref, (element) => {
|
|
798
|
+
context.setOverlay(element);
|
|
799
|
+
}];
|
|
800
|
+
}, _el$3);
|
|
801
|
+
runHydrationEvents();
|
|
802
|
+
return _el$3;
|
|
803
|
+
}
|
|
804
|
+
function Content(props) {
|
|
805
|
+
const context = useContext(DrawerContext);
|
|
806
|
+
const forceMount = useContext(PortalContext);
|
|
807
|
+
return createComponent(Show, {
|
|
808
|
+
get when() {
|
|
809
|
+
return context.present || props.forceMount === true || forceMount;
|
|
810
|
+
},
|
|
811
|
+
get children() {
|
|
812
|
+
return createComponent(ContentElement, props);
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
function ContentElement(props) {
|
|
817
|
+
const context = useContext(DrawerContext);
|
|
818
|
+
const rest = omit(props, "forceMount", "ref", "onOpenAutoFocus", "onCloseAutoFocus", "onEscapeKeyDown", "onPointerDownOutside", "onFocusOutside", "onInteractOutside", "onPointerDown", "onPointerMove", "onPointerUp", "onPointerCancel", "onLostPointerCapture");
|
|
819
|
+
createLayer(context, props);
|
|
820
|
+
onSettled(() => () => {
|
|
821
|
+
context.setContent(null);
|
|
822
|
+
});
|
|
823
|
+
return createComponent(FocusScope, {
|
|
824
|
+
get contain() {
|
|
825
|
+
return memo(() => {
|
|
826
|
+
return !!(context.isOpen && context.modal);
|
|
827
|
+
})() ? !context.childOpen : context.isOpen && context.modal;
|
|
828
|
+
},
|
|
829
|
+
get children() {
|
|
830
|
+
var _el$4 = getNextElement(_tmpl$2);
|
|
831
|
+
spread(_el$4, [
|
|
832
|
+
{
|
|
833
|
+
get id() {
|
|
834
|
+
return context.contentId;
|
|
835
|
+
},
|
|
836
|
+
role: "dialog",
|
|
837
|
+
get "aria-modal"() {
|
|
838
|
+
return context.modal ? "true" : void 0;
|
|
839
|
+
},
|
|
840
|
+
get "aria-labelledby"() {
|
|
841
|
+
return context.titleId;
|
|
842
|
+
},
|
|
843
|
+
get "aria-describedby"() {
|
|
844
|
+
return context.descriptionId;
|
|
845
|
+
},
|
|
846
|
+
tabindex: -1
|
|
847
|
+
},
|
|
848
|
+
rest,
|
|
849
|
+
{
|
|
850
|
+
get "data-state"() {
|
|
851
|
+
return context.isOpen ? "open" : "closed";
|
|
852
|
+
},
|
|
853
|
+
"data-vaul-drawer": "",
|
|
854
|
+
get "data-vaul-drawer-direction"() {
|
|
855
|
+
return context.direction;
|
|
856
|
+
},
|
|
857
|
+
get "data-vaul-custom-container"() {
|
|
858
|
+
return context.props.container ? "true" : "false";
|
|
859
|
+
},
|
|
860
|
+
get "data-vaul-snap-points"() {
|
|
861
|
+
return (context.props.snapPoints?.length ?? 0) > 0 ? "true" : "false";
|
|
862
|
+
},
|
|
863
|
+
get "data-vaul-delayed-snap-points"() {
|
|
864
|
+
return context.snapPointsOffset.length > 0 ? "true" : "false";
|
|
865
|
+
},
|
|
866
|
+
get "data-vaul-handle-only"() {
|
|
867
|
+
return context.props.handleOnly === true ? "true" : "false";
|
|
868
|
+
},
|
|
869
|
+
get "data-vaul-animate"() {
|
|
870
|
+
return context.shouldAnimate ? "true" : "false";
|
|
871
|
+
},
|
|
872
|
+
onPointerDown: (event) => {
|
|
873
|
+
callHandler(props.onPointerDown, event);
|
|
874
|
+
context.press(event);
|
|
875
|
+
},
|
|
876
|
+
onPointerMove: (event) => {
|
|
877
|
+
callHandler(props.onPointerMove, event);
|
|
878
|
+
if (!event.defaultPrevented) context.drag(event);
|
|
879
|
+
},
|
|
880
|
+
onPointerUp: (event) => {
|
|
881
|
+
callHandler(props.onPointerUp, event);
|
|
882
|
+
context.release(event);
|
|
883
|
+
},
|
|
884
|
+
onPointerCancel: (event) => {
|
|
885
|
+
callHandler(props.onPointerCancel, event);
|
|
886
|
+
context.cancelDrag();
|
|
887
|
+
},
|
|
888
|
+
onLostPointerCapture: (event) => {
|
|
889
|
+
callHandler(props.onLostPointerCapture, event);
|
|
890
|
+
context.cancelDrag();
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
], false);
|
|
894
|
+
ref(() => {
|
|
895
|
+
return [props.ref, (element) => {
|
|
896
|
+
context.setContent(element);
|
|
897
|
+
}];
|
|
898
|
+
}, _el$4);
|
|
899
|
+
runHydrationEvents();
|
|
900
|
+
return _el$4;
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
function Title(props) {
|
|
905
|
+
const context = useContext(DrawerContext);
|
|
906
|
+
var _el$5 = getNextElement(_tmpl$3);
|
|
907
|
+
spread(_el$5, [{ get id() {
|
|
908
|
+
return context.titleId;
|
|
909
|
+
} }, props], false);
|
|
910
|
+
runHydrationEvents();
|
|
911
|
+
return _el$5;
|
|
912
|
+
}
|
|
913
|
+
function Description(props) {
|
|
914
|
+
const context = useContext(DrawerContext);
|
|
915
|
+
var _el$6 = getNextElement(_tmpl$4);
|
|
916
|
+
spread(_el$6, [{ get id() {
|
|
917
|
+
return context.descriptionId;
|
|
918
|
+
} }, props], false);
|
|
919
|
+
runHydrationEvents();
|
|
920
|
+
return _el$6;
|
|
921
|
+
}
|
|
922
|
+
function Handle(props) {
|
|
923
|
+
const context = useContext(DrawerContext);
|
|
924
|
+
const rest = omit(props, "preventCycle", "children", "onClick", "onPointerDown", "onPointerMove", "onPointerCancel");
|
|
925
|
+
let pressTime = 0;
|
|
926
|
+
let pressPosition = {
|
|
927
|
+
x: 0,
|
|
928
|
+
y: 0
|
|
929
|
+
};
|
|
930
|
+
let moved = false;
|
|
931
|
+
let lastClick = -Infinity;
|
|
932
|
+
function cycle() {
|
|
933
|
+
if (props.preventCycle === true || moved || Date.now() - pressTime > 250 || Date.now() - lastClick < 120) return;
|
|
934
|
+
lastClick = Date.now();
|
|
935
|
+
const points = context.props.snapPoints;
|
|
936
|
+
if (!points || points.length === 0) {
|
|
937
|
+
context.close();
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
const next = points[context.activeSnapPointIndex + 1];
|
|
941
|
+
if (next !== void 0) context.setActiveSnapPoint(next);
|
|
942
|
+
else if (context.dismissible) context.close();
|
|
943
|
+
else context.setActiveSnapPoint(points[0] ?? null);
|
|
944
|
+
}
|
|
945
|
+
var _el$7 = getNextElement(_tmpl$5);
|
|
946
|
+
var _el$8 = _el$7.firstChild;
|
|
947
|
+
spread(_el$7, [rest, {
|
|
948
|
+
"data-vaul-handle": "",
|
|
949
|
+
"aria-hidden": "true",
|
|
950
|
+
get "data-vaul-drawer-visible"() {
|
|
951
|
+
return context.isOpen ? "true" : "false";
|
|
952
|
+
},
|
|
953
|
+
onClick: (event) => {
|
|
954
|
+
callHandler(props.onClick, event);
|
|
955
|
+
if (!event.defaultPrevented) cycle();
|
|
956
|
+
},
|
|
957
|
+
onPointerDown: (event) => {
|
|
958
|
+
callHandler(props.onPointerDown, event);
|
|
959
|
+
if (event.defaultPrevented) return;
|
|
960
|
+
pressTime = Date.now();
|
|
961
|
+
pressPosition = {
|
|
962
|
+
x: event.clientX,
|
|
963
|
+
y: event.clientY
|
|
964
|
+
};
|
|
965
|
+
moved = false;
|
|
966
|
+
context.press(event, true);
|
|
967
|
+
event.stopPropagation();
|
|
968
|
+
},
|
|
969
|
+
onPointerMove: (event) => {
|
|
970
|
+
callHandler(props.onPointerMove, event);
|
|
971
|
+
if (Math.abs(event.clientX - pressPosition.x) > 2 || Math.abs(event.clientY - pressPosition.y) > 2) moved = true;
|
|
972
|
+
},
|
|
973
|
+
onPointerCancel: (event) => {
|
|
974
|
+
callHandler(props.onPointerCancel, event);
|
|
975
|
+
moved = true;
|
|
976
|
+
context.cancelDrag();
|
|
977
|
+
}
|
|
978
|
+
}], true);
|
|
979
|
+
insert(_el$8, scope(() => {
|
|
980
|
+
return props.children;
|
|
981
|
+
}));
|
|
982
|
+
runHydrationEvents();
|
|
983
|
+
return _el$7;
|
|
984
|
+
}
|
|
985
|
+
function callHandler(handler, event) {
|
|
986
|
+
if (typeof handler === "function") handler(event);
|
|
987
|
+
else if (handler) handler[0](handler[1], event);
|
|
988
|
+
}
|
|
989
|
+
// src/index.ts
|
|
990
|
+
const Drawer = {
|
|
991
|
+
Close,
|
|
992
|
+
Content,
|
|
993
|
+
Description,
|
|
994
|
+
Handle,
|
|
995
|
+
NestedRoot,
|
|
996
|
+
Overlay,
|
|
997
|
+
Portal,
|
|
998
|
+
Root,
|
|
999
|
+
Title,
|
|
1000
|
+
Trigger
|
|
1001
|
+
};
|
|
1002
|
+
export { Close, Content, Description, Drawer, Handle, NestedRoot, Overlay, Portal, Root, Title, Trigger };
|
|
1003
|
+
|
|
1004
|
+
//# sourceMappingURL=index.js.map
|