Skip to content

Commit b988fca

Browse files
committed
more
1 parent 6ba065c commit b988fca

File tree

5 files changed

+108
-86
lines changed

5 files changed

+108
-86
lines changed

packages/vaul-svelte/src/lib/components/drawer/drawer.svelte

+7-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
onOpenChange = noop,
1515
closeThreshold = DEFAULT_CLOSE_THRESHOLD,
1616
scrollLockTimeout = DEFAULT_SCROLL_LOCK_TIMEOUT,
17-
snapPoints = [],
17+
snapPoints = null,
1818
fadeFromIndex = snapPoints && snapPoints.length - 1,
1919
backgroundColor = "black",
2020
nested = false,
@@ -30,6 +30,7 @@
3030
handleOnly = false,
3131
noBodyStyles = false,
3232
preventScrollRestoration = true,
33+
setBackgroundColorOnScale = true,
3334
...restProps
3435
}: DrawerRootProps = $props();
3536
@@ -65,6 +66,7 @@
6566
handleOnly: box.with(() => handleOnly),
6667
noBodyStyles: box.with(() => noBodyStyles),
6768
preventScrollRestoration: box.with(() => preventScrollRestoration),
69+
setBackgroundColorOnScale: box.with(() => setBackgroundColorOnScale),
6870
});
6971
</script>
7072

@@ -204,7 +206,7 @@
204206
opacity: 1;
205207
}
206208
207-
:global([vaul-handle]) {
209+
:global([data-vaul-handle]) {
208210
display: block;
209211
position: relative;
210212
opacity: 0.8;
@@ -217,15 +219,15 @@
217219
cursor: grab;
218220
}
219221
220-
:global([vaul-handle]:hover, [vaul-handle]:active) {
222+
:global([data-vaul-handle]:hover, [data-vaul-handle]:active) {
221223
opacity: 1;
222224
}
223225
224-
:global([vaul-handle]:active) {
226+
:global([data-vaul-handle]:active) {
225227
cursor: grabbing;
226228
}
227229
228-
:global([vaul-handle-hitarea]) {
230+
:global([data-vaul-handle-hitarea]) {
229231
position: absolute;
230232
left: 50%;
231233
top: 50%;

packages/vaul-svelte/src/lib/components/drawer/types.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ type BaseDrawerRootPropsWithoutHTML = WithChildren<{
4949
* Example [0.2, 0.5, 0.8]. You can also use px values, which doesn't take
5050
* screen height into account.
5151
*/
52-
snapPoints?: (number | string)[];
52+
snapPoints?: (number | string)[] | null;
5353

5454
/**
5555
* Index of a `snapPoint` from which the overlay fade should be applied.
5656
*
5757
* @default snapPoints[snapPoints.length - 1] (last snap point)
5858
*/
59-
fadeFromIndex?: number;
59+
fadeFromIndex?: number | null;
6060

6161
/**
6262
* A callback function that is called when the drawer is dragged
@@ -152,6 +152,13 @@ type BaseDrawerRootPropsWithoutHTML = WithChildren<{
152152
* @default false
153153
*/
154154
noBodyStyles?: boolean;
155+
156+
/**
157+
* When false we don't change body's background color when the drawer is open.
158+
*
159+
* @default true
160+
*/
161+
setBackgroundColorOnScale?: boolean;
155162
}>;
156163

157164
export type DrawerRootPropsWithoutHTML = BaseDrawerRootPropsWithoutHTML &

packages/vaul-svelte/src/lib/position-fixed.svelte.ts

+52-51
Original file line numberDiff line numberDiff line change
@@ -79,62 +79,63 @@ export class PositionFixed {
7979

8080
#setPositionFixed = () => {
8181
// If previousBodyPosition is already set, don't set it again.
82-
if (!(previousBodyPosition === null && this.#open.current && !this.#noBodyStyles.current))
83-
return;
84-
85-
previousBodyPosition = {
86-
position: document.body.style.position,
87-
top: document.body.style.top,
88-
left: document.body.style.left,
89-
height: document.body.style.height,
90-
right: "unset",
91-
};
92-
93-
// Update the dom inside an animation frame
94-
const { scrollX, innerHeight } = window;
95-
96-
document.body.style.setProperty("position", "fixed", "important");
97-
Object.assign(document.body.style, {
98-
top: `${-this.#scrollPos}px`,
99-
left: `${-scrollX}px`,
100-
right: "0px",
101-
height: "auto",
102-
});
103-
104-
setTimeout(
105-
() =>
106-
requestAnimationFrame(() => {
107-
// Attempt to check if the bottom bar appeared due to the position change
108-
const bottomBarHeight = innerHeight - window.innerHeight;
109-
if (bottomBarHeight && this.#scrollPos >= innerHeight) {
110-
// Move the content further up so that the bottom bar doesn't hide it
111-
document.body.style.top = `${-(this.#scrollPos + bottomBarHeight)}px`;
112-
}
113-
}),
114-
300
115-
);
116-
};
82+
if (previousBodyPosition === null && this.#open.current && !this.#noBodyStyles.current) {
83+
previousBodyPosition = {
84+
position: document.body.style.position,
85+
top: document.body.style.top,
86+
left: document.body.style.left,
87+
height: document.body.style.height,
88+
right: "unset",
89+
};
11790

118-
restorePositionSetting = () => {
119-
if (previousBodyPosition === null || this.#noBodyStyles.current) return;
120-
const activeUrl = this.#activeUrl;
91+
// Update the dom inside an animation frame
92+
const { scrollX, innerHeight } = window;
12193

122-
// Convert the position from "px" to Int
123-
const y = -Number.parseInt(document.body.style.top, 10);
124-
const x = -Number.parseInt(document.body.style.left, 10);
94+
document.body.style.setProperty("position", "fixed", "important");
95+
Object.assign(document.body.style, {
96+
top: `${-this.#scrollPos}px`,
97+
left: `${-scrollX}px`,
98+
right: "0px",
99+
height: "auto",
100+
});
125101

126-
// Restore styles
127-
Object.assign(document.body.style, previousBodyPosition);
102+
window.setTimeout(
103+
() =>
104+
window.requestAnimationFrame(() => {
105+
// Attempt to check if the bottom bar appeared due to the position change
106+
const bottomBarHeight = innerHeight - window.innerHeight;
107+
if (bottomBarHeight && this.#scrollPos >= innerHeight) {
108+
// Move the content further up so that the bottom bar doesn't hide it
109+
document.body.style.top = `${-(this.#scrollPos + bottomBarHeight)}px`;
110+
}
111+
}),
112+
300
113+
);
114+
}
115+
};
128116

129-
window.requestAnimationFrame(() => {
130-
if (this.#preventScrollRestoration.current && activeUrl !== window.location.href) {
131-
this.#activeUrl = window.location.href;
132-
return;
133-
}
117+
restorePositionSetting = () => {
118+
if (previousBodyPosition !== null && !this.#noBodyStyles) {
119+
// Convert the position from "px" to Int
120+
const y = -Number.parseInt(document.body.style.top, 10);
121+
const x = -Number.parseInt(document.body.style.left, 10);
122+
123+
// Restore styles
124+
Object.assign(document.body.style, previousBodyPosition);
125+
126+
window.requestAnimationFrame(() => {
127+
if (
128+
this.#preventScrollRestoration.current &&
129+
this.#activeUrl !== window.location.href
130+
) {
131+
this.#activeUrl = window.location.href;
132+
return;
133+
}
134134

135-
window.scrollTo(x, y);
136-
});
135+
window.scrollTo(x, y);
136+
});
137137

138-
previousBodyPosition = null;
138+
previousBodyPosition = null;
139+
}
139140
};
140141
}

packages/vaul-svelte/src/lib/snap-points.svelte.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@ import { setStyles } from "./internal/helpers/index.js";
66
import { TRANSITIONS, VELOCITY_THRESHOLD } from "./internal/constants.js";
77

88
type SnapPointsProps = WritableBoxedValues<{
9-
activeSnapPoint: number | string | null;
9+
activeSnapPoint: number | string | null | undefined;
1010
}> &
1111
ReadableBoxedValues<{
12-
snapPoints: (number | string)[];
13-
fadeFromIndex: number;
12+
snapPoints: (number | string)[] | null;
13+
fadeFromIndex: number | null;
1414
drawerRef: HTMLElement | null;
1515
overlayRef: HTMLElement | null;
1616
direction: DrawerDirection;
1717
}> & {
1818
onSnapPointChange: (activeSnapPointIdx: number) => void;
19-
setActiveSnapPoint: (newValue: number | string | null) => void;
19+
setActiveSnapPoint: (newValue: number | string | null | undefined) => void;
2020
};
2121

2222
export class SnapPoints {
@@ -175,7 +175,8 @@ export class SnapPoints {
175175
velocity: number;
176176
dismissible: boolean;
177177
}) => {
178-
if (this.#fadeFromIndex.current === undefined) return;
178+
if (this.#fadeFromIndex.current === undefined || this.#fadeFromIndex.current === null)
179+
return;
179180
const direction = this.#direction.current;
180181
const activeSnapPointOffset = this.activeSnapPointOffset;
181182
const activeSnapPointIndex = this.activeSnapPointIndex;
@@ -221,6 +222,7 @@ export class SnapPoints {
221222

222223
// Don't do anything if we swipe upwards while being on the last snap point
223224
if (dragDirection > 0 && this.isLastSnapPoint) {
225+
if (!this.#snapPoints.current) return;
224226
this.snapToPoint(this.snapPointsOffset[this.#snapPoints.current.length - 1]);
225227
return;
226228
}
@@ -276,7 +278,8 @@ export class SnapPoints {
276278
!snapPoints ||
277279
typeof activeSnapPointIndex !== "number" ||
278280
!snapPointsOffset ||
279-
fadeFromIndex === undefined
281+
fadeFromIndex === undefined ||
282+
fadeFromIndex === null
280283
)
281284
return null;
282285

packages/vaul-svelte/src/lib/vaul.svelte.ts

+31-22
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,16 @@ const DRAG_CLASS = "vaul-dragging";
2525

2626
export type DrawerDirection = "left" | "right" | "top" | "bottom";
2727

28-
export type OnDragEvent = PointerEvent | TouchEvent;
29-
export type OnDrag = (event: OnDragEvent, percentageDragged: number) => void;
28+
export type OnDrag = (event: PointerEvent, percentageDragged: number) => void;
3029
export type OnReleaseEvent = PointerEvent | MouseEvent | TouchEvent;
31-
export type OnRelease = (event: OnReleaseEvent, open: boolean) => void;
30+
export type OnRelease = (event: PointerEvent, open: boolean) => void;
3231

3332
type DrawerRootStateProps = ReadableBoxedValues<{
3433
closeThreshold: number;
3534
shouldScaleBackground: boolean;
3635
scrollLockTimeout: number;
37-
snapPoints: (string | number)[];
38-
fadeFromIndex: number;
36+
snapPoints: (string | number)[] | null;
37+
fadeFromIndex: number | null;
3938
fixed: boolean;
4039
dismissible: boolean;
4140
direction: DrawerDirection;
@@ -52,7 +51,7 @@ type DrawerRootStateProps = ReadableBoxedValues<{
5251
}> &
5352
WritableBoxedValues<{
5453
open: boolean;
55-
activeSnapPoint: number | string | null;
54+
activeSnapPoint: number | string | null | undefined;
5655
}>;
5756

5857
class DrawerRootState {
@@ -279,7 +278,7 @@ class DrawerRootState {
279278
});
280279
}
281280

282-
setActiveSnapPoint = (newValue: number | string | null) => {
281+
setActiveSnapPoint = (newValue: number | string | null | undefined) => {
283282
this.activeSnapPoint.current = newValue;
284283
};
285284

@@ -625,7 +624,7 @@ class DrawerRootState {
625624
this.dragEndTime = new Date();
626625
};
627626

628-
onRelease = (e: PointerEvent | MouseEvent) => {
627+
onRelease = (e: PointerEvent) => {
629628
const drawerNode = this.drawerNode;
630629
if (!this.isDragging || !drawerNode) return;
631630

@@ -806,6 +805,15 @@ class DrawerRootState {
806805
}
807806
};
808807

808+
onOpenChange = (o: boolean) => {
809+
if (!o) {
810+
this.closeDrawer();
811+
} else {
812+
this.hasBeenOpened = true;
813+
this.setOpen(true);
814+
}
815+
};
816+
809817
createContentState = (props: DrawerContentStateProps) => {
810818
return new DrawerContentState(props, this);
811819
};
@@ -939,9 +947,9 @@ class DrawerContentState {
939947
() =>
940948
({
941949
id: this.#id.current,
942-
"vaul-drawer": "",
943-
"vaul-drawer-direction": this.root.direction.current,
944-
"vaul-drawer-visible": this.root.visible ? "true" : "false",
950+
"data-vaul-drawer": "",
951+
"data-vaul-drawer-direction": this.root.direction.current,
952+
"data-vaul-drawer-visible": this.root.visible ? "true" : "false",
945953
style: this.#style,
946954
onpointerdown: this.#onpointerdown,
947955
onpointermove: this.#onpointermove,
@@ -975,19 +983,19 @@ class DrawerOverlayState {
975983
});
976984
}
977985

978-
#onmouseup = (e: MouseEvent) => {
986+
#onmouseup = (e: PointerEvent) => {
979987
this.root.onRelease(e);
980988
};
981989

982990
props = $derived.by(
983991
() =>
984992
({
985993
id: this.#id.current,
986-
"vaul-drawer-visible": this.root.visible ? "true" : "false",
987-
"vaul-overlay": "",
988-
"vaul-snap-points":
994+
"data-vaul-drawer-visible": this.root.visible ? "true" : "false",
995+
"data-vaul-overlay": "",
996+
"data-vaul-snap-points":
989997
this.root.open.current && this.#hasSnapPoints ? "true" : "false",
990-
"vaul-snap-points-overlay":
998+
"data-vaul-snap-points-overlay":
991999
this.root.open.current && this.root.snapPointState.shouldFade
9921000
? "true"
9931001
: "false",
@@ -1003,13 +1011,14 @@ type DrawerHandleStateProps = WithRefProps &
10031011

10041012
const LONG_HANDLE_PRESS_TIMEOUT = 250;
10051013
const DOUBLE_TAP_TIMEOUT = 120;
1014+
10061015
class DrawerHandleState {
10071016
#id: DrawerHandleStateProps["id"];
10081017
#ref: DrawerHandleStateProps["ref"];
10091018
#preventCycle: DrawerHandleStateProps["preventCycle"];
10101019
root: DrawerRootState;
1011-
#closeTimeoutId: number | null = null;
1012-
#shouldCancelInteractions = false;
1020+
#closeTimeoutId: number | null = $state(null);
1021+
#shouldCancelInteractions = $state(false);
10131022

10141023
constructor(props: DrawerHandleStateProps, root: DrawerRootState) {
10151024
this.#id = props.id;
@@ -1039,7 +1048,7 @@ class DrawerHandleState {
10391048

10401049
handleCycleSnapPoints = () => {
10411050
// prevent accidental taps while resizing drawer
1042-
if (this.root.isDragging || this.#preventCycle || this.#shouldCancelInteractions) {
1051+
if (this.root.isDragging || this.#preventCycle.current || this.#shouldCancelInteractions) {
10431052
this.handleCancelInteraction();
10441053
return;
10451054
}
@@ -1114,8 +1123,8 @@ class DrawerHandleState {
11141123
() =>
11151124
({
11161125
id: this.#id.current,
1117-
"vaul-drawer-visible": this.root.visible ? "true" : "false",
1118-
"vaul-handle": "",
1126+
"data-vaul-drawer-visible": this.root.visible ? "true" : "false",
1127+
"data-vaul-handle": "",
11191128
"aria-hidden": "true",
11201129
onclick: this.#onclick,
11211130
ondblclick: this.#ondblclick,
@@ -1128,7 +1137,7 @@ class DrawerHandleState {
11281137
hitAreaProps = $derived.by(
11291138
() =>
11301139
({
1131-
"vaul-handle-hitarea": "",
1140+
"data-vaul-handle-hitarea": "",
11321141
"aria-hidden": "true",
11331142
}) as const
11341143
);

0 commit comments

Comments
 (0)