luxen-ui 0.18.0 → 0.18.2

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": [
@@ -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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"}
@@ -98,6 +98,13 @@ export class Dropdown extends LuxenElement {
98
98
  this._onTriggerClick = (e) => {
99
99
  if (this.disabled)
100
100
  return;
101
+ // The pointerdown that produced this click already light-dismissed the panel:
102
+ // `open` still reads true, but the panel has left the top layer and the
103
+ // queued `toggle` owns the close (and its `hide` event). Closing here too
104
+ // would emit a second one. A keyboard activation never gets here — no
105
+ // light-dismiss, so the panel is still open.
106
+ if (this.open && !this._panelEl?.matches(':popover-open'))
107
+ return;
101
108
  this.toggle();
102
109
  // Space/Enter on a native button dispatches click with detail=0; focus the
103
110
  // first item so the menu is keyboard-navigable immediately on open.
@@ -108,7 +115,20 @@ export class Dropdown extends LuxenElement {
108
115
  this._onTriggerKeyDown = (e) => {
109
116
  if (this.disabled)
110
117
  return;
111
- if (e.key === 'ArrowDown') {
118
+ if (e.key === 'Escape') {
119
+ // A pointer-opened menu leaves focus on the trigger, so `_onPanelKeyDown`
120
+ // never sees the key. The platform's popover light-dismiss normally covers
121
+ // that, but it runs as a close request the page can suppress — any
122
+ // `preventDefault()` on the Escape keydown (a common app-level shortcut
123
+ // handler) leaves the menu stuck open. Close it here, and preventDefault
124
+ // so the close request doesn't race our animated hide.
125
+ if (!this.open)
126
+ return;
127
+ e.preventDefault();
128
+ this.hide();
129
+ // Focus is already on the trigger — nothing to restore.
130
+ }
131
+ else if (e.key === 'ArrowDown') {
112
132
  e.preventDefault();
113
133
  this.show();
114
134
  requestAnimationFrame(() => this._focusFirstItem());
@@ -220,13 +240,35 @@ export class Dropdown extends LuxenElement {
220
240
  clearTimeout(this._hoverTimer);
221
241
  this._hoverItem = null;
222
242
  };
223
- /** Sync `open` when popover="auto" light-dismiss fires. */
243
+ /**
244
+ * Route `popover="auto"` light-dismiss through the same close path as every
245
+ * other user-driven close (trigger click, Escape, item selection), so the
246
+ * cancelable `hide` event fires for it too. Assigning `open` here directly
247
+ * would skip it and desync anything a consumer syncs on `hide`.
248
+ *
249
+ * Driving `open` as a property or attribute still closes the menu with only
250
+ * `after-hide` — `l-dialog` mediates that path from `updated()`, this element
251
+ * does not. A gap worth closing on its own.
252
+ *
253
+ * The platform makes a popover's close non-cancelable (`beforetoggle` is only
254
+ * cancelable when opening), so a vetoed `hide` is honored by putting the panel
255
+ * back. `toggle` is the right hook for that: it is queued after the hide has
256
+ * actually been applied, whereas during `beforetoggle` the panel is still
257
+ * `:popover-open` and `showPopover()` would be a no-op the pending hide undoes.
258
+ */
224
259
  this._onToggle = (e) => {
225
260
  const toggleEvent = e;
226
- if (toggleEvent.newState === 'closed' && this.open) {
261
+ // Our own close path flips `open` before hiding the popover, so this guard
262
+ // keeps it from emitting a second `hide` for the same close.
263
+ if (toggleEvent.newState !== 'closed' || !this.open)
264
+ return;
265
+ if (this.dispatchEvent(new HideEvent())) {
227
266
  this.open = false;
228
- this._triggerEl?.setAttribute('aria-expanded', 'false');
267
+ return;
229
268
  }
269
+ const panel = this._panelEl;
270
+ if (panel?.isConnected)
271
+ panel.showPopover();
230
272
  };
231
273
  }
232
274
  /** Whether the dropdown is open. */
@@ -34,6 +34,8 @@ interface TabsEventMap {
34
34
  * @cssproperty [--indicator-thickness=2px] - `line` variant: thickness of the active underline.
35
35
  * @cssproperty [--track-color=var(--l-color-border)] - `line` variant: color of the static bottom border the tabs sit on.
36
36
  * @cssproperty [--track-thickness=1px] - `line` variant: thickness of the static bottom border.
37
+ * @cssproperty [--hover-color=var(--l-color-bg-state-hover)] - `line` variant: fill of the pill that appears behind a hovered tab label.
38
+ * @cssproperty [--hover-inset=4px] - `line` variant: block-axis gap between the hover pill and the tab edges, keeping it detached from the bottom border.
37
39
  *
38
40
  * @customElement l-tabs
39
41
  */
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tabs/tabs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAG7D,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;AAC9C,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,UAAU,CAAC;AAExD,gEAAgE;AAChE,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;gBACjB,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;CAK/C;AAED,UAAU,YAAY;IACpB,MAAM,EAAE,eAAe,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,qBAAa,IAAK,SAAQ,YAAY;IAC3B,gBAAgB;IAIzB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,eAAe,CAA+B;IAEtD,sBAAsB;IAEtB,OAAO,EAAE,WAAW,CAAU;IAE9B,yCAAyC;IAEzC,KAAK,SAAO;IAEZ,4CAA4C;IAE5C,SAAS,UAAS;IAElB,uBAAuB;IAEvB,WAAW,EAAE,eAAe,CAAgB;IAInC,iBAAiB;IAUjB,oBAAoB;IAM7B,mFAAmF;IACnF,OAAO,CAAC,SAAS;IAOR,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAW9C,OAAO,CAAC,MAAM;IA0Dd,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,UAAU;IA2BlB,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,QAAQ,CAQd;IAEF,OAAO,CAAC,UAAU,CAkChB;CACH;AA8BD,MAAM,WAAW,IAAI;IACnB,gBAAgB,CAAC,CAAC,SAAS,MAAM,YAAY,EAC3C,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,EACnD,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;IACR,gBAAgB,CACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,kCAAkC,EAC5C,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;IACR,mBAAmB,CAAC,CAAC,SAAS,MAAM,YAAY,EAC9C,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,EACnD,OAAO,CAAC,EAAE,OAAO,GAAG,oBAAoB,GACvC,IAAI,CAAC;IACR,mBAAmB,CACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,kCAAkC,EAC5C,OAAO,CAAC,EAAE,OAAO,GAAG,oBAAoB,GACvC,IAAI,CAAC;CACT"}
1
+ {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tabs/tabs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAG7D,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;AAC9C,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,UAAU,CAAC;AAExD,gEAAgE;AAChE,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;gBACjB,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;CAK/C;AAED,UAAU,YAAY;IACpB,MAAM,EAAE,eAAe,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,qBAAa,IAAK,SAAQ,YAAY;IAC3B,gBAAgB;IAIzB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,eAAe,CAA+B;IAEtD,sBAAsB;IAEtB,OAAO,EAAE,WAAW,CAAU;IAE9B,yCAAyC;IAEzC,KAAK,SAAO;IAEZ,4CAA4C;IAE5C,SAAS,UAAS;IAElB,uBAAuB;IAEvB,WAAW,EAAE,eAAe,CAAgB;IAInC,iBAAiB;IAUjB,oBAAoB;IAM7B,mFAAmF;IACnF,OAAO,CAAC,SAAS;IAOR,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAW9C,OAAO,CAAC,MAAM;IA0Dd,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,UAAU;IA2BlB,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,QAAQ,CAQd;IAEF,OAAO,CAAC,UAAU,CAkChB;CACH;AA8BD,MAAM,WAAW,IAAI;IACnB,gBAAgB,CAAC,CAAC,SAAS,MAAM,YAAY,EAC3C,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,EACnD,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;IACR,gBAAgB,CACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,kCAAkC,EAC5C,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;IACR,mBAAmB,CAAC,CAAC,SAAS,MAAM,YAAY,EAC9C,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,EACnD,OAAO,CAAC,EAAE,OAAO,GAAG,oBAAoB,GACvC,IAAI,CAAC;IACR,mBAAmB,CACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,kCAAkC,EAC5C,OAAO,CAAC,EAAE,OAAO,GAAG,oBAAoB,GACvC,IAAI,CAAC;CACT"}
@@ -39,6 +39,8 @@ export class TabsChangeEvent extends Event {
39
39
  * @cssproperty [--indicator-thickness=2px] - `line` variant: thickness of the active underline.
40
40
  * @cssproperty [--track-color=var(--l-color-border)] - `line` variant: color of the static bottom border the tabs sit on.
41
41
  * @cssproperty [--track-thickness=1px] - `line` variant: thickness of the static bottom border.
42
+ * @cssproperty [--hover-color=var(--l-color-bg-state-hover)] - `line` variant: fill of the pill that appears behind a hovered tab label.
43
+ * @cssproperty [--hover-inset=4px] - `line` variant: block-axis gap between the hover pill and the tab edges, keeping it detached from the bottom border.
42
44
  *
43
45
  * @customElement l-tabs
44
46
  */
@@ -87,11 +87,25 @@ export declare class Tag extends LuxenElement {
87
87
  accessor control: TagControl;
88
88
  /** Disable the tag — dims it and blocks selection and removal. */
89
89
  accessor disabled: boolean;
90
+ constructor();
90
91
  willUpdate(): void;
91
92
  updated(): void;
92
93
  private _requestRemove;
93
94
  private _onKeyDown;
94
95
  private _toggle;
96
+ /**
97
+ * Events do not propagate *down* into a shadow tree, so a click dispatched on
98
+ * the host — `tag.click()`, a test runner resolving the chip by its test id,
99
+ * a runner computing the chip's centre (`elementFromPoint()` retargets shadow
100
+ * content back to the host) — never reaches the toggle button or the
101
+ * checkbox, and silently does nothing. Delegate it.
102
+ *
103
+ * Only when the host *is* the target: a real gesture originates at the inner
104
+ * button, at the checkbox, or at slotted content, and is already handled
105
+ * where it lands — so this never double-toggles. `removable` stays out of it;
106
+ * removing is the × button's own gesture.
107
+ */
108
+ private _onHostClick;
95
109
  private _onCheckboxChange;
96
110
  private _label;
97
111
  private _removeButton;
@@ -1 +1 @@
1
- {"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tag/tag.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAS7D,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACzC,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC;AAE7C;;;;;GAKG;AACH,qBAAa,cAAe,SAAQ,KAAK;;CAIxC;AAED,uEAAuE;AACvE,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;gBACf,QAAQ,EAAE,OAAO;CAI9B;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,2BAA2B;QACnC,MAAM,EAAE,cAAc,CAAC;KACxB;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,qBAAa,GAAI,SAAQ,YAAY;IACnC,OAAgB,MAAM,4BAA4C;IAElE,OAAO,CAAC,SAAS,CAAgC;IAEjD,+CAA+C;IAE/C,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAQ;IAE9B,kEAAkE;IAElE,QAAQ,CAAC,SAAS,UAAS;IAE3B,oEAAoE;IAEpE,QAAQ,CAAC,UAAU,UAAS;IAE5B,4EAA4E;IAE5E,QAAQ,CAAC,QAAQ,UAAS;IAE1B;;;;OAIG;IAEH,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAU;IAEtC,kEAAkE;IAElE,QAAQ,CAAC,QAAQ,UAAS;IAEjB,UAAU;IAOV,OAAO;IAWhB,OAAO,CAAC,cAAc,CAKpB;IAEF,OAAO,CAAC,UAAU,CAMhB;IAEF,OAAO,CAAC,OAAO,CAKb;IAEF,OAAO,CAAC,iBAAiB,CAGvB;IAEF,OAAO,CAAC,MAAM;IAad,OAAO,CAAC,aAAa;IAaZ,MAAM;CAqDhB;AAQD,MAAM,WAAW,GAAG;IAClB,gBAAgB,CAAC,CAAC,SAAS,MAAM,WAAW,EAC1C,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI,EACjD,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;IACR,gBAAgB,CACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,kCAAkC,EAC5C,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;IACR,mBAAmB,CAAC,CAAC,SAAS,MAAM,WAAW,EAC7C,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI,EACjD,OAAO,CAAC,EAAE,OAAO,GAAG,oBAAoB,GACvC,IAAI,CAAC;IACR,mBAAmB,CACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,kCAAkC,EAC5C,OAAO,CAAC,EAAE,OAAO,GAAG,oBAAoB,GACvC,IAAI,CAAC;CACT"}
1
+ {"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tag/tag.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAS7D,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACzC,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC;AAE7C;;;;;GAKG;AACH,qBAAa,cAAe,SAAQ,KAAK;;CAIxC;AAED,uEAAuE;AACvE,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;gBACf,QAAQ,EAAE,OAAO;CAI9B;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,2BAA2B;QACnC,MAAM,EAAE,cAAc,CAAC;KACxB;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,qBAAa,GAAI,SAAQ,YAAY;IACnC,OAAgB,MAAM,4BAA4C;IAElE,OAAO,CAAC,SAAS,CAAgC;IAEjD,+CAA+C;IAE/C,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAQ;IAE9B,kEAAkE;IAElE,QAAQ,CAAC,SAAS,UAAS;IAE3B,oEAAoE;IAEpE,QAAQ,CAAC,UAAU,UAAS;IAE5B,4EAA4E;IAE5E,QAAQ,CAAC,QAAQ,UAAS;IAE1B;;;;OAIG;IAEH,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAU;IAEtC,kEAAkE;IAElE,QAAQ,CAAC,QAAQ,UAAS;;IASjB,UAAU;IAOV,OAAO;IAWhB,OAAO,CAAC,cAAc,CAKpB;IAEF,OAAO,CAAC,UAAU,CAMhB;IAEF,OAAO,CAAC,OAAO,CAKb;IAEF;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,YAAY,CAMlB;IAEF,OAAO,CAAC,iBAAiB,CAGvB;IAEF,OAAO,CAAC,MAAM;IAad,OAAO,CAAC,aAAa;IAaZ,MAAM;CAqDhB;AAQD,MAAM,WAAW,GAAG;IAClB,gBAAgB,CAAC,CAAC,SAAS,MAAM,WAAW,EAC1C,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI,EACjD,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;IACR,gBAAgB,CACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,kCAAkC,EAC5C,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;IACR,mBAAmB,CAAC,CAAC,SAAS,MAAM,WAAW,EAC7C,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI,EACjD,OAAO,CAAC,EAAE,OAAO,GAAG,oBAAoB,GACvC,IAAI,CAAC;IACR,mBAAmB,CACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,kCAAkC,EAC5C,OAAO,CAAC,EAAE,OAAO,GAAG,oBAAoB,GACvC,IAAI,CAAC;CACT"}
@@ -90,8 +90,30 @@ export class TagChangeEvent extends Event {
90
90
  */
91
91
  // oxlint-disable-next-line typescript/no-unsafe-declaration-merging -- typed addEventListener overloads merged below; no uninitialized properties.
92
92
  export class Tag extends LuxenElement {
93
+ /** Tag size: `sm`, `md` (default), or `lg`. */
94
+ get size() { return __classPrivateFieldGet(this, _Tag_size_accessor_storage, "f"); }
95
+ set size(value) { __classPrivateFieldSet(this, _Tag_size_accessor_storage, value, "f"); }
96
+ /** Show a remove button (and enable Backspace/Delete removal). */
97
+ get removable() { return __classPrivateFieldGet(this, _Tag_removable_accessor_storage, "f"); }
98
+ set removable(value) { __classPrivateFieldSet(this, _Tag_removable_accessor_storage, value, "f"); }
99
+ /** Make the tag a filter control the user can toggle on and off. */
100
+ get selectable() { return __classPrivateFieldGet(this, _Tag_selectable_accessor_storage, "f"); }
101
+ set selectable(value) { __classPrivateFieldSet(this, _Tag_selectable_accessor_storage, value, "f"); }
102
+ /** Whether the tag is selected. Reflected, so `[selected]` is styleable. */
103
+ get selected() { return __classPrivateFieldGet(this, _Tag_selected_accessor_storage, "f"); }
104
+ set selected(value) { __classPrivateFieldSet(this, _Tag_selected_accessor_storage, value, "f"); }
105
+ /**
106
+ * What drives the selection: `none` (default) makes the chip itself a toggle
107
+ * button; `checkbox` renders a checkbox inside and makes the chip its label —
108
+ * the right choice for a multi-select facet. Implies `selectable`.
109
+ */
110
+ get control() { return __classPrivateFieldGet(this, _Tag_control_accessor_storage, "f"); }
111
+ set control(value) { __classPrivateFieldSet(this, _Tag_control_accessor_storage, value, "f"); }
112
+ /** Disable the tag — dims it and blocks selection and removal. */
113
+ get disabled() { return __classPrivateFieldGet(this, _Tag_disabled_accessor_storage, "f"); }
114
+ set disabled(value) { __classPrivateFieldSet(this, _Tag_disabled_accessor_storage, value, "f"); }
93
115
  constructor() {
94
- super(...arguments);
116
+ super();
95
117
  this._localize = new LocalizeController(this);
96
118
  _Tag_size_accessor_storage.set(this, 'md');
97
119
  _Tag_removable_accessor_storage.set(this, false);
@@ -122,33 +144,35 @@ export class Tag extends LuxenElement {
122
144
  this.selected = !this.selected;
123
145
  this.dispatchEvent(new TagChangeEvent(this.selected));
124
146
  };
147
+ /**
148
+ * Events do not propagate *down* into a shadow tree, so a click dispatched on
149
+ * the host — `tag.click()`, a test runner resolving the chip by its test id,
150
+ * a runner computing the chip's centre (`elementFromPoint()` retargets shadow
151
+ * content back to the host) — never reaches the toggle button or the
152
+ * checkbox, and silently does nothing. Delegate it.
153
+ *
154
+ * Only when the host *is* the target: a real gesture originates at the inner
155
+ * button, at the checkbox, or at slotted content, and is already handled
156
+ * where it lands — so this never double-toggles. `removable` stays out of it;
157
+ * removing is the × button's own gesture.
158
+ */
159
+ this._onHostClick = (e) => {
160
+ if (!this.selectable || this.disabled)
161
+ return;
162
+ if (e.composedPath()[0] !== this)
163
+ return;
164
+ // Right for `control="checkbox"` too: `_toggle()` flips `selected` and
165
+ // fires `change`, and `updated()` re-asserts `box.checked` from it.
166
+ this._toggle();
167
+ };
125
168
  this._onCheckboxChange = (e) => {
126
169
  this.selected = e.target.checked;
127
170
  this.dispatchEvent(new TagChangeEvent(this.selected));
128
171
  };
172
+ // The chip is operated from inside the shadow root, which a click
173
+ // dispatched on the host never reaches — see `_onHostClick`.
174
+ this.addEventListener('click', this._onHostClick);
129
175
  }
130
- /** Tag size: `sm`, `md` (default), or `lg`. */
131
- get size() { return __classPrivateFieldGet(this, _Tag_size_accessor_storage, "f"); }
132
- set size(value) { __classPrivateFieldSet(this, _Tag_size_accessor_storage, value, "f"); }
133
- /** Show a remove button (and enable Backspace/Delete removal). */
134
- get removable() { return __classPrivateFieldGet(this, _Tag_removable_accessor_storage, "f"); }
135
- set removable(value) { __classPrivateFieldSet(this, _Tag_removable_accessor_storage, value, "f"); }
136
- /** Make the tag a filter control the user can toggle on and off. */
137
- get selectable() { return __classPrivateFieldGet(this, _Tag_selectable_accessor_storage, "f"); }
138
- set selectable(value) { __classPrivateFieldSet(this, _Tag_selectable_accessor_storage, value, "f"); }
139
- /** Whether the tag is selected. Reflected, so `[selected]` is styleable. */
140
- get selected() { return __classPrivateFieldGet(this, _Tag_selected_accessor_storage, "f"); }
141
- set selected(value) { __classPrivateFieldSet(this, _Tag_selected_accessor_storage, value, "f"); }
142
- /**
143
- * What drives the selection: `none` (default) makes the chip itself a toggle
144
- * button; `checkbox` renders a checkbox inside and makes the chip its label —
145
- * the right choice for a multi-select facet. Implies `selectable`.
146
- */
147
- get control() { return __classPrivateFieldGet(this, _Tag_control_accessor_storage, "f"); }
148
- set control(value) { __classPrivateFieldSet(this, _Tag_control_accessor_storage, value, "f"); }
149
- /** Disable the tag — dims it and blocks selection and removal. */
150
- get disabled() { return __classPrivateFieldGet(this, _Tag_disabled_accessor_storage, "f"); }
151
- set disabled(value) { __classPrivateFieldSet(this, _Tag_disabled_accessor_storage, value, "f"); }
152
176
  willUpdate() {
153
177
  // A checkbox is only ever rendered on a selectable chip, so the attribute
154
178
  // (which every selectable style rule keys off) is derived rather than