@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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 pekochan069
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/NOTICE.txt
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
@solid2-aria/vaul third-party notices
|
|
2
|
+
==============================
|
|
3
|
+
|
|
4
|
+
Derived from Vaul (https://github.com/emilkowalski/vaul), version 1.1.2,
|
|
5
|
+
revision 3e97aac6a38e4481bade71d7233ed6002e80f9b0.
|
|
6
|
+
Copyright (c) 2023 Emil Kowalski.
|
|
7
|
+
The upstream MIT license is reproduced verbatim in VAUL-LICENSE.
|
|
8
|
+
|
|
9
|
+
Source mappings are recorded in each derived source file. Changes replace
|
|
10
|
+
React and Radix Dialog with native Solid 2 reactivity, callback refs, JSX,
|
|
11
|
+
contexts, lifecycle, presence, and DOM events. Drawer geometry, drag damping,
|
|
12
|
+
velocity thresholds, snap selection, background scaling, fixed positioning,
|
|
13
|
+
and directional CSS are adapted from Vaul. CSS also corrects the upstream
|
|
14
|
+
handle selector and supports native touch scrolling and reduced motion.
|
|
15
|
+
Exit motion uses Solid-controlled transitions without competing CSS keyframes.
|
|
16
|
+
Snap entry waits for viewport measurement and starts from the closed position.
|
|
17
|
+
|
|
18
|
+
Vaul's src/use-prevent-scroll.ts identifies Adobe React Spectrum as its
|
|
19
|
+
source. That file is not copied into this package. Accessibility and scroll
|
|
20
|
+
prevention use the separately licensed @solid2-aria/core dependency, whose Adobe
|
|
21
|
+
attribution and Apache-2.0 notices remain with that package.
|
|
22
|
+
|
|
23
|
+
Vaul's React-specific src/use-controllable-state.ts and src/use-composed-refs.ts
|
|
24
|
+
identify Radix UI as their source. Neither file is copied. Controlled signals
|
|
25
|
+
and ref arrays use Solid's native APIs.
|
|
26
|
+
|
|
27
|
+
Tests, build scripts, and the export barrel are independently authored.
|
|
28
|
+
Solid Aria contributions use the MIT license in LICENSE, Copyright (c) 2026
|
|
29
|
+
pekochan069. This license does not replace the upstream license and notices.
|
package/README.md
CHANGED
|
@@ -1,3 +1,153 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @solid2-aria/vaul
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Build unstyled, draggable drawers with Solid 2. This package ports [Vaul](https://github.com/emilkowalski/vaul) 1.1.2 and uses Solid2 Aria for focus management and scroll prevention.
|
|
4
|
+
|
|
5
|
+
## Add a drawer
|
|
6
|
+
|
|
7
|
+
Install the package alongside Solid 2 and its web renderer:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
bun add @solid2-aria/vaul solid-js@^2.0.0-rc.17 @solidjs/web@^2.0.0-rc.17
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Set `jsxImportSource` to `@solidjs/web` in your TypeScript configuration. Import the drawer stylesheet once in your application:
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { Drawer } from "@solid2-aria/vaul";
|
|
17
|
+
|
|
18
|
+
import "@solid2-aria/vaul/style.css";
|
|
19
|
+
|
|
20
|
+
export function Example() {
|
|
21
|
+
return (
|
|
22
|
+
<Drawer.Root>
|
|
23
|
+
<Drawer.Trigger>Open settings</Drawer.Trigger>
|
|
24
|
+
<Drawer.Portal>
|
|
25
|
+
<Drawer.Overlay class="drawer-overlay" />
|
|
26
|
+
<Drawer.Content class="drawer-content">
|
|
27
|
+
<Drawer.Handle />
|
|
28
|
+
<Drawer.Title>Settings</Drawer.Title>
|
|
29
|
+
<Drawer.Description>Change your preferences.</Drawer.Description>
|
|
30
|
+
<Drawer.Close>Done</Drawer.Close>
|
|
31
|
+
</Drawer.Content>
|
|
32
|
+
</Drawer.Portal>
|
|
33
|
+
</Drawer.Root>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Add your layout and colors. The package stylesheet supplies gestures, directional animations, and the handle appearance:
|
|
39
|
+
|
|
40
|
+
```css
|
|
41
|
+
.drawer-overlay {
|
|
42
|
+
position: fixed;
|
|
43
|
+
inset: 0;
|
|
44
|
+
z-index: 40;
|
|
45
|
+
background: rgb(0 0 0 / 40%);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.drawer-content {
|
|
49
|
+
position: fixed;
|
|
50
|
+
right: 0;
|
|
51
|
+
bottom: 0;
|
|
52
|
+
left: 0;
|
|
53
|
+
z-index: 41;
|
|
54
|
+
box-sizing: border-box;
|
|
55
|
+
max-height: 90dvh;
|
|
56
|
+
overflow-y: auto;
|
|
57
|
+
padding: 24px;
|
|
58
|
+
border-radius: 12px 12px 0 0;
|
|
59
|
+
background: white;
|
|
60
|
+
color: black;
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Click **Open settings**, drag toward the bottom edge, or press Escape to close the drawer. To use another direction, set `direction="top"`, `"left"`, or `"right"` on `Drawer.Root` and position your content against that edge.
|
|
65
|
+
|
|
66
|
+
## Control opening and snap points
|
|
67
|
+
|
|
68
|
+
Pass signal values at the JSX boundary. Snap points are visible viewport fractions or pixel strings, ordered from the smallest visible portion to the largest. Give snap-point content the full height or width of its viewport or container:
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import { Drawer } from "@solid2-aria/vaul";
|
|
72
|
+
import type { SnapPoint } from "@solid2-aria/vaul";
|
|
73
|
+
import { createSignal } from "solid-js";
|
|
74
|
+
|
|
75
|
+
export function SnappingDrawer() {
|
|
76
|
+
const [open, setOpen] = createSignal(false);
|
|
77
|
+
const [snap, setSnap] = createSignal<SnapPoint | null>(0.25);
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<Drawer.Root
|
|
81
|
+
open={open()}
|
|
82
|
+
onOpenChange={(value) => {
|
|
83
|
+
setOpen(value);
|
|
84
|
+
}}
|
|
85
|
+
snapPoints={[0.25, 0.5, 1]}
|
|
86
|
+
activeSnapPoint={snap()}
|
|
87
|
+
setActiveSnapPoint={(value) => {
|
|
88
|
+
setSnap(value);
|
|
89
|
+
}}
|
|
90
|
+
fadeFromIndex={2}
|
|
91
|
+
>
|
|
92
|
+
<Drawer.Trigger>Open drawer</Drawer.Trigger>
|
|
93
|
+
<Drawer.Portal>
|
|
94
|
+
<Drawer.Overlay class="drawer-overlay" />
|
|
95
|
+
<Drawer.Content
|
|
96
|
+
class="drawer-content"
|
|
97
|
+
style={{ height: "100dvh", "max-height": "100dvh" }}
|
|
98
|
+
>
|
|
99
|
+
<Drawer.Handle />
|
|
100
|
+
<Drawer.Title>Choose a height</Drawer.Title>
|
|
101
|
+
<Drawer.Description>
|
|
102
|
+
Drag or tap the handle to change the snap point.
|
|
103
|
+
</Drawer.Description>
|
|
104
|
+
<Drawer.Close>Done</Drawer.Close>
|
|
105
|
+
</Drawer.Content>
|
|
106
|
+
</Drawer.Portal>
|
|
107
|
+
</Drawer.Root>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Set `snapToSequentialPoint` to keep each gesture within the adjacent snap points. Add `data-vaul-no-drag` to controls that must not initiate dragging. Set `handleOnly` on the root to restrict dragging to `Drawer.Handle`.
|
|
113
|
+
|
|
114
|
+
For a nested drawer, put `Drawer.NestedRoot` inside the parent content and give it its own trigger, portal, overlay, and content. Use higher stacking levels for the nested overlay and content.
|
|
115
|
+
|
|
116
|
+
To scale the page while a drawer opens, add `data-vaul-drawer-wrapper` to the page container and set `shouldScaleBackground` on the root. Keep the portal outside that wrapper.
|
|
117
|
+
|
|
118
|
+
## Compose a custom trigger
|
|
119
|
+
|
|
120
|
+
Use `render` on `Drawer.Trigger` or `Drawer.Close` in place of React's `asChild`. Spread the supplied props onto your button to retain its ref, events, and ARIA attributes:
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
<Drawer.Trigger
|
|
124
|
+
render={(attributes) => (
|
|
125
|
+
<button {...attributes} class="primary-button">
|
|
126
|
+
Open
|
|
127
|
+
</button>
|
|
128
|
+
)}
|
|
129
|
+
/>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Use Solid's `class` prop and callback refs. Content event handlers can call `preventDefault()` to cancel Escape dismissal, outside dismissal, or automatic focus.
|
|
133
|
+
|
|
134
|
+
Portals mount after the client settles, so server rendering and hydration do not access `document`. For server-rendered inline content, omit `Drawer.Portal`.
|
|
135
|
+
|
|
136
|
+
## Verify the package
|
|
137
|
+
|
|
138
|
+
From this directory:
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
bun install
|
|
142
|
+
bun run check-types
|
|
143
|
+
bun test --conditions=browser --conditions=development --preload ./tests/setup.ts
|
|
144
|
+
bun run check
|
|
145
|
+
bun run build
|
|
146
|
+
bun run check-build
|
|
147
|
+
bunx playwright install chromium
|
|
148
|
+
bun run check-browser
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`check-build` installs only the shipped files into a temporary consumer and checks server rendering, hydration, exports, and consumer types. `check-browser` drives the built package in Chromium.
|
|
152
|
+
|
|
153
|
+
See the [API reference](docs/api.md) for defaults and component props. The upstream revision, source attribution, and modifications are recorded in [NOTICE.txt](NOTICE.txt). Solid Aria contributions use the [MIT license](LICENSE). Vaul's original MIT license is preserved in [VAUL-LICENSE](VAUL-LICENSE).
|
package/VAUL-LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Emil Kowalski
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,107 @@
|
|
|
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 { JSX } from "@solidjs/web";
|
|
8
|
+
type DrawerDirection = "top" | "bottom" | "left" | "right";
|
|
9
|
+
type SnapPoint = number | string;
|
|
10
|
+
interface WithFadeFromProps {
|
|
11
|
+
/** Visible viewport fractions (0–1) or pixel lengths, ordered smallest first. */
|
|
12
|
+
snapPoints: readonly SnapPoint[];
|
|
13
|
+
fadeFromIndex: number;
|
|
14
|
+
}
|
|
15
|
+
interface WithoutFadeFromProps {
|
|
16
|
+
snapPoints?: readonly SnapPoint[];
|
|
17
|
+
fadeFromIndex?: never;
|
|
18
|
+
}
|
|
19
|
+
type DialogProps = {
|
|
20
|
+
children?: JSX.Element;
|
|
21
|
+
open?: boolean;
|
|
22
|
+
defaultOpen?: boolean;
|
|
23
|
+
onOpenChange?: (open: boolean) => void;
|
|
24
|
+
onClose?: () => void;
|
|
25
|
+
onAnimationEnd?: (open: boolean) => void;
|
|
26
|
+
activeSnapPoint?: SnapPoint | null;
|
|
27
|
+
setActiveSnapPoint?: (point: SnapPoint | null) => void;
|
|
28
|
+
closeThreshold?: number;
|
|
29
|
+
scrollLockTimeout?: number;
|
|
30
|
+
dismissible?: boolean;
|
|
31
|
+
modal?: boolean;
|
|
32
|
+
nested?: boolean;
|
|
33
|
+
direction?: DrawerDirection;
|
|
34
|
+
handleOnly?: boolean;
|
|
35
|
+
shouldScaleBackground?: boolean;
|
|
36
|
+
setBackgroundColorOnScale?: boolean;
|
|
37
|
+
noBodyStyles?: boolean;
|
|
38
|
+
fixed?: boolean;
|
|
39
|
+
/** Enables the additional mobile input scroll prevention. */
|
|
40
|
+
disablePreventScroll?: boolean;
|
|
41
|
+
repositionInputs?: boolean;
|
|
42
|
+
snapToSequentialPoint?: boolean;
|
|
43
|
+
container?: HTMLElement | null;
|
|
44
|
+
preventScrollRestoration?: boolean;
|
|
45
|
+
autoFocus?: boolean;
|
|
46
|
+
onDrag?: (event: PointerEvent, percentageDragged: number) => void;
|
|
47
|
+
onRelease?: (event: PointerEvent, open: boolean) => void;
|
|
48
|
+
} & (WithFadeFromProps | WithoutFadeFromProps);
|
|
49
|
+
type DrawerProps = DialogProps;
|
|
50
|
+
type PointerDownOutsideEvent = CustomEvent<{
|
|
51
|
+
originalEvent: PointerEvent;
|
|
52
|
+
}>;
|
|
53
|
+
type FocusOutsideEvent = CustomEvent<{
|
|
54
|
+
originalEvent: FocusEvent;
|
|
55
|
+
}>;
|
|
56
|
+
type InteractOutsideEvent = PointerDownOutsideEvent | FocusOutsideEvent;
|
|
57
|
+
type ContentProps = JSX.HTMLAttributes<HTMLDivElement> & {
|
|
58
|
+
forceMount?: boolean;
|
|
59
|
+
onOpenAutoFocus?: (event: Event) => void;
|
|
60
|
+
onCloseAutoFocus?: (event: Event) => void;
|
|
61
|
+
onEscapeKeyDown?: (event: KeyboardEvent) => void;
|
|
62
|
+
onPointerDownOutside?: (event: PointerDownOutsideEvent) => void;
|
|
63
|
+
onFocusOutside?: (event: FocusOutsideEvent) => void;
|
|
64
|
+
onInteractOutside?: (event: InteractOutsideEvent) => void;
|
|
65
|
+
};
|
|
66
|
+
type OverlayProps = JSX.HTMLAttributes<HTMLDivElement> & {
|
|
67
|
+
forceMount?: boolean;
|
|
68
|
+
};
|
|
69
|
+
type HandleProps = JSX.HTMLAttributes<HTMLDivElement> & {
|
|
70
|
+
preventCycle?: boolean;
|
|
71
|
+
};
|
|
72
|
+
type TriggerProps = JSX.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
73
|
+
/** Compose a custom button by spreading these reactive props onto it. */
|
|
74
|
+
render?: (props: JSX.ButtonHTMLAttributes<HTMLButtonElement>) => JSX.Element;
|
|
75
|
+
};
|
|
76
|
+
type CloseProps = TriggerProps;
|
|
77
|
+
type TitleProps = JSX.HTMLAttributes<HTMLHeadingElement>;
|
|
78
|
+
type DescriptionProps = JSX.HTMLAttributes<HTMLParagraphElement>;
|
|
79
|
+
interface PortalProps {
|
|
80
|
+
children?: JSX.Element;
|
|
81
|
+
container?: HTMLElement | null;
|
|
82
|
+
forceMount?: boolean;
|
|
83
|
+
}
|
|
84
|
+
export declare function Root(props: DialogProps): JSX.Element;
|
|
85
|
+
export declare function NestedRoot(props: DialogProps): JSX.Element;
|
|
86
|
+
export declare function Portal(props: PortalProps): JSX.Element;
|
|
87
|
+
export declare function Trigger(props: TriggerProps): JSX.Element;
|
|
88
|
+
export declare function Close(props: CloseProps): JSX.Element;
|
|
89
|
+
export declare function Overlay(props: OverlayProps): JSX.Element;
|
|
90
|
+
export declare function Content(props: ContentProps): JSX.Element;
|
|
91
|
+
export declare function Title(props: TitleProps): JSX.Element;
|
|
92
|
+
export declare function Description(props: DescriptionProps): JSX.Element;
|
|
93
|
+
export declare function Handle(props: HandleProps): JSX.Element;
|
|
94
|
+
export declare const Drawer: {
|
|
95
|
+
Close: typeof Close;
|
|
96
|
+
Content: typeof Content;
|
|
97
|
+
Description: typeof Description;
|
|
98
|
+
Handle: typeof Handle;
|
|
99
|
+
NestedRoot: typeof NestedRoot;
|
|
100
|
+
Overlay: typeof Overlay;
|
|
101
|
+
Portal: typeof Portal;
|
|
102
|
+
Root: typeof Root;
|
|
103
|
+
Title: typeof Title;
|
|
104
|
+
Trigger: typeof Trigger;
|
|
105
|
+
};
|
|
106
|
+
export type { CloseProps, ContentProps, DescriptionProps, DialogProps, DrawerDirection, DrawerProps, FocusOutsideEvent, HandleProps, InteractOutsideEvent, OverlayProps, PointerDownOutsideEvent, PortalProps, SnapPoint, TitleProps, TriggerProps, WithFadeFromProps, WithoutFadeFromProps };
|
|
107
|
+
//# sourceMappingURL=index.d.ts.map
|