@nordhealth/components 4.16.0 → 4.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/Dropdown.js CHANGED
@@ -1,2 +1,2 @@
1
- import{_ as t}from"./tslib.es6-CmLYFWVC.js";import{css as e,html as o,LitElement as n}from"lit";import{query as s,state as i,property as r,customElement as a}from"lit/decorators.js";import{ifDefined as d}from"lit/directives/if-defined.js";import{S as l}from"./SlotController-Z6eG7LSZ.js";import{o as p}from"./observe-D0n0zOfU.js";import{F as c}from"./Popout-vR6LxNS9.js";import{s as u}from"./Component-DSU3Qp0O.js";import"./Icon.js";import"./DropdownItem.js";import"./EventController-BBOmvfLa.js";import"./positioning-D-K8Mueq.js";import"./DirectionController-ChvNGESZ.js";import"./LightDismissController-4pH8cdko.js";import"./ShortcutController-BIb3WGzH.js";import"./tinykeys.module-_6MZt7MP.js";import"./ScrollbarController-BFC67Y2x.js";import"./events-Bv6wNHwJ.js";import"lit/directives/unsafe-html.js";import"./cond-CI1KbneT.js";import"./IconManager.js";import"lit/directives/ref.js";import"./FocusableMixin-BlQLNPdJ.js";import"./DropdownItem-tmJQrv7d.js";const h=e`:host{--_n-dropdown-size:var(--n-dropdown-size, 250px);--_n-dropdown-max-block-size:var(--n-dropdown-max-block-size, 460px)}.n-dropdown-content{padding:var(--n-space-s) 0;min-inline-size:var(--_n-dropdown-size);max-inline-size:calc(var(--_n-dropdown-size) * 1.5);max-block-size:var(--_n-dropdown-max-block-size);overflow-y:auto}@media (max-width:35.9375em){.n-dropdown-content{max-block-size:70vh;max-inline-size:none}.n-dropdown-header.is-navigation-header{padding:var(--n-space-s) 0}.n-dropdown-back-item{padding-inline-start:var(--n-space-s);padding-inline-end:var(--n-space-s);inline-size:100%}.n-dropdown-content.is-submenu-active ::slotted(nord-dropdown-group),.n-dropdown-content.is-submenu-active ::slotted(nord-dropdown-item),.n-dropdown-content.is-submenu-active ::slotted(nord-dropdown-submenu:not([mobile-active])){display:none}}::slotted(nord-dropdown-group),::slotted(nord-dropdown-item){padding-inline-start:var(--n-space-s);padding-inline-end:var(--n-space-s)}::slotted(nord-dropdown-group){padding-block-end:var(--n-space-s);border-block-end:1px solid var(--n-color-border);margin-block-end:var(--n-space-s)}::slotted(nord-dropdown-group:last-child){padding-block-end:0;border-block-end:0;margin-block-end:0}::slotted(nord-message:first-of-type){padding-block-start:0}::slotted(nord-message:last-of-type){margin-block-end:var(--n-space-s)}slot[name=toggle]{display:inline-block}:host([expand]) slot[name=toggle]{inline-size:100%}:host([size='s']){--_n-dropdown-size:var(--n-dropdown-size, 150px)}:host([size='l']){--_n-dropdown-size:var(--n-dropdown-size, 300px)}.n-dropdown-header{padding:calc(var(--n-space-m) + 2px) var(--n-space-m);border-block-end:1px solid var(--n-color-border);background-color:var(--n-color-surface-raised);border-start-start-radius:var(--n-border-radius);border-start-end-radius:var(--n-border-radius);font-weight:var(--n-font-weight);display:flex;gap:var(--n-space-s);align-items:center;flex-wrap:wrap}.n-dropdown-header ::slotted(nord-button){--n-button-gap:var(--n-space-xs);--n-button-background-color:var(--n-color-surface)}.n-dropdown-header ::slotted(nord-button:hover){--n-button-background-color:var(--n-color-button-hover)}::slotted([slot=header-end]){margin-inline-start:auto;gap:var(--n-space-s);display:flex;align-items:center;flex-wrap:wrap}::slotted(:is(h1, h2, h3, h4, h5, h6, p)){margin:0!important}`;let m=class extends(c(n)){constructor(){super(...arguments),this.headerSlot=new l(this,"header"),this.headerEndSlot=new l(this,"header-end"),this.submenuStack=[],this.isNavigating=!1,this.expand=!1,this.size="m",this.alwaysFloating=!1}get isShowingSubmenu(){return this.submenuStack.length>0}get submenuStackRef(){return this.submenuStack}get deepestSubmenu(){return this.submenuStack[this.submenuStack.length-1]}connectedCallback(){super.connectedCallback();const t=this.querySelector('[slot="toggle"]');null==t||t.setAttribute("aria-haspopup","true")}render(){var t;const e=this.submenuStack[this.submenuStack.length-1];return o`<div class="n-dropdown" @nord-submenu-navigate="${this.handleSubmenuNavigate}" @focusout="${this.handleBlur}"><slot name="toggle" aria-controls="popout"></slot><nord-popout id="popout" align="${d(this.align)}" position="${d(this.position)}" ?open="${this.open}" ?always-floating="${this.alwaysFloating}" @open="${this.handleOpen}" @close="${this.handleClose}">${this.isShowingSubmenu?o`<div class="n-dropdown-header is-navigation-header"><nord-dropdown-item @click="${this.handleBackClick}" class="n-dropdown-back-item"><nord-icon slot="start" name="arrow-left" size="s"></nord-icon>${null!==(t=null==e?void 0:e.label)&&void 0!==t?t:""}</nord-dropdown-item></div>`:o`<div class="n-dropdown-header" ?hidden="${this.headerSlot.isEmpty&&this.headerEndSlot.isEmpty}"><slot name="${this.headerSlot.slotName}"></slot><slot name="${this.headerEndSlot.slotName}"></slot></div>`}<div class="n-dropdown-content ${this.isShowingSubmenu?"is-submenu-active":""}"><slot></slot></div></nord-popout></div>`}handleBlur(t){const e=t.relatedTarget;this.isNavigating||this.isShowingSubmenu||e&&(this.contains(e)||this.popout.hide(!1))}handleOpen(){this.open=!0}handleBackClick(t){t.preventDefault(),t.stopPropagation(),this.isNavigating=!0,this.navigateBack(),this.updateComplete.then((()=>{this.isNavigating=!1;const t=this.submenuStack[this.submenuStack.length-1],e=t?t.querySelector('[slot="trigger"]'):this.querySelector("nord-dropdown-item");null==e||e.focus()}))}handleClose(t){if(this.isNavigating)return;this.clearSubmenuStack();const e=t.target;"NORD-POPOUT"===(null==e?void 0:e.tagName)&&this.contains(e)||(this.open=!1)}handleOpenChange(){var t;if(this.open){const e=null!==(t=this.querySelector("[autofocus]"))&&void 0!==t?t:this.querySelector("nord-dropdown-item, nord-message");null==e||e.focus(),this.list.scrollTop=0}else this.isNavigating||this.clearSubmenuStack()}navigateBack(){if(0===this.submenuStack.length)return;const t=this.submenuStack[this.submenuStack.length-1];t.deactivateMobile(),t.requestUpdate();const e=this.submenuStack[this.submenuStack.length-2];e&&(e.removeAttribute("has-active-child"),e.requestUpdate()),this.submenuStack=this.submenuStack.slice(0,-1)}clearSubmenuStack(){for(const t of this.submenuStack)t.deactivateMobile(),t.removeAttribute("has-active-child");this.submenuStack=[]}handleSubmenuNavigate(t){const e=t;e.stopPropagation();const o=this.submenuStack[this.submenuStack.length-1];o&&(o.setAttribute("has-active-child",""),o.requestUpdate());const n=e.detail.submenu;this.submenuStack=[...this.submenuStack,n],this.updateComplete.then((()=>{n.requestUpdate()}))}hide(t){return this.popout.hide(t)}show(){return this.popout.show()}};m.styles=[u,h],m.shadowRootOptions={...n.shadowRootOptions,delegatesFocus:!0},t([s(".n-dropdown-content")],m.prototype,"list",void 0),t([s("nord-popout",!0)],m.prototype,"popout",void 0),t([i()],m.prototype,"submenuStack",void 0),t([r({reflect:!0,type:Boolean})],m.prototype,"expand",void 0),t([r({reflect:!0})],m.prototype,"size",void 0),t([r({reflect:!0,type:Boolean,attribute:"always-floating"})],m.prototype,"alwaysFloating",void 0),t([p("open","updated")],m.prototype,"handleOpenChange",null),m=t([a("nord-dropdown")],m);var g=m;export{g as default};
1
+ import{_ as t}from"./tslib.es6-CmLYFWVC.js";import{css as e,html as o,LitElement as n}from"lit";import{query as s,state as i,property as a,customElement as r}from"lit/decorators.js";import{ifDefined as d}from"lit/directives/if-defined.js";import{S as l}from"./SlotController-Z6eG7LSZ.js";import{o as p}from"./observe-D0n0zOfU.js";import{F as c}from"./Popout-vR6LxNS9.js";import{s as u}from"./Component-DSU3Qp0O.js";import"./Icon.js";import"./DropdownItem.js";import"./EventController-BBOmvfLa.js";import"./positioning-D-K8Mueq.js";import"./DirectionController-ChvNGESZ.js";import"./LightDismissController-4pH8cdko.js";import"./ShortcutController-BIb3WGzH.js";import"./tinykeys.module-_6MZt7MP.js";import"./ScrollbarController-BFC67Y2x.js";import"./events-Bv6wNHwJ.js";import"lit/directives/unsafe-html.js";import"./cond-CI1KbneT.js";import"./IconManager.js";import"lit/directives/ref.js";import"./FocusableMixin-BlQLNPdJ.js";import"./DropdownItem-tmJQrv7d.js";const h=e`:host{--_n-dropdown-size:var(--n-dropdown-size, 250px);--_n-dropdown-max-block-size:var(--n-dropdown-max-block-size, 460px)}.n-dropdown-content{padding:var(--n-space-s) 0;min-inline-size:var(--_n-dropdown-size);max-inline-size:calc(var(--_n-dropdown-size) * 1.5);max-block-size:var(--_n-dropdown-max-block-size);overflow-y:auto}@media (max-width:35.9375em){.n-dropdown-content{max-block-size:70vh;max-inline-size:none}.n-dropdown-header.is-navigation-header{padding:var(--n-space-s) 0}.n-dropdown-back-item{padding-inline-start:var(--n-space-s);padding-inline-end:var(--n-space-s);inline-size:100%}.n-dropdown-content.is-submenu-active ::slotted(nord-dropdown-group),.n-dropdown-content.is-submenu-active ::slotted(nord-dropdown-item),.n-dropdown-content.is-submenu-active ::slotted(nord-dropdown-submenu:not([mobile-active])){display:none}}::slotted(nord-dropdown-group),::slotted(nord-dropdown-item){padding-inline-start:var(--n-space-s);padding-inline-end:var(--n-space-s)}::slotted(nord-dropdown-group){padding-block-end:var(--n-space-s);border-block-end:1px solid var(--n-color-border);margin-block-end:var(--n-space-s)}::slotted(nord-dropdown-group:last-child){padding-block-end:0;border-block-end:0;margin-block-end:0}::slotted(nord-message:first-of-type){padding-block-start:0}::slotted(nord-message:last-of-type){margin-block-end:var(--n-space-s)}slot[name=toggle]{display:inline-block}:host([expand]) slot[name=toggle]{inline-size:100%}:host([size='s']){--_n-dropdown-size:var(--n-dropdown-size, 150px)}:host([size='l']){--_n-dropdown-size:var(--n-dropdown-size, 300px)}.n-dropdown-header{padding:calc(var(--n-space-m) + 2px) var(--n-space-m);border-block-end:1px solid var(--n-color-border);background-color:var(--n-color-surface-raised);border-start-start-radius:var(--n-border-radius);border-start-end-radius:var(--n-border-radius);font-weight:var(--n-font-weight);display:flex;gap:var(--n-space-s);align-items:center;flex-wrap:wrap}.n-dropdown-header ::slotted(nord-button){--n-button-gap:var(--n-space-xs);--n-button-background-color:var(--n-color-surface)}.n-dropdown-header ::slotted(nord-button:hover){--n-button-background-color:var(--n-color-button-hover)}::slotted([slot=header-end]){margin-inline-start:auto;gap:var(--n-space-s);display:flex;align-items:center;flex-wrap:wrap}::slotted(:is(h1, h2, h3, h4, h5, h6, p)){margin:0!important}`;let m=class extends(c(n)){constructor(){super(...arguments),this.headerSlot=new l(this,"header"),this.headerEndSlot=new l(this,"header-end"),this.submenuStack=[],this.isNavigating=!1,this.expand=!1,this.size="m",this.alwaysFloating=!1}get isShowingSubmenu(){return this.submenuStack.length>0}get submenuStackRef(){return this.submenuStack}get deepestSubmenu(){return this.submenuStack[this.submenuStack.length-1]}handleAlwaysFloatingChange(){this.open&&(this.open=!1,this.updateComplete.then((()=>{this.open=!0})))}connectedCallback(){super.connectedCallback();const t=this.querySelector('[slot="toggle"]');null==t||t.setAttribute("aria-haspopup","true")}render(){var t;const e=this.submenuStack[this.submenuStack.length-1];return o`<div class="n-dropdown" @nord-submenu-navigate="${this.handleSubmenuNavigate}" @focusout="${this.handleBlur}"><slot name="toggle" aria-controls="popout"></slot><nord-popout id="popout" align="${d(this.align)}" position="${d(this.position)}" ?open="${this.open}" ?always-floating="${this.alwaysFloating}" @open="${this.handleOpen}" @close="${this.handleClose}">${this.isShowingSubmenu?o`<div class="n-dropdown-header is-navigation-header"><nord-dropdown-item @click="${this.handleBackClick}" class="n-dropdown-back-item"><nord-icon slot="start" name="arrow-left" size="s"></nord-icon>${null!==(t=null==e?void 0:e.label)&&void 0!==t?t:""}</nord-dropdown-item></div>`:o`<div class="n-dropdown-header" ?hidden="${this.headerSlot.isEmpty&&this.headerEndSlot.isEmpty}"><slot name="${this.headerSlot.slotName}"></slot><slot name="${this.headerEndSlot.slotName}"></slot></div>`}<div class="n-dropdown-content ${this.isShowingSubmenu?"is-submenu-active":""}"><slot></slot></div></nord-popout></div>`}handleBlur(t){const e=t.relatedTarget;this.isNavigating||this.isShowingSubmenu||e&&(this.contains(e)||this.popout.hide(!1))}handleOpen(){this.open=!0}handleBackClick(t){t.preventDefault(),t.stopPropagation(),this.isNavigating=!0,this.navigateBack(),this.updateComplete.then((()=>{this.isNavigating=!1;const t=this.submenuStack[this.submenuStack.length-1],e=t?t.querySelector('[slot="trigger"]'):this.querySelector("nord-dropdown-item");null==e||e.focus()}))}handleClose(t){if(this.isNavigating)return;this.clearSubmenuStack();const e=t.target;"NORD-POPOUT"===(null==e?void 0:e.tagName)&&this.contains(e)||(this.open=!1)}handleOpenChange(){var t;if(this.open){const e=null!==(t=this.querySelector("[autofocus]"))&&void 0!==t?t:this.querySelector("nord-dropdown-item, nord-message");null==e||e.focus(),this.list.scrollTop=0}else this.isNavigating||this.clearSubmenuStack()}navigateBack(){if(0===this.submenuStack.length)return;const t=this.submenuStack[this.submenuStack.length-1];t.deactivateMobile(),t.requestUpdate();const e=this.submenuStack[this.submenuStack.length-2];e&&(e.removeAttribute("has-active-child"),e.requestUpdate()),this.submenuStack=this.submenuStack.slice(0,-1)}clearSubmenuStack(){for(const t of this.submenuStack)t.deactivateMobile(),t.removeAttribute("has-active-child");this.submenuStack=[]}handleSubmenuNavigate(t){const e=t;e.stopPropagation();const o=this.submenuStack[this.submenuStack.length-1];o&&(o.setAttribute("has-active-child",""),o.requestUpdate());const n=e.detail.submenu;this.submenuStack=[...this.submenuStack,n],this.updateComplete.then((()=>{n.requestUpdate()}))}hide(t){return this.popout.hide(t)}show(){return this.popout.show()}};m.styles=[u,h],m.shadowRootOptions={...n.shadowRootOptions,delegatesFocus:!0},t([s(".n-dropdown-content")],m.prototype,"list",void 0),t([s("nord-popout",!0)],m.prototype,"popout",void 0),t([i()],m.prototype,"submenuStack",void 0),t([a({reflect:!0,type:Boolean})],m.prototype,"expand",void 0),t([a({reflect:!0})],m.prototype,"size",void 0),t([a({reflect:!0,type:Boolean,attribute:"always-floating"})],m.prototype,"alwaysFloating",void 0),t([p("alwaysFloating")],m.prototype,"handleAlwaysFloatingChange",null),t([p("open","updated")],m.prototype,"handleOpenChange",null),m=t([r("nord-dropdown")],m);var g=m;export{g as default};
2
2
  //# sourceMappingURL=Dropdown.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Dropdown.js","sources":["../src/dropdown/Dropdown.ts"],"sourcesContent":["import type DropdownSubmenu from '../dropdown-submenu/DropdownSubmenu.js'\nimport type Popout from '../popout/Popout.js'\nimport { html, LitElement } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { SlotController } from '../common/controllers/SlotController.js'\nimport { observe } from '../common/decorators/observe.js'\n\nimport { FloatingMixin } from '../common/mixins/FloatingComponentMixin.js'\nimport componentStyle from '../common/styles/Component.css'\n\nimport style from './Dropdown.css'\nimport '../popout/Popout.js'\nimport '../icon/Icon.js'\nimport '../dropdown-item/DropdownItem.js'\n\n/**\n * Dropdown menu displays a list of actions or selectable options for\n * a user. Dropdown uses popout component internally to create\n * the overlay functionality.\n *\n * @status ready\n * @category action\n *\n * @slot - The dropdown content.\n * @slot toggle - Used to place the toggle for dropdown.\n * @slot header - Optional slot that holds a header for the dropdown.\n * @slot header-end - Optional slot that positions content at the end of the header. Useful for actions or additional info.\n *\n * @fires {NordEvent} open - Dispatched when the popout is opened.\n * @fires {NordEvent} close - Dispatched when the popout is closed.\n *\n * @cssprop [--n-dropdown-size=250px] - Controls the inline size, or width, of the dropdown. Will resize up to 1.5 times to account for larger content.\n * @cssprop [--n-dropdown-max-block-size=460px] - Controls the maximum block size, or height, of the dropdown. Larger content will get a scrollbar.\n */\n@customElement('nord-dropdown')\nexport default class Dropdown extends FloatingMixin(LitElement) {\n static styles = [componentStyle, style]\n\n /**\n * we delegate focus, to ensure focus does not move to body if you click\n * some whitespace or a dropdown-group heading, as this would close the dropdown\n * @internal\n */\n static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true }\n\n private headerSlot = new SlotController(this, 'header')\n private headerEndSlot = new SlotController(this, 'header-end')\n\n @query('.n-dropdown-content') private list!: HTMLElement\n @query('nord-popout', true) private popout!: Popout\n\n @state() private submenuStack: DropdownSubmenu[] = []\n private isNavigating = false\n\n private get isShowingSubmenu(): boolean {\n return this.submenuStack.length > 0\n }\n\n /**\n * @internal\n */\n get submenuStackRef(): readonly DropdownSubmenu[] {\n return this.submenuStack\n }\n\n /**\n * @internal\n */\n get deepestSubmenu(): DropdownSubmenu | undefined {\n return this.submenuStack[this.submenuStack.length - 1]\n }\n\n /**\n * Controls whether the toggle slot expands to fill the width of its container.\n */\n @property({ reflect: true, type: Boolean }) expand = false\n\n /**\n * The size of the dropdown. This affects the minimum and maximum inline-size\n * of the dropdown.\n */\n @property({ reflect: true }) size: 's' | 'm' | 'l' = 'm'\n\n /**\n * Set to true to always display the dropdown as a floating overlay, even on smaller viewports.\n */\n @property({ reflect: true, type: Boolean, attribute: 'always-floating' })\n alwaysFloating: boolean = false\n\n connectedCallback() {\n super.connectedCallback()\n\n const toggle = this.querySelector(`[slot=\"toggle\"]`)\n toggle?.setAttribute('aria-haspopup', 'true')\n }\n\n render() {\n const activeSubmenu = this.submenuStack[this.submenuStack.length - 1]\n\n return html`\n <div class=\"n-dropdown\" @nord-submenu-navigate=${this.handleSubmenuNavigate} @focusout=${this.handleBlur}>\n <slot name=\"toggle\" aria-controls=\"popout\"></slot>\n <nord-popout\n id=\"popout\"\n align=${ifDefined(this.align)}\n position=${ifDefined(this.position)}\n ?open=${this.open}\n ?always-floating=${this.alwaysFloating}\n @open=${this.handleOpen}\n @close=${this.handleClose}\n >\n ${\n this.isShowingSubmenu\n ? html`\n <div class=\"n-dropdown-header is-navigation-header\">\n <nord-dropdown-item @click=${this.handleBackClick} class=\"n-dropdown-back-item\">\n <nord-icon slot=\"start\" name=\"arrow-left\" size=\"s\"></nord-icon>\n ${activeSubmenu?.label ?? ''}\n </nord-dropdown-item>\n </div>\n `\n : html`\n <div class=\"n-dropdown-header\" ?hidden=${this.headerSlot.isEmpty && this.headerEndSlot.isEmpty}>\n <slot name=${this.headerSlot.slotName}></slot>\n <slot name=${this.headerEndSlot.slotName}></slot>\n </div>\n `\n }\n <div class=\"n-dropdown-content ${this.isShowingSubmenu ? 'is-submenu-active' : ''}\">\n <slot></slot>\n </div>\n </nord-popout>\n </div>\n `\n }\n\n private handleBlur(e: FocusEvent) {\n const relatedTarget = e.relatedTarget as HTMLElement\n\n // Don't close during navigation or if we're still showing a submenu\n // (the blur event fires after back button is removed from DOM, but we're still in submenu mode)\n if (this.isNavigating || this.isShowingSubmenu)\n return\n\n // Safari will set relatedTarget to null when clicking on the trigger button\n // because it doesn't focus buttons on click.\n // this caused weird behavior where the dropdown closed _and_ opened with a single click.\n // so we only run this logic if relatedTarget is set, which sidesteps this issue\n if (!relatedTarget) {\n return\n }\n\n // Close dropdown if focus moved outside\n if (!this.contains(relatedTarget)) {\n this.popout.hide(false)\n }\n }\n\n private handleOpen() {\n this.open = true\n }\n\n private handleBackClick(event: MouseEvent) {\n event.preventDefault()\n event.stopPropagation()\n\n this.isNavigating = true\n this.navigateBack()\n\n // Reset navigation flag after updates complete\n this.updateComplete.then(() => {\n this.isNavigating = false\n // Focus the trigger of the submenu we're returning to, or the first item\n const newTop = this.submenuStack[this.submenuStack.length - 1]\n const focusTarget = newTop\n ? newTop.querySelector<HTMLElement>('[slot=\"trigger\"]')\n : this.querySelector<HTMLElement>('nord-dropdown-item')\n focusTarget?.focus()\n })\n }\n\n private handleClose(e: Event) {\n // Don't close during navigation\n if (this.isNavigating)\n return\n\n // Clear submenu stack on close\n this.clearSubmenuStack()\n\n // Ignore close events from child popouts (submenus)\n // The event target will be a nord-popout element that is a child of this dropdown\n const eventTarget = e.target as HTMLElement\n const isChildPopout = eventTarget?.tagName === 'NORD-POPOUT' && this.contains(eventTarget)\n\n if (isChildPopout) {\n return\n }\n\n this.open = false\n }\n\n @observe('open', 'updated')\n protected handleOpenChange() {\n if (this.open) {\n const focusTarget\n = this.querySelector<HTMLElement>('[autofocus]')\n ?? this.querySelector<HTMLElement>('nord-dropdown-item, nord-message')\n\n focusTarget?.focus()\n this.list.scrollTop = 0\n }\n else if (!this.isNavigating) {\n // Clear submenu stack when dropdown closes (but not during navigation)\n this.clearSubmenuStack()\n }\n }\n\n /**\n * Navigate back one level in the submenu stack.\n * @internal\n */\n navigateBack() {\n if (this.submenuStack.length === 0)\n return\n\n const topSubmenu = this.submenuStack[this.submenuStack.length - 1]\n topSubmenu.deactivateMobile()\n // Trigger re-render so it loses active and is-deepest-active classes\n topSubmenu.requestUpdate()\n\n const newTop = this.submenuStack[this.submenuStack.length - 2]\n if (newTop) {\n newTop.removeAttribute('has-active-child')\n // Trigger re-render so it gains is-deepest-active class back\n newTop.requestUpdate()\n }\n\n this.submenuStack = this.submenuStack.slice(0, -1)\n }\n\n /**\n * Clear the entire submenu stack.\n * @internal\n */\n private clearSubmenuStack() {\n for (const submenu of this.submenuStack) {\n submenu.deactivateMobile()\n submenu.removeAttribute('has-active-child')\n }\n this.submenuStack = []\n }\n\n /**\n * Handle submenu navigation event.\n * @internal\n */\n private handleSubmenuNavigate(event: Event) {\n const customEvent = event as CustomEvent<{ submenu: DropdownSubmenu }>\n customEvent.stopPropagation()\n\n const previousDeepest = this.submenuStack[this.submenuStack.length - 1]\n if (previousDeepest) {\n previousDeepest.setAttribute('has-active-child', '')\n // Trigger re-render so it loses is-deepest-active class\n previousDeepest.requestUpdate()\n }\n\n const newSubmenu = customEvent.detail.submenu\n this.submenuStack = [...this.submenuStack, newSubmenu]\n\n // Trigger re-render of new deepest so it gains is-deepest-active class\n this.updateComplete.then(() => {\n newSubmenu.requestUpdate()\n })\n }\n\n /**\n * Hide the dropdown programmatically.\n * This method delegates to the Dropdown's internal Popout component.\n * See [Popout's hide() method](/components/popout#methods-hide) for more details.\n * @param moveFocusToButton A boolean option to move the focus to the original button that opens the dropdown.\n */\n hide(moveFocusToButton?: boolean): Promise<TransitionEvent | void> {\n return this.popout.hide(moveFocusToButton)\n }\n\n /**\n * Show the dropdown programmatically.\n * This method delegates to the Dropdown's internal Popout component.\n * See [Popout's show() method](/components/popout#methods-hide) for more details.\n */\n show(): Promise<TransitionEvent | void> {\n return this.popout.show()\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-dropdown': Dropdown\n }\n}\n"],"names":["Dropdown","FloatingMixin","LitElement","constructor","this","headerSlot","SlotController","headerEndSlot","submenuStack","isNavigating","expand","size","alwaysFloating","isShowingSubmenu","length","submenuStackRef","deepestSubmenu","connectedCallback","super","toggle","querySelector","setAttribute","render","activeSubmenu","html","handleSubmenuNavigate","handleBlur","ifDefined","align","position","open","handleOpen","handleClose","handleBackClick","_a","label","isEmpty","slotName","e","relatedTarget","contains","popout","hide","event","preventDefault","stopPropagation","navigateBack","updateComplete","then","newTop","focusTarget","focus","clearSubmenuStack","eventTarget","target","tagName","handleOpenChange","list","scrollTop","topSubmenu","deactivateMobile","requestUpdate","removeAttribute","slice","submenu","customEvent","previousDeepest","newSubmenu","detail","moveFocusToButton","show","styles","componentStyle","style","shadowRootOptions","delegatesFocus","__decorate","query","prototype","state","property","reflect","type","Boolean","attribute","observe","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"Dropdown.js","sources":["../src/dropdown/Dropdown.ts"],"sourcesContent":["import type DropdownSubmenu from '../dropdown-submenu/DropdownSubmenu.js'\nimport type Popout from '../popout/Popout.js'\nimport { html, LitElement } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { SlotController } from '../common/controllers/SlotController.js'\nimport { observe } from '../common/decorators/observe.js'\n\nimport { FloatingMixin } from '../common/mixins/FloatingComponentMixin.js'\nimport componentStyle from '../common/styles/Component.css'\n\nimport style from './Dropdown.css'\nimport '../popout/Popout.js'\nimport '../icon/Icon.js'\nimport '../dropdown-item/DropdownItem.js'\n\n/**\n * Dropdown menu displays a list of actions or selectable options for\n * a user. Dropdown uses popout component internally to create\n * the overlay functionality.\n *\n * @status ready\n * @category action\n *\n * @slot - The dropdown content.\n * @slot toggle - Used to place the toggle for dropdown.\n * @slot header - Optional slot that holds a header for the dropdown.\n * @slot header-end - Optional slot that positions content at the end of the header. Useful for actions or additional info.\n *\n * @fires {NordEvent} open - Dispatched when the popout is opened.\n * @fires {NordEvent} close - Dispatched when the popout is closed.\n *\n * @cssprop [--n-dropdown-size=250px] - Controls the inline size, or width, of the dropdown. Will resize up to 1.5 times to account for larger content.\n * @cssprop [--n-dropdown-max-block-size=460px] - Controls the maximum block size, or height, of the dropdown. Larger content will get a scrollbar.\n */\n@customElement('nord-dropdown')\nexport default class Dropdown extends FloatingMixin(LitElement) {\n static styles = [componentStyle, style]\n\n /**\n * we delegate focus, to ensure focus does not move to body if you click\n * some whitespace or a dropdown-group heading, as this would close the dropdown\n * @internal\n */\n static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true }\n\n private headerSlot = new SlotController(this, 'header')\n private headerEndSlot = new SlotController(this, 'header-end')\n\n @query('.n-dropdown-content') private list!: HTMLElement\n @query('nord-popout', true) private popout!: Popout\n\n @state() private submenuStack: DropdownSubmenu[] = []\n private isNavigating = false\n\n private get isShowingSubmenu(): boolean {\n return this.submenuStack.length > 0\n }\n\n /**\n * @internal\n */\n get submenuStackRef(): readonly DropdownSubmenu[] {\n return this.submenuStack\n }\n\n /**\n * @internal\n */\n get deepestSubmenu(): DropdownSubmenu | undefined {\n return this.submenuStack[this.submenuStack.length - 1]\n }\n\n /**\n * Controls whether the toggle slot expands to fill the width of its container.\n */\n @property({ reflect: true, type: Boolean }) expand = false\n\n /**\n * The size of the dropdown. This affects the minimum and maximum inline-size\n * of the dropdown.\n */\n @property({ reflect: true }) size: 's' | 'm' | 'l' = 'm'\n\n /**\n * Set to true to always display the dropdown as a floating overlay, even on smaller viewports.\n */\n @property({ reflect: true, type: Boolean, attribute: 'always-floating' })\n alwaysFloating: boolean = false\n\n @observe('alwaysFloating')\n protected handleAlwaysFloatingChange() {\n if (this.open) {\n this.open = false\n this.updateComplete.then(() => {\n this.open = true\n })\n }\n }\n\n connectedCallback() {\n super.connectedCallback()\n\n const toggle = this.querySelector(`[slot=\"toggle\"]`)\n toggle?.setAttribute('aria-haspopup', 'true')\n }\n\n render() {\n const activeSubmenu = this.submenuStack[this.submenuStack.length - 1]\n\n return html`\n <div class=\"n-dropdown\" @nord-submenu-navigate=${this.handleSubmenuNavigate} @focusout=${this.handleBlur}>\n <slot name=\"toggle\" aria-controls=\"popout\"></slot>\n <nord-popout\n id=\"popout\"\n align=${ifDefined(this.align)}\n position=${ifDefined(this.position)}\n ?open=${this.open}\n ?always-floating=${this.alwaysFloating}\n @open=${this.handleOpen}\n @close=${this.handleClose}\n >\n ${\n this.isShowingSubmenu\n ? html`\n <div class=\"n-dropdown-header is-navigation-header\">\n <nord-dropdown-item @click=${this.handleBackClick} class=\"n-dropdown-back-item\">\n <nord-icon slot=\"start\" name=\"arrow-left\" size=\"s\"></nord-icon>\n ${activeSubmenu?.label ?? ''}\n </nord-dropdown-item>\n </div>\n `\n : html`\n <div class=\"n-dropdown-header\" ?hidden=${this.headerSlot.isEmpty && this.headerEndSlot.isEmpty}>\n <slot name=${this.headerSlot.slotName}></slot>\n <slot name=${this.headerEndSlot.slotName}></slot>\n </div>\n `\n }\n <div class=\"n-dropdown-content ${this.isShowingSubmenu ? 'is-submenu-active' : ''}\">\n <slot></slot>\n </div>\n </nord-popout>\n </div>\n `\n }\n\n private handleBlur(e: FocusEvent) {\n const relatedTarget = e.relatedTarget as HTMLElement\n\n // Don't close during navigation or if we're still showing a submenu\n // (the blur event fires after back button is removed from DOM, but we're still in submenu mode)\n if (this.isNavigating || this.isShowingSubmenu)\n return\n\n // Safari will set relatedTarget to null when clicking on the trigger button\n // because it doesn't focus buttons on click.\n // this caused weird behavior where the dropdown closed _and_ opened with a single click.\n // so we only run this logic if relatedTarget is set, which sidesteps this issue\n if (!relatedTarget) {\n return\n }\n\n // Close dropdown if focus moved outside\n if (!this.contains(relatedTarget)) {\n this.popout.hide(false)\n }\n }\n\n private handleOpen() {\n this.open = true\n }\n\n private handleBackClick(event: MouseEvent) {\n event.preventDefault()\n event.stopPropagation()\n\n this.isNavigating = true\n this.navigateBack()\n\n // Reset navigation flag after updates complete\n this.updateComplete.then(() => {\n this.isNavigating = false\n // Focus the trigger of the submenu we're returning to, or the first item\n const newTop = this.submenuStack[this.submenuStack.length - 1]\n const focusTarget = newTop\n ? newTop.querySelector<HTMLElement>('[slot=\"trigger\"]')\n : this.querySelector<HTMLElement>('nord-dropdown-item')\n focusTarget?.focus()\n })\n }\n\n private handleClose(e: Event) {\n // Don't close during navigation\n if (this.isNavigating)\n return\n\n // Clear submenu stack on close\n this.clearSubmenuStack()\n\n // Ignore close events from child popouts (submenus)\n // The event target will be a nord-popout element that is a child of this dropdown\n const eventTarget = e.target as HTMLElement\n const isChildPopout = eventTarget?.tagName === 'NORD-POPOUT' && this.contains(eventTarget)\n\n if (isChildPopout) {\n return\n }\n\n this.open = false\n }\n\n @observe('open', 'updated')\n protected handleOpenChange() {\n if (this.open) {\n const focusTarget\n = this.querySelector<HTMLElement>('[autofocus]')\n ?? this.querySelector<HTMLElement>('nord-dropdown-item, nord-message')\n\n focusTarget?.focus()\n this.list.scrollTop = 0\n }\n else if (!this.isNavigating) {\n // Clear submenu stack when dropdown closes (but not during navigation)\n this.clearSubmenuStack()\n }\n }\n\n /**\n * Navigate back one level in the submenu stack.\n * @internal\n */\n navigateBack() {\n if (this.submenuStack.length === 0)\n return\n\n const topSubmenu = this.submenuStack[this.submenuStack.length - 1]\n topSubmenu.deactivateMobile()\n // Trigger re-render so it loses active and is-deepest-active classes\n topSubmenu.requestUpdate()\n\n const newTop = this.submenuStack[this.submenuStack.length - 2]\n if (newTop) {\n newTop.removeAttribute('has-active-child')\n // Trigger re-render so it gains is-deepest-active class back\n newTop.requestUpdate()\n }\n\n this.submenuStack = this.submenuStack.slice(0, -1)\n }\n\n /**\n * Clear the entire submenu stack.\n * @internal\n */\n private clearSubmenuStack() {\n for (const submenu of this.submenuStack) {\n submenu.deactivateMobile()\n submenu.removeAttribute('has-active-child')\n }\n this.submenuStack = []\n }\n\n /**\n * Handle submenu navigation event.\n * @internal\n */\n private handleSubmenuNavigate(event: Event) {\n const customEvent = event as CustomEvent<{ submenu: DropdownSubmenu }>\n customEvent.stopPropagation()\n\n const previousDeepest = this.submenuStack[this.submenuStack.length - 1]\n if (previousDeepest) {\n previousDeepest.setAttribute('has-active-child', '')\n // Trigger re-render so it loses is-deepest-active class\n previousDeepest.requestUpdate()\n }\n\n const newSubmenu = customEvent.detail.submenu\n this.submenuStack = [...this.submenuStack, newSubmenu]\n\n // Trigger re-render of new deepest so it gains is-deepest-active class\n this.updateComplete.then(() => {\n newSubmenu.requestUpdate()\n })\n }\n\n /**\n * Hide the dropdown programmatically.\n * This method delegates to the Dropdown's internal Popout component.\n * See [Popout's hide() method](/components/popout#methods-hide) for more details.\n * @param moveFocusToButton A boolean option to move the focus to the original button that opens the dropdown.\n */\n hide(moveFocusToButton?: boolean): Promise<TransitionEvent | void> {\n return this.popout.hide(moveFocusToButton)\n }\n\n /**\n * Show the dropdown programmatically.\n * This method delegates to the Dropdown's internal Popout component.\n * See [Popout's show() method](/components/popout#methods-hide) for more details.\n */\n show(): Promise<TransitionEvent | void> {\n return this.popout.show()\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-dropdown': Dropdown\n }\n}\n"],"names":["Dropdown","FloatingMixin","LitElement","constructor","this","headerSlot","SlotController","headerEndSlot","submenuStack","isNavigating","expand","size","alwaysFloating","isShowingSubmenu","length","submenuStackRef","deepestSubmenu","handleAlwaysFloatingChange","open","updateComplete","then","connectedCallback","super","toggle","querySelector","setAttribute","render","activeSubmenu","html","handleSubmenuNavigate","handleBlur","ifDefined","align","position","handleOpen","handleClose","handleBackClick","_a","label","isEmpty","slotName","e","relatedTarget","contains","popout","hide","event","preventDefault","stopPropagation","navigateBack","newTop","focusTarget","focus","clearSubmenuStack","eventTarget","target","tagName","handleOpenChange","list","scrollTop","topSubmenu","deactivateMobile","requestUpdate","removeAttribute","slice","submenu","customEvent","previousDeepest","newSubmenu","detail","moveFocusToButton","show","styles","componentStyle","style","shadowRootOptions","delegatesFocus","__decorate","query","prototype","state","property","reflect","type","Boolean","attribute","observe","customElement"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{_ as e}from"./tslib.es6-CmLYFWVC.js";import{css as t,LitElement as o,html as n}from"lit";import{query as i,property as s,state as r,customElement as l}from"lit/decorators.js";import{classMap as d}from"lit/directives/class-map.js";import{E as a}from"./EventController-BBOmvfLa.js";import{s as u}from"./Component-DSU3Qp0O.js";import"./Popout-vR6LxNS9.js";import"./positioning-D-K8Mueq.js";import"./DirectionController-ChvNGESZ.js";import"./LightDismissController-4pH8cdko.js";import"./ShortcutController-BIb3WGzH.js";import"./tinykeys.module-_6MZt7MP.js";import"./ScrollbarController-BFC67Y2x.js";import"./observe-D0n0zOfU.js";import"./events-Bv6wNHwJ.js";const p=t`:host{display:block;--_n-submenu-focus-padding:2px}.n-dropdown-submenu-content{padding-block-start:var(--_n-submenu-content-padding-block,var(--n-space-s));padding-block-end:var(--_n-submenu-content-padding-block,var(--n-space-s));min-inline-size:var(--_n-dropdown-size);max-inline-size:calc(var(--_n-dropdown-size) * 1.5);max-block-size:var(--_n-dropdown-max-block-size);overflow-y:auto}:host([mobile-active]){--_n-submenu-content-padding-block:0}@media (max-width:35.9375em){.n-dropdown-submenu-content{max-block-size:70vh;max-inline-size:none}.n-dropdown-submenu-content.is-deepest-active{padding-block-start:var(--_n-submenu-focus-padding);padding-block-end:var(--_n-submenu-focus-padding)}:host([mobile-active]) ::slotted([slot=trigger]){display:none}:host([mobile-active][has-active-child]) ::slotted(nord-dropdown-group),:host([mobile-active][has-active-child]) ::slotted(nord-dropdown-item),:host([mobile-active][has-active-child]) ::slotted(nord-dropdown-submenu:not([mobile-active])){display:none}}::slotted(nord-dropdown-item){padding-inline-start:var(--n-space-s);padding-inline-end:var(--n-space-s)}::slotted(nord-dropdown-group){padding-inline-start:var(--n-space-s);padding-inline-end:var(--n-space-s);padding-block-end:var(--n-space-s);border-block-end:1px solid var(--n-color-border);margin-block-end:var(--n-space-s)}::slotted(nord-dropdown-group:last-child){padding-block-end:0;border-block-end:0;margin-block-end:0}`;let h=0,c=class extends o{constructor(){super(...arguments),this.mobileActive=!1,this.popoutId="nord-dropdown-submenu-popout-"+ ++h,this.events=new a(this),this.currentTriggerElement=null,this.popoutOpen=!1,this.mobileMediaQuery=window.matchMedia("(max-width: 35.9375em)"),this.isSmallScreen=this.mobileMediaQuery.matches,this.parentDropdownAlwaysFloating=!1,this.handleTriggerMouseEnter=()=>{var e;this.shouldUseMobileStack||(this.closeOtherSubmenus(),null===(e=this.popout)||void 0===e||e.show())},this.handleTriggerClick=e=>{var t;e.preventDefault(),e.stopImmediatePropagation(),this.shouldUseMobileStack?this.navigateIntoSubmenu():(this.closeOtherSubmenus(),null===(t=this.popout)||void 0===t||t.show())},this.handleTriggerKeydown=e=>{var t;if("ArrowRight"===e.key||"Enter"===e.key){if(e.preventDefault(),this.shouldUseMobileStack)return void this.navigateIntoSubmenu();this.closeOtherSubmenus(),null===(t=this.popout)||void 0===t||t.show(),this.updateComplete.then((()=>{var e;null===(e=this.querySelector("nord-dropdown-item"))||void 0===e||e.focus()}))}},this.handleContentKeydown=e=>{var t,o;if("ArrowLeft"===e.key){if(e.preventDefault(),e.stopPropagation(),this.shouldUseMobileStack&&this.mobileActive)return void(null===(t=this.closest("nord-dropdown"))||void 0===t||t.navigateBack());null===(o=this.popout)||void 0===o||o.hide(!0)}},this.handlePopoutOpen=()=>{this.popoutOpen=!0,this.closeOtherSubmenus()},this.handlePopoutClose=e=>{e.stopPropagation(),this.popoutOpen=!1},this.handleParentDropdownMouseOver=e=>{var t;if(this.shouldUseMobileStack)return;const o=e.target;"NORD-DROPDOWN-ITEM"===o.tagName&&!this.contains(o)&&this.popoutOpen&&(e.stopImmediatePropagation(),null===(t=this.popout)||void 0===t||t.hide())}}get shouldUseMobileStack(){return this.isSmallScreen&&!this.parentDropdownAlwaysFloating}get parentDropdown(){return this.closest("nord-dropdown")}get isInSubmenuStack(){const e=this.parentDropdown;return!!e&&e.submenuStackRef.includes(this)}get isDeepestInStack(){const e=this.parentDropdown;return!!e&&e.deepestSubmenu===this}connectedCallback(){super.connectedCallback();const e=this.querySelector('[slot="trigger"]');null==e||e.setAttribute("aria-haspopup","menu");const t=this.closest("nord-dropdown");t&&(this.parentDropdownAlwaysFloating=t.alwaysFloating,this.events.listen(t,"mouseover",this.handleParentDropdownMouseOver)),this.events.listen(this.mobileMediaQuery,"change",(e=>{this.isSmallScreen=e.matches,this.requestUpdate()}))}render(){return this.shouldUseMobileStack&&this.mobileActive?n`<slot name="trigger"></slot><div class="${d({"n-dropdown-submenu-content":!0,active:this.isInSubmenuStack,"is-deepest-active":this.isDeepestInStack})}" @keydown="${this.handleContentKeydown}"><slot></slot></div>`:n`<slot name="trigger" aria-controls="${this.popoutId}" @slotchange="${this.handleTriggerSlotChange}"></slot><nord-popout id="${this.popoutId}" position="inline-end" always-floating @open="${this.handlePopoutOpen}" @close="${this.handlePopoutClose}"><div class="n-dropdown-submenu-content" @keydown="${this.handleContentKeydown}"><slot></slot></div></nord-popout>`}handleTriggerSlotChange(){var e;const t=null===(e=this.shadowRoot)||void 0===e?void 0:e.querySelector('slot[name="trigger"]'),o=null==t?void 0:t.assignedElements()[0];if(this.currentTriggerElement&&this.currentTriggerElement!==o&&(this.currentTriggerElement.removeEventListener("mouseenter",this.handleTriggerMouseEnter),this.currentTriggerElement.removeEventListener("click",this.handleTriggerClick),this.currentTriggerElement.removeEventListener("keydown",this.handleTriggerKeydown)),this.currentTriggerElement=null!=o?o:null,!o)return;o.setAttribute("aria-haspopup","menu");const n=!window.matchMedia("(hover: hover)").matches;this.events.listen(o,"mouseenter",this.handleTriggerMouseEnter),n&&!this.isSmallScreen||this.events.listen(o,"click",this.handleTriggerClick),this.events.listen(o,"keydown",this.handleTriggerKeydown)}closeOtherSubmenus(){var e;if(this.shouldUseMobileStack)return;const t=null===(e=this.parentElement)||void 0===e?void 0:e.closest("nord-dropdown, nord-dropdown-submenu");t&&Array.from(t.querySelectorAll(":scope > nord-dropdown-submenu")).forEach((e=>{e!==this&&e.close()}))}deactivateMobile(){var e;this.mobileActive=!1;const t=null===(e=this.shadowRoot)||void 0===e?void 0:e.querySelector('slot[name="trigger"]'),o=null==t?void 0:t.assignedElements()[0];null==o||o.removeAttribute("aria-expanded")}get label(){var e,t,o,n;const i=null===(e=this.shadowRoot)||void 0===e?void 0:e.querySelector('slot[name="trigger"]');return null!==(n=null===(o=null===(t=null==i?void 0:i.assignedElements()[0])||void 0===t?void 0:t.textContent)||void 0===o?void 0:o.trim())&&void 0!==n?n:""}close(){return this.mobileActive?(this.deactivateMobile(),Promise.resolve()):this.popout?this.popout.hide():Promise.reject(new Error("DropdownSubmenu: popout component not found or not ready"))}navigateIntoSubmenu(){this.mobileActive=!0,this.dispatchEvent(new CustomEvent("nord-submenu-navigate",{bubbles:!0,detail:{submenu:this}})),this.updateComplete.then((()=>{const e=this.querySelector(".n-dropdown-submenu-content"),t=null==e?void 0:e.querySelector("nord-dropdown-item");null==t||t.focus()}))}};c.styles=[u,p],e([i("nord-popout")],c.prototype,"popout",void 0),e([s({reflect:!0,type:Boolean,attribute:"mobile-active"})],c.prototype,"mobileActive",void 0),e([r()],c.prototype,"isSmallScreen",void 0),c=e([l("nord-dropdown-submenu")],c);var m=c;export{m as default};
1
+ import{_ as e}from"./tslib.es6-CmLYFWVC.js";import{css as t,LitElement as o,html as n}from"lit";import{query as i,state as s,customElement as r}from"lit/decorators.js";import{classMap as l}from"lit/directives/class-map.js";import{E as a}from"./EventController-BBOmvfLa.js";import{s as d}from"./Component-DSU3Qp0O.js";import"./Popout-vR6LxNS9.js";import"./positioning-D-K8Mueq.js";import"./DirectionController-ChvNGESZ.js";import"./LightDismissController-4pH8cdko.js";import"./ShortcutController-BIb3WGzH.js";import"./tinykeys.module-_6MZt7MP.js";import"./ScrollbarController-BFC67Y2x.js";import"./observe-D0n0zOfU.js";import"./events-Bv6wNHwJ.js";const u=t`:host{display:block;--_n-submenu-focus-padding:2px}.n-dropdown-submenu-content{padding-block-start:var(--_n-submenu-content-padding-block,var(--n-space-s));padding-block-end:var(--_n-submenu-content-padding-block,var(--n-space-s));min-inline-size:var(--_n-dropdown-size);max-inline-size:calc(var(--_n-dropdown-size) * 1.5);max-block-size:var(--_n-dropdown-max-block-size);overflow-y:auto}:host([mobile-active]){--_n-submenu-content-padding-block:0}@media (max-width:35.9375em){.n-dropdown-submenu-content{max-block-size:70vh;max-inline-size:none}.n-dropdown-submenu-content.is-deepest-active{padding-block-start:var(--_n-submenu-focus-padding);padding-block-end:var(--_n-submenu-focus-padding)}:host([mobile-active]) ::slotted([slot=trigger]){display:none}:host([mobile-active][has-active-child]) ::slotted(nord-dropdown-group),:host([mobile-active][has-active-child]) ::slotted(nord-dropdown-item),:host([mobile-active][has-active-child]) ::slotted(nord-dropdown-submenu:not([mobile-active])){display:none}}::slotted(nord-dropdown-item){padding-inline-start:var(--n-space-s);padding-inline-end:var(--n-space-s)}::slotted(nord-dropdown-group){padding-inline-start:var(--n-space-s);padding-inline-end:var(--n-space-s);padding-block-end:var(--n-space-s);border-block-end:1px solid var(--n-color-border);margin-block-end:var(--n-space-s)}::slotted(nord-dropdown-group:last-child){padding-block-end:0;border-block-end:0;margin-block-end:0}`;let p=0,h=class extends o{constructor(){super(...arguments),this.mobileActive=!1,this.popoutId="nord-dropdown-submenu-popout-"+ ++p,this.events=new a(this),this.currentTriggerElement=null,this.popoutOpen=!1,this.mobileMediaQuery=window.matchMedia("(max-width: 35.9375em)"),this.isSmallScreen=this.mobileMediaQuery.matches,this.parentDropdownAlwaysFloating=!1,this.handleTriggerMouseEnter=()=>{var e;this.shouldUseMobileStack||(this.closeOtherSubmenus(),null===(e=this.popout)||void 0===e||e.show())},this.handleTriggerClick=e=>{var t;e.preventDefault(),e.stopImmediatePropagation(),this.shouldUseMobileStack?this.navigateIntoSubmenu():(this.closeOtherSubmenus(),null===(t=this.popout)||void 0===t||t.show())},this.handleTriggerKeydown=e=>{var t;if("ArrowRight"===e.key||"Enter"===e.key){if(e.preventDefault(),this.shouldUseMobileStack)return void this.navigateIntoSubmenu();this.closeOtherSubmenus(),null===(t=this.popout)||void 0===t||t.show(),this.updateComplete.then((()=>{var e;null===(e=this.querySelector("nord-dropdown-item"))||void 0===e||e.focus()}))}},this.handleContentKeydown=e=>{var t,o;if("ArrowLeft"===e.key){if(e.preventDefault(),e.stopPropagation(),this.shouldUseMobileStack&&this.mobileActive)return void(null===(t=this.closest("nord-dropdown"))||void 0===t||t.navigateBack());null===(o=this.popout)||void 0===o||o.hide(!0)}},this.handlePopoutOpen=()=>{this.popoutOpen=!0,this.closeOtherSubmenus()},this.handlePopoutClose=e=>{e.stopPropagation(),this.popoutOpen=!1},this.handleParentDropdownMouseOver=e=>{var t;if(this.shouldUseMobileStack)return;const o=e.target;"NORD-DROPDOWN-ITEM"===o.tagName&&!this.contains(o)&&this.popoutOpen&&(e.stopImmediatePropagation(),null===(t=this.popout)||void 0===t||t.hide())}}get shouldUseMobileStack(){return this.isSmallScreen&&!this.parentDropdownAlwaysFloating}get parentDropdown(){return this.closest("nord-dropdown")}get isInSubmenuStack(){const e=this.parentDropdown;return!!e&&e.submenuStackRef.includes(this)}get isDeepestInStack(){const e=this.parentDropdown;return!!e&&e.deepestSubmenu===this}connectedCallback(){super.connectedCallback();const e=this.querySelector('[slot="trigger"]');null==e||e.setAttribute("aria-haspopup","menu");const t=this.closest("nord-dropdown");t&&(this.parentDropdownAlwaysFloating=t.alwaysFloating,this.events.listen(t,"mouseover",this.handleParentDropdownMouseOver),this.parentObserver=new MutationObserver((e=>{for(const o of e)"always-floating"===o.attributeName&&(this.parentDropdownAlwaysFloating=t.alwaysFloating)})),this.parentObserver.observe(t,{attributes:!0,attributeFilter:["always-floating"]})),this.events.listen(this.mobileMediaQuery,"change",(e=>{this.isSmallScreen=e.matches,this.requestUpdate()}))}disconnectedCallback(){var e;super.disconnectedCallback(),null===(e=this.parentObserver)||void 0===e||e.disconnect()}render(){return this.shouldUseMobileStack&&this.mobileActive?n`<slot name="trigger"></slot><div class="${l({"n-dropdown-submenu-content":!0,active:this.isInSubmenuStack,"is-deepest-active":this.isDeepestInStack})}" @keydown="${this.handleContentKeydown}"><slot></slot></div>`:n`<slot name="trigger" aria-controls="${this.popoutId}" @slotchange="${this.handleTriggerSlotChange}"></slot><nord-popout id="${this.popoutId}" position="inline-end" always-floating @open="${this.handlePopoutOpen}" @close="${this.handlePopoutClose}"><div class="n-dropdown-submenu-content" @keydown="${this.handleContentKeydown}"><slot></slot></div></nord-popout>`}handleTriggerSlotChange(){var e;const t=null===(e=this.shadowRoot)||void 0===e?void 0:e.querySelector('slot[name="trigger"]'),o=null==t?void 0:t.assignedElements()[0];if(this.currentTriggerElement&&this.currentTriggerElement!==o&&(this.currentTriggerElement.removeEventListener("mouseenter",this.handleTriggerMouseEnter),this.currentTriggerElement.removeEventListener("click",this.handleTriggerClick),this.currentTriggerElement.removeEventListener("keydown",this.handleTriggerKeydown)),this.currentTriggerElement=null!=o?o:null,!o)return;o.setAttribute("aria-haspopup","menu");const n=!window.matchMedia("(hover: hover)").matches;this.events.listen(o,"mouseenter",this.handleTriggerMouseEnter),n&&!this.isSmallScreen||this.events.listen(o,"click",this.handleTriggerClick),this.events.listen(o,"keydown",this.handleTriggerKeydown)}closeOtherSubmenus(){var e;if(this.shouldUseMobileStack)return;const t=null===(e=this.parentElement)||void 0===e?void 0:e.closest("nord-dropdown, nord-dropdown-submenu");t&&Array.from(t.querySelectorAll(":scope > nord-dropdown-submenu")).forEach((e=>{e!==this&&e.close()}))}deactivateMobile(){var e;this.mobileActive=!1,this.removeAttribute("mobile-active");const t=null===(e=this.shadowRoot)||void 0===e?void 0:e.querySelector('slot[name="trigger"]'),o=null==t?void 0:t.assignedElements()[0];null==o||o.removeAttribute("aria-expanded")}get label(){var e,t,o,n;const i=null===(e=this.shadowRoot)||void 0===e?void 0:e.querySelector('slot[name="trigger"]');return null!==(n=null===(o=null===(t=null==i?void 0:i.assignedElements()[0])||void 0===t?void 0:t.textContent)||void 0===o?void 0:o.trim())&&void 0!==n?n:""}close(){return this.mobileActive?(this.deactivateMobile(),Promise.resolve()):this.popout?this.popout.hide():Promise.reject(new Error("DropdownSubmenu: popout component not found or not ready"))}navigateIntoSubmenu(){this.mobileActive=!0,this.setAttribute("mobile-active",""),this.dispatchEvent(new CustomEvent("nord-submenu-navigate",{bubbles:!0,detail:{submenu:this}})),this.updateComplete.then((()=>{const e=this.querySelector(".n-dropdown-submenu-content"),t=null==e?void 0:e.querySelector("nord-dropdown-item");null==t||t.focus()}))}};h.styles=[d,u],e([i("nord-popout")],h.prototype,"popout",void 0),e([s()],h.prototype,"mobileActive",void 0),e([s()],h.prototype,"isSmallScreen",void 0),e([s()],h.prototype,"parentDropdownAlwaysFloating",void 0),h=e([r("nord-dropdown-submenu")],h);var c=h;export{c as default};
2
2
  //# sourceMappingURL=DropdownSubmenu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownSubmenu.js","sources":["../src/dropdown-submenu/DropdownSubmenu.ts"],"sourcesContent":["import type Dropdown from '../dropdown/Dropdown.js'\nimport type Popout from '../popout/Popout.js'\nimport { html, LitElement } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { EventController } from '../common/controllers/EventController.js'\nimport componentStyle from '../common/styles/Component.css'\nimport style from './DropdownSubmenu.css'\nimport '../popout/Popout.js'\n\nlet popoutCounter = 0\n\n/**\n * Dropdown submenu nests a secondary menu within a parent dropdown.\n * The trigger slot contains the item that opens the submenu, and the default slot contains the submenu items.\n *\n * Supports both hover (non-touch) and click (touch-devices/accessibility) interactions.\n *\n * On small screens, uses mobile stack navigation: tapping a submenu trigger replaces the\n * dropdown's visible content with the submenu's items and shows a back button.\n *\n * @status ready\n * @category action\n *\n * @slot trigger - The element that opens the submenu (typically nord-dropdown-item).\n * @slot - The submenu content items.\n *\n * @fires {NordEvent} open - Forwarded from the internal nord-popout.\n * @fires {NordEvent} close - Forwarded from the internal nord-popout.\n * @fires {CustomEvent} nord-submenu-navigate - Fired when mobile stack navigation activates this submenu.\n */\n@customElement('nord-dropdown-submenu')\nexport default class DropdownSubmenu extends LitElement {\n static styles = [componentStyle, style]\n\n @query('nord-popout')\n private popout?: Popout\n\n @property({ reflect: true, type: Boolean, attribute: 'mobile-active' })\n mobileActive = false\n\n private readonly popoutId = `nord-dropdown-submenu-popout-${++popoutCounter}`\n private events = new EventController(this)\n private currentTriggerElement: HTMLElement | null = null\n private popoutOpen = false\n private readonly mobileMediaQuery = window.matchMedia('(max-width: 35.9375em)')\n @state() private isSmallScreen = this.mobileMediaQuery.matches\n private parentDropdownAlwaysFloating = false\n\n private get shouldUseMobileStack(): boolean {\n return this.isSmallScreen && !this.parentDropdownAlwaysFloating\n }\n\n private get parentDropdown(): Dropdown | null {\n return this.closest<Dropdown>('nord-dropdown')\n }\n\n private get isInSubmenuStack(): boolean {\n const parent = this.parentDropdown\n if (!parent)\n return false\n return parent.submenuStackRef.includes(this)\n }\n\n private get isDeepestInStack(): boolean {\n const parent = this.parentDropdown\n if (!parent)\n return false\n return parent.deepestSubmenu === this\n }\n\n connectedCallback() {\n super.connectedCallback()\n\n // Set aria-haspopup on trigger before first render\n const triggerElement = this.querySelector<HTMLElement>('[slot=\"trigger\"]')\n triggerElement?.setAttribute('aria-haspopup', 'menu')\n\n // Read alwaysFloating from parent dropdown\n const parentDropdown = this.closest<Dropdown>('nord-dropdown')\n if (parentDropdown) {\n this.parentDropdownAlwaysFloating = parentDropdown.alwaysFloating\n // Close this submenu when a sibling regular item is hovered\n this.events.listen(parentDropdown, 'mouseover', this.handleParentDropdownMouseOver)\n }\n\n // Listen for screen size changes (use correct breakpoint)\n this.events.listen(this.mobileMediaQuery, 'change', (event: MediaQueryListEvent) => {\n this.isSmallScreen = event.matches\n this.requestUpdate()\n })\n }\n\n render() {\n // Mobile stack navigation: show content inline when active\n if (this.shouldUseMobileStack && this.mobileActive) {\n // Add active class for any submenu in the stack, and is-deepest-active for the deepest one\n return html`\n <slot name=\"trigger\"></slot>\n <div class=${classMap({\n 'n-dropdown-submenu-content': true,\n 'active': this.isInSubmenuStack,\n 'is-deepest-active': this.isDeepestInStack,\n })} @keydown=${this.handleContentKeydown}>\n <slot></slot>\n </div>\n `\n }\n\n // Desktop/always-floating mode: show popout\n return html`\n <slot\n name=\"trigger\"\n aria-controls=${this.popoutId}\n @slotchange=${this.handleTriggerSlotChange}\n ></slot>\n <nord-popout\n id=${this.popoutId}\n position=\"inline-end\"\n always-floating\n @open=${this.handlePopoutOpen}\n @close=${this.handlePopoutClose}\n >\n <div\n class=\"n-dropdown-submenu-content\"\n @keydown=${this.handleContentKeydown}\n >\n <slot></slot>\n </div>\n </nord-popout>\n `\n }\n\n private handleTriggerSlotChange() {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n const triggerElement = slot?.assignedElements()[0] as HTMLElement | undefined\n\n // Remove listeners from previous trigger element\n if (this.currentTriggerElement && this.currentTriggerElement !== triggerElement) {\n this.currentTriggerElement.removeEventListener('mouseenter', this.handleTriggerMouseEnter)\n this.currentTriggerElement.removeEventListener('click', this.handleTriggerClick)\n this.currentTriggerElement.removeEventListener('keydown', this.handleTriggerKeydown)\n }\n\n this.currentTriggerElement = triggerElement ?? null\n\n if (!triggerElement)\n return\n\n triggerElement.setAttribute('aria-haspopup', 'menu')\n\n const isTouchDevice = !window.matchMedia('(hover: hover)').matches\n\n // Non-touch devices: hover to open\n this.events.listen(triggerElement, 'mouseenter', this.handleTriggerMouseEnter)\n // Non-touch devices or small screens: click to navigate/open\n if (!isTouchDevice || this.isSmallScreen) {\n this.events.listen(triggerElement, 'click', this.handleTriggerClick)\n }\n // Keyboard: arrow keys for navigation\n this.events.listen(triggerElement, 'keydown', this.handleTriggerKeydown)\n }\n\n private handleTriggerMouseEnter = () => {\n // On mobile, don't open popout on hover — only on click\n if (this.shouldUseMobileStack)\n return\n\n this.closeOtherSubmenus()\n this.popout?.show()\n }\n\n private handleTriggerClick = (event: MouseEvent) => {\n event.preventDefault()\n event.stopImmediatePropagation()\n\n if (this.shouldUseMobileStack) {\n this.navigateIntoSubmenu()\n return\n }\n\n this.closeOtherSubmenus()\n this.popout?.show()\n }\n\n private handleTriggerKeydown = (event: KeyboardEvent) => {\n if (event.key === 'ArrowRight' || event.key === 'Enter') {\n event.preventDefault()\n\n if (this.shouldUseMobileStack) {\n this.navigateIntoSubmenu()\n return\n }\n\n this.closeOtherSubmenus()\n this.popout?.show()\n this.updateComplete.then(() => {\n this.querySelector<HTMLElement>('nord-dropdown-item')?.focus()\n })\n }\n }\n\n private handleContentKeydown = (event: KeyboardEvent) => {\n if (event.key === 'ArrowLeft') {\n event.preventDefault()\n event.stopPropagation()\n\n if (this.shouldUseMobileStack && this.mobileActive) {\n this.closest<Dropdown>('nord-dropdown')?.navigateBack()\n return\n }\n\n this.popout?.hide(true)\n }\n }\n\n private handlePopoutOpen = () => {\n this.popoutOpen = true\n this.closeOtherSubmenus()\n }\n\n private handlePopoutClose = (event: Event) => {\n event.stopPropagation()\n this.popoutOpen = false\n }\n\n private handleParentDropdownMouseOver = (event: MouseEvent) => {\n // Don't close on mouseover during mobile stack navigation\n if (this.shouldUseMobileStack)\n return\n\n const target = event.target as HTMLElement\n const isRegularDropdownItem = target.tagName === 'NORD-DROPDOWN-ITEM' && !this.contains(target)\n if (isRegularDropdownItem && this.popoutOpen) {\n event.stopImmediatePropagation()\n this.popout?.hide()\n }\n }\n\n private closeOtherSubmenus() {\n // Don't close siblings during mobile stack navigation\n if (this.shouldUseMobileStack)\n return\n\n // Find the immediate parent container (dropdown or submenu)\n const immediateParent = this.parentElement?.closest('nord-dropdown, nord-dropdown-submenu')\n if (!immediateParent)\n return\n\n // Close only siblings at the same level\n Array.from(\n immediateParent.querySelectorAll<DropdownSubmenu>(':scope > nord-dropdown-submenu'),\n ).forEach((sibling) => {\n if (sibling !== this)\n sibling.close()\n })\n }\n\n /**\n * Deactivate mobile stack navigation (remove from stack).\n * @internal\n */\n deactivateMobile() {\n this.mobileActive = false\n\n // Clear aria-expanded that may have been set by Popout during hover\n const triggerSlot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n const triggerElement = triggerSlot?.assignedElements()[0] as HTMLElement | undefined\n triggerElement?.removeAttribute('aria-expanded')\n }\n\n /**\n * Read trigger text for back button title in Dropdown.\n * @internal\n */\n get label(): string {\n const triggerSlot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n return triggerSlot?.assignedElements()[0]?.textContent?.trim() ?? ''\n }\n\n /**\n * Close the submenu programmatically.\n * Returns a promise that resolves when the close animation completes.\n */\n close(): Promise<TransitionEvent | void> {\n if (this.mobileActive) {\n this.deactivateMobile()\n return Promise.resolve()\n }\n\n if (!this.popout) {\n return Promise.reject(new Error('DropdownSubmenu: popout component not found or not ready'))\n }\n return this.popout.hide()\n }\n\n /**\n * Navigate into this submenu using mobile stack navigation.\n * @internal\n */\n private navigateIntoSubmenu() {\n this.mobileActive = true\n this.dispatchEvent(\n new CustomEvent('nord-submenu-navigate', { bubbles: true, detail: { submenu: this } }),\n )\n this.updateComplete.then(() => {\n // Focus on first submenu item (not back button in header)\n const contentDiv = this.querySelector('.n-dropdown-submenu-content')\n const firstItem = contentDiv?.querySelector<HTMLElement>('nord-dropdown-item')\n firstItem?.focus()\n })\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-dropdown-submenu': DropdownSubmenu\n }\n}\n"],"names":["popoutCounter","DropdownSubmenu","LitElement","constructor","this","mobileActive","popoutId","events","EventController","currentTriggerElement","popoutOpen","mobileMediaQuery","window","matchMedia","isSmallScreen","matches","parentDropdownAlwaysFloating","handleTriggerMouseEnter","shouldUseMobileStack","closeOtherSubmenus","_a","popout","show","handleTriggerClick","event","preventDefault","stopImmediatePropagation","navigateIntoSubmenu","handleTriggerKeydown","key","updateComplete","then","querySelector","focus","handleContentKeydown","stopPropagation","closest","navigateBack","_b","hide","handlePopoutOpen","handlePopoutClose","handleParentDropdownMouseOver","target","tagName","contains","parentDropdown","isInSubmenuStack","parent","submenuStackRef","includes","isDeepestInStack","deepestSubmenu","connectedCallback","super","triggerElement","setAttribute","alwaysFloating","listen","requestUpdate","render","html","classMap","active","handleTriggerSlotChange","slot","shadowRoot","assignedElements","removeEventListener","isTouchDevice","immediateParent","parentElement","Array","from","querySelectorAll","forEach","sibling","close","deactivateMobile","triggerSlot","removeAttribute","label","_d","textContent","_c","trim","Promise","resolve","reject","Error","dispatchEvent","CustomEvent","bubbles","detail","submenu","contentDiv","firstItem","styles","componentStyle","style","__decorate","query","prototype","property","reflect","type","Boolean","attribute","state","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"DropdownSubmenu.js","sources":["../src/dropdown-submenu/DropdownSubmenu.ts"],"sourcesContent":["import type Dropdown from '../dropdown/Dropdown.js'\nimport type Popout from '../popout/Popout.js'\nimport { html, LitElement } from 'lit'\nimport { customElement, query, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { EventController } from '../common/controllers/EventController.js'\nimport componentStyle from '../common/styles/Component.css'\nimport style from './DropdownSubmenu.css'\nimport '../popout/Popout.js'\n\nlet popoutCounter = 0\n\n/**\n * Dropdown submenu nests a secondary menu within a parent dropdown.\n * The trigger slot contains the item that opens the submenu, and the default slot contains the submenu items.\n *\n * Supports both hover (non-touch) and click (touch-devices/accessibility) interactions.\n *\n * On small screens, uses mobile stack navigation: tapping a submenu trigger replaces the\n * dropdown's visible content with the submenu's items and shows a back button.\n *\n * @status ready\n * @category action\n *\n * @slot trigger - The element that opens the submenu (typically nord-dropdown-item).\n * @slot - The submenu content items.\n *\n * @fires {NordEvent} open - Forwarded from the internal nord-popout.\n * @fires {NordEvent} close - Forwarded from the internal nord-popout.\n * @fires {CustomEvent} nord-submenu-navigate - Fired when mobile stack navigation activates this submenu.\n */\n@customElement('nord-dropdown-submenu')\nexport default class DropdownSubmenu extends LitElement {\n static styles = [componentStyle, style]\n\n @query('nord-popout')\n private popout?: Popout\n\n /** @internal */\n @state() private mobileActive = false\n\n private readonly popoutId = `nord-dropdown-submenu-popout-${++popoutCounter}`\n private events = new EventController(this)\n private currentTriggerElement: HTMLElement | null = null\n private popoutOpen = false\n private readonly mobileMediaQuery = window.matchMedia('(max-width: 35.9375em)')\n @state() private isSmallScreen = this.mobileMediaQuery.matches\n @state() private parentDropdownAlwaysFloating = false\n private parentObserver?: MutationObserver\n\n private get shouldUseMobileStack(): boolean {\n return this.isSmallScreen && !this.parentDropdownAlwaysFloating\n }\n\n private get parentDropdown(): Dropdown | null {\n return this.closest<Dropdown>('nord-dropdown')\n }\n\n private get isInSubmenuStack(): boolean {\n const parent = this.parentDropdown\n if (!parent)\n return false\n return parent.submenuStackRef.includes(this)\n }\n\n private get isDeepestInStack(): boolean {\n const parent = this.parentDropdown\n if (!parent)\n return false\n return parent.deepestSubmenu === this\n }\n\n connectedCallback() {\n super.connectedCallback()\n\n // Set aria-haspopup on trigger before first render\n const triggerElement = this.querySelector<HTMLElement>('[slot=\"trigger\"]')\n triggerElement?.setAttribute('aria-haspopup', 'menu')\n\n // Read alwaysFloating from parent dropdown\n const parentDropdown = this.closest<Dropdown>('nord-dropdown')\n if (parentDropdown) {\n this.parentDropdownAlwaysFloating = parentDropdown.alwaysFloating\n // Close this submenu when a sibling regular item is hovered\n this.events.listen(parentDropdown, 'mouseover', this.handleParentDropdownMouseOver)\n\n // Observe always-floating attribute on parent dropdown for reactivity\n this.parentObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.attributeName === 'always-floating') {\n this.parentDropdownAlwaysFloating = parentDropdown.alwaysFloating\n }\n }\n })\n this.parentObserver.observe(parentDropdown, {\n attributes: true,\n attributeFilter: ['always-floating'],\n })\n }\n\n // Listen for screen size changes (use correct breakpoint)\n this.events.listen(this.mobileMediaQuery, 'change', (event: MediaQueryListEvent) => {\n this.isSmallScreen = event.matches\n this.requestUpdate()\n })\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.parentObserver?.disconnect()\n }\n\n render() {\n // Mobile stack navigation: show content inline when active\n if (this.shouldUseMobileStack && this.mobileActive) {\n // Add active class for any submenu in the stack, and is-deepest-active for the deepest one\n return html`\n <slot name=\"trigger\"></slot>\n <div class=${classMap({\n 'n-dropdown-submenu-content': true,\n 'active': this.isInSubmenuStack,\n 'is-deepest-active': this.isDeepestInStack,\n })} @keydown=${this.handleContentKeydown}>\n <slot></slot>\n </div>\n `\n }\n\n // Desktop/always-floating mode: show popout\n return html`\n <slot\n name=\"trigger\"\n aria-controls=${this.popoutId}\n @slotchange=${this.handleTriggerSlotChange}\n ></slot>\n <nord-popout\n id=${this.popoutId}\n position=\"inline-end\"\n always-floating\n @open=${this.handlePopoutOpen}\n @close=${this.handlePopoutClose}\n >\n <div\n class=\"n-dropdown-submenu-content\"\n @keydown=${this.handleContentKeydown}\n >\n <slot></slot>\n </div>\n </nord-popout>\n `\n }\n\n private handleTriggerSlotChange() {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n const triggerElement = slot?.assignedElements()[0] as HTMLElement | undefined\n\n // Remove listeners from previous trigger element\n if (this.currentTriggerElement && this.currentTriggerElement !== triggerElement) {\n this.currentTriggerElement.removeEventListener('mouseenter', this.handleTriggerMouseEnter)\n this.currentTriggerElement.removeEventListener('click', this.handleTriggerClick)\n this.currentTriggerElement.removeEventListener('keydown', this.handleTriggerKeydown)\n }\n\n this.currentTriggerElement = triggerElement ?? null\n\n if (!triggerElement)\n return\n\n triggerElement.setAttribute('aria-haspopup', 'menu')\n\n const isTouchDevice = !window.matchMedia('(hover: hover)').matches\n\n // Non-touch devices: hover to open\n this.events.listen(triggerElement, 'mouseenter', this.handleTriggerMouseEnter)\n // Non-touch devices or small screens: click to navigate/open\n if (!isTouchDevice || this.isSmallScreen) {\n this.events.listen(triggerElement, 'click', this.handleTriggerClick)\n }\n // Keyboard: arrow keys for navigation\n this.events.listen(triggerElement, 'keydown', this.handleTriggerKeydown)\n }\n\n private handleTriggerMouseEnter = () => {\n // On mobile, don't open popout on hover — only on click\n if (this.shouldUseMobileStack)\n return\n\n this.closeOtherSubmenus()\n this.popout?.show()\n }\n\n private handleTriggerClick = (event: MouseEvent) => {\n event.preventDefault()\n event.stopImmediatePropagation()\n\n if (this.shouldUseMobileStack) {\n this.navigateIntoSubmenu()\n return\n }\n\n this.closeOtherSubmenus()\n this.popout?.show()\n }\n\n private handleTriggerKeydown = (event: KeyboardEvent) => {\n if (event.key === 'ArrowRight' || event.key === 'Enter') {\n event.preventDefault()\n\n if (this.shouldUseMobileStack) {\n this.navigateIntoSubmenu()\n return\n }\n\n this.closeOtherSubmenus()\n this.popout?.show()\n this.updateComplete.then(() => {\n this.querySelector<HTMLElement>('nord-dropdown-item')?.focus()\n })\n }\n }\n\n private handleContentKeydown = (event: KeyboardEvent) => {\n if (event.key === 'ArrowLeft') {\n event.preventDefault()\n event.stopPropagation()\n\n if (this.shouldUseMobileStack && this.mobileActive) {\n this.closest<Dropdown>('nord-dropdown')?.navigateBack()\n return\n }\n\n this.popout?.hide(true)\n }\n }\n\n private handlePopoutOpen = () => {\n this.popoutOpen = true\n this.closeOtherSubmenus()\n }\n\n private handlePopoutClose = (event: Event) => {\n event.stopPropagation()\n this.popoutOpen = false\n }\n\n private handleParentDropdownMouseOver = (event: MouseEvent) => {\n // Don't close on mouseover during mobile stack navigation\n if (this.shouldUseMobileStack)\n return\n\n const target = event.target as HTMLElement\n const isRegularDropdownItem = target.tagName === 'NORD-DROPDOWN-ITEM' && !this.contains(target)\n if (isRegularDropdownItem && this.popoutOpen) {\n event.stopImmediatePropagation()\n this.popout?.hide()\n }\n }\n\n private closeOtherSubmenus() {\n // Don't close siblings during mobile stack navigation\n if (this.shouldUseMobileStack)\n return\n\n // Find the immediate parent container (dropdown or submenu)\n const immediateParent = this.parentElement?.closest('nord-dropdown, nord-dropdown-submenu')\n if (!immediateParent)\n return\n\n // Close only siblings at the same level\n Array.from(\n immediateParent.querySelectorAll<DropdownSubmenu>(':scope > nord-dropdown-submenu'),\n ).forEach((sibling) => {\n if (sibling !== this)\n sibling.close()\n })\n }\n\n /**\n * Deactivate mobile stack navigation (remove from stack).\n * @internal\n */\n deactivateMobile() {\n this.mobileActive = false\n\n // NATIVELY REMOVE THE ATTRIBUTE FROM THE HOST\n this.removeAttribute('mobile-active')\n\n // Clear aria-expanded that may have been set by Popout during hover\n const triggerSlot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n const triggerElement = triggerSlot?.assignedElements()[0] as HTMLElement | undefined\n triggerElement?.removeAttribute('aria-expanded')\n }\n\n /**\n * Read trigger text for back button title in Dropdown.\n * @internal\n */\n get label(): string {\n const triggerSlot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n return triggerSlot?.assignedElements()[0]?.textContent?.trim() ?? ''\n }\n\n /**\n * Close the submenu programmatically.\n * Returns a promise that resolves when the close animation completes.\n */\n close(): Promise<TransitionEvent | void> {\n if (this.mobileActive) {\n this.deactivateMobile()\n return Promise.resolve()\n }\n\n if (!this.popout) {\n return Promise.reject(new Error('DropdownSubmenu: popout component not found or not ready'))\n }\n return this.popout.hide()\n }\n\n /**\n * Navigate into this submenu using mobile stack navigation.\n * @internal\n */\n private navigateIntoSubmenu() {\n this.mobileActive = true\n this.setAttribute('mobile-active', '')\n this.dispatchEvent(\n new CustomEvent('nord-submenu-navigate', { bubbles: true, detail: { submenu: this } }),\n )\n this.updateComplete.then(() => {\n // Focus on first submenu item (not back button in header)\n const contentDiv = this.querySelector('.n-dropdown-submenu-content')\n const firstItem = contentDiv?.querySelector<HTMLElement>('nord-dropdown-item')\n firstItem?.focus()\n })\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-dropdown-submenu': DropdownSubmenu\n }\n}\n"],"names":["popoutCounter","DropdownSubmenu","LitElement","constructor","this","mobileActive","popoutId","events","EventController","currentTriggerElement","popoutOpen","mobileMediaQuery","window","matchMedia","isSmallScreen","matches","parentDropdownAlwaysFloating","handleTriggerMouseEnter","shouldUseMobileStack","closeOtherSubmenus","_a","popout","show","handleTriggerClick","event","preventDefault","stopImmediatePropagation","navigateIntoSubmenu","handleTriggerKeydown","key","updateComplete","then","querySelector","focus","handleContentKeydown","stopPropagation","closest","navigateBack","_b","hide","handlePopoutOpen","handlePopoutClose","handleParentDropdownMouseOver","target","tagName","contains","parentDropdown","isInSubmenuStack","parent","submenuStackRef","includes","isDeepestInStack","deepestSubmenu","connectedCallback","super","triggerElement","setAttribute","alwaysFloating","listen","parentObserver","MutationObserver","mutations","mutation","attributeName","observe","attributes","attributeFilter","requestUpdate","disconnectedCallback","disconnect","render","html","classMap","active","handleTriggerSlotChange","slot","shadowRoot","assignedElements","removeEventListener","isTouchDevice","immediateParent","parentElement","Array","from","querySelectorAll","forEach","sibling","close","deactivateMobile","removeAttribute","triggerSlot","label","_d","textContent","_c","trim","Promise","resolve","reject","Error","dispatchEvent","CustomEvent","bubbles","detail","submenu","contentDiv","firstItem","styles","componentStyle","style","__decorate","query","prototype","state","customElement"],"mappings":"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"}