css-drawer 0.1.0 → 0.1.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 +241 -12
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +7 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +7 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/react.cjs +1 -1
- package/dist/react.css +65 -50
- package/dist/react.css.map +1 -1
- package/dist/react.d.cts +4 -1
- package/dist/react.d.cts.map +1 -1
- package/dist/react.d.mts +4 -1
- package/dist/react.d.mts.map +1 -1
- package/dist/react.mjs +1 -1
- package/dist/react.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,6 +121,7 @@ ref.current?.close()
|
|
|
121
121
|
| Prop | Type | Default | Description |
|
|
122
122
|
|------|------|---------|-------------|
|
|
123
123
|
| `ref` | `Ref<HTMLDialogElement>` | - | Ref to control the dialog |
|
|
124
|
+
| `closeOnOutsideClick` | `boolean` | `true` | Close when clicking outside the drawer |
|
|
124
125
|
| `className` | `string` | - | Additional CSS classes |
|
|
125
126
|
| `...props` | `DialogHTMLAttributes` | - | All native dialog props |
|
|
126
127
|
|
|
@@ -263,6 +264,7 @@ open(drawer)
|
|
|
263
264
|
| `content` | `string` | `''` | HTML content |
|
|
264
265
|
| `handle` | `boolean` | `true` | Include drag handle |
|
|
265
266
|
| `className` | `string` | `''` | Additional CSS classes |
|
|
267
|
+
| `closeOnOutsideClick` | `boolean` | `true` | Close when clicking outside |
|
|
266
268
|
|
|
267
269
|
**Returns:** `HTMLDialogElement`
|
|
268
270
|
|
|
@@ -387,37 +389,262 @@ No setup required.
|
|
|
387
389
|
|
|
388
390
|
---
|
|
389
391
|
|
|
390
|
-
##
|
|
392
|
+
## Preventing Outside Click Close
|
|
391
393
|
|
|
392
|
-
|
|
394
|
+
By default, clicking the backdrop closes the drawer. Disable this for forms or when accidental dismissal could cause data loss.
|
|
395
|
+
|
|
396
|
+
### React
|
|
397
|
+
|
|
398
|
+
```tsx
|
|
399
|
+
<Drawer.Content ref={ref} closeOnOutsideClick={false}>
|
|
400
|
+
{/* Form content - won't close on backdrop click */}
|
|
401
|
+
</Drawer.Content>
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### Vanilla JS
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
const drawer = create({
|
|
408
|
+
id: 'form-drawer',
|
|
409
|
+
closeOnOutsideClick: false
|
|
410
|
+
})
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Vanilla HTML
|
|
414
|
+
|
|
415
|
+
```html
|
|
416
|
+
<dialog class="drawer" data-close-on-outside-click="false">
|
|
417
|
+
<!-- Won't close on backdrop click -->
|
|
418
|
+
</dialog>
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
> **Note:** Users can still close with Escape key (native dialog behavior) or explicit close buttons.
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## Theming
|
|
426
|
+
|
|
427
|
+
### CSS Custom Properties
|
|
428
|
+
|
|
429
|
+
Override any of these CSS custom properties to customize the drawer:
|
|
393
430
|
|
|
394
431
|
```css
|
|
395
432
|
:root {
|
|
433
|
+
/* Visual */
|
|
396
434
|
--drawer-bg: #fff;
|
|
397
435
|
--drawer-radius: 24px;
|
|
436
|
+
--drawer-backdrop: hsl(0 0% 0% / 0.4);
|
|
437
|
+
--drawer-backdrop-blur: 4px;
|
|
438
|
+
|
|
439
|
+
/* Sizing */
|
|
398
440
|
--drawer-max-width: 500px;
|
|
399
441
|
--drawer-max-height: 96dvh;
|
|
400
|
-
|
|
401
|
-
|
|
442
|
+
|
|
443
|
+
/* Handle */
|
|
444
|
+
--drawer-handle-bg: hsl(0 0% 80%);
|
|
445
|
+
--drawer-handle-bg-hover: hsl(0 0% 60%);
|
|
446
|
+
--drawer-handle-width: 48px;
|
|
447
|
+
--drawer-handle-width-hover: 56px;
|
|
448
|
+
--drawer-handle-height: 5px;
|
|
449
|
+
--drawer-handle-padding-block: 1rem 0.5rem;
|
|
450
|
+
--drawer-handle-padding-inline: 0;
|
|
451
|
+
|
|
452
|
+
/* Shadows */
|
|
453
|
+
--drawer-shadow-bottom: 0 -10px 60px hsl(0 0% 0% / 0.12), 0 -4px 20px hsl(0 0% 0% / 0.08);
|
|
454
|
+
--drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.12), 0 4px 20px hsl(0 0% 0% / 0.08);
|
|
455
|
+
--drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.12), -4px 0 20px hsl(0 0% 0% / 0.08);
|
|
456
|
+
--drawer-shadow-left: 10px 0 60px hsl(0 0% 0% / 0.12), 4px 0 20px hsl(0 0% 0% / 0.08);
|
|
457
|
+
|
|
458
|
+
/* Animation */
|
|
402
459
|
--drawer-duration: 0.5s;
|
|
403
460
|
--drawer-duration-close: 0.35s;
|
|
404
461
|
--drawer-ease: cubic-bezier(0.32, 0.72, 0, 1);
|
|
462
|
+
|
|
463
|
+
/* Nesting effects */
|
|
464
|
+
--drawer-nested-scale: 0.94;
|
|
465
|
+
--drawer-nested-offset: 20px;
|
|
466
|
+
--drawer-nested-brightness: 0.92;
|
|
467
|
+
--drawer-nested-backdrop: hsl(0 0% 0% / 0.15);
|
|
405
468
|
}
|
|
406
469
|
```
|
|
407
470
|
|
|
471
|
+
### All Variables Reference
|
|
472
|
+
|
|
473
|
+
#### Visual
|
|
474
|
+
|
|
475
|
+
| Variable | Default (Light) | Default (Dark) | Description |
|
|
476
|
+
|----------|-----------------|----------------|-------------|
|
|
477
|
+
| `--drawer-bg` | `#fff` | `hsl(0 0% 12%)` | Background color |
|
|
478
|
+
| `--drawer-radius` | `24px` | Same | Base border radius value |
|
|
479
|
+
| `--drawer-border-radius` | Direction-based | Same | Full border-radius override (e.g., `16px 16px 0 0`) |
|
|
480
|
+
| `--drawer-backdrop` | `hsl(0 0% 0% / 0.4)` | Same | Backdrop overlay color |
|
|
481
|
+
| `--drawer-backdrop-blur` | `4px` | Same | Backdrop blur amount |
|
|
482
|
+
|
|
483
|
+
#### Sizing
|
|
484
|
+
|
|
408
485
|
| Variable | Default | Description |
|
|
409
486
|
|----------|---------|-------------|
|
|
410
|
-
| `--drawer-bg` | `#fff` | Background color |
|
|
411
|
-
| `--drawer-radius` | `24px` | Border radius |
|
|
412
487
|
| `--drawer-max-width` | `500px` | Maximum width |
|
|
413
|
-
| `--drawer-max-height` | `96dvh` | Maximum height |
|
|
414
|
-
|
|
415
|
-
|
|
488
|
+
| `--drawer-max-height` | `96dvh` | Maximum height (uses dynamic viewport) |
|
|
489
|
+
|
|
490
|
+
#### Handle
|
|
491
|
+
|
|
492
|
+
| Variable | Default (Light) | Default (Dark) | Description |
|
|
493
|
+
|----------|-----------------|----------------|-------------|
|
|
494
|
+
| `--drawer-handle-bg` | `hsl(0 0% 80%)` | `hsl(0 0% 35%)` | Handle background color |
|
|
495
|
+
| `--drawer-handle-bg-hover` | `hsl(0 0% 60%)` | `hsl(0 0% 50%)` | Handle hover color |
|
|
496
|
+
| `--drawer-handle-width` | `48px` | Same | Handle width |
|
|
497
|
+
| `--drawer-handle-width-hover` | `56px` | Same | Handle width on hover |
|
|
498
|
+
| `--drawer-handle-height` | `5px` | Same | Handle height/thickness |
|
|
499
|
+
| `--drawer-handle-padding-block` | `1rem 0.5rem` | Same | Handle vertical padding |
|
|
500
|
+
| `--drawer-handle-padding-inline` | `0` | Same | Handle horizontal padding |
|
|
501
|
+
|
|
502
|
+
#### Shadows
|
|
503
|
+
|
|
504
|
+
| Variable | Default (Light) | Default (Dark) |
|
|
505
|
+
|----------|-----------------|----------------|
|
|
506
|
+
| `--drawer-shadow-bottom` | `0 -10px 60px hsl(0 0% 0% / 0.12), ...` | Darker |
|
|
507
|
+
| `--drawer-shadow-top` | `0 10px 60px hsl(0 0% 0% / 0.12), ...` | Darker |
|
|
508
|
+
| `--drawer-shadow-left` | `10px 0 60px hsl(0 0% 0% / 0.12), ...` | Darker |
|
|
509
|
+
| `--drawer-shadow-right` | `-10px 0 60px hsl(0 0% 0% / 0.12), ...` | Darker |
|
|
510
|
+
|
|
511
|
+
#### Animation
|
|
512
|
+
|
|
513
|
+
| Variable | Default | Description |
|
|
514
|
+
|----------|---------|-------------|
|
|
416
515
|
| `--drawer-duration` | `0.5s` | Open animation duration |
|
|
417
516
|
| `--drawer-duration-close` | `0.35s` | Close animation duration |
|
|
418
|
-
| `--drawer-ease` | `cubic-bezier(0.32, 0.72, 0, 1)` | Animation easing |
|
|
517
|
+
| `--drawer-ease` | `cubic-bezier(0.32, 0.72, 0, 1)` | Animation easing curve |
|
|
518
|
+
|
|
519
|
+
#### Nesting Effects
|
|
520
|
+
|
|
521
|
+
| Variable | Default | Description |
|
|
522
|
+
|----------|---------|-------------|
|
|
523
|
+
| `--drawer-nested-scale` | `0.94` | Scale factor for stacked drawers |
|
|
524
|
+
| `--drawer-nested-offset` | `20px` | Vertical offset per nesting level |
|
|
525
|
+
| `--drawer-nested-brightness` | `0.92` | Brightness multiplier for stacked drawers |
|
|
526
|
+
| `--drawer-nested-backdrop` | `hsl(0 0% 0% / 0.15)` | Backdrop color for nested drawers |
|
|
527
|
+
|
|
528
|
+
### Dark Mode
|
|
419
529
|
|
|
420
|
-
Dark mode is automatic via `prefers-color-scheme`.
|
|
530
|
+
Dark mode is automatic via `prefers-color-scheme`. Override for manual control:
|
|
531
|
+
|
|
532
|
+
```css
|
|
533
|
+
/* Force dark mode */
|
|
534
|
+
.dark .drawer,
|
|
535
|
+
[data-theme="dark"] .drawer {
|
|
536
|
+
--drawer-bg: hsl(0 0% 12%);
|
|
537
|
+
--drawer-handle-bg: hsl(0 0% 35%);
|
|
538
|
+
--drawer-handle-bg-hover: hsl(0 0% 50%);
|
|
539
|
+
--drawer-shadow-bottom: 0 -10px 60px hsl(0 0% 0% / 0.4), 0 -4px 20px hsl(0 0% 0% / 0.3);
|
|
540
|
+
}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### Tailwind CSS v4
|
|
544
|
+
|
|
545
|
+
CSS Drawer works with Tailwind v4. Use CSS custom properties in your theme:
|
|
546
|
+
|
|
547
|
+
```css
|
|
548
|
+
@import "tailwindcss";
|
|
549
|
+
|
|
550
|
+
@layer base {
|
|
551
|
+
:root {
|
|
552
|
+
--drawer-bg: var(--color-white);
|
|
553
|
+
--drawer-radius: var(--radius-2xl);
|
|
554
|
+
--drawer-handle-bg: var(--color-zinc-300);
|
|
555
|
+
--drawer-backdrop: oklch(0% 0 0 / 0.4);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
.dark {
|
|
559
|
+
--drawer-bg: var(--color-zinc-900);
|
|
560
|
+
--drawer-handle-bg: var(--color-zinc-600);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
You can also pass Tailwind classes directly to components:
|
|
566
|
+
|
|
567
|
+
```tsx
|
|
568
|
+
<Drawer.Content ref={ref} className="bg-white dark:bg-zinc-900">
|
|
569
|
+
<Drawer.Handle className="bg-zinc-300 dark:bg-zinc-600" />
|
|
570
|
+
<div className="drawer-content">
|
|
571
|
+
<Drawer.Title className="text-xl font-semibold">Title</Drawer.Title>
|
|
572
|
+
</div>
|
|
573
|
+
</Drawer.Content>
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
> **Note:** Base drawer styles have equal specificity to Tailwind utilities. For guaranteed overrides, use CSS custom properties or increase specificity with a wrapper class.
|
|
577
|
+
|
|
578
|
+
### Tailwind CSS v3
|
|
579
|
+
|
|
580
|
+
For Tailwind v3, use the `theme()` function in your CSS:
|
|
581
|
+
|
|
582
|
+
```css
|
|
583
|
+
@layer base {
|
|
584
|
+
:root {
|
|
585
|
+
--drawer-bg: theme('colors.white');
|
|
586
|
+
--drawer-radius: theme('borderRadius.2xl');
|
|
587
|
+
--drawer-handle-bg: theme('colors.zinc.300');
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.dark {
|
|
591
|
+
--drawer-bg: theme('colors.zinc.900');
|
|
592
|
+
--drawer-handle-bg: theme('colors.zinc.600');
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
### Per-Drawer Customization
|
|
598
|
+
|
|
599
|
+
Override variables on individual drawers:
|
|
600
|
+
|
|
601
|
+
```tsx
|
|
602
|
+
<Drawer.Content
|
|
603
|
+
ref={ref}
|
|
604
|
+
style={{
|
|
605
|
+
'--drawer-bg': '#f0f0f0',
|
|
606
|
+
'--drawer-radius': '16px',
|
|
607
|
+
'--drawer-max-width': '400px'
|
|
608
|
+
} as React.CSSProperties}
|
|
609
|
+
>
|
|
610
|
+
...
|
|
611
|
+
</Drawer.Content>
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
```html
|
|
615
|
+
<!-- Vanilla HTML -->
|
|
616
|
+
<dialog
|
|
617
|
+
class="drawer"
|
|
618
|
+
style="--drawer-bg: #f0f0f0; --drawer-radius: 16px;"
|
|
619
|
+
>
|
|
620
|
+
...
|
|
621
|
+
</dialog>
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### Custom Border Radius
|
|
625
|
+
|
|
626
|
+
By default, border radius is direction-aware (e.g., bottom drawer rounds top corners). Override with `--drawer-border-radius` for full control:
|
|
627
|
+
|
|
628
|
+
```tsx
|
|
629
|
+
{/* Round all corners */}
|
|
630
|
+
<Drawer.Content
|
|
631
|
+
ref={ref}
|
|
632
|
+
style={{ '--drawer-border-radius': '16px' } as React.CSSProperties}
|
|
633
|
+
>
|
|
634
|
+
|
|
635
|
+
{/* Asymmetric corners */}
|
|
636
|
+
<Drawer.Content
|
|
637
|
+
ref={ref}
|
|
638
|
+
style={{ '--drawer-border-radius': '24px 24px 8px 8px' } as React.CSSProperties}
|
|
639
|
+
>
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
```html
|
|
643
|
+
<!-- No rounded corners -->
|
|
644
|
+
<dialog class="drawer" style="--drawer-border-radius: 0;">
|
|
645
|
+
...
|
|
646
|
+
</dialog>
|
|
647
|
+
```
|
|
421
648
|
|
|
422
649
|
---
|
|
423
650
|
|
|
@@ -427,7 +654,9 @@ Dark mode is automatic via `prefers-color-scheme`.
|
|
|
427
654
|
|-------|-------------|
|
|
428
655
|
| `.drawer` | Required on the dialog element |
|
|
429
656
|
| `.drawer-handle` | Visual drag handle |
|
|
430
|
-
| `.drawer-content` | Scrollable content area |
|
|
657
|
+
| `.drawer-content` | Scrollable content area (structural only - add your own padding) |
|
|
658
|
+
|
|
659
|
+
> **Note:** The `.drawer-content` class is intentionally unopinionated - it only provides scroll behavior (`overflow-y: auto`, `overscroll-behavior: contain`). Add your own padding to match your design system.
|
|
431
660
|
|
|
432
661
|
---
|
|
433
662
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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
|
|
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
2
|
${r?`<div class="drawer-handle"></div>`:``}
|
|
3
3
|
<div class="drawer-content">${n}</div>
|
|
4
|
-
`,
|
|
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;
|
package/dist/index.d.cts
CHANGED
|
@@ -14,6 +14,8 @@ interface CreateDrawerOptions {
|
|
|
14
14
|
handle?: boolean;
|
|
15
15
|
/** Additional CSS classes */
|
|
16
16
|
className?: string;
|
|
17
|
+
/** Close when clicking outside (default: true) */
|
|
18
|
+
closeOnOutsideClick?: boolean;
|
|
17
19
|
}
|
|
18
20
|
interface DrawerEventHandlers {
|
|
19
21
|
/** Called when drawer opens */
|
|
@@ -62,6 +64,7 @@ declare function unmount(drawer: DrawerRef): void;
|
|
|
62
64
|
/**
|
|
63
65
|
* Initialize global backdrop-click-to-close behavior
|
|
64
66
|
* Alternative to adding onclick to each drawer
|
|
67
|
+
* Respects data-close-on-outside-click="false" attribute
|
|
65
68
|
*/
|
|
66
69
|
declare function init(): () => void;
|
|
67
70
|
/**
|
|
@@ -73,9 +76,12 @@ declare function subscribe(drawer: DrawerRef, handlers: DrawerEventHandlers): ()
|
|
|
73
76
|
* React-friendly hook helper - returns props to spread on dialog
|
|
74
77
|
* Usage: <dialog {...drawer.props('my-drawer')} />
|
|
75
78
|
*/
|
|
76
|
-
declare function props(id: string
|
|
79
|
+
declare function props(id: string, options?: {
|
|
80
|
+
closeOnOutsideClick?: boolean;
|
|
81
|
+
}): {
|
|
77
82
|
readonly id: string;
|
|
78
83
|
readonly className: "drawer";
|
|
84
|
+
readonly 'data-close-on-outside-click': "false" | undefined;
|
|
79
85
|
readonly onClick: (e: MouseEvent) => void;
|
|
80
86
|
};
|
|
81
87
|
//#endregion
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;AAwCA;AAEA;AAEA;
|
|
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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -14,6 +14,8 @@ interface CreateDrawerOptions {
|
|
|
14
14
|
handle?: boolean;
|
|
15
15
|
/** Additional CSS classes */
|
|
16
16
|
className?: string;
|
|
17
|
+
/** Close when clicking outside (default: true) */
|
|
18
|
+
closeOnOutsideClick?: boolean;
|
|
17
19
|
}
|
|
18
20
|
interface DrawerEventHandlers {
|
|
19
21
|
/** Called when drawer opens */
|
|
@@ -62,6 +64,7 @@ declare function unmount(drawer: DrawerRef): void;
|
|
|
62
64
|
/**
|
|
63
65
|
* Initialize global backdrop-click-to-close behavior
|
|
64
66
|
* Alternative to adding onclick to each drawer
|
|
67
|
+
* Respects data-close-on-outside-click="false" attribute
|
|
65
68
|
*/
|
|
66
69
|
declare function init(): () => void;
|
|
67
70
|
/**
|
|
@@ -73,9 +76,12 @@ declare function subscribe(drawer: DrawerRef, handlers: DrawerEventHandlers): ()
|
|
|
73
76
|
* React-friendly hook helper - returns props to spread on dialog
|
|
74
77
|
* Usage: <dialog {...drawer.props('my-drawer')} />
|
|
75
78
|
*/
|
|
76
|
-
declare function props(id: string
|
|
79
|
+
declare function props(id: string, options?: {
|
|
80
|
+
closeOnOutsideClick?: boolean;
|
|
81
|
+
}): {
|
|
77
82
|
readonly id: string;
|
|
78
83
|
readonly className: "drawer";
|
|
84
|
+
readonly 'data-close-on-outside-click': "false" | undefined;
|
|
79
85
|
readonly onClick: (e: MouseEvent) => void;
|
|
80
86
|
};
|
|
81
87
|
//#endregion
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;AAwCA;AAEA;AAEA;
|
|
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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +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
|
|
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
2
|
${r?`<div class="drawer-handle"></div>`:``}
|
|
3
3
|
<div class="drawer-content">${n}</div>
|
|
4
|
-
`,
|
|
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
5
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -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}\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 = '' } = options\n\n const dialog = document.createElement('dialog') as DrawerElement\n dialog.className = `drawer ${className}`.trim()\n if (id) dialog.id = id\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\n dialog.addEventListener('click', (e) => {\n if (e.target === dialog) dialog.close()\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 */\nexport function init(): () => void {\n const handler = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n if (target.matches('dialog.drawer')) {\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) {\n return {\n id,\n className: 'drawer',\n onClick: (e: MouseEvent) => {\n if (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,
|
|
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"}
|
package/dist/react.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
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:e,className:n,...
|
|
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:e,className:n,closeOnOutsideClick:i=!0,...a},o)=>{let{direction:s}=r();return(0,t.jsx)(`dialog`,{ref:o,className:`drawer ${n??``}`.trim(),"data-direction":s,onClick:e=>{a.onClick?.(e),i&&e.target===e.currentTarget&&e.currentTarget.close()},...a,children:e})});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.css
CHANGED
|
@@ -1,25 +1,48 @@
|
|
|
1
1
|
/* CSS Drawer - Vaul-quality drawer with auto-nesting and directions */
|
|
2
2
|
|
|
3
3
|
:root {
|
|
4
|
+
/* Visual */
|
|
4
5
|
--drawer-bg: #fff;
|
|
5
6
|
--drawer-radius: 24px;
|
|
7
|
+
--drawer-backdrop: hsl(0 0% 0% / 0.4);
|
|
8
|
+
--drawer-backdrop-blur: 4px;
|
|
9
|
+
|
|
10
|
+
/* Sizing */
|
|
6
11
|
--drawer-max-width: 500px;
|
|
7
12
|
--drawer-max-height: 96dvh;
|
|
8
|
-
|
|
9
|
-
|
|
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 */
|
|
10
24
|
--drawer-shadow-bottom: 0 -10px 60px hsl(0 0% 0% / 0.12), 0 -4px 20px hsl(0 0% 0% / 0.08);
|
|
11
25
|
--drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.12), 0 4px 20px hsl(0 0% 0% / 0.08);
|
|
12
26
|
--drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.12), -4px 0 20px hsl(0 0% 0% / 0.08);
|
|
13
27
|
--drawer-shadow-left: 10px 0 60px hsl(0 0% 0% / 0.12), 4px 0 20px hsl(0 0% 0% / 0.08);
|
|
28
|
+
|
|
29
|
+
/* Animation */
|
|
14
30
|
--drawer-duration: 0.5s;
|
|
15
31
|
--drawer-duration-close: 0.35s;
|
|
16
32
|
--drawer-ease: cubic-bezier(0.32, 0.72, 0, 1);
|
|
33
|
+
|
|
34
|
+
/* Nesting effects */
|
|
35
|
+
--drawer-nested-scale: 0.94;
|
|
36
|
+
--drawer-nested-offset: 20px;
|
|
37
|
+
--drawer-nested-brightness: 0.92;
|
|
38
|
+
--drawer-nested-backdrop: hsl(0 0% 0% / 0.15);
|
|
17
39
|
}
|
|
18
40
|
|
|
19
41
|
@media (prefers-color-scheme: dark) {
|
|
20
42
|
:root {
|
|
21
43
|
--drawer-bg: hsl(0 0% 12%);
|
|
22
|
-
--drawer-handle: hsl(0 0% 35%);
|
|
44
|
+
--drawer-handle-bg: hsl(0 0% 35%);
|
|
45
|
+
--drawer-handle-bg-hover: hsl(0 0% 50%);
|
|
23
46
|
--drawer-shadow-bottom: 0 -10px 60px hsl(0 0% 0% / 0.4), 0 -4px 20px hsl(0 0% 0% / 0.3);
|
|
24
47
|
--drawer-shadow-top: 0 10px 60px hsl(0 0% 0% / 0.4), 0 4px 20px hsl(0 0% 0% / 0.3);
|
|
25
48
|
--drawer-shadow-right: -10px 0 60px hsl(0 0% 0% / 0.4), -4px 0 20px hsl(0 0% 0% / 0.3);
|
|
@@ -35,7 +58,7 @@ body {
|
|
|
35
58
|
|
|
36
59
|
body:has(.drawer[open]) {
|
|
37
60
|
overflow: hidden;
|
|
38
|
-
scale:
|
|
61
|
+
scale: var(--drawer-nested-scale);
|
|
39
62
|
border-radius: var(--drawer-radius);
|
|
40
63
|
}
|
|
41
64
|
|
|
@@ -60,13 +83,14 @@ body:has(.drawer[open]) {
|
|
|
60
83
|
|
|
61
84
|
/* Default: bottom */
|
|
62
85
|
--_translate-closed: 0 100%;
|
|
86
|
+
--_border-radius: var(--drawer-radius) var(--drawer-radius) 0 0;
|
|
63
87
|
inset: auto 0 0 0;
|
|
64
88
|
margin-inline: auto;
|
|
65
89
|
width: 100%;
|
|
66
90
|
max-width: var(--drawer-max-width);
|
|
67
91
|
height: auto;
|
|
68
92
|
max-height: var(--drawer-max-height);
|
|
69
|
-
border-radius: var(--drawer-radius
|
|
93
|
+
border-radius: var(--drawer-border-radius, var(--_border-radius));
|
|
70
94
|
box-shadow: var(--drawer-shadow-bottom);
|
|
71
95
|
translate: var(--_translate-closed);
|
|
72
96
|
}
|
|
@@ -74,8 +98,8 @@ body:has(.drawer[open]) {
|
|
|
74
98
|
.drawer::backdrop {
|
|
75
99
|
background: var(--drawer-backdrop);
|
|
76
100
|
opacity: 0;
|
|
77
|
-
backdrop-filter: blur(
|
|
78
|
-
-webkit-backdrop-filter: blur(
|
|
101
|
+
backdrop-filter: blur(var(--drawer-backdrop-blur));
|
|
102
|
+
-webkit-backdrop-filter: blur(var(--drawer-backdrop-blur));
|
|
79
103
|
transition:
|
|
80
104
|
display var(--drawer-duration-close) allow-discrete,
|
|
81
105
|
overlay var(--drawer-duration-close) allow-discrete,
|
|
@@ -109,39 +133,39 @@ body:has(.drawer[open]) {
|
|
|
109
133
|
/* Right */
|
|
110
134
|
.drawer[data-direction="right"] {
|
|
111
135
|
--_translate-closed: 100% 0;
|
|
136
|
+
--_border-radius: var(--drawer-radius) 0 0 var(--drawer-radius);
|
|
112
137
|
inset: 0 0 0 auto;
|
|
113
138
|
margin: 0;
|
|
114
139
|
width: 100%;
|
|
115
140
|
max-width: var(--drawer-max-width);
|
|
116
141
|
height: 100dvh;
|
|
117
142
|
max-height: 100dvh;
|
|
118
|
-
border-radius: var(--drawer-radius) 0 0 var(--drawer-radius);
|
|
119
143
|
box-shadow: var(--drawer-shadow-right);
|
|
120
144
|
}
|
|
121
145
|
|
|
122
146
|
/* Left */
|
|
123
147
|
.drawer[data-direction="left"] {
|
|
124
148
|
--_translate-closed: -100% 0;
|
|
149
|
+
--_border-radius: 0 var(--drawer-radius) var(--drawer-radius) 0;
|
|
125
150
|
inset: 0 auto 0 0;
|
|
126
151
|
margin: 0;
|
|
127
152
|
width: 100%;
|
|
128
153
|
max-width: var(--drawer-max-width);
|
|
129
154
|
height: 100dvh;
|
|
130
155
|
max-height: 100dvh;
|
|
131
|
-
border-radius: 0 var(--drawer-radius) var(--drawer-radius) 0;
|
|
132
156
|
box-shadow: var(--drawer-shadow-left);
|
|
133
157
|
}
|
|
134
158
|
|
|
135
159
|
/* Top */
|
|
136
160
|
.drawer[data-direction="top"] {
|
|
137
161
|
--_translate-closed: 0 -100%;
|
|
162
|
+
--_border-radius: 0 0 var(--drawer-radius) var(--drawer-radius);
|
|
138
163
|
inset: 0 0 auto 0;
|
|
139
164
|
margin-inline: auto;
|
|
140
165
|
width: 100%;
|
|
141
166
|
max-width: var(--drawer-max-width);
|
|
142
167
|
height: auto;
|
|
143
168
|
max-height: var(--drawer-max-height);
|
|
144
|
-
border-radius: 0 0 var(--drawer-radius) var(--drawer-radius);
|
|
145
169
|
box-shadow: var(--drawer-shadow-top);
|
|
146
170
|
}
|
|
147
171
|
|
|
@@ -150,44 +174,44 @@ body:has(.drawer[open]) {
|
|
|
150
174
|
|
|
151
175
|
/* 1+ open drawers after */
|
|
152
176
|
.drawer[open]:has(~ .drawer[open]) {
|
|
153
|
-
scale:
|
|
154
|
-
translate: 0 -
|
|
177
|
+
scale: var(--drawer-nested-scale);
|
|
178
|
+
translate: 0 calc(-1 * var(--drawer-nested-offset));
|
|
155
179
|
border-radius: var(--drawer-radius);
|
|
156
|
-
filter: brightness(
|
|
180
|
+
filter: brightness(var(--drawer-nested-brightness));
|
|
157
181
|
pointer-events: none;
|
|
158
182
|
}
|
|
159
183
|
|
|
160
184
|
/* 2+ open drawers after */
|
|
161
185
|
.drawer[open]:has(~ .drawer[open] ~ .drawer[open]) {
|
|
162
|
-
scale:
|
|
163
|
-
translate: 0 -
|
|
164
|
-
filter: brightness(
|
|
186
|
+
scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale));
|
|
187
|
+
translate: 0 calc(-2 * var(--drawer-nested-offset));
|
|
188
|
+
filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));
|
|
165
189
|
}
|
|
166
190
|
|
|
167
191
|
/* 3+ open drawers after */
|
|
168
192
|
.drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {
|
|
169
|
-
scale:
|
|
170
|
-
translate: 0 -
|
|
171
|
-
filter: brightness(
|
|
193
|
+
scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));
|
|
194
|
+
translate: 0 calc(-3 * var(--drawer-nested-offset));
|
|
195
|
+
filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));
|
|
172
196
|
}
|
|
173
197
|
|
|
174
198
|
/* 4+ open drawers after */
|
|
175
199
|
.drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {
|
|
176
|
-
scale:
|
|
177
|
-
translate: 0 -
|
|
178
|
-
filter: brightness(
|
|
200
|
+
scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));
|
|
201
|
+
translate: 0 calc(-4 * var(--drawer-nested-offset));
|
|
202
|
+
filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));
|
|
179
203
|
}
|
|
180
204
|
|
|
181
205
|
/* 5+ open drawers after */
|
|
182
206
|
.drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {
|
|
183
|
-
scale:
|
|
184
|
-
translate: 0 -
|
|
185
|
-
filter: brightness(
|
|
207
|
+
scale: calc(var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale) * var(--drawer-nested-scale));
|
|
208
|
+
translate: 0 calc(-5 * var(--drawer-nested-offset));
|
|
209
|
+
filter: brightness(calc(var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness) * var(--drawer-nested-brightness)));
|
|
186
210
|
}
|
|
187
211
|
|
|
188
212
|
/* Lighter backdrop for stacked drawers */
|
|
189
213
|
.drawer[open] ~ .drawer[open]::backdrop {
|
|
190
|
-
background:
|
|
214
|
+
background: var(--drawer-nested-backdrop);
|
|
191
215
|
backdrop-filter: none;
|
|
192
216
|
}
|
|
193
217
|
|
|
@@ -195,22 +219,23 @@ body:has(.drawer[open]) {
|
|
|
195
219
|
.drawer-handle {
|
|
196
220
|
display: flex;
|
|
197
221
|
justify-content: center;
|
|
198
|
-
padding:
|
|
222
|
+
padding-block: var(--drawer-handle-padding-block);
|
|
223
|
+
padding-inline: var(--drawer-handle-padding-inline);
|
|
199
224
|
cursor: grab;
|
|
200
225
|
}
|
|
201
226
|
|
|
202
227
|
.drawer-handle::before {
|
|
203
228
|
content: '';
|
|
204
|
-
width:
|
|
205
|
-
height:
|
|
206
|
-
background: var(--drawer-handle);
|
|
229
|
+
width: var(--drawer-handle-width);
|
|
230
|
+
height: var(--drawer-handle-height);
|
|
231
|
+
background: var(--drawer-handle-bg);
|
|
207
232
|
border-radius: 100px;
|
|
208
233
|
transition: width 0.2s var(--drawer-ease), height 0.2s var(--drawer-ease), background 0.2s ease;
|
|
209
234
|
}
|
|
210
235
|
|
|
211
236
|
.drawer-handle:hover::before {
|
|
212
|
-
width:
|
|
213
|
-
background:
|
|
237
|
+
width: var(--drawer-handle-width-hover);
|
|
238
|
+
background: var(--drawer-handle-bg-hover);
|
|
214
239
|
}
|
|
215
240
|
|
|
216
241
|
/* Vertical handle for left/right drawers */
|
|
@@ -219,7 +244,8 @@ body:has(.drawer[open]) {
|
|
|
219
244
|
flex-direction: column;
|
|
220
245
|
align-items: center;
|
|
221
246
|
justify-content: center;
|
|
222
|
-
padding:
|
|
247
|
+
padding-block: var(--drawer-handle-padding-inline);
|
|
248
|
+
padding-inline: var(--drawer-handle-padding-block);
|
|
223
249
|
height: 100%;
|
|
224
250
|
position: absolute;
|
|
225
251
|
top: 0;
|
|
@@ -231,40 +257,29 @@ body:has(.drawer[open]) {
|
|
|
231
257
|
|
|
232
258
|
.drawer[data-direction="left"] .drawer-handle::before,
|
|
233
259
|
.drawer[data-direction="right"] .drawer-handle::before {
|
|
234
|
-
width:
|
|
235
|
-
height:
|
|
260
|
+
width: var(--drawer-handle-height);
|
|
261
|
+
height: var(--drawer-handle-width);
|
|
236
262
|
}
|
|
237
263
|
|
|
238
264
|
.drawer[data-direction="left"] .drawer-handle:hover::before,
|
|
239
265
|
.drawer[data-direction="right"] .drawer-handle:hover::before {
|
|
240
|
-
width:
|
|
241
|
-
height:
|
|
266
|
+
width: var(--drawer-handle-height);
|
|
267
|
+
height: var(--drawer-handle-width-hover);
|
|
242
268
|
}
|
|
243
269
|
|
|
244
|
-
/* Content */
|
|
270
|
+
/* Content - structural only, no opinionated padding */
|
|
245
271
|
.drawer-content {
|
|
246
|
-
padding: 0.5rem 1.5rem 2rem;
|
|
247
|
-
padding-bottom: calc(2rem + env(safe-area-inset-bottom, 0px));
|
|
248
272
|
overflow-x: hidden;
|
|
249
273
|
overflow-y: auto;
|
|
250
274
|
overscroll-behavior: contain;
|
|
251
|
-
max-height: calc(var(--drawer-max-height) - 60px);
|
|
252
275
|
}
|
|
253
276
|
|
|
254
|
-
/* Content
|
|
277
|
+
/* Content sizing for directions */
|
|
255
278
|
.drawer[data-direction="left"] .drawer-content,
|
|
256
279
|
.drawer[data-direction="right"] .drawer-content {
|
|
257
|
-
padding: 1.5rem;
|
|
258
|
-
padding-left: 2.5rem;
|
|
259
|
-
max-height: 100%;
|
|
260
280
|
height: 100%;
|
|
261
281
|
}
|
|
262
282
|
|
|
263
|
-
.drawer[data-direction="top"] .drawer-content {
|
|
264
|
-
padding-bottom: 1.5rem;
|
|
265
|
-
padding-top: 0.5rem;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
283
|
/* Reduced motion */
|
|
269
284
|
@media (prefers-reduced-motion: reduce) {
|
|
270
285
|
*, *::before, *::after {
|
package/dist/react.css.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 --drawer-bg: #fff;\n --drawer-radius: 24px;\n --drawer-max-width: 500px;\n --drawer-max-height: 96dvh;\n --drawer-backdrop: hsl(0 0% 0% / 0.4);\n --drawer-handle: hsl(0 0% 80%);\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-duration: 0.5s;\n --drawer-duration-close: 0.35s;\n --drawer-ease: cubic-bezier(0.32, 0.72, 0, 1);\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --drawer-bg: hsl(0 0% 12%);\n --drawer-handle: hsl(0 0% 35%);\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: 0.94;\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 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-radius) var(--drawer-radius) 0 0;\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(4px);\n -webkit-backdrop-filter: blur(4px);\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 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 border-radius: var(--drawer-radius) 0 0 var(--drawer-radius);\n box-shadow: var(--drawer-shadow-right);\n}\n\n/* Left */\n.drawer[data-direction=\"left\"] {\n --_translate-closed: -100% 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 border-radius: 0 var(--drawer-radius) var(--drawer-radius) 0;\n box-shadow: var(--drawer-shadow-left);\n}\n\n/* Top */\n.drawer[data-direction=\"top\"] {\n --_translate-closed: 0 -100%;\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 border-radius: 0 0 var(--drawer-radius) var(--drawer-radius);\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: 0.94;\n translate: 0 -20px;\n border-radius: var(--drawer-radius);\n filter: brightness(0.92);\n pointer-events: none;\n}\n\n/* 2+ open drawers after */\n.drawer[open]:has(~ .drawer[open] ~ .drawer[open]) {\n scale: 0.88;\n translate: 0 -40px;\n filter: brightness(0.84);\n}\n\n/* 3+ open drawers after */\n.drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {\n scale: 0.82;\n translate: 0 -60px;\n filter: brightness(0.76);\n}\n\n/* 4+ open drawers after */\n.drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {\n scale: 0.76;\n translate: 0 -80px;\n filter: brightness(0.68);\n}\n\n/* 5+ open drawers after */\n.drawer[open]:has(~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open] ~ .drawer[open]) {\n scale: 0.70;\n translate: 0 -100px;\n filter: brightness(0.60);\n}\n\n/* Lighter backdrop for stacked drawers */\n.drawer[open] ~ .drawer[open]::backdrop {\n background: hsl(0 0% 0% / 0.15);\n backdrop-filter: none;\n}\n\n/* Handle */\n.drawer-handle {\n display: flex;\n justify-content: center;\n padding: 1rem 0 0.5rem;\n cursor: grab;\n}\n\n.drawer-handle::before {\n content: '';\n width: 48px;\n height: 5px;\n background: var(--drawer-handle);\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: 56px;\n background: hsl(0 0% 60%);\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: 0.5rem 1rem 0.5rem 0.5rem;\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: 5px;\n height: 48px;\n}\n\n.drawer[data-direction=\"left\"] .drawer-handle:hover::before,\n.drawer[data-direction=\"right\"] .drawer-handle:hover::before {\n width: 5px;\n height: 56px;\n}\n\n/* Content */\n.drawer-content {\n padding: 0.5rem 1.5rem 2rem;\n padding-bottom: calc(2rem + env(safe-area-inset-bottom, 0px));\n overflow-x: hidden;\n overflow-y: auto;\n overscroll-behavior: contain;\n max-height: calc(var(--drawer-max-height) - 60px);\n}\n\n/* Content adjustments for directions */\n.drawer[data-direction=\"left\"] .drawer-content,\n.drawer[data-direction=\"right\"] .drawer-content {\n padding: 1.5rem;\n padding-left: 2.5rem;\n max-height: 100%;\n height: 100%;\n}\n\n.drawer[data-direction=\"top\"] .drawer-content {\n padding-bottom: 1.5rem;\n padding-top: 0.5rem;\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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;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;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
|
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}\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;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
package/dist/react.d.cts
CHANGED
|
@@ -13,7 +13,10 @@ declare function Root({
|
|
|
13
13
|
children,
|
|
14
14
|
direction
|
|
15
15
|
}: RootProps): react_jsx_runtime0.JSX.Element;
|
|
16
|
-
interface ContentProps extends Omit<ComponentPropsWithoutRef<'dialog'>, 'open'> {
|
|
16
|
+
interface ContentProps extends Omit<ComponentPropsWithoutRef<'dialog'>, 'open'> {
|
|
17
|
+
/** Close when clicking outside the drawer (default: true) */
|
|
18
|
+
closeOnOutsideClick?: boolean;
|
|
19
|
+
}
|
|
17
20
|
interface HandleProps extends ComponentPropsWithoutRef<'div'> {}
|
|
18
21
|
interface TitleProps extends ComponentPropsWithoutRef<'h2'> {}
|
|
19
22
|
interface DescriptionProps extends ComponentPropsWithoutRef<'p'> {}
|
package/dist/react.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.cts","names":[],"sources":["../src/react.tsx"],"sourcesContent":[],"mappings":";;;;;KA8CK,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;
|
|
1
|
+
{"version":3,"file":"react.d.cts","names":[],"sources":["../src/react.tsx"],"sourcesContent":[],"mappings":";;;;;KA8CK,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,mBAAA,CAAA,EAAA,OAAA;;AAAA,UAwCtC,WAAA,SAAoB,wBA/BM,CAAA,KAAL,CAAA,CAAI,CAAA;AA+BmB,UAa5C,UAAA,SAAmB,wBAAA,CAAwB,IAAA,CAAA,CAAA,CAAA;AAgBrD,UARU,gBAAA,SAAyB,wBAclC,CAAA,GAAA,CAAA,CAAA;cANY"}
|
package/dist/react.d.mts
CHANGED
|
@@ -13,7 +13,10 @@ declare function Root({
|
|
|
13
13
|
children,
|
|
14
14
|
direction
|
|
15
15
|
}: RootProps): react_jsx_runtime0.JSX.Element;
|
|
16
|
-
interface ContentProps extends Omit<ComponentPropsWithoutRef<'dialog'>, 'open'> {
|
|
16
|
+
interface ContentProps extends Omit<ComponentPropsWithoutRef<'dialog'>, 'open'> {
|
|
17
|
+
/** Close when clicking outside the drawer (default: true) */
|
|
18
|
+
closeOnOutsideClick?: boolean;
|
|
19
|
+
}
|
|
17
20
|
interface HandleProps extends ComponentPropsWithoutRef<'div'> {}
|
|
18
21
|
interface TitleProps extends ComponentPropsWithoutRef<'h2'> {}
|
|
19
22
|
interface DescriptionProps extends ComponentPropsWithoutRef<'p'> {}
|
package/dist/react.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.mts","names":[],"sources":["../src/react.tsx"],"sourcesContent":[],"mappings":";;;;;KA8CK,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;
|
|
1
|
+
{"version":3,"file":"react.d.mts","names":[],"sources":["../src/react.tsx"],"sourcesContent":[],"mappings":";;;;;KA8CK,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,mBAAA,CAAA,EAAA,OAAA;;AAAA,UAwCtC,WAAA,SAAoB,wBA/BM,CAAA,KAAL,CAAI,CAAA,CAAA;AA+BmB,UAa5C,UAAA,SAAmB,wBAAwB,CAAA,IAAA,CAAA,CAAA,CAAA;AAgBrD,UARU,gBAAA,SAAyB,wBAclC,CAAA,GAAA,CAAA,CAAA;cANY"}
|
package/dist/react.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import{createContext as e,forwardRef as t,useContext as n}from"react";import{jsx as r}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 i=e({direction:void 0});function a(){return n(i)}function o({children:e,direction:t}){return r(i.Provider,{value:{direction:t},children:e})}const s=t(({children:e,className:t,...
|
|
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 i=e({direction:void 0});function a(){return n(i)}function o({children:e,direction:t}){return r(i.Provider,{value:{direction:t},children:e})}const s=t(({children:e,className:t,closeOnOutsideClick:n=!0,...i},o)=>{let{direction:s}=a();return r(`dialog`,{ref:o,className:`drawer ${t??``}`.trim(),"data-direction":s,onClick:e=>{i.onClick?.(e),n&&e.target===e.currentTarget&&e.currentTarget.close()},...i,children:e})});s.displayName=`Drawer.Content`;const c=t(({className:e,...t},n)=>r(`div`,{ref:n,className:`drawer-handle ${e??``}`.trim(),"aria-hidden":`true`,...t}));c.displayName=`Drawer.Handle`;const l=t((e,t)=>r(`h2`,{ref:t,...e}));l.displayName=`Drawer.Title`;const u=t((e,t)=>r(`p`,{ref:t,...e}));u.displayName=`Drawer.Description`;const d={Root:o,Content:s,Handle:c,Title:l,Description:u};export{d as Drawer};
|
|
3
3
|
//# sourceMappingURL=react.mjs.map
|
package/dist/react.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.mjs","names":[],"sources":["../src/react.tsx"],"sourcesContent":["import {\n createContext,\n useContext,\n forwardRef,\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\nconst Content = forwardRef<HTMLDialogElement, ContentProps>(\n ({ children, className, ...props }, ref) => {\n const { direction } = useDrawerContext()\n\n return (\n <dialog\n ref={ref}\n className={`drawer ${className ?? ''}`.trim()}\n data-direction={direction}\n onClick={(e) => {\n props.onClick?.(e)\n // Backdrop click - only if clicking the dialog element itself\n if (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":"8GAUA,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,
|
|
1
|
+
{"version":3,"file":"react.mjs","names":[],"sources":["../src/react.tsx"],"sourcesContent":["import {\n createContext,\n useContext,\n forwardRef,\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 /** Close when clicking outside the drawer (default: true) */\n closeOnOutsideClick?: boolean\n}\n\nconst Content = forwardRef<HTMLDialogElement, ContentProps>(\n ({ children, className, closeOnOutsideClick = true, ...props }, ref) => {\n const { direction } = useDrawerContext()\n\n return (\n <dialog\n ref={ref}\n className={`drawer ${className ?? ''}`.trim()}\n data-direction={direction}\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":"8GAUA,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,CAU7B,MAAM,EAAU,GACb,CAAE,WAAU,YAAW,sBAAsB,GAAM,GAAG,GAAS,IAAQ,CACtE,GAAM,CAAE,aAAc,GAAkB,CAExC,OACE,EAAC,SAAA,CACM,MACL,UAAW,UAAU,GAAa,KAAK,MAAM,CAC7C,iBAAgB,EAChB,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"}
|