@duskmoon-dev/el-drawer 0.4.0 → 0.6.0
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 +158 -0
- package/dist/cjs/index.js +15 -99
- package/dist/cjs/index.js.map +3 -3
- package/dist/cjs/register.js +15 -99
- package/dist/cjs/register.js.map +3 -3
- package/dist/esm/index.js +13 -97
- package/dist/esm/index.js.map +3 -3
- package/dist/esm/register.js +13 -97
- package/dist/esm/register.js.map +3 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/el-dm-drawer.d.ts +2 -1
- package/dist/types/el-dm-drawer.d.ts.map +1 -1
- package/package.json +6 -5
package/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# @duskmoon-dev/el-drawer
|
|
2
|
+
|
|
3
|
+
A slide-out drawer component built with Web Components.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @duskmoon-dev/el-drawer
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Auto-Register
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import '@duskmoon-dev/el-drawer/register';
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<el-dm-drawer id="myDrawer">
|
|
21
|
+
<span slot="header">Drawer Title</span>
|
|
22
|
+
<p>Drawer content goes here.</p>
|
|
23
|
+
</el-dm-drawer>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Manual Registration
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { ElDmDrawer, register } from '@duskmoon-dev/el-drawer';
|
|
30
|
+
|
|
31
|
+
// Register with default tag name
|
|
32
|
+
register();
|
|
33
|
+
|
|
34
|
+
// Or register with custom tag name
|
|
35
|
+
customElements.define('my-drawer', ElDmDrawer);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Positions
|
|
39
|
+
|
|
40
|
+
| Position | Description |
|
|
41
|
+
|----------|-------------|
|
|
42
|
+
| `left` | Slide from left (default) |
|
|
43
|
+
| `right` | Slide from right |
|
|
44
|
+
| `top` | Slide from top |
|
|
45
|
+
| `bottom` | Slide from bottom |
|
|
46
|
+
|
|
47
|
+
## Attributes
|
|
48
|
+
|
|
49
|
+
| Attribute | Type | Default | Description |
|
|
50
|
+
|-----------|------|---------|-------------|
|
|
51
|
+
| `open` | `boolean` | `false` | Whether the drawer is open |
|
|
52
|
+
| `position` | `string` | `'left'` | Position: `left`, `right`, `top`, `bottom` |
|
|
53
|
+
| `modal` | `boolean` | `true` | Show backdrop overlay |
|
|
54
|
+
| `width` | `string` | `'300px'` | Drawer width (for left/right) |
|
|
55
|
+
|
|
56
|
+
## Slots
|
|
57
|
+
|
|
58
|
+
| Slot | Description |
|
|
59
|
+
|------|-------------|
|
|
60
|
+
| (default) | Drawer body content |
|
|
61
|
+
| `header` | Drawer header |
|
|
62
|
+
| `footer` | Drawer footer |
|
|
63
|
+
|
|
64
|
+
## CSS Parts
|
|
65
|
+
|
|
66
|
+
| Part | Description |
|
|
67
|
+
|------|-------------|
|
|
68
|
+
| `drawer` | The drawer element |
|
|
69
|
+
| `backdrop` | The backdrop overlay |
|
|
70
|
+
| `content` | The content wrapper |
|
|
71
|
+
| `header` | The header section |
|
|
72
|
+
| `body` | The body section |
|
|
73
|
+
| `footer` | The footer section |
|
|
74
|
+
|
|
75
|
+
## Events
|
|
76
|
+
|
|
77
|
+
| Event | Detail | Description |
|
|
78
|
+
|-------|--------|-------------|
|
|
79
|
+
| `open` | - | Fired when drawer opens |
|
|
80
|
+
| `close` | - | Fired when drawer closes |
|
|
81
|
+
|
|
82
|
+
## Examples
|
|
83
|
+
|
|
84
|
+
### Basic
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<el-dm-button onclick="document.querySelector('#drawer').open = true">
|
|
88
|
+
Open Drawer
|
|
89
|
+
</el-dm-button>
|
|
90
|
+
|
|
91
|
+
<el-dm-drawer id="drawer">
|
|
92
|
+
<span slot="header">Menu</span>
|
|
93
|
+
<nav>
|
|
94
|
+
<a href="#">Home</a>
|
|
95
|
+
<a href="#">About</a>
|
|
96
|
+
<a href="#">Contact</a>
|
|
97
|
+
</nav>
|
|
98
|
+
</el-dm-drawer>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Positions
|
|
102
|
+
|
|
103
|
+
```html
|
|
104
|
+
<el-dm-drawer position="left">Left drawer</el-dm-drawer>
|
|
105
|
+
<el-dm-drawer position="right">Right drawer</el-dm-drawer>
|
|
106
|
+
<el-dm-drawer position="top">Top drawer</el-dm-drawer>
|
|
107
|
+
<el-dm-drawer position="bottom">Bottom drawer</el-dm-drawer>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Custom Width
|
|
111
|
+
|
|
112
|
+
```html
|
|
113
|
+
<el-dm-drawer width="400px">
|
|
114
|
+
Wider drawer
|
|
115
|
+
</el-dm-drawer>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Without Backdrop
|
|
119
|
+
|
|
120
|
+
```html
|
|
121
|
+
<el-dm-drawer modal="false">
|
|
122
|
+
No backdrop
|
|
123
|
+
</el-dm-drawer>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### With Footer
|
|
127
|
+
|
|
128
|
+
```html
|
|
129
|
+
<el-dm-drawer>
|
|
130
|
+
<span slot="header">Settings</span>
|
|
131
|
+
<p>Drawer content</p>
|
|
132
|
+
<div slot="footer">
|
|
133
|
+
<el-dm-button variant="ghost">Cancel</el-dm-button>
|
|
134
|
+
<el-dm-button variant="primary">Save</el-dm-button>
|
|
135
|
+
</div>
|
|
136
|
+
</el-dm-drawer>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Programmatic Control
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
const drawer = document.querySelector('el-dm-drawer');
|
|
143
|
+
|
|
144
|
+
// Open
|
|
145
|
+
drawer.open = true;
|
|
146
|
+
|
|
147
|
+
// Close
|
|
148
|
+
drawer.open = false;
|
|
149
|
+
|
|
150
|
+
// Listen for events
|
|
151
|
+
drawer.addEventListener('close', () => {
|
|
152
|
+
console.log('Drawer closed');
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
MIT
|
package/dist/cjs/index.js
CHANGED
|
@@ -35,8 +35,10 @@ __export(exports_src, {
|
|
|
35
35
|
module.exports = __toCommonJS(exports_src);
|
|
36
36
|
|
|
37
37
|
// src/el-dm-drawer.ts
|
|
38
|
-
var
|
|
39
|
-
var
|
|
38
|
+
var import_el_base = require("@duskmoon-dev/el-base");
|
|
39
|
+
var import_drawer = require("@duskmoon-dev/core/components/drawer");
|
|
40
|
+
var coreStyles = import_drawer.css.replace(/@layer\s+components\s*\{/, "").replace(/\}\s*$/, "");
|
|
41
|
+
var styles = import_el_base.css`
|
|
40
42
|
:host {
|
|
41
43
|
display: contents;
|
|
42
44
|
}
|
|
@@ -45,6 +47,10 @@ var styles = import_el_core.css`
|
|
|
45
47
|
display: none !important;
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
/* Import core drawer styles */
|
|
51
|
+
${coreStyles}
|
|
52
|
+
|
|
53
|
+
/* Web component specific: wrapper for positioning context */
|
|
48
54
|
.drawer-wrapper {
|
|
49
55
|
position: fixed;
|
|
50
56
|
inset: 0;
|
|
@@ -56,105 +62,14 @@ var styles = import_el_core.css`
|
|
|
56
62
|
pointer-events: auto;
|
|
57
63
|
}
|
|
58
64
|
|
|
59
|
-
|
|
60
|
-
position: absolute;
|
|
61
|
-
inset: 0;
|
|
62
|
-
background-color: rgba(0, 0, 0, 0.5);
|
|
63
|
-
opacity: 0;
|
|
64
|
-
visibility: hidden;
|
|
65
|
-
transition:
|
|
66
|
-
opacity 300ms ease,
|
|
67
|
-
visibility 300ms ease;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.drawer-wrapper.open .drawer-backdrop {
|
|
71
|
-
opacity: 1;
|
|
72
|
-
visibility: visible;
|
|
73
|
-
}
|
|
74
|
-
|
|
65
|
+
/* Override core's fixed positioning — our wrapper handles it */
|
|
75
66
|
.drawer {
|
|
76
67
|
position: absolute;
|
|
77
|
-
top: 0;
|
|
78
|
-
bottom: 0;
|
|
79
|
-
display: flex;
|
|
80
|
-
flex-direction: column;
|
|
81
68
|
width: var(--drawer-width, 280px);
|
|
82
|
-
max-width: 100vw;
|
|
83
|
-
background-color: var(--color-surface);
|
|
84
|
-
box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
|
85
|
-
transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
86
69
|
font-family: inherit;
|
|
87
70
|
pointer-events: auto;
|
|
88
71
|
}
|
|
89
72
|
|
|
90
|
-
.drawer-left {
|
|
91
|
-
left: 0;
|
|
92
|
-
border-right: 1px solid var(--color-outline);
|
|
93
|
-
transform: translateX(-100%);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
.drawer-right {
|
|
97
|
-
right: 0;
|
|
98
|
-
border-left: 1px solid var(--color-outline);
|
|
99
|
-
transform: translateX(100%);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.drawer-wrapper.open .drawer-left,
|
|
103
|
-
.drawer-wrapper.open .drawer-right {
|
|
104
|
-
transform: translateX(0);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.drawer-header {
|
|
108
|
-
display: flex;
|
|
109
|
-
align-items: center;
|
|
110
|
-
justify-content: space-between;
|
|
111
|
-
padding: 1rem 1.5rem;
|
|
112
|
-
border-bottom: 1px solid var(--color-outline);
|
|
113
|
-
flex-shrink: 0;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.drawer-body {
|
|
117
|
-
flex: 1;
|
|
118
|
-
padding: 1rem 1.5rem;
|
|
119
|
-
overflow-y: auto;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
.drawer-footer {
|
|
123
|
-
display: flex;
|
|
124
|
-
align-items: center;
|
|
125
|
-
gap: 0.5rem;
|
|
126
|
-
padding: 1rem 1.5rem;
|
|
127
|
-
border-top: 1px solid var(--color-outline);
|
|
128
|
-
flex-shrink: 0;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
.drawer-close {
|
|
132
|
-
display: flex;
|
|
133
|
-
align-items: center;
|
|
134
|
-
justify-content: center;
|
|
135
|
-
width: 2rem;
|
|
136
|
-
height: 2rem;
|
|
137
|
-
border: none;
|
|
138
|
-
background: transparent;
|
|
139
|
-
border-radius: 0.5rem;
|
|
140
|
-
cursor: pointer;
|
|
141
|
-
color: var(--color-on-surface);
|
|
142
|
-
opacity: 0.7;
|
|
143
|
-
transition:
|
|
144
|
-
opacity 150ms ease,
|
|
145
|
-
background-color 150ms ease;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
.drawer-close:hover {
|
|
149
|
-
opacity: 1;
|
|
150
|
-
background-color: var(--color-surface-variant);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
.drawer-close:focus {
|
|
154
|
-
outline: 2px solid var(--color-primary);
|
|
155
|
-
outline-offset: 2px;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
73
|
/* Non-modal drawer positioning */
|
|
159
74
|
:host(:not([modal])) .drawer-wrapper {
|
|
160
75
|
pointer-events: none;
|
|
@@ -165,7 +80,7 @@ var styles = import_el_core.css`
|
|
|
165
80
|
}
|
|
166
81
|
`;
|
|
167
82
|
|
|
168
|
-
class ElDmDrawer extends
|
|
83
|
+
class ElDmDrawer extends import_el_base.BaseElement {
|
|
169
84
|
static properties = {
|
|
170
85
|
open: { type: Boolean, reflect: true },
|
|
171
86
|
position: { type: String, reflect: true, default: "left" },
|
|
@@ -176,7 +91,7 @@ class ElDmDrawer extends import_el_core.BaseElement {
|
|
|
176
91
|
_previouslyFocused = null;
|
|
177
92
|
constructor() {
|
|
178
93
|
super();
|
|
179
|
-
this.attachStyles(styles);
|
|
94
|
+
this.attachStyles([styles, import_el_base.animationStyles]);
|
|
180
95
|
}
|
|
181
96
|
_handleBackdropClick(event) {
|
|
182
97
|
if (this.modal && event.target === event.currentTarget) {
|
|
@@ -288,12 +203,13 @@ class ElDmDrawer extends import_el_core.BaseElement {
|
|
|
288
203
|
}
|
|
289
204
|
render() {
|
|
290
205
|
const positionClass = this.position === "right" ? "drawer-right" : "drawer-left";
|
|
206
|
+
const openClass = this.open ? "drawer-open" : "";
|
|
291
207
|
const widthStyle = this.width ? `--drawer-width: ${this.width}` : "";
|
|
292
208
|
return `
|
|
293
209
|
<div class="drawer-wrapper ${this.open ? "open" : ""}" part="wrapper">
|
|
294
|
-
${this.modal ?
|
|
210
|
+
${this.modal ? `<div class="drawer-backdrop ${this.open ? "drawer-backdrop-show" : ""}" part="backdrop"></div>` : ""}
|
|
295
211
|
<div
|
|
296
|
-
class="drawer ${positionClass}"
|
|
212
|
+
class="drawer ${positionClass} ${openClass}"
|
|
297
213
|
role="dialog"
|
|
298
214
|
aria-modal="${this.modal ? "true" : "false"}"
|
|
299
215
|
style="${widthStyle}"
|
|
@@ -335,5 +251,5 @@ function register() {
|
|
|
335
251
|
}
|
|
336
252
|
}
|
|
337
253
|
|
|
338
|
-
//# debugId=
|
|
254
|
+
//# debugId=89D85777152BF73364756E2164756E21
|
|
339
255
|
//# sourceMappingURL=index.js.map
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/el-dm-drawer.ts", "../../src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * DuskMoon Drawer Element\n *\n * A side navigation drawer/sidebar component for displaying navigation or content panels.\n * Supports left/right positioning, modal mode with backdrop, and smooth slide animations.\n *\n * @element el-dm-drawer\n *\n * @attr {boolean} open - Whether the drawer is open\n * @attr {string} position - Drawer position: 'left' or 'right'\n * @attr {boolean} modal - Whether drawer shows backdrop and traps focus\n * @attr {string} width - Custom width for the drawer (CSS value)\n *\n * @slot - Default slot for drawer content\n * @slot header - Drawer header section\n * @slot footer - Drawer footer section\n *\n * @csspart drawer - The drawer container\n * @csspart backdrop - The backdrop overlay (modal mode)\n * @csspart content - The content wrapper\n * @csspart header - The header section\n * @csspart body - The body section\n * @csspart footer - The footer section\n *\n * @fires open - Fired when drawer opens\n * @fires close - Fired when drawer closes\n */\n\nimport { BaseElement, css } from '@duskmoon-dev/el-core';\n\nexport type DrawerPosition = 'left' | 'right';\n\nconst styles = css`\n :host {\n display: contents;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n
|
|
5
|
+
"/**\n * DuskMoon Drawer Element\n *\n * A side navigation drawer/sidebar component for displaying navigation or content panels.\n * Supports left/right positioning, modal mode with backdrop, and smooth slide animations.\n * Uses styles from @duskmoon-dev/core for consistent theming.\n *\n * @element el-dm-drawer\n *\n * @attr {boolean} open - Whether the drawer is open\n * @attr {string} position - Drawer position: 'left' or 'right'\n * @attr {boolean} modal - Whether drawer shows backdrop and traps focus\n * @attr {string} width - Custom width for the drawer (CSS value)\n *\n * @slot - Default slot for drawer content\n * @slot header - Drawer header section\n * @slot footer - Drawer footer section\n *\n * @csspart drawer - The drawer container\n * @csspart backdrop - The backdrop overlay (modal mode)\n * @csspart content - The content wrapper\n * @csspart header - The header section\n * @csspart body - The body section\n * @csspart footer - The footer section\n *\n * @fires open - Fired when drawer opens\n * @fires close - Fired when drawer closes\n */\n\nimport { BaseElement, css, animationStyles } from '@duskmoon-dev/el-base';\nimport { css as drawerCSS } from '@duskmoon-dev/core/components/drawer';\n\nexport type DrawerPosition = 'left' | 'right';\n\n// Strip @layer wrapper for Shadow DOM compatibility\nconst coreStyles = drawerCSS.replace(/@layer\\s+components\\s*\\{/, '').replace(/\\}\\s*$/, '');\n\nconst styles = css`\n :host {\n display: contents;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n /* Import core drawer styles */\n ${coreStyles}\n\n /* Web component specific: wrapper for positioning context */\n .drawer-wrapper {\n position: fixed;\n inset: 0;\n z-index: 1000;\n pointer-events: none;\n }\n\n .drawer-wrapper.open {\n pointer-events: auto;\n }\n\n /* Override core's fixed positioning — our wrapper handles it */\n .drawer {\n position: absolute;\n width: var(--drawer-width, 280px);\n font-family: inherit;\n pointer-events: auto;\n }\n\n /* Non-modal drawer positioning */\n :host(:not([modal])) .drawer-wrapper {\n pointer-events: none;\n }\n\n :host(:not([modal])) .drawer {\n pointer-events: auto;\n }\n`;\n\nexport class ElDmDrawer extends BaseElement {\n static properties = {\n open: { type: Boolean, reflect: true },\n position: { type: String, reflect: true, default: 'left' },\n modal: { type: Boolean, reflect: true },\n width: { type: String, reflect: true },\n };\n\n declare open: boolean;\n declare position: DrawerPosition;\n declare modal: boolean;\n declare width: string;\n\n private _focusableElements: HTMLElement[] = [];\n private _previouslyFocused: HTMLElement | null = null;\n\n constructor() {\n super();\n this.attachStyles([styles, animationStyles]);\n }\n\n private _handleBackdropClick(event: Event): void {\n if (this.modal && event.target === event.currentTarget) {\n this.hide();\n }\n }\n\n private _handleKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape' && this.modal) {\n this.hide();\n return;\n }\n\n // Focus trap for modal mode\n if (event.key === 'Tab' && this.modal && this.open) {\n this._handleTabKey(event);\n }\n };\n\n private _handleTabKey(event: KeyboardEvent): void {\n const focusable = this._getFocusableElements();\n if (focusable.length === 0) return;\n\n const firstFocusable = focusable[0];\n const lastFocusable = focusable[focusable.length - 1];\n\n if (event.shiftKey) {\n if (document.activeElement === firstFocusable) {\n event.preventDefault();\n lastFocusable.focus();\n }\n } else {\n if (document.activeElement === lastFocusable) {\n event.preventDefault();\n firstFocusable.focus();\n }\n }\n }\n\n private _getFocusableElements(): HTMLElement[] {\n const drawer = this.shadowRoot?.querySelector('.drawer');\n if (!drawer) return [];\n\n const focusableSelectors = [\n 'button:not([disabled])',\n 'a[href]',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n ].join(', ');\n\n // Get focusable elements from shadow DOM\n const shadowFocusable = Array.from(\n drawer.querySelectorAll(focusableSelectors),\n ) as HTMLElement[];\n\n // Get focusable elements from slotted content\n const slots = drawer.querySelectorAll('slot');\n const slottedFocusable: HTMLElement[] = [];\n\n slots.forEach((slot) => {\n const assignedElements = slot.assignedElements({ flatten: true });\n assignedElements.forEach((el) => {\n if (el instanceof HTMLElement) {\n if (el.matches(focusableSelectors)) {\n slottedFocusable.push(el);\n }\n slottedFocusable.push(\n ...(Array.from(el.querySelectorAll(focusableSelectors)) as HTMLElement[]),\n );\n }\n });\n });\n\n return [...shadowFocusable, ...slottedFocusable];\n }\n\n private _trapFocus(): void {\n this._previouslyFocused = document.activeElement as HTMLElement;\n this._focusableElements = this._getFocusableElements();\n\n // Focus first focusable element or the drawer itself\n requestAnimationFrame(() => {\n if (this._focusableElements.length > 0) {\n this._focusableElements[0].focus();\n } else {\n const drawer = this.shadowRoot?.querySelector('.drawer') as HTMLElement;\n drawer?.focus();\n }\n });\n }\n\n private _releaseFocus(): void {\n if (this._previouslyFocused && this._previouslyFocused.focus) {\n this._previouslyFocused.focus();\n }\n this._previouslyFocused = null;\n }\n\n show(): void {\n this.open = true;\n document.addEventListener('keydown', this._handleKeyDown);\n\n if (this.modal) {\n document.body.style.overflow = 'hidden';\n this._trapFocus();\n }\n\n this.emit('open');\n }\n\n hide(): void {\n this.open = false;\n document.removeEventListener('keydown', this._handleKeyDown);\n\n if (this.modal) {\n document.body.style.overflow = '';\n this._releaseFocus();\n }\n\n this.emit('close');\n }\n\n toggle(): void {\n if (this.open) {\n this.hide();\n } else {\n this.show();\n }\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback?.();\n document.removeEventListener('keydown', this._handleKeyDown);\n document.body.style.overflow = '';\n }\n\n render(): string {\n const positionClass = this.position === 'right' ? 'drawer-right' : 'drawer-left';\n const openClass = this.open ? 'drawer-open' : '';\n const widthStyle = this.width ? `--drawer-width: ${this.width}` : '';\n\n return `\n <div class=\"drawer-wrapper ${this.open ? 'open' : ''}\" part=\"wrapper\">\n ${this.modal ? `<div class=\"drawer-backdrop ${this.open ? 'drawer-backdrop-show' : ''}\" part=\"backdrop\"></div>` : ''}\n <div\n class=\"drawer ${positionClass} ${openClass}\"\n role=\"dialog\"\n aria-modal=\"${this.modal ? 'true' : 'false'}\"\n style=\"${widthStyle}\"\n tabindex=\"-1\"\n part=\"drawer\"\n >\n <div class=\"drawer-header\" part=\"header\">\n <slot name=\"header\"></slot>\n <button class=\"drawer-close\" part=\"close\" aria-label=\"Close drawer\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </div>\n <div class=\"drawer-body\" part=\"body\">\n <slot></slot>\n </div>\n <div class=\"drawer-footer\" part=\"footer\">\n <slot name=\"footer\"></slot>\n </div>\n </div>\n </div>\n `;\n }\n\n update(): void {\n super.update();\n\n const backdrop = this.shadowRoot?.querySelector('.drawer-backdrop');\n backdrop?.addEventListener('click', this._handleBackdropClick.bind(this));\n\n const closeBtn = this.shadowRoot?.querySelector('.drawer-close');\n closeBtn?.addEventListener('click', () => this.hide());\n }\n}\n",
|
|
6
6
|
"import { ElDmDrawer } from './el-dm-drawer.js';\n\nexport { ElDmDrawer };\nexport type { DrawerPosition } from './el-dm-drawer.js';\n\nexport function register(): void {\n if (!customElements.get('el-dm-drawer')) {\n customElements.define('el-dm-drawer', ElDmDrawer);\n }\n}\n"
|
|
7
7
|
],
|
|
8
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
9
|
-
"debugId": "
|
|
8
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BkD,IAAlD;AACiC,IAAjC;AAKA,IAAM,aAAa,kBAAU,QAAQ,4BAA4B,EAAE,EAAE,QAAQ,UAAU,EAAE;AAEzF,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAUX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCG,MAAM,mBAAmB,2BAAY;AAAA,SACnC,aAAa;AAAA,IAClB,MAAM,EAAE,MAAM,SAAS,SAAS,KAAK;AAAA,IACrC,UAAU,EAAE,MAAM,QAAQ,SAAS,MAAM,SAAS,OAAO;AAAA,IACzD,OAAO,EAAE,MAAM,SAAS,SAAS,KAAK;AAAA,IACtC,OAAO,EAAE,MAAM,QAAQ,SAAS,KAAK;AAAA,EACvC;AAAA,EAOQ,qBAAoC,CAAC;AAAA,EACrC,qBAAyC;AAAA,EAEjD,WAAW,GAAG;AAAA,IACZ,MAAM;AAAA,IACN,KAAK,aAAa,CAAC,QAAQ,8BAAe,CAAC;AAAA;AAAA,EAGrC,oBAAoB,CAAC,OAAoB;AAAA,IAC/C,IAAI,KAAK,SAAS,MAAM,WAAW,MAAM,eAAe;AAAA,MACtD,KAAK,KAAK;AAAA,IACZ;AAAA;AAAA,EAGM,iBAAiB,CAAC,UAA+B;AAAA,IACvD,IAAI,MAAM,QAAQ,YAAY,KAAK,OAAO;AAAA,MACxC,KAAK,KAAK;AAAA,MACV;AAAA,IACF;AAAA,IAGA,IAAI,MAAM,QAAQ,SAAS,KAAK,SAAS,KAAK,MAAM;AAAA,MAClD,KAAK,cAAc,KAAK;AAAA,IAC1B;AAAA;AAAA,EAGM,aAAa,CAAC,OAA4B;AAAA,IAChD,MAAM,YAAY,KAAK,sBAAsB;AAAA,IAC7C,IAAI,UAAU,WAAW;AAAA,MAAG;AAAA,IAE5B,MAAM,iBAAiB,UAAU;AAAA,IACjC,MAAM,gBAAgB,UAAU,UAAU,SAAS;AAAA,IAEnD,IAAI,MAAM,UAAU;AAAA,MAClB,IAAI,SAAS,kBAAkB,gBAAgB;AAAA,QAC7C,MAAM,eAAe;AAAA,QACrB,cAAc,MAAM;AAAA,MACtB;AAAA,IACF,EAAO;AAAA,MACL,IAAI,SAAS,kBAAkB,eAAe;AAAA,QAC5C,MAAM,eAAe;AAAA,QACrB,eAAe,MAAM;AAAA,MACvB;AAAA;AAAA;AAAA,EAII,qBAAqB,GAAkB;AAAA,IAC7C,MAAM,SAAS,KAAK,YAAY,cAAc,SAAS;AAAA,IACvD,IAAI,CAAC;AAAA,MAAQ,OAAO,CAAC;AAAA,IAErB,MAAM,qBAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,IAGX,MAAM,kBAAkB,MAAM,KAC5B,OAAO,iBAAiB,kBAAkB,CAC5C;AAAA,IAGA,MAAM,QAAQ,OAAO,iBAAiB,MAAM;AAAA,IAC5C,MAAM,mBAAkC,CAAC;AAAA,IAEzC,MAAM,QAAQ,CAAC,SAAS;AAAA,MACtB,MAAM,mBAAmB,KAAK,iBAAiB,EAAE,SAAS,KAAK,CAAC;AAAA,MAChE,iBAAiB,QAAQ,CAAC,OAAO;AAAA,QAC/B,IAAI,cAAc,aAAa;AAAA,UAC7B,IAAI,GAAG,QAAQ,kBAAkB,GAAG;AAAA,YAClC,iBAAiB,KAAK,EAAE;AAAA,UAC1B;AAAA,UACA,iBAAiB,KACf,GAAI,MAAM,KAAK,GAAG,iBAAiB,kBAAkB,CAAC,CACxD;AAAA,QACF;AAAA,OACD;AAAA,KACF;AAAA,IAED,OAAO,CAAC,GAAG,iBAAiB,GAAG,gBAAgB;AAAA;AAAA,EAGzC,UAAU,GAAS;AAAA,IACzB,KAAK,qBAAqB,SAAS;AAAA,IACnC,KAAK,qBAAqB,KAAK,sBAAsB;AAAA,IAGrD,sBAAsB,MAAM;AAAA,MAC1B,IAAI,KAAK,mBAAmB,SAAS,GAAG;AAAA,QACtC,KAAK,mBAAmB,GAAG,MAAM;AAAA,MACnC,EAAO;AAAA,QACL,MAAM,SAAS,KAAK,YAAY,cAAc,SAAS;AAAA,QACvD,QAAQ,MAAM;AAAA;AAAA,KAEjB;AAAA;AAAA,EAGK,aAAa,GAAS;AAAA,IAC5B,IAAI,KAAK,sBAAsB,KAAK,mBAAmB,OAAO;AAAA,MAC5D,KAAK,mBAAmB,MAAM;AAAA,IAChC;AAAA,IACA,KAAK,qBAAqB;AAAA;AAAA,EAG5B,IAAI,GAAS;AAAA,IACX,KAAK,OAAO;AAAA,IACZ,SAAS,iBAAiB,WAAW,KAAK,cAAc;AAAA,IAExD,IAAI,KAAK,OAAO;AAAA,MACd,SAAS,KAAK,MAAM,WAAW;AAAA,MAC/B,KAAK,WAAW;AAAA,IAClB;AAAA,IAEA,KAAK,KAAK,MAAM;AAAA;AAAA,EAGlB,IAAI,GAAS;AAAA,IACX,KAAK,OAAO;AAAA,IACZ,SAAS,oBAAoB,WAAW,KAAK,cAAc;AAAA,IAE3D,IAAI,KAAK,OAAO;AAAA,MACd,SAAS,KAAK,MAAM,WAAW;AAAA,MAC/B,KAAK,cAAc;AAAA,IACrB;AAAA,IAEA,KAAK,KAAK,OAAO;AAAA;AAAA,EAGnB,MAAM,GAAS;AAAA,IACb,IAAI,KAAK,MAAM;AAAA,MACb,KAAK,KAAK;AAAA,IACZ,EAAO;AAAA,MACL,KAAK,KAAK;AAAA;AAAA;AAAA,EAId,oBAAoB,GAAS;AAAA,IAC3B,MAAM,uBAAuB;AAAA,IAC7B,SAAS,oBAAoB,WAAW,KAAK,cAAc;AAAA,IAC3D,SAAS,KAAK,MAAM,WAAW;AAAA;AAAA,EAGjC,MAAM,GAAW;AAAA,IACf,MAAM,gBAAgB,KAAK,aAAa,UAAU,iBAAiB;AAAA,IACnE,MAAM,YAAY,KAAK,OAAO,gBAAgB;AAAA,IAC9C,MAAM,aAAa,KAAK,QAAQ,mBAAmB,KAAK,UAAU;AAAA,IAElE,OAAO;AAAA,mCACwB,KAAK,OAAO,SAAS;AAAA,UAC9C,KAAK,QAAQ,+BAA+B,KAAK,OAAO,yBAAyB,+BAA+B;AAAA;AAAA,0BAEhG,iBAAiB;AAAA;AAAA,wBAEnB,KAAK,QAAQ,SAAS;AAAA,mBAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBjB,MAAM,GAAS;AAAA,IACb,MAAM,OAAO;AAAA,IAEb,MAAM,WAAW,KAAK,YAAY,cAAc,kBAAkB;AAAA,IAClE,UAAU,iBAAiB,SAAS,KAAK,qBAAqB,KAAK,IAAI,CAAC;AAAA,IAExE,MAAM,WAAW,KAAK,YAAY,cAAc,eAAe;AAAA,IAC/D,UAAU,iBAAiB,SAAS,MAAM,KAAK,KAAK,CAAC;AAAA;AAEzD;;;ACrRO,SAAS,QAAQ,GAAS;AAAA,EAC/B,IAAI,CAAC,eAAe,IAAI,cAAc,GAAG;AAAA,IACvC,eAAe,OAAO,gBAAgB,UAAU;AAAA,EAClD;AAAA;",
|
|
9
|
+
"debugId": "89D85777152BF73364756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
package/dist/cjs/register.js
CHANGED
|
@@ -35,8 +35,10 @@ __export(exports_src, {
|
|
|
35
35
|
module.exports = __toCommonJS(exports_src);
|
|
36
36
|
|
|
37
37
|
// src/el-dm-drawer.ts
|
|
38
|
-
var
|
|
39
|
-
var
|
|
38
|
+
var import_el_base = require("@duskmoon-dev/el-base");
|
|
39
|
+
var import_drawer = require("@duskmoon-dev/core/components/drawer");
|
|
40
|
+
var coreStyles = import_drawer.css.replace(/@layer\s+components\s*\{/, "").replace(/\}\s*$/, "");
|
|
41
|
+
var styles = import_el_base.css`
|
|
40
42
|
:host {
|
|
41
43
|
display: contents;
|
|
42
44
|
}
|
|
@@ -45,6 +47,10 @@ var styles = import_el_core.css`
|
|
|
45
47
|
display: none !important;
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
/* Import core drawer styles */
|
|
51
|
+
${coreStyles}
|
|
52
|
+
|
|
53
|
+
/* Web component specific: wrapper for positioning context */
|
|
48
54
|
.drawer-wrapper {
|
|
49
55
|
position: fixed;
|
|
50
56
|
inset: 0;
|
|
@@ -56,105 +62,14 @@ var styles = import_el_core.css`
|
|
|
56
62
|
pointer-events: auto;
|
|
57
63
|
}
|
|
58
64
|
|
|
59
|
-
|
|
60
|
-
position: absolute;
|
|
61
|
-
inset: 0;
|
|
62
|
-
background-color: rgba(0, 0, 0, 0.5);
|
|
63
|
-
opacity: 0;
|
|
64
|
-
visibility: hidden;
|
|
65
|
-
transition:
|
|
66
|
-
opacity 300ms ease,
|
|
67
|
-
visibility 300ms ease;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.drawer-wrapper.open .drawer-backdrop {
|
|
71
|
-
opacity: 1;
|
|
72
|
-
visibility: visible;
|
|
73
|
-
}
|
|
74
|
-
|
|
65
|
+
/* Override core's fixed positioning — our wrapper handles it */
|
|
75
66
|
.drawer {
|
|
76
67
|
position: absolute;
|
|
77
|
-
top: 0;
|
|
78
|
-
bottom: 0;
|
|
79
|
-
display: flex;
|
|
80
|
-
flex-direction: column;
|
|
81
68
|
width: var(--drawer-width, 280px);
|
|
82
|
-
max-width: 100vw;
|
|
83
|
-
background-color: var(--color-surface);
|
|
84
|
-
box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
|
85
|
-
transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
86
69
|
font-family: inherit;
|
|
87
70
|
pointer-events: auto;
|
|
88
71
|
}
|
|
89
72
|
|
|
90
|
-
.drawer-left {
|
|
91
|
-
left: 0;
|
|
92
|
-
border-right: 1px solid var(--color-outline);
|
|
93
|
-
transform: translateX(-100%);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
.drawer-right {
|
|
97
|
-
right: 0;
|
|
98
|
-
border-left: 1px solid var(--color-outline);
|
|
99
|
-
transform: translateX(100%);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.drawer-wrapper.open .drawer-left,
|
|
103
|
-
.drawer-wrapper.open .drawer-right {
|
|
104
|
-
transform: translateX(0);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.drawer-header {
|
|
108
|
-
display: flex;
|
|
109
|
-
align-items: center;
|
|
110
|
-
justify-content: space-between;
|
|
111
|
-
padding: 1rem 1.5rem;
|
|
112
|
-
border-bottom: 1px solid var(--color-outline);
|
|
113
|
-
flex-shrink: 0;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.drawer-body {
|
|
117
|
-
flex: 1;
|
|
118
|
-
padding: 1rem 1.5rem;
|
|
119
|
-
overflow-y: auto;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
.drawer-footer {
|
|
123
|
-
display: flex;
|
|
124
|
-
align-items: center;
|
|
125
|
-
gap: 0.5rem;
|
|
126
|
-
padding: 1rem 1.5rem;
|
|
127
|
-
border-top: 1px solid var(--color-outline);
|
|
128
|
-
flex-shrink: 0;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
.drawer-close {
|
|
132
|
-
display: flex;
|
|
133
|
-
align-items: center;
|
|
134
|
-
justify-content: center;
|
|
135
|
-
width: 2rem;
|
|
136
|
-
height: 2rem;
|
|
137
|
-
border: none;
|
|
138
|
-
background: transparent;
|
|
139
|
-
border-radius: 0.5rem;
|
|
140
|
-
cursor: pointer;
|
|
141
|
-
color: var(--color-on-surface);
|
|
142
|
-
opacity: 0.7;
|
|
143
|
-
transition:
|
|
144
|
-
opacity 150ms ease,
|
|
145
|
-
background-color 150ms ease;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
.drawer-close:hover {
|
|
149
|
-
opacity: 1;
|
|
150
|
-
background-color: var(--color-surface-variant);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
.drawer-close:focus {
|
|
154
|
-
outline: 2px solid var(--color-primary);
|
|
155
|
-
outline-offset: 2px;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
73
|
/* Non-modal drawer positioning */
|
|
159
74
|
:host(:not([modal])) .drawer-wrapper {
|
|
160
75
|
pointer-events: none;
|
|
@@ -165,7 +80,7 @@ var styles = import_el_core.css`
|
|
|
165
80
|
}
|
|
166
81
|
`;
|
|
167
82
|
|
|
168
|
-
class ElDmDrawer extends
|
|
83
|
+
class ElDmDrawer extends import_el_base.BaseElement {
|
|
169
84
|
static properties = {
|
|
170
85
|
open: { type: Boolean, reflect: true },
|
|
171
86
|
position: { type: String, reflect: true, default: "left" },
|
|
@@ -176,7 +91,7 @@ class ElDmDrawer extends import_el_core.BaseElement {
|
|
|
176
91
|
_previouslyFocused = null;
|
|
177
92
|
constructor() {
|
|
178
93
|
super();
|
|
179
|
-
this.attachStyles(styles);
|
|
94
|
+
this.attachStyles([styles, import_el_base.animationStyles]);
|
|
180
95
|
}
|
|
181
96
|
_handleBackdropClick(event) {
|
|
182
97
|
if (this.modal && event.target === event.currentTarget) {
|
|
@@ -288,12 +203,13 @@ class ElDmDrawer extends import_el_core.BaseElement {
|
|
|
288
203
|
}
|
|
289
204
|
render() {
|
|
290
205
|
const positionClass = this.position === "right" ? "drawer-right" : "drawer-left";
|
|
206
|
+
const openClass = this.open ? "drawer-open" : "";
|
|
291
207
|
const widthStyle = this.width ? `--drawer-width: ${this.width}` : "";
|
|
292
208
|
return `
|
|
293
209
|
<div class="drawer-wrapper ${this.open ? "open" : ""}" part="wrapper">
|
|
294
|
-
${this.modal ?
|
|
210
|
+
${this.modal ? `<div class="drawer-backdrop ${this.open ? "drawer-backdrop-show" : ""}" part="backdrop"></div>` : ""}
|
|
295
211
|
<div
|
|
296
|
-
class="drawer ${positionClass}"
|
|
212
|
+
class="drawer ${positionClass} ${openClass}"
|
|
297
213
|
role="dialog"
|
|
298
214
|
aria-modal="${this.modal ? "true" : "false"}"
|
|
299
215
|
style="${widthStyle}"
|
|
@@ -338,5 +254,5 @@ function register() {
|
|
|
338
254
|
// src/register.ts
|
|
339
255
|
register();
|
|
340
256
|
|
|
341
|
-
//# debugId=
|
|
257
|
+
//# debugId=6774C31116ACBA6164756E2164756E21
|
|
342
258
|
//# sourceMappingURL=register.js.map
|
package/dist/cjs/register.js.map
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/el-dm-drawer.ts", "../../src/index.ts", "../../src/register.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * DuskMoon Drawer Element\n *\n * A side navigation drawer/sidebar component for displaying navigation or content panels.\n * Supports left/right positioning, modal mode with backdrop, and smooth slide animations.\n *\n * @element el-dm-drawer\n *\n * @attr {boolean} open - Whether the drawer is open\n * @attr {string} position - Drawer position: 'left' or 'right'\n * @attr {boolean} modal - Whether drawer shows backdrop and traps focus\n * @attr {string} width - Custom width for the drawer (CSS value)\n *\n * @slot - Default slot for drawer content\n * @slot header - Drawer header section\n * @slot footer - Drawer footer section\n *\n * @csspart drawer - The drawer container\n * @csspart backdrop - The backdrop overlay (modal mode)\n * @csspart content - The content wrapper\n * @csspart header - The header section\n * @csspart body - The body section\n * @csspart footer - The footer section\n *\n * @fires open - Fired when drawer opens\n * @fires close - Fired when drawer closes\n */\n\nimport { BaseElement, css } from '@duskmoon-dev/el-core';\n\nexport type DrawerPosition = 'left' | 'right';\n\nconst styles = css`\n :host {\n display: contents;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n
|
|
5
|
+
"/**\n * DuskMoon Drawer Element\n *\n * A side navigation drawer/sidebar component for displaying navigation or content panels.\n * Supports left/right positioning, modal mode with backdrop, and smooth slide animations.\n * Uses styles from @duskmoon-dev/core for consistent theming.\n *\n * @element el-dm-drawer\n *\n * @attr {boolean} open - Whether the drawer is open\n * @attr {string} position - Drawer position: 'left' or 'right'\n * @attr {boolean} modal - Whether drawer shows backdrop and traps focus\n * @attr {string} width - Custom width for the drawer (CSS value)\n *\n * @slot - Default slot for drawer content\n * @slot header - Drawer header section\n * @slot footer - Drawer footer section\n *\n * @csspart drawer - The drawer container\n * @csspart backdrop - The backdrop overlay (modal mode)\n * @csspart content - The content wrapper\n * @csspart header - The header section\n * @csspart body - The body section\n * @csspart footer - The footer section\n *\n * @fires open - Fired when drawer opens\n * @fires close - Fired when drawer closes\n */\n\nimport { BaseElement, css, animationStyles } from '@duskmoon-dev/el-base';\nimport { css as drawerCSS } from '@duskmoon-dev/core/components/drawer';\n\nexport type DrawerPosition = 'left' | 'right';\n\n// Strip @layer wrapper for Shadow DOM compatibility\nconst coreStyles = drawerCSS.replace(/@layer\\s+components\\s*\\{/, '').replace(/\\}\\s*$/, '');\n\nconst styles = css`\n :host {\n display: contents;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n /* Import core drawer styles */\n ${coreStyles}\n\n /* Web component specific: wrapper for positioning context */\n .drawer-wrapper {\n position: fixed;\n inset: 0;\n z-index: 1000;\n pointer-events: none;\n }\n\n .drawer-wrapper.open {\n pointer-events: auto;\n }\n\n /* Override core's fixed positioning — our wrapper handles it */\n .drawer {\n position: absolute;\n width: var(--drawer-width, 280px);\n font-family: inherit;\n pointer-events: auto;\n }\n\n /* Non-modal drawer positioning */\n :host(:not([modal])) .drawer-wrapper {\n pointer-events: none;\n }\n\n :host(:not([modal])) .drawer {\n pointer-events: auto;\n }\n`;\n\nexport class ElDmDrawer extends BaseElement {\n static properties = {\n open: { type: Boolean, reflect: true },\n position: { type: String, reflect: true, default: 'left' },\n modal: { type: Boolean, reflect: true },\n width: { type: String, reflect: true },\n };\n\n declare open: boolean;\n declare position: DrawerPosition;\n declare modal: boolean;\n declare width: string;\n\n private _focusableElements: HTMLElement[] = [];\n private _previouslyFocused: HTMLElement | null = null;\n\n constructor() {\n super();\n this.attachStyles([styles, animationStyles]);\n }\n\n private _handleBackdropClick(event: Event): void {\n if (this.modal && event.target === event.currentTarget) {\n this.hide();\n }\n }\n\n private _handleKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape' && this.modal) {\n this.hide();\n return;\n }\n\n // Focus trap for modal mode\n if (event.key === 'Tab' && this.modal && this.open) {\n this._handleTabKey(event);\n }\n };\n\n private _handleTabKey(event: KeyboardEvent): void {\n const focusable = this._getFocusableElements();\n if (focusable.length === 0) return;\n\n const firstFocusable = focusable[0];\n const lastFocusable = focusable[focusable.length - 1];\n\n if (event.shiftKey) {\n if (document.activeElement === firstFocusable) {\n event.preventDefault();\n lastFocusable.focus();\n }\n } else {\n if (document.activeElement === lastFocusable) {\n event.preventDefault();\n firstFocusable.focus();\n }\n }\n }\n\n private _getFocusableElements(): HTMLElement[] {\n const drawer = this.shadowRoot?.querySelector('.drawer');\n if (!drawer) return [];\n\n const focusableSelectors = [\n 'button:not([disabled])',\n 'a[href]',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n ].join(', ');\n\n // Get focusable elements from shadow DOM\n const shadowFocusable = Array.from(\n drawer.querySelectorAll(focusableSelectors),\n ) as HTMLElement[];\n\n // Get focusable elements from slotted content\n const slots = drawer.querySelectorAll('slot');\n const slottedFocusable: HTMLElement[] = [];\n\n slots.forEach((slot) => {\n const assignedElements = slot.assignedElements({ flatten: true });\n assignedElements.forEach((el) => {\n if (el instanceof HTMLElement) {\n if (el.matches(focusableSelectors)) {\n slottedFocusable.push(el);\n }\n slottedFocusable.push(\n ...(Array.from(el.querySelectorAll(focusableSelectors)) as HTMLElement[]),\n );\n }\n });\n });\n\n return [...shadowFocusable, ...slottedFocusable];\n }\n\n private _trapFocus(): void {\n this._previouslyFocused = document.activeElement as HTMLElement;\n this._focusableElements = this._getFocusableElements();\n\n // Focus first focusable element or the drawer itself\n requestAnimationFrame(() => {\n if (this._focusableElements.length > 0) {\n this._focusableElements[0].focus();\n } else {\n const drawer = this.shadowRoot?.querySelector('.drawer') as HTMLElement;\n drawer?.focus();\n }\n });\n }\n\n private _releaseFocus(): void {\n if (this._previouslyFocused && this._previouslyFocused.focus) {\n this._previouslyFocused.focus();\n }\n this._previouslyFocused = null;\n }\n\n show(): void {\n this.open = true;\n document.addEventListener('keydown', this._handleKeyDown);\n\n if (this.modal) {\n document.body.style.overflow = 'hidden';\n this._trapFocus();\n }\n\n this.emit('open');\n }\n\n hide(): void {\n this.open = false;\n document.removeEventListener('keydown', this._handleKeyDown);\n\n if (this.modal) {\n document.body.style.overflow = '';\n this._releaseFocus();\n }\n\n this.emit('close');\n }\n\n toggle(): void {\n if (this.open) {\n this.hide();\n } else {\n this.show();\n }\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback?.();\n document.removeEventListener('keydown', this._handleKeyDown);\n document.body.style.overflow = '';\n }\n\n render(): string {\n const positionClass = this.position === 'right' ? 'drawer-right' : 'drawer-left';\n const openClass = this.open ? 'drawer-open' : '';\n const widthStyle = this.width ? `--drawer-width: ${this.width}` : '';\n\n return `\n <div class=\"drawer-wrapper ${this.open ? 'open' : ''}\" part=\"wrapper\">\n ${this.modal ? `<div class=\"drawer-backdrop ${this.open ? 'drawer-backdrop-show' : ''}\" part=\"backdrop\"></div>` : ''}\n <div\n class=\"drawer ${positionClass} ${openClass}\"\n role=\"dialog\"\n aria-modal=\"${this.modal ? 'true' : 'false'}\"\n style=\"${widthStyle}\"\n tabindex=\"-1\"\n part=\"drawer\"\n >\n <div class=\"drawer-header\" part=\"header\">\n <slot name=\"header\"></slot>\n <button class=\"drawer-close\" part=\"close\" aria-label=\"Close drawer\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </div>\n <div class=\"drawer-body\" part=\"body\">\n <slot></slot>\n </div>\n <div class=\"drawer-footer\" part=\"footer\">\n <slot name=\"footer\"></slot>\n </div>\n </div>\n </div>\n `;\n }\n\n update(): void {\n super.update();\n\n const backdrop = this.shadowRoot?.querySelector('.drawer-backdrop');\n backdrop?.addEventListener('click', this._handleBackdropClick.bind(this));\n\n const closeBtn = this.shadowRoot?.querySelector('.drawer-close');\n closeBtn?.addEventListener('click', () => this.hide());\n }\n}\n",
|
|
6
6
|
"import { ElDmDrawer } from './el-dm-drawer.js';\n\nexport { ElDmDrawer };\nexport type { DrawerPosition } from './el-dm-drawer.js';\n\nexport function register(): void {\n if (!customElements.get('el-dm-drawer')) {\n customElements.define('el-dm-drawer', ElDmDrawer);\n }\n}\n",
|
|
7
7
|
"import { register } from './index.js';\nregister();\n"
|
|
8
8
|
],
|
|
9
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
10
|
-
"debugId": "
|
|
9
|
+
"mappings": "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",
|
|
10
|
+
"debugId": "6774C31116ACBA6164756E2164756E21",
|
|
11
11
|
"names": []
|
|
12
12
|
}
|