@duskmoon-dev/el-menu 0.4.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.
@@ -0,0 +1,510 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
6
+ var __toCommonJS = (from) => {
7
+ var entry = __moduleCache.get(from), desc;
8
+ if (entry)
9
+ return entry;
10
+ entry = __defProp({}, "__esModule", { value: true });
11
+ if (from && typeof from === "object" || typeof from === "function")
12
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
13
+ get: () => from[key],
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ }));
16
+ __moduleCache.set(from, entry);
17
+ return entry;
18
+ };
19
+ var __export = (target, all) => {
20
+ for (var name in all)
21
+ __defProp(target, name, {
22
+ get: all[name],
23
+ enumerable: true,
24
+ configurable: true,
25
+ set: (newValue) => all[name] = () => newValue
26
+ });
27
+ };
28
+
29
+ // src/index.ts
30
+ var exports_src = {};
31
+ __export(exports_src, {
32
+ register: () => register,
33
+ ElDmMenuItem: () => ElDmMenuItem,
34
+ ElDmMenu: () => ElDmMenu
35
+ });
36
+ module.exports = __toCommonJS(exports_src);
37
+
38
+ // src/el-dm-menu.ts
39
+ var import_el_core = require("@duskmoon-dev/el-core");
40
+ var menuStyles = import_el_core.css`
41
+ :host {
42
+ display: inline-block;
43
+ position: relative;
44
+ }
45
+
46
+ :host([hidden]) {
47
+ display: none !important;
48
+ }
49
+
50
+ .menu-container {
51
+ position: absolute;
52
+ z-index: 1000;
53
+ min-width: 160px;
54
+ max-width: 320px;
55
+ background-color: var(--color-surface, #ffffff);
56
+ border: 1px solid var(--color-outline-variant, #e0e0e0);
57
+ border-radius: 0.5rem;
58
+ box-shadow:
59
+ 0 4px 6px -1px rgba(0, 0, 0, 0.1),
60
+ 0 2px 4px -1px rgba(0, 0, 0, 0.06);
61
+ padding: 0.25rem 0;
62
+ opacity: 0;
63
+ visibility: hidden;
64
+ transform: scale(0.95);
65
+ transform-origin: top left;
66
+ transition:
67
+ opacity 150ms ease,
68
+ visibility 150ms ease,
69
+ transform 150ms ease;
70
+ font-family: inherit;
71
+ }
72
+
73
+ .menu-container.visible {
74
+ opacity: 1;
75
+ visibility: visible;
76
+ transform: scale(1);
77
+ }
78
+
79
+ /* Placement styles */
80
+ .placement-bottom,
81
+ .placement-bottom-start,
82
+ .placement-bottom-end {
83
+ top: 100%;
84
+ margin-top: 0.25rem;
85
+ transform-origin: top;
86
+ }
87
+
88
+ .placement-bottom {
89
+ left: 50%;
90
+ transform: translateX(-50%) scale(0.95);
91
+ }
92
+
93
+ .placement-bottom.visible {
94
+ transform: translateX(-50%) scale(1);
95
+ }
96
+
97
+ .placement-bottom-start {
98
+ left: 0;
99
+ }
100
+
101
+ .placement-bottom-end {
102
+ right: 0;
103
+ left: auto;
104
+ }
105
+
106
+ .placement-top,
107
+ .placement-top-start,
108
+ .placement-top-end {
109
+ bottom: 100%;
110
+ margin-bottom: 0.25rem;
111
+ transform-origin: bottom;
112
+ }
113
+
114
+ .placement-top {
115
+ left: 50%;
116
+ transform: translateX(-50%) scale(0.95);
117
+ }
118
+
119
+ .placement-top.visible {
120
+ transform: translateX(-50%) scale(1);
121
+ }
122
+
123
+ .placement-top-start {
124
+ left: 0;
125
+ }
126
+
127
+ .placement-top-end {
128
+ right: 0;
129
+ left: auto;
130
+ }
131
+
132
+ .placement-left {
133
+ right: 100%;
134
+ top: 0;
135
+ margin-right: 0.25rem;
136
+ transform-origin: right;
137
+ }
138
+
139
+ .placement-right {
140
+ left: 100%;
141
+ top: 0;
142
+ margin-left: 0.25rem;
143
+ transform-origin: left;
144
+ }
145
+
146
+ .items-wrapper {
147
+ display: flex;
148
+ flex-direction: column;
149
+ }
150
+
151
+ ::slotted(el-dm-menu-item) {
152
+ display: block;
153
+ }
154
+
155
+ ::slotted([role='separator']) {
156
+ height: 1px;
157
+ background-color: var(--color-outline-variant, #e0e0e0);
158
+ margin: 0.25rem 0;
159
+ }
160
+ `;
161
+
162
+ class ElDmMenu extends import_el_core.BaseElement {
163
+ static properties = {
164
+ open: { type: Boolean, reflect: true, default: false },
165
+ anchor: { type: String, reflect: true },
166
+ placement: { type: String, reflect: true, default: "bottom-start" }
167
+ };
168
+ _anchorElement = null;
169
+ _focusedIndex = -1;
170
+ _boundHandleDocumentClick;
171
+ _boundHandleKeydown;
172
+ constructor() {
173
+ super();
174
+ this.attachStyles(menuStyles);
175
+ this._boundHandleDocumentClick = this._handleDocumentClick.bind(this);
176
+ this._boundHandleKeydown = this._handleKeydown.bind(this);
177
+ }
178
+ connectedCallback() {
179
+ super.connectedCallback();
180
+ this._setupAnchor();
181
+ }
182
+ disconnectedCallback() {
183
+ super.disconnectedCallback?.();
184
+ this._removeGlobalListeners();
185
+ }
186
+ _setupAnchor() {
187
+ if (this.anchor) {
188
+ this._anchorElement = document.querySelector(this.anchor) || this.closest(this.anchor) || document.getElementById(this.anchor);
189
+ }
190
+ }
191
+ _addGlobalListeners() {
192
+ document.addEventListener("click", this._boundHandleDocumentClick);
193
+ document.addEventListener("keydown", this._boundHandleKeydown);
194
+ }
195
+ _removeGlobalListeners() {
196
+ document.removeEventListener("click", this._boundHandleDocumentClick);
197
+ document.removeEventListener("keydown", this._boundHandleKeydown);
198
+ }
199
+ _handleDocumentClick(event) {
200
+ const target = event.target;
201
+ if (!this.contains(target) && !this._anchorElement?.contains(target)) {
202
+ this.hide();
203
+ }
204
+ }
205
+ _handleKeydown(event) {
206
+ if (!this.open)
207
+ return;
208
+ const items = this._getMenuItems();
209
+ if (items.length === 0)
210
+ return;
211
+ switch (event.key) {
212
+ case "Escape":
213
+ event.preventDefault();
214
+ this.hide();
215
+ this._anchorElement?.focus();
216
+ break;
217
+ case "ArrowDown":
218
+ event.preventDefault();
219
+ this._focusItem(this._getNextFocusableIndex(this._focusedIndex, 1, items));
220
+ break;
221
+ case "ArrowUp":
222
+ event.preventDefault();
223
+ this._focusItem(this._getNextFocusableIndex(this._focusedIndex, -1, items));
224
+ break;
225
+ case "Home":
226
+ event.preventDefault();
227
+ this._focusItem(this._getNextFocusableIndex(-1, 1, items));
228
+ break;
229
+ case "End":
230
+ event.preventDefault();
231
+ this._focusItem(this._getNextFocusableIndex(items.length, -1, items));
232
+ break;
233
+ case "Enter":
234
+ case " ":
235
+ event.preventDefault();
236
+ if (this._focusedIndex >= 0 && this._focusedIndex < items.length) {
237
+ const item = items[this._focusedIndex];
238
+ if (!item.disabled) {
239
+ this._selectItem(item);
240
+ }
241
+ }
242
+ break;
243
+ case "Tab":
244
+ this.hide();
245
+ break;
246
+ }
247
+ }
248
+ _getMenuItems() {
249
+ const slot = this.shadowRoot?.querySelector("slot");
250
+ if (!slot)
251
+ return [];
252
+ return slot.assignedElements().filter((el) => el.tagName === "EL-DM-MENU-ITEM" && !el.hasAttribute("hidden"));
253
+ }
254
+ _getNextFocusableIndex(currentIndex, direction, items) {
255
+ let nextIndex = currentIndex + direction;
256
+ while (nextIndex >= 0 && nextIndex < items.length) {
257
+ const item = items[nextIndex];
258
+ if (!item.disabled) {
259
+ return nextIndex;
260
+ }
261
+ nextIndex += direction;
262
+ }
263
+ if (direction > 0) {
264
+ return this._getNextFocusableIndex(-1, 1, items);
265
+ } else {
266
+ return this._getNextFocusableIndex(items.length, -1, items);
267
+ }
268
+ }
269
+ _focusItem(index) {
270
+ const items = this._getMenuItems();
271
+ if (index < 0 || index >= items.length)
272
+ return;
273
+ if (this._focusedIndex >= 0 && this._focusedIndex < items.length) {
274
+ items[this._focusedIndex].focused = false;
275
+ }
276
+ this._focusedIndex = index;
277
+ const item = items[index];
278
+ item.focused = true;
279
+ item.focus();
280
+ }
281
+ _selectItem(item) {
282
+ this.emit("select", { value: item.value || item.textContent?.trim() });
283
+ this.hide();
284
+ }
285
+ _updatePosition() {
286
+ const menuContainer = this.shadowRoot?.querySelector(".menu-container");
287
+ if (!menuContainer)
288
+ return;
289
+ requestAnimationFrame(() => {
290
+ const rect = menuContainer.getBoundingClientRect();
291
+ const viewportHeight = window.innerHeight;
292
+ const viewportWidth = window.innerWidth;
293
+ let finalPlacement = this.placement;
294
+ if (finalPlacement.startsWith("bottom") && rect.bottom > viewportHeight) {
295
+ finalPlacement = finalPlacement.replace("bottom", "top");
296
+ } else if (finalPlacement.startsWith("top") && rect.top < 0) {
297
+ finalPlacement = finalPlacement.replace("top", "bottom");
298
+ }
299
+ if (finalPlacement === "right" && rect.right > viewportWidth) {
300
+ finalPlacement = "left";
301
+ } else if (finalPlacement === "left" && rect.left < 0) {
302
+ finalPlacement = "right";
303
+ }
304
+ if (finalPlacement !== this.placement) {
305
+ menuContainer.className = `menu-container placement-${finalPlacement}${this.open ? " visible" : ""}`;
306
+ }
307
+ });
308
+ }
309
+ show() {
310
+ if (this.open)
311
+ return;
312
+ this.open = true;
313
+ this._focusedIndex = -1;
314
+ this._addGlobalListeners();
315
+ this._updatePosition();
316
+ this.emit("open");
317
+ requestAnimationFrame(() => {
318
+ const items = this._getMenuItems();
319
+ if (items.length > 0) {
320
+ this._focusItem(this._getNextFocusableIndex(-1, 1, items));
321
+ }
322
+ });
323
+ }
324
+ hide() {
325
+ if (!this.open)
326
+ return;
327
+ this.open = false;
328
+ this._focusedIndex = -1;
329
+ this._removeGlobalListeners();
330
+ this.emit("close");
331
+ const items = this._getMenuItems();
332
+ items.forEach((item) => {
333
+ item.focused = false;
334
+ });
335
+ }
336
+ toggle() {
337
+ if (this.open) {
338
+ this.hide();
339
+ } else {
340
+ this.show();
341
+ }
342
+ }
343
+ update() {
344
+ super.update?.();
345
+ const menuContainer = this.shadowRoot?.querySelector(".menu-container");
346
+ if (menuContainer) {
347
+ menuContainer.classList.toggle("visible", this.open);
348
+ if (this.open) {
349
+ this._updatePosition();
350
+ }
351
+ }
352
+ }
353
+ render() {
354
+ const placementClass = `placement-${this.placement || "bottom-start"}`;
355
+ return `
356
+ <slot name="trigger"></slot>
357
+ <div
358
+ class="menu-container ${placementClass}${this.open ? " visible" : ""}"
359
+ part="menu"
360
+ role="menu"
361
+ aria-hidden="${!this.open}"
362
+ >
363
+ <div class="items-wrapper" part="items">
364
+ <slot></slot>
365
+ </div>
366
+ </div>
367
+ `;
368
+ }
369
+ }
370
+ var menuItemStyles = import_el_core.css`
371
+ :host {
372
+ display: block;
373
+ }
374
+
375
+ :host([hidden]) {
376
+ display: none !important;
377
+ }
378
+
379
+ .menu-item {
380
+ display: flex;
381
+ align-items: center;
382
+ gap: 0.75rem;
383
+ padding: 0.5rem 1rem;
384
+ cursor: pointer;
385
+ color: var(--color-on-surface, #1f1f1f);
386
+ background-color: transparent;
387
+ border: none;
388
+ width: 100%;
389
+ text-align: left;
390
+ font-size: 0.875rem;
391
+ line-height: 1.25rem;
392
+ font-family: inherit;
393
+ transition:
394
+ background-color 150ms ease,
395
+ color 150ms ease;
396
+ outline: none;
397
+ }
398
+
399
+ .menu-item:hover:not(.disabled) {
400
+ background-color: var(--color-surface-container-highest, #f5f5f5);
401
+ }
402
+
403
+ .menu-item:focus:not(.disabled),
404
+ .menu-item.focused:not(.disabled) {
405
+ background-color: var(--color-surface-container-highest, #f5f5f5);
406
+ outline: 2px solid var(--color-primary, #6750a4);
407
+ outline-offset: -2px;
408
+ }
409
+
410
+ .menu-item.disabled {
411
+ cursor: not-allowed;
412
+ opacity: 0.5;
413
+ color: var(--color-on-surface-variant, #49454f);
414
+ }
415
+
416
+ .icon-wrapper {
417
+ display: flex;
418
+ align-items: center;
419
+ justify-content: center;
420
+ width: 1.25rem;
421
+ height: 1.25rem;
422
+ flex-shrink: 0;
423
+ }
424
+
425
+ .icon-wrapper:empty {
426
+ display: none;
427
+ }
428
+
429
+ .content-wrapper {
430
+ flex: 1;
431
+ min-width: 0;
432
+ }
433
+
434
+ ::slotted(svg),
435
+ ::slotted(img) {
436
+ width: 1.25rem;
437
+ height: 1.25rem;
438
+ }
439
+ `;
440
+
441
+ class ElDmMenuItem extends import_el_core.BaseElement {
442
+ static properties = {
443
+ value: { type: String, reflect: true },
444
+ disabled: { type: Boolean, reflect: true, default: false },
445
+ focused: { type: Boolean, reflect: true, default: false }
446
+ };
447
+ constructor() {
448
+ super();
449
+ this.attachStyles(menuItemStyles);
450
+ }
451
+ connectedCallback() {
452
+ super.connectedCallback();
453
+ this.setAttribute("role", "menuitem");
454
+ this.setAttribute("tabindex", "-1");
455
+ this.addEventListener("click", this._handleClick.bind(this));
456
+ }
457
+ _handleClick(event) {
458
+ if (this.disabled) {
459
+ event.preventDefault();
460
+ event.stopPropagation();
461
+ return;
462
+ }
463
+ const menu = this.closest("el-dm-menu");
464
+ if (menu) {
465
+ menu.dispatchEvent(new CustomEvent("select", {
466
+ bubbles: true,
467
+ composed: true,
468
+ detail: { value: this.value || this.textContent?.trim() }
469
+ }));
470
+ menu.hide();
471
+ }
472
+ }
473
+ update() {
474
+ super.update?.();
475
+ this.setAttribute("aria-disabled", String(this.disabled));
476
+ const itemEl = this.shadowRoot?.querySelector(".menu-item");
477
+ if (itemEl) {
478
+ itemEl.classList.toggle("disabled", this.disabled);
479
+ itemEl.classList.toggle("focused", this.focused);
480
+ }
481
+ }
482
+ render() {
483
+ return `
484
+ <div
485
+ class="menu-item${this.disabled ? " disabled" : ""}${this.focused ? " focused" : ""}"
486
+ part="item"
487
+ >
488
+ <span class="icon-wrapper" part="icon">
489
+ <slot name="icon"></slot>
490
+ </span>
491
+ <span class="content-wrapper" part="content">
492
+ <slot></slot>
493
+ </span>
494
+ </div>
495
+ `;
496
+ }
497
+ }
498
+
499
+ // src/index.ts
500
+ function register() {
501
+ if (!customElements.get("el-dm-menu")) {
502
+ customElements.define("el-dm-menu", ElDmMenu);
503
+ }
504
+ if (!customElements.get("el-dm-menu-item")) {
505
+ customElements.define("el-dm-menu-item", ElDmMenuItem);
506
+ }
507
+ }
508
+
509
+ //# debugId=597792FA78F8BC4F64756E2164756E21
510
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/el-dm-menu.ts", "../../src/index.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * DuskMoon Menu Element\n *\n * A dropdown menu component with menu items supporting keyboard navigation.\n *\n * @element el-dm-menu\n *\n * @attr {boolean} open - Whether the menu is open\n * @attr {string} anchor - Element ref or CSS selector for the anchor element\n * @attr {string} placement - Menu placement: top, bottom, left, right, top-start, top-end, bottom-start, bottom-end\n *\n * @slot - Default slot for menu items\n *\n * @csspart menu - The menu container\n * @csspart items - The menu items wrapper\n *\n * @fires open - Fired when the menu opens\n * @fires close - Fired when the menu closes\n * @fires select - Fired when a menu item is selected (detail: { value: string })\n */\n\nimport { BaseElement, css } from '@duskmoon-dev/el-core';\n\nexport type MenuPlacement =\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'top-start'\n | 'top-end'\n | 'bottom-start'\n | 'bottom-end';\n\nconst menuStyles = css`\n :host {\n display: inline-block;\n position: relative;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n .menu-container {\n position: absolute;\n z-index: 1000;\n min-width: 160px;\n max-width: 320px;\n background-color: var(--color-surface, #ffffff);\n border: 1px solid var(--color-outline-variant, #e0e0e0);\n border-radius: 0.5rem;\n box-shadow:\n 0 4px 6px -1px rgba(0, 0, 0, 0.1),\n 0 2px 4px -1px rgba(0, 0, 0, 0.06);\n padding: 0.25rem 0;\n opacity: 0;\n visibility: hidden;\n transform: scale(0.95);\n transform-origin: top left;\n transition:\n opacity 150ms ease,\n visibility 150ms ease,\n transform 150ms ease;\n font-family: inherit;\n }\n\n .menu-container.visible {\n opacity: 1;\n visibility: visible;\n transform: scale(1);\n }\n\n /* Placement styles */\n .placement-bottom,\n .placement-bottom-start,\n .placement-bottom-end {\n top: 100%;\n margin-top: 0.25rem;\n transform-origin: top;\n }\n\n .placement-bottom {\n left: 50%;\n transform: translateX(-50%) scale(0.95);\n }\n\n .placement-bottom.visible {\n transform: translateX(-50%) scale(1);\n }\n\n .placement-bottom-start {\n left: 0;\n }\n\n .placement-bottom-end {\n right: 0;\n left: auto;\n }\n\n .placement-top,\n .placement-top-start,\n .placement-top-end {\n bottom: 100%;\n margin-bottom: 0.25rem;\n transform-origin: bottom;\n }\n\n .placement-top {\n left: 50%;\n transform: translateX(-50%) scale(0.95);\n }\n\n .placement-top.visible {\n transform: translateX(-50%) scale(1);\n }\n\n .placement-top-start {\n left: 0;\n }\n\n .placement-top-end {\n right: 0;\n left: auto;\n }\n\n .placement-left {\n right: 100%;\n top: 0;\n margin-right: 0.25rem;\n transform-origin: right;\n }\n\n .placement-right {\n left: 100%;\n top: 0;\n margin-left: 0.25rem;\n transform-origin: left;\n }\n\n .items-wrapper {\n display: flex;\n flex-direction: column;\n }\n\n ::slotted(el-dm-menu-item) {\n display: block;\n }\n\n ::slotted([role='separator']) {\n height: 1px;\n background-color: var(--color-outline-variant, #e0e0e0);\n margin: 0.25rem 0;\n }\n`;\n\nexport class ElDmMenu extends BaseElement {\n static properties = {\n open: { type: Boolean, reflect: true, default: false },\n anchor: { type: String, reflect: true },\n placement: { type: String, reflect: true, default: 'bottom-start' },\n };\n\n declare open: boolean;\n declare anchor: string;\n declare placement: MenuPlacement;\n\n private _anchorElement: HTMLElement | null = null;\n private _focusedIndex = -1;\n private _boundHandleDocumentClick: (e: MouseEvent) => void;\n private _boundHandleKeydown: (e: KeyboardEvent) => void;\n\n constructor() {\n super();\n this.attachStyles(menuStyles);\n this._boundHandleDocumentClick = this._handleDocumentClick.bind(this);\n this._boundHandleKeydown = this._handleKeydown.bind(this);\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n this._setupAnchor();\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback?.();\n this._removeGlobalListeners();\n }\n\n private _setupAnchor(): void {\n if (this.anchor) {\n this._anchorElement =\n document.querySelector(this.anchor) ||\n this.closest(this.anchor) ||\n document.getElementById(this.anchor);\n }\n }\n\n private _addGlobalListeners(): void {\n document.addEventListener('click', this._boundHandleDocumentClick);\n document.addEventListener('keydown', this._boundHandleKeydown);\n }\n\n private _removeGlobalListeners(): void {\n document.removeEventListener('click', this._boundHandleDocumentClick);\n document.removeEventListener('keydown', this._boundHandleKeydown);\n }\n\n private _handleDocumentClick(event: MouseEvent): void {\n const target = event.target as Node;\n if (!this.contains(target) && !this._anchorElement?.contains(target)) {\n this.hide();\n }\n }\n\n private _handleKeydown(event: KeyboardEvent): void {\n if (!this.open) return;\n\n const items = this._getMenuItems();\n if (items.length === 0) return;\n\n switch (event.key) {\n case 'Escape':\n event.preventDefault();\n this.hide();\n this._anchorElement?.focus();\n break;\n\n case 'ArrowDown':\n event.preventDefault();\n this._focusItem(this._getNextFocusableIndex(this._focusedIndex, 1, items));\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n this._focusItem(this._getNextFocusableIndex(this._focusedIndex, -1, items));\n break;\n\n case 'Home':\n event.preventDefault();\n this._focusItem(this._getNextFocusableIndex(-1, 1, items));\n break;\n\n case 'End':\n event.preventDefault();\n this._focusItem(this._getNextFocusableIndex(items.length, -1, items));\n break;\n\n case 'Enter':\n case ' ':\n event.preventDefault();\n if (this._focusedIndex >= 0 && this._focusedIndex < items.length) {\n const item = items[this._focusedIndex] as ElDmMenuItem;\n if (!item.disabled) {\n this._selectItem(item);\n }\n }\n break;\n\n case 'Tab':\n this.hide();\n break;\n }\n }\n\n private _getMenuItems(): Element[] {\n const slot = this.shadowRoot?.querySelector('slot');\n if (!slot) return [];\n return slot\n .assignedElements()\n .filter((el) => el.tagName === 'EL-DM-MENU-ITEM' && !el.hasAttribute('hidden'));\n }\n\n private _getNextFocusableIndex(\n currentIndex: number,\n direction: number,\n items: Element[],\n ): number {\n let nextIndex = currentIndex + direction;\n\n while (nextIndex >= 0 && nextIndex < items.length) {\n const item = items[nextIndex] as ElDmMenuItem;\n if (!item.disabled) {\n return nextIndex;\n }\n nextIndex += direction;\n }\n\n // Wrap around\n if (direction > 0) {\n return this._getNextFocusableIndex(-1, 1, items);\n } else {\n return this._getNextFocusableIndex(items.length, -1, items);\n }\n }\n\n private _focusItem(index: number): void {\n const items = this._getMenuItems();\n if (index < 0 || index >= items.length) return;\n\n // Remove focus from previous item\n if (this._focusedIndex >= 0 && this._focusedIndex < items.length) {\n (items[this._focusedIndex] as ElDmMenuItem).focused = false;\n }\n\n // Focus new item\n this._focusedIndex = index;\n const item = items[index] as ElDmMenuItem;\n item.focused = true;\n item.focus();\n }\n\n private _selectItem(item: ElDmMenuItem): void {\n this.emit('select', { value: item.value || item.textContent?.trim() });\n this.hide();\n }\n\n private _updatePosition(): void {\n const menuContainer = this.shadowRoot?.querySelector('.menu-container') as HTMLElement;\n if (!menuContainer) return;\n\n // Check if menu would go off screen and flip if necessary\n requestAnimationFrame(() => {\n const rect = menuContainer.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const viewportWidth = window.innerWidth;\n\n let finalPlacement = this.placement;\n\n // Flip vertical placement if needed\n if (finalPlacement.startsWith('bottom') && rect.bottom > viewportHeight) {\n finalPlacement = finalPlacement.replace('bottom', 'top') as MenuPlacement;\n } else if (finalPlacement.startsWith('top') && rect.top < 0) {\n finalPlacement = finalPlacement.replace('top', 'bottom') as MenuPlacement;\n }\n\n // Flip horizontal placement if needed\n if (finalPlacement === 'right' && rect.right > viewportWidth) {\n finalPlacement = 'left';\n } else if (finalPlacement === 'left' && rect.left < 0) {\n finalPlacement = 'right';\n }\n\n // Update class if flipped\n if (finalPlacement !== this.placement) {\n menuContainer.className = `menu-container placement-${finalPlacement}${this.open ? ' visible' : ''}`;\n }\n });\n }\n\n /**\n * Show the menu\n */\n show(): void {\n if (this.open) return;\n this.open = true;\n this._focusedIndex = -1;\n this._addGlobalListeners();\n this._updatePosition();\n this.emit('open');\n\n // Focus first item after menu opens\n requestAnimationFrame(() => {\n const items = this._getMenuItems();\n if (items.length > 0) {\n this._focusItem(this._getNextFocusableIndex(-1, 1, items));\n }\n });\n }\n\n /**\n * Hide the menu\n */\n hide(): void {\n if (!this.open) return;\n this.open = false;\n this._focusedIndex = -1;\n this._removeGlobalListeners();\n this.emit('close');\n\n // Clear focus from items\n const items = this._getMenuItems();\n items.forEach((item) => {\n (item as ElDmMenuItem).focused = false;\n });\n }\n\n /**\n * Toggle the menu open/closed\n */\n toggle(): void {\n if (this.open) {\n this.hide();\n } else {\n this.show();\n }\n }\n\n update(): void {\n super.update?.();\n const menuContainer = this.shadowRoot?.querySelector('.menu-container');\n if (menuContainer) {\n menuContainer.classList.toggle('visible', this.open);\n if (this.open) {\n this._updatePosition();\n }\n }\n }\n\n render(): string {\n const placementClass = `placement-${this.placement || 'bottom-start'}`;\n\n return `\n <slot name=\"trigger\"></slot>\n <div\n class=\"menu-container ${placementClass}${this.open ? ' visible' : ''}\"\n part=\"menu\"\n role=\"menu\"\n aria-hidden=\"${!this.open}\"\n >\n <div class=\"items-wrapper\" part=\"items\">\n <slot></slot>\n </div>\n </div>\n `;\n }\n}\n\n/**\n * DuskMoon Menu Item Element\n *\n * A menu item component for use within el-dm-menu.\n *\n * @element el-dm-menu-item\n *\n * @attr {string} value - The value associated with this item\n * @attr {boolean} disabled - Whether the item is disabled\n * @attr {boolean} focused - Whether the item is currently focused (internal)\n *\n * @slot - Default slot for item content\n * @slot icon - Slot for an icon before the content\n *\n * @csspart item - The menu item container\n * @csspart icon - The icon wrapper\n * @csspart content - The content wrapper\n */\n\nconst menuItemStyles = css`\n :host {\n display: block;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n .menu-item {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.5rem 1rem;\n cursor: pointer;\n color: var(--color-on-surface, #1f1f1f);\n background-color: transparent;\n border: none;\n width: 100%;\n text-align: left;\n font-size: 0.875rem;\n line-height: 1.25rem;\n font-family: inherit;\n transition:\n background-color 150ms ease,\n color 150ms ease;\n outline: none;\n }\n\n .menu-item:hover:not(.disabled) {\n background-color: var(--color-surface-container-highest, #f5f5f5);\n }\n\n .menu-item:focus:not(.disabled),\n .menu-item.focused:not(.disabled) {\n background-color: var(--color-surface-container-highest, #f5f5f5);\n outline: 2px solid var(--color-primary, #6750a4);\n outline-offset: -2px;\n }\n\n .menu-item.disabled {\n cursor: not-allowed;\n opacity: 0.5;\n color: var(--color-on-surface-variant, #49454f);\n }\n\n .icon-wrapper {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n flex-shrink: 0;\n }\n\n .icon-wrapper:empty {\n display: none;\n }\n\n .content-wrapper {\n flex: 1;\n min-width: 0;\n }\n\n ::slotted(svg),\n ::slotted(img) {\n width: 1.25rem;\n height: 1.25rem;\n }\n`;\n\nexport class ElDmMenuItem extends BaseElement {\n static properties = {\n value: { type: String, reflect: true },\n disabled: { type: Boolean, reflect: true, default: false },\n focused: { type: Boolean, reflect: true, default: false },\n };\n\n declare value: string;\n declare disabled: boolean;\n declare focused: boolean;\n\n constructor() {\n super();\n this.attachStyles(menuItemStyles);\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('role', 'menuitem');\n this.setAttribute('tabindex', '-1');\n this.addEventListener('click', this._handleClick.bind(this));\n }\n\n private _handleClick(event: MouseEvent): void {\n if (this.disabled) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n // Dispatch select event on parent menu\n const menu = this.closest('el-dm-menu') as ElDmMenu;\n if (menu) {\n menu.dispatchEvent(\n new CustomEvent('select', {\n bubbles: true,\n composed: true,\n detail: { value: this.value || this.textContent?.trim() },\n }),\n );\n menu.hide();\n }\n }\n\n update(): void {\n super.update?.();\n this.setAttribute('aria-disabled', String(this.disabled));\n\n const itemEl = this.shadowRoot?.querySelector('.menu-item');\n if (itemEl) {\n itemEl.classList.toggle('disabled', this.disabled);\n itemEl.classList.toggle('focused', this.focused);\n }\n }\n\n render(): string {\n return `\n <div\n class=\"menu-item${this.disabled ? ' disabled' : ''}${this.focused ? ' focused' : ''}\"\n part=\"item\"\n >\n <span class=\"icon-wrapper\" part=\"icon\">\n <slot name=\"icon\"></slot>\n </span>\n <span class=\"content-wrapper\" part=\"content\">\n <slot></slot>\n </span>\n </div>\n `;\n }\n}\n",
6
+ "/**\n * @duskmoon-dev/el-menu\n *\n * DuskMoon Menu custom elements\n */\n\nimport { ElDmMenu } from './el-dm-menu.js';\nimport { ElDmMenuItem } from './el-dm-menu.js';\n\nexport { ElDmMenu, ElDmMenuItem };\n\n/**\n * Register the el-dm-menu and el-dm-menu-item custom elements\n *\n * @example\n * ```ts\n * import { register } from '@duskmoon-dev/el-menu';\n * register();\n * ```\n */\nexport function register(): void {\n if (!customElements.get('el-dm-menu')) {\n customElements.define('el-dm-menu', ElDmMenu);\n }\n if (!customElements.get('el-dm-menu-item')) {\n customElements.define('el-dm-menu-item', ElDmMenuItem);\n }\n}\n"
7
+ ],
8
+ "mappings": "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",
9
+ "debugId": "597792FA78F8BC4F64756E2164756E21",
10
+ "names": []
11
+ }