luxen-ui 0.18.1 → 0.18.3

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.
@@ -172,181 +172,6 @@
172
172
  }
173
173
  ]
174
174
  },
175
- {
176
- "kind": "javascript-module",
177
- "path": "src/html/elements/avatar/avatar.ts",
178
- "declarations": [
179
- {
180
- "kind": "class",
181
- "description": "",
182
- "name": "Avatar",
183
- "cssProperties": [
184
- {
185
- "description": "Box size (any length). Set it inline (e.g. `style=\"--size: 20px\"`) for an arbitrary size beyond the `size` token scale; the font then follows proportionally. The `size` attribute sets it to the matching token.",
186
- "name": "--size",
187
- "default": "40px"
188
- },
189
- {
190
- "description": "Background fill color for initials and the default icon.",
191
- "name": "--color"
192
- },
193
- {
194
- "description": "Initials/icon color over `--color`. Defaults to an auto-derived readable color; set it to enforce a specific brand color (overrides the automatic choice).",
195
- "name": "--text-color"
196
- },
197
- {
198
- "description": "Set to `circle` for a fully circular avatar (default is a rounded square).",
199
- "name": "--appearance"
200
- }
201
- ],
202
- "cssParts": [
203
- {
204
- "description": "The avatar container that paints `--color`; style it (e.g. `color`) to override the auto-derived text color.",
205
- "name": "base"
206
- }
207
- ],
208
- "members": [
209
- {
210
- "kind": "field",
211
- "name": "src",
212
- "type": {
213
- "text": "string"
214
- },
215
- "default": "''",
216
- "description": "Image URL. Falls back to initials (then the default icon) if it fails to load.",
217
- "attribute": "src"
218
- },
219
- {
220
- "kind": "field",
221
- "name": "name",
222
- "type": {
223
- "text": "string"
224
- },
225
- "default": "''",
226
- "description": "Name used as the accessible label and to derive the initials fallback.",
227
- "attribute": "name"
228
- },
229
- {
230
- "kind": "field",
231
- "name": "size",
232
- "type": {
233
- "text": "string"
234
- },
235
- "default": "'md'",
236
- "description": "Avatar size: `xs`, `sm`, `md` (default), `lg`, or `xl`.",
237
- "attribute": "size",
238
- "reflects": true
239
- },
240
- {
241
- "kind": "field",
242
- "name": "badge",
243
- "type": {
244
- "text": "number"
245
- },
246
- "default": "0",
247
- "description": "Count shown in the corner badge. `0` hides the badge.",
248
- "attribute": "badge"
249
- },
250
- {
251
- "kind": "field",
252
- "name": "interactive",
253
- "type": {
254
- "text": "boolean"
255
- },
256
- "default": "false",
257
- "description": "Render as a `<button>` with focus ring and hover states.",
258
- "attribute": "interactive",
259
- "reflects": true
260
- }
261
- ],
262
- "attributes": [
263
- {
264
- "name": "src",
265
- "type": {
266
- "text": "string"
267
- },
268
- "default": "''",
269
- "description": "Image URL. Falls back to initials (then the default icon) if it fails to load.",
270
- "fieldName": "src"
271
- },
272
- {
273
- "name": "name",
274
- "type": {
275
- "text": "string"
276
- },
277
- "default": "''",
278
- "description": "Name used as the accessible label and to derive the initials fallback.",
279
- "fieldName": "name"
280
- },
281
- {
282
- "name": "size",
283
- "type": {
284
- "text": "string"
285
- },
286
- "default": "'md'",
287
- "description": "Avatar size: `xs`, `sm`, `md` (default), `lg`, or `xl`.",
288
- "fieldName": "size"
289
- },
290
- {
291
- "name": "badge",
292
- "type": {
293
- "text": "number"
294
- },
295
- "default": "0",
296
- "description": "Count shown in the corner badge. `0` hides the badge.",
297
- "fieldName": "badge"
298
- },
299
- {
300
- "name": "interactive",
301
- "type": {
302
- "text": "boolean"
303
- },
304
- "default": "false",
305
- "description": "Render as a `<button>` with focus ring and hover states.",
306
- "fieldName": "interactive"
307
- }
308
- ],
309
- "superclass": {
310
- "name": "LuxenElement",
311
- "module": "/src/html/shared/luxen-element.js"
312
- },
313
- "tagName": "l-avatar",
314
- "customElement": true,
315
- "summary": "An avatar component for displaying user images, initials, or a default icon.",
316
- "_cssClasses": [
317
- {
318
- "name": ".l-avatar-group",
319
- "description": "Flex wrapper that overlaps a row of stacked avatars."
320
- }
321
- ]
322
- }
323
- ],
324
- "exports": [
325
- {
326
- "kind": "js",
327
- "name": "Avatar",
328
- "declaration": {
329
- "name": "Avatar",
330
- "module": "src/html/elements/avatar/avatar.ts"
331
- }
332
- }
333
- ]
334
- },
335
- {
336
- "kind": "javascript-module",
337
- "path": "src/html/elements/avatar/index.ts",
338
- "declarations": [],
339
- "exports": [
340
- {
341
- "kind": "js",
342
- "name": "*",
343
- "declaration": {
344
- "name": "*",
345
- "module": "src/html/elements/avatar/avatar.js"
346
- }
347
- }
348
- ]
349
- },
350
175
  {
351
176
  "kind": "javascript-module",
352
177
  "path": "src/html/elements/alert-dialog/alert-dialog.ts",
@@ -827,6 +652,181 @@
827
652
  }
828
653
  ]
829
654
  },
655
+ {
656
+ "kind": "javascript-module",
657
+ "path": "src/html/elements/avatar/avatar.ts",
658
+ "declarations": [
659
+ {
660
+ "kind": "class",
661
+ "description": "",
662
+ "name": "Avatar",
663
+ "cssProperties": [
664
+ {
665
+ "description": "Box size (any length). Set it inline (e.g. `style=\"--size: 20px\"`) for an arbitrary size beyond the `size` token scale; the font then follows proportionally. The `size` attribute sets it to the matching token.",
666
+ "name": "--size",
667
+ "default": "40px"
668
+ },
669
+ {
670
+ "description": "Background fill color for initials and the default icon.",
671
+ "name": "--color"
672
+ },
673
+ {
674
+ "description": "Initials/icon color over `--color`. Defaults to an auto-derived readable color; set it to enforce a specific brand color (overrides the automatic choice).",
675
+ "name": "--text-color"
676
+ },
677
+ {
678
+ "description": "Set to `circle` for a fully circular avatar (default is a rounded square).",
679
+ "name": "--appearance"
680
+ }
681
+ ],
682
+ "cssParts": [
683
+ {
684
+ "description": "The avatar container that paints `--color`; style it (e.g. `color`) to override the auto-derived text color.",
685
+ "name": "base"
686
+ }
687
+ ],
688
+ "members": [
689
+ {
690
+ "kind": "field",
691
+ "name": "src",
692
+ "type": {
693
+ "text": "string"
694
+ },
695
+ "default": "''",
696
+ "description": "Image URL. Falls back to initials (then the default icon) if it fails to load.",
697
+ "attribute": "src"
698
+ },
699
+ {
700
+ "kind": "field",
701
+ "name": "name",
702
+ "type": {
703
+ "text": "string"
704
+ },
705
+ "default": "''",
706
+ "description": "Name used as the accessible label and to derive the initials fallback.",
707
+ "attribute": "name"
708
+ },
709
+ {
710
+ "kind": "field",
711
+ "name": "size",
712
+ "type": {
713
+ "text": "string"
714
+ },
715
+ "default": "'md'",
716
+ "description": "Avatar size: `xs`, `sm`, `md` (default), `lg`, or `xl`.",
717
+ "attribute": "size",
718
+ "reflects": true
719
+ },
720
+ {
721
+ "kind": "field",
722
+ "name": "badge",
723
+ "type": {
724
+ "text": "number"
725
+ },
726
+ "default": "0",
727
+ "description": "Count shown in the corner badge. `0` hides the badge.",
728
+ "attribute": "badge"
729
+ },
730
+ {
731
+ "kind": "field",
732
+ "name": "interactive",
733
+ "type": {
734
+ "text": "boolean"
735
+ },
736
+ "default": "false",
737
+ "description": "Render as a `<button>` with focus ring and hover states.",
738
+ "attribute": "interactive",
739
+ "reflects": true
740
+ }
741
+ ],
742
+ "attributes": [
743
+ {
744
+ "name": "src",
745
+ "type": {
746
+ "text": "string"
747
+ },
748
+ "default": "''",
749
+ "description": "Image URL. Falls back to initials (then the default icon) if it fails to load.",
750
+ "fieldName": "src"
751
+ },
752
+ {
753
+ "name": "name",
754
+ "type": {
755
+ "text": "string"
756
+ },
757
+ "default": "''",
758
+ "description": "Name used as the accessible label and to derive the initials fallback.",
759
+ "fieldName": "name"
760
+ },
761
+ {
762
+ "name": "size",
763
+ "type": {
764
+ "text": "string"
765
+ },
766
+ "default": "'md'",
767
+ "description": "Avatar size: `xs`, `sm`, `md` (default), `lg`, or `xl`.",
768
+ "fieldName": "size"
769
+ },
770
+ {
771
+ "name": "badge",
772
+ "type": {
773
+ "text": "number"
774
+ },
775
+ "default": "0",
776
+ "description": "Count shown in the corner badge. `0` hides the badge.",
777
+ "fieldName": "badge"
778
+ },
779
+ {
780
+ "name": "interactive",
781
+ "type": {
782
+ "text": "boolean"
783
+ },
784
+ "default": "false",
785
+ "description": "Render as a `<button>` with focus ring and hover states.",
786
+ "fieldName": "interactive"
787
+ }
788
+ ],
789
+ "superclass": {
790
+ "name": "LuxenElement",
791
+ "module": "/src/html/shared/luxen-element.js"
792
+ },
793
+ "tagName": "l-avatar",
794
+ "customElement": true,
795
+ "summary": "An avatar component for displaying user images, initials, or a default icon.",
796
+ "_cssClasses": [
797
+ {
798
+ "name": ".l-avatar-group",
799
+ "description": "Flex wrapper that overlaps a row of stacked avatars."
800
+ }
801
+ ]
802
+ }
803
+ ],
804
+ "exports": [
805
+ {
806
+ "kind": "js",
807
+ "name": "Avatar",
808
+ "declaration": {
809
+ "name": "Avatar",
810
+ "module": "src/html/elements/avatar/avatar.ts"
811
+ }
812
+ }
813
+ ]
814
+ },
815
+ {
816
+ "kind": "javascript-module",
817
+ "path": "src/html/elements/avatar/index.ts",
818
+ "declarations": [],
819
+ "exports": [
820
+ {
821
+ "kind": "js",
822
+ "name": "*",
823
+ "declaration": {
824
+ "name": "*",
825
+ "module": "src/html/elements/avatar/avatar.js"
826
+ }
827
+ }
828
+ ]
829
+ },
830
830
  {
831
831
  "kind": "javascript-module",
832
832
  "path": "src/html/elements/badge/badge.ts",
@@ -8573,6 +8573,16 @@
8573
8573
  "description": "`line` variant: thickness of the static bottom border.",
8574
8574
  "name": "--track-thickness",
8575
8575
  "default": "1px"
8576
+ },
8577
+ {
8578
+ "description": "`line` variant: fill of the pill that appears behind a hovered tab label.",
8579
+ "name": "--hover-color",
8580
+ "default": "var(--l-color-bg-state-hover)"
8581
+ },
8582
+ {
8583
+ "description": "`line` variant: block-axis gap between the hover pill and the tab edges, keeping it detached from the bottom border.",
8584
+ "name": "--hover-inset",
8585
+ "default": "4px"
8576
8586
  }
8577
8587
  ],
8578
8588
  "members": [
@@ -8624,7 +8634,7 @@
8624
8634
  "events": [
8625
8635
  {
8626
8636
  "name": "change",
8627
- "description": "Fired when the active tab changes. Bubbles. Properties: `index: number`, `name: string | null`.",
8637
+ "description": "Fired when the active tab changes. Bubbles. Not cancelable. Properties: `index: number`, `name: string | null`.",
8628
8638
  "cancelable": false
8629
8639
  }
8630
8640
  ],
@@ -8678,6 +8688,11 @@
8678
8688
  "title": "Mark the initially-active tab with `aria-selected=\"true\"` so it is styled as",
8679
8689
  "language": "html",
8680
8690
  "code": "selected before the script upgrades the element (progressive enhancement).\n```html\n<l-tabs variant=\"enclosed\">\n <div>\n <button aria-selected=\"true\">Tab 1</button>\n <button>Tab 2</button>\n </div>\n <div>Content 1</div>\n <div>Content 2</div>\n</l-tabs>\n```"
8691
+ },
8692
+ {
8693
+ "title": "A tab button marked `disabled` (or `aria-disabled=\"true\"`) is skipped by",
8694
+ "language": "html",
8695
+ "code": "arrow keys, `Home` and `End`, and cannot be selected by a click or by\n`value` — it still owns its panel, so the tab/panel order is unchanged.\n```html\n<button disabled>Billing</button>\n```"
8681
8696
  }
8682
8697
  ]
8683
8698
  }
@@ -107,7 +107,22 @@ export declare class Dropdown extends LuxenElement {
107
107
  private _onPanelPointerOut;
108
108
  private _selectCurrentItem;
109
109
  private _selectItem;
110
- /** Sync `open` when popover="auto" light-dismiss fires. */
110
+ /**
111
+ * Route `popover="auto"` light-dismiss through the same close path as every
112
+ * other user-driven close (trigger click, Escape, item selection), so the
113
+ * cancelable `hide` event fires for it too. Assigning `open` here directly
114
+ * would skip it and desync anything a consumer syncs on `hide`.
115
+ *
116
+ * Driving `open` as a property or attribute still closes the menu with only
117
+ * `after-hide` — `l-dialog` mediates that path from `updated()`, this element
118
+ * does not. A gap worth closing on its own.
119
+ *
120
+ * The platform makes a popover's close non-cancelable (`beforetoggle` is only
121
+ * cancelable when opening), so a vetoed `hide` is honored by putting the panel
122
+ * back. `toggle` is the right hook for that: it is queued after the hide has
123
+ * actually been applied, whereas during `beforetoggle` the panel is still
124
+ * `:popover-open` and `showPopover()` would be a no-op the pending hide undoes.
125
+ */
111
126
  private _onToggle;
112
127
  render(): import('lit').TemplateResult<1>;
113
128
  }
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.d.ts","sourceRoot":"","sources":["../../../src/html/elements/dropdown/dropdown.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dropdown.d.ts","sourceRoot":"","sources":["../../../src/html/elements/dropdown/dropdown.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import{tagName as e}from"../../registry.js";import{i as t}from"../../chunks/lit.js";import{i as n,t as r}from"../../chunks/decorate.js";import{a as i}from"../../chunks/lit-html.js";import{LuxenElement as a}from"../../shared/luxen-element.js";import{ShowEvent as o}from"../../events/show.js";import{AfterShowEvent as s}from"../../events/after-show.js";import{HideEvent as c}from"../../events/hide.js";import{AfterHideEvent as l}from"../../events/after-hide.js";import u from"../../shared/styles/host.styles.js";import{PopoverController as d}from"../../shared/controllers/popover.js";var f=t(`:host{--padding:.25rem;--background:var(--l-color-surface-overlay);--border-radius:6px;--shadow:var(--l-shadow-md);--show-duration:150;--hide-duration:150;display:inline-block;position:relative}.trigger{display:contents}[popover]{inset:unset;box-sizing:border-box;width:max-content;padding:var(--padding);border:1px solid var(--l-color-border-overlay);border-radius:var(--border-radius);background:var(--background);color:var(--l-color-text-primary);box-shadow:var(--shadow);margin:0;font-size:.875rem;line-height:1.5;overflow:visible}::slotted(hr){height:1px;margin-block:var(--padding);margin-inline:calc(var(--padding) * -1);background:var(--l-color-divider);border:0}`),p=class extends Event{constructor(e){super(`select`,{bubbles:!0,composed:!1,cancelable:!1}),this.item=e}},m=class extends a{constructor(...e){super(...e),this._floating=new d(this,{getTriggerElement:()=>this._triggerEl,getFloatingElement:()=>this._panelEl,getArrowElement:()=>null}),this._typeaheadBuffer=``,this._typeaheadTimeout=0,this.#e=!1,this.#t=`bottom-start`,this.#n=4,this.#r=!1,this._hoverTimer=0,this._hoverItem=null,this._onTriggerSlotChange=()=>{let e=this._triggerEl;if(!e)return;e.setAttribute(`aria-haspopup`,`menu`),e.setAttribute(`aria-expanded`,String(this.open));let t=e.getAttribute(`aria-label`)??e.textContent?.trim()??``,n=this.shadowRoot?.querySelector(`[role="menu"]`);n&&t&&n.setAttribute(`aria-label`,t)},this._onTriggerClick=e=>{this.disabled||(this.toggle(),this.open&&e.detail===0&&requestAnimationFrame(()=>this._focusFirstItem()))},this._onTriggerKeyDown=e=>{this.disabled||(e.key===`ArrowDown`?(e.preventDefault(),this.show(),requestAnimationFrame(()=>this._focusFirstItem())):e.key===`ArrowUp`&&(e.preventDefault(),this.show(),requestAnimationFrame(()=>this._focusLastItem())))},this._onPanelKeyDown=e=>{switch(e.key){case`ArrowDown`:e.preventDefault(),this._focusNextItem();break;case`ArrowUp`:e.preventDefault(),this._focusPreviousItem();break;case`Home`:e.preventDefault(),this._focusFirstItem(this._currentLevelItems());break;case`End`:e.preventDefault(),this._focusLastItem(this._currentLevelItems());break;case`ArrowRight`:{let t=this._getCurrentItem();t?.hasSubmenu&&(e.preventDefault(),this._openSubmenu(t,{focus:!0}));break}case`ArrowLeft`:{let t=this._parentItemOf(this._getCurrentItem());t&&(e.preventDefault(),t.closeSubmenu(),this._setActiveItem(t));break}case`Escape`:{e.preventDefault();let t=this._parentItemOf(this._getCurrentItem());t?(t.closeSubmenu(),this._setActiveItem(t)):(this.hide(),this._triggerEl?.focus());break}case`Tab`:this.hide();break;case`Enter`:case` `:e.preventDefault(),this._selectCurrentItem();break;default:e.key.length===1&&!e.ctrlKey&&!e.metaKey&&this._handleTypeahead(e.key)}},this._onItemClick=e=>{let t=this._itemFromEvent(e);if(!(!t||t.disabled)){if(t.hasSubmenu){t.submenuOpen?t.closeSubmenu():this._openSubmenu(t);return}this._selectItem(t)}},this._onPanelPointerOver=e=>{if(e.pointerType!==`mouse`)return;let t=this._itemFromEvent(e);t!==this._hoverItem&&(clearTimeout(this._hoverTimer),this._hoverItem=t,!(!t||t.disabled)&&(this._hoverTimer=window.setTimeout(()=>{this._openSubmenu(t)},100)))},this._onPanelPointerOut=()=>{clearTimeout(this._hoverTimer),this._hoverItem=null},this._onToggle=e=>{e.newState===`closed`&&this.open&&(this.open=!1,this._triggerEl?.setAttribute(`aria-expanded`,`false`))}}static{this.styles=[u,f]}#e;get open(){return this.#e}set open(e){this.#e=e}#t;get placement(){return this.#t}set placement(e){this.#t=e}#n;get distance(){return this.#n}set distance(e){this.#n=e}#r;get disabled(){return this.#r}set disabled(e){this.#r=e}#i;get minWidth(){return this.#i}set minWidth(e){this.#i=e}get _triggerEl(){return this.shadowRoot.querySelector(`.trigger slot`)?.assignedElements()[0]??null}get _panelEl(){return this.shadowRoot.querySelector(`[popover]`)}_getItems(){let t=this.shadowRoot.querySelector(`slot:not([name])`);return t?t.assignedElements().filter(t=>t.tagName===e(`dropdown-item`).toUpperCase()&&!t.disabled):[]}_getAllItems(){let t=this.shadowRoot.querySelector(`slot:not([name])`);return t?t.assignedElements().filter(t=>t.tagName===e(`dropdown-item`).toUpperCase()):[]}_getAllItemsDeep(){return[...this.querySelectorAll(e(`dropdown-item`))]}_levelItemsOf(t){let n=t.parentElement;return n&&n.tagName===e(`dropdown-item`).toUpperCase()?n.getSubmenuItems():this._getItems()}_parentItemOf(t){let n=t?.parentElement;return n&&n.tagName===e(`dropdown-item`).toUpperCase()?n:null}_currentLevelItems(){let e=this._getCurrentItem();return e?this._levelItemsOf(e):this._getItems()}_getDuration(e){let t=parseFloat(getComputedStyle(this).getPropertyValue(e));return Number.isNaN(t)?150:t}show(){this.open||this.disabled||this.dispatchEvent(new o)&&(this.open=!0)}hide(){this.open&&this.dispatchEvent(new c)&&(this.open=!1)}toggle(){this.open?this.hide():this.show()}disconnectedCallback(){super.disconnectedCallback(),clearTimeout(this._hoverTimer),this._hoverItem=null}updated(e){e.has(`open`)&&this._handleOpenChange()}async _handleOpenChange(){let e=this._panelEl;if(!e)return;let t={placement:this.placement,distance:this.distance,minWidth:this.minWidth};if(this.open){if(e.showPopover(),await this._floating.updatePosition(t),!this.open)return;await this._floating.animateShow(e,this._getDuration(`--show-duration`)),this._floating.startPositioning(t),this._triggerEl?.setAttribute(`aria-expanded`,`true`),this.dispatchEvent(new s)}else this._floating.stopPositioning(),this._closeAllSubmenus(),this._triggerEl?.setAttribute(`aria-expanded`,`false`),await this._floating.animateHide(e,this._getDuration(`--hide-duration`)),e.matches(`:popover-open`)&&e.hidePopover(),this.dispatchEvent(new l)}async _openSubmenu(e,{focus:t=!1}={}){if(!this.open||!this.isConnected)return;let n=!1;for(let t of this._levelItemsOf(e))t!==e&&(t.contains(document.activeElement)&&(n=!0),t.closeSubmenu());if(n&&!t&&this._setActiveItem(e),e.openSubmenu(),t){await e.updateComplete;let t=e.getSubmenuItems()[0];t&&this._setActiveItem(t)}}_closeAllSubmenus(){clearTimeout(this._hoverTimer),this._hoverItem=null;for(let e of this._getAllItems())e.closeSubmenu()}_itemFromEvent(t){let n=t.composedPath(),r=e(`dropdown-item`).toUpperCase(),i=n.find(e=>e instanceof Element&&e.tagName===r)??null;if(!i)return null;let a=i.shadowRoot?.querySelector(`.item`);if(a&&!n.includes(a)){let e=i.shadowRoot?.querySelector(`.submenu`);if(e&&n.includes(e))return null}return i}_setActiveItem(e){let t=e.shadowRoot.querySelector(`.item`);if(t){for(let e of this._getAllItemsDeep())e.shadowRoot.querySelector(`.item`)?.setAttribute(`tabindex`,`-1`);t.setAttribute(`tabindex`,`0`),t.focus();for(let t of this._levelItemsOf(e))t!==e&&t.closeSubmenu()}}_focusFirstItem(e=this._getItems()){e.length&&this._setActiveItem(e[0])}_focusLastItem(e=this._getItems()){e.length&&this._setActiveItem(e[e.length-1])}_getCurrentItem(){return this._getAllItemsDeep().find(e=>{let t=e.shadowRoot.querySelector(`.item`);return t?.getAttribute(`tabindex`)===`0`&&e.shadowRoot.activeElement===t})??null}_focusNextItem(){let e=this._currentLevelItems(),t=this._getCurrentItem(),n=e[((t?e.indexOf(t):-1)+1)%e.length];n&&this._setActiveItem(n)}_focusPreviousItem(){let e=this._currentLevelItems(),t=this._getCurrentItem(),n=e[((t?e.indexOf(t):0)-1+e.length)%e.length];n&&this._setActiveItem(n)}_handleTypeahead(e){clearTimeout(this._typeaheadTimeout),this._typeaheadBuffer+=e.toLowerCase(),this._typeaheadTimeout=window.setTimeout(()=>{this._typeaheadBuffer=``},500);let t=this._currentLevelItems().find(e=>e.getTextLabel().toLowerCase().startsWith(this._typeaheadBuffer));t&&this._setActiveItem(t)}_selectCurrentItem(){let e=this._getCurrentItem();e&&(e.hasSubmenu?this._openSubmenu(e,{focus:!0}):this._selectItem(e))}_selectItem(e){e.type===`checkbox`&&(e.checked=!e.checked),this.dispatchEvent(new p(e)),e.type!==`checkbox`&&(this.hide(),this._triggerEl?.focus())}render(){return i`
1
+ import{tagName as e}from"../../registry.js";import{i as t}from"../../chunks/lit.js";import{i as n,t as r}from"../../chunks/decorate.js";import{a as i}from"../../chunks/lit-html.js";import{LuxenElement as a}from"../../shared/luxen-element.js";import{ShowEvent as o}from"../../events/show.js";import{AfterShowEvent as s}from"../../events/after-show.js";import{HideEvent as c}from"../../events/hide.js";import{AfterHideEvent as l}from"../../events/after-hide.js";import u from"../../shared/styles/host.styles.js";import{PopoverController as d}from"../../shared/controllers/popover.js";var f=t(`:host{--padding:.25rem;--background:var(--l-color-surface-overlay);--border-radius:6px;--shadow:var(--l-shadow-md);--show-duration:150;--hide-duration:150;display:inline-block;position:relative}.trigger{display:contents}[popover]{inset:unset;box-sizing:border-box;width:max-content;padding:var(--padding);border:1px solid var(--l-color-border-overlay);border-radius:var(--border-radius);background:var(--background);color:var(--l-color-text-primary);box-shadow:var(--shadow);margin:0;font-size:.875rem;line-height:1.5;overflow:visible}::slotted(hr){height:1px;margin-block:var(--padding);margin-inline:calc(var(--padding) * -1);background:var(--l-color-divider);border:0}`),p=class extends Event{constructor(e){super(`select`,{bubbles:!0,composed:!1,cancelable:!1}),this.item=e}},m=class extends a{constructor(...e){super(...e),this._floating=new d(this,{getTriggerElement:()=>this._triggerEl,getFloatingElement:()=>this._panelEl,getArrowElement:()=>null}),this._typeaheadBuffer=``,this._typeaheadTimeout=0,this.#e=!1,this.#t=`bottom-start`,this.#n=4,this.#r=!1,this._hoverTimer=0,this._hoverItem=null,this._onTriggerSlotChange=()=>{let e=this._triggerEl;if(!e)return;e.setAttribute(`aria-haspopup`,`menu`),e.setAttribute(`aria-expanded`,String(this.open));let t=e.getAttribute(`aria-label`)??e.textContent?.trim()??``,n=this.shadowRoot?.querySelector(`[role="menu"]`);n&&t&&n.setAttribute(`aria-label`,t)},this._onTriggerClick=e=>{this.disabled||this.open&&!this._panelEl?.matches(`:popover-open`)||(this.toggle(),this.open&&e.detail===0&&requestAnimationFrame(()=>this._focusFirstItem()))},this._onTriggerKeyDown=e=>{if(!this.disabled)if(e.key===`Escape`){if(!this.open)return;e.preventDefault(),this.hide()}else e.key===`ArrowDown`?(e.preventDefault(),this.show(),requestAnimationFrame(()=>this._focusFirstItem())):e.key===`ArrowUp`&&(e.preventDefault(),this.show(),requestAnimationFrame(()=>this._focusLastItem()))},this._onPanelKeyDown=e=>{switch(e.key){case`ArrowDown`:e.preventDefault(),this._focusNextItem();break;case`ArrowUp`:e.preventDefault(),this._focusPreviousItem();break;case`Home`:e.preventDefault(),this._focusFirstItem(this._currentLevelItems());break;case`End`:e.preventDefault(),this._focusLastItem(this._currentLevelItems());break;case`ArrowRight`:{let t=this._getCurrentItem();t?.hasSubmenu&&(e.preventDefault(),this._openSubmenu(t,{focus:!0}));break}case`ArrowLeft`:{let t=this._parentItemOf(this._getCurrentItem());t&&(e.preventDefault(),t.closeSubmenu(),this._setActiveItem(t));break}case`Escape`:{e.preventDefault();let t=this._parentItemOf(this._getCurrentItem());t?(t.closeSubmenu(),this._setActiveItem(t)):(this.hide(),this._triggerEl?.focus());break}case`Tab`:this.hide();break;case`Enter`:case` `:e.preventDefault(),this._selectCurrentItem();break;default:e.key.length===1&&!e.ctrlKey&&!e.metaKey&&this._handleTypeahead(e.key)}},this._onItemClick=e=>{let t=this._itemFromEvent(e);if(!(!t||t.disabled)){if(t.hasSubmenu){t.submenuOpen?t.closeSubmenu():this._openSubmenu(t);return}this._selectItem(t)}},this._onPanelPointerOver=e=>{if(e.pointerType!==`mouse`)return;let t=this._itemFromEvent(e);t!==this._hoverItem&&(clearTimeout(this._hoverTimer),this._hoverItem=t,!(!t||t.disabled)&&(this._hoverTimer=window.setTimeout(()=>{this._openSubmenu(t)},100)))},this._onPanelPointerOut=()=>{clearTimeout(this._hoverTimer),this._hoverItem=null},this._onToggle=e=>{if(e.newState!==`closed`||!this.open)return;if(this.dispatchEvent(new c)){this.open=!1;return}let t=this._panelEl;t?.isConnected&&t.showPopover()}}static{this.styles=[u,f]}#e;get open(){return this.#e}set open(e){this.#e=e}#t;get placement(){return this.#t}set placement(e){this.#t=e}#n;get distance(){return this.#n}set distance(e){this.#n=e}#r;get disabled(){return this.#r}set disabled(e){this.#r=e}#i;get minWidth(){return this.#i}set minWidth(e){this.#i=e}get _triggerEl(){return this.shadowRoot.querySelector(`.trigger slot`)?.assignedElements()[0]??null}get _panelEl(){return this.shadowRoot.querySelector(`[popover]`)}_getItems(){let t=this.shadowRoot.querySelector(`slot:not([name])`);return t?t.assignedElements().filter(t=>t.tagName===e(`dropdown-item`).toUpperCase()&&!t.disabled):[]}_getAllItems(){let t=this.shadowRoot.querySelector(`slot:not([name])`);return t?t.assignedElements().filter(t=>t.tagName===e(`dropdown-item`).toUpperCase()):[]}_getAllItemsDeep(){return[...this.querySelectorAll(e(`dropdown-item`))]}_levelItemsOf(t){let n=t.parentElement;return n&&n.tagName===e(`dropdown-item`).toUpperCase()?n.getSubmenuItems():this._getItems()}_parentItemOf(t){let n=t?.parentElement;return n&&n.tagName===e(`dropdown-item`).toUpperCase()?n:null}_currentLevelItems(){let e=this._getCurrentItem();return e?this._levelItemsOf(e):this._getItems()}_getDuration(e){let t=parseFloat(getComputedStyle(this).getPropertyValue(e));return Number.isNaN(t)?150:t}show(){this.open||this.disabled||this.dispatchEvent(new o)&&(this.open=!0)}hide(){this.open&&this.dispatchEvent(new c)&&(this.open=!1)}toggle(){this.open?this.hide():this.show()}disconnectedCallback(){super.disconnectedCallback(),clearTimeout(this._hoverTimer),this._hoverItem=null}updated(e){e.has(`open`)&&this._handleOpenChange()}async _handleOpenChange(){let e=this._panelEl;if(!e)return;let t={placement:this.placement,distance:this.distance,minWidth:this.minWidth};if(this.open){if(e.showPopover(),await this._floating.updatePosition(t),!this.open)return;await this._floating.animateShow(e,this._getDuration(`--show-duration`)),this._floating.startPositioning(t),this._triggerEl?.setAttribute(`aria-expanded`,`true`),this.dispatchEvent(new s)}else this._floating.stopPositioning(),this._closeAllSubmenus(),this._triggerEl?.setAttribute(`aria-expanded`,`false`),await this._floating.animateHide(e,this._getDuration(`--hide-duration`)),e.matches(`:popover-open`)&&e.hidePopover(),this.dispatchEvent(new l)}async _openSubmenu(e,{focus:t=!1}={}){if(!this.open||!this.isConnected)return;let n=!1;for(let t of this._levelItemsOf(e))t!==e&&(t.contains(document.activeElement)&&(n=!0),t.closeSubmenu());if(n&&!t&&this._setActiveItem(e),e.openSubmenu(),t){await e.updateComplete;let t=e.getSubmenuItems()[0];t&&this._setActiveItem(t)}}_closeAllSubmenus(){clearTimeout(this._hoverTimer),this._hoverItem=null;for(let e of this._getAllItems())e.closeSubmenu()}_itemFromEvent(t){let n=t.composedPath(),r=e(`dropdown-item`).toUpperCase(),i=n.find(e=>e instanceof Element&&e.tagName===r)??null;if(!i)return null;let a=i.shadowRoot?.querySelector(`.item`);if(a&&!n.includes(a)){let e=i.shadowRoot?.querySelector(`.submenu`);if(e&&n.includes(e))return null}return i}_setActiveItem(e){let t=e.shadowRoot.querySelector(`.item`);if(t){for(let e of this._getAllItemsDeep())e.shadowRoot.querySelector(`.item`)?.setAttribute(`tabindex`,`-1`);t.setAttribute(`tabindex`,`0`),t.focus();for(let t of this._levelItemsOf(e))t!==e&&t.closeSubmenu()}}_focusFirstItem(e=this._getItems()){e.length&&this._setActiveItem(e[0])}_focusLastItem(e=this._getItems()){e.length&&this._setActiveItem(e[e.length-1])}_getCurrentItem(){return this._getAllItemsDeep().find(e=>{let t=e.shadowRoot.querySelector(`.item`);return t?.getAttribute(`tabindex`)===`0`&&e.shadowRoot.activeElement===t})??null}_focusNextItem(){let e=this._currentLevelItems(),t=this._getCurrentItem(),n=e[((t?e.indexOf(t):-1)+1)%e.length];n&&this._setActiveItem(n)}_focusPreviousItem(){let e=this._currentLevelItems(),t=this._getCurrentItem(),n=e[((t?e.indexOf(t):0)-1+e.length)%e.length];n&&this._setActiveItem(n)}_handleTypeahead(e){clearTimeout(this._typeaheadTimeout),this._typeaheadBuffer+=e.toLowerCase(),this._typeaheadTimeout=window.setTimeout(()=>{this._typeaheadBuffer=``},500);let t=this._currentLevelItems().find(e=>e.getTextLabel().toLowerCase().startsWith(this._typeaheadBuffer));t&&this._setActiveItem(t)}_selectCurrentItem(){let e=this._getCurrentItem();e&&(e.hasSubmenu?this._openSubmenu(e,{focus:!0}):this._selectItem(e))}_selectItem(e){e.type===`checkbox`&&(e.checked=!e.checked),this.dispatchEvent(new p(e)),e.type!==`checkbox`&&(this.hide(),this._triggerEl?.focus())}render(){return i`
2
2
  <div
3
3
  class="trigger"
4
4
  @click=${this._onTriggerClick}
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.js","names":[],"sources":["../../../src/html/elements/dropdown/dropdown.css?inline","../../../src/html/elements/dropdown/dropdown.ts"],"sourcesContent":[":host {\n --padding: 0.25rem;\n\n --background: var(--l-color-surface-overlay);\n --border-radius: 6px;\n --shadow: var(--l-shadow-md);\n --show-duration: 150;\n --hide-duration: 150;\n\n display: inline-block;\n position: relative;\n}\n\n.trigger {\n display: contents;\n}\n\n[popover] {\n inset: unset;\n overflow: visible;\n box-sizing: border-box;\n width: max-content;\n padding: var(--padding);\n margin: 0;\n border: 1px solid var(--l-color-border-overlay);\n border-radius: var(--border-radius);\n background: var(--background);\n color: var(--l-color-text-primary);\n box-shadow: var(--shadow);\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n/* Lightweight separator alternative to <l-divider> — same dimensions, no extra import. */\n::slotted(hr) {\n height: 1px;\n margin-block: var(--padding);\n margin-inline: calc(var(--padding) * -1);\n border: 0;\n background: var(--l-color-divider);\n}\n","import { html, unsafeCSS, type PropertyValues } from 'lit';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport { property } from 'lit/decorators.js';\nimport type { Placement } from '@floating-ui/dom';\nimport { PopoverController } from '../../shared/controllers/popover.js';\nimport { tagName } from '../../registry.js';\nimport type { DropdownItem } from '../dropdown-item/dropdown-item.js';\nimport { ShowEvent, AfterShowEvent, HideEvent, AfterHideEvent } from '../../events/index.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport rawStyles from './dropdown.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/** Fired when a dropdown item is selected. Bubbles; not composed. */\nexport class DropdownSelectEvent extends Event {\n readonly item: DropdownItem;\n constructor(item: DropdownItem) {\n super('select', { bubbles: true, composed: false, cancelable: false });\n this.item = item;\n }\n}\n\ninterface DropdownEventMap {\n select: DropdownSelectEvent;\n}\n\n/**\n * A dropdown menu anchored to a trigger element.\n *\n * @slot trigger - The element that triggers the dropdown.\n * @slot header - Optional content rendered above the menu items (e.g. a user profile row). Use an `<l-divider>` (or `<hr>`) after it to separate from items.\n * @slot - Menu content (`l-dropdown-item` elements). Drop an `<l-divider>` (or `<hr>`) between items to render a section separator, or an `<l-dropdown-label>` to caption a group of items. Nest items with `slot=\"submenu\"` inside an item to create a submenu.\n * @slot footer - Optional content rendered below the menu items (e.g. a version label or shortcut row). Use an `<l-divider>` (or `<hr>`) before it to separate from items.\n *\n * @csspart panel - The floating menu container.\n *\n * @cssproperty --background - Panel background color.\n * @cssproperty --border-radius - Panel border radius. Default `8px`.\n * @cssproperty --padding - Panel inner padding. Default `0.25rem`. Slotted `<l-divider>` elements bleed by this amount on each side to span the panel edges.\n * @cssproperty --shadow - Panel box shadow.\n * @cssproperty --show-duration - Show animation duration in ms. Default `150`.\n * @cssproperty --hide-duration - Hide animation duration in ms. Default `150`.\n *\n * @event show - Fired before the dropdown opens. Cancelable.\n * @event after-show - Fired after the open animation completes.\n * @event hide - Fired before the dropdown closes. Cancelable.\n * @event after-hide - Fired after the close animation completes.\n * @event select - Fired when an item is selected, including items nested in submenus. Bubbles. Properties: `item: DropdownItem`.\n *\n * @customElement l-dropdown\n */\n// oxlint-disable-next-line typescript/no-unsafe-declaration-merging -- typed addEventListener overloads merged below; no uninitialized properties.\nexport class Dropdown extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n private _floating = new PopoverController(this, {\n getTriggerElement: () => this._triggerEl,\n getFloatingElement: () => this._panelEl,\n getArrowElement: () => null,\n });\n\n private _typeaheadBuffer = '';\n private _typeaheadTimeout = 0;\n\n /** Whether the dropdown is open. */\n @property({ type: Boolean, reflect: true })\n accessor open = false;\n\n /** Preferred placement of the panel. */\n @property()\n accessor placement: Placement = 'bottom-start';\n\n /** Distance in pixels from the trigger. */\n @property({ type: Number })\n accessor distance = 4;\n\n /** Disables the dropdown trigger. */\n @property({ type: Boolean, reflect: true })\n accessor disabled = false;\n\n /**\n * Floor the panel's width at the trigger's width. Set to `trigger` so the\n * panel is never narrower than the trigger; it still grows with its content.\n * Useful for select-like triggers (a date-range or filter button) where the\n * panel should line up with the control. Re-applies if the trigger resizes\n * while open.\n */\n @property({ attribute: 'min-width' })\n accessor minWidth: 'trigger' | undefined;\n\n private get _triggerEl(): HTMLElement | null {\n const slot = this.shadowRoot!.querySelector<HTMLSlotElement>('.trigger slot');\n return (slot?.assignedElements()[0] as HTMLElement) ?? null;\n }\n\n private get _panelEl(): HTMLElement | null {\n return this.shadowRoot!.querySelector<HTMLElement>('[popover]');\n }\n\n private _getItems(): DropdownItem[] {\n const menuSlot = this.shadowRoot!.querySelector<HTMLSlotElement>('slot:not([name])');\n if (!menuSlot) return [];\n return (menuSlot.assignedElements() as DropdownItem[]).filter(\n (el) => el.tagName === tagName('dropdown-item').toUpperCase() && !el.disabled,\n );\n }\n\n private _getAllItems(): DropdownItem[] {\n const menuSlot = this.shadowRoot!.querySelector<HTMLSlotElement>('slot:not([name])');\n if (!menuSlot) return [];\n return (menuSlot.assignedElements() as DropdownItem[]).filter(\n (el) => el.tagName === tagName('dropdown-item').toUpperCase(),\n );\n }\n\n /** Every item in the menu tree, submenu items included (light-DOM descendants). */\n private _getAllItemsDeep(): DropdownItem[] {\n return [...this.querySelectorAll<DropdownItem>(tagName('dropdown-item'))];\n }\n\n /** The enabled items of the menu level `item` belongs to (its siblings, itself included). */\n private _levelItemsOf(item: DropdownItem): DropdownItem[] {\n const parent = item.parentElement;\n if (parent && parent.tagName === tagName('dropdown-item').toUpperCase()) {\n return (parent as DropdownItem).getSubmenuItems();\n }\n return this._getItems();\n }\n\n /** The parent item whose submenu contains `item`, or null at the root level. */\n private _parentItemOf(item: DropdownItem | null): DropdownItem | null {\n const parent = item?.parentElement;\n if (parent && parent.tagName === tagName('dropdown-item').toUpperCase()) {\n return parent as DropdownItem;\n }\n return null;\n }\n\n /** The enabled items of the level that currently holds focus (root level as fallback). */\n private _currentLevelItems(): DropdownItem[] {\n const current = this._getCurrentItem();\n return current ? this._levelItemsOf(current) : this._getItems();\n }\n\n private _getDuration(prop: '--show-duration' | '--hide-duration'): number {\n const parsed = parseFloat(getComputedStyle(this).getPropertyValue(prop));\n return Number.isNaN(parsed) ? 150 : parsed;\n }\n\n // --- Public API ---\n\n show() {\n if (this.open || this.disabled) return;\n if (this.dispatchEvent(new ShowEvent())) this.open = true;\n }\n\n hide() {\n if (!this.open) return;\n if (this.dispatchEvent(new HideEvent())) this.open = false;\n }\n\n toggle() {\n if (this.open) this.hide();\n else this.show();\n }\n\n // --- Lifecycle ---\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n clearTimeout(this._hoverTimer);\n this._hoverItem = null;\n }\n\n override updated(changed: PropertyValues<this>) {\n if (changed.has('open')) {\n void this._handleOpenChange();\n }\n }\n\n // --- Open/Close ---\n\n private async _handleOpenChange() {\n const panel = this._panelEl;\n if (!panel) return;\n\n const posOpts = {\n placement: this.placement,\n distance: this.distance,\n minWidth: this.minWidth,\n };\n\n if (this.open) {\n panel.showPopover();\n await this._floating.updatePosition(posOpts);\n if (!this.open) return;\n await this._floating.animateShow(panel, this._getDuration('--show-duration'));\n this._floating.startPositioning(posOpts);\n this._triggerEl?.setAttribute('aria-expanded', 'true');\n this.dispatchEvent(new AfterShowEvent());\n } else {\n this._floating.stopPositioning();\n this._closeAllSubmenus();\n this._triggerEl?.setAttribute('aria-expanded', 'false');\n await this._floating.animateHide(panel, this._getDuration('--hide-duration'));\n if (panel.matches(':popover-open')) panel.hidePopover();\n this.dispatchEvent(new AfterHideEvent());\n }\n }\n\n // --- Submenus ---\n\n private _hoverTimer = 0;\n private _hoverItem: DropdownItem | null = null;\n\n private async _openSubmenu(item: DropdownItem, { focus = false } = {}) {\n // A pending hover timer may fire after the menu closed or unmounted\n if (!this.open || !this.isConnected) return;\n // Only one submenu open per level. If a sibling we're about to close holds\n // the focus (keyboard focus inside it, mouse hovers another row), the panel\n // would vanish under the focus and drop it to <body> — move focus to `item`\n // first so the roving tabindex stays coherent.\n let stealsFocus = false;\n for (const sibling of this._levelItemsOf(item)) {\n if (sibling === item) continue;\n if (sibling.contains(document.activeElement)) stealsFocus = true;\n sibling.closeSubmenu();\n }\n if (stealsFocus && !focus) this._setActiveItem(item);\n item.openSubmenu();\n if (focus) {\n await item.updateComplete;\n const first = item.getSubmenuItems()[0];\n if (first) this._setActiveItem(first);\n }\n }\n\n private _closeAllSubmenus() {\n clearTimeout(this._hoverTimer);\n this._hoverItem = null;\n for (const item of this._getAllItems()) item.closeSubmenu();\n }\n\n /**\n * The item targeted by a pointer event, via the composed path. Returns null\n * for hits inside an item's submenu panel that miss every nested item row\n * (e.g. the panel padding) — those must not read as hits on the parent item.\n */\n private _itemFromEvent(e: Event): DropdownItem | null {\n const path = e.composedPath();\n const itemTag = tagName('dropdown-item').toUpperCase();\n const item =\n path.find((n): n is DropdownItem => n instanceof Element && n.tagName === itemTag) ?? null;\n if (!item) return null;\n const row = item.shadowRoot?.querySelector('.item');\n if (row && !path.includes(row)) {\n // The path reached the item host but not its row. Reject only when the\n // hit actually landed inside this item's own submenu panel (its padding),\n // which must not read as a selection of the parent item.\n //\n // Why not `return null` outright: a click dispatched on the host element\n // — `item.click()`, a synthetic MouseEvent, or a testing tool (Cypress,\n // Playwright) whose coordinate hit-test resolves to the host rather than\n // the inner row — produces a path with neither the row nor the submenu in\n // it. Such programmatic activation should still select the item. Checking\n // for the submenu explicitly (instead of the absent row) is also\n // retargeting-independent, so it holds regardless of which shadow tree the\n // listener sits in.\n const submenu = item.shadowRoot?.querySelector('.submenu');\n if (submenu && path.includes(submenu)) return null;\n }\n return item;\n }\n\n // --- Focus management ---\n\n private _setActiveItem(item: DropdownItem) {\n const itemEl = item.shadowRoot!.querySelector<HTMLElement>('.item');\n if (!itemEl) return;\n\n // Reset all items, submenu items included — one roving tabindex tree-wide\n for (const i of this._getAllItemsDeep()) {\n const el = i.shadowRoot!.querySelector<HTMLElement>('.item');\n el?.setAttribute('tabindex', '-1');\n }\n\n itemEl.setAttribute('tabindex', '0');\n itemEl.focus();\n\n // APG: moving focus within a level collapses any sibling's open submenu, so\n // an unfocused parent never keeps aria-expanded=\"true\". The active item's\n // own submenu (one level down) is untouched — `item` is not its own sibling.\n for (const sibling of this._levelItemsOf(item)) {\n if (sibling !== item) sibling.closeSubmenu();\n }\n }\n\n private _focusFirstItem(items = this._getItems()) {\n if (items.length) this._setActiveItem(items[0]);\n }\n\n private _focusLastItem(items = this._getItems()) {\n if (items.length) this._setActiveItem(items[items.length - 1]);\n }\n\n private _getCurrentItem(): DropdownItem | null {\n return (\n this._getAllItemsDeep().find((item) => {\n const el = item.shadowRoot!.querySelector<HTMLElement>('.item');\n return el?.getAttribute('tabindex') === '0' && item.shadowRoot!.activeElement === el;\n }) ?? null\n );\n }\n\n private _focusNextItem() {\n const items = this._currentLevelItems();\n const current = this._getCurrentItem();\n const index = current ? items.indexOf(current) : -1;\n const next = items[(index + 1) % items.length];\n if (next) this._setActiveItem(next);\n }\n\n private _focusPreviousItem() {\n const items = this._currentLevelItems();\n const current = this._getCurrentItem();\n const index = current ? items.indexOf(current) : 0;\n const prev = items[(index - 1 + items.length) % items.length];\n if (prev) this._setActiveItem(prev);\n }\n\n // --- Typeahead ---\n\n private _handleTypeahead(key: string) {\n clearTimeout(this._typeaheadTimeout);\n this._typeaheadBuffer += key.toLowerCase();\n this._typeaheadTimeout = window.setTimeout(() => {\n this._typeaheadBuffer = '';\n }, 500);\n\n const items = this._currentLevelItems();\n const match = items.find((item) =>\n item.getTextLabel().toLowerCase().startsWith(this._typeaheadBuffer),\n );\n if (match) this._setActiveItem(match);\n }\n\n // --- Event handlers ---\n\n /**\n * Expose menu-button semantics on whatever element is slotted as the trigger,\n * and give the root `role=\"menu\"` panel an accessible name derived from it.\n * Runs on initial assignment and on any runtime trigger swap.\n */\n private _onTriggerSlotChange = () => {\n const trigger = this._triggerEl;\n if (!trigger) return;\n trigger.setAttribute('aria-haspopup', 'menu');\n trigger.setAttribute('aria-expanded', String(this.open));\n\n // Cross-shadow aria-labelledby to the trigger is impossible, so copy its\n // accessible name onto the menu as a plain aria-label.\n const name = trigger.getAttribute('aria-label') ?? trigger.textContent?.trim() ?? '';\n const menu = this.shadowRoot?.querySelector<HTMLElement>('[role=\"menu\"]');\n if (menu && name) menu.setAttribute('aria-label', name);\n };\n\n private _onTriggerClick = (e: MouseEvent) => {\n if (this.disabled) return;\n this.toggle();\n // Space/Enter on a native button dispatches click with detail=0; focus the\n // first item so the menu is keyboard-navigable immediately on open.\n if (this.open && e.detail === 0) {\n requestAnimationFrame(() => this._focusFirstItem());\n }\n };\n\n private _onTriggerKeyDown = (e: KeyboardEvent) => {\n if (this.disabled) return;\n\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n this.show();\n requestAnimationFrame(() => this._focusFirstItem());\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n this.show();\n requestAnimationFrame(() => this._focusLastItem());\n }\n };\n\n private _onPanelKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n this._focusNextItem();\n break;\n case 'ArrowUp':\n e.preventDefault();\n this._focusPreviousItem();\n break;\n case 'Home':\n e.preventDefault();\n this._focusFirstItem(this._currentLevelItems());\n break;\n case 'End':\n e.preventDefault();\n this._focusLastItem(this._currentLevelItems());\n break;\n case 'ArrowRight': {\n const current = this._getCurrentItem();\n if (current?.hasSubmenu) {\n e.preventDefault();\n void this._openSubmenu(current, { focus: true });\n }\n break;\n }\n case 'ArrowLeft': {\n const parentItem = this._parentItemOf(this._getCurrentItem());\n if (parentItem) {\n e.preventDefault();\n parentItem.closeSubmenu();\n this._setActiveItem(parentItem);\n }\n break;\n }\n case 'Escape': {\n // Close one level at a time: a submenu first, the menu itself at the root\n e.preventDefault();\n const parentItem = this._parentItemOf(this._getCurrentItem());\n if (parentItem) {\n parentItem.closeSubmenu();\n this._setActiveItem(parentItem);\n } else {\n this.hide();\n this._triggerEl?.focus();\n }\n break;\n }\n case 'Tab':\n // APG: Tab closes the menu (and any open submenus, via the hide path)\n // and lets focus move to the next tab-sequence element naturally — so\n // no preventDefault and no focus return to the trigger.\n this.hide();\n break;\n case 'Enter':\n case ' ':\n e.preventDefault();\n this._selectCurrentItem();\n break;\n default:\n if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) {\n this._handleTypeahead(e.key);\n }\n }\n };\n\n private _onItemClick = (e: Event) => {\n const item = this._itemFromEvent(e);\n if (!item || item.disabled) return;\n if (item.hasSubmenu) {\n // A parent item toggles its submenu instead of selecting\n if (item.submenuOpen) item.closeSubmenu();\n else void this._openSubmenu(item);\n return;\n }\n this._selectItem(item);\n };\n\n /** Open submenus on hover after a short intent delay; hovering a sibling closes them. */\n private _onPanelPointerOver = (e: PointerEvent) => {\n // Touch taps fire pointerover too — they must only toggle via click,\n // or the hover timer would reopen a submenu the tap just closed.\n if (e.pointerType !== 'mouse') return;\n const item = this._itemFromEvent(e);\n if (item === this._hoverItem) return;\n clearTimeout(this._hoverTimer);\n this._hoverItem = item;\n if (!item || item.disabled) return;\n this._hoverTimer = window.setTimeout(() => {\n void this._openSubmenu(item);\n }, 100);\n };\n\n private _onPanelPointerOut = () => {\n clearTimeout(this._hoverTimer);\n this._hoverItem = null;\n };\n\n private _selectCurrentItem() {\n const current = this._getCurrentItem();\n if (!current) return;\n if (current.hasSubmenu) {\n void this._openSubmenu(current, { focus: true });\n } else {\n this._selectItem(current);\n }\n }\n\n private _selectItem(item: DropdownItem) {\n if (item.type === 'checkbox') {\n item.checked = !item.checked;\n }\n this.dispatchEvent(new DropdownSelectEvent(item));\n if (item.type !== 'checkbox') {\n this.hide();\n this._triggerEl?.focus();\n }\n }\n\n /** Sync `open` when popover=\"auto\" light-dismiss fires. */\n private _onToggle = (e: Event) => {\n const toggleEvent = e as ToggleEvent;\n if (toggleEvent.newState === 'closed' && this.open) {\n this.open = false;\n this._triggerEl?.setAttribute('aria-expanded', 'false');\n }\n };\n\n override render() {\n return html`\n <div\n class=\"trigger\"\n @click=${this._onTriggerClick}\n @keydown=${this._onTriggerKeyDown}\n >\n <slot\n name=\"trigger\"\n @slotchange=${this._onTriggerSlotChange}\n ></slot>\n </div>\n <div\n popover=\"auto\"\n part=\"panel\"\n @keydown=${this._onPanelKeyDown}\n @click=${this._onItemClick}\n @pointerover=${this._onPanelPointerOver}\n @pointerout=${this._onPanelPointerOut}\n @toggle=${this._onToggle}\n >\n <slot name=\"header\"></slot>\n <div role=\"menu\">\n <slot></slot>\n </div>\n <slot name=\"footer\"></slot>\n </div>\n `;\n }\n}\n\n// Types `addEventListener('select', …)` as `DropdownSelectEvent` on this element\n// (the global event map can't be augmented for the colliding name `select`).\n// See the Tabs interface in tabs.ts for the full rationale and the gotchas.\nexport interface Dropdown {\n addEventListener<K extends keyof DropdownEventMap>(\n type: K,\n listener: (this: Dropdown, ev: DropdownEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void;\n removeEventListener<K extends keyof DropdownEventMap>(\n type: K,\n listener: (this: Dropdown, ev: DropdownEventMap[K]) => void,\n options?: boolean | EventListenerOptions,\n ): void;\n removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"dropdown.js","names":[],"sources":["../../../src/html/elements/dropdown/dropdown.css?inline","../../../src/html/elements/dropdown/dropdown.ts"],"sourcesContent":[":host {\n --padding: 0.25rem;\n\n --background: var(--l-color-surface-overlay);\n --border-radius: 6px;\n --shadow: var(--l-shadow-md);\n --show-duration: 150;\n --hide-duration: 150;\n\n display: inline-block;\n position: relative;\n}\n\n.trigger {\n display: contents;\n}\n\n[popover] {\n inset: unset;\n overflow: visible;\n box-sizing: border-box;\n width: max-content;\n padding: var(--padding);\n margin: 0;\n border: 1px solid var(--l-color-border-overlay);\n border-radius: var(--border-radius);\n background: var(--background);\n color: var(--l-color-text-primary);\n box-shadow: var(--shadow);\n font-size: 0.875rem;\n line-height: 1.5;\n}\n\n/* Lightweight separator alternative to <l-divider> — same dimensions, no extra import. */\n::slotted(hr) {\n height: 1px;\n margin-block: var(--padding);\n margin-inline: calc(var(--padding) * -1);\n border: 0;\n background: var(--l-color-divider);\n}\n","import { html, unsafeCSS, type PropertyValues } from 'lit';\nimport { LuxenElement } from '../../shared/luxen-element.js';\nimport { property } from 'lit/decorators.js';\nimport type { Placement } from '@floating-ui/dom';\nimport { PopoverController } from '../../shared/controllers/popover.js';\nimport { tagName } from '../../registry.js';\nimport type { DropdownItem } from '../dropdown-item/dropdown-item.js';\nimport { ShowEvent, AfterShowEvent, HideEvent, AfterHideEvent } from '../../events/index.js';\nimport hostStyles from '../../shared/styles/host.styles.js';\nimport rawStyles from './dropdown.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/** Fired when a dropdown item is selected. Bubbles; not composed. */\nexport class DropdownSelectEvent extends Event {\n readonly item: DropdownItem;\n constructor(item: DropdownItem) {\n super('select', { bubbles: true, composed: false, cancelable: false });\n this.item = item;\n }\n}\n\ninterface DropdownEventMap {\n select: DropdownSelectEvent;\n}\n\n/**\n * A dropdown menu anchored to a trigger element.\n *\n * @slot trigger - The element that triggers the dropdown.\n * @slot header - Optional content rendered above the menu items (e.g. a user profile row). Use an `<l-divider>` (or `<hr>`) after it to separate from items.\n * @slot - Menu content (`l-dropdown-item` elements). Drop an `<l-divider>` (or `<hr>`) between items to render a section separator, or an `<l-dropdown-label>` to caption a group of items. Nest items with `slot=\"submenu\"` inside an item to create a submenu.\n * @slot footer - Optional content rendered below the menu items (e.g. a version label or shortcut row). Use an `<l-divider>` (or `<hr>`) before it to separate from items.\n *\n * @csspart panel - The floating menu container.\n *\n * @cssproperty --background - Panel background color.\n * @cssproperty --border-radius - Panel border radius. Default `8px`.\n * @cssproperty --padding - Panel inner padding. Default `0.25rem`. Slotted `<l-divider>` elements bleed by this amount on each side to span the panel edges.\n * @cssproperty --shadow - Panel box shadow.\n * @cssproperty --show-duration - Show animation duration in ms. Default `150`.\n * @cssproperty --hide-duration - Hide animation duration in ms. Default `150`.\n *\n * @event show - Fired before the dropdown opens. Cancelable.\n * @event after-show - Fired after the open animation completes.\n * @event hide - Fired before the dropdown closes. Cancelable.\n * @event after-hide - Fired after the close animation completes.\n * @event select - Fired when an item is selected, including items nested in submenus. Bubbles. Properties: `item: DropdownItem`.\n *\n * @customElement l-dropdown\n */\n// oxlint-disable-next-line typescript/no-unsafe-declaration-merging -- typed addEventListener overloads merged below; no uninitialized properties.\nexport class Dropdown extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n private _floating = new PopoverController(this, {\n getTriggerElement: () => this._triggerEl,\n getFloatingElement: () => this._panelEl,\n getArrowElement: () => null,\n });\n\n private _typeaheadBuffer = '';\n private _typeaheadTimeout = 0;\n\n /** Whether the dropdown is open. */\n @property({ type: Boolean, reflect: true })\n accessor open = false;\n\n /** Preferred placement of the panel. */\n @property()\n accessor placement: Placement = 'bottom-start';\n\n /** Distance in pixels from the trigger. */\n @property({ type: Number })\n accessor distance = 4;\n\n /** Disables the dropdown trigger. */\n @property({ type: Boolean, reflect: true })\n accessor disabled = false;\n\n /**\n * Floor the panel's width at the trigger's width. Set to `trigger` so the\n * panel is never narrower than the trigger; it still grows with its content.\n * Useful for select-like triggers (a date-range or filter button) where the\n * panel should line up with the control. Re-applies if the trigger resizes\n * while open.\n */\n @property({ attribute: 'min-width' })\n accessor minWidth: 'trigger' | undefined;\n\n private get _triggerEl(): HTMLElement | null {\n const slot = this.shadowRoot!.querySelector<HTMLSlotElement>('.trigger slot');\n return (slot?.assignedElements()[0] as HTMLElement) ?? null;\n }\n\n private get _panelEl(): HTMLElement | null {\n return this.shadowRoot!.querySelector<HTMLElement>('[popover]');\n }\n\n private _getItems(): DropdownItem[] {\n const menuSlot = this.shadowRoot!.querySelector<HTMLSlotElement>('slot:not([name])');\n if (!menuSlot) return [];\n return (menuSlot.assignedElements() as DropdownItem[]).filter(\n (el) => el.tagName === tagName('dropdown-item').toUpperCase() && !el.disabled,\n );\n }\n\n private _getAllItems(): DropdownItem[] {\n const menuSlot = this.shadowRoot!.querySelector<HTMLSlotElement>('slot:not([name])');\n if (!menuSlot) return [];\n return (menuSlot.assignedElements() as DropdownItem[]).filter(\n (el) => el.tagName === tagName('dropdown-item').toUpperCase(),\n );\n }\n\n /** Every item in the menu tree, submenu items included (light-DOM descendants). */\n private _getAllItemsDeep(): DropdownItem[] {\n return [...this.querySelectorAll<DropdownItem>(tagName('dropdown-item'))];\n }\n\n /** The enabled items of the menu level `item` belongs to (its siblings, itself included). */\n private _levelItemsOf(item: DropdownItem): DropdownItem[] {\n const parent = item.parentElement;\n if (parent && parent.tagName === tagName('dropdown-item').toUpperCase()) {\n return (parent as DropdownItem).getSubmenuItems();\n }\n return this._getItems();\n }\n\n /** The parent item whose submenu contains `item`, or null at the root level. */\n private _parentItemOf(item: DropdownItem | null): DropdownItem | null {\n const parent = item?.parentElement;\n if (parent && parent.tagName === tagName('dropdown-item').toUpperCase()) {\n return parent as DropdownItem;\n }\n return null;\n }\n\n /** The enabled items of the level that currently holds focus (root level as fallback). */\n private _currentLevelItems(): DropdownItem[] {\n const current = this._getCurrentItem();\n return current ? this._levelItemsOf(current) : this._getItems();\n }\n\n private _getDuration(prop: '--show-duration' | '--hide-duration'): number {\n const parsed = parseFloat(getComputedStyle(this).getPropertyValue(prop));\n return Number.isNaN(parsed) ? 150 : parsed;\n }\n\n // --- Public API ---\n\n show() {\n if (this.open || this.disabled) return;\n if (this.dispatchEvent(new ShowEvent())) this.open = true;\n }\n\n hide() {\n if (!this.open) return;\n if (this.dispatchEvent(new HideEvent())) this.open = false;\n }\n\n toggle() {\n if (this.open) this.hide();\n else this.show();\n }\n\n // --- Lifecycle ---\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n clearTimeout(this._hoverTimer);\n this._hoverItem = null;\n }\n\n override updated(changed: PropertyValues<this>) {\n if (changed.has('open')) {\n void this._handleOpenChange();\n }\n }\n\n // --- Open/Close ---\n\n private async _handleOpenChange() {\n const panel = this._panelEl;\n if (!panel) return;\n\n const posOpts = {\n placement: this.placement,\n distance: this.distance,\n minWidth: this.minWidth,\n };\n\n if (this.open) {\n panel.showPopover();\n await this._floating.updatePosition(posOpts);\n if (!this.open) return;\n await this._floating.animateShow(panel, this._getDuration('--show-duration'));\n this._floating.startPositioning(posOpts);\n this._triggerEl?.setAttribute('aria-expanded', 'true');\n this.dispatchEvent(new AfterShowEvent());\n } else {\n this._floating.stopPositioning();\n this._closeAllSubmenus();\n this._triggerEl?.setAttribute('aria-expanded', 'false');\n await this._floating.animateHide(panel, this._getDuration('--hide-duration'));\n if (panel.matches(':popover-open')) panel.hidePopover();\n this.dispatchEvent(new AfterHideEvent());\n }\n }\n\n // --- Submenus ---\n\n private _hoverTimer = 0;\n private _hoverItem: DropdownItem | null = null;\n\n private async _openSubmenu(item: DropdownItem, { focus = false } = {}) {\n // A pending hover timer may fire after the menu closed or unmounted\n if (!this.open || !this.isConnected) return;\n // Only one submenu open per level. If a sibling we're about to close holds\n // the focus (keyboard focus inside it, mouse hovers another row), the panel\n // would vanish under the focus and drop it to <body> — move focus to `item`\n // first so the roving tabindex stays coherent.\n let stealsFocus = false;\n for (const sibling of this._levelItemsOf(item)) {\n if (sibling === item) continue;\n if (sibling.contains(document.activeElement)) stealsFocus = true;\n sibling.closeSubmenu();\n }\n if (stealsFocus && !focus) this._setActiveItem(item);\n item.openSubmenu();\n if (focus) {\n await item.updateComplete;\n const first = item.getSubmenuItems()[0];\n if (first) this._setActiveItem(first);\n }\n }\n\n private _closeAllSubmenus() {\n clearTimeout(this._hoverTimer);\n this._hoverItem = null;\n for (const item of this._getAllItems()) item.closeSubmenu();\n }\n\n /**\n * The item targeted by a pointer event, via the composed path. Returns null\n * for hits inside an item's submenu panel that miss every nested item row\n * (e.g. the panel padding) — those must not read as hits on the parent item.\n */\n private _itemFromEvent(e: Event): DropdownItem | null {\n const path = e.composedPath();\n const itemTag = tagName('dropdown-item').toUpperCase();\n const item =\n path.find((n): n is DropdownItem => n instanceof Element && n.tagName === itemTag) ?? null;\n if (!item) return null;\n const row = item.shadowRoot?.querySelector('.item');\n if (row && !path.includes(row)) {\n // The path reached the item host but not its row. Reject only when the\n // hit actually landed inside this item's own submenu panel (its padding),\n // which must not read as a selection of the parent item.\n //\n // Why not `return null` outright: a click dispatched on the host element\n // — `item.click()`, a synthetic MouseEvent, or a testing tool (Cypress,\n // Playwright) whose coordinate hit-test resolves to the host rather than\n // the inner row — produces a path with neither the row nor the submenu in\n // it. Such programmatic activation should still select the item. Checking\n // for the submenu explicitly (instead of the absent row) is also\n // retargeting-independent, so it holds regardless of which shadow tree the\n // listener sits in.\n const submenu = item.shadowRoot?.querySelector('.submenu');\n if (submenu && path.includes(submenu)) return null;\n }\n return item;\n }\n\n // --- Focus management ---\n\n private _setActiveItem(item: DropdownItem) {\n const itemEl = item.shadowRoot!.querySelector<HTMLElement>('.item');\n if (!itemEl) return;\n\n // Reset all items, submenu items included — one roving tabindex tree-wide\n for (const i of this._getAllItemsDeep()) {\n const el = i.shadowRoot!.querySelector<HTMLElement>('.item');\n el?.setAttribute('tabindex', '-1');\n }\n\n itemEl.setAttribute('tabindex', '0');\n itemEl.focus();\n\n // APG: moving focus within a level collapses any sibling's open submenu, so\n // an unfocused parent never keeps aria-expanded=\"true\". The active item's\n // own submenu (one level down) is untouched — `item` is not its own sibling.\n for (const sibling of this._levelItemsOf(item)) {\n if (sibling !== item) sibling.closeSubmenu();\n }\n }\n\n private _focusFirstItem(items = this._getItems()) {\n if (items.length) this._setActiveItem(items[0]);\n }\n\n private _focusLastItem(items = this._getItems()) {\n if (items.length) this._setActiveItem(items[items.length - 1]);\n }\n\n private _getCurrentItem(): DropdownItem | null {\n return (\n this._getAllItemsDeep().find((item) => {\n const el = item.shadowRoot!.querySelector<HTMLElement>('.item');\n return el?.getAttribute('tabindex') === '0' && item.shadowRoot!.activeElement === el;\n }) ?? null\n );\n }\n\n private _focusNextItem() {\n const items = this._currentLevelItems();\n const current = this._getCurrentItem();\n const index = current ? items.indexOf(current) : -1;\n const next = items[(index + 1) % items.length];\n if (next) this._setActiveItem(next);\n }\n\n private _focusPreviousItem() {\n const items = this._currentLevelItems();\n const current = this._getCurrentItem();\n const index = current ? items.indexOf(current) : 0;\n const prev = items[(index - 1 + items.length) % items.length];\n if (prev) this._setActiveItem(prev);\n }\n\n // --- Typeahead ---\n\n private _handleTypeahead(key: string) {\n clearTimeout(this._typeaheadTimeout);\n this._typeaheadBuffer += key.toLowerCase();\n this._typeaheadTimeout = window.setTimeout(() => {\n this._typeaheadBuffer = '';\n }, 500);\n\n const items = this._currentLevelItems();\n const match = items.find((item) =>\n item.getTextLabel().toLowerCase().startsWith(this._typeaheadBuffer),\n );\n if (match) this._setActiveItem(match);\n }\n\n // --- Event handlers ---\n\n /**\n * Expose menu-button semantics on whatever element is slotted as the trigger,\n * and give the root `role=\"menu\"` panel an accessible name derived from it.\n * Runs on initial assignment and on any runtime trigger swap.\n */\n private _onTriggerSlotChange = () => {\n const trigger = this._triggerEl;\n if (!trigger) return;\n trigger.setAttribute('aria-haspopup', 'menu');\n trigger.setAttribute('aria-expanded', String(this.open));\n\n // Cross-shadow aria-labelledby to the trigger is impossible, so copy its\n // accessible name onto the menu as a plain aria-label.\n const name = trigger.getAttribute('aria-label') ?? trigger.textContent?.trim() ?? '';\n const menu = this.shadowRoot?.querySelector<HTMLElement>('[role=\"menu\"]');\n if (menu && name) menu.setAttribute('aria-label', name);\n };\n\n private _onTriggerClick = (e: MouseEvent) => {\n if (this.disabled) return;\n // The pointerdown that produced this click already light-dismissed the panel:\n // `open` still reads true, but the panel has left the top layer and the\n // queued `toggle` owns the close (and its `hide` event). Closing here too\n // would emit a second one. A keyboard activation never gets here — no\n // light-dismiss, so the panel is still open.\n if (this.open && !this._panelEl?.matches(':popover-open')) return;\n this.toggle();\n // Space/Enter on a native button dispatches click with detail=0; focus the\n // first item so the menu is keyboard-navigable immediately on open.\n if (this.open && e.detail === 0) {\n requestAnimationFrame(() => this._focusFirstItem());\n }\n };\n\n private _onTriggerKeyDown = (e: KeyboardEvent) => {\n if (this.disabled) return;\n\n if (e.key === 'Escape') {\n // A pointer-opened menu leaves focus on the trigger, so `_onPanelKeyDown`\n // never sees the key. The platform's popover light-dismiss normally covers\n // that, but it runs as a close request the page can suppress — any\n // `preventDefault()` on the Escape keydown (a common app-level shortcut\n // handler) leaves the menu stuck open. Close it here, and preventDefault\n // so the close request doesn't race our animated hide.\n if (!this.open) return;\n e.preventDefault();\n this.hide();\n // Focus is already on the trigger — nothing to restore.\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n this.show();\n requestAnimationFrame(() => this._focusFirstItem());\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n this.show();\n requestAnimationFrame(() => this._focusLastItem());\n }\n };\n\n private _onPanelKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n this._focusNextItem();\n break;\n case 'ArrowUp':\n e.preventDefault();\n this._focusPreviousItem();\n break;\n case 'Home':\n e.preventDefault();\n this._focusFirstItem(this._currentLevelItems());\n break;\n case 'End':\n e.preventDefault();\n this._focusLastItem(this._currentLevelItems());\n break;\n case 'ArrowRight': {\n const current = this._getCurrentItem();\n if (current?.hasSubmenu) {\n e.preventDefault();\n void this._openSubmenu(current, { focus: true });\n }\n break;\n }\n case 'ArrowLeft': {\n const parentItem = this._parentItemOf(this._getCurrentItem());\n if (parentItem) {\n e.preventDefault();\n parentItem.closeSubmenu();\n this._setActiveItem(parentItem);\n }\n break;\n }\n case 'Escape': {\n // Close one level at a time: a submenu first, the menu itself at the root\n e.preventDefault();\n const parentItem = this._parentItemOf(this._getCurrentItem());\n if (parentItem) {\n parentItem.closeSubmenu();\n this._setActiveItem(parentItem);\n } else {\n this.hide();\n this._triggerEl?.focus();\n }\n break;\n }\n case 'Tab':\n // APG: Tab closes the menu (and any open submenus, via the hide path)\n // and lets focus move to the next tab-sequence element naturally — so\n // no preventDefault and no focus return to the trigger.\n this.hide();\n break;\n case 'Enter':\n case ' ':\n e.preventDefault();\n this._selectCurrentItem();\n break;\n default:\n if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) {\n this._handleTypeahead(e.key);\n }\n }\n };\n\n private _onItemClick = (e: Event) => {\n const item = this._itemFromEvent(e);\n if (!item || item.disabled) return;\n if (item.hasSubmenu) {\n // A parent item toggles its submenu instead of selecting\n if (item.submenuOpen) item.closeSubmenu();\n else void this._openSubmenu(item);\n return;\n }\n this._selectItem(item);\n };\n\n /** Open submenus on hover after a short intent delay; hovering a sibling closes them. */\n private _onPanelPointerOver = (e: PointerEvent) => {\n // Touch taps fire pointerover too — they must only toggle via click,\n // or the hover timer would reopen a submenu the tap just closed.\n if (e.pointerType !== 'mouse') return;\n const item = this._itemFromEvent(e);\n if (item === this._hoverItem) return;\n clearTimeout(this._hoverTimer);\n this._hoverItem = item;\n if (!item || item.disabled) return;\n this._hoverTimer = window.setTimeout(() => {\n void this._openSubmenu(item);\n }, 100);\n };\n\n private _onPanelPointerOut = () => {\n clearTimeout(this._hoverTimer);\n this._hoverItem = null;\n };\n\n private _selectCurrentItem() {\n const current = this._getCurrentItem();\n if (!current) return;\n if (current.hasSubmenu) {\n void this._openSubmenu(current, { focus: true });\n } else {\n this._selectItem(current);\n }\n }\n\n private _selectItem(item: DropdownItem) {\n if (item.type === 'checkbox') {\n item.checked = !item.checked;\n }\n this.dispatchEvent(new DropdownSelectEvent(item));\n if (item.type !== 'checkbox') {\n this.hide();\n this._triggerEl?.focus();\n }\n }\n\n /**\n * Route `popover=\"auto\"` light-dismiss through the same close path as every\n * other user-driven close (trigger click, Escape, item selection), so the\n * cancelable `hide` event fires for it too. Assigning `open` here directly\n * would skip it and desync anything a consumer syncs on `hide`.\n *\n * Driving `open` as a property or attribute still closes the menu with only\n * `after-hide` — `l-dialog` mediates that path from `updated()`, this element\n * does not. A gap worth closing on its own.\n *\n * The platform makes a popover's close non-cancelable (`beforetoggle` is only\n * cancelable when opening), so a vetoed `hide` is honored by putting the panel\n * back. `toggle` is the right hook for that: it is queued after the hide has\n * actually been applied, whereas during `beforetoggle` the panel is still\n * `:popover-open` and `showPopover()` would be a no-op the pending hide undoes.\n */\n private _onToggle = (e: Event) => {\n const toggleEvent = e as ToggleEvent;\n // Our own close path flips `open` before hiding the popover, so this guard\n // keeps it from emitting a second `hide` for the same close.\n if (toggleEvent.newState !== 'closed' || !this.open) return;\n\n if (this.dispatchEvent(new HideEvent())) {\n this.open = false;\n return;\n }\n const panel = this._panelEl;\n if (panel?.isConnected) panel.showPopover();\n };\n\n override render() {\n return html`\n <div\n class=\"trigger\"\n @click=${this._onTriggerClick}\n @keydown=${this._onTriggerKeyDown}\n >\n <slot\n name=\"trigger\"\n @slotchange=${this._onTriggerSlotChange}\n ></slot>\n </div>\n <div\n popover=\"auto\"\n part=\"panel\"\n @keydown=${this._onPanelKeyDown}\n @click=${this._onItemClick}\n @pointerover=${this._onPanelPointerOver}\n @pointerout=${this._onPanelPointerOut}\n @toggle=${this._onToggle}\n >\n <slot name=\"header\"></slot>\n <div role=\"menu\">\n <slot></slot>\n </div>\n <slot name=\"footer\"></slot>\n </div>\n `;\n }\n}\n\n// Types `addEventListener('select', …)` as `DropdownSelectEvent` on this element\n// (the global event map can't be augmented for the colliding name `select`).\n// See the Tabs interface in tabs.ts for the full rationale and the gotchas.\nexport interface Dropdown {\n addEventListener<K extends keyof DropdownEventMap>(\n type: K,\n listener: (this: Dropdown, ev: DropdownEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void;\n removeEventListener<K extends keyof DropdownEventMap>(\n type: K,\n listener: (this: Dropdown, ev: DropdownEventMap[K]) => void,\n options?: boolean | EventListenerOptions,\n ): void;\n removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void;\n}\n"],"mappings":"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"}