css-drawer 0.1.4 → 0.2.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/README.md CHANGED
@@ -58,7 +58,7 @@ function App() {
58
58
 
59
59
  ```ts
60
60
  import { open, close } from 'css-drawer'
61
- import 'css-drawer/styles'
61
+ // Styles are auto-injected
62
62
 
63
63
  document.querySelector('#open-btn').onclick = () => open('my-drawer')
64
64
  ```
@@ -68,7 +68,7 @@ document.querySelector('#open-btn').onclick = () => open('my-drawer')
68
68
 
69
69
  <dialog class="drawer" id="my-drawer">
70
70
  <div class="drawer-handle"></div>
71
- <div className="drawer-content">
71
+ <div class="drawer-content">
72
72
  <h2>Title</h2>
73
73
  <p>Description</p>
74
74
  <button onclick="this.closest('dialog').close()">Close</button>
@@ -76,6 +76,44 @@ document.querySelector('#open-btn').onclick = () => open('my-drawer')
76
76
  </dialog>
77
77
  ```
78
78
 
79
+ ### Angular
80
+
81
+ Angular's build system doesn't process CSS imports from JS modules. Import styles in your global `styles.css`:
82
+
83
+ ```css
84
+ /* src/styles.css */
85
+ @import 'css-drawer/styles';
86
+ ```
87
+
88
+ Then use the native dialog API in your component:
89
+
90
+ ```typescript
91
+ import { Component } from '@angular/core';
92
+
93
+ @Component({
94
+ selector: 'app-example',
95
+ template: `
96
+ <button (click)="openDrawer(drawer)">Open</button>
97
+
98
+ <dialog #drawer class="drawer" data-direction="modal">
99
+ <div class="drawer-content">
100
+ <h2>Title</h2>
101
+ <button (click)="closeDrawer(drawer)">Close</button>
102
+ </div>
103
+ </dialog>
104
+ `
105
+ })
106
+ export class ExampleComponent {
107
+ openDrawer(dialog: HTMLDialogElement) {
108
+ dialog.showModal();
109
+ }
110
+
111
+ closeDrawer(dialog: HTMLDialogElement) {
112
+ dialog.close();
113
+ }
114
+ }
115
+ ```
116
+
79
117
  ---
80
118
 
81
119
  ## React API
@@ -99,7 +137,7 @@ Provides context for direction. Wrap your drawer content.
99
137
 
100
138
  | Prop | Type | Default | Description |
101
139
  |------|------|---------|-------------|
102
- | `direction` | `'bottom' \| 'top' \| 'left' \| 'right'` | `'bottom'` | Direction the drawer opens from |
140
+ | `direction` | `'bottom' \| 'top' \| 'left' \| 'right' \| 'modal'` | `'bottom'` | Direction the drawer opens from |
103
141
  | `children` | `ReactNode` | - | Drawer content |
104
142
 
105
143
  ### Drawer.Content
@@ -193,7 +231,7 @@ Semantic description for accessibility.
193
231
 
194
232
  ```ts
195
233
  import { open, close, closeAll } from 'css-drawer'
196
- import 'css-drawer/styles'
234
+ // Styles are auto-injected
197
235
  ```
198
236
 
199
237
  ### open(drawer)
@@ -286,6 +324,7 @@ open(drawer)
286
324
  |--------|------|---------|-------------|
287
325
  | `id` | `string` | - | Drawer ID |
288
326
  | `content` | `string` | `''` | HTML content |
327
+ | `direction` | `DrawerDirection` | `'bottom'` | Direction the drawer opens from |
289
328
  | `handle` | `boolean` | `true` | Include drag handle |
290
329
  | `className` | `string` | `''` | Additional CSS classes |
291
330
  | `closeOnOutsideClick` | `boolean` | `true` | Close when clicking outside |
@@ -377,6 +416,7 @@ const isMobile = useMediaQuery('(max-width: 768px)')
377
416
  | `top` | Opens from top |
378
417
  | `left` | Opens from left |
379
418
  | `right` | Opens from right |
419
+ | `modal` | Centered modal with scale animation |
380
420
 
381
421
  ---
382
422
 
@@ -384,7 +424,9 @@ const isMobile = useMediaQuery('(max-width: 768px)')
384
424
 
385
425
  Drawers automatically stack when opened. No configuration needed.
386
426
 
387
- ### With Refs
427
+ ### Recommended: Sibling Pattern
428
+
429
+ For the best visual stacking effect (scale + dim), place drawers as **siblings** in the DOM:
388
430
 
389
431
  ```tsx
390
432
  const drawer1 = useRef<HTMLDialogElement>(null)
@@ -396,6 +438,16 @@ drawer1.current?.showModal()
396
438
  // Open drawer2 on top
397
439
  drawer2.current?.showModal()
398
440
  // drawer1 automatically scales down and dims
441
+
442
+ <>
443
+ <Drawer.Root>
444
+ <Drawer.Content ref={drawer1}>First drawer</Drawer.Content>
445
+ </Drawer.Root>
446
+
447
+ <Drawer.Root>
448
+ <Drawer.Content ref={drawer2}>Second drawer (sibling)</Drawer.Content>
449
+ </Drawer.Root>
450
+ </>
399
451
  ```
400
452
 
401
453
  ### With Controlled State
@@ -428,6 +480,28 @@ const [confirmOpen, setConfirmOpen] = useState(false)
428
480
 
429
481
  Works up to 5 levels. CSS `:has()` selectors handle the visual stacking.
430
482
 
483
+ ### DOM-Nested Dialogs
484
+
485
+ You can also nest a drawer inside another drawer's content (DOM nesting). This pattern works functionally—close events, buttons, and accessibility all work correctly—but the **automatic CSS scaling effect is not applied** to DOM-nested dialogs.
486
+
487
+ ```tsx
488
+ // DOM-nested: works but no auto-scaling
489
+ <Drawer.Root>
490
+ <Drawer.Content open={parentOpen} onOpenChange={setParentOpen}>
491
+ <p>Parent content</p>
492
+
493
+ {/* Child nested inside parent */}
494
+ <Drawer.Root>
495
+ <Drawer.Content open={childOpen} onOpenChange={setChildOpen}>
496
+ <p>Child content</p>
497
+ </Drawer.Content>
498
+ </Drawer.Root>
499
+ </Drawer.Content>
500
+ </Drawer.Root>
501
+ ```
502
+
503
+ Use the **sibling pattern** if you want the visual stacking effect.
504
+
431
505
  ---
432
506
 
433
507
  ## Accessibility
@@ -508,6 +582,7 @@ Override any of these CSS custom properties to customize the drawer:
508
582
  --drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.12), 0 4px 20px hsl(0 0% 0% / 0.08);
509
583
  --drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.12), -4px 0 20px hsl(0 0% 0% / 0.08);
510
584
  --drawer-shadow-left: 10px 0 60px hsl(0 0% 0% / 0.12), 4px 0 20px hsl(0 0% 0% / 0.08);
585
+ --drawer-shadow-modal: 0 25px 50px -12px hsl(0 0% 0% / 0.25);
511
586
 
512
587
  /* Animation */
513
588
  --drawer-duration: 0.5s;
@@ -561,6 +636,7 @@ Override any of these CSS custom properties to customize the drawer:
561
636
  | `--drawer-shadow-top` | `0 10px 60px hsl(0 0% 0% / 0.12), ...` | Darker |
562
637
  | `--drawer-shadow-left` | `10px 0 60px hsl(0 0% 0% / 0.12), ...` | Darker |
563
638
  | `--drawer-shadow-right` | `-10px 0 60px hsl(0 0% 0% / 0.12), ...` | Darker |
639
+ | `--drawer-shadow-modal` | `0 25px 50px -12px hsl(0 0% 0% / 0.25)` | Darker |
564
640
 
565
641
  #### Animation
566
642
 
@@ -731,6 +807,7 @@ Uses `@starting-style`, `:has()`, `allow-discrete`, and `dvh` units.
731
807
  Full TypeScript support included.
732
808
 
733
809
  ```tsx
810
+ // React
734
811
  import {
735
812
  Drawer,
736
813
  type DrawerRootProps,
@@ -738,11 +815,14 @@ import {
738
815
  type DrawerDirection
739
816
  } from 'css-drawer/react'
740
817
 
818
+ // Vanilla JS
741
819
  import {
742
820
  open,
743
821
  close,
822
+ create,
744
823
  type DrawerElement,
745
- type DrawerRef
824
+ type DrawerRef,
825
+ type DrawerDirection
746
826
  } from 'css-drawer'
747
827
  ```
748
828
 
File without changes
@@ -0,0 +1,331 @@
1
+ /* CSS Drawer - Vaul-quality drawer with auto-nesting and directions */
2
+
3
+ :root {
4
+ /* Visual */
5
+ --drawer-bg: #fff;
6
+ --drawer-radius: 24px;
7
+ --drawer-backdrop: hsl(0 0% 0% / 0.4);
8
+ --drawer-backdrop-blur: 4px;
9
+
10
+ /* Sizing */
11
+ --drawer-max-width: 500px;
12
+ --drawer-max-height: 96dvh;
13
+
14
+ /* Handle */
15
+ --drawer-handle-bg: hsl(0 0% 80%);
16
+ --drawer-handle-bg-hover: hsl(0 0% 60%);
17
+ --drawer-handle-width: 48px;
18
+ --drawer-handle-width-hover: 56px;
19
+ --drawer-handle-height: 5px;
20
+ --drawer-handle-padding-block: 1rem 0.5rem;
21
+ --drawer-handle-padding-inline: 0;
22
+
23
+ /* Shadows */
24
+ --drawer-shadow-bottom: 0 -10px 60px hsl(0 0% 0% / 0.12), 0 -4px 20px hsl(0 0% 0% / 0.08);
25
+ --drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.12), 0 4px 20px hsl(0 0% 0% / 0.08);
26
+ --drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.12), -4px 0 20px hsl(0 0% 0% / 0.08);
27
+ --drawer-shadow-left: 10px 0 60px hsl(0 0% 0% / 0.12), 4px 0 20px hsl(0 0% 0% / 0.08);
28
+ --drawer-shadow-modal: 0 25px 50px -12px hsl(0 0% 0% / 0.25);
29
+
30
+ /* Animation */
31
+ --drawer-duration: 0.5s;
32
+ --drawer-duration-close: 0.35s;
33
+ --drawer-ease: cubic-bezier(0.32, 0.72, 0, 1);
34
+
35
+ /* Nesting effects */
36
+ --drawer-nested-scale: 0.94;
37
+ --drawer-nested-offset: 20px;
38
+ --drawer-nested-brightness: 0.92;
39
+ --drawer-nested-backdrop: hsl(0 0% 0% / 0.15);
40
+ }
41
+
42
+ @media (prefers-color-scheme: dark) {
43
+ :root {
44
+ --drawer-bg: hsl(0 0% 12%);
45
+ --drawer-handle-bg: hsl(0 0% 35%);
46
+ --drawer-handle-bg-hover: hsl(0 0% 50%);
47
+ --drawer-shadow-bottom: 0 -10px 60px hsl(0 0% 0% / 0.4), 0 -4px 20px hsl(0 0% 0% / 0.3);
48
+ --drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.4), 0 4px 20px hsl(0 0% 0% / 0.3);
49
+ --drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.4), -4px 0 20px hsl(0 0% 0% / 0.3);
50
+ --drawer-shadow-left: 10px 0 60px hsl(0 0% 0% / 0.4), 4px 0 20px hsl(0 0% 0% / 0.3);
51
+ --drawer-shadow-modal: 0 25px 50px -12px hsl(0 0% 0% / 0.5);
52
+ }
53
+ }
54
+
55
+ /* Background scale effect */
56
+ body {
57
+ transition: scale var(--drawer-duration) var(--drawer-ease), border-radius var(--drawer-duration) var(--drawer-ease);
58
+ transform-origin: center top;
59
+ }
60
+
61
+ body:has(.drawer[open]) {
62
+ overflow: hidden;
63
+ scale: var(--drawer-nested-scale);
64
+ border-radius: var(--drawer-radius);
65
+ }
66
+
67
+ /* Base drawer */
68
+ .drawer {
69
+ border: none;
70
+ padding: 0;
71
+ margin: 0;
72
+ max-width: 100%;
73
+ max-height: 100%;
74
+ position: fixed;
75
+ background: var(--drawer-bg);
76
+ overflow: hidden;
77
+ opacity: 0;
78
+ transition:
79
+ display var(--drawer-duration-close) allow-discrete,
80
+ overlay var(--drawer-duration-close) allow-discrete,
81
+ translate var(--drawer-duration-close) var(--drawer-ease),
82
+ scale var(--drawer-duration-close) var(--drawer-ease),
83
+ filter var(--drawer-duration-close) ease,
84
+ opacity var(--drawer-duration-close) ease;
85
+
86
+ /* Default: bottom */
87
+ --_translate-closed: 0 100%;
88
+ --_border-radius: var(--drawer-radius) var(--drawer-radius) 0 0;
89
+ inset: auto 0 0 0;
90
+ margin-inline: auto;
91
+ width: 100%;
92
+ max-width: var(--drawer-max-width);
93
+ height: auto;
94
+ max-height: var(--drawer-max-height);
95
+ border-radius: var(--drawer-border-radius, var(--_border-radius));
96
+ box-shadow: var(--drawer-shadow-bottom);
97
+ translate: var(--_translate-closed);
98
+ }
99
+
100
+ .drawer::backdrop {
101
+ background: var(--drawer-backdrop);
102
+ opacity: 0;
103
+ backdrop-filter: blur(var(--drawer-backdrop-blur));
104
+ -webkit-backdrop-filter: blur(var(--drawer-backdrop-blur));
105
+ transition:
106
+ display var(--drawer-duration-close) allow-discrete,
107
+ overlay var(--drawer-duration-close) allow-discrete,
108
+ opacity var(--drawer-duration-close) ease;
109
+ }
110
+
111
+ .drawer[open] {
112
+ opacity: 1;
113
+ translate: 0 0;
114
+ transition:
115
+ display var(--drawer-duration) allow-discrete,
116
+ overlay var(--drawer-duration) allow-discrete,
117
+ translate var(--drawer-duration) var(--drawer-ease),
118
+ scale var(--drawer-duration) var(--drawer-ease),
119
+ filter var(--drawer-duration) ease,
120
+ opacity 0.15s ease;
121
+ }
122
+
123
+ .drawer[open]::backdrop {
124
+ opacity: 1;
125
+ transition: display var(--drawer-duration) allow-discrete, overlay var(--drawer-duration) allow-discrete, opacity 0.2s ease;
126
+ }
127
+
128
+ @starting-style {
129
+ .drawer[open] { opacity: 0; translate: var(--_translate-closed); }
130
+ .drawer[open]::backdrop { opacity: 0; }
131
+ }
132
+
133
+ /* ===== DIRECTIONS ===== */
134
+
135
+ /* Right */
136
+ .drawer[data-direction="right"] {
137
+ --_translate-closed: 100% 0;
138
+ --_border-radius: var(--drawer-radius) 0 0 var(--drawer-radius);
139
+ inset: 0 0 0 auto;
140
+ margin: 0;
141
+ width: 100%;
142
+ max-width: var(--drawer-max-width);
143
+ height: 100dvh;
144
+ max-height: 100dvh;
145
+ box-shadow: var(--drawer-shadow-right);
146
+ }
147
+
148
+ /* Left */
149
+ .drawer[data-direction="left"] {
150
+ --_translate-closed: -100% 0;
151
+ --_border-radius: 0 var(--drawer-radius) var(--drawer-radius) 0;
152
+ inset: 0 auto 0 0;
153
+ margin: 0;
154
+ width: 100%;
155
+ max-width: var(--drawer-max-width);
156
+ height: 100dvh;
157
+ max-height: 100dvh;
158
+ box-shadow: var(--drawer-shadow-left);
159
+ }
160
+
161
+ /* Top */
162
+ .drawer[data-direction="top"] {
163
+ --_translate-closed: 0 -100%;
164
+ --_border-radius: 0 0 var(--drawer-radius) var(--drawer-radius);
165
+ inset: 0 0 auto 0;
166
+ margin-inline: auto;
167
+ width: 100%;
168
+ max-width: var(--drawer-max-width);
169
+ height: auto;
170
+ max-height: var(--drawer-max-height);
171
+ box-shadow: var(--drawer-shadow-top);
172
+ }
173
+
174
+ /* Modal (centered) */
175
+ .drawer[data-direction="modal"] {
176
+ --_translate-closed: 0 0;
177
+ --_border-radius: var(--drawer-radius);
178
+ inset: 0;
179
+ margin: auto;
180
+ width: fit-content;
181
+ max-width: var(--drawer-max-width);
182
+ height: fit-content;
183
+ max-height: var(--drawer-max-height);
184
+ box-shadow: var(--drawer-shadow-modal);
185
+ scale: var(--drawer-nested-scale);
186
+ }
187
+
188
+ .drawer[data-direction="modal"][open] {
189
+ scale: 1;
190
+ }
191
+
192
+ @starting-style {
193
+ .drawer[data-direction="modal"][open] {
194
+ scale: var(--drawer-nested-scale);
195
+ }
196
+ }
197
+
198
+ /* ===== AUTO-NESTING (up to 5 levels) ===== */
199
+ /* Uses sibling combinators to count open drawers */
200
+
201
+ /* 1+ open drawers after */
202
+ .drawer[open]:has(~ .drawer[open]) {
203
+ scale: var(--drawer-nested-scale);
204
+ translate: 0 calc(-1 * var(--drawer-nested-offset));
205
+ border-radius: var(--drawer-radius);
206
+ filter: brightness(var(--drawer-nested-brightness));
207
+ pointer-events: none;
208
+ }
209
+
210
+ /* 2+ open drawers after */
211
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open]) {
212
+ scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale));
213
+ translate: 0 calc(-2 * var(--drawer-nested-offset));
214
+ filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));
215
+ }
216
+
217
+ /* 3+ open drawers after */
218
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {
219
+ scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));
220
+ translate: 0 calc(-3 * var(--drawer-nested-offset));
221
+ filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));
222
+ }
223
+
224
+ /* 4+ open drawers after */
225
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {
226
+ scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));
227
+ translate: 0 calc(-4 * var(--drawer-nested-offset));
228
+ filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));
229
+ }
230
+
231
+ /* 5+ open drawers after */
232
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {
233
+ scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));
234
+ translate: 0 calc(-5 * var(--drawer-nested-offset));
235
+ filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));
236
+ }
237
+
238
+ /* Lighter backdrop for stacked drawers */
239
+ .drawer[open] ~ .drawer[open]::backdrop {
240
+ background: var(--drawer-nested-backdrop);
241
+ backdrop-filter: none;
242
+ }
243
+
244
+ /* Handle */
245
+ .drawer-handle {
246
+ display: flex;
247
+ justify-content: center;
248
+ padding-block: var(--drawer-handle-padding-block);
249
+ padding-inline: var(--drawer-handle-padding-inline);
250
+ cursor: grab;
251
+ }
252
+
253
+ .drawer-handle::before {
254
+ content: '';
255
+ width: var(--drawer-handle-width);
256
+ height: var(--drawer-handle-height);
257
+ background: var(--drawer-handle-bg);
258
+ border-radius: 100px;
259
+ transition: width 0.2s var(--drawer-ease), height 0.2s var(--drawer-ease), background 0.2s ease;
260
+ }
261
+
262
+ .drawer-handle:hover::before {
263
+ width: var(--drawer-handle-width-hover);
264
+ background: var(--drawer-handle-bg-hover);
265
+ }
266
+
267
+ /* Vertical handle for left/right drawers */
268
+ .drawer[data-direction="left"] .drawer-handle,
269
+ .drawer[data-direction="right"] .drawer-handle {
270
+ flex-direction: column;
271
+ align-items: center;
272
+ justify-content: center;
273
+ padding-block: var(--drawer-handle-padding-inline);
274
+ padding-inline: var(--drawer-handle-padding-block);
275
+ height: 100%;
276
+ position: absolute;
277
+ top: 0;
278
+ writing-mode: vertical-lr;
279
+ }
280
+
281
+ .drawer[data-direction="left"] .drawer-handle { right: 0; }
282
+ .drawer[data-direction="right"] .drawer-handle { left: 0; }
283
+
284
+ .drawer[data-direction="left"] .drawer-handle::before,
285
+ .drawer[data-direction="right"] .drawer-handle::before {
286
+ width: var(--drawer-handle-height);
287
+ height: var(--drawer-handle-width);
288
+ }
289
+
290
+ .drawer[data-direction="left"] .drawer-handle:hover::before,
291
+ .drawer[data-direction="right"] .drawer-handle:hover::before {
292
+ width: var(--drawer-handle-height);
293
+ height: var(--drawer-handle-width-hover);
294
+ }
295
+
296
+ /* Content - structural only, no opinionated padding */
297
+ .drawer-content {
298
+ overflow-x: hidden;
299
+ overflow-y: auto;
300
+ overscroll-behavior: contain;
301
+ flex: 1;
302
+ min-height: 0;
303
+ }
304
+
305
+ /* Content sizing for directions */
306
+ .drawer[data-direction="left"] .drawer-content,
307
+ .drawer[data-direction="right"] .drawer-content {
308
+ height: 100%;
309
+ }
310
+
311
+ /* Reduced motion */
312
+ @media (prefers-reduced-motion: reduce) {
313
+ *, *::before, *::after {
314
+ transition-duration: 0.01ms !important;
315
+ }
316
+
317
+ body:has(.drawer[open]) {
318
+ scale: 1;
319
+ }
320
+
321
+ .drawer[open]:has(~ .drawer[open]),
322
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open]),
323
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open]),
324
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]),
325
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {
326
+ scale: 1;
327
+ translate: 0 0;
328
+ filter: none;
329
+ }
330
+ }
331
+
@@ -0,0 +1,333 @@
1
+ /* CSS Drawer - Vaul-quality drawer with auto-nesting and directions */
2
+
3
+ :root {
4
+ /* Visual */
5
+ --drawer-bg: #fff;
6
+ --drawer-radius: 24px;
7
+ --drawer-backdrop: hsl(0 0% 0% / 0.4);
8
+ --drawer-backdrop-blur: 4px;
9
+
10
+ /* Sizing */
11
+ --drawer-max-width: 500px;
12
+ --drawer-max-height: 96dvh;
13
+
14
+ /* Handle */
15
+ --drawer-handle-bg: hsl(0 0% 80%);
16
+ --drawer-handle-bg-hover: hsl(0 0% 60%);
17
+ --drawer-handle-width: 48px;
18
+ --drawer-handle-width-hover: 56px;
19
+ --drawer-handle-height: 5px;
20
+ --drawer-handle-padding-block: 1rem 0.5rem;
21
+ --drawer-handle-padding-inline: 0;
22
+
23
+ /* Shadows */
24
+ --drawer-shadow-bottom: 0 -10px 60px hsl(0 0% 0% / 0.12), 0 -4px 20px hsl(0 0% 0% / 0.08);
25
+ --drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.12), 0 4px 20px hsl(0 0% 0% / 0.08);
26
+ --drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.12), -4px 0 20px hsl(0 0% 0% / 0.08);
27
+ --drawer-shadow-left: 10px 0 60px hsl(0 0% 0% / 0.12), 4px 0 20px hsl(0 0% 0% / 0.08);
28
+ --drawer-shadow-modal: 0 25px 50px -12px hsl(0 0% 0% / 0.25);
29
+
30
+ /* Animation */
31
+ --drawer-duration: 0.5s;
32
+ --drawer-duration-close: 0.35s;
33
+ --drawer-ease: cubic-bezier(0.32, 0.72, 0, 1);
34
+
35
+ /* Nesting effects */
36
+ --drawer-nested-scale: 0.94;
37
+ --drawer-nested-offset: 20px;
38
+ --drawer-nested-brightness: 0.92;
39
+ --drawer-nested-backdrop: hsl(0 0% 0% / 0.15);
40
+ }
41
+
42
+ @media (prefers-color-scheme: dark) {
43
+ :root {
44
+ --drawer-bg: hsl(0 0% 12%);
45
+ --drawer-handle-bg: hsl(0 0% 35%);
46
+ --drawer-handle-bg-hover: hsl(0 0% 50%);
47
+ --drawer-shadow-bottom: 0 -10px 60px hsl(0 0% 0% / 0.4), 0 -4px 20px hsl(0 0% 0% / 0.3);
48
+ --drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.4), 0 4px 20px hsl(0 0% 0% / 0.3);
49
+ --drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.4), -4px 0 20px hsl(0 0% 0% / 0.3);
50
+ --drawer-shadow-left: 10px 0 60px hsl(0 0% 0% / 0.4), 4px 0 20px hsl(0 0% 0% / 0.3);
51
+ --drawer-shadow-modal: 0 25px 50px -12px hsl(0 0% 0% / 0.5);
52
+ }
53
+ }
54
+
55
+ /* Background scale effect */
56
+ body {
57
+ transition: scale var(--drawer-duration) var(--drawer-ease), border-radius var(--drawer-duration) var(--drawer-ease);
58
+ transform-origin: center top;
59
+ }
60
+
61
+ body:has(.drawer[open]) {
62
+ overflow: hidden;
63
+ scale: var(--drawer-nested-scale);
64
+ border-radius: var(--drawer-radius);
65
+ }
66
+
67
+ /* Base drawer */
68
+ .drawer {
69
+ border: none;
70
+ padding: 0;
71
+ margin: 0;
72
+ max-width: 100%;
73
+ max-height: 100%;
74
+ position: fixed;
75
+ background: var(--drawer-bg);
76
+ overflow: hidden;
77
+ opacity: 0;
78
+ transition:
79
+ display var(--drawer-duration-close) allow-discrete,
80
+ overlay var(--drawer-duration-close) allow-discrete,
81
+ translate var(--drawer-duration-close) var(--drawer-ease),
82
+ scale var(--drawer-duration-close) var(--drawer-ease),
83
+ filter var(--drawer-duration-close) ease,
84
+ opacity var(--drawer-duration-close) ease;
85
+
86
+ /* Default: bottom */
87
+ --_translate-closed: 0 100%;
88
+ --_border-radius: var(--drawer-radius) var(--drawer-radius) 0 0;
89
+ inset: auto 0 0 0;
90
+ margin-inline: auto;
91
+ width: 100%;
92
+ max-width: var(--drawer-max-width);
93
+ height: auto;
94
+ max-height: var(--drawer-max-height);
95
+ border-radius: var(--drawer-border-radius, var(--_border-radius));
96
+ box-shadow: var(--drawer-shadow-bottom);
97
+ translate: var(--_translate-closed);
98
+ }
99
+
100
+ .drawer::backdrop {
101
+ background: var(--drawer-backdrop);
102
+ opacity: 0;
103
+ backdrop-filter: blur(var(--drawer-backdrop-blur));
104
+ -webkit-backdrop-filter: blur(var(--drawer-backdrop-blur));
105
+ transition:
106
+ display var(--drawer-duration-close) allow-discrete,
107
+ overlay var(--drawer-duration-close) allow-discrete,
108
+ opacity var(--drawer-duration-close) ease;
109
+ }
110
+
111
+ .drawer[open] {
112
+ opacity: 1;
113
+ translate: 0 0;
114
+ transition:
115
+ display var(--drawer-duration) allow-discrete,
116
+ overlay var(--drawer-duration) allow-discrete,
117
+ translate var(--drawer-duration) var(--drawer-ease),
118
+ scale var(--drawer-duration) var(--drawer-ease),
119
+ filter var(--drawer-duration) ease,
120
+ opacity 0.15s ease;
121
+ }
122
+
123
+ .drawer[open]::backdrop {
124
+ opacity: 1;
125
+ transition: display var(--drawer-duration) allow-discrete, overlay var(--drawer-duration) allow-discrete, opacity 0.2s ease;
126
+ }
127
+
128
+ @starting-style {
129
+ .drawer[open] { opacity: 0; translate: var(--_translate-closed); }
130
+ .drawer[open]::backdrop { opacity: 0; }
131
+ }
132
+
133
+ /* ===== DIRECTIONS ===== */
134
+
135
+ /* Right */
136
+ .drawer[data-direction="right"] {
137
+ --_translate-closed: 100% 0;
138
+ --_border-radius: var(--drawer-radius) 0 0 var(--drawer-radius);
139
+ inset: 0 0 0 auto;
140
+ margin: 0;
141
+ width: 100%;
142
+ max-width: var(--drawer-max-width);
143
+ height: 100dvh;
144
+ max-height: 100dvh;
145
+ box-shadow: var(--drawer-shadow-right);
146
+ }
147
+
148
+ /* Left */
149
+ .drawer[data-direction="left"] {
150
+ --_translate-closed: -100% 0;
151
+ --_border-radius: 0 var(--drawer-radius) var(--drawer-radius) 0;
152
+ inset: 0 auto 0 0;
153
+ margin: 0;
154
+ width: 100%;
155
+ max-width: var(--drawer-max-width);
156
+ height: 100dvh;
157
+ max-height: 100dvh;
158
+ box-shadow: var(--drawer-shadow-left);
159
+ }
160
+
161
+ /* Top */
162
+ .drawer[data-direction="top"] {
163
+ --_translate-closed: 0 -100%;
164
+ --_border-radius: 0 0 var(--drawer-radius) var(--drawer-radius);
165
+ inset: 0 0 auto 0;
166
+ margin-inline: auto;
167
+ width: 100%;
168
+ max-width: var(--drawer-max-width);
169
+ height: auto;
170
+ max-height: var(--drawer-max-height);
171
+ box-shadow: var(--drawer-shadow-top);
172
+ }
173
+
174
+ /* Modal (centered) */
175
+ .drawer[data-direction="modal"] {
176
+ --_translate-closed: 0 0;
177
+ --_border-radius: var(--drawer-radius);
178
+ inset: 0;
179
+ margin: auto;
180
+ width: fit-content;
181
+ max-width: var(--drawer-max-width);
182
+ height: fit-content;
183
+ max-height: var(--drawer-max-height);
184
+ box-shadow: var(--drawer-shadow-modal);
185
+ scale: var(--drawer-nested-scale);
186
+ }
187
+
188
+ .drawer[data-direction="modal"][open] {
189
+ scale: 1;
190
+ }
191
+
192
+ @starting-style {
193
+ .drawer[data-direction="modal"][open] {
194
+ scale: var(--drawer-nested-scale);
195
+ }
196
+ }
197
+
198
+ /* ===== AUTO-NESTING (up to 5 levels) ===== */
199
+ /* Uses sibling combinators to count open drawers */
200
+
201
+ /* 1+ open drawers after */
202
+ .drawer[open]:has(~ .drawer[open]) {
203
+ scale: var(--drawer-nested-scale);
204
+ translate: 0 calc(-1 * var(--drawer-nested-offset));
205
+ border-radius: var(--drawer-radius);
206
+ filter: brightness(var(--drawer-nested-brightness));
207
+ pointer-events: none;
208
+ }
209
+
210
+ /* 2+ open drawers after */
211
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open]) {
212
+ scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale));
213
+ translate: 0 calc(-2 * var(--drawer-nested-offset));
214
+ filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));
215
+ }
216
+
217
+ /* 3+ open drawers after */
218
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {
219
+ scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));
220
+ translate: 0 calc(-3 * var(--drawer-nested-offset));
221
+ filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));
222
+ }
223
+
224
+ /* 4+ open drawers after */
225
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {
226
+ scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));
227
+ translate: 0 calc(-4 * var(--drawer-nested-offset));
228
+ filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));
229
+ }
230
+
231
+ /* 5+ open drawers after */
232
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {
233
+ scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));
234
+ translate: 0 calc(-5 * var(--drawer-nested-offset));
235
+ filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));
236
+ }
237
+
238
+ /* Lighter backdrop for stacked drawers */
239
+ .drawer[open] ~ .drawer[open]::backdrop {
240
+ background: var(--drawer-nested-backdrop);
241
+ backdrop-filter: none;
242
+ }
243
+
244
+ /* Handle */
245
+ .drawer-handle {
246
+ display: flex;
247
+ justify-content: center;
248
+ padding-block: var(--drawer-handle-padding-block);
249
+ padding-inline: var(--drawer-handle-padding-inline);
250
+ cursor: grab;
251
+ }
252
+
253
+ .drawer-handle::before {
254
+ content: '';
255
+ width: var(--drawer-handle-width);
256
+ height: var(--drawer-handle-height);
257
+ background: var(--drawer-handle-bg);
258
+ border-radius: 100px;
259
+ transition: width 0.2s var(--drawer-ease), height 0.2s var(--drawer-ease), background 0.2s ease;
260
+ }
261
+
262
+ .drawer-handle:hover::before {
263
+ width: var(--drawer-handle-width-hover);
264
+ background: var(--drawer-handle-bg-hover);
265
+ }
266
+
267
+ /* Vertical handle for left/right drawers */
268
+ .drawer[data-direction="left"] .drawer-handle,
269
+ .drawer[data-direction="right"] .drawer-handle {
270
+ flex-direction: column;
271
+ align-items: center;
272
+ justify-content: center;
273
+ padding-block: var(--drawer-handle-padding-inline);
274
+ padding-inline: var(--drawer-handle-padding-block);
275
+ height: 100%;
276
+ position: absolute;
277
+ top: 0;
278
+ writing-mode: vertical-lr;
279
+ }
280
+
281
+ .drawer[data-direction="left"] .drawer-handle { right: 0; }
282
+ .drawer[data-direction="right"] .drawer-handle { left: 0; }
283
+
284
+ .drawer[data-direction="left"] .drawer-handle::before,
285
+ .drawer[data-direction="right"] .drawer-handle::before {
286
+ width: var(--drawer-handle-height);
287
+ height: var(--drawer-handle-width);
288
+ }
289
+
290
+ .drawer[data-direction="left"] .drawer-handle:hover::before,
291
+ .drawer[data-direction="right"] .drawer-handle:hover::before {
292
+ width: var(--drawer-handle-height);
293
+ height: var(--drawer-handle-width-hover);
294
+ }
295
+
296
+ /* Content - structural only, no opinionated padding */
297
+ .drawer-content {
298
+ overflow-x: hidden;
299
+ overflow-y: auto;
300
+ overscroll-behavior: contain;
301
+ flex: 1;
302
+ min-height: 0;
303
+ }
304
+
305
+ /* Content sizing for directions */
306
+ .drawer[data-direction="left"] .drawer-content,
307
+ .drawer[data-direction="right"] .drawer-content {
308
+ height: 100%;
309
+ }
310
+
311
+ /* Reduced motion */
312
+ @media (prefers-reduced-motion: reduce) {
313
+ *, *::before, *::after {
314
+ transition-duration: 0.01ms !important;
315
+ }
316
+
317
+ body:has(.drawer[open]) {
318
+ scale: 1;
319
+ }
320
+
321
+ .drawer[open]:has(~ .drawer[open]),
322
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open]),
323
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open]),
324
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]),
325
+ .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {
326
+ scale: 1;
327
+ translate: 0 0;
328
+ filter: none;
329
+ }
330
+ }
331
+
332
+
333
+ /*# sourceMappingURL=drawer-CXCJQa45.css.map*/
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drawer-CXCJQa45.css","names":[],"sources":["../src/drawer.css"],"sourcesContent":["/* CSS Drawer - Vaul-quality drawer with auto-nesting and directions */\n\n:root {\n /* Visual */\n --drawer-bg: #fff;\n --drawer-radius: 24px;\n --drawer-backdrop: hsl(0 0% 0% / 0.4);\n --drawer-backdrop-blur: 4px;\n\n /* Sizing */\n --drawer-max-width: 500px;\n --drawer-max-height: 96dvh;\n\n /* Handle */\n --drawer-handle-bg: hsl(0 0% 80%);\n --drawer-handle-bg-hover: hsl(0 0% 60%);\n --drawer-handle-width: 48px;\n --drawer-handle-width-hover: 56px;\n --drawer-handle-height: 5px;\n --drawer-handle-padding-block: 1rem 0.5rem;\n --drawer-handle-padding-inline: 0;\n\n /* Shadows */\n --drawer-shadow-bottom: 0 -10px 60px hsl(0 0% 0% / 0.12), 0 -4px 20px hsl(0 0% 0% / 0.08);\n --drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.12), 0 4px 20px hsl(0 0% 0% / 0.08);\n --drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.12), -4px 0 20px hsl(0 0% 0% / 0.08);\n --drawer-shadow-left: 10px 0 60px hsl(0 0% 0% / 0.12), 4px 0 20px hsl(0 0% 0% / 0.08);\n --drawer-shadow-modal: 0 25px 50px -12px hsl(0 0% 0% / 0.25);\n\n /* Animation */\n --drawer-duration: 0.5s;\n --drawer-duration-close: 0.35s;\n --drawer-ease: cubic-bezier(0.32, 0.72, 0, 1);\n\n /* Nesting effects */\n --drawer-nested-scale: 0.94;\n --drawer-nested-offset: 20px;\n --drawer-nested-brightness: 0.92;\n --drawer-nested-backdrop: hsl(0 0% 0% / 0.15);\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --drawer-bg: hsl(0 0% 12%);\n --drawer-handle-bg: hsl(0 0% 35%);\n --drawer-handle-bg-hover: hsl(0 0% 50%);\n --drawer-shadow-bottom: 0 -10px 60px hsl(0 0% 0% / 0.4), 0 -4px 20px hsl(0 0% 0% / 0.3);\n --drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.4), 0 4px 20px hsl(0 0% 0% / 0.3);\n --drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.4), -4px 0 20px hsl(0 0% 0% / 0.3);\n --drawer-shadow-left: 10px 0 60px hsl(0 0% 0% / 0.4), 4px 0 20px hsl(0 0% 0% / 0.3);\n --drawer-shadow-modal: 0 25px 50px -12px hsl(0 0% 0% / 0.5);\n }\n}\n\n/* Background scale effect */\nbody {\n transition: scale var(--drawer-duration) var(--drawer-ease), border-radius var(--drawer-duration) var(--drawer-ease);\n transform-origin: center top;\n}\n\nbody:has(.drawer[open]) {\n overflow: hidden;\n scale: var(--drawer-nested-scale);\n border-radius: var(--drawer-radius);\n}\n\n/* Base drawer */\n.drawer {\n border: none;\n padding: 0;\n margin: 0;\n max-width: 100%;\n max-height: 100%;\n position: fixed;\n background: var(--drawer-bg);\n overflow: hidden;\n opacity: 0;\n transition:\n display var(--drawer-duration-close) allow-discrete,\n overlay var(--drawer-duration-close) allow-discrete,\n translate var(--drawer-duration-close) var(--drawer-ease),\n scale var(--drawer-duration-close) var(--drawer-ease),\n filter var(--drawer-duration-close) ease,\n opacity var(--drawer-duration-close) ease;\n\n /* Default: bottom */\n --_translate-closed: 0 100%;\n --_border-radius: var(--drawer-radius) var(--drawer-radius) 0 0;\n inset: auto 0 0 0;\n margin-inline: auto;\n width: 100%;\n max-width: var(--drawer-max-width);\n height: auto;\n max-height: var(--drawer-max-height);\n border-radius: var(--drawer-border-radius, var(--_border-radius));\n box-shadow: var(--drawer-shadow-bottom);\n translate: var(--_translate-closed);\n}\n\n.drawer::backdrop {\n background: var(--drawer-backdrop);\n opacity: 0;\n backdrop-filter: blur(var(--drawer-backdrop-blur));\n -webkit-backdrop-filter: blur(var(--drawer-backdrop-blur));\n transition:\n display var(--drawer-duration-close) allow-discrete,\n overlay var(--drawer-duration-close) allow-discrete,\n opacity var(--drawer-duration-close) ease;\n}\n\n.drawer[open] {\n opacity: 1;\n translate: 0 0;\n transition:\n display var(--drawer-duration) allow-discrete,\n overlay var(--drawer-duration) allow-discrete,\n translate var(--drawer-duration) var(--drawer-ease),\n scale var(--drawer-duration) var(--drawer-ease),\n filter var(--drawer-duration) ease,\n opacity 0.15s ease;\n}\n\n.drawer[open]::backdrop {\n opacity: 1;\n transition: display var(--drawer-duration) allow-discrete, overlay var(--drawer-duration) allow-discrete, opacity 0.2s ease;\n}\n\n@starting-style {\n .drawer[open] { opacity: 0; translate: var(--_translate-closed); }\n .drawer[open]::backdrop { opacity: 0; }\n}\n\n/* ===== DIRECTIONS ===== */\n\n/* Right */\n.drawer[data-direction=\"right\"] {\n --_translate-closed: 100% 0;\n --_border-radius: var(--drawer-radius) 0 0 var(--drawer-radius);\n inset: 0 0 0 auto;\n margin: 0;\n width: 100%;\n max-width: var(--drawer-max-width);\n height: 100dvh;\n max-height: 100dvh;\n box-shadow: var(--drawer-shadow-right);\n}\n\n/* Left */\n.drawer[data-direction=\"left\"] {\n --_translate-closed: -100% 0;\n --_border-radius: 0 var(--drawer-radius) var(--drawer-radius) 0;\n inset: 0 auto 0 0;\n margin: 0;\n width: 100%;\n max-width: var(--drawer-max-width);\n height: 100dvh;\n max-height: 100dvh;\n box-shadow: var(--drawer-shadow-left);\n}\n\n/* Top */\n.drawer[data-direction=\"top\"] {\n --_translate-closed: 0 -100%;\n --_border-radius: 0 0 var(--drawer-radius) var(--drawer-radius);\n inset: 0 0 auto 0;\n margin-inline: auto;\n width: 100%;\n max-width: var(--drawer-max-width);\n height: auto;\n max-height: var(--drawer-max-height);\n box-shadow: var(--drawer-shadow-top);\n}\n\n/* Modal (centered) */\n.drawer[data-direction=\"modal\"] {\n --_translate-closed: 0 0;\n --_border-radius: var(--drawer-radius);\n inset: 0;\n margin: auto;\n width: fit-content;\n max-width: var(--drawer-max-width);\n height: fit-content;\n max-height: var(--drawer-max-height);\n box-shadow: var(--drawer-shadow-modal);\n scale: var(--drawer-nested-scale);\n}\n\n.drawer[data-direction=\"modal\"][open] {\n scale: 1;\n}\n\n@starting-style {\n .drawer[data-direction=\"modal\"][open] {\n scale: var(--drawer-nested-scale);\n }\n}\n\n/* ===== AUTO-NESTING (up to 5 levels) ===== */\n/* Uses sibling combinators to count open drawers */\n\n/* 1+ open drawers after */\n.drawer[open]:has(~ .drawer[open]) {\n scale: var(--drawer-nested-scale);\n translate: 0 calc(-1 * var(--drawer-nested-offset));\n border-radius: var(--drawer-radius);\n filter: brightness(var(--drawer-nested-brightness));\n pointer-events: none;\n}\n\n/* 2+ open drawers after */\n.drawer[open]:has(~ .drawer[open] ~ .drawer[open]) {\n scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale));\n translate: 0 calc(-2 * var(--drawer-nested-offset));\n filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));\n}\n\n/* 3+ open drawers after */\n.drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {\n scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));\n translate: 0 calc(-3 * var(--drawer-nested-offset));\n filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));\n}\n\n/* 4+ open drawers after */\n.drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {\n scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));\n translate: 0 calc(-4 * var(--drawer-nested-offset));\n filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));\n}\n\n/* 5+ open drawers after */\n.drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {\n scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));\n translate: 0 calc(-5 * var(--drawer-nested-offset));\n filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));\n}\n\n/* Lighter backdrop for stacked drawers */\n.drawer[open] ~ .drawer[open]::backdrop {\n background: var(--drawer-nested-backdrop);\n backdrop-filter: none;\n}\n\n/* Handle */\n.drawer-handle {\n display: flex;\n justify-content: center;\n padding-block: var(--drawer-handle-padding-block);\n padding-inline: var(--drawer-handle-padding-inline);\n cursor: grab;\n}\n\n.drawer-handle::before {\n content: '';\n width: var(--drawer-handle-width);\n height: var(--drawer-handle-height);\n background: var(--drawer-handle-bg);\n border-radius: 100px;\n transition: width 0.2s var(--drawer-ease), height 0.2s var(--drawer-ease), background 0.2s ease;\n}\n\n.drawer-handle:hover::before {\n width: var(--drawer-handle-width-hover);\n background: var(--drawer-handle-bg-hover);\n}\n\n/* Vertical handle for left/right drawers */\n.drawer[data-direction=\"left\"] .drawer-handle,\n.drawer[data-direction=\"right\"] .drawer-handle {\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding-block: var(--drawer-handle-padding-inline);\n padding-inline: var(--drawer-handle-padding-block);\n height: 100%;\n position: absolute;\n top: 0;\n writing-mode: vertical-lr;\n}\n\n.drawer[data-direction=\"left\"] .drawer-handle { right: 0; }\n.drawer[data-direction=\"right\"] .drawer-handle { left: 0; }\n\n.drawer[data-direction=\"left\"] .drawer-handle::before,\n.drawer[data-direction=\"right\"] .drawer-handle::before {\n width: var(--drawer-handle-height);\n height: var(--drawer-handle-width);\n}\n\n.drawer[data-direction=\"left\"] .drawer-handle:hover::before,\n.drawer[data-direction=\"right\"] .drawer-handle:hover::before {\n width: var(--drawer-handle-height);\n height: var(--drawer-handle-width-hover);\n}\n\n/* Content - structural only, no opinionated padding */\n.drawer-content {\n overflow-x: hidden;\n overflow-y: auto;\n overscroll-behavior: contain;\n flex: 1;\n min-height: 0;\n}\n\n/* Content sizing for directions */\n.drawer[data-direction=\"left\"] .drawer-content,\n.drawer[data-direction=\"right\"] .drawer-content {\n height: 100%;\n}\n\n/* Reduced motion */\n@media (prefers-reduced-motion: reduce) {\n *, *::before, *::after {\n transition-duration: 0.01ms !important;\n }\n\n body:has(.drawer[open]) {\n scale: 1;\n }\n\n .drawer[open]:has(~ .drawer[open]),\n .drawer[open]:has(~ .drawer[open] ~ .drawer[open]),\n .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open]),\n .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]),\n .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {\n scale: 1;\n translate: 0 0;\n filter: none;\n }\n}\n"],"mappings":"AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
@@ -0,0 +1 @@
1
+ export{};
package/dist/index.cjs CHANGED
@@ -1,4 +1,5 @@
1
- if(typeof window<`u`){let e=()=>{let e=Array.from(document.querySelectorAll(`dialog.drawer[open]`));e.forEach((t,n)=>{n===e.length-1?t.removeAttribute(`inert`):t.setAttribute(`inert`,``)})};new MutationObserver(t=>{for(let n of t)if(n.type===`attributes`&&n.attributeName===`open`&&n.target.classList.contains(`drawer`)){e();break}}).observe(document.body,{subtree:!0,attributes:!0,attributeFilter:[`open`]})}function e(e){return e?typeof e==`string`?document.getElementById(e):e:null}function t(t){e(t)?.showModal()}function n(t){e(t)?.close()}function r(){Array.from(document.querySelectorAll(`dialog.drawer[open]`)).reverse().forEach(e=>e.close())}function i(t){return e(t)?.open??!1}function a(){return Array.from(document.querySelectorAll(`dialog.drawer[open]`))}function o(){let e=a();return e[e.length-1]??null}function s(e={}){let{id:t,content:n=``,handle:r=!0,className:i=``,closeOnOutsideClick:a=!0}=e,o=document.createElement(`dialog`);return o.className=`drawer ${i}`.trim(),t&&(o.id=t),a||(o.dataset.closeOnOutsideClick=`false`),o.innerHTML=`
2
- ${r?`<div class="drawer-handle"></div>`:``}
1
+ require('./drawer-C21nwiwE.css');
2
+ if(require(`./drawer-BWZh2Fyp.cjs`),typeof window<`u`){let e=()=>{let e=Array.from(document.querySelectorAll(`dialog.drawer[open]`));e.forEach((t,n)=>{n===e.length-1?t.removeAttribute(`inert`):t.setAttribute(`inert`,``)})};new MutationObserver(t=>{for(let n of t)if(n.type===`attributes`&&n.attributeName===`open`&&n.target.classList.contains(`drawer`)){e();break}}).observe(document.body,{subtree:!0,attributes:!0,attributeFilter:[`open`]})}function e(e){return e?typeof e==`string`?document.getElementById(e):e:null}function t(t){e(t)?.showModal()}function n(t){e(t)?.close()}function r(){Array.from(document.querySelectorAll(`dialog.drawer[open]`)).reverse().forEach(e=>e.close())}function i(t){return e(t)?.open??!1}function a(){return Array.from(document.querySelectorAll(`dialog.drawer[open]`))}function o(){let e=a();return e[e.length-1]??null}function s(e={}){let{id:t,content:n=``,direction:r,handle:i=!0,className:a=``,closeOnOutsideClick:o=!0}=e,s=document.createElement(`dialog`);return s.className=`drawer ${a}`.trim(),t&&(s.id=t),r&&(s.dataset.direction=r),o||(s.dataset.closeOnOutsideClick=`false`),s.innerHTML=`
3
+ ${i?`<div class="drawer-handle"></div>`:``}
3
4
  <div class="drawer-content">${n}</div>
4
- `,o.addEventListener(`click`,e=>{e.target===o&&o.dataset.closeOnOutsideClick!==`false`&&o.close()}),o}function c(e){return document.body.appendChild(e),e}function l(t){e(t)?.remove()}function u(){let e=e=>{let t=e.target;t.matches(`dialog.drawer`)&&t.dataset.closeOnOutsideClick!==`false`&&t.close()};return document.addEventListener(`click`,e),()=>document.removeEventListener(`click`,e)}function d(t,n){let r=e(t);if(!r)return()=>{};let{onOpen:i,onClose:a,onCancel:o}=n,s=()=>a?.(),c=()=>o?.(),l=new MutationObserver(e=>{for(let t of e)t.attributeName===`open`&&r.open&&i?.()});return r.addEventListener(`close`,s),r.addEventListener(`cancel`,c),l.observe(r,{attributes:!0}),()=>{r.removeEventListener(`close`,s),r.removeEventListener(`cancel`,c),l.disconnect()}}function f(e,t){let n=t?.closeOnOutsideClick??!0;return{id:e,className:`drawer`,"data-close-on-outside-click":n?void 0:`false`,onClick:e=>{n&&e.target===e.currentTarget&&e.currentTarget.close()}}}exports.close=n,exports.closeAll=r,exports.create=s,exports.getOpen=a,exports.getTop=o,exports.init=u,exports.isOpen=i,exports.mount=c,exports.open=t,exports.props=f,exports.subscribe=d,exports.unmount=l;
5
+ `,s.addEventListener(`click`,e=>{e.target===s&&s.dataset.closeOnOutsideClick!==`false`&&s.close()}),s}function c(e){return document.body.appendChild(e),e}function l(t){e(t)?.remove()}function u(){let e=e=>{let t=e.target;t.matches(`dialog.drawer`)&&t.dataset.closeOnOutsideClick!==`false`&&t.close()};return document.addEventListener(`click`,e),()=>document.removeEventListener(`click`,e)}function d(t,n){let r=e(t);if(!r)return()=>{};let{onOpen:i,onClose:a,onCancel:o}=n,s=()=>a?.(),c=()=>o?.(),l=new MutationObserver(e=>{for(let t of e)t.attributeName===`open`&&r.open&&i?.()});return r.addEventListener(`close`,s),r.addEventListener(`cancel`,c),l.observe(r,{attributes:!0}),()=>{r.removeEventListener(`close`,s),r.removeEventListener(`cancel`,c),l.disconnect()}}function f(e,t){let n=t?.closeOnOutsideClick??!0;return{id:e,className:`drawer`,"data-close-on-outside-click":n?void 0:`false`,onClick:e=>{n&&e.target===e.currentTarget&&e.currentTarget.close()}}}exports.close=n,exports.closeAll=r,exports.create=s,exports.getOpen=a,exports.getTop=o,exports.init=u,exports.isOpen=i,exports.mount=c,exports.open=t,exports.props=f,exports.subscribe=d,exports.unmount=l;
package/dist/index.d.cts CHANGED
@@ -1,15 +1,15 @@
1
1
  //#region src/index.d.ts
2
- /**
3
- * CSS Drawer - Headless drawer component
4
- * Works with any framework: React, Vue, Svelte, vanilla JS
5
- */
2
+
6
3
  type DrawerElement = HTMLDialogElement;
7
4
  type DrawerRef = string | DrawerElement | null | undefined;
5
+ type DrawerDirection = 'bottom' | 'top' | 'left' | 'right' | 'modal';
8
6
  interface CreateDrawerOptions {
9
7
  /** Drawer ID */
10
8
  id?: string;
11
9
  /** HTML content for the drawer */
12
10
  content?: string;
11
+ /** Direction the drawer opens from (default: 'bottom') */
12
+ direction?: DrawerDirection;
13
13
  /** Include drag handle (default: true) */
14
14
  handle?: boolean;
15
15
  /** Additional CSS classes */
@@ -85,5 +85,5 @@ declare function props(id: string, options?: {
85
85
  readonly onClick: (e: MouseEvent) => void;
86
86
  };
87
87
  //#endregion
88
- export { CreateDrawerOptions, DrawerElement, DrawerEventHandlers, DrawerRef, close, closeAll, create, getOpen, getTop, init, isOpen, mount, open, props, subscribe, unmount };
88
+ export { CreateDrawerOptions, DrawerDirection, DrawerElement, DrawerEventHandlers, DrawerRef, close, closeAll, create, getOpen, getTop, init, isOpen, mount, open, props, subscribe, unmount };
89
89
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;AAwCA;AAEA;AAEA;AAaiB,KAjBL,aAAA,GAAgB,iBAiBQ;AAuBpB,KAtCJ,SAAA,GAsCiB,MAAA,GAtCI,aAsCK,GAAA,IAAA,GAAA,SAAA;AAQtB,UA5CC,mBAAA,CA4CsB;EAQvB;EAQA,EAAA,CAAA,EAAA,MAAM;EAQN;EAOA,OAAA,CAAA,EAAM,MAAA;EAQN;EA4BA,MAAA,CAAA,EAAK,OAAA;EAQL;EAUA,SAAI,CAAA,EAAA,MAAA;EAgBJ;EAoCA,mBAAK,CAMJ,EAAA,OAAA;;UA9KA,mBAAA;;;;;;;;;;;iBAuBD,IAAA,SAAa;;;;iBAQb,KAAA,SAAc;;;;iBAQd,QAAA,CAAA;;;;iBAQA,MAAA,SAAe;;;;iBAQf,OAAA,CAAA,GAAW;;;;iBAOX,MAAA,CAAA,GAAU;;;;iBAQV,MAAA,WAAgB,sBAA2B;;;;iBA4B3C,KAAA,SAAc,gBAAgB;;;;iBAQ9B,OAAA,SAAgB;;;;;;iBAUhB,IAAA,CAAA;;;;;iBAgBA,SAAA,SACN,qBACE;;;;;iBAkCI,KAAA;;;;;;wBAMC"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;AA8DiB,KArBL,aAAA,GAAgB,iBAqBQ;AAuBpB,KA1CJ,SAAA,GA0CiB,MAAA,GA1CI,aA0CK,GAAA,IAAA,GAAA,SAAA;AAQtB,KAhDJ,eAAA,GAgDkB,QAAS,GAAA,KAAA,GAAA,MAAA,GAAA,OAAA,GAAA,OAAA;AAQvB,UAtDC,mBAAA,CAsDO;EAQR;EAQA,EAAA,CAAA,EAAA,MAAO;EAOP;EAQA,OAAA,CAAA,EAAM,MAAA;EA6BN;EAQA,SAAA,CAAO,EApHT,eAoHkB;EAUhB;EAgBA,MAAA,CAAA,EAAA,OAAS;EAoCT;;;;;UAzKC,mBAAA;;;;;;;;;;;iBAuBD,IAAA,SAAa;;;;iBAQb,KAAA,SAAc;;;;iBAQd,QAAA,CAAA;;;;iBAQA,MAAA,SAAe;;;;iBAQf,OAAA,CAAA,GAAW;;;;iBAOX,MAAA,CAAA,GAAU;;;;iBAQV,MAAA,WAAgB,sBAA2B;;;;iBA6B3C,KAAA,SAAc,gBAAgB;;;;iBAQ9B,OAAA,SAAgB;;;;;;iBAUhB,IAAA,CAAA;;;;;iBAgBA,SAAA,SACN,qBACE;;;;;iBAkCI,KAAA;;;;;;wBAMC"}
package/dist/index.d.mts CHANGED
@@ -1,15 +1,15 @@
1
1
  //#region src/index.d.ts
2
- /**
3
- * CSS Drawer - Headless drawer component
4
- * Works with any framework: React, Vue, Svelte, vanilla JS
5
- */
2
+
6
3
  type DrawerElement = HTMLDialogElement;
7
4
  type DrawerRef = string | DrawerElement | null | undefined;
5
+ type DrawerDirection = 'bottom' | 'top' | 'left' | 'right' | 'modal';
8
6
  interface CreateDrawerOptions {
9
7
  /** Drawer ID */
10
8
  id?: string;
11
9
  /** HTML content for the drawer */
12
10
  content?: string;
11
+ /** Direction the drawer opens from (default: 'bottom') */
12
+ direction?: DrawerDirection;
13
13
  /** Include drag handle (default: true) */
14
14
  handle?: boolean;
15
15
  /** Additional CSS classes */
@@ -85,5 +85,5 @@ declare function props(id: string, options?: {
85
85
  readonly onClick: (e: MouseEvent) => void;
86
86
  };
87
87
  //#endregion
88
- export { CreateDrawerOptions, DrawerElement, DrawerEventHandlers, DrawerRef, close, closeAll, create, getOpen, getTop, init, isOpen, mount, open, props, subscribe, unmount };
88
+ export { CreateDrawerOptions, DrawerDirection, DrawerElement, DrawerEventHandlers, DrawerRef, close, closeAll, create, getOpen, getTop, init, isOpen, mount, open, props, subscribe, unmount };
89
89
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;AAwCA;AAEA;AAEA;AAaiB,KAjBL,aAAA,GAAgB,iBAiBQ;AAuBpB,KAtCJ,SAAA,GAsCiB,MAAA,GAtCI,aAsCK,GAAA,IAAA,GAAA,SAAA;AAQtB,UA5CC,mBAAA,CA4CsB;EAQvB;EAQA,EAAA,CAAA,EAAA,MAAM;EAQN;EAOA,OAAA,CAAA,EAAM,MAAA;EAQN;EA4BA,MAAA,CAAA,EAAK,OAAA;EAQL;EAUA,SAAI,CAAA,EAAA,MAAA;EAgBJ;EAoCA,mBAAK,CAMJ,EAAA,OAAA;;UA9KA,mBAAA;;;;;;;;;;;iBAuBD,IAAA,SAAa;;;;iBAQb,KAAA,SAAc;;;;iBAQd,QAAA,CAAA;;;;iBAQA,MAAA,SAAe;;;;iBAQf,OAAA,CAAA,GAAW;;;;iBAOX,MAAA,CAAA,GAAU;;;;iBAQV,MAAA,WAAgB,sBAA2B;;;;iBA4B3C,KAAA,SAAc,gBAAgB;;;;iBAQ9B,OAAA,SAAgB;;;;;;iBAUhB,IAAA,CAAA;;;;;iBAgBA,SAAA,SACN,qBACE;;;;;iBAkCI,KAAA;;;;;;wBAMC"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;AA8DiB,KArBL,aAAA,GAAgB,iBAqBQ;AAuBpB,KA1CJ,SAAA,GA0CiB,MAAA,GA1CI,aA0CK,GAAA,IAAA,GAAA,SAAA;AAQtB,KAhDJ,eAAA,GAgDkB,QAAS,GAAA,KAAA,GAAA,MAAA,GAAA,OAAA,GAAA,OAAA;AAQvB,UAtDC,mBAAA,CAsDO;EAQR;EAQA,EAAA,CAAA,EAAA,MAAO;EAOP;EAQA,OAAA,CAAA,EAAM,MAAA;EA6BN;EAQA,SAAA,CAAO,EApHT,eAoHkB;EAUhB;EAgBA,MAAA,CAAA,EAAA,OAAS;EAoCT;;;;;UAzKC,mBAAA;;;;;;;;;;;iBAuBD,IAAA,SAAa;;;;iBAQb,KAAA,SAAc;;;;iBAQd,QAAA,CAAA;;;;iBAQA,MAAA,SAAe;;;;iBAQf,OAAA,CAAA,GAAW;;;;iBAOX,MAAA,CAAA,GAAU;;;;iBAQV,MAAA,WAAgB,sBAA2B;;;;iBA6B3C,KAAA,SAAc,gBAAgB;;;;iBAQ9B,OAAA,SAAgB;;;;;;iBAUhB,IAAA,CAAA;;;;;iBAgBA,SAAA,SACN,qBACE;;;;;iBAkCI,KAAA;;;;;;wBAMC"}
package/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
- if(typeof window<`u`){let e=()=>{let e=Array.from(document.querySelectorAll(`dialog.drawer[open]`));e.forEach((t,n)=>{n===e.length-1?t.removeAttribute(`inert`):t.setAttribute(`inert`,``)})};new MutationObserver(t=>{for(let n of t)if(n.type===`attributes`&&n.attributeName===`open`&&n.target.classList.contains(`drawer`)){e();break}}).observe(document.body,{subtree:!0,attributes:!0,attributeFilter:[`open`]})}function e(e){return e?typeof e==`string`?document.getElementById(e):e:null}function t(t){e(t)?.showModal()}function n(t){e(t)?.close()}function r(){Array.from(document.querySelectorAll(`dialog.drawer[open]`)).reverse().forEach(e=>e.close())}function i(t){return e(t)?.open??!1}function a(){return Array.from(document.querySelectorAll(`dialog.drawer[open]`))}function o(){let e=a();return e[e.length-1]??null}function s(e={}){let{id:t,content:n=``,handle:r=!0,className:i=``,closeOnOutsideClick:a=!0}=e,o=document.createElement(`dialog`);return o.className=`drawer ${i}`.trim(),t&&(o.id=t),a||(o.dataset.closeOnOutsideClick=`false`),o.innerHTML=`
2
- ${r?`<div class="drawer-handle"></div>`:``}
1
+ import"./drawer-CiHZcyXE.mjs";import './drawer-CXCJQa45.css';
2
+ if(typeof window<`u`){let e=()=>{let e=Array.from(document.querySelectorAll(`dialog.drawer[open]`));e.forEach((t,n)=>{n===e.length-1?t.removeAttribute(`inert`):t.setAttribute(`inert`,``)})};new MutationObserver(t=>{for(let n of t)if(n.type===`attributes`&&n.attributeName===`open`&&n.target.classList.contains(`drawer`)){e();break}}).observe(document.body,{subtree:!0,attributes:!0,attributeFilter:[`open`]})}function e(e){return e?typeof e==`string`?document.getElementById(e):e:null}function t(t){e(t)?.showModal()}function n(t){e(t)?.close()}function r(){Array.from(document.querySelectorAll(`dialog.drawer[open]`)).reverse().forEach(e=>e.close())}function i(t){return e(t)?.open??!1}function a(){return Array.from(document.querySelectorAll(`dialog.drawer[open]`))}function o(){let e=a();return e[e.length-1]??null}function s(e={}){let{id:t,content:n=``,direction:r,handle:i=!0,className:a=``,closeOnOutsideClick:o=!0}=e,s=document.createElement(`dialog`);return s.className=`drawer ${a}`.trim(),t&&(s.id=t),r&&(s.dataset.direction=r),o||(s.dataset.closeOnOutsideClick=`false`),s.innerHTML=`
3
+ ${i?`<div class="drawer-handle"></div>`:``}
3
4
  <div class="drawer-content">${n}</div>
4
- `,o.addEventListener(`click`,e=>{e.target===o&&o.dataset.closeOnOutsideClick!==`false`&&o.close()}),o}function c(e){return document.body.appendChild(e),e}function l(t){e(t)?.remove()}function u(){let e=e=>{let t=e.target;t.matches(`dialog.drawer`)&&t.dataset.closeOnOutsideClick!==`false`&&t.close()};return document.addEventListener(`click`,e),()=>document.removeEventListener(`click`,e)}function d(t,n){let r=e(t);if(!r)return()=>{};let{onOpen:i,onClose:a,onCancel:o}=n,s=()=>a?.(),c=()=>o?.(),l=new MutationObserver(e=>{for(let t of e)t.attributeName===`open`&&r.open&&i?.()});return r.addEventListener(`close`,s),r.addEventListener(`cancel`,c),l.observe(r,{attributes:!0}),()=>{r.removeEventListener(`close`,s),r.removeEventListener(`cancel`,c),l.disconnect()}}function f(e,t){let n=t?.closeOnOutsideClick??!0;return{id:e,className:`drawer`,"data-close-on-outside-click":n?void 0:`false`,onClick:e=>{n&&e.target===e.currentTarget&&e.currentTarget.close()}}}export{n as close,r as closeAll,s as create,a as getOpen,o as getTop,u as init,i as isOpen,c as mount,t as open,f as props,d as subscribe,l as unmount};
5
+ `,s.addEventListener(`click`,e=>{e.target===s&&s.dataset.closeOnOutsideClick!==`false`&&s.close()}),s}function c(e){return document.body.appendChild(e),e}function l(t){e(t)?.remove()}function u(){let e=e=>{let t=e.target;t.matches(`dialog.drawer`)&&t.dataset.closeOnOutsideClick!==`false`&&t.close()};return document.addEventListener(`click`,e),()=>document.removeEventListener(`click`,e)}function d(t,n){let r=e(t);if(!r)return()=>{};let{onOpen:i,onClose:a,onCancel:o}=n,s=()=>a?.(),c=()=>o?.(),l=new MutationObserver(e=>{for(let t of e)t.attributeName===`open`&&r.open&&i?.()});return r.addEventListener(`close`,s),r.addEventListener(`cancel`,c),l.observe(r,{attributes:!0}),()=>{r.removeEventListener(`close`,s),r.removeEventListener(`cancel`,c),l.disconnect()}}function f(e,t){let n=t?.closeOnOutsideClick??!0;return{id:e,className:`drawer`,"data-close-on-outside-click":n?void 0:`false`,onClick:e=>{n&&e.target===e.currentTarget&&e.currentTarget.close()}}}export{n as close,r as closeAll,s as create,a as getOpen,o as getTop,u as init,i as isOpen,c as mount,t as open,f as props,d as subscribe,l as unmount};
5
6
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["open"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * CSS Drawer - Headless drawer component\n * Works with any framework: React, Vue, Svelte, vanilla JS\n */\n\n/* ===== Auto-enable accessibility for stacked drawers ===== */\nif (typeof window !== 'undefined') {\n const updateInertState = () => {\n const openDrawers = Array.from(\n document.querySelectorAll<HTMLDialogElement>('dialog.drawer[open]')\n )\n openDrawers.forEach((drawer, index) => {\n if (index === openDrawers.length - 1) {\n drawer.removeAttribute('inert')\n } else {\n drawer.setAttribute('inert', '')\n }\n })\n }\n\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (\n mutation.type === 'attributes' &&\n mutation.attributeName === 'open' &&\n (mutation.target as HTMLElement).classList.contains('drawer')\n ) {\n updateInertState()\n break\n }\n }\n })\n\n observer.observe(document.body, {\n subtree: true,\n attributes: true,\n attributeFilter: ['open'],\n })\n}\n\nexport type DrawerElement = HTMLDialogElement\n\nexport type DrawerRef = string | DrawerElement | null | undefined\n\nexport interface CreateDrawerOptions {\n /** Drawer ID */\n id?: string\n /** HTML content for the drawer */\n content?: string\n /** Include drag handle (default: true) */\n handle?: boolean\n /** Additional CSS classes */\n className?: string\n /** Close when clicking outside (default: true) */\n closeOnOutsideClick?: boolean\n}\n\nexport interface DrawerEventHandlers {\n /** Called when drawer opens */\n onOpen?: () => void\n /** Called when drawer closes */\n onClose?: () => void\n /** Called when drawer is cancelled (backdrop click or Escape) */\n onCancel?: () => void\n}\n\n/**\n * Resolve a drawer reference to an element\n */\nfunction resolve(drawer: DrawerRef): DrawerElement | null {\n if (!drawer) return null\n if (typeof drawer === 'string') {\n return document.getElementById(drawer) as DrawerElement | null\n }\n return drawer\n}\n\n/**\n * Open a drawer by ID or element reference\n */\nexport function open(drawer: DrawerRef): void {\n const el = resolve(drawer)\n el?.showModal()\n}\n\n/**\n * Close a drawer by ID or element reference\n */\nexport function close(drawer: DrawerRef): void {\n const el = resolve(drawer)\n el?.close()\n}\n\n/**\n * Close all open drawers (in reverse DOM order for proper animation)\n */\nexport function closeAll(): void {\n const drawers = Array.from(document.querySelectorAll<DrawerElement>('dialog.drawer[open]'))\n drawers.reverse().forEach((d) => d.close())\n}\n\n/**\n * Check if a drawer is open\n */\nexport function isOpen(drawer: DrawerRef): boolean {\n const el = resolve(drawer)\n return el?.open ?? false\n}\n\n/**\n * Get all open drawers\n */\nexport function getOpen(): DrawerElement[] {\n return Array.from(document.querySelectorAll<DrawerElement>('dialog.drawer[open]'))\n}\n\n/**\n * Get the topmost open drawer\n */\nexport function getTop(): DrawerElement | null {\n const open = getOpen()\n return open[open.length - 1] ?? null\n}\n\n/**\n * Create a drawer element programmatically\n */\nexport function create(options: CreateDrawerOptions = {}): DrawerElement {\n const { id, content = '', handle = true, className = '', closeOnOutsideClick = true } = options\n\n const dialog = document.createElement('dialog') as DrawerElement\n dialog.className = `drawer ${className}`.trim()\n if (id) dialog.id = id\n if (!closeOnOutsideClick) {\n dialog.dataset.closeOnOutsideClick = 'false'\n }\n\n dialog.innerHTML = `\n ${handle ? '<div class=\"drawer-handle\"></div>' : ''}\n <div class=\"drawer-content\">${content}</div>\n `\n\n // Backdrop click to close (respects data attribute)\n dialog.addEventListener('click', (e) => {\n if (e.target === dialog && dialog.dataset.closeOnOutsideClick !== 'false') {\n dialog.close()\n }\n })\n\n return dialog\n}\n\n/**\n * Mount a drawer to the DOM (appends to body)\n */\nexport function mount(drawer: DrawerElement): DrawerElement {\n document.body.appendChild(drawer)\n return drawer\n}\n\n/**\n * Unmount a drawer from the DOM\n */\nexport function unmount(drawer: DrawerRef): void {\n const el = resolve(drawer)\n el?.remove()\n}\n\n/**\n * Initialize global backdrop-click-to-close behavior\n * Alternative to adding onclick to each drawer\n * Respects data-close-on-outside-click=\"false\" attribute\n */\nexport function init(): () => void {\n const handler = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n if (target.matches('dialog.drawer') && (target as DrawerElement).dataset.closeOnOutsideClick !== 'false') {\n ;(target as DrawerElement).close()\n }\n }\n\n document.addEventListener('click', handler)\n return () => document.removeEventListener('click', handler)\n}\n\n/**\n * Subscribe to drawer events\n * @returns Cleanup function\n */\nexport function subscribe(\n drawer: DrawerRef,\n handlers: DrawerEventHandlers\n): () => void {\n const el = resolve(drawer)\n if (!el) return () => {}\n\n const { onOpen, onClose, onCancel } = handlers\n\n const handleClose = () => onClose?.()\n const handleCancel = () => onCancel?.()\n\n // Use MutationObserver to detect open attribute\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.attributeName === 'open' && el.open) {\n onOpen?.()\n }\n }\n })\n\n el.addEventListener('close', handleClose)\n el.addEventListener('cancel', handleCancel)\n observer.observe(el, { attributes: true })\n\n return () => {\n el.removeEventListener('close', handleClose)\n el.removeEventListener('cancel', handleCancel)\n observer.disconnect()\n }\n}\n\n/**\n * React-friendly hook helper - returns props to spread on dialog\n * Usage: <dialog {...drawer.props('my-drawer')} />\n */\nexport function props(id: string, options?: { closeOnOutsideClick?: boolean }) {\n const closeOnOutsideClick = options?.closeOnOutsideClick ?? true\n return {\n id,\n className: 'drawer',\n 'data-close-on-outside-click': closeOnOutsideClick ? undefined : 'false',\n onClick: (e: MouseEvent) => {\n if (closeOnOutsideClick && e.target === e.currentTarget) {\n ;(e.currentTarget as DrawerElement).close()\n }\n },\n } as const\n}\n\n"],"mappings":"AAMA,GAAI,OAAO,OAAW,IAAa,CACjC,IAAM,MAAyB,CAC7B,IAAM,EAAc,MAAM,KACxB,SAAS,iBAAoC,sBAAsB,CACpE,CACD,EAAY,SAAS,EAAQ,IAAU,CACjC,IAAU,EAAY,OAAS,EACjC,EAAO,gBAAgB,QAAQ,CAE/B,EAAO,aAAa,QAAS,GAAG,EAElC,EAGa,IAAI,iBAAkB,GAAc,CACnD,IAAK,IAAM,KAAY,EACrB,GACE,EAAS,OAAS,cAClB,EAAS,gBAAkB,QAC1B,EAAS,OAAuB,UAAU,SAAS,SAAS,CAC7D,CACA,GAAkB,CAClB,QAGJ,CAEO,QAAQ,SAAS,KAAM,CAC9B,QAAS,GACT,WAAY,GACZ,gBAAiB,CAAC,OAAO,CAC1B,CAAC,CAgCJ,SAAS,EAAQ,EAAyC,CAKxD,OAJK,EACD,OAAO,GAAW,SACb,SAAS,eAAe,EAAO,CAEjC,EAJa,KAUtB,SAAgB,EAAK,EAAyB,CACjC,EAAQ,EAAO,EACtB,WAAW,CAMjB,SAAgB,EAAM,EAAyB,CAClC,EAAQ,EAAO,EACtB,OAAO,CAMb,SAAgB,GAAiB,CACf,MAAM,KAAK,SAAS,iBAAgC,sBAAsB,CAAC,CACnF,SAAS,CAAC,QAAS,GAAM,EAAE,OAAO,CAAC,CAM7C,SAAgB,EAAO,EAA4B,CAEjD,OADW,EAAQ,EAAO,EACf,MAAQ,GAMrB,SAAgB,GAA2B,CACzC,OAAO,MAAM,KAAK,SAAS,iBAAgC,sBAAsB,CAAC,CAMpF,SAAgB,GAA+B,CAC7C,IAAMA,EAAO,GAAS,CACtB,OAAOA,EAAKA,EAAK,OAAS,IAAM,KAMlC,SAAgB,EAAO,EAA+B,EAAE,CAAiB,CACvE,GAAM,CAAE,KAAI,UAAU,GAAI,SAAS,GAAM,YAAY,GAAI,sBAAsB,IAAS,EAElF,EAAS,SAAS,cAAc,SAAS,CAmB/C,MAlBA,GAAO,UAAY,UAAU,IAAY,MAAM,CAC3C,IAAI,EAAO,GAAK,GACf,IACH,EAAO,QAAQ,oBAAsB,SAGvC,EAAO,UAAY;MACf,EAAS,oCAAsC,GAAG;kCACtB,EAAQ;IAIxC,EAAO,iBAAiB,QAAU,GAAM,CAClC,EAAE,SAAW,GAAU,EAAO,QAAQ,sBAAwB,SAChE,EAAO,OAAO,EAEhB,CAEK,EAMT,SAAgB,EAAM,EAAsC,CAE1D,OADA,SAAS,KAAK,YAAY,EAAO,CAC1B,EAMT,SAAgB,EAAQ,EAAyB,CACpC,EAAQ,EAAO,EACtB,QAAQ,CAQd,SAAgB,GAAmB,CACjC,IAAM,EAAW,GAAkB,CACjC,IAAM,EAAS,EAAE,OACb,EAAO,QAAQ,gBAAgB,EAAK,EAAyB,QAAQ,sBAAwB,SAC7F,EAAyB,OAAO,EAKtC,OADA,SAAS,iBAAiB,QAAS,EAAQ,KAC9B,SAAS,oBAAoB,QAAS,EAAQ,CAO7D,SAAgB,EACd,EACA,EACY,CACZ,IAAM,EAAK,EAAQ,EAAO,CAC1B,GAAI,CAAC,EAAI,UAAa,GAEtB,GAAM,CAAE,SAAQ,UAAS,YAAa,EAEhC,MAAoB,KAAW,CAC/B,MAAqB,KAAY,CAGjC,EAAW,IAAI,iBAAkB,GAAc,CACnD,IAAK,IAAM,KAAY,EACjB,EAAS,gBAAkB,QAAU,EAAG,MAC1C,KAAU,EAGd,CAMF,OAJA,EAAG,iBAAiB,QAAS,EAAY,CACzC,EAAG,iBAAiB,SAAU,EAAa,CAC3C,EAAS,QAAQ,EAAI,CAAE,WAAY,GAAM,CAAC,KAE7B,CACX,EAAG,oBAAoB,QAAS,EAAY,CAC5C,EAAG,oBAAoB,SAAU,EAAa,CAC9C,EAAS,YAAY,EAQzB,SAAgB,EAAM,EAAY,EAA6C,CAC7E,IAAM,EAAsB,GAAS,qBAAuB,GAC5D,MAAO,CACL,KACA,UAAW,SACX,8BAA+B,EAAsB,IAAA,GAAY,QACjE,QAAU,GAAkB,CACtB,GAAuB,EAAE,SAAW,EAAE,eACtC,EAAE,cAAgC,OAAO,EAGhD"}
1
+ {"version":3,"file":"index.mjs","names":["open"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * CSS Drawer - Headless drawer component\n * Works with any framework: React, Vue, Svelte, vanilla JS\n */\nimport './drawer.css'\n\n/* ===== Auto-enable accessibility for stacked drawers ===== */\nif (typeof window !== 'undefined') {\n const updateInertState = () => {\n const openDrawers = Array.from(\n document.querySelectorAll<HTMLDialogElement>('dialog.drawer[open]')\n )\n openDrawers.forEach((drawer, index) => {\n if (index === openDrawers.length - 1) {\n drawer.removeAttribute('inert')\n } else {\n drawer.setAttribute('inert', '')\n }\n })\n }\n\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (\n mutation.type === 'attributes' &&\n mutation.attributeName === 'open' &&\n (mutation.target as HTMLElement).classList.contains('drawer')\n ) {\n updateInertState()\n break\n }\n }\n })\n\n observer.observe(document.body, {\n subtree: true,\n attributes: true,\n attributeFilter: ['open'],\n })\n}\n\nexport type DrawerElement = HTMLDialogElement\n\nexport type DrawerRef = string | DrawerElement | null | undefined\n\nexport type DrawerDirection = 'bottom' | 'top' | 'left' | 'right' | 'modal'\n\nexport interface CreateDrawerOptions {\n /** Drawer ID */\n id?: string\n /** HTML content for the drawer */\n content?: string\n /** Direction the drawer opens from (default: 'bottom') */\n direction?: DrawerDirection\n /** Include drag handle (default: true) */\n handle?: boolean\n /** Additional CSS classes */\n className?: string\n /** Close when clicking outside (default: true) */\n closeOnOutsideClick?: boolean\n}\n\nexport interface DrawerEventHandlers {\n /** Called when drawer opens */\n onOpen?: () => void\n /** Called when drawer closes */\n onClose?: () => void\n /** Called when drawer is cancelled (backdrop click or Escape) */\n onCancel?: () => void\n}\n\n/**\n * Resolve a drawer reference to an element\n */\nfunction resolve(drawer: DrawerRef): DrawerElement | null {\n if (!drawer) return null\n if (typeof drawer === 'string') {\n return document.getElementById(drawer) as DrawerElement | null\n }\n return drawer\n}\n\n/**\n * Open a drawer by ID or element reference\n */\nexport function open(drawer: DrawerRef): void {\n const el = resolve(drawer)\n el?.showModal()\n}\n\n/**\n * Close a drawer by ID or element reference\n */\nexport function close(drawer: DrawerRef): void {\n const el = resolve(drawer)\n el?.close()\n}\n\n/**\n * Close all open drawers (in reverse DOM order for proper animation)\n */\nexport function closeAll(): void {\n const drawers = Array.from(document.querySelectorAll<DrawerElement>('dialog.drawer[open]'))\n drawers.reverse().forEach((d) => d.close())\n}\n\n/**\n * Check if a drawer is open\n */\nexport function isOpen(drawer: DrawerRef): boolean {\n const el = resolve(drawer)\n return el?.open ?? false\n}\n\n/**\n * Get all open drawers\n */\nexport function getOpen(): DrawerElement[] {\n return Array.from(document.querySelectorAll<DrawerElement>('dialog.drawer[open]'))\n}\n\n/**\n * Get the topmost open drawer\n */\nexport function getTop(): DrawerElement | null {\n const open = getOpen()\n return open[open.length - 1] ?? null\n}\n\n/**\n * Create a drawer element programmatically\n */\nexport function create(options: CreateDrawerOptions = {}): DrawerElement {\n const { id, content = '', direction, handle = true, className = '', closeOnOutsideClick = true } = options\n\n const dialog = document.createElement('dialog') as DrawerElement\n dialog.className = `drawer ${className}`.trim()\n if (id) dialog.id = id\n if (direction) dialog.dataset.direction = direction\n if (!closeOnOutsideClick) {\n dialog.dataset.closeOnOutsideClick = 'false'\n }\n\n dialog.innerHTML = `\n ${handle ? '<div class=\"drawer-handle\"></div>' : ''}\n <div class=\"drawer-content\">${content}</div>\n `\n\n // Backdrop click to close (respects data attribute)\n dialog.addEventListener('click', (e) => {\n if (e.target === dialog && dialog.dataset.closeOnOutsideClick !== 'false') {\n dialog.close()\n }\n })\n\n return dialog\n}\n\n/**\n * Mount a drawer to the DOM (appends to body)\n */\nexport function mount(drawer: DrawerElement): DrawerElement {\n document.body.appendChild(drawer)\n return drawer\n}\n\n/**\n * Unmount a drawer from the DOM\n */\nexport function unmount(drawer: DrawerRef): void {\n const el = resolve(drawer)\n el?.remove()\n}\n\n/**\n * Initialize global backdrop-click-to-close behavior\n * Alternative to adding onclick to each drawer\n * Respects data-close-on-outside-click=\"false\" attribute\n */\nexport function init(): () => void {\n const handler = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n if (target.matches('dialog.drawer') && (target as DrawerElement).dataset.closeOnOutsideClick !== 'false') {\n ;(target as DrawerElement).close()\n }\n }\n\n document.addEventListener('click', handler)\n return () => document.removeEventListener('click', handler)\n}\n\n/**\n * Subscribe to drawer events\n * @returns Cleanup function\n */\nexport function subscribe(\n drawer: DrawerRef,\n handlers: DrawerEventHandlers\n): () => void {\n const el = resolve(drawer)\n if (!el) return () => {}\n\n const { onOpen, onClose, onCancel } = handlers\n\n const handleClose = () => onClose?.()\n const handleCancel = () => onCancel?.()\n\n // Use MutationObserver to detect open attribute\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.attributeName === 'open' && el.open) {\n onOpen?.()\n }\n }\n })\n\n el.addEventListener('close', handleClose)\n el.addEventListener('cancel', handleCancel)\n observer.observe(el, { attributes: true })\n\n return () => {\n el.removeEventListener('close', handleClose)\n el.removeEventListener('cancel', handleCancel)\n observer.disconnect()\n }\n}\n\n/**\n * React-friendly hook helper - returns props to spread on dialog\n * Usage: <dialog {...drawer.props('my-drawer')} />\n */\nexport function props(id: string, options?: { closeOnOutsideClick?: boolean }) {\n const closeOnOutsideClick = options?.closeOnOutsideClick ?? true\n return {\n id,\n className: 'drawer',\n 'data-close-on-outside-click': closeOnOutsideClick ? undefined : 'false',\n onClick: (e: MouseEvent) => {\n if (closeOnOutsideClick && e.target === e.currentTarget) {\n ;(e.currentTarget as DrawerElement).close()\n }\n },\n } as const\n}\n\n"],"mappings":"8BAOA,GAAI,OAAO,OAAW,IAAa,CACjC,IAAM,MAAyB,CAC7B,IAAM,EAAc,MAAM,KACxB,SAAS,iBAAoC,sBAAsB,CACpE,CACD,EAAY,SAAS,EAAQ,IAAU,CACjC,IAAU,EAAY,OAAS,EACjC,EAAO,gBAAgB,QAAQ,CAE/B,EAAO,aAAa,QAAS,GAAG,EAElC,EAGa,IAAI,iBAAkB,GAAc,CACnD,IAAK,IAAM,KAAY,EACrB,GACE,EAAS,OAAS,cAClB,EAAS,gBAAkB,QAC1B,EAAS,OAAuB,UAAU,SAAS,SAAS,CAC7D,CACA,GAAkB,CAClB,QAGJ,CAEO,QAAQ,SAAS,KAAM,CAC9B,QAAS,GACT,WAAY,GACZ,gBAAiB,CAAC,OAAO,CAC1B,CAAC,CAoCJ,SAAS,EAAQ,EAAyC,CAKxD,OAJK,EACD,OAAO,GAAW,SACb,SAAS,eAAe,EAAO,CAEjC,EAJa,KAUtB,SAAgB,EAAK,EAAyB,CACjC,EAAQ,EAAO,EACtB,WAAW,CAMjB,SAAgB,EAAM,EAAyB,CAClC,EAAQ,EAAO,EACtB,OAAO,CAMb,SAAgB,GAAiB,CACf,MAAM,KAAK,SAAS,iBAAgC,sBAAsB,CAAC,CACnF,SAAS,CAAC,QAAS,GAAM,EAAE,OAAO,CAAC,CAM7C,SAAgB,EAAO,EAA4B,CAEjD,OADW,EAAQ,EAAO,EACf,MAAQ,GAMrB,SAAgB,GAA2B,CACzC,OAAO,MAAM,KAAK,SAAS,iBAAgC,sBAAsB,CAAC,CAMpF,SAAgB,GAA+B,CAC7C,IAAMA,EAAO,GAAS,CACtB,OAAOA,EAAKA,EAAK,OAAS,IAAM,KAMlC,SAAgB,EAAO,EAA+B,EAAE,CAAiB,CACvE,GAAM,CAAE,KAAI,UAAU,GAAI,YAAW,SAAS,GAAM,YAAY,GAAI,sBAAsB,IAAS,EAE7F,EAAS,SAAS,cAAc,SAAS,CAoB/C,MAnBA,GAAO,UAAY,UAAU,IAAY,MAAM,CAC3C,IAAI,EAAO,GAAK,GAChB,IAAW,EAAO,QAAQ,UAAY,GACrC,IACH,EAAO,QAAQ,oBAAsB,SAGvC,EAAO,UAAY;MACf,EAAS,oCAAsC,GAAG;kCACtB,EAAQ;IAIxC,EAAO,iBAAiB,QAAU,GAAM,CAClC,EAAE,SAAW,GAAU,EAAO,QAAQ,sBAAwB,SAChE,EAAO,OAAO,EAEhB,CAEK,EAMT,SAAgB,EAAM,EAAsC,CAE1D,OADA,SAAS,KAAK,YAAY,EAAO,CAC1B,EAMT,SAAgB,EAAQ,EAAyB,CACpC,EAAQ,EAAO,EACtB,QAAQ,CAQd,SAAgB,GAAmB,CACjC,IAAM,EAAW,GAAkB,CACjC,IAAM,EAAS,EAAE,OACb,EAAO,QAAQ,gBAAgB,EAAK,EAAyB,QAAQ,sBAAwB,SAC7F,EAAyB,OAAO,EAKtC,OADA,SAAS,iBAAiB,QAAS,EAAQ,KAC9B,SAAS,oBAAoB,QAAS,EAAQ,CAO7D,SAAgB,EACd,EACA,EACY,CACZ,IAAM,EAAK,EAAQ,EAAO,CAC1B,GAAI,CAAC,EAAI,UAAa,GAEtB,GAAM,CAAE,SAAQ,UAAS,YAAa,EAEhC,MAAoB,KAAW,CAC/B,MAAqB,KAAY,CAGjC,EAAW,IAAI,iBAAkB,GAAc,CACnD,IAAK,IAAM,KAAY,EACjB,EAAS,gBAAkB,QAAU,EAAG,MAC1C,KAAU,EAGd,CAMF,OAJA,EAAG,iBAAiB,QAAS,EAAY,CACzC,EAAG,iBAAiB,SAAU,EAAa,CAC3C,EAAS,QAAQ,EAAI,CAAE,WAAY,GAAM,CAAC,KAE7B,CACX,EAAG,oBAAoB,QAAS,EAAY,CAC5C,EAAG,oBAAoB,SAAU,EAAa,CAC9C,EAAS,YAAY,EAQzB,SAAgB,EAAM,EAAY,EAA6C,CAC7E,IAAM,EAAsB,GAAS,qBAAuB,GAC5D,MAAO,CACL,KACA,UAAW,SACX,8BAA+B,EAAsB,IAAA,GAAY,QACjE,QAAU,GAAkB,CACtB,GAAuB,EAAE,SAAW,EAAE,eACtC,EAAE,cAAgC,OAAO,EAGhD"}
package/dist/react.cjs CHANGED
@@ -1,2 +1,2 @@
1
- require('./react.css');
2
- let e=require(`react`),t=require(`react/jsx-runtime`);if(typeof window<`u`){let e=()=>{let e=Array.from(document.querySelectorAll(`dialog.drawer[open]`));e.forEach((t,n)=>{n===e.length-1?t.removeAttribute(`inert`):t.setAttribute(`inert`,``)})};new MutationObserver(t=>{for(let n of t)if(n.type===`attributes`&&n.attributeName===`open`&&n.target.classList.contains(`drawer`)){e();break}}).observe(document.body,{subtree:!0,attributes:!0,attributeFilter:[`open`]})}const n=(0,e.createContext)({direction:void 0});function r(){return(0,e.useContext)(n)}function i({children:e,direction:r}){return(0,t.jsx)(n.Provider,{value:{direction:r},children:e})}const a=(0,e.forwardRef)(({children:n,className:i,open:a,onOpenChange:o,closeOnOutsideClick:s=!0,...c},l)=>{let{direction:u}=r(),d=(0,e.useRef)(null),f=l||d;return(0,e.useEffect)(()=>{let e=f.current;e&&(a&&!e.open?(e.showModal(),o?.(!0)):a===!1&&e.open&&e.close())},[a]),(0,t.jsx)(`dialog`,{ref:f,className:`drawer ${i??``}`.trim(),"data-direction":u,onClose:e=>{c.onClose?.(e),o?.(!1)},onClick:e=>{c.onClick?.(e),s&&e.target===e.currentTarget&&e.currentTarget.close()},...c,children:n})});a.displayName=`Drawer.Content`;const o=(0,e.forwardRef)(({className:e,...n},r)=>(0,t.jsx)(`div`,{ref:r,className:`drawer-handle ${e??``}`.trim(),"aria-hidden":`true`,...n}));o.displayName=`Drawer.Handle`;const s=(0,e.forwardRef)((e,n)=>(0,t.jsx)(`h2`,{ref:n,...e}));s.displayName=`Drawer.Title`;const c=(0,e.forwardRef)((e,n)=>(0,t.jsx)(`p`,{ref:n,...e}));c.displayName=`Drawer.Description`;const l={Root:i,Content:a,Handle:o,Title:s,Description:c};exports.Drawer=l;
1
+ require(`./drawer-BWZh2Fyp.cjs`);require('./drawer-C21nwiwE.css');
2
+ let e=require(`react`),t=require(`react/jsx-runtime`);if(typeof window<`u`){let e=()=>{let e=Array.from(document.querySelectorAll(`dialog.drawer[open]`));e.forEach((t,n)=>{n===e.length-1?t.removeAttribute(`inert`):t.setAttribute(`inert`,``)})};new MutationObserver(t=>{for(let n of t)if(n.type===`attributes`&&n.attributeName===`open`&&n.target.classList.contains(`drawer`)){e();break}}).observe(document.body,{subtree:!0,attributes:!0,attributeFilter:[`open`]})}const n=(0,e.createContext)({direction:void 0});function r(){return(0,e.useContext)(n)}function i({children:e,direction:r}){return(0,t.jsx)(n.Provider,{value:{direction:r},children:e})}const a=(0,e.forwardRef)(({children:n,className:i,open:a,onOpenChange:o,closeOnOutsideClick:s=!0,...c},l)=>{let{direction:u}=r(),d=(0,e.useRef)(null),f=l||d;return(0,e.useEffect)(()=>{let e=f.current;e&&(a&&!e.open?(e.showModal(),o?.(!0)):a===!1&&e.open&&e.close())},[a]),(0,t.jsx)(`dialog`,{ref:f,className:`drawer ${i??``}`.trim(),"data-direction":u,onClose:e=>{e.target===e.currentTarget&&(c.onClose?.(e),o?.(!1))},onClick:e=>{c.onClick?.(e),s&&e.target===e.currentTarget&&e.currentTarget.close()},...c,children:n})});a.displayName=`Drawer.Content`;const o=(0,e.forwardRef)(({className:e,...n},r)=>(0,t.jsx)(`div`,{ref:r,className:`drawer-handle ${e??``}`.trim(),"aria-hidden":`true`,...n}));o.displayName=`Drawer.Handle`;const s=(0,e.forwardRef)((e,n)=>(0,t.jsx)(`h2`,{ref:n,...e}));s.displayName=`Drawer.Title`;const c=(0,e.forwardRef)((e,n)=>(0,t.jsx)(`p`,{ref:n,...e}));c.displayName=`Drawer.Description`;const l={Root:i,Content:a,Handle:o,Title:s,Description:c};exports.Drawer=l;
package/dist/react.d.cts CHANGED
@@ -3,7 +3,7 @@ import * as react0 from "react";
3
3
  import { ComponentPropsWithoutRef, ReactNode } from "react";
4
4
 
5
5
  //#region src/react.d.ts
6
- type Direction = 'bottom' | 'top' | 'left' | 'right';
6
+ type Direction = 'bottom' | 'top' | 'left' | 'right' | 'modal';
7
7
  interface RootProps {
8
8
  children: ReactNode;
9
9
  /** Direction the drawer opens from */
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.cts","names":[],"sources":["../src/react.tsx"],"sourcesContent":[],"mappings":";;;;;KAgDK,SAAA;UAcK,SAAA;YACE;EAfP;EAcK,SAAA,CAAA,EAGI,SAHK;AAGI;iBAGd,IAAA,CAAO;EAAA,QAAA;EAAA;AAAA,CAAA,EAAuB,SAAvB,CAAA,EAAgC,kBAAA,CAAA,GAAA,CAAA,OAAhC;UASN,YAAA,SAAqB,IATL,CASU,wBATV,CAAA,QAAA,CAAA,EAAA,MAAA,CAAA,CAAA;EAAa;EAAS,IAAA,CAAA,EAAA,OAAA;EAAA;EAStC,YAAA,CAAA,EAAa,CAAA,IAAA,EAAA,OAAa,EAAA,GAAA,IAAA;EAqD1B;EAaA,mBAAW,CAAA,EAAA,OAAQ;AAAwB;AAgBrD,UA7BU,WAAA,SAAoB,wBAmC7B,CAAA,KAAA,CAAA,CAAA;UAtBS,UAAA,SAAmB;UAQnB,gBAAA,SAAyB;cAQtB"}
1
+ {"version":3,"file":"react.d.cts","names":[],"sources":["../src/react.tsx"],"sourcesContent":[],"mappings":";;;;;KAgDK,SAAA;UAcK,SAAA;YACE;EAfP;EAcK,SAAA,CAAA,EAGI,SAHK;AAGI;iBAGd,IAAA,CAAO;EAAA,QAAA;EAAA;AAAA,CAAA,EAAuB,SAAvB,CAAA,EAAgC,kBAAA,CAAA,GAAA,CAAA,OAAhC;UASN,YAAA,SAAqB,IATL,CASU,wBATV,CAAA,QAAA,CAAA,EAAA,MAAA,CAAA,CAAA;EAAa;EAAS,IAAA,CAAA,EAAA,OAAA;EAAA;EAStC,YAAA,CAAA,EAAa,CAAA,IAAA,EAAA,OAAa,EAAA,GAAA,IAAA;EAyD1B;EAaA,mBAAW,CAAA,EAAA,OAAQ;AAAwB;AAgBrD,UA7BU,WAAA,SAAoB,wBAmC7B,CAAA,KAAA,CAAA,CAAA;UAtBS,UAAA,SAAmB;UAQnB,gBAAA,SAAyB;cAQtB"}
package/dist/react.d.mts CHANGED
@@ -3,7 +3,7 @@ import { ComponentPropsWithoutRef, ReactNode } from "react";
3
3
  import * as react_jsx_runtime0 from "react/jsx-runtime";
4
4
 
5
5
  //#region src/react.d.ts
6
- type Direction = 'bottom' | 'top' | 'left' | 'right';
6
+ type Direction = 'bottom' | 'top' | 'left' | 'right' | 'modal';
7
7
  interface RootProps {
8
8
  children: ReactNode;
9
9
  /** Direction the drawer opens from */
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.mts","names":[],"sources":["../src/react.tsx"],"sourcesContent":[],"mappings":";;;;;KAgDK,SAAA;UAcK,SAAA;YACE;EAfP;EAcK,SAAA,CAAA,EAGI,SAHK;AAGI;iBAGd,IAAA,CAAO;EAAA,QAAA;EAAA;AAAA,CAAA,EAAuB,SAAvB,CAAA,EAAgC,kBAAA,CAAA,GAAA,CAAA,OAAhC;UASN,YAAA,SAAqB,IATL,CASU,wBATV,CAAA,QAAA,CAAA,EAAA,MAAA,CAAA,CAAA;EAAa;EAAS,IAAA,CAAA,EAAA,OAAA;EAAA;EAStC,YAAA,CAAA,EAAa,CAAA,IAAA,EAAA,OAAa,EAAA,GAAA,IAAA;EAqD1B;EAaA,mBAAW,CAAA,EAAA,OAAQ;AAAwB;AAgBrD,UA7BU,WAAA,SAAoB,wBAmC7B,CAAA,KAAA,CAAA,CAAA;UAtBS,UAAA,SAAmB;UAQnB,gBAAA,SAAyB;cAQtB"}
1
+ {"version":3,"file":"react.d.mts","names":[],"sources":["../src/react.tsx"],"sourcesContent":[],"mappings":";;;;;KAgDK,SAAA;UAcK,SAAA;YACE;EAfP;EAcK,SAAA,CAAA,EAGI,SAHK;AAGI;iBAGd,IAAA,CAAO;EAAA,QAAA;EAAA;AAAA,CAAA,EAAuB,SAAvB,CAAA,EAAgC,kBAAA,CAAA,GAAA,CAAA,OAAhC;UASN,YAAA,SAAqB,IATL,CASU,wBATV,CAAA,QAAA,CAAA,EAAA,MAAA,CAAA,CAAA;EAAa;EAAS,IAAA,CAAA,EAAA,OAAA;EAAA;EAStC,YAAA,CAAA,EAAa,CAAA,IAAA,EAAA,OAAa,EAAA,GAAA,IAAA;EAyD1B;EAaA,mBAAW,CAAA,EAAA,OAAQ;AAAwB;AAgBrD,UA7BU,WAAA,SAAoB,wBAmC7B,CAAA,KAAA,CAAA,CAAA;UAtBS,UAAA,SAAmB;UAQnB,gBAAA,SAAyB;cAQtB"}
package/dist/react.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import{createContext as e,forwardRef as t,useContext as n,useEffect as r,useRef as i}from"react";import{jsx as a}from"react/jsx-runtime";import './react.css';
2
- if(typeof window<`u`){let e=()=>{let e=Array.from(document.querySelectorAll(`dialog.drawer[open]`));e.forEach((t,n)=>{n===e.length-1?t.removeAttribute(`inert`):t.setAttribute(`inert`,``)})};new MutationObserver(t=>{for(let n of t)if(n.type===`attributes`&&n.attributeName===`open`&&n.target.classList.contains(`drawer`)){e();break}}).observe(document.body,{subtree:!0,attributes:!0,attributeFilter:[`open`]})}const o=e({direction:void 0});function s(){return n(o)}function c({children:e,direction:t}){return a(o.Provider,{value:{direction:t},children:e})}const l=t(({children:e,className:t,open:n,onOpenChange:o,closeOnOutsideClick:c=!0,...l},u)=>{let{direction:d}=s(),f=i(null),p=u||f;return r(()=>{let e=p.current;e&&(n&&!e.open?(e.showModal(),o?.(!0)):n===!1&&e.open&&e.close())},[n]),a(`dialog`,{ref:p,className:`drawer ${t??``}`.trim(),"data-direction":d,onClose:e=>{l.onClose?.(e),o?.(!1)},onClick:e=>{l.onClick?.(e),c&&e.target===e.currentTarget&&e.currentTarget.close()},...l,children:e})});l.displayName=`Drawer.Content`;const u=t(({className:e,...t},n)=>a(`div`,{ref:n,className:`drawer-handle ${e??``}`.trim(),"aria-hidden":`true`,...t}));u.displayName=`Drawer.Handle`;const d=t((e,t)=>a(`h2`,{ref:t,...e}));d.displayName=`Drawer.Title`;const f=t((e,t)=>a(`p`,{ref:t,...e}));f.displayName=`Drawer.Description`;const p={Root:c,Content:l,Handle:u,Title:d,Description:f};export{p as Drawer};
1
+ import"./drawer-CiHZcyXE.mjs";import{createContext as e,forwardRef as t,useContext as n,useEffect as r,useRef as i}from"react";import{jsx as a}from"react/jsx-runtime";import './drawer-CXCJQa45.css';
2
+ if(typeof window<`u`){let e=()=>{let e=Array.from(document.querySelectorAll(`dialog.drawer[open]`));e.forEach((t,n)=>{n===e.length-1?t.removeAttribute(`inert`):t.setAttribute(`inert`,``)})};new MutationObserver(t=>{for(let n of t)if(n.type===`attributes`&&n.attributeName===`open`&&n.target.classList.contains(`drawer`)){e();break}}).observe(document.body,{subtree:!0,attributes:!0,attributeFilter:[`open`]})}const o=e({direction:void 0});function s(){return n(o)}function c({children:e,direction:t}){return a(o.Provider,{value:{direction:t},children:e})}const l=t(({children:e,className:t,open:n,onOpenChange:o,closeOnOutsideClick:c=!0,...l},u)=>{let{direction:d}=s(),f=i(null),p=u||f;return r(()=>{let e=p.current;e&&(n&&!e.open?(e.showModal(),o?.(!0)):n===!1&&e.open&&e.close())},[n]),a(`dialog`,{ref:p,className:`drawer ${t??``}`.trim(),"data-direction":d,onClose:e=>{e.target===e.currentTarget&&(l.onClose?.(e),o?.(!1))},onClick:e=>{l.onClick?.(e),c&&e.target===e.currentTarget&&e.currentTarget.close()},...l,children:e})});l.displayName=`Drawer.Content`;const u=t(({className:e,...t},n)=>a(`div`,{ref:n,className:`drawer-handle ${e??``}`.trim(),"aria-hidden":`true`,...t}));u.displayName=`Drawer.Handle`;const d=t((e,t)=>a(`h2`,{ref:t,...e}));d.displayName=`Drawer.Title`;const f=t((e,t)=>a(`p`,{ref:t,...e}));f.displayName=`Drawer.Description`;const p={Root:c,Content:l,Handle:u,Title:d,Description:f};export{p as Drawer};
3
3
  //# sourceMappingURL=react.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"react.mjs","names":[],"sources":["../src/react.tsx"],"sourcesContent":["import {\n createContext,\n useContext,\n forwardRef,\n useEffect,\n useRef,\n type ReactNode,\n type ComponentPropsWithoutRef,\n} from 'react'\nimport './drawer.css'\n\n/* ===== Auto-enable accessibility for stacked drawers ===== */\nif (typeof window !== 'undefined') {\n const updateInertState = () => {\n const openDrawers = Array.from(\n document.querySelectorAll<HTMLDialogElement>('dialog.drawer[open]')\n )\n openDrawers.forEach((drawer, index) => {\n const isTopmost = index === openDrawers.length - 1\n if (isTopmost) {\n drawer.removeAttribute('inert')\n } else {\n drawer.setAttribute('inert', '')\n }\n })\n }\n\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (\n mutation.type === 'attributes' &&\n mutation.attributeName === 'open' &&\n (mutation.target as HTMLElement).classList.contains('drawer')\n ) {\n updateInertState()\n break\n }\n }\n })\n\n observer.observe(document.body, {\n subtree: true,\n attributes: true,\n attributeFilter: ['open'],\n })\n}\n\n/* ===== Types ===== */\ntype Direction = 'bottom' | 'top' | 'left' | 'right'\n\ninterface DrawerContextValue {\n direction?: Direction\n}\n\n/* ===== Context ===== */\nconst DrawerContext = createContext<DrawerContextValue>({ direction: undefined })\n\nfunction useDrawerContext() {\n return useContext(DrawerContext)\n}\n\n/* ===== Root ===== */\ninterface RootProps {\n children: ReactNode\n /** Direction the drawer opens from */\n direction?: Direction\n}\n\nfunction Root({ children, direction }: RootProps) {\n return (\n <DrawerContext.Provider value={{ direction }}>\n {children}\n </DrawerContext.Provider>\n )\n}\n\n/* ===== Content ===== */\ninterface ContentProps extends Omit<ComponentPropsWithoutRef<'dialog'>, 'open'> {\n /** Controlled open state */\n open?: boolean\n /** Called when open state changes */\n onOpenChange?: (open: boolean) => void\n /** Close when clicking outside the drawer (default: true) */\n closeOnOutsideClick?: boolean\n}\n\nconst Content = forwardRef<HTMLDialogElement, ContentProps>(\n ({ children, className, open, onOpenChange, closeOnOutsideClick = true, ...props }, ref) => {\n const { direction } = useDrawerContext()\n const internalRef = useRef<HTMLDialogElement>(null)\n const dialogRef = (ref as React.RefObject<HTMLDialogElement>) || internalRef\n\n useEffect(() => {\n const dialog = dialogRef.current\n if (!dialog) return\n\n if (open && !dialog.open) {\n dialog.showModal()\n onOpenChange?.(true)\n } else if (open === false && dialog.open) {\n dialog.close()\n }\n }, [open])\n\n return (\n <dialog\n ref={dialogRef}\n className={`drawer ${className ?? ''}`.trim()}\n data-direction={direction}\n onClose={(e) => {\n props.onClose?.(e)\n onOpenChange?.(false)\n }}\n onClick={(e) => {\n props.onClick?.(e)\n // Backdrop click - only if clicking the dialog element itself\n if (closeOnOutsideClick && e.target === e.currentTarget) {\n e.currentTarget.close()\n }\n }}\n {...props}\n >\n {children}\n </dialog>\n )\n }\n)\nContent.displayName = 'Drawer.Content'\n\n/* ===== Handle ===== */\ninterface HandleProps extends ComponentPropsWithoutRef<'div'> {}\n\nconst Handle = forwardRef<HTMLDivElement, HandleProps>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={`drawer-handle ${className ?? ''}`.trim()}\n aria-hidden=\"true\"\n {...props}\n />\n))\nHandle.displayName = 'Drawer.Handle'\n\n/* ===== Title ===== */\ninterface TitleProps extends ComponentPropsWithoutRef<'h2'> {}\n\nconst Title = forwardRef<HTMLHeadingElement, TitleProps>((props, ref) => (\n <h2 ref={ref} {...props} />\n))\nTitle.displayName = 'Drawer.Title'\n\n/* ===== Description ===== */\ninterface DescriptionProps extends ComponentPropsWithoutRef<'p'> {}\n\nconst Description = forwardRef<HTMLParagraphElement, DescriptionProps>((props, ref) => (\n <p ref={ref} {...props} />\n))\nDescription.displayName = 'Drawer.Description'\n\n/* ===== Namespace Export ===== */\nexport const Drawer = {\n Root,\n Content,\n Handle,\n Title,\n Description,\n}\n\nexport type {\n RootProps as DrawerRootProps,\n ContentProps as DrawerContentProps,\n HandleProps as DrawerHandleProps,\n TitleProps as DrawerTitleProps,\n DescriptionProps as DrawerDescriptionProps,\n Direction as DrawerDirection,\n}\n"],"mappings":"yIAYA,GAAI,OAAO,OAAW,IAAa,CACjC,IAAM,MAAyB,CAC7B,IAAM,EAAc,MAAM,KACxB,SAAS,iBAAoC,sBAAsB,CACpE,CACD,EAAY,SAAS,EAAQ,IAAU,CACnB,IAAU,EAAY,OAAS,EAE/C,EAAO,gBAAgB,QAAQ,CAE/B,EAAO,aAAa,QAAS,GAAG,EAElC,EAGa,IAAI,iBAAkB,GAAc,CACnD,IAAK,IAAM,KAAY,EACrB,GACE,EAAS,OAAS,cAClB,EAAS,gBAAkB,QAC1B,EAAS,OAAuB,UAAU,SAAS,SAAS,CAC7D,CACA,GAAkB,CAClB,QAGJ,CAEO,QAAQ,SAAS,KAAM,CAC9B,QAAS,GACT,WAAY,GACZ,gBAAiB,CAAC,OAAO,CAC1B,CAAC,CAWJ,MAAM,EAAgB,EAAkC,CAAE,UAAW,IAAA,GAAW,CAAC,CAEjF,SAAS,GAAmB,CAC1B,OAAO,EAAW,EAAc,CAUlC,SAAS,EAAK,CAAE,WAAU,aAAwB,CAChD,OACE,EAAC,EAAc,SAAA,CAAS,MAAO,CAAE,YAAW,CACzC,YACsB,CAc7B,MAAM,EAAU,GACb,CAAE,WAAU,YAAW,OAAM,eAAc,sBAAsB,GAAM,GAAG,GAAS,IAAQ,CAC1F,GAAM,CAAE,aAAc,GAAkB,CAClC,EAAc,EAA0B,KAAK,CAC7C,EAAa,GAA8C,EAcjE,OAZA,MAAgB,CACd,IAAM,EAAS,EAAU,QACpB,IAED,GAAQ,CAAC,EAAO,MAClB,EAAO,WAAW,CAClB,IAAe,GAAK,EACX,IAAS,IAAS,EAAO,MAClC,EAAO,OAAO,GAEf,CAAC,EAAK,CAAC,CAGR,EAAC,SAAA,CACC,IAAK,EACL,UAAW,UAAU,GAAa,KAAK,MAAM,CAC7C,iBAAgB,EAChB,QAAU,GAAM,CACd,EAAM,UAAU,EAAE,CAClB,IAAe,GAAM,EAEvB,QAAU,GAAM,CACd,EAAM,UAAU,EAAE,CAEd,GAAuB,EAAE,SAAW,EAAE,eACxC,EAAE,cAAc,OAAO,EAG3B,GAAI,EAEH,YACM,EAGd,CACD,EAAQ,YAAc,iBAKtB,MAAM,EAAS,GAAyC,CAAE,YAAW,GAAG,GAAS,IAC/E,EAAC,MAAA,CACM,MACL,UAAW,iBAAiB,GAAa,KAAK,MAAM,CACpD,cAAY,OACZ,GAAI,GACJ,CACF,CACF,EAAO,YAAc,gBAKrB,MAAM,EAAQ,GAA4C,EAAO,IAC/D,EAAC,KAAA,CAAQ,MAAK,GAAI,GAAS,CAC3B,CACF,EAAM,YAAc,eAKpB,MAAM,EAAc,GAAoD,EAAO,IAC7E,EAAC,IAAA,CAAO,MAAK,GAAI,GAAS,CAC1B,CACF,EAAY,YAAc,qBAG1B,MAAa,EAAS,CACpB,OACA,UACA,SACA,QACA,cACD"}
1
+ {"version":3,"file":"react.mjs","names":[],"sources":["../src/react.tsx"],"sourcesContent":["import {\n createContext,\n useContext,\n forwardRef,\n useEffect,\n useRef,\n type ReactNode,\n type ComponentPropsWithoutRef,\n} from 'react'\nimport './drawer.css'\n\n/* ===== Auto-enable accessibility for stacked drawers ===== */\nif (typeof window !== 'undefined') {\n const updateInertState = () => {\n const openDrawers = Array.from(\n document.querySelectorAll<HTMLDialogElement>('dialog.drawer[open]')\n )\n openDrawers.forEach((drawer, index) => {\n const isTopmost = index === openDrawers.length - 1\n if (isTopmost) {\n drawer.removeAttribute('inert')\n } else {\n drawer.setAttribute('inert', '')\n }\n })\n }\n\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (\n mutation.type === 'attributes' &&\n mutation.attributeName === 'open' &&\n (mutation.target as HTMLElement).classList.contains('drawer')\n ) {\n updateInertState()\n break\n }\n }\n })\n\n observer.observe(document.body, {\n subtree: true,\n attributes: true,\n attributeFilter: ['open'],\n })\n}\n\n/* ===== Types ===== */\ntype Direction = 'bottom' | 'top' | 'left' | 'right' | 'modal'\n\ninterface DrawerContextValue {\n direction?: Direction\n}\n\n/* ===== Context ===== */\nconst DrawerContext = createContext<DrawerContextValue>({ direction: undefined })\n\nfunction useDrawerContext() {\n return useContext(DrawerContext)\n}\n\n/* ===== Root ===== */\ninterface RootProps {\n children: ReactNode\n /** Direction the drawer opens from */\n direction?: Direction\n}\n\nfunction Root({ children, direction }: RootProps) {\n return (\n <DrawerContext.Provider value={{ direction }}>\n {children}\n </DrawerContext.Provider>\n )\n}\n\n/* ===== Content ===== */\ninterface ContentProps extends Omit<ComponentPropsWithoutRef<'dialog'>, 'open'> {\n /** Controlled open state */\n open?: boolean\n /** Called when open state changes */\n onOpenChange?: (open: boolean) => void\n /** Close when clicking outside the drawer (default: true) */\n closeOnOutsideClick?: boolean\n}\n\nconst Content = forwardRef<HTMLDialogElement, ContentProps>(\n ({ children, className, open, onOpenChange, closeOnOutsideClick = true, ...props }, ref) => {\n const { direction } = useDrawerContext()\n const internalRef = useRef<HTMLDialogElement>(null)\n const dialogRef = (ref as React.RefObject<HTMLDialogElement>) || internalRef\n\n useEffect(() => {\n const dialog = dialogRef.current\n if (!dialog) return\n\n if (open && !dialog.open) {\n dialog.showModal()\n onOpenChange?.(true)\n } else if (open === false && dialog.open) {\n dialog.close()\n }\n }, [open])\n\n return (\n <dialog\n ref={dialogRef}\n className={`drawer ${className ?? ''}`.trim()}\n data-direction={direction}\n onClose={(e) => {\n // Only handle close event if it originated from THIS dialog\n // This prevents nested dialogs from triggering parent dialog closes\n if (e.target !== e.currentTarget) return\n\n props.onClose?.(e)\n onOpenChange?.(false)\n }}\n onClick={(e) => {\n props.onClick?.(e)\n // Backdrop click - only if clicking the dialog element itself\n if (closeOnOutsideClick && e.target === e.currentTarget) {\n e.currentTarget.close()\n }\n }}\n {...props}\n >\n {children}\n </dialog>\n )\n }\n)\nContent.displayName = 'Drawer.Content'\n\n/* ===== Handle ===== */\ninterface HandleProps extends ComponentPropsWithoutRef<'div'> {}\n\nconst Handle = forwardRef<HTMLDivElement, HandleProps>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={`drawer-handle ${className ?? ''}`.trim()}\n aria-hidden=\"true\"\n {...props}\n />\n))\nHandle.displayName = 'Drawer.Handle'\n\n/* ===== Title ===== */\ninterface TitleProps extends ComponentPropsWithoutRef<'h2'> {}\n\nconst Title = forwardRef<HTMLHeadingElement, TitleProps>((props, ref) => (\n <h2 ref={ref} {...props} />\n))\nTitle.displayName = 'Drawer.Title'\n\n/* ===== Description ===== */\ninterface DescriptionProps extends ComponentPropsWithoutRef<'p'> {}\n\nconst Description = forwardRef<HTMLParagraphElement, DescriptionProps>((props, ref) => (\n <p ref={ref} {...props} />\n))\nDescription.displayName = 'Drawer.Description'\n\n/* ===== Namespace Export ===== */\nexport const Drawer = {\n Root,\n Content,\n Handle,\n Title,\n Description,\n}\n\nexport type {\n RootProps as DrawerRootProps,\n ContentProps as DrawerContentProps,\n HandleProps as DrawerHandleProps,\n TitleProps as DrawerTitleProps,\n DescriptionProps as DrawerDescriptionProps,\n Direction as DrawerDirection,\n}\n"],"mappings":"uKAYA,GAAI,OAAO,OAAW,IAAa,CACjC,IAAM,MAAyB,CAC7B,IAAM,EAAc,MAAM,KACxB,SAAS,iBAAoC,sBAAsB,CACpE,CACD,EAAY,SAAS,EAAQ,IAAU,CACnB,IAAU,EAAY,OAAS,EAE/C,EAAO,gBAAgB,QAAQ,CAE/B,EAAO,aAAa,QAAS,GAAG,EAElC,EAGa,IAAI,iBAAkB,GAAc,CACnD,IAAK,IAAM,KAAY,EACrB,GACE,EAAS,OAAS,cAClB,EAAS,gBAAkB,QAC1B,EAAS,OAAuB,UAAU,SAAS,SAAS,CAC7D,CACA,GAAkB,CAClB,QAGJ,CAEO,QAAQ,SAAS,KAAM,CAC9B,QAAS,GACT,WAAY,GACZ,gBAAiB,CAAC,OAAO,CAC1B,CAAC,CAWJ,MAAM,EAAgB,EAAkC,CAAE,UAAW,IAAA,GAAW,CAAC,CAEjF,SAAS,GAAmB,CAC1B,OAAO,EAAW,EAAc,CAUlC,SAAS,EAAK,CAAE,WAAU,aAAwB,CAChD,OACE,EAAC,EAAc,SAAA,CAAS,MAAO,CAAE,YAAW,CACzC,YACsB,CAc7B,MAAM,EAAU,GACb,CAAE,WAAU,YAAW,OAAM,eAAc,sBAAsB,GAAM,GAAG,GAAS,IAAQ,CAC1F,GAAM,CAAE,aAAc,GAAkB,CAClC,EAAc,EAA0B,KAAK,CAC7C,EAAa,GAA8C,EAcjE,OAZA,MAAgB,CACd,IAAM,EAAS,EAAU,QACpB,IAED,GAAQ,CAAC,EAAO,MAClB,EAAO,WAAW,CAClB,IAAe,GAAK,EACX,IAAS,IAAS,EAAO,MAClC,EAAO,OAAO,GAEf,CAAC,EAAK,CAAC,CAGR,EAAC,SAAA,CACC,IAAK,EACL,UAAW,UAAU,GAAa,KAAK,MAAM,CAC7C,iBAAgB,EAChB,QAAU,GAAM,CAGV,EAAE,SAAW,EAAE,gBAEnB,EAAM,UAAU,EAAE,CAClB,IAAe,GAAM,GAEvB,QAAU,GAAM,CACd,EAAM,UAAU,EAAE,CAEd,GAAuB,EAAE,SAAW,EAAE,eACxC,EAAE,cAAc,OAAO,EAG3B,GAAI,EAEH,YACM,EAGd,CACD,EAAQ,YAAc,iBAKtB,MAAM,EAAS,GAAyC,CAAE,YAAW,GAAG,GAAS,IAC/E,EAAC,MAAA,CACM,MACL,UAAW,iBAAiB,GAAa,KAAK,MAAM,CACpD,cAAY,OACZ,GAAI,GACJ,CACF,CACF,EAAO,YAAc,gBAKrB,MAAM,EAAQ,GAA4C,EAAO,IAC/D,EAAC,KAAA,CAAQ,MAAK,GAAI,GAAS,CAC3B,CACF,EAAM,YAAc,eAKpB,MAAM,EAAc,GAAoD,EAAO,IAC7E,EAAC,IAAA,CAAO,MAAK,GAAI,GAAS,CAC1B,CACF,EAAY,YAAc,qBAG1B,MAAa,EAAS,CACpB,OACA,UACA,SACA,QACA,cACD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "css-drawer",
3
- "version": "0.1.4",
3
+ "version": "0.2.1",
4
4
  "description": "Vaul-quality drawer component using native <dialog> and pure CSS animations",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -27,11 +27,12 @@
27
27
  "default": "./dist/react.cjs"
28
28
  }
29
29
  },
30
- "./styles": "./dist/react.css",
31
- "./drawer.css": "./dist/react.css"
30
+ "./styles": "./src/drawer.css",
31
+ "./drawer.css": "./src/drawer.css"
32
32
  },
33
33
  "files": [
34
- "dist"
34
+ "dist",
35
+ "src/drawer.css"
35
36
  ],
36
37
  "peerDependencies": {
37
38
  "react": ">=18.0.0",
@@ -25,6 +25,7 @@
25
25
  --drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.12), 0 4px 20px hsl(0 0% 0% / 0.08);
26
26
  --drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.12), -4px 0 20px hsl(0 0% 0% / 0.08);
27
27
  --drawer-shadow-left: 10px 0 60px hsl(0 0% 0% / 0.12), 4px 0 20px hsl(0 0% 0% / 0.08);
28
+ --drawer-shadow-modal: 0 25px 50px -12px hsl(0 0% 0% / 0.25);
28
29
 
29
30
  /* Animation */
30
31
  --drawer-duration: 0.5s;
@@ -47,6 +48,7 @@
47
48
  --drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.4), 0 4px 20px hsl(0 0% 0% / 0.3);
48
49
  --drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.4), -4px 0 20px hsl(0 0% 0% / 0.3);
49
50
  --drawer-shadow-left: 10px 0 60px hsl(0 0% 0% / 0.4), 4px 0 20px hsl(0 0% 0% / 0.3);
51
+ --drawer-shadow-modal: 0 25px 50px -12px hsl(0 0% 0% / 0.5);
50
52
  }
51
53
  }
52
54
 
@@ -169,6 +171,30 @@ body:has(.drawer[open]) {
169
171
  box-shadow: var(--drawer-shadow-top);
170
172
  }
171
173
 
174
+ /* Modal (centered) */
175
+ .drawer[data-direction="modal"] {
176
+ --_translate-closed: 0 0;
177
+ --_border-radius: var(--drawer-radius);
178
+ inset: 0;
179
+ margin: auto;
180
+ width: fit-content;
181
+ max-width: var(--drawer-max-width);
182
+ height: fit-content;
183
+ max-height: var(--drawer-max-height);
184
+ box-shadow: var(--drawer-shadow-modal);
185
+ scale: var(--drawer-nested-scale);
186
+ }
187
+
188
+ .drawer[data-direction="modal"][open] {
189
+ scale: 1;
190
+ }
191
+
192
+ @starting-style {
193
+ .drawer[data-direction="modal"][open] {
194
+ scale: var(--drawer-nested-scale);
195
+ }
196
+ }
197
+
172
198
  /* ===== AUTO-NESTING (up to 5 levels) ===== */
173
199
  /* Uses sibling combinators to count open drawers */
174
200
 
@@ -302,6 +328,3 @@ body:has(.drawer[open]) {
302
328
  filter: none;
303
329
  }
304
330
  }
305
-
306
-
307
- /*# sourceMappingURL=react.css.map*/
@@ -1 +0,0 @@
1
- {"version":3,"file":"react.css","names":[],"sources":["../src/drawer.css"],"sourcesContent":["/* CSS Drawer - Vaul-quality drawer with auto-nesting and directions */\n\n:root {\n /* Visual */\n --drawer-bg: #fff;\n --drawer-radius: 24px;\n --drawer-backdrop: hsl(0 0% 0% / 0.4);\n --drawer-backdrop-blur: 4px;\n\n /* Sizing */\n --drawer-max-width: 500px;\n --drawer-max-height: 96dvh;\n\n /* Handle */\n --drawer-handle-bg: hsl(0 0% 80%);\n --drawer-handle-bg-hover: hsl(0 0% 60%);\n --drawer-handle-width: 48px;\n --drawer-handle-width-hover: 56px;\n --drawer-handle-height: 5px;\n --drawer-handle-padding-block: 1rem 0.5rem;\n --drawer-handle-padding-inline: 0;\n\n /* Shadows */\n --drawer-shadow-bottom: 0 -10px 60px hsl(0 0% 0% / 0.12), 0 -4px 20px hsl(0 0% 0% / 0.08);\n --drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.12), 0 4px 20px hsl(0 0% 0% / 0.08);\n --drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.12), -4px 0 20px hsl(0 0% 0% / 0.08);\n --drawer-shadow-left: 10px 0 60px hsl(0 0% 0% / 0.12), 4px 0 20px hsl(0 0% 0% / 0.08);\n\n /* Animation */\n --drawer-duration: 0.5s;\n --drawer-duration-close: 0.35s;\n --drawer-ease: cubic-bezier(0.32, 0.72, 0, 1);\n\n /* Nesting effects */\n --drawer-nested-scale: 0.94;\n --drawer-nested-offset: 20px;\n --drawer-nested-brightness: 0.92;\n --drawer-nested-backdrop: hsl(0 0% 0% / 0.15);\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --drawer-bg: hsl(0 0% 12%);\n --drawer-handle-bg: hsl(0 0% 35%);\n --drawer-handle-bg-hover: hsl(0 0% 50%);\n --drawer-shadow-bottom: 0 -10px 60px hsl(0 0% 0% / 0.4), 0 -4px 20px hsl(0 0% 0% / 0.3);\n --drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.4), 0 4px 20px hsl(0 0% 0% / 0.3);\n --drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.4), -4px 0 20px hsl(0 0% 0% / 0.3);\n --drawer-shadow-left: 10px 0 60px hsl(0 0% 0% / 0.4), 4px 0 20px hsl(0 0% 0% / 0.3);\n }\n}\n\n/* Background scale effect */\nbody {\n transition: scale var(--drawer-duration) var(--drawer-ease), border-radius var(--drawer-duration) var(--drawer-ease);\n transform-origin: center top;\n}\n\nbody:has(.drawer[open]) {\n overflow: hidden;\n scale: var(--drawer-nested-scale);\n border-radius: var(--drawer-radius);\n}\n\n/* Base drawer */\n.drawer {\n border: none;\n padding: 0;\n margin: 0;\n max-width: 100%;\n max-height: 100%;\n position: fixed;\n background: var(--drawer-bg);\n overflow: hidden;\n opacity: 0;\n transition:\n display var(--drawer-duration-close) allow-discrete,\n overlay var(--drawer-duration-close) allow-discrete,\n translate var(--drawer-duration-close) var(--drawer-ease),\n scale var(--drawer-duration-close) var(--drawer-ease),\n filter var(--drawer-duration-close) ease,\n opacity var(--drawer-duration-close) ease;\n\n /* Default: bottom */\n --_translate-closed: 0 100%;\n --_border-radius: var(--drawer-radius) var(--drawer-radius) 0 0;\n inset: auto 0 0 0;\n margin-inline: auto;\n width: 100%;\n max-width: var(--drawer-max-width);\n height: auto;\n max-height: var(--drawer-max-height);\n border-radius: var(--drawer-border-radius, var(--_border-radius));\n box-shadow: var(--drawer-shadow-bottom);\n translate: var(--_translate-closed);\n}\n\n.drawer::backdrop {\n background: var(--drawer-backdrop);\n opacity: 0;\n backdrop-filter: blur(var(--drawer-backdrop-blur));\n -webkit-backdrop-filter: blur(var(--drawer-backdrop-blur));\n transition:\n display var(--drawer-duration-close) allow-discrete,\n overlay var(--drawer-duration-close) allow-discrete,\n opacity var(--drawer-duration-close) ease;\n}\n\n.drawer[open] {\n opacity: 1;\n translate: 0 0;\n transition:\n display var(--drawer-duration) allow-discrete,\n overlay var(--drawer-duration) allow-discrete,\n translate var(--drawer-duration) var(--drawer-ease),\n scale var(--drawer-duration) var(--drawer-ease),\n filter var(--drawer-duration) ease,\n opacity 0.15s ease;\n}\n\n.drawer[open]::backdrop {\n opacity: 1;\n transition: display var(--drawer-duration) allow-discrete, overlay var(--drawer-duration) allow-discrete, opacity 0.2s ease;\n}\n\n@starting-style {\n .drawer[open] { opacity: 0; translate: var(--_translate-closed); }\n .drawer[open]::backdrop { opacity: 0; }\n}\n\n/* ===== DIRECTIONS ===== */\n\n/* Right */\n.drawer[data-direction=\"right\"] {\n --_translate-closed: 100% 0;\n --_border-radius: var(--drawer-radius) 0 0 var(--drawer-radius);\n inset: 0 0 0 auto;\n margin: 0;\n width: 100%;\n max-width: var(--drawer-max-width);\n height: 100dvh;\n max-height: 100dvh;\n box-shadow: var(--drawer-shadow-right);\n}\n\n/* Left */\n.drawer[data-direction=\"left\"] {\n --_translate-closed: -100% 0;\n --_border-radius: 0 var(--drawer-radius) var(--drawer-radius) 0;\n inset: 0 auto 0 0;\n margin: 0;\n width: 100%;\n max-width: var(--drawer-max-width);\n height: 100dvh;\n max-height: 100dvh;\n box-shadow: var(--drawer-shadow-left);\n}\n\n/* Top */\n.drawer[data-direction=\"top\"] {\n --_translate-closed: 0 -100%;\n --_border-radius: 0 0 var(--drawer-radius) var(--drawer-radius);\n inset: 0 0 auto 0;\n margin-inline: auto;\n width: 100%;\n max-width: var(--drawer-max-width);\n height: auto;\n max-height: var(--drawer-max-height);\n box-shadow: var(--drawer-shadow-top);\n}\n\n/* ===== AUTO-NESTING (up to 5 levels) ===== */\n/* Uses sibling combinators to count open drawers */\n\n/* 1+ open drawers after */\n.drawer[open]:has(~ .drawer[open]) {\n scale: var(--drawer-nested-scale);\n translate: 0 calc(-1 * var(--drawer-nested-offset));\n border-radius: var(--drawer-radius);\n filter: brightness(var(--drawer-nested-brightness));\n pointer-events: none;\n}\n\n/* 2+ open drawers after */\n.drawer[open]:has(~ .drawer[open] ~ .drawer[open]) {\n scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale));\n translate: 0 calc(-2 * var(--drawer-nested-offset));\n filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));\n}\n\n/* 3+ open drawers after */\n.drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {\n scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));\n translate: 0 calc(-3 * var(--drawer-nested-offset));\n filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));\n}\n\n/* 4+ open drawers after */\n.drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {\n scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));\n translate: 0 calc(-4 * var(--drawer-nested-offset));\n filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));\n}\n\n/* 5+ open drawers after */\n.drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {\n scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));\n translate: 0 calc(-5 * var(--drawer-nested-offset));\n filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));\n}\n\n/* Lighter backdrop for stacked drawers */\n.drawer[open] ~ .drawer[open]::backdrop {\n background: var(--drawer-nested-backdrop);\n backdrop-filter: none;\n}\n\n/* Handle */\n.drawer-handle {\n display: flex;\n justify-content: center;\n padding-block: var(--drawer-handle-padding-block);\n padding-inline: var(--drawer-handle-padding-inline);\n cursor: grab;\n}\n\n.drawer-handle::before {\n content: '';\n width: var(--drawer-handle-width);\n height: var(--drawer-handle-height);\n background: var(--drawer-handle-bg);\n border-radius: 100px;\n transition: width 0.2s var(--drawer-ease), height 0.2s var(--drawer-ease), background 0.2s ease;\n}\n\n.drawer-handle:hover::before {\n width: var(--drawer-handle-width-hover);\n background: var(--drawer-handle-bg-hover);\n}\n\n/* Vertical handle for left/right drawers */\n.drawer[data-direction=\"left\"] .drawer-handle,\n.drawer[data-direction=\"right\"] .drawer-handle {\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding-block: var(--drawer-handle-padding-inline);\n padding-inline: var(--drawer-handle-padding-block);\n height: 100%;\n position: absolute;\n top: 0;\n writing-mode: vertical-lr;\n}\n\n.drawer[data-direction=\"left\"] .drawer-handle { right: 0; }\n.drawer[data-direction=\"right\"] .drawer-handle { left: 0; }\n\n.drawer[data-direction=\"left\"] .drawer-handle::before,\n.drawer[data-direction=\"right\"] .drawer-handle::before {\n width: var(--drawer-handle-height);\n height: var(--drawer-handle-width);\n}\n\n.drawer[data-direction=\"left\"] .drawer-handle:hover::before,\n.drawer[data-direction=\"right\"] .drawer-handle:hover::before {\n width: var(--drawer-handle-height);\n height: var(--drawer-handle-width-hover);\n}\n\n/* Content - structural only, no opinionated padding */\n.drawer-content {\n overflow-x: hidden;\n overflow-y: auto;\n overscroll-behavior: contain;\n flex: 1;\n min-height: 0;\n}\n\n/* Content sizing for directions */\n.drawer[data-direction=\"left\"] .drawer-content,\n.drawer[data-direction=\"right\"] .drawer-content {\n height: 100%;\n}\n\n/* Reduced motion */\n@media (prefers-reduced-motion: reduce) {\n *, *::before, *::after {\n transition-duration: 0.01ms !important;\n }\n\n body:has(.drawer[open]) {\n scale: 1;\n }\n\n .drawer[open]:has(~ .drawer[open]),\n .drawer[open]:has(~ .drawer[open] ~ .drawer[open]),\n .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open]),\n .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]),\n .drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {\n scale: 1;\n translate: 0 0;\n filter: none;\n }\n}\n"],"mappings":"AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}