@duskmoon-dev/el-menu 0.5.0 → 0.7.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/dist/esm/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  // src/el-dm-menu.ts
2
- import { BaseElement, css } from "@duskmoon-dev/el-core";
2
+ import { BaseElement, css } from "@duskmoon-dev/el-base";
3
+ import { css as navigationCSS } from "@duskmoon-dev/core/components/navigation";
4
+ var coreStyles = navigationCSS.replace(/@layer\s+components\s*\{/, "").replace(/\}\s*$/, "");
3
5
  var menuStyles = css`
4
6
  :host {
5
7
  display: inline-block;
@@ -10,7 +12,11 @@ var menuStyles = css`
10
12
  display: none !important;
11
13
  }
12
14
 
13
- .menu-container {
15
+ /* Import core navigation styles */
16
+ ${coreStyles}
17
+
18
+ /* Override core .menu for dropdown behavior */
19
+ .menu {
14
20
  position: absolute;
15
21
  z-index: 1000;
16
22
  min-width: 160px;
@@ -31,9 +37,12 @@ var menuStyles = css`
31
37
  visibility 150ms ease,
32
38
  transform 150ms ease;
33
39
  font-family: inherit;
40
+ flex-direction: column;
41
+ flex-wrap: nowrap;
42
+ gap: 0;
34
43
  }
35
44
 
36
- .menu-container.visible {
45
+ .menu.visible {
37
46
  opacity: 1;
38
47
  visibility: visible;
39
48
  transform: scale(1);
@@ -246,11 +255,11 @@ class ElDmMenu extends BaseElement {
246
255
  this.hide();
247
256
  }
248
257
  _updatePosition() {
249
- const menuContainer = this.shadowRoot?.querySelector(".menu-container");
250
- if (!menuContainer)
258
+ const menuEl = this.shadowRoot?.querySelector(".menu");
259
+ if (!menuEl)
251
260
  return;
252
261
  requestAnimationFrame(() => {
253
- const rect = menuContainer.getBoundingClientRect();
262
+ const rect = menuEl.getBoundingClientRect();
254
263
  const viewportHeight = window.innerHeight;
255
264
  const viewportWidth = window.innerWidth;
256
265
  let finalPlacement = this.placement;
@@ -265,7 +274,7 @@ class ElDmMenu extends BaseElement {
265
274
  finalPlacement = "right";
266
275
  }
267
276
  if (finalPlacement !== this.placement) {
268
- menuContainer.className = `menu-container placement-${finalPlacement}${this.open ? " visible" : ""}`;
277
+ menuEl.className = `menu placement-${finalPlacement}${this.open ? " visible" : ""}`;
269
278
  }
270
279
  });
271
280
  }
@@ -305,9 +314,9 @@ class ElDmMenu extends BaseElement {
305
314
  }
306
315
  update() {
307
316
  super.update?.();
308
- const menuContainer = this.shadowRoot?.querySelector(".menu-container");
309
- if (menuContainer) {
310
- menuContainer.classList.toggle("visible", this.open);
317
+ const menuEl = this.shadowRoot?.querySelector(".menu");
318
+ if (menuEl) {
319
+ menuEl.classList.toggle("visible", this.open);
311
320
  if (this.open) {
312
321
  this._updatePosition();
313
322
  }
@@ -318,7 +327,7 @@ class ElDmMenu extends BaseElement {
318
327
  return `
319
328
  <slot name="trigger"></slot>
320
329
  <div
321
- class="menu-container ${placementClass}${this.open ? " visible" : ""}"
330
+ class="menu ${placementClass}${this.open ? " visible" : ""}"
322
331
  part="menu"
323
332
  role="menu"
324
333
  aria-hidden="${!this.open}"
@@ -474,5 +483,5 @@ export {
474
483
  ElDmMenu
475
484
  };
476
485
 
477
- //# debugId=240A8CA23E7105C364756E2164756E21
486
+ //# debugId=CF26230AFE7269CB64756E2164756E21
478
487
  //# sourceMappingURL=index.js.map
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/el-dm-menu.ts", "../../src/index.ts"],
4
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",
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-base';\nimport { css as navigationCSS } from '@duskmoon-dev/core/components/navigation';\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\n// Strip @layer wrapper for Shadow DOM compatibility\nconst coreStyles = navigationCSS.replace(/@layer\\s+components\\s*\\{/, '').replace(/\\}\\s*$/, '');\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 /* Import core navigation styles */\n ${coreStyles}\n\n /* Override core .menu for dropdown behavior */\n .menu {\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 flex-direction: column;\n flex-wrap: nowrap;\n gap: 0;\n }\n\n .menu.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 menuEl = this.shadowRoot?.querySelector('.menu') as HTMLElement;\n if (!menuEl) return;\n\n // Check if menu would go off screen and flip if necessary\n requestAnimationFrame(() => {\n const rect = menuEl.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 menuEl.className = `menu 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 menuEl = this.shadowRoot?.querySelector('.menu');\n if (menuEl) {\n menuEl.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 ${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
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
7
  ],
8
- "mappings": "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",
9
- "debugId": "240A8CA23E7105C364756E2164756E21",
8
+ "mappings": "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",
9
+ "debugId": "CF26230AFE7269CB64756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -1,5 +1,7 @@
1
1
  // src/el-dm-menu.ts
2
- import { BaseElement, css } from "@duskmoon-dev/el-core";
2
+ import { BaseElement, css } from "@duskmoon-dev/el-base";
3
+ import { css as navigationCSS } from "@duskmoon-dev/core/components/navigation";
4
+ var coreStyles = navigationCSS.replace(/@layer\s+components\s*\{/, "").replace(/\}\s*$/, "");
3
5
  var menuStyles = css`
4
6
  :host {
5
7
  display: inline-block;
@@ -10,7 +12,11 @@ var menuStyles = css`
10
12
  display: none !important;
11
13
  }
12
14
 
13
- .menu-container {
15
+ /* Import core navigation styles */
16
+ ${coreStyles}
17
+
18
+ /* Override core .menu for dropdown behavior */
19
+ .menu {
14
20
  position: absolute;
15
21
  z-index: 1000;
16
22
  min-width: 160px;
@@ -31,9 +37,12 @@ var menuStyles = css`
31
37
  visibility 150ms ease,
32
38
  transform 150ms ease;
33
39
  font-family: inherit;
40
+ flex-direction: column;
41
+ flex-wrap: nowrap;
42
+ gap: 0;
34
43
  }
35
44
 
36
- .menu-container.visible {
45
+ .menu.visible {
37
46
  opacity: 1;
38
47
  visibility: visible;
39
48
  transform: scale(1);
@@ -246,11 +255,11 @@ class ElDmMenu extends BaseElement {
246
255
  this.hide();
247
256
  }
248
257
  _updatePosition() {
249
- const menuContainer = this.shadowRoot?.querySelector(".menu-container");
250
- if (!menuContainer)
258
+ const menuEl = this.shadowRoot?.querySelector(".menu");
259
+ if (!menuEl)
251
260
  return;
252
261
  requestAnimationFrame(() => {
253
- const rect = menuContainer.getBoundingClientRect();
262
+ const rect = menuEl.getBoundingClientRect();
254
263
  const viewportHeight = window.innerHeight;
255
264
  const viewportWidth = window.innerWidth;
256
265
  let finalPlacement = this.placement;
@@ -265,7 +274,7 @@ class ElDmMenu extends BaseElement {
265
274
  finalPlacement = "right";
266
275
  }
267
276
  if (finalPlacement !== this.placement) {
268
- menuContainer.className = `menu-container placement-${finalPlacement}${this.open ? " visible" : ""}`;
277
+ menuEl.className = `menu placement-${finalPlacement}${this.open ? " visible" : ""}`;
269
278
  }
270
279
  });
271
280
  }
@@ -305,9 +314,9 @@ class ElDmMenu extends BaseElement {
305
314
  }
306
315
  update() {
307
316
  super.update?.();
308
- const menuContainer = this.shadowRoot?.querySelector(".menu-container");
309
- if (menuContainer) {
310
- menuContainer.classList.toggle("visible", this.open);
317
+ const menuEl = this.shadowRoot?.querySelector(".menu");
318
+ if (menuEl) {
319
+ menuEl.classList.toggle("visible", this.open);
311
320
  if (this.open) {
312
321
  this._updatePosition();
313
322
  }
@@ -318,7 +327,7 @@ class ElDmMenu extends BaseElement {
318
327
  return `
319
328
  <slot name="trigger"></slot>
320
329
  <div
321
- class="menu-container ${placementClass}${this.open ? " visible" : ""}"
330
+ class="menu ${placementClass}${this.open ? " visible" : ""}"
322
331
  part="menu"
323
332
  role="menu"
324
333
  aria-hidden="${!this.open}"
@@ -472,5 +481,5 @@ function register() {
472
481
  // src/register.ts
473
482
  register();
474
483
 
475
- //# debugId=AC91F58B3AE1C2B764756E2164756E21
484
+ //# debugId=1061BBF74117BF7F64756E2164756E21
476
485
  //# sourceMappingURL=register.js.map
@@ -2,11 +2,11 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/el-dm-menu.ts", "../../src/index.ts", "../../src/register.ts"],
4
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",
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-base';\nimport { css as navigationCSS } from '@duskmoon-dev/core/components/navigation';\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\n// Strip @layer wrapper for Shadow DOM compatibility\nconst coreStyles = navigationCSS.replace(/@layer\\s+components\\s*\\{/, '').replace(/\\}\\s*$/, '');\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 /* Import core navigation styles */\n ${coreStyles}\n\n /* Override core .menu for dropdown behavior */\n .menu {\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 flex-direction: column;\n flex-wrap: nowrap;\n gap: 0;\n }\n\n .menu.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 menuEl = this.shadowRoot?.querySelector('.menu') as HTMLElement;\n if (!menuEl) return;\n\n // Check if menu would go off screen and flip if necessary\n requestAnimationFrame(() => {\n const rect = menuEl.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 menuEl.className = `menu 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 menuEl = this.shadowRoot?.querySelector('.menu');\n if (menuEl) {\n menuEl.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 ${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
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
7
  "/**\n * Auto-register el-dm-menu and el-dm-menu-item custom elements\n *\n * @example\n * ```ts\n * import '@duskmoon-dev/el-menu/register';\n *\n * // Now you can use <el-dm-menu> and <el-dm-menu-item> in HTML\n * ```\n */\nimport { register } from './index.js';\n\nregister();\n"
8
8
  ],
9
- "mappings": "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",
10
- "debugId": "AC91F58B3AE1C2B764756E2164756E21",
9
+ "mappings": "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",
10
+ "debugId": "1061BBF74117BF7F64756E2164756E21",
11
11
  "names": []
12
12
  }