@latty-ds/web 0.10.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/custom-elements.json +1969 -228
  2. package/dist/components/accordion/index.js +36 -2
  3. package/dist/components/alert/alert.d.ts +29 -6
  4. package/dist/components/alert/alert.types.d.ts +5 -0
  5. package/dist/components/alert/index.js +124 -17
  6. package/dist/components/avatar/avatar.d.ts +2 -0
  7. package/dist/components/avatar/index.js +10 -3
  8. package/dist/components/breadcrumb/breadcrumb.d.ts +4 -0
  9. package/dist/components/breadcrumb/breadcrumb.types.d.ts +5 -0
  10. package/dist/components/breadcrumb/index.js +20 -3
  11. package/dist/components/button/button.d.ts +33 -0
  12. package/dist/components/button/index.js +135 -12
  13. package/dist/components/calendar/calendar.d.ts +15 -7
  14. package/dist/components/calendar/calendar.types.d.ts +17 -1
  15. package/dist/components/calendar/index.js +78 -25
  16. package/dist/components/checkbox/checkbox.d.ts +14 -2
  17. package/dist/components/checkbox/checkbox.types.d.ts +5 -0
  18. package/dist/components/checkbox/index.js +82 -5
  19. package/dist/components/chip/chip.d.ts +4 -1
  20. package/dist/components/chip/chip.types.d.ts +5 -0
  21. package/dist/components/chip/index.js +29 -1
  22. package/dist/components/color-input/color-input.d.ts +11 -2
  23. package/dist/components/color-input/color-input.types.d.ts +5 -0
  24. package/dist/components/color-input/index.js +92 -8
  25. package/dist/components/combobox/combobox.d.ts +18 -2
  26. package/dist/components/combobox/combobox.types.d.ts +7 -0
  27. package/dist/components/combobox/index.js +164 -23
  28. package/dist/components/date-input/date-input.d.ts +22 -7
  29. package/dist/components/date-input/date-input.types.d.ts +7 -0
  30. package/dist/components/date-input/index.js +216 -53
  31. package/dist/components/datepicker/datepicker.d.ts +9 -1
  32. package/dist/components/datepicker/index.js +108 -15
  33. package/dist/components/dialog/dialog.d.ts +39 -19
  34. package/dist/components/dialog/dialog.types.d.ts +5 -0
  35. package/dist/components/dialog/index.js +237 -90
  36. package/dist/components/divider/index.js +2 -2
  37. package/dist/components/dropdown/dropdown.d.ts +4 -0
  38. package/dist/components/dropdown/index.js +43 -3
  39. package/dist/components/icon-button/icon-button.d.ts +4 -0
  40. package/dist/components/icon-button/index.js +36 -1
  41. package/dist/components/image/image.d.ts +7 -7
  42. package/dist/components/image/index.js +6 -11
  43. package/dist/components/list/index.js +14 -4
  44. package/dist/components/nav/index.js +37 -17
  45. package/dist/components/nav/nav-item.d.ts +8 -8
  46. package/dist/components/pagination/index.js +57 -16
  47. package/dist/components/pagination/pagination.d.ts +8 -1
  48. package/dist/components/pagination/pagination.types.d.ts +15 -0
  49. package/dist/components/progress/index.js +44 -6
  50. package/dist/components/progress/progress.d.ts +12 -0
  51. package/dist/components/radio/index.js +148 -9
  52. package/dist/components/radio/radio.d.ts +34 -2
  53. package/dist/components/radio/radio.types.d.ts +5 -0
  54. package/dist/components/radio-group/index.js +120 -29
  55. package/dist/components/radio-group/radio-group.d.ts +27 -2
  56. package/dist/components/select/index.js +197 -44
  57. package/dist/components/select/select.d.ts +38 -4
  58. package/dist/components/select/select.types.d.ts +5 -0
  59. package/dist/components/shared/aria-forwarding.d.ts +1 -1
  60. package/dist/components/shared/form-default.d.ts +30 -0
  61. package/dist/components/shared/form-disabled.d.ts +40 -0
  62. package/dist/components/shared/form-field.d.ts +7 -0
  63. package/dist/components/shared/form-validity.d.ts +17 -0
  64. package/dist/components/shared/roving.d.ts +11 -0
  65. package/dist/components/shared/scroll-lock.d.ts +2 -0
  66. package/dist/components/sidepanel/index.js +275 -72
  67. package/dist/components/sidepanel/sidepanel.d.ts +32 -10
  68. package/dist/components/sidepanel/sidepanel.types.d.ts +10 -1
  69. package/dist/components/skeleton/index.js +3 -8
  70. package/dist/components/slider/index.js +307 -75
  71. package/dist/components/slider/slider.d.ts +16 -3
  72. package/dist/components/snackbar/index.js +82 -9
  73. package/dist/components/snackbar/snackbar.d.ts +17 -1
  74. package/dist/components/snackbar/snackbar.types.d.ts +5 -0
  75. package/dist/components/surface/index.js +8 -0
  76. package/dist/components/switch/index.js +101 -5
  77. package/dist/components/switch/switch.d.ts +13 -2
  78. package/dist/components/switch/switch.types.d.ts +5 -0
  79. package/dist/components/tab/index.js +15 -14
  80. package/dist/components/tab/tab.d.ts +0 -1
  81. package/dist/components/tab-group/index.js +102 -30
  82. package/dist/components/tab-group/tab-group.d.ts +17 -2
  83. package/dist/components/table/index.js +105 -61
  84. package/dist/components/table/table.d.ts +8 -2
  85. package/dist/components/table/table.types.d.ts +4 -3
  86. package/dist/components/text/index.js +16 -1
  87. package/dist/components/text/text.d.ts +1 -1
  88. package/dist/components/textfield/index.js +243 -35
  89. package/dist/components/textfield/textfield.d.ts +24 -2
  90. package/dist/components/textfield/textfield.types.d.ts +11 -0
  91. package/dist/components/tooltip/index.js +176 -49
  92. package/dist/components/tooltip/tooltip.d.ts +17 -0
  93. package/dist/components/tooltip/tooltip.types.d.ts +5 -1
  94. package/dist/index.cjs +2458 -683
  95. package/dist/index.js +2469 -690
  96. package/dist/manifest.json +202 -32
  97. package/dist/utils/dev-warn.d.ts +5 -0
  98. package/dist/utils/index.d.ts +1 -0
  99. package/package.json +3 -7
@@ -9,7 +9,7 @@
9
9
  {
10
10
  "kind": "variable",
11
11
  "name": "accordionStyles",
12
- "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); width: 100%; } details { border-radius: var(--lt-border-radius); transition: background-color 120ms ease, border-color 120ms ease; } summary { cursor: pointer; list-style: none; user-select: none; border-radius: var(--lt-border-radius); overflow: hidden; } summary::-webkit-details-marker { display: none; } .summary-content { align-items: center; display: flex; gap: var(--lt-spacing-3); justify-content: space-between; padding: var(--lt-accordion-summary-padding, var(--lt-spacing-4)); } .start-icon { color: var(--lt-text-subtle); flex-shrink: 0; font-size: 1.25rem; } .summary-text { color: var(--lt-accordion-header-color, var(--lt-text-default)); flex: 1; } .summary-text::part(base) { font-size: var(--lt-accordion-header-font-size, 1rem); font-weight: var(--lt-accordion-header-font-weight, 600); } .chevron { color: var(--lt-text-subtle); flex-shrink: 0; height: 20px; transition: transform 200ms ease; width: 20px; } details[open] .chevron { transform: rotate(180deg); } summary:hover .chevron { color: var(--lt-text-default); } summary:focus-visible { outline: 2px solid var(--lt-border-focus); outline-offset: 2px; border-radius: var(--lt-border-radius); } .content { height: 0; overflow: hidden; transition: height 200ms ease; } .content-inner { color: var(--lt-text-subtle); font-size: 0.9375rem; line-height: 1.6; padding: var(--lt-accordion-content-padding, 0 var(--lt-spacing-4) var(--lt-spacing-4)); } /* Variant: default */ :host([appearance='default']) details { background: var(--lt-bg-subtle); border: var(--lt-border-width, 1px) solid var(--lt-border-default); } :host([appearance='default']) details:hover { border-color: var(--lt-border-strong); } /* Variant: filled */ :host([appearance='filled']) details { background: var(--lt-bg-surface); border: none; } :host([appearance='filled']) details:hover { background: var(--lt-bg-overlay); } /* Variant: outlined */ :host([appearance='outlined']) details { background: transparent; border: var(--lt-border-width, 1px) solid var(--lt-border-default); } :host([appearance='outlined']) details:hover { border-color: var(--lt-border-strong); } /* Variant: clean */ :host([appearance='clean']) details { background: transparent; border: none; } /* Disabled state */ :host([disabled]) details { opacity: 0.6; pointer-events: none; } :host([uppercase]) .summary-text::part(base) { font-variant-caps: small-caps; letter-spacing: 0.05rem; text-transform: lowercase; } `"
12
+ "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); width: 100%; } details { border-radius: var(--lt-border-radius); transition: background-color 120ms ease, border-color 120ms ease; } summary { cursor: pointer; list-style: none; user-select: none; border-radius: var(--lt-border-radius); overflow: hidden; } summary::-webkit-details-marker { display: none; } .summary-content { align-items: center; display: flex; gap: var(--lt-spacing-3); justify-content: space-between; padding: var(--lt-accordion-summary-padding, var(--lt-spacing-4)); } .start-icon { color: var(--lt-text-subtle); flex-shrink: 0; font-size: 1.25rem; } .summary-text { color: var(--lt-accordion-header-color, var(--lt-text-default)); flex: 1; } .summary-text::part(base) { font-size: var(--lt-accordion-header-font-size, 1rem); font-weight: var(--lt-accordion-header-font-weight, 600); } .chevron { color: var(--lt-text-subtle); flex-shrink: 0; height: 20px; transition: transform 200ms ease; width: 20px; } details[open] .chevron { transform: rotate(180deg); } summary:hover .chevron { color: var(--lt-text-default); } summary:focus-visible { outline: 2px solid var(--lt-border-focus); outline-offset: 2px; border-radius: var(--lt-border-radius); } .content { height: 0; overflow: hidden; transition: height 200ms ease; } .content-inner { color: var(--lt-text-subtle); font-size: 0.9375rem; line-height: 1.6; padding: var(--lt-accordion-content-padding, 0 var(--lt-spacing-4) var(--lt-spacing-4)); } /* Variant: default */ :host([appearance='default']) details { background: var(--lt-bg-subtle); border: var(--lt-border-width, 1px) solid var(--lt-border-default); } :host([appearance='default']) details:hover { border-color: var(--lt-border-strong); } /* Variant: filled */ :host([appearance='filled']) details { background: var(--lt-bg-surface); border: none; } :host([appearance='filled']) details:hover { background: var(--lt-bg-overlay); } /* Variant: outlined */ :host([appearance='outlined']) details { background: transparent; border: var(--lt-border-width, 1px) solid var(--lt-border-default); } :host([appearance='outlined']) details:hover { border-color: var(--lt-border-strong); } /* Variant: clean */ :host([appearance='clean']) details { background: transparent; border: none; } /* Disabled state */ :host([disabled]) details { opacity: 0.6; pointer-events: none; } :host([uppercase]) .summary-text::part(base) { font-variant-caps: small-caps; letter-spacing: 0.05rem; text-transform: lowercase; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { details, .chevron { transition: none; } /* .content's height transition can't just be removed — accordion.ts's handleTransitionEnd() clears _animating and finalizes styles only when the CSS transition actually completes; transition:none fires no transitionend at all, leaving _animating stuck true after the very first toggle and silently breaking every subsequent open/close. A 1ms duration is imperceptible (satisfies the reduced-motion intent) but still fires the event the component's own state machine depends on. */ .content { transition: height 1ms; } } `"
13
13
  }
14
14
  ],
15
15
  "exports": [
@@ -166,6 +166,14 @@
166
166
  "kind": "method",
167
167
  "name": "handleTransitionEnd",
168
168
  "privacy": "private",
169
+ "parameters": [
170
+ {
171
+ "name": "e",
172
+ "type": {
173
+ "text": "TransitionEvent"
174
+ }
175
+ }
176
+ ],
169
177
  "description": "Handles the end of the transition to clear inline styles."
170
178
  },
171
179
  {
@@ -231,7 +239,7 @@
231
239
  {
232
240
  "kind": "variable",
233
241
  "name": "alertStyles",
234
- "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); opacity: 1; transform: translateY(0); transition: opacity 200ms ease, transform 200ms ease; /* Default variant tokens — public props override first, then variant defaults */ --_bg-subtle: var(--lt-alert-bg, var(--lt-bg-neutral-subtle)); --_bg-solid: var(--lt-alert-bg, var(--lt-bg-inverse)); --_border: var(--lt-alert-border-color, var(--lt-border-strong)); --_color: var(--lt-alert-color, var(--lt-text-default)); --_color-solid: var(--lt-alert-color, var(--lt-text-inverse)); } :host([dismissed]) { opacity: 0; transform: translateY(-4px); } /* ── Per-variant tokens ──────────────────────────────────── */ :host([variant='success']) { --_bg-subtle: var(--lt-alert-bg, var(--lt-bg-success-subtle)); --_bg-solid: var(--lt-alert-bg, var(--lt-bg-success)); --_border: var(--lt-alert-border-color, var(--lt-border-success-strong)); --_color: var(--lt-alert-color, var(--lt-text-success)); --_color-solid: var(--lt-alert-color, var(--lt-text-on-success)); } :host([variant='warning']) { --_bg-subtle: var(--lt-alert-bg, var(--lt-bg-warning-subtle)); --_bg-solid: var(--lt-alert-bg, var(--lt-bg-warning)); --_border: var(--lt-alert-border-color, var(--lt-border-warning-strong)); --_color: var(--lt-alert-color, var(--lt-text-warning)); --_color-solid: var(--lt-alert-color, var(--lt-text-on-warning)); } :host([variant='error']) { --_bg-subtle: var(--lt-alert-bg, var(--lt-bg-error-subtle)); --_bg-solid: var(--lt-alert-bg, var(--lt-bg-error)); --_border: var(--lt-alert-border-color, var(--lt-border-error-strong)); --_color: var(--lt-alert-color, var(--lt-text-error)); --_color-solid: var(--lt-alert-color, var(--lt-text-on-error)); } :host([variant='info']) { --_bg-subtle: var(--lt-alert-bg, var(--lt-bg-info-subtle)); --_bg-solid: var(--lt-alert-bg, var(--lt-bg-info)); --_border: var(--lt-alert-border-color, var(--lt-border-info-strong)); --_color: var(--lt-alert-color, var(--lt-text-info)); --_color-solid: var(--lt-alert-color, var(--lt-text-on-info)); } /* ── Layout ──────────────────────────────────────────────── */ .inner { align-items: flex-start; border-radius: var(--lt-border-radius); display: flex; gap: var(--lt-spacing-3); padding: var(--lt-spacing-3) var(--lt-spacing-4); } /* ── Appearances ─────────────────────────────────────────── */ /* filled (default) — subtle tinted bg + full border */ :host([appearance='filled']) .inner, :host(:not([appearance])) .inner { background: var(--_bg-subtle); border: var(--lt-border-width, 1px) solid var(--_border); color: var(--_color); } /* outlined — white bg + colored border */ :host([appearance='outlined']) .inner { background: var(--lt-bg-default); border: var(--lt-border-width, 1px) solid var(--_border); color: var(--_color); } /* solid — solid color bg, no border */ :host([appearance='solid']) .inner { background: var(--_bg-solid); border: none; color: var(--_color-solid); } /* ── Icon ────────────────────────────────────────────────── */ .icon { flex-shrink: 0; font-size: 1.125rem; margin-top: 1px; } /* ── Body ────────────────────────────────────────────────── */ .body { flex: 1; min-width: 0; } .title { margin: 0 0 var(--lt-spacing-1); } .content { font-size: 0.875rem; line-height: 1.5; } .title + .content { opacity: 0.8; } /* ── Close button ────────────────────────────────────────── */ .close { flex-shrink: 0; margin-top: 1px; opacity: 0.7; } .close:hover { opacity: 1; } :host([uppercase]) .title::part(base) { font-variant-caps: small-caps; letter-spacing: 0.05rem; text-transform: lowercase; } `"
242
+ "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); opacity: 1; transform: translateY(0); transition: opacity 200ms ease, transform 200ms ease; /* Default variant tokens — public props override first, then variant defaults */ --_bg-subtle: var(--lt-alert-bg, var(--lt-bg-neutral-subtle)); --_bg-solid: var(--lt-alert-bg, var(--lt-bg-inverse)); --_border: var(--lt-alert-border-color, var(--lt-border-strong)); --_color: var(--lt-alert-color, var(--lt-text-default)); --_color-solid: var(--lt-alert-color, var(--lt-text-inverse)); } :host([dismissed]) { opacity: 0; transform: translateY(-4px); } /* Hidden once the fade above finishes. Not removed from the DOM — see the open property's doc comment. */ :host(:not([open])) { display: none; } /* ── Per-variant tokens ──────────────────────────────────── */ :host([variant='success']) { --_bg-subtle: var(--lt-alert-bg, var(--lt-bg-success-subtle)); --_bg-solid: var(--lt-alert-bg, var(--lt-interactive-success-bg)); --_border: var(--lt-alert-border-color, var(--lt-border-success-strong)); --_color: var(--lt-alert-color, var(--lt-text-success)); --_color-solid: var(--lt-alert-color, var(--lt-text-on-success)); } :host([variant='warning']) { --_bg-subtle: var(--lt-alert-bg, var(--lt-bg-warning-subtle)); --_bg-solid: var(--lt-alert-bg, var(--lt-interactive-warning-bg)); --_border: var(--lt-alert-border-color, var(--lt-border-warning-strong)); --_color: var(--lt-alert-color, var(--lt-text-warning)); --_color-solid: var(--lt-alert-color, var(--lt-text-on-warning)); } :host([variant='error']) { --_bg-subtle: var(--lt-alert-bg, var(--lt-bg-error-subtle)); --_bg-solid: var(--lt-alert-bg, var(--lt-interactive-error-bg)); --_border: var(--lt-alert-border-color, var(--lt-border-error-strong)); --_color: var(--lt-alert-color, var(--lt-text-error)); --_color-solid: var(--lt-alert-color, var(--lt-text-on-error)); } :host([variant='info']) { --_bg-subtle: var(--lt-alert-bg, var(--lt-bg-info-subtle)); --_bg-solid: var(--lt-alert-bg, var(--lt-interactive-info-bg)); --_border: var(--lt-alert-border-color, var(--lt-border-info-strong)); --_color: var(--lt-alert-color, var(--lt-text-info)); --_color-solid: var(--lt-alert-color, var(--lt-text-on-info)); } /* ── Layout ──────────────────────────────────────────────── */ .inner { align-items: flex-start; border-radius: var(--lt-border-radius); display: flex; gap: var(--lt-spacing-3); padding: var(--lt-spacing-3) var(--lt-spacing-4); } /* ── Appearances ─────────────────────────────────────────── */ /* filled (default) — subtle tinted bg + full border */ :host([appearance='filled']) .inner, :host(:not([appearance])) .inner { background: var(--_bg-subtle); border: var(--lt-border-width, 1px) solid var(--_border); color: var(--_color); } /* outlined — white bg + colored border */ :host([appearance='outlined']) .inner { background: var(--lt-bg-default); border: var(--lt-border-width, 1px) solid var(--_border); color: var(--_color); } /* solid — solid color bg, no border. Fills come from the interactive tokens, the same ones the on-colour is picked against, so the text holds AA; body text is never dimmed with opacity, which would only lower it. */ :host([appearance='solid']) .inner { background: var(--_bg-solid); border: none; color: var(--_color-solid); } /* ── Icon ────────────────────────────────────────────────── */ .icon { flex-shrink: 0; font-size: 1.125rem; margin-top: 1px; } /* ── Body ────────────────────────────────────────────────── */ .body { flex: 1; min-width: 0; } .title { margin: 0 0 var(--lt-spacing-1); } .content { font-size: 0.875rem; line-height: 1.5; } /* ── Close button ────────────────────────────────────────── */ .close { flex-shrink: 0; margin-top: 1px; opacity: 0.7; } .close:hover { opacity: 1; } :host([uppercase]) .title::part(base) { font-variant-caps: small-caps; letter-spacing: 0.05rem; text-transform: lowercase; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { :host { transition: none; } } `"
235
243
  }
236
244
  ],
237
245
  "exports": [
@@ -286,13 +294,21 @@
286
294
  },
287
295
  {
288
296
  "kind": "field",
289
- "name": "title",
297
+ "name": "heading",
290
298
  "type": {
291
299
  "text": "string"
292
300
  },
293
301
  "default": "''",
294
302
  "description": "Optional bold heading above the body content."
295
303
  },
304
+ {
305
+ "kind": "field",
306
+ "name": "title",
307
+ "type": {
308
+ "text": "string"
309
+ },
310
+ "deprecated": "Use `heading` instead. `title` collides with the browser's own native tooltip attribute — every\nHTML element has one regardless of custom-element status, so `<lt-alert title=\"…\">` made hovering anywhere\nover the alert show a browser tooltip, and assistive tech could read it as a duplicate description (ALR-3).\nThis alias keeps existing markup/JS working; the native `title` attribute is always stripped as soon as\nit's read, so the tooltip never appears."
311
+ },
296
312
  {
297
313
  "kind": "field",
298
314
  "name": "icon",
@@ -309,7 +325,16 @@
309
325
  "text": "boolean"
310
326
  },
311
327
  "default": "false",
312
- "description": "Show a dismiss button. Clicking it fires lt-close and removes the element."
328
+ "description": "Show a dismiss button. Clicking it fires `close` and hides the element (sets `open` to false)."
329
+ },
330
+ {
331
+ "kind": "field",
332
+ "name": "open",
333
+ "type": {
334
+ "text": "boolean"
335
+ },
336
+ "default": "true",
337
+ "description": "Whether the alert is visible. Defaults to true, so existing markup with no attribute keeps showing.\nDismissing (or setting this to false directly) hides the alert but does not remove it from the DOM —\nthat choice is left to the consumer, since a framework that owns this node would otherwise fight the\nalert over removing it out from under its own reconciliation."
313
338
  },
314
339
  {
315
340
  "kind": "field",
@@ -327,7 +352,25 @@
327
352
  "text": "boolean"
328
353
  },
329
354
  "default": "false",
330
- "description": "Renders the title in small caps with wider letter spacing."
355
+ "description": "Renders the heading in small caps with wider letter spacing."
356
+ },
357
+ {
358
+ "kind": "field",
359
+ "name": "labels",
360
+ "type": {
361
+ "text": "Partial<AlertLabels>"
362
+ },
363
+ "default": "{}",
364
+ "description": "Overridable UI text (the dismiss button's accessible name), for i18n. English defaults — override only the keys you need."
365
+ },
366
+ {
367
+ "kind": "field",
368
+ "name": "_labels",
369
+ "type": {
370
+ "text": "AlertLabels"
371
+ },
372
+ "privacy": "private",
373
+ "readonly": true
331
374
  },
332
375
  {
333
376
  "kind": "field",
@@ -345,6 +388,27 @@
345
388
  "name": "_handleClose",
346
389
  "privacy": "private"
347
390
  },
391
+ {
392
+ "kind": "method",
393
+ "name": "updated",
394
+ "parameters": [
395
+ {
396
+ "name": "changed",
397
+ "type": {
398
+ "text": "PropertyValues<this>"
399
+ }
400
+ }
401
+ ]
402
+ },
403
+ {
404
+ "kind": "field",
405
+ "name": "_role",
406
+ "type": {
407
+ "text": "'alert' | 'status'"
408
+ },
409
+ "privacy": "private",
410
+ "readonly": true
411
+ },
348
412
  {
349
413
  "kind": "field",
350
414
  "name": "_resolvedIcon",
@@ -361,7 +425,7 @@
361
425
  ],
362
426
  "events": [
363
427
  {
364
- "description": "Fired when the dismiss button is clicked, just before the element is removed.",
428
+ "description": "Fired when the dismiss button is clicked, just before the element is hidden. Cancelable.",
365
429
  "name": "close"
366
430
  }
367
431
  ],
@@ -523,6 +587,18 @@
523
587
  "privacy": "private",
524
588
  "readonly": true
525
589
  },
590
+ {
591
+ "kind": "method",
592
+ "name": "willUpdate",
593
+ "parameters": [
594
+ {
595
+ "name": "changed",
596
+ "type": {
597
+ "text": "PropertyValues<this>"
598
+ }
599
+ }
600
+ ]
601
+ },
526
602
  {
527
603
  "kind": "method",
528
604
  "name": "_handleImgError",
@@ -747,7 +823,7 @@
747
823
  {
748
824
  "kind": "variable",
749
825
  "name": "breadcrumbItemStyles",
750
- "default": "css` :host { align-items: center; display: inline-flex; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); font-size: 0.875rem; } [part='link'] { color: var(--lt-interactive-primary-bg); text-decoration: none; transition: color 120ms ease; } [part='link']:hover { color: var(--lt-interactive-primary-bg-hover); text-decoration: underline; } [part='text'] { color: var(--lt-text-default); font-weight: 600; } [part='separator'] { color: var(--lt-text-muted); margin-inline: var(--lt-spacing-2); user-select: none; } [part='separator']::after { content: var(--lt-breadcrumb-separator, '/'); } :host(:last-child) [part='separator'] { display: none; } `"
826
+ "default": "css` :host { align-items: center; display: inline-flex; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); font-size: 0.875rem; } [part='link'] { color: var(--lt-text-primary); text-decoration: none; transition: color 120ms ease; } [part='link']:hover { text-decoration: underline; } [part='text'] { color: var(--lt-text-default); font-weight: 600; } [part='separator'] { color: var(--lt-text-muted); margin-inline: var(--lt-spacing-2); user-select: none; } [part='separator']::after { content: var(--lt-breadcrumb-separator, '/'); } :host(:last-child) [part='separator'] { display: none; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { [part='link'] { transition: none; } } `"
751
827
  }
752
828
  ],
753
829
  "exports": [
@@ -793,6 +869,24 @@
793
869
  "default": "'/'",
794
870
  "description": "The character or element to use as a separator between breadcrumb items.\nThis is passed down to all children items via CSS variables."
795
871
  },
872
+ {
873
+ "kind": "field",
874
+ "name": "labels",
875
+ "type": {
876
+ "text": "Partial<BreadcrumbLabels>"
877
+ },
878
+ "default": "{}",
879
+ "description": "Overridable UI text (the breadcrumb nav's landmark label), for i18n. English defaults — override only the keys you need."
880
+ },
881
+ {
882
+ "kind": "field",
883
+ "name": "_labels",
884
+ "type": {
885
+ "text": "BreadcrumbLabels"
886
+ },
887
+ "privacy": "private",
888
+ "readonly": true
889
+ },
796
890
  {
797
891
  "kind": "method",
798
892
  "name": "updated",
@@ -925,7 +1019,7 @@
925
1019
  {
926
1020
  "kind": "variable",
927
1021
  "name": "buttonStyles",
928
- "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); /* Internal state props — set per variant/appearance below */ --_color: var(--lt-text-on-primary); --_bg: var(--lt-interactive-primary-bg); --_border-color: transparent; --_hover-bg: var(--lt-interactive-primary-bg-hover); --_active-bg: var(--lt-interactive-primary-bg-active); } :host([full-width]) { display: block; width: 100%; } :host([full-width]) [part='base'] { width: 100%; } [part='base'] { align-items: center; background: var(--lt-button-bg, var(--_bg)); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-button-border-color, var(--_border-color)); box-sizing: border-box; color: var(--lt-button-color, var(--_color)); cursor: pointer; display: inline-flex; font-family: inherit; font-weight: 400; gap: var(--lt-spacing-2); justify-content: center; line-height: 1; min-width: var(--lt-button-min-width, 88px); user-select: none; transition: background-color 120ms ease, border-color 120ms ease, transform 50ms ease; } [part='base']:active { transform: translateY(1px); } [part='base']:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: 2px; } [part='base'][disabled], [part='base'][aria-disabled='true'] { cursor: not-allowed; opacity: 0.6; pointer-events: none; transform: none; } /* anchor reset — browsers apply link color + underline by default */ a[part='base'] { text-decoration: none; } /* sizes */ :host([size='sm']) [part='base'] { font-size: 0.875rem; height: 32px; padding-inline: var(--lt-spacing-3); } :host([size='md']) [part='base'] { font-size: 1rem; height: 40px; padding-inline: var(--lt-spacing-4); } :host([size='lg']) [part='base'] { font-size: 1.0625rem; height: 48px; padding-inline: var(--lt-spacing-5); } /* variants — solid */ :host([variant='primary']) { --_bg: var(--lt-interactive-primary-bg); --_color: var(--lt-text-on-primary); --_hover-bg: var(--lt-interactive-primary-bg-hover); --_active-bg: var(--lt-interactive-primary-bg-active); } :host([variant='secondary']) { --_bg: var(--lt-interactive-secondary-bg); --_color: var(--lt-text-on-secondary); --_hover-bg: var(--lt-interactive-secondary-bg-hover); --_active-bg: var(--lt-interactive-secondary-bg-active); } :host([variant='neutral']) { --_bg: var(--lt-interactive-neutral-bg); --_color: var(--lt-color-neutral-50); --_hover-bg: var(--lt-interactive-neutral-bg-hover); --_active-bg: var(--lt-interactive-neutral-bg-active); } :host([variant='success']) { --_bg: var(--lt-interactive-success-bg); --_color: var(--lt-text-on-success); --_hover-bg: var(--lt-interactive-success-bg-hover); --_active-bg: var(--lt-interactive-success-bg-active); } :host([variant='warning']) { --_bg: var(--lt-interactive-warning-bg); --_color: var(--lt-text-on-warning); --_hover-bg: var(--lt-interactive-warning-bg-hover); --_active-bg: var(--lt-interactive-warning-bg-active); } :host([variant='error']) { --_bg: var(--lt-interactive-error-bg); --_color: var(--lt-text-on-error); --_hover-bg: var(--lt-interactive-error-bg-hover); --_active-bg: var(--lt-interactive-error-bg-active); } :host([variant='info']) { --_bg: var(--lt-interactive-info-bg); --_color: var(--lt-text-on-info); --_hover-bg: var(--lt-interactive-info-bg-hover); --_active-bg: var(--lt-interactive-info-bg-active); } [part='base']:hover:not([disabled]):not([aria-disabled='true']) { background: var(--lt-button-bg, var(--_hover-bg)); } [part='base']:active:not([disabled]):not([aria-disabled='true']) { background: var(--lt-button-bg, var(--_active-bg)); } /* outlined appearance */ :host([appearance='outlined'][variant='primary']) { --_bg: transparent; --_color: var(--lt-text-primary); --_border-color: var(--lt-border-primary-strong); --_hover-bg: var(--lt-bg-primary-subtle); --_active-bg: var(--lt-bg-primary-subtle); } :host([appearance='outlined'][variant='secondary']) { --_bg: transparent; --_color: var(--lt-text-secondary); --_border-color: var(--lt-border-secondary-strong); --_hover-bg: var(--lt-bg-secondary-subtle); --_active-bg: var(--lt-bg-secondary-subtle); } :host([appearance='outlined'][variant='neutral']) { --_bg: transparent; --_color: var(--lt-text-neutral); --_border-color: var(--lt-border-strong); --_hover-bg: var(--lt-bg-subtle); --_active-bg: var(--lt-bg-surface); } :host([appearance='outlined'][variant='success']) { --_bg: transparent; --_color: var(--lt-text-success); --_border-color: var(--lt-border-success-strong); --_hover-bg: var(--lt-bg-success-subtle); --_active-bg: var(--lt-bg-success-subtle); } :host([appearance='outlined'][variant='warning']) { --_bg: transparent; --_color: var(--lt-text-warning); --_border-color: var(--lt-border-warning-strong); --_hover-bg: var(--lt-bg-warning-subtle); --_active-bg: var(--lt-bg-warning-subtle); } :host([appearance='outlined'][variant='error']) { --_bg: transparent; --_color: var(--lt-text-error); --_border-color: var(--lt-border-error-strong); --_hover-bg: var(--lt-bg-error-subtle); --_active-bg: var(--lt-bg-error-subtle); } :host([appearance='outlined'][variant='info']) { --_bg: transparent; --_color: var(--lt-text-info); --_border-color: var(--lt-border-info-strong); --_hover-bg: var(--lt-bg-info-subtle); --_active-bg: var(--lt-bg-info-subtle); } /* ghost appearance — transparent background, no border, low-emphasis text button */ :host([appearance='ghost'][variant='primary']) { --_bg: transparent; --_color: var(--lt-text-primary); --_hover-bg: var(--lt-bg-primary-subtle); --_active-bg: var(--lt-bg-primary-subtle); } :host([appearance='ghost'][variant='secondary']) { --_bg: transparent; --_color: var(--lt-text-secondary); --_hover-bg: var(--lt-bg-secondary-subtle); --_active-bg: var(--lt-bg-secondary-subtle); } :host([appearance='ghost'][variant='neutral']) { --_bg: transparent; --_color: var(--lt-text-neutral); --_hover-bg: var(--lt-bg-subtle); --_active-bg: var(--lt-bg-surface); } :host([appearance='ghost'][variant='success']) { --_bg: transparent; --_color: var(--lt-text-success); --_hover-bg: var(--lt-bg-success-subtle); --_active-bg: var(--lt-bg-success-subtle); } :host([appearance='ghost'][variant='warning']) { --_bg: transparent; --_color: var(--lt-text-warning); --_hover-bg: var(--lt-bg-warning-subtle); --_active-bg: var(--lt-bg-warning-subtle); } :host([appearance='ghost'][variant='error']) { --_bg: transparent; --_color: var(--lt-text-error); --_hover-bg: var(--lt-bg-error-subtle); --_active-bg: var(--lt-bg-error-subtle); } :host([appearance='ghost'][variant='info']) { --_bg: transparent; --_color: var(--lt-text-info); --_hover-bg: var(--lt-bg-info-subtle); --_active-bg: var(--lt-bg-info-subtle); } :host([appearance='outlined']) [part='base']:active:not([disabled]):not([aria-disabled='true']), :host([appearance='ghost']) [part='base']:active:not([disabled]):not([aria-disabled='true']) { opacity: 0.8; } /* bordered — adds a border on top of whatever appearance is active; a no-op on outlined, which already sets the same border color. */ :host([bordered][variant='primary']) { --_border-color: var(--lt-border-primary-strong); } :host([bordered][variant='secondary']) { --_border-color: var(--lt-border-secondary-strong); } :host([bordered][variant='neutral']) { --_border-color: var(--lt-border-strong); } :host([bordered][variant='success']) { --_border-color: var(--lt-border-success-strong); } :host([bordered][variant='warning']) { --_border-color: var(--lt-border-warning-strong); } :host([bordered][variant='error']) { --_border-color: var(--lt-border-error-strong); } :host([bordered][variant='info']) { --_border-color: var(--lt-border-info-strong); } /* loading */ .spinner { animation: spin 700ms linear infinite; border-radius: 999px; border-right-color: transparent; border: 2px solid currentColor; height: 1em; width: 1em; } @keyframes spin { to { transform: rotate(360deg); } } .icon, .end { align-items: center; display: inline-flex; justify-content: center; } :host([uppercase]) [part='base'] { font-variant-caps: small-caps; letter-spacing: 0.05rem; text-transform: lowercase; } `"
1022
+ "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); /* Internal state props — set per variant/appearance below */ --_color: var(--lt-text-on-primary); --_bg: var(--lt-interactive-primary-bg); --_border-color: transparent; --_hover-bg: var(--lt-interactive-primary-bg-hover); --_active-bg: var(--lt-interactive-primary-bg-active); } :host([full-width]) { display: block; width: 100%; } :host([full-width]) [part='base'] { width: 100%; } [part='base'] { align-items: center; background: var(--lt-button-bg, var(--_bg)); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-button-border-color, var(--_border-color)); box-sizing: border-box; color: var(--lt-button-color, var(--_color)); cursor: pointer; display: inline-flex; font-family: inherit; font-weight: 400; gap: var(--lt-spacing-2); justify-content: center; line-height: 1; min-width: var(--lt-button-min-width, 88px); position: relative; user-select: none; transition: background-color 120ms ease, border-color 120ms ease, transform 50ms ease; } /* Wraps the icons/slot so it can be hidden (opacity, not display/visibility — that would drop it from the accessibility tree too) while loading without collapsing the button's width or its accessible name. */ .label { align-items: center; display: inline-flex; gap: inherit; } .label.is-loading { opacity: 0; } /* Centered over the (invisible but still laid-out) label, not laid out alongside it. */ .spinner { inset: 0; margin: auto; position: absolute; } [part='base']:active { transform: translateY(1px); } [part='base']:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: 2px; } [part='base'][disabled], [part='base'][aria-disabled='true'] { cursor: not-allowed; opacity: 0.6; pointer-events: none; transform: none; } /* anchor reset — browsers apply link color + underline by default */ a[part='base'] { text-decoration: none; } /* sizes */ :host([size='sm']) [part='base'] { font-size: 0.875rem; height: 32px; padding-inline: var(--lt-spacing-3); } :host([size='md']) [part='base'] { font-size: 1rem; height: 40px; padding-inline: var(--lt-spacing-4); } :host([size='lg']) [part='base'] { font-size: 1.0625rem; height: 48px; padding-inline: var(--lt-spacing-5); } /* variants — solid */ :host([variant='primary']) { --_bg: var(--lt-interactive-primary-bg); --_color: var(--lt-text-on-primary); --_hover-bg: var(--lt-interactive-primary-bg-hover); --_active-bg: var(--lt-interactive-primary-bg-active); } :host([variant='secondary']) { --_bg: var(--lt-interactive-secondary-bg); --_color: var(--lt-text-on-secondary); --_hover-bg: var(--lt-interactive-secondary-bg-hover); --_active-bg: var(--lt-interactive-secondary-bg-active); } :host([variant='neutral']) { --_bg: var(--lt-interactive-neutral-bg); --_color: var(--lt-color-neutral-50); --_hover-bg: var(--lt-interactive-neutral-bg-hover); --_active-bg: var(--lt-interactive-neutral-bg-active); } :host([variant='success']) { --_bg: var(--lt-interactive-success-bg); --_color: var(--lt-text-on-success); --_hover-bg: var(--lt-interactive-success-bg-hover); --_active-bg: var(--lt-interactive-success-bg-active); } :host([variant='warning']) { --_bg: var(--lt-interactive-warning-bg); --_color: var(--lt-text-on-warning); --_hover-bg: var(--lt-interactive-warning-bg-hover); --_active-bg: var(--lt-interactive-warning-bg-active); } :host([variant='error']) { --_bg: var(--lt-interactive-error-bg); --_color: var(--lt-text-on-error); --_hover-bg: var(--lt-interactive-error-bg-hover); --_active-bg: var(--lt-interactive-error-bg-active); } :host([variant='info']) { --_bg: var(--lt-interactive-info-bg); --_color: var(--lt-text-on-info); --_hover-bg: var(--lt-interactive-info-bg-hover); --_active-bg: var(--lt-interactive-info-bg-active); } [part='base']:hover:not([disabled]):not([aria-disabled='true']) { background: var(--lt-button-bg, var(--_hover-bg)); } [part='base']:active:not([disabled]):not([aria-disabled='true']) { background: var(--lt-button-bg, var(--_active-bg)); } /* outlined appearance */ :host([appearance='outlined'][variant='primary']) { --_bg: transparent; --_color: var(--lt-text-primary); --_border-color: var(--lt-border-primary-strong); --_hover-bg: var(--lt-bg-primary-subtle); --_active-bg: var(--lt-bg-primary-subtle); } :host([appearance='outlined'][variant='secondary']) { --_bg: transparent; --_color: var(--lt-text-secondary); --_border-color: var(--lt-border-secondary-strong); --_hover-bg: var(--lt-bg-secondary-subtle); --_active-bg: var(--lt-bg-secondary-subtle); } :host([appearance='outlined'][variant='neutral']) { --_bg: transparent; --_color: var(--lt-text-neutral); --_border-color: var(--lt-border-strong); --_hover-bg: var(--lt-bg-subtle); --_active-bg: var(--lt-bg-surface); } :host([appearance='outlined'][variant='success']) { --_bg: transparent; --_color: var(--lt-text-success); --_border-color: var(--lt-border-success-strong); --_hover-bg: var(--lt-bg-success-subtle); --_active-bg: var(--lt-bg-success-subtle); } :host([appearance='outlined'][variant='warning']) { --_bg: transparent; --_color: var(--lt-text-warning); --_border-color: var(--lt-border-warning-strong); --_hover-bg: var(--lt-bg-warning-subtle); --_active-bg: var(--lt-bg-warning-subtle); } :host([appearance='outlined'][variant='error']) { --_bg: transparent; --_color: var(--lt-text-error); --_border-color: var(--lt-border-error-strong); --_hover-bg: var(--lt-bg-error-subtle); --_active-bg: var(--lt-bg-error-subtle); } :host([appearance='outlined'][variant='info']) { --_bg: transparent; --_color: var(--lt-text-info); --_border-color: var(--lt-border-info-strong); --_hover-bg: var(--lt-bg-info-subtle); --_active-bg: var(--lt-bg-info-subtle); } /* ghost appearance — transparent background, no border, low-emphasis text button */ :host([appearance='ghost'][variant='primary']) { --_bg: transparent; --_color: var(--lt-text-primary); --_hover-bg: var(--lt-bg-primary-subtle); --_active-bg: var(--lt-bg-primary-subtle); } :host([appearance='ghost'][variant='secondary']) { --_bg: transparent; --_color: var(--lt-text-secondary); --_hover-bg: var(--lt-bg-secondary-subtle); --_active-bg: var(--lt-bg-secondary-subtle); } :host([appearance='ghost'][variant='neutral']) { --_bg: transparent; --_color: var(--lt-text-neutral); --_hover-bg: var(--lt-bg-subtle); --_active-bg: var(--lt-bg-surface); } :host([appearance='ghost'][variant='success']) { --_bg: transparent; --_color: var(--lt-text-success); --_hover-bg: var(--lt-bg-success-subtle); --_active-bg: var(--lt-bg-success-subtle); } :host([appearance='ghost'][variant='warning']) { --_bg: transparent; --_color: var(--lt-text-warning); --_hover-bg: var(--lt-bg-warning-subtle); --_active-bg: var(--lt-bg-warning-subtle); } :host([appearance='ghost'][variant='error']) { --_bg: transparent; --_color: var(--lt-text-error); --_hover-bg: var(--lt-bg-error-subtle); --_active-bg: var(--lt-bg-error-subtle); } :host([appearance='ghost'][variant='info']) { --_bg: transparent; --_color: var(--lt-text-info); --_hover-bg: var(--lt-bg-info-subtle); --_active-bg: var(--lt-bg-info-subtle); } :host([appearance='outlined']) [part='base']:active:not([disabled]):not([aria-disabled='true']), :host([appearance='ghost']) [part='base']:active:not([disabled]):not([aria-disabled='true']) { opacity: 0.8; } /* bordered — adds a border on top of whatever appearance is active; a no-op on outlined, which already sets the same border color. */ :host([bordered][variant='primary']) { --_border-color: var(--lt-border-primary-strong); } :host([bordered][variant='secondary']) { --_border-color: var(--lt-border-secondary-strong); } :host([bordered][variant='neutral']) { --_border-color: var(--lt-border-strong); } :host([bordered][variant='success']) { --_border-color: var(--lt-border-success-strong); } :host([bordered][variant='warning']) { --_border-color: var(--lt-border-warning-strong); } :host([bordered][variant='error']) { --_border-color: var(--lt-border-error-strong); } :host([bordered][variant='info']) { --_border-color: var(--lt-border-info-strong); } /* loading */ .spinner { animation: spin 700ms linear infinite; border-radius: 999px; border-right-color: transparent; border: 2px solid currentColor; height: 1em; width: 1em; } @keyframes spin { to { transform: rotate(360deg); } } .icon, .end { align-items: center; display: inline-flex; justify-content: center; } :host([uppercase]) [part='base'] { font-variant-caps: small-caps; letter-spacing: 0.05rem; text-transform: lowercase; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { [part='base'] { transition: none; } .spinner { animation: none; } } `"
929
1023
  }
930
1024
  ],
931
1025
  "exports": [
@@ -976,6 +1070,15 @@
976
1070
  "static": true,
977
1071
  "default": "true"
978
1072
  },
1073
+ {
1074
+ "kind": "field",
1075
+ "name": "shadowRootOptions",
1076
+ "type": {
1077
+ "text": "object"
1078
+ },
1079
+ "static": true,
1080
+ "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true }"
1081
+ },
979
1082
  {
980
1083
  "kind": "field",
981
1084
  "name": "_internals",
@@ -990,6 +1093,29 @@
990
1093
  "privacy": "private",
991
1094
  "default": "new AriaForwardingController(this, () => this.shadowRoot?.querySelector('[part=\"base\"]'))"
992
1095
  },
1096
+ {
1097
+ "kind": "field",
1098
+ "name": "_fieldsetDisabled",
1099
+ "privacy": "private",
1100
+ "default": "new FormDisabledController(this)"
1101
+ },
1102
+ {
1103
+ "kind": "field",
1104
+ "name": "_blockClickWhileBusy",
1105
+ "privacy": "private"
1106
+ },
1107
+ {
1108
+ "kind": "method",
1109
+ "name": "formDisabledCallback",
1110
+ "parameters": [
1111
+ {
1112
+ "name": "disabled",
1113
+ "type": {
1114
+ "text": "boolean"
1115
+ }
1116
+ }
1117
+ ]
1118
+ },
993
1119
  {
994
1120
  "kind": "field",
995
1121
  "name": "variant",
@@ -1116,6 +1242,52 @@
1116
1242
  "default": "'button'",
1117
1243
  "description": "Form behaviour when the button is inside a `<form>`.\n`submit` triggers form validation and submission; `reset` restores initial values."
1118
1244
  },
1245
+ {
1246
+ "kind": "field",
1247
+ "name": "name",
1248
+ "type": {
1249
+ "text": "string"
1250
+ },
1251
+ "default": "''",
1252
+ "description": "Name submitted alongside `value` when this button triggers a form submission (`type=\"submit\"`), matching a\nnative `<button name value>` — only included in the submitted data for the button that actually triggered\nthe submission, not every submit button in the form."
1253
+ },
1254
+ {
1255
+ "kind": "field",
1256
+ "name": "value",
1257
+ "type": {
1258
+ "text": "string"
1259
+ },
1260
+ "default": "''",
1261
+ "description": "Value submitted alongside `name`. See `name`."
1262
+ },
1263
+ {
1264
+ "kind": "field",
1265
+ "name": "formAction",
1266
+ "type": {
1267
+ "text": "string"
1268
+ },
1269
+ "default": "''",
1270
+ "description": "Overrides the form's own `action` for a submission triggered by this button, matching a native\n`<button formaction>`. Only applies when `type=\"submit\"`."
1271
+ },
1272
+ {
1273
+ "kind": "field",
1274
+ "name": "_proxySubmitBtn",
1275
+ "type": {
1276
+ "text": "HTMLButtonElement | null"
1277
+ },
1278
+ "privacy": "private",
1279
+ "default": "null"
1280
+ },
1281
+ {
1282
+ "kind": "method",
1283
+ "name": "_getProxySubmitBtn",
1284
+ "privacy": "private",
1285
+ "return": {
1286
+ "type": {
1287
+ "text": "HTMLButtonElement"
1288
+ }
1289
+ }
1290
+ },
1119
1291
  {
1120
1292
  "kind": "method",
1121
1293
  "name": "_handleClick",
@@ -1199,7 +1371,7 @@
1199
1371
  {
1200
1372
  "kind": "variable",
1201
1373
  "name": "calendarStyles",
1202
- "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .calendar { background: var(--lt-bg-default); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); display: flex; flex-direction: column; gap: var(--lt-spacing-2); padding: var(--lt-spacing-3); width: 17.25rem; } /* ── Header ── */ .header { align-items: center; display: flex; justify-content: space-between; } .month-label-btn { align-items: center; background: transparent; border-radius: var(--lt-border-radius); border: 1px solid transparent; color: var(--lt-text-default); cursor: pointer; display: inline-flex; font-family: inherit; font-size: 0.9375rem; font-weight: 600; gap: var(--lt-spacing-1); letter-spacing: 0.01em; padding: var(--lt-spacing-1) var(--lt-spacing-2); transition: background 120ms ease, border-color 120ms ease; } .month-label-btn:hover:not(:disabled) { background: var(--lt-bg-neutral-subtle); border-color: var(--lt-border-default); } .month-label-btn--open { background: var(--lt-bg-neutral-subtle); border-color: var(--lt-border-default); } .month-label-btn:disabled { cursor: not-allowed; opacity: 0.6; } .picker-chevron { color: var(--lt-text-subtle); transition: transform 150ms ease; } .month-label-btn--open .picker-chevron { transform: rotate(180deg); } .nav-btn { align-items: center; background: transparent; border-radius: var(--lt-border-radius); border: 1px solid transparent; color: var(--lt-text-subtle); cursor: pointer; display: inline-flex; height: 2rem; justify-content: center; padding: 0; transition: background 120ms ease, border-color 120ms ease, color 120ms ease; width: 2rem; } .nav-btn:hover:not(:disabled) { background: var(--lt-bg-neutral-subtle); border-color: var(--lt-border-default); color: var(--lt-text-default); } .nav-btn:disabled { color: var(--lt-text-disabled); cursor: not-allowed; } /* ── Weekday headers ── */ .weekdays { column-gap: 0; display: grid; grid-template-columns: repeat(7, 1fr); } .weekday { color: var(--lt-text-muted); font-size: 0.75rem; font-weight: 500; text-align: center; } /* ── Day grid ── */ .grid { column-gap: 0; display: grid; grid-template-columns: repeat(7, 1fr); row-gap: var(--lt-spacing-1); } [role='row'] { display: contents; } /* Day button — strip layer in range mode */ .day { align-items: center; background: transparent; border: none; color: var(--lt-text-default); cursor: pointer; display: inline-flex; font-family: inherit; font-size: 0.8125rem; font-weight: 400; height: 2.25rem; justify-content: center; outline: none; padding: 0; transition: background 100ms ease; width: 100%; } .day:disabled { cursor: not-allowed; } /* Day inner — the visible circle */ .day__inner { align-items: center; background: transparent; border: 2px solid transparent; border-radius: 50%; color: inherit; display: inline-flex; font-size: inherit; font-weight: inherit; height: 2.25rem; justify-content: center; transition: background 100ms ease, border-color 100ms ease, color 100ms ease; width: 2.25rem; } .day:hover:not(:disabled) .day__inner { background: var(--lt-bg-neutral-subtle); } .day:focus-visible .day__inner { outline: 2px solid var(--lt-border-focus); outline-offset: 1px; } /* Today ring */ .day--today .day__inner { border-color: var(--lt-border-primary); font-weight: 600; } /* Single-mode selected */ .day--selected .day__inner { background: var(--lt-interactive-primary-bg); border-color: transparent; color: var(--lt-text-on-primary); font-weight: 600; } .day--selected:hover:not(:disabled) .day__inner { background: var(--lt-interactive-primary-bg-hover); } /* Outside days — dimmed by the muted text color alone. They're enabled, clickable buttons, and a 0.5 opacity on top of muted text took them to ~2:1 (WCAG AA needs 4.5:1). */ .day--outside { color: var(--lt-text-muted); } /* Empty filler cell */ .day--empty { background: transparent; border: none; cursor: default; pointer-events: none; } .day:disabled .day__inner { color: var(--lt-text-disabled); opacity: 0.4; } /* ── Range strips (on .day button = strip layer) ── */ /* Start: transparent on left, strip on right */ .day--range-left { background: linear-gradient(to right, transparent 50%, var(--lt-bg-primary-subtle) 50%); } /* End: strip on left, transparent on right */ .day--range-right { background: linear-gradient(to right, var(--lt-bg-primary-subtle) 50%, transparent 50%); } /* Same-day start+end — no strip needed */ .day--range-left.day--range-right { background: transparent; } /* Days between confirmed endpoints */ .day--in-range { background: var(--lt-bg-primary-subtle); } .day--in-range:hover:not(:disabled) .day__inner { background: var(--lt-bg-neutral-subtle); } /* Days between hover preview endpoints */ .day--in-hover-range { background: var(--lt-bg-primary-subtle); opacity: 0.45; } /* Confirmed range endpoint circle */ .day--range-confirmed .day__inner { background: var(--lt-interactive-primary-bg); border-color: transparent; color: var(--lt-text-on-primary); font-weight: 600; } .day--range-confirmed:hover:not(:disabled) .day__inner { background: var(--lt-interactive-primary-bg-hover); } /* Hover preview endpoint circle (semi-transparent) */ .day--range-hover .day__inner { background: var(--lt-interactive-primary-bg); border-color: transparent; color: var(--lt-text-on-primary); opacity: 0.5; } /* ── Multi-month layout ── */ .calendar--multi { width: auto; } .month-label-row { display: flex; flex: 1; justify-content: space-around; } .month-label { color: var(--lt-text-default); font-size: 0.9375rem; font-weight: 600; letter-spacing: 0.01em; text-align: center; } .month-panels { display: flex; gap: var(--lt-spacing-4); } .month-col { width: 17.25rem; } /* ── Month/year picker ── */ .picker-months { display: grid; gap: var(--lt-spacing-1); grid-template-columns: repeat(3, 1fr); } .picker-month-btn { background: transparent; border-radius: var(--lt-border-radius); border: 1px solid transparent; color: var(--lt-text-default); cursor: pointer; font-family: inherit; font-size: 0.8125rem; font-weight: 400; padding: var(--lt-spacing-2) 0; text-align: center; transition: background 100ms ease, border-color 100ms ease; } .picker-month-btn:hover:not(:disabled) { background: var(--lt-bg-neutral-subtle); border-color: var(--lt-border-default); } .picker-month-btn--current { background: var(--lt-interactive-primary-bg); border-color: transparent; color: var(--lt-text-on-primary); font-weight: 600; } .picker-month-btn--current:hover:not(:disabled) { background: var(--lt-interactive-primary-bg-hover); } .picker-month-btn:disabled { color: var(--lt-text-disabled); cursor: not-allowed; opacity: 0.5; } /* ── Footer ── */ .footer { border-top: 1px solid var(--lt-border-subtle); display: flex; justify-content: flex-end; padding-top: var(--lt-spacing-1); } .today-btn { background: transparent; border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); color: var(--lt-text-subtle); cursor: pointer; font-family: inherit; font-size: 0.75rem; font-weight: 500; padding: var(--lt-spacing-1) var(--lt-spacing-2); transition: background 120ms ease, border-color 120ms ease, color 120ms ease; } .today-btn:hover:not(:disabled) { background: var(--lt-bg-neutral-subtle); border-color: var(--lt-border-strong); color: var(--lt-text-default); } .today-btn:disabled { color: var(--lt-text-disabled); cursor: not-allowed; opacity: 0.5; } `"
1374
+ "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .calendar { background: var(--lt-bg-default); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); display: flex; flex-direction: column; gap: var(--lt-spacing-2); padding: var(--lt-spacing-3); width: 17.25rem; } /* ── Header ── */ .header { align-items: center; display: flex; justify-content: space-between; } .month-label-btn { align-items: center; background: transparent; border-radius: var(--lt-border-radius); border: 1px solid transparent; color: var(--lt-text-default); cursor: pointer; display: inline-flex; font-family: inherit; font-size: 0.9375rem; font-weight: 600; gap: var(--lt-spacing-1); letter-spacing: 0.01em; padding: var(--lt-spacing-1) var(--lt-spacing-2); transition: background 120ms ease, border-color 120ms ease; } .month-label-btn:hover:not(:disabled) { background: var(--lt-bg-neutral-subtle); border-color: var(--lt-border-default); } .month-label-btn--open { background: var(--lt-bg-neutral-subtle); border-color: var(--lt-border-default); } .month-label-btn:disabled { cursor: not-allowed; opacity: 0.6; } .picker-chevron { color: var(--lt-text-subtle); transition: transform 150ms ease; } .month-label-btn--open .picker-chevron { transform: rotate(180deg); } .nav-btn { align-items: center; background: transparent; border-radius: var(--lt-border-radius); border: 1px solid transparent; color: var(--lt-text-subtle); cursor: pointer; display: inline-flex; height: 2rem; justify-content: center; padding: 0; transition: background 120ms ease, border-color 120ms ease, color 120ms ease; width: 2rem; } .nav-btn:hover:not(:disabled) { background: var(--lt-bg-neutral-subtle); border-color: var(--lt-border-default); color: var(--lt-text-default); } .nav-btn:disabled { color: var(--lt-text-disabled); cursor: not-allowed; } /* ── Weekday headers ── */ .weekdays { column-gap: 0; display: grid; grid-template-columns: repeat(7, 1fr); } .weekday { color: var(--lt-text-muted); font-size: 0.75rem; font-weight: 500; text-align: center; } /* ── Day grid ── */ .grid { column-gap: 0; display: grid; grid-template-columns: repeat(7, 1fr); row-gap: var(--lt-spacing-1); } [role='row'] { display: contents; } /* Day button — strip layer in range mode */ .day { align-items: center; background: transparent; border: none; color: var(--lt-text-default); cursor: pointer; display: inline-flex; font-family: inherit; font-size: 0.8125rem; font-weight: 400; height: 2.25rem; justify-content: center; outline: none; padding: 0; transition: background 100ms ease; width: 100%; } /* aria-disabled, not the disabled attribute — a disabled day stays focusable, so keyboard users can arrow through it instead of the roving tabindex skipping straight over it (it just can't be selected). */ .day[aria-disabled='true'] { cursor: not-allowed; } /* Day inner — the visible circle */ .day__inner { align-items: center; background: transparent; border: 2px solid transparent; border-radius: 50%; color: inherit; display: inline-flex; font-size: inherit; font-weight: inherit; height: 2.25rem; justify-content: center; transition: background 100ms ease, border-color 100ms ease, color 100ms ease; width: 2.25rem; } .day:hover:not([aria-disabled='true']) .day__inner { background: var(--lt-bg-neutral-subtle); } .day:focus-visible .day__inner { outline: 2px solid var(--lt-border-focus); outline-offset: 1px; } /* Today ring */ .day--today .day__inner { border-color: var(--lt-border-primary); font-weight: 600; } /* Single-mode selected */ .day--selected .day__inner { background: var(--lt-interactive-primary-bg); border-color: transparent; color: var(--lt-text-on-primary); font-weight: 600; } .day--selected:hover:not([aria-disabled='true']) .day__inner { background: var(--lt-interactive-primary-bg-hover); } /* Outside days — dimmed by the muted text color alone. They're enabled, clickable buttons, and a 0.5 opacity on top of muted text took them to ~2:1 (WCAG AA needs 4.5:1). */ .day--outside { color: var(--lt-text-muted); } /* Empty filler cell */ .day--empty { background: transparent; border: none; cursor: default; pointer-events: none; } .day[aria-disabled='true'] .day__inner { color: var(--lt-text-disabled); opacity: 0.4; } /* ── Range strips (on .day button = strip layer) ── */ /* Start: transparent on left, strip on right */ .day--range-left { background: linear-gradient(to right, transparent 50%, var(--lt-bg-primary-subtle) 50%); } /* End: strip on left, transparent on right */ .day--range-right { background: linear-gradient(to right, var(--lt-bg-primary-subtle) 50%, transparent 50%); } /* Same-day start+end — no strip needed */ .day--range-left.day--range-right { background: transparent; } /* Days between confirmed endpoints */ .day--in-range { background: var(--lt-bg-primary-subtle); } .day--in-range:hover:not([aria-disabled='true']) .day__inner { background: var(--lt-bg-neutral-subtle); } /* Days between hover preview endpoints */ .day--in-hover-range { background: var(--lt-bg-primary-subtle); opacity: 0.45; } /* Confirmed range endpoint circle */ .day--range-confirmed .day__inner { background: var(--lt-interactive-primary-bg); border-color: transparent; color: var(--lt-text-on-primary); font-weight: 600; } .day--range-confirmed:hover:not([aria-disabled='true']) .day__inner { background: var(--lt-interactive-primary-bg-hover); } /* Hover preview endpoint circle (semi-transparent) */ .day--range-hover .day__inner { background: var(--lt-interactive-primary-bg); border-color: transparent; color: var(--lt-text-on-primary); opacity: 0.5; } /* ── Multi-month layout ── */ .calendar--multi { width: auto; } .month-label-row { display: flex; flex: 1; justify-content: space-around; } .month-label { color: var(--lt-text-default); font-size: 0.9375rem; font-weight: 600; letter-spacing: 0.01em; text-align: center; } .month-panels { display: flex; gap: var(--lt-spacing-4); } .month-col { width: 17.25rem; } /* ── Month/year picker ── */ .picker-months { display: grid; gap: var(--lt-spacing-1); grid-template-columns: repeat(3, 1fr); } .picker-month-btn { background: transparent; border-radius: var(--lt-border-radius); border: 1px solid transparent; color: var(--lt-text-default); cursor: pointer; font-family: inherit; font-size: 0.8125rem; font-weight: 400; padding: var(--lt-spacing-2) 0; text-align: center; transition: background 100ms ease, border-color 100ms ease; } .picker-month-btn:hover:not(:disabled) { background: var(--lt-bg-neutral-subtle); border-color: var(--lt-border-default); } .picker-month-btn--current { background: var(--lt-interactive-primary-bg); border-color: transparent; color: var(--lt-text-on-primary); font-weight: 600; } .picker-month-btn--current:hover:not(:disabled) { background: var(--lt-interactive-primary-bg-hover); } .picker-month-btn:disabled { color: var(--lt-text-disabled); cursor: not-allowed; opacity: 0.5; } /* ── Footer ── */ .footer { border-top: 1px solid var(--lt-border-subtle); display: flex; justify-content: flex-end; padding-top: var(--lt-spacing-1); } .today-btn { background: transparent; border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); color: var(--lt-text-subtle); cursor: pointer; font-family: inherit; font-size: 0.75rem; font-weight: 500; padding: var(--lt-spacing-1) var(--lt-spacing-2); transition: background 120ms ease, border-color 120ms ease, color 120ms ease; } .today-btn:hover:not(:disabled) { background: var(--lt-bg-neutral-subtle); border-color: var(--lt-border-strong); color: var(--lt-text-default); } .today-btn:disabled { color: var(--lt-text-disabled); cursor: not-allowed; opacity: 0.5; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { .month-label-btn, .picker-chevron, .nav-btn, .day, .day__inner, .picker-month-btn, .today-btn { transition: none; } } `"
1203
1375
  }
1204
1376
  ],
1205
1377
  "exports": [
@@ -1294,11 +1466,20 @@
1294
1466
  {
1295
1467
  "kind": "field",
1296
1468
  "name": "weekStart",
1469
+ "type": {
1470
+ "text": "CalendarWeekStart | undefined"
1471
+ },
1472
+ "description": "First day of the week (0 = Sunday … 6 = Saturday). Defaults to whatever `locale` implies (via\n`Intl.Locale#getWeekInfo`, falling back to Sunday) — set this explicitly only to override that."
1473
+ },
1474
+ {
1475
+ "kind": "field",
1476
+ "name": "_weekStart",
1297
1477
  "type": {
1298
1478
  "text": "CalendarWeekStart"
1299
1479
  },
1300
- "default": "'0'",
1301
- "description": "First day of the week. 0 = Sunday, 1 = Monday."
1480
+ "privacy": "private",
1481
+ "description": "`weekStart` if explicitly set, otherwise derived from `locale`. Internal code should always read this, never `weekStart` directly.",
1482
+ "readonly": true
1302
1483
  },
1303
1484
  {
1304
1485
  "kind": "field",
@@ -1334,7 +1515,25 @@
1334
1515
  "text": "Date[]"
1335
1516
  },
1336
1517
  "default": "[]",
1337
- "description": "Specific dates to disable, as an array of Date objects. Not reflected as an attribute."
1518
+ "description": "Specific dates to disable, as an array of Date objects. Set as a JS property (`.disabledDates`)."
1519
+ },
1520
+ {
1521
+ "kind": "field",
1522
+ "name": "labels",
1523
+ "type": {
1524
+ "text": "Partial<CalendarLabels>"
1525
+ },
1526
+ "default": "{}",
1527
+ "description": "Overridable UI text (nav button labels, the \"Today\" footer button, the month/year picker toggle), for i18n. English defaults — override only the keys you need."
1528
+ },
1529
+ {
1530
+ "kind": "field",
1531
+ "name": "_labels",
1532
+ "type": {
1533
+ "text": "CalendarLabels"
1534
+ },
1535
+ "privacy": "private",
1536
+ "readonly": true
1338
1537
  },
1339
1538
  {
1340
1539
  "kind": "field",
@@ -1679,9 +1878,9 @@
1679
1878
  "events": [
1680
1879
  {
1681
1880
  "type": {
1682
- "text": "CustomEvent<{valueStart: string, valueEnd: string}>"
1881
+ "text": "CustomEvent<{value: string} | {valueStart: string, valueEnd: string}>"
1683
1882
  },
1684
- "description": "Fired when a full range is selected (mode=\"range\").",
1883
+ "description": "Fired when a date is selected (mode=\"single\", detail `{ value }`) or when a full range is selected (mode=\"range\", detail `{ valueStart, valueEnd }`).",
1685
1884
  "name": "change"
1686
1885
  },
1687
1886
  {
@@ -1689,7 +1888,7 @@
1689
1888
  "text": "CustomEvent<{year: number, month: number}>"
1690
1889
  },
1691
1890
  "description": "Fired when the viewed month changes.",
1692
- "name": "month-change"
1891
+ "name": "monthchange"
1693
1892
  }
1694
1893
  ],
1695
1894
  "superclass": {
@@ -1733,7 +1932,7 @@
1733
1932
  {
1734
1933
  "kind": "variable",
1735
1934
  "name": "checkboxStyles",
1736
- "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .checkbox-wrapper { align-items: center; cursor: pointer; display: inline-flex; gap: var(--lt-spacing-2); } .box { display: inline-flex; flex-shrink: 0; position: relative; } :host([label-position='left']) .checkbox-wrapper { flex-direction: row-reverse; } :host([disabled]) .checkbox-wrapper { cursor: not-allowed; opacity: 0.6; } input[type='checkbox'] { appearance: none; border-radius: calc(var(--lt-border-radius) * 0.5); border: 2px solid var(--lt-border-strong); cursor: pointer; margin: 0; position: relative; transition: background-color 120ms ease, border-color 120ms ease; } input[type='checkbox']:hover:not(:disabled) { border-color: var(--lt-color-neutral-600); } input[type='checkbox']:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: 2px; } input[type='checkbox']:disabled { cursor: not-allowed; } .checkmark { align-items: center; color: white; display: none; inset: 0; justify-content: center; pointer-events: none; position: absolute; } input[type='checkbox']:checked ~ .checkmark, input[type='checkbox']:indeterminate ~ .checkmark { display: flex; } .label { color: var(--lt-text-default); user-select: none; } /* Size variants */ :host([size='sm']) input[type='checkbox'] { height: 16px; width: 16px; } :host([size='sm']) .label { font-size: 0.875rem; } :host([size='md']) input[type='checkbox'] { height: 20px; width: 20px; } :host([size='md']) .label { font-size: 1rem; } :host([size='lg']) input[type='checkbox'] { height: 24px; width: 24px; } :host([size='lg']) .label { font-size: 1.0625rem; } /* Variant styles */ :host([variant='primary']) input[type='checkbox']:checked, :host([variant='primary']) input[type='checkbox']:indeterminate { background: var(--lt-interactive-primary-bg); border-color: var(--lt-interactive-primary-bg); } :host([variant='primary']) input[type='checkbox']:checked:hover:not(:disabled), :host([variant='primary']) input[type='checkbox']:indeterminate:hover:not(:disabled) { background: var(--lt-interactive-primary-bg-hover); border-color: var(--lt-interactive-primary-bg-hover); } :host([variant='secondary']) input[type='checkbox']:checked, :host([variant='secondary']) input[type='checkbox']:indeterminate { background: var(--lt-interactive-secondary-bg); border-color: var(--lt-interactive-secondary-bg); } :host([variant='secondary']) input[type='checkbox']:checked:hover:not(:disabled), :host([variant='secondary']) input[type='checkbox']:indeterminate:hover:not(:disabled) { background: var(--lt-interactive-secondary-bg-hover); border-color: var(--lt-interactive-secondary-bg-hover); } :host([variant='success']) input[type='checkbox']:checked, :host([variant='success']) input[type='checkbox']:indeterminate { background: var(--lt-interactive-success-bg); border-color: var(--lt-interactive-success-bg); } :host([variant='success']) input[type='checkbox']:checked:hover:not(:disabled), :host([variant='success']) input[type='checkbox']:indeterminate:hover:not(:disabled) { background: var(--lt-interactive-success-bg-hover); border-color: var(--lt-interactive-success-bg-hover); } :host([variant='error']) input[type='checkbox']:checked, :host([variant='error']) input[type='checkbox']:indeterminate { background: var(--lt-interactive-error-bg); border-color: var(--lt-interactive-error-bg); } :host([variant='error']) input[type='checkbox']:checked:hover:not(:disabled), :host([variant='error']) input[type='checkbox']:indeterminate:hover:not(:disabled) { background: var(--lt-interactive-error-bg-hover); border-color: var(--lt-interactive-error-bg-hover); } :host([variant='info']) input[type='checkbox']:checked, :host([variant='info']) input[type='checkbox']:indeterminate { background: var(--lt-interactive-info-bg); border-color: var(--lt-interactive-info-bg); } :host([variant='info']) input[type='checkbox']:checked:hover:not(:disabled), :host([variant='info']) input[type='checkbox']:indeterminate:hover:not(:disabled) { background: var(--lt-interactive-info-bg-hover); border-color: var(--lt-interactive-info-bg-hover); } `"
1935
+ "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .checkbox-wrapper { align-items: center; cursor: pointer; display: inline-flex; gap: var(--lt-spacing-2); } .box { display: inline-flex; flex-shrink: 0; position: relative; } :host([label-position='left']) .checkbox-wrapper { flex-direction: row-reverse; } /* :host(:disabled) — the browser matches this automatically for a form-associated element inside a disabled <fieldset>, no JS required; :host([disabled]) covers the component's own explicit attribute. */ :host([disabled]) .checkbox-wrapper, :host(:disabled) .checkbox-wrapper { cursor: not-allowed; opacity: 0.6; } input[type='checkbox'] { appearance: none; border-radius: calc(var(--lt-border-radius) * 0.5); border: 2px solid var(--lt-border-strong); cursor: pointer; margin: 0; position: relative; transition: background-color 120ms ease, border-color 120ms ease; } input[type='checkbox']:hover:not(:disabled) { border-color: var(--lt-color-neutral-600); } input[type='checkbox']:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: 2px; } input[type='checkbox']:disabled { cursor: not-allowed; } .checkmark { align-items: center; color: white; display: none; inset: 0; justify-content: center; pointer-events: none; position: absolute; } input[type='checkbox']:checked ~ .checkmark, input[type='checkbox']:indeterminate ~ .checkmark { display: flex; } .label { color: var(--lt-text-default); user-select: none; } /* Size variants */ :host([size='sm']) input[type='checkbox'] { height: 16px; width: 16px; } :host([size='sm']) .label { font-size: 0.875rem; } :host([size='md']) input[type='checkbox'] { height: 20px; width: 20px; } :host([size='md']) .label { font-size: 1rem; } :host([size='lg']) input[type='checkbox'] { height: 24px; width: 24px; } :host([size='lg']) .label { font-size: 1.0625rem; } /* Variant styles */ :host([variant='primary']) input[type='checkbox']:checked, :host([variant='primary']) input[type='checkbox']:indeterminate { background: var(--lt-interactive-primary-bg); border-color: var(--lt-interactive-primary-bg); } :host([variant='primary']) input[type='checkbox']:checked:hover:not(:disabled), :host([variant='primary']) input[type='checkbox']:indeterminate:hover:not(:disabled) { background: var(--lt-interactive-primary-bg-hover); border-color: var(--lt-interactive-primary-bg-hover); } :host([variant='secondary']) input[type='checkbox']:checked, :host([variant='secondary']) input[type='checkbox']:indeterminate { background: var(--lt-interactive-secondary-bg); border-color: var(--lt-interactive-secondary-bg); } :host([variant='secondary']) input[type='checkbox']:checked:hover:not(:disabled), :host([variant='secondary']) input[type='checkbox']:indeterminate:hover:not(:disabled) { background: var(--lt-interactive-secondary-bg-hover); border-color: var(--lt-interactive-secondary-bg-hover); } :host([variant='success']) input[type='checkbox']:checked, :host([variant='success']) input[type='checkbox']:indeterminate { background: var(--lt-interactive-success-bg); border-color: var(--lt-interactive-success-bg); } :host([variant='success']) input[type='checkbox']:checked:hover:not(:disabled), :host([variant='success']) input[type='checkbox']:indeterminate:hover:not(:disabled) { background: var(--lt-interactive-success-bg-hover); border-color: var(--lt-interactive-success-bg-hover); } :host([variant='error']) input[type='checkbox']:checked, :host([variant='error']) input[type='checkbox']:indeterminate { background: var(--lt-interactive-error-bg); border-color: var(--lt-interactive-error-bg); } :host([variant='error']) input[type='checkbox']:checked:hover:not(:disabled), :host([variant='error']) input[type='checkbox']:indeterminate:hover:not(:disabled) { background: var(--lt-interactive-error-bg-hover); border-color: var(--lt-interactive-error-bg-hover); } :host([variant='info']) input[type='checkbox']:checked, :host([variant='info']) input[type='checkbox']:indeterminate { background: var(--lt-interactive-info-bg); border-color: var(--lt-interactive-info-bg); } :host([variant='info']) input[type='checkbox']:checked:hover:not(:disabled), :host([variant='info']) input[type='checkbox']:indeterminate:hover:not(:disabled) { background: var(--lt-interactive-info-bg-hover); border-color: var(--lt-interactive-info-bg-hover); } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { input[type='checkbox'] { transition: none; } } `"
1737
1936
  }
1738
1937
  ],
1739
1938
  "exports": [
@@ -1779,6 +1978,18 @@
1779
1978
  },
1780
1979
  "privacy": "private"
1781
1980
  },
1981
+ {
1982
+ "kind": "field",
1983
+ "name": "_default",
1984
+ "privacy": "private",
1985
+ "default": "new FormDefaultController(this, () => this.checked)"
1986
+ },
1987
+ {
1988
+ "kind": "field",
1989
+ "name": "_fieldsetDisabled",
1990
+ "privacy": "private",
1991
+ "default": "new FormDisabledController(this)"
1992
+ },
1782
1993
  {
1783
1994
  "kind": "field",
1784
1995
  "name": "variant",
@@ -1804,7 +2015,7 @@
1804
2015
  "text": "boolean"
1805
2016
  },
1806
2017
  "default": "false",
1807
- "description": "Whether the checkbox is checked."
2018
+ "description": "Whether the checkbox is checked. Not reflected as an attribute — a native checkbox's `checked` _content_\nattribute stays fixed at the markup default and never tracks interaction (that's what `defaultChecked` is\nfor); reflecting it live meant `formResetCallback` could no longer tell what the original default was. Read\nthe property, or the `change` event's `detail.checked`, instead of `[checked]`/`hasAttribute('checked')`."
1808
2019
  },
1809
2020
  {
1810
2021
  "kind": "field",
@@ -1869,6 +2080,24 @@
1869
2080
  "default": "'on'",
1870
2081
  "description": "Value attribute for form submission."
1871
2082
  },
2083
+ {
2084
+ "kind": "field",
2085
+ "name": "labels",
2086
+ "type": {
2087
+ "text": "Partial<CheckboxLabels>"
2088
+ },
2089
+ "default": "{}",
2090
+ "description": "Overridable UI text (the required-field validation message), for i18n. English defaults — override only the keys you need."
2091
+ },
2092
+ {
2093
+ "kind": "field",
2094
+ "name": "_labels",
2095
+ "type": {
2096
+ "text": "CheckboxLabels"
2097
+ },
2098
+ "privacy": "private",
2099
+ "readonly": true
2100
+ },
1872
2101
  {
1873
2102
  "kind": "field",
1874
2103
  "name": "input",
@@ -1894,6 +2123,28 @@
1894
2123
  "kind": "method",
1895
2124
  "name": "formResetCallback"
1896
2125
  },
2126
+ {
2127
+ "kind": "method",
2128
+ "name": "formDisabledCallback",
2129
+ "parameters": [
2130
+ {
2131
+ "name": "disabled",
2132
+ "type": {
2133
+ "text": "boolean"
2134
+ }
2135
+ }
2136
+ ]
2137
+ },
2138
+ {
2139
+ "kind": "field",
2140
+ "name": "_isDisabled",
2141
+ "type": {
2142
+ "text": "boolean"
2143
+ },
2144
+ "privacy": "private",
2145
+ "description": "`this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`).",
2146
+ "readonly": true
2147
+ },
1897
2148
  {
1898
2149
  "kind": "method",
1899
2150
  "name": "checkValidity"
@@ -1923,6 +2174,11 @@
1923
2174
  "privacy": "private",
1924
2175
  "description": "Renders the checkbox icon based on state.\nShows checkmark when checked, minus when indeterminate."
1925
2176
  },
2177
+ {
2178
+ "kind": "method",
2179
+ "name": "firstUpdated",
2180
+ "privacy": "protected"
2181
+ },
1926
2182
  {
1927
2183
  "kind": "method",
1928
2184
  "name": "render"
@@ -2002,7 +2258,7 @@
2002
2258
  {
2003
2259
  "kind": "variable",
2004
2260
  "name": "chipStyles",
2005
- "default": "css` :host { display: inline-flex; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); vertical-align: middle; } span[part='base'] { align-items: center; background: var(--lt-chip-bg); border-radius: 999px; /* Chips are small pills (as short as 20px tall at size=\"sm\") — a \"thick\" (4px) themed border eats too much of that height and reads as compressed/squished, so cap what the chip actually renders at \"medium\" (2px) regardless of the theme's configured border width. */ border: min(var(--lt-border-width, 1px), 2px) solid var(--lt-chip-border-color, transparent); color: var(--lt-chip-color); box-sizing: border-box; display: inline-flex; font-weight: 400; line-height: 1; transition: background-color 120ms ease, border-color 120ms ease; user-select: none; white-space: nowrap; } ::slotted([slot='icon']) { flex-shrink: 0; } .delete { align-items: center; background: none; border-radius: 999px; border: none; color: inherit; cursor: pointer; display: inline-flex; flex-shrink: 0; justify-content: center; opacity: 0.6; padding: 0; transition: opacity 120ms ease, background-color 120ms ease; } .delete:hover:not(:disabled) { opacity: 1; } .delete:disabled { cursor: not-allowed; } :host([disabled]) span[part='base'] { cursor: not-allowed; opacity: 0.5; pointer-events: none; } /* ── Sizes ────────────────────────────────────────────────────────────── */ :host([size='sm']) span[part='base'] { font-size: 0.75rem; gap: var(--lt-spacing-1); height: 20px; padding-inline: var(--lt-spacing-2); } :host([size='md']) span[part='base'] { font-size: 0.8125rem; gap: var(--lt-spacing-1); height: 26px; padding-inline: var(--lt-spacing-3); } :host([size='lg']) span[part='base'] { font-size: 0.9375rem; gap: var(--lt-spacing-2); height: 32px; padding-inline: var(--lt-spacing-4); } /* ── Filled (tinted bg, colored border, dark text) ───────────────────── */ :host([appearance='filled'][variant='primary']) span[part='base'] { background: var(--lt-bg-primary-subtle); border-color: var(--lt-border-primary); color: var(--lt-text-primary); } :host([appearance='filled'][variant='secondary']) span[part='base'] { background: var(--lt-bg-secondary-subtle); border-color: var(--lt-border-secondary); color: var(--lt-text-secondary); } :host([appearance='filled'][variant='neutral']) span[part='base'] { background: var(--lt-bg-surface); border-color: var(--lt-border-default); color: var(--lt-text-neutral); } :host([appearance='filled'][variant='success']) span[part='base'] { background: var(--lt-bg-success-subtle); border-color: var(--lt-border-success); color: var(--lt-text-success); } :host([appearance='filled'][variant='warning']) span[part='base'] { background: var(--lt-bg-warning-subtle); border-color: var(--lt-border-warning); color: var(--lt-text-warning); } :host([appearance='filled'][variant='error']) span[part='base'] { background: var(--lt-bg-error-subtle); border-color: var(--lt-border-error); color: var(--lt-text-error); } :host([appearance='filled'][variant='info']) span[part='base'] { background: var(--lt-bg-info-subtle); border-color: var(--lt-border-info); color: var(--lt-text-info); } /* ── Outlined (transparent bg, colored border and text) ──────────────── */ :host([appearance='outlined'][variant='primary']) span[part='base'] { background: transparent; border-color: var(--lt-border-primary-strong); color: var(--lt-text-primary); } :host([appearance='outlined'][variant='secondary']) span[part='base'] { background: transparent; border-color: var(--lt-border-secondary-strong); color: var(--lt-text-secondary); } :host([appearance='outlined'][variant='neutral']) span[part='base'] { background: transparent; border-color: var(--lt-border-strong); color: var(--lt-text-neutral); } :host([appearance='outlined'][variant='success']) span[part='base'] { background: transparent; border-color: var(--lt-border-success-strong); color: var(--lt-text-success); } :host([appearance='outlined'][variant='warning']) span[part='base'] { background: transparent; border-color: var(--lt-border-warning-strong); color: var(--lt-text-warning); } :host([appearance='outlined'][variant='error']) span[part='base'] { background: transparent; border-color: var(--lt-border-error-strong); color: var(--lt-text-error); } :host([appearance='outlined'][variant='info']) span[part='base'] { background: transparent; border-color: var(--lt-border-info-strong); color: var(--lt-text-info); } `"
2261
+ "default": "css` :host { display: inline-flex; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); vertical-align: middle; } span[part='base'] { align-items: center; background: var(--lt-chip-bg); border-radius: 999px; /* Chips are small pills (as short as 20px tall at size=\"sm\") — a \"thick\" (4px) themed border eats too much of that height and reads as compressed/squished, so cap what the chip actually renders at \"medium\" (2px) regardless of the theme's configured border width. */ border: min(var(--lt-border-width, 1px), 2px) solid var(--lt-chip-border-color, transparent); color: var(--lt-chip-color); box-sizing: border-box; display: inline-flex; font-weight: 400; line-height: 1; transition: background-color 120ms ease, border-color 120ms ease; user-select: none; white-space: nowrap; } ::slotted([slot='icon']) { flex-shrink: 0; } .delete { align-items: center; background: none; border-radius: 999px; border: none; color: inherit; cursor: pointer; display: inline-flex; flex-shrink: 0; justify-content: center; /* WCAG 2.5.8: a 24px target. The negative margin gives the extra size back, so the chip layout is unchanged. */ margin: -6px; min-height: 24px; min-width: 24px; opacity: 0.6; padding: 0; transition: opacity 120ms ease, background-color 120ms ease; } /* The large chip's icon is 16px rather than 12px, so it needs less negative margin to keep the same layout. */ :host([size='lg']) .delete { margin: -4px; } .delete:hover:not(:disabled) { opacity: 1; } .delete:disabled { cursor: not-allowed; } :host([disabled]) span[part='base'] { cursor: not-allowed; opacity: 0.5; pointer-events: none; } /* ── Sizes ────────────────────────────────────────────────────────────── */ :host([size='sm']) span[part='base'] { font-size: 0.75rem; gap: var(--lt-spacing-1); height: 20px; padding-inline: var(--lt-spacing-2); } :host([size='md']) span[part='base'] { font-size: 0.8125rem; gap: var(--lt-spacing-1); height: 26px; padding-inline: var(--lt-spacing-3); } :host([size='lg']) span[part='base'] { font-size: 0.9375rem; gap: var(--lt-spacing-2); height: 32px; padding-inline: var(--lt-spacing-4); } /* ── Filled (tinted bg, colored border, dark text) ───────────────────── */ :host([appearance='filled'][variant='primary']) span[part='base'] { background: var(--lt-bg-primary-subtle); border-color: var(--lt-border-primary); color: var(--lt-text-primary); } :host([appearance='filled'][variant='secondary']) span[part='base'] { background: var(--lt-bg-secondary-subtle); border-color: var(--lt-border-secondary); color: var(--lt-text-secondary); } :host([appearance='filled'][variant='neutral']) span[part='base'] { background: var(--lt-bg-surface); border-color: var(--lt-border-default); color: var(--lt-text-neutral); } :host([appearance='filled'][variant='success']) span[part='base'] { background: var(--lt-bg-success-subtle); border-color: var(--lt-border-success); color: var(--lt-text-success); } :host([appearance='filled'][variant='warning']) span[part='base'] { background: var(--lt-bg-warning-subtle); border-color: var(--lt-border-warning); color: var(--lt-text-warning); } :host([appearance='filled'][variant='error']) span[part='base'] { background: var(--lt-bg-error-subtle); border-color: var(--lt-border-error); color: var(--lt-text-error); } :host([appearance='filled'][variant='info']) span[part='base'] { background: var(--lt-bg-info-subtle); border-color: var(--lt-border-info); color: var(--lt-text-info); } /* ── Outlined (transparent bg, colored border and text) ──────────────── */ :host([appearance='outlined'][variant='primary']) span[part='base'] { background: transparent; border-color: var(--lt-border-primary-strong); color: var(--lt-text-primary); } :host([appearance='outlined'][variant='secondary']) span[part='base'] { background: transparent; border-color: var(--lt-border-secondary-strong); color: var(--lt-text-secondary); } :host([appearance='outlined'][variant='neutral']) span[part='base'] { background: transparent; border-color: var(--lt-border-strong); color: var(--lt-text-neutral); } :host([appearance='outlined'][variant='success']) span[part='base'] { background: transparent; border-color: var(--lt-border-success-strong); color: var(--lt-text-success); } :host([appearance='outlined'][variant='warning']) span[part='base'] { background: transparent; border-color: var(--lt-border-warning-strong); color: var(--lt-text-warning); } :host([appearance='outlined'][variant='error']) span[part='base'] { background: transparent; border-color: var(--lt-border-error-strong); color: var(--lt-text-error); } :host([appearance='outlined'][variant='info']) span[part='base'] { background: transparent; border-color: var(--lt-border-info-strong); color: var(--lt-text-info); } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { span[part='base'], .delete { transition: none; } } `"
2006
2262
  }
2007
2263
  ],
2008
2264
  "exports": [
@@ -2095,6 +2351,24 @@
2095
2351
  "default": "''",
2096
2352
  "description": "Background color override. Accepts a hex value (#1a1a2e) or a CSS token name (--lt-color-primary-600)."
2097
2353
  },
2354
+ {
2355
+ "kind": "field",
2356
+ "name": "labels",
2357
+ "type": {
2358
+ "text": "Partial<ChipLabels>"
2359
+ },
2360
+ "default": "{}",
2361
+ "description": "Overridable UI text (the delete button's accessible name), for i18n. English defaults — override only the keys you need."
2362
+ },
2363
+ {
2364
+ "kind": "field",
2365
+ "name": "_labels",
2366
+ "type": {
2367
+ "text": "ChipLabels"
2368
+ },
2369
+ "privacy": "private",
2370
+ "readonly": true
2371
+ },
2098
2372
  {
2099
2373
  "kind": "field",
2100
2374
  "name": "_deleteIconSize",
@@ -2182,7 +2456,7 @@
2182
2456
  {
2183
2457
  "kind": "variable",
2184
2458
  "name": "colorInputStyles",
2185
- "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); width: 100%; } .wrapper { display: flex; flex-direction: column; gap: var(--lt-spacing-1); width: 100%; cursor: pointer; } :host([disabled]) .wrapper { cursor: not-allowed; } .label { color: var(--lt-text-subtle); } .input-container { position: relative; display: flex; align-items: center; background: var(--lt-bg-subtle); border: var(--lt-border-width, 1px) solid var(--lt-border-default); border-radius: var(--lt-border-radius); box-sizing: border-box; transition: border-color 120ms ease, box-shadow 120ms ease; width: 100%; overflow: hidden; } .input-container:hover:not(:has(.native-picker:disabled)) { border-color: var(--lt-border-strong); } .input-container:focus-within { border-color: var(--lt-interactive-primary-bg); box-shadow: 0 0 0 3px var(--lt-bg-primary-subtle); outline: none; } :host([disabled]) .input-container { background: var(--lt-bg-surface); } .color-swatch { flex-shrink: 0; border-radius: 50%; border: 1.5px solid rgb(0 0 0 / 0.15); box-sizing: border-box; } .color-swatch.empty { border-style: dashed; border-color: var(--lt-border-default); background: repeating-conic-gradient(var(--lt-bg-muted) 0% 25%, transparent 0% 50%) 0 0 / 8px 8px; } .display-value { flex: 1; color: var(--lt-text-default); font-family: inherit; font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .display-value.is-placeholder { color: var(--lt-text-muted); } :host([disabled]) .display-value { color: var(--lt-text-muted); } .icon-end { flex-shrink: 0; color: var(--lt-text-muted); pointer-events: none; } /* The native picker is invisible but covers the entire container to handle all click/keyboard events */ .native-picker { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; border: none; padding: 0; } .native-picker:disabled { cursor: not-allowed; } /* ── sizes ───────────────────────────────────────────────────────────────── */ :host([size='sm']) .input-container { height: 32px; padding-inline: var(--lt-spacing-3); gap: var(--lt-spacing-2); font-size: 0.875rem; } :host([size='sm']) .color-swatch { width: 14px; height: 14px; } :host([size='md']) .input-container { height: 40px; padding-inline: var(--lt-spacing-4); gap: var(--lt-spacing-2); font-size: 1rem; } :host([size='md']) .color-swatch { width: 16px; height: 16px; } :host([size='lg']) .input-container { height: 48px; padding-inline: var(--lt-spacing-5); gap: var(--lt-spacing-3); font-size: 1.0625rem; } :host([size='lg']) .color-swatch { width: 20px; height: 20px; } :host([size='lg']) .icon-end { width: 24px; height: 24px; } `"
2459
+ "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); width: 100%; } .wrapper { display: flex; flex-direction: column; gap: var(--lt-spacing-1); width: 100%; cursor: pointer; } /* :host(:disabled) — the browser matches this automatically for a form-associated element inside a disabled <fieldset>, no JS required; :host([disabled]) covers the component's own explicit attribute. */ :host([disabled]) .wrapper, :host(:disabled) .wrapper { cursor: not-allowed; } .label { color: var(--lt-text-subtle); } .input-container { position: relative; display: flex; align-items: center; background: var(--lt-bg-subtle); border: var(--lt-border-width, 1px) solid var(--lt-border-default); border-radius: var(--lt-border-radius); box-sizing: border-box; transition: border-color 120ms ease, box-shadow 120ms ease; width: 100%; overflow: hidden; } .input-container:hover:not(:has(.native-picker:disabled)) { border-color: var(--lt-border-strong); } .input-container:focus-within { border-color: var(--lt-interactive-primary-bg); box-shadow: 0 0 0 3px var(--lt-bg-primary-subtle); outline: none; } :host([disabled]) .input-container, :host(:disabled) .input-container { background: var(--lt-bg-surface); } .color-swatch { flex-shrink: 0; border-radius: 50%; border: 1.5px solid rgb(0 0 0 / 0.15); box-sizing: border-box; } .color-swatch.empty { border-style: dashed; border-color: var(--lt-border-default); background: repeating-conic-gradient(var(--lt-bg-muted) 0% 25%, transparent 0% 50%) 0 0 / 8px 8px; } .display-value { flex: 1; color: var(--lt-text-default); font-family: inherit; font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .display-value.is-placeholder { color: var(--lt-text-muted); } :host([disabled]) .display-value, :host(:disabled) .display-value { color: var(--lt-text-muted); } .icon-end { flex-shrink: 0; color: var(--lt-text-muted); pointer-events: none; } /* The native picker is invisible but covers the entire container to handle all click/keyboard events */ .native-picker { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; border: none; padding: 0; } .native-picker:disabled { cursor: not-allowed; } /* ── sizes ───────────────────────────────────────────────────────────────── */ :host([size='sm']) .input-container { height: 32px; padding-inline: var(--lt-spacing-3); gap: var(--lt-spacing-2); font-size: 0.875rem; } :host([size='sm']) .color-swatch { width: 14px; height: 14px; } :host([size='md']) .input-container { height: 40px; padding-inline: var(--lt-spacing-4); gap: var(--lt-spacing-2); font-size: 1rem; } :host([size='md']) .color-swatch { width: 16px; height: 16px; } :host([size='lg']) .input-container { height: 48px; padding-inline: var(--lt-spacing-5); gap: var(--lt-spacing-3); font-size: 1.0625rem; } :host([size='lg']) .color-swatch { width: 20px; height: 20px; } :host([size='lg']) .icon-end { width: 24px; height: 24px; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { .input-container { transition: none; } } `"
2186
2460
  }
2187
2461
  ],
2188
2462
  "exports": [
@@ -2228,6 +2502,18 @@
2228
2502
  },
2229
2503
  "privacy": "private"
2230
2504
  },
2505
+ {
2506
+ "kind": "field",
2507
+ "name": "_default",
2508
+ "privacy": "private",
2509
+ "default": "new FormDefaultController(this, () => this.value)"
2510
+ },
2511
+ {
2512
+ "kind": "field",
2513
+ "name": "_fieldsetDisabled",
2514
+ "privacy": "private",
2515
+ "default": "new FormDisabledController(this)"
2516
+ },
2231
2517
  {
2232
2518
  "kind": "field",
2233
2519
  "name": "value",
@@ -2235,7 +2521,7 @@
2235
2521
  "text": "string"
2236
2522
  },
2237
2523
  "default": "''",
2238
- "description": "The current color value. Accepts hex (`#7c3aed`), rgb (`rgb(124, 58, 237)`),\nor hsl (`hsl(263, 70%, 58%)`). Emitted values match the `format` prop."
2524
+ "description": "The current color value. Accepts hex (`#7c3aed`), rgb (`rgb(124, 58, 237)`),\nor hsl (`hsl(263, 70%, 58%)`). Emitted values match the `format` prop. Not reflected as an attribute —\nread the property, or the `change` event's `detail.value`, instead of `getAttribute('value')`/`[value]`."
2239
2525
  },
2240
2526
  {
2241
2527
  "kind": "field",
@@ -2300,6 +2586,24 @@
2300
2586
  "default": "'md'",
2301
2587
  "description": "Size of the input — affects height and padding."
2302
2588
  },
2589
+ {
2590
+ "kind": "field",
2591
+ "name": "labels",
2592
+ "type": {
2593
+ "text": "Partial<ColorInputLabels>"
2594
+ },
2595
+ "default": "{}",
2596
+ "description": "Overridable UI text (the required-field validation message), for i18n. English defaults — override only the keys you need."
2597
+ },
2598
+ {
2599
+ "kind": "field",
2600
+ "name": "_labels",
2601
+ "type": {
2602
+ "text": "ColorInputLabels"
2603
+ },
2604
+ "privacy": "private",
2605
+ "readonly": true
2606
+ },
2303
2607
  {
2304
2608
  "kind": "method",
2305
2609
  "name": "updated"
@@ -2308,6 +2612,28 @@
2308
2612
  "kind": "method",
2309
2613
  "name": "formResetCallback"
2310
2614
  },
2615
+ {
2616
+ "kind": "method",
2617
+ "name": "formDisabledCallback",
2618
+ "parameters": [
2619
+ {
2620
+ "name": "disabled",
2621
+ "type": {
2622
+ "text": "boolean"
2623
+ }
2624
+ }
2625
+ ]
2626
+ },
2627
+ {
2628
+ "kind": "field",
2629
+ "name": "_isDisabled",
2630
+ "type": {
2631
+ "text": "boolean"
2632
+ },
2633
+ "privacy": "private",
2634
+ "description": "`this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`).",
2635
+ "readonly": true
2636
+ },
2311
2637
  {
2312
2638
  "kind": "method",
2313
2639
  "name": "checkValidity"
@@ -2387,7 +2713,7 @@
2387
2713
  "type": {
2388
2714
  "text": "array"
2389
2715
  },
2390
- "default": "[ floatingPanelReset, css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); position: relative; } .wrapper { display: flex; flex-direction: column; gap: var(--lt-spacing-1); } label { color: var(--lt-text-default); } .required-indicator { color: var(--lt-color-error-500); margin-left: 2px; } .input-wrap { align-items: center; background: var(--lt-bg-surface); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); cursor: text; display: flex; gap: var(--lt-spacing-2); overflow: hidden; position: relative; transition: border-color 150ms ease, box-shadow 150ms ease; } :host([open]) .input-wrap, .input-wrap:focus-within { border-color: var(--lt-border-primary); box-shadow: 0 0 0 3px var(--lt-bg-primary-subtle); } :host([variant='error']) .input-wrap { border-color: var(--lt-color-error-500); } :host([variant='error'][open]) .input-wrap, :host([variant='error']) .input-wrap:focus-within { box-shadow: 0 0 0 3px var(--lt-bg-error-subtle); } :host([variant='success']) .input-wrap { border-color: var(--lt-color-success-500); } :host([variant='warning']) .input-wrap { border-color: var(--lt-color-warning-500); } :host([disabled]) .input-wrap { background: var(--lt-bg-neutral-subtle); cursor: not-allowed; pointer-events: none; } input { background: transparent; border: none; color: var(--lt-text-default); flex: 1; font-family: inherit; min-width: 0; outline: none; } input::placeholder { color: var(--lt-text-placeholder, var(--lt-color-neutral-400)); } :host([disabled]) input { color: var(--lt-text-subtle); cursor: not-allowed; } /* Sizes */ :host([size='sm']) .input-wrap { height: 32px; padding: 0 var(--lt-spacing-2); } :host([size='sm']) input { font-size: 0.8125rem; } :host([size='md']) .input-wrap, :host(:not([size])) .input-wrap { height: 40px; padding: 0 var(--lt-spacing-3); } :host([size='md']) input, :host(:not([size])) input { font-size: 0.9375rem; } :host([size='lg']) .input-wrap { height: 48px; padding: 0 var(--lt-spacing-4); } :host([size='lg']) input { font-size: 1rem; } .chevron { color: var(--lt-text-subtle); flex-shrink: 0; pointer-events: none; transition: transform 150ms ease; } :host([open]) .chevron { transform: rotate(180deg); } .dropdown { background: var(--lt-bg-surface); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); box-shadow: var(--lt-shadow-md); max-height: 240px; overflow-y: auto; z-index: 100; } .option { align-items: center; background: transparent; border: none; color: var(--lt-text-default); cursor: pointer; display: flex; font-family: inherit; font-size: 0.9375rem; padding: var(--lt-spacing-2) var(--lt-spacing-3); text-align: left; width: 100%; } .option:hover { background: var(--lt-bg-neutral-subtle); } .option[aria-selected='true'] { background: var(--lt-bg-primary-subtle); color: var(--lt-color-primary-700); font-weight: 500; } .option[disabled] { color: var(--lt-text-subtle); cursor: not-allowed; pointer-events: none; } .no-results { color: var(--lt-text-subtle); font-size: 0.875rem; padding: var(--lt-spacing-3); text-align: center; } .helper-text { color: var(--lt-text-subtle); font-size: 0.8125rem; } :host([variant='error']) .helper-text { color: var(--lt-color-error-600); } :host([variant='success']) .helper-text { color: var(--lt-color-success-600); } :host([variant='warning']) .helper-text { color: var(--lt-color-warning-700); } ` ]"
2716
+ "default": "[ floatingPanelReset, css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); position: relative; } .wrapper { display: flex; flex-direction: column; gap: var(--lt-spacing-1); } label { color: var(--lt-text-default); } .required-indicator { color: var(--lt-text-error); margin-inline-start: 2px; } .input-wrap { align-items: center; background: var(--lt-bg-surface); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); cursor: text; display: flex; gap: var(--lt-spacing-2); overflow: hidden; position: relative; transition: border-color 150ms ease, box-shadow 150ms ease; } :host([open]) .input-wrap, .input-wrap:focus-within { border-color: var(--lt-border-primary); box-shadow: 0 0 0 3px var(--lt-bg-primary-subtle); } :host([variant='error']) .input-wrap { border-color: var(--lt-text-error); } :host([variant='error'][open]) .input-wrap, :host([variant='error']) .input-wrap:focus-within { box-shadow: 0 0 0 3px var(--lt-bg-error-subtle); } :host([variant='success']) .input-wrap { border-color: var(--lt-color-success-500); } :host([variant='warning']) .input-wrap { border-color: var(--lt-color-warning-500); } /* :host(:disabled) — the browser matches this automatically for a form-associated element inside a disabled <fieldset>, no JS required; :host([disabled]) covers the component's own explicit attribute. */ :host([disabled]) .input-wrap, :host(:disabled) .input-wrap { background: var(--lt-bg-neutral-subtle); cursor: not-allowed; pointer-events: none; } input { background: transparent; border: none; color: var(--lt-text-default); flex: 1; font-family: inherit; min-width: 0; outline: none; } input::placeholder { color: var(--lt-text-placeholder, var(--lt-color-neutral-400)); } :host([disabled]) input, :host(:disabled) input { color: var(--lt-text-subtle); cursor: not-allowed; } /* Sizes */ :host([size='sm']) .input-wrap { height: 32px; padding: 0 var(--lt-spacing-2); } :host([size='sm']) input { font-size: 0.8125rem; } :host([size='md']) .input-wrap, :host(:not([size])) .input-wrap { height: 40px; padding: 0 var(--lt-spacing-3); } :host([size='md']) input, :host(:not([size])) input { font-size: 0.9375rem; } :host([size='lg']) .input-wrap { height: 48px; padding: 0 var(--lt-spacing-4); } :host([size='lg']) input { font-size: 1rem; } .chevron { color: var(--lt-text-subtle); flex-shrink: 0; pointer-events: none; transition: transform 150ms ease; } :host([open]) .chevron { transform: rotate(180deg); } .dropdown { background: var(--lt-bg-surface); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); box-shadow: var(--lt-shadow-md); max-height: 240px; overflow-y: auto; z-index: 100; } .option { align-items: center; background: transparent; border: none; color: var(--lt-text-default); cursor: pointer; display: flex; font-family: inherit; font-size: 0.9375rem; padding: var(--lt-spacing-2) var(--lt-spacing-3); text-align: start; width: 100%; } .option:hover { background: var(--lt-bg-neutral-subtle); } .option[data-active='true'] { background: var(--lt-bg-neutral-subtle); outline: 2px solid var(--lt-interactive-primary-bg); outline-offset: -2px; } .option[aria-selected='true'] { background: var(--lt-bg-primary-subtle); color: var(--lt-text-primary); font-weight: 500; } .option[disabled] { color: var(--lt-text-subtle); cursor: not-allowed; pointer-events: none; } .no-results { color: var(--lt-text-subtle); font-size: 0.875rem; padding: var(--lt-spacing-3); text-align: center; } .helper-text { color: var(--lt-text-subtle); font-size: 0.8125rem; } :host([variant='error']) .helper-text { color: var(--lt-text-error); } :host([variant='success']) .helper-text { color: var(--lt-text-success); } :host([variant='warning']) .helper-text { color: var(--lt-text-warning); } /* ── Reduced motion ───────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { .input-wrap, .chevron { transition: none; } } ` ]"
2391
2717
  }
2392
2718
  ],
2393
2719
  "exports": [
@@ -2435,9 +2761,28 @@
2435
2761
  },
2436
2762
  {
2437
2763
  "kind": "field",
2438
- "name": "options",
2439
- "type": {
2440
- "text": "ComboboxOption[]"
2764
+ "name": "_default",
2765
+ "privacy": "private",
2766
+ "default": "new FormDefaultController(this, () => this.value)"
2767
+ },
2768
+ {
2769
+ "kind": "field",
2770
+ "name": "_fieldsetDisabled",
2771
+ "privacy": "private",
2772
+ "default": "new FormDisabledController(this)"
2773
+ },
2774
+ {
2775
+ "kind": "field",
2776
+ "name": "_uid",
2777
+ "privacy": "private",
2778
+ "readonly": true,
2779
+ "default": "`lt-combobox-${comboboxCount++}`"
2780
+ },
2781
+ {
2782
+ "kind": "field",
2783
+ "name": "options",
2784
+ "type": {
2785
+ "text": "ComboboxOption[]"
2441
2786
  },
2442
2787
  "default": "[]",
2443
2788
  "description": "Array of selectable options. Set as a JS property (`.options`)."
@@ -2449,7 +2794,7 @@
2449
2794
  "text": "string"
2450
2795
  },
2451
2796
  "default": "''",
2452
- "description": "Currently selected value."
2797
+ "description": "Currently selected value. Not reflected as an attribute — read the property, or the `change` event's\n`detail.value`, instead of `getAttribute('value')`/`[value]` (consistent with the rest of the form\ncontrols; see `lt-textfield`'s equivalent doc comment for why)."
2453
2798
  },
2454
2799
  {
2455
2800
  "kind": "field",
@@ -2523,6 +2868,24 @@
2523
2868
  "default": "''",
2524
2869
  "description": "Name used in form submission."
2525
2870
  },
2871
+ {
2872
+ "kind": "field",
2873
+ "name": "labels",
2874
+ "type": {
2875
+ "text": "Partial<ComboboxLabels>"
2876
+ },
2877
+ "default": "{}",
2878
+ "description": "Overridable UI text (validation message, \"no results\" text), for i18n. English defaults — override only the keys you need."
2879
+ },
2880
+ {
2881
+ "kind": "field",
2882
+ "name": "_labels",
2883
+ "type": {
2884
+ "text": "ComboboxLabels"
2885
+ },
2886
+ "privacy": "private",
2887
+ "readonly": true
2888
+ },
2526
2889
  {
2527
2890
  "kind": "field",
2528
2891
  "name": "query",
@@ -2568,6 +2931,12 @@
2568
2931
  "privacy": "private",
2569
2932
  "default": "null"
2570
2933
  },
2934
+ {
2935
+ "kind": "field",
2936
+ "name": "_fieldIds",
2937
+ "privacy": "private",
2938
+ "readonly": true
2939
+ },
2571
2940
  {
2572
2941
  "kind": "field",
2573
2942
  "name": "selectedLabel",
@@ -2586,6 +2955,46 @@
2586
2955
  "privacy": "private",
2587
2956
  "readonly": true
2588
2957
  },
2958
+ {
2959
+ "kind": "field",
2960
+ "name": "enabledOpts",
2961
+ "type": {
2962
+ "text": "ComboboxOption[]"
2963
+ },
2964
+ "privacy": "private",
2965
+ "readonly": true
2966
+ },
2967
+ {
2968
+ "kind": "method",
2969
+ "name": "_idFor",
2970
+ "privacy": "private",
2971
+ "return": {
2972
+ "type": {
2973
+ "text": "string"
2974
+ }
2975
+ },
2976
+ "parameters": [
2977
+ {
2978
+ "name": "opt",
2979
+ "type": {
2980
+ "text": "ComboboxOption"
2981
+ }
2982
+ }
2983
+ ]
2984
+ },
2985
+ {
2986
+ "kind": "method",
2987
+ "name": "_preventFocusSteal",
2988
+ "privacy": "private",
2989
+ "parameters": [
2990
+ {
2991
+ "name": "e",
2992
+ "type": {
2993
+ "text": "MouseEvent"
2994
+ }
2995
+ }
2996
+ ]
2997
+ },
2589
2998
  {
2590
2999
  "kind": "method",
2591
3000
  "name": "openDropdown",
@@ -2640,6 +3049,11 @@
2640
3049
  }
2641
3050
  ]
2642
3051
  },
3052
+ {
3053
+ "kind": "field",
3054
+ "name": "_onFocusOut",
3055
+ "privacy": "private"
3056
+ },
2643
3057
  {
2644
3058
  "kind": "method",
2645
3059
  "name": "updated"
@@ -2648,6 +3062,28 @@
2648
3062
  "kind": "method",
2649
3063
  "name": "formResetCallback"
2650
3064
  },
3065
+ {
3066
+ "kind": "method",
3067
+ "name": "formDisabledCallback",
3068
+ "parameters": [
3069
+ {
3070
+ "name": "disabled",
3071
+ "type": {
3072
+ "text": "boolean"
3073
+ }
3074
+ }
3075
+ ]
3076
+ },
3077
+ {
3078
+ "kind": "field",
3079
+ "name": "_isDisabled",
3080
+ "type": {
3081
+ "text": "boolean"
3082
+ },
3083
+ "privacy": "private",
3084
+ "description": "`this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`).",
3085
+ "readonly": true
3086
+ },
2651
3087
  {
2652
3088
  "kind": "method",
2653
3089
  "name": "checkValidity"
@@ -2738,7 +3174,7 @@
2738
3174
  "type": {
2739
3175
  "text": "array"
2740
3176
  },
2741
- "default": "[ floatingPanelReset, css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .wrapper { display: flex; flex-direction: column; gap: var(--lt-spacing-1); } label { color: var(--lt-text-default); cursor: default; } .required-indicator { color: var(--lt-color-error-500); margin-left: 2px; } /* ── Field ── */ .field { position: relative; } .field-btn { align-items: center; background: var(--lt-bg-surface); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); color: var(--lt-text-default); cursor: pointer; display: flex; font-family: inherit; justify-content: space-between; outline: none; text-align: left; transition: border-color 150ms ease, box-shadow 150ms ease; width: 100%; } .field-btn:focus-visible { border-color: var(--lt-border-primary); box-shadow: 0 0 0 3px var(--lt-bg-primary-subtle); } .field-btn:disabled { background: var(--lt-bg-neutral-subtle); color: var(--lt-text-subtle); cursor: not-allowed; } .display-value { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .display-value--placeholder { color: var(--lt-text-muted); } .calendar-icon { color: var(--lt-text-subtle); flex-shrink: 0; line-height: 0; margin-left: var(--lt-spacing-2); } /* ── Sizes ── */ :host([size='sm']) .field-btn { font-size: 0.8125rem; height: 32px; padding: 0 var(--lt-spacing-2); } :host([size='md']) .field-btn, :host(:not([size])) .field-btn { font-size: 0.9375rem; height: 40px; padding: 0 var(--lt-spacing-3); } :host([size='lg']) .field-btn { font-size: 1rem; height: 48px; padding: 0 var(--lt-spacing-4); } /* ── Variants ── */ :host([variant='success']) .field-btn { border-color: var(--lt-color-success-500); } :host([variant='success']) .field-btn:focus-visible { box-shadow: 0 0 0 3px var(--lt-bg-success-subtle); } :host([variant='warning']) .field-btn { border-color: var(--lt-color-warning-500); } :host([variant='warning']) .field-btn:focus-visible { box-shadow: 0 0 0 3px var(--lt-bg-warning-subtle); } :host([variant='error']) .field-btn { border-color: var(--lt-color-error-500); } :host([variant='error']) .field-btn:focus-visible { box-shadow: 0 0 0 3px var(--lt-bg-error-subtle); } /* ── Dropdown ── */ .dropdown { display: none; filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.08)); z-index: 9999; } /* ── Helper text ── */ .helper-text { color: var(--lt-text-subtle); font-size: 0.8125rem; } :host([variant='error']) .helper-text { color: var(--lt-color-error-600); } :host([variant='success']) .helper-text { color: var(--lt-color-success-600); } :host([variant='warning']) .helper-text { color: var(--lt-color-warning-700); } ` ]"
3177
+ "default": "[ floatingPanelReset, css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .wrapper { display: flex; flex-direction: column; gap: var(--lt-spacing-1); } label { color: var(--lt-text-default); cursor: default; } .required-indicator { color: var(--lt-text-error); margin-inline-start: 2px; } /* ── Field ── */ .field { position: relative; } .field-btn { align-items: center; background: var(--lt-bg-surface); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); color: var(--lt-text-default); cursor: pointer; display: flex; font-family: inherit; justify-content: space-between; outline: none; text-align: start; transition: border-color 150ms ease, box-shadow 150ms ease; width: 100%; } .field-btn:focus-visible { border-color: var(--lt-border-primary); box-shadow: 0 0 0 3px var(--lt-bg-primary-subtle); } .field-btn:disabled { background: var(--lt-bg-neutral-subtle); color: var(--lt-text-subtle); cursor: not-allowed; } .display-value { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .display-value--placeholder { color: var(--lt-text-muted); } .calendar-icon { color: var(--lt-text-subtle); flex-shrink: 0; line-height: 0; margin-inline-start: var(--lt-spacing-2); } /* ── Sizes ── */ :host([size='sm']) .field-btn { font-size: 0.8125rem; height: 32px; padding: 0 var(--lt-spacing-2); } :host([size='md']) .field-btn, :host(:not([size])) .field-btn { font-size: 0.9375rem; height: 40px; padding: 0 var(--lt-spacing-3); } :host([size='lg']) .field-btn { font-size: 1rem; height: 48px; padding: 0 var(--lt-spacing-4); } /* ── Variants ── */ :host([variant='success']) .field-btn { border-color: var(--lt-color-success-500); } :host([variant='success']) .field-btn:focus-visible { box-shadow: 0 0 0 3px var(--lt-bg-success-subtle); } :host([variant='warning']) .field-btn { border-color: var(--lt-color-warning-500); } :host([variant='warning']) .field-btn:focus-visible { box-shadow: 0 0 0 3px var(--lt-bg-warning-subtle); } :host([variant='error']) .field-btn { border-color: var(--lt-text-error); } :host([variant='error']) .field-btn:focus-visible { box-shadow: 0 0 0 3px var(--lt-bg-error-subtle); } /* ── Dropdown ── */ .dropdown { display: none; filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.08)); z-index: 9999; } /* ── Helper text ── */ .helper-text { color: var(--lt-text-subtle); font-size: 0.8125rem; } :host([variant='error']) .helper-text { color: var(--lt-text-error); } :host([variant='success']) .helper-text { color: var(--lt-text-success); } :host([variant='warning']) .helper-text { color: var(--lt-text-warning); } /* ── Reduced motion ───────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { .field-btn { transition: none; } } ` ]"
2742
3178
  }
2743
3179
  ],
2744
3180
  "exports": [
@@ -2784,6 +3220,18 @@
2784
3220
  },
2785
3221
  "privacy": "private"
2786
3222
  },
3223
+ {
3224
+ "kind": "field",
3225
+ "name": "_default",
3226
+ "privacy": "private",
3227
+ "default": "new FormDefaultController(this, () => this.value)"
3228
+ },
3229
+ {
3230
+ "kind": "field",
3231
+ "name": "_fieldsetDisabled",
3232
+ "privacy": "private",
3233
+ "default": "new FormDisabledController(this)"
3234
+ },
2787
3235
  {
2788
3236
  "kind": "field",
2789
3237
  "name": "value",
@@ -2791,7 +3239,7 @@
2791
3239
  "text": "string"
2792
3240
  },
2793
3241
  "default": "''",
2794
- "description": "Selected date in ISO format (YYYY-MM-DD)."
3242
+ "description": "Selected date in ISO format (YYYY-MM-DD). Not reflected as an attribute — read the property, or the\n`change` event's `detail.value`, instead of `getAttribute('value')`/`[value]`."
2795
3243
  },
2796
3244
  {
2797
3245
  "kind": "field",
@@ -2833,10 +3281,9 @@
2833
3281
  "kind": "field",
2834
3282
  "name": "weekStart",
2835
3283
  "type": {
2836
- "text": "'0' | '1'"
3284
+ "text": "CalendarWeekStart | undefined"
2837
3285
  },
2838
- "default": "'0'",
2839
- "description": "First day of the week in the calendar. 0 = Sunday, 1 = Monday."
3286
+ "description": "First day of the week in the calendar (0 = Sunday … 6 = Saturday). Defaults to whatever `locale` implies —\nset this explicitly only to override that. Forwarded as-is to the internal `lt-calendar`, which does the\nactual derivation when this is left unset."
2840
3287
  },
2841
3288
  {
2842
3289
  "kind": "field",
@@ -2908,7 +3355,7 @@
2908
3355
  "text": "string"
2909
3356
  },
2910
3357
  "default": "''",
2911
- "description": "Name used in form submission via a hidden input."
3358
+ "description": "Name used in form submission (through `ElementInternals`, so no hidden input is rendered)."
2912
3359
  },
2913
3360
  {
2914
3361
  "kind": "field",
@@ -2917,7 +3364,25 @@
2917
3364
  "text": "Calendar['disabledDates']"
2918
3365
  },
2919
3366
  "default": "[]",
2920
- "description": "Individual dates to disable in the calendar, as Date objects."
3367
+ "description": "Individual dates to disable in the calendar, as Date objects. Set as a JS property (`.disabledDates`)."
3368
+ },
3369
+ {
3370
+ "kind": "field",
3371
+ "name": "labels",
3372
+ "type": {
3373
+ "text": "Partial<DateInputLabels>"
3374
+ },
3375
+ "default": "{}",
3376
+ "description": "Overridable UI text (validation message, calendar popover's accessible label), for i18n. English defaults — override only the keys you need."
3377
+ },
3378
+ {
3379
+ "kind": "field",
3380
+ "name": "_labels",
3381
+ "type": {
3382
+ "text": "DateInputLabels"
3383
+ },
3384
+ "privacy": "private",
3385
+ "readonly": true
2921
3386
  },
2922
3387
  {
2923
3388
  "kind": "field",
@@ -2946,6 +3411,12 @@
2946
3411
  "privacy": "private",
2947
3412
  "default": "null"
2948
3413
  },
3414
+ {
3415
+ "kind": "field",
3416
+ "name": "_fieldIds",
3417
+ "privacy": "private",
3418
+ "readonly": true
3419
+ },
2949
3420
  {
2950
3421
  "kind": "field",
2951
3422
  "name": "_displayValue",
@@ -2993,12 +3464,42 @@
2993
3464
  },
2994
3465
  {
2995
3466
  "kind": "method",
2996
- "name": "updated"
3467
+ "name": "updated",
3468
+ "parameters": [
3469
+ {
3470
+ "name": "changed",
3471
+ "type": {
3472
+ "text": "Map<string, unknown>"
3473
+ }
3474
+ }
3475
+ ]
2997
3476
  },
2998
3477
  {
2999
3478
  "kind": "method",
3000
3479
  "name": "formResetCallback"
3001
3480
  },
3481
+ {
3482
+ "kind": "method",
3483
+ "name": "formDisabledCallback",
3484
+ "parameters": [
3485
+ {
3486
+ "name": "disabled",
3487
+ "type": {
3488
+ "text": "boolean"
3489
+ }
3490
+ }
3491
+ ]
3492
+ },
3493
+ {
3494
+ "kind": "field",
3495
+ "name": "_isDisabled",
3496
+ "type": {
3497
+ "text": "boolean"
3498
+ },
3499
+ "privacy": "private",
3500
+ "description": "`this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`).",
3501
+ "readonly": true
3502
+ },
3002
3503
  {
3003
3504
  "kind": "method",
3004
3505
  "name": "checkValidity"
@@ -3086,7 +3587,7 @@
3086
3587
  {
3087
3588
  "kind": "variable",
3088
3589
  "name": "datepickerStyles",
3089
- "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .wrapper { display: flex; flex-direction: column; gap: var(--lt-spacing-1); } label { color: var(--lt-text-default); display: flex; flex-direction: column; gap: var(--lt-spacing-1); } .required-indicator { color: var(--lt-color-error-500); } input { background: var(--lt-bg-surface); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); color: var(--lt-text-default); font-family: inherit; font-size: 0.9375rem; outline: none; transition: border-color 150ms ease, box-shadow 150ms ease; width: 100%; box-sizing: border-box; } input:focus { border-color: var(--lt-border-primary); box-shadow: 0 0 0 3px var(--lt-bg-primary-subtle); } input:disabled { background: var(--lt-bg-neutral-subtle); color: var(--lt-text-subtle); cursor: not-allowed; } /* Sizes */ :host([size='sm']) input { font-size: 0.8125rem; height: 32px; padding: 0 var(--lt-spacing-2); } :host([size='md']) input, :host(:not([size])) input { font-size: 0.9375rem; height: 40px; padding: 0 var(--lt-spacing-3); } :host([size='lg']) input { font-size: 1rem; height: 48px; padding: 0 var(--lt-spacing-4); } /* Variants */ :host([variant='success']) input { border-color: var(--lt-color-success-500); } :host([variant='success']) input:focus { box-shadow: 0 0 0 3px var(--lt-bg-success-subtle); } :host([variant='warning']) input { border-color: var(--lt-color-warning-500); } :host([variant='warning']) input:focus { box-shadow: 0 0 0 3px var(--lt-bg-warning-subtle); } :host([variant='error']) input { border-color: var(--lt-color-error-500); } :host([variant='error']) input:focus { box-shadow: 0 0 0 3px var(--lt-bg-error-subtle); } .helper-text { color: var(--lt-text-subtle); font-size: 0.8125rem; } :host([variant='error']) .helper-text { color: var(--lt-color-error-600); } :host([variant='success']) .helper-text { color: var(--lt-color-success-600); } :host([variant='warning']) .helper-text { color: var(--lt-color-warning-700); } `"
3590
+ "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .wrapper { display: flex; flex-direction: column; gap: var(--lt-spacing-1); } label { color: var(--lt-text-default); display: flex; flex-direction: column; gap: var(--lt-spacing-1); } .required-indicator { color: var(--lt-text-error); } input { background: var(--lt-bg-surface); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); color: var(--lt-text-default); font-family: inherit; font-size: 0.9375rem; outline: none; transition: border-color 150ms ease, box-shadow 150ms ease; width: 100%; box-sizing: border-box; } input:focus { border-color: var(--lt-border-primary); box-shadow: 0 0 0 3px var(--lt-bg-primary-subtle); } input:disabled { background: var(--lt-bg-neutral-subtle); color: var(--lt-text-subtle); cursor: not-allowed; } /* Sizes */ :host([size='sm']) input { font-size: 0.8125rem; height: 32px; padding: 0 var(--lt-spacing-2); } :host([size='md']) input, :host(:not([size])) input { font-size: 0.9375rem; height: 40px; padding: 0 var(--lt-spacing-3); } :host([size='lg']) input { font-size: 1rem; height: 48px; padding: 0 var(--lt-spacing-4); } /* Variants */ :host([variant='success']) input { border-color: var(--lt-color-success-500); } :host([variant='success']) input:focus { box-shadow: 0 0 0 3px var(--lt-bg-success-subtle); } :host([variant='warning']) input { border-color: var(--lt-color-warning-500); } :host([variant='warning']) input:focus { box-shadow: 0 0 0 3px var(--lt-bg-warning-subtle); } :host([variant='error']) input { border-color: var(--lt-text-error); } :host([variant='error']) input:focus { box-shadow: 0 0 0 3px var(--lt-bg-error-subtle); } .helper-text { color: var(--lt-text-subtle); font-size: 0.8125rem; } :host([variant='error']) .helper-text { color: var(--lt-text-error); } :host([variant='success']) .helper-text { color: var(--lt-text-success); } :host([variant='warning']) .helper-text { color: var(--lt-text-warning); } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { input { transition: none; } } `"
3090
3591
  }
3091
3592
  ],
3092
3593
  "exports": [
@@ -3132,6 +3633,18 @@
3132
3633
  },
3133
3634
  "privacy": "private"
3134
3635
  },
3636
+ {
3637
+ "kind": "field",
3638
+ "name": "_default",
3639
+ "privacy": "private",
3640
+ "default": "new FormDefaultController(this, () => this.value)"
3641
+ },
3642
+ {
3643
+ "kind": "field",
3644
+ "name": "_fieldsetDisabled",
3645
+ "privacy": "private",
3646
+ "default": "new FormDisabledController(this)"
3647
+ },
3135
3648
  {
3136
3649
  "kind": "field",
3137
3650
  "name": "type",
@@ -3148,7 +3661,7 @@
3148
3661
  "text": "string"
3149
3662
  },
3150
3663
  "default": "''",
3151
- "description": "Current value in the format required by the native input (`YYYY-MM-DD`, `HH:MM`, or `YYYY-MM-DDTHH:MM`)."
3664
+ "description": "Current value in the format required by the native input (`YYYY-MM-DD`, `HH:MM`, or `YYYY-MM-DDTHH:MM`).\nNot reflected as an attribute — read the property, or the `change` event's `detail.value`, instead of\n`getAttribute('value')`/`[value]`."
3152
3665
  },
3153
3666
  {
3154
3667
  "kind": "field",
@@ -3186,6 +3699,12 @@
3186
3699
  "default": "''",
3187
3700
  "description": "Helper or error text displayed below the input."
3188
3701
  },
3702
+ {
3703
+ "kind": "field",
3704
+ "name": "_fieldIds",
3705
+ "privacy": "private",
3706
+ "readonly": true
3707
+ },
3189
3708
  {
3190
3709
  "kind": "field",
3191
3710
  "name": "variant",
@@ -3265,6 +3784,28 @@
3265
3784
  "kind": "method",
3266
3785
  "name": "formResetCallback"
3267
3786
  },
3787
+ {
3788
+ "kind": "method",
3789
+ "name": "formDisabledCallback",
3790
+ "parameters": [
3791
+ {
3792
+ "name": "disabled",
3793
+ "type": {
3794
+ "text": "boolean"
3795
+ }
3796
+ }
3797
+ ]
3798
+ },
3799
+ {
3800
+ "kind": "field",
3801
+ "name": "_isDisabled",
3802
+ "type": {
3803
+ "text": "boolean"
3804
+ },
3805
+ "privacy": "private",
3806
+ "description": "`this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`).",
3807
+ "readonly": true
3808
+ },
3268
3809
  {
3269
3810
  "kind": "method",
3270
3811
  "name": "checkValidity"
@@ -3276,12 +3817,28 @@
3276
3817
  {
3277
3818
  "kind": "method",
3278
3819
  "name": "handleChange",
3279
- "privacy": "private"
3820
+ "privacy": "private",
3821
+ "parameters": [
3822
+ {
3823
+ "name": "e",
3824
+ "type": {
3825
+ "text": "Event"
3826
+ }
3827
+ }
3828
+ ]
3280
3829
  },
3281
3830
  {
3282
3831
  "kind": "method",
3283
3832
  "name": "handleInput",
3284
- "privacy": "private"
3833
+ "privacy": "private",
3834
+ "parameters": [
3835
+ {
3836
+ "name": "e",
3837
+ "type": {
3838
+ "text": "Event"
3839
+ }
3840
+ }
3841
+ ]
3285
3842
  },
3286
3843
  {
3287
3844
  "kind": "method",
@@ -3369,7 +3926,7 @@
3369
3926
  {
3370
3927
  "kind": "variable",
3371
3928
  "name": "dialogStyles",
3372
- "default": "css` :host { font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } /* Backdrop */ .backdrop { align-items: center; background: rgba(0, 0, 0, var(--lt-dialog-overlay-opacity, 0.5)); display: flex; height: 100vh; justify-content: center; left: 0; opacity: 0; padding: var(--lt-spacing-4); position: fixed; top: 0; transition: opacity 200ms ease; width: 100vw; z-index: 1000; } :host([open]) .backdrop { opacity: 1; } :host(:not([open])) .backdrop { pointer-events: none; } /* lt-surface host — flex item inside .backdrop, sized per size variant */ lt-surface { width: 100%; } :host([size='sm']) lt-surface { max-width: 400px; } :host([size='md']) lt-surface { max-width: 600px; } :host([size='lg']) lt-surface { max-width: 800px; } :host([size='xl']) lt-surface { max-width: 1000px; } :host([size='fullscreen']) .backdrop { padding: 0; } :host([size='fullscreen']) lt-surface { height: 100vh; max-height: 100vh; max-width: 100vw; } /* lt-surface inner div — layout and animation */ lt-surface::part(surface) { display: flex; flex-direction: column; max-height: calc(100vh - var(--lt-spacing-8)); opacity: 0; position: relative; transform: translateY(16px); transition: opacity 220ms ease, transform 220ms cubic-bezier(0.34, 1.2, 0.64, 1); } :host([open]) lt-surface::part(surface) { opacity: 1; transform: translateY(0); } :host([size='fullscreen']) lt-surface::part(surface) { border-radius: 0; max-height: 100vh; } /* Header */ .header { align-items: center; border-bottom: 1px solid var(--lt-border-default); display: flex; gap: var(--lt-spacing-4); padding: var(--lt-spacing-5); position: relative; } .header-content { flex: 1; } .title { color: var(--lt-text-default); } .close-button { flex-shrink: 0; } /* Body */ .body { color: var(--lt-color-neutral-700); flex: 1; overflow-y: auto; padding: var(--lt-spacing-5); } /* Footer */ .footer { border-top: 1px solid var(--lt-border-default); display: flex; gap: var(--lt-spacing-3); justify-content: flex-end; padding: var(--lt-spacing-5); } :host([uppercase]) .title::part(base) { font-variant-caps: small-caps; letter-spacing: 0.05rem; text-transform: lowercase; } `"
3929
+ "default": "css` :host { font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } /* The native <dialog> is the modal surface now — its own showModal()/close() give the top-layer stacking, focus trap and inert background for free (DLG-1). Reset its UA-default border/padding/background (a native <dialog> renders with a visible border and white background by default) so lt-surface, not the browser's own chrome, controls how it looks. Width/height are viewport-relative with a spacing-4 inset on each side (matching the old .backdrop's padding), capped per size variant below. */ dialog { background: transparent; border: none; max-height: calc(100vh - var(--lt-spacing-8)); overflow: visible; padding: 0; width: calc(100vw - var(--lt-spacing-8)); /* display/overlay (top-layer membership) are the only things animated on <dialog> itself — the entrance/exit motion (opacity + translateY) lives on lt-surface below, unaffected by any of this. Without these, close() would remove the dialog (and its ::backdrop) from rendering instantly, cutting that motion off partway through; allow-discrete keeps it rendered for the transition's duration instead, then removes it. */ transition: display 220ms allow-discrete, overlay 220ms allow-discrete; } :host([size='sm']) dialog { max-width: 400px; } :host([size='md']) dialog { max-width: 600px; } :host([size='lg']) dialog { max-width: 800px; } :host([size='xl']) dialog { max-width: 1000px; } :host([size='fullscreen']) dialog { height: 100vh; max-height: 100vh; max-width: 100vw; width: 100vw; } /* ::backdrop replaces the old .backdrop div — it's a real paintable box (just not a real DOM node), so its own background-color transition plays independently of lt-surface's. */ dialog::backdrop { background: rgba(0, 0, 0, 0); transition: background-color 200ms ease, display 220ms allow-discrete, overlay 220ms allow-discrete; } dialog[open]::backdrop { background: rgba(0, 0, 0, var(--lt-dialog-overlay-opacity, 0.5)); } /* lt-surface — fills the <dialog>, sized by it (max-width/height above); the entrance/exit animation */ lt-surface { display: flex; flex-direction: column; height: 100%; opacity: 0; transform: translateY(16px); transition: opacity 220ms ease, transform 220ms cubic-bezier(0.34, 1.2, 0.64, 1); width: 100%; } dialog[open] lt-surface { opacity: 1; transform: translateY(0); } lt-surface::part(surface) { display: flex; flex: 1; flex-direction: column; min-height: 0; } /* Header */ .header { align-items: center; border-bottom: 1px solid var(--lt-border-default); display: flex; gap: var(--lt-spacing-4); padding: var(--lt-spacing-5); position: relative; } .header-content { flex: 1; } .title { color: var(--lt-text-default); } .close-button { flex-shrink: 0; } /* Body */ .body { color: var(--lt-text-neutral); flex: 1; overflow-y: auto; padding: var(--lt-spacing-5); } /* Footer */ .footer { border-top: 1px solid var(--lt-border-default); display: flex; gap: var(--lt-spacing-3); justify-content: flex-end; padding: var(--lt-spacing-5); } :host([uppercase]) .title::part(base) { font-variant-caps: small-caps; letter-spacing: 0.05rem; text-transform: lowercase; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { dialog, dialog::backdrop, lt-surface { transition: none; } } `"
3373
3930
  }
3374
3931
  ],
3375
3932
  "exports": [
@@ -3389,7 +3946,7 @@
3389
3946
  "declarations": [
3390
3947
  {
3391
3948
  "kind": "class",
3392
- "description": "Dialog component (modal) with backdrop, animations, and accessibility features.",
3949
+ "description": "Dialog component (modal) built on the native `<dialog>` element, with a backdrop, animations, and full\naccessibility features for free — top-layer stacking, a real focus trap, an inert page background, and\nEscape-to-close all come from the platform (`showModal()`), not from anything this component builds itself\n(DLG-1). Body scroll locking is the one thing native `<dialog>` doesn't do on its own — this component keeps\nits own ref-counted lock for that (DLG-3, see `shared/scroll-lock.ts`).",
3393
3950
  "name": "Dialog",
3394
3951
  "slots": [
3395
3952
  {
@@ -3397,7 +3954,7 @@
3397
3954
  "name": ""
3398
3955
  },
3399
3956
  {
3400
- "description": "Custom header content (overrides title prop)",
3957
+ "description": "Custom header content (overrides heading prop)",
3401
3958
  "name": "header"
3402
3959
  },
3403
3960
  {
@@ -3435,12 +3992,20 @@
3435
3992
  },
3436
3993
  {
3437
3994
  "kind": "field",
3438
- "name": "title",
3995
+ "name": "heading",
3439
3996
  "type": {
3440
3997
  "text": "string"
3441
3998
  },
3442
3999
  "default": "''",
3443
- "description": "Dialog title displayed in the header."
4000
+ "description": "Dialog heading displayed in the header."
4001
+ },
4002
+ {
4003
+ "kind": "field",
4004
+ "name": "title",
4005
+ "type": {
4006
+ "text": "string"
4007
+ },
4008
+ "deprecated": "Use `heading` instead. `title` collides with the browser's own native tooltip attribute — every\nHTML element has one regardless of custom-element status, so `<lt-dialog title=\"…\">` made hovering anywhere\nover the dialog show a browser tooltip, and assistive tech could read it as a duplicate description (DLG-6).\nThis alias keeps existing markup/JS working; the native `title` attribute is always stripped as soon as\nit's read, so the tooltip never appears."
3444
4009
  },
3445
4010
  {
3446
4011
  "kind": "field",
@@ -3476,7 +4041,7 @@
3476
4041
  "text": "boolean"
3477
4042
  },
3478
4043
  "default": "false",
3479
- "description": "Renders the dialog title in small caps with wider letter spacing."
4044
+ "description": "Renders the dialog heading in small caps with wider letter spacing."
3480
4045
  },
3481
4046
  {
3482
4047
  "kind": "field",
@@ -3505,11 +4070,29 @@
3505
4070
  "default": "'filled'",
3506
4071
  "description": "Visual appearance of the internal surface, matching `lt-surface`'s vocabulary."
3507
4072
  },
4073
+ {
4074
+ "kind": "field",
4075
+ "name": "labels",
4076
+ "type": {
4077
+ "text": "Partial<DialogLabels>"
4078
+ },
4079
+ "default": "{}",
4080
+ "description": "Overridable UI text (the close button's accessible name), for i18n. English defaults — override only the keys you need."
4081
+ },
4082
+ {
4083
+ "kind": "field",
4084
+ "name": "_labels",
4085
+ "type": {
4086
+ "text": "DialogLabels"
4087
+ },
4088
+ "privacy": "private",
4089
+ "readonly": true
4090
+ },
3508
4091
  {
3509
4092
  "kind": "field",
3510
4093
  "name": "dialogElement",
3511
4094
  "type": {
3512
- "text": "HTMLElement | undefined"
4095
+ "text": "HTMLDialogElement | undefined"
3513
4096
  },
3514
4097
  "privacy": "private"
3515
4098
  },
@@ -3521,6 +4104,24 @@
3521
4104
  },
3522
4105
  "privacy": "private"
3523
4106
  },
4107
+ {
4108
+ "kind": "field",
4109
+ "name": "_scrollLocked",
4110
+ "type": {
4111
+ "text": "boolean"
4112
+ },
4113
+ "privacy": "private",
4114
+ "default": "false"
4115
+ },
4116
+ {
4117
+ "kind": "field",
4118
+ "name": "_skipNextOpenChange",
4119
+ "type": {
4120
+ "text": "boolean"
4121
+ },
4122
+ "privacy": "private",
4123
+ "default": "true"
4124
+ },
3524
4125
  {
3525
4126
  "kind": "method",
3526
4127
  "name": "show",
@@ -3539,6 +4140,11 @@
3539
4140
  "privacy": "public",
3540
4141
  "description": "Toggles the dialog open/closed state."
3541
4142
  },
4143
+ {
4144
+ "kind": "method",
4145
+ "name": "firstUpdated",
4146
+ "privacy": "protected"
4147
+ },
3542
4148
  {
3543
4149
  "kind": "method",
3544
4150
  "name": "updated",
@@ -3546,7 +4152,7 @@
3546
4152
  {
3547
4153
  "name": "changedProperties",
3548
4154
  "type": {
3549
- "text": "Map<string, unknown>"
4155
+ "text": "PropertyValues<this>"
3550
4156
  }
3551
4157
  }
3552
4158
  ]
@@ -3568,21 +4174,18 @@
3568
4174
  },
3569
4175
  {
3570
4176
  "kind": "field",
3571
- "name": "handleKeydown",
4177
+ "name": "_handleCancel",
3572
4178
  "privacy": "private"
3573
4179
  },
3574
4180
  {
3575
- "kind": "method",
3576
- "name": "handleBackdropClick",
3577
- "privacy": "private",
3578
- "parameters": [
3579
- {
3580
- "name": "event",
3581
- "type": {
3582
- "text": "MouseEvent"
3583
- }
3584
- }
3585
- ]
4181
+ "kind": "field",
4182
+ "name": "_handleNativeClose",
4183
+ "privacy": "private"
4184
+ },
4185
+ {
4186
+ "kind": "field",
4187
+ "name": "_handleDialogClick",
4188
+ "privacy": "private"
3586
4189
  },
3587
4190
  {
3588
4191
  "kind": "method",
@@ -3614,29 +4217,18 @@
3614
4217
  ],
3615
4218
  "events": [
3616
4219
  {
3617
- "name": "dialog-open",
4220
+ "name": "open",
3618
4221
  "type": {
3619
4222
  "text": "CustomEvent"
3620
4223
  },
3621
- "description": "Fired when dialog opens (deprecated, use `open`)"
4224
+ "description": "Fired when dialog opens"
3622
4225
  },
3623
4226
  {
3624
4227
  "name": "close",
3625
4228
  "type": {
3626
4229
  "text": "CustomEvent"
3627
4230
  },
3628
- "description": "Fired when dialog closes"
3629
- },
3630
- {
3631
- "name": "dialog-close",
3632
- "type": {
3633
- "text": "CustomEvent"
3634
- },
3635
- "description": "Fired when dialog closes (deprecated, use `close`)"
3636
- },
3637
- {
3638
- "description": "Fired when dialog opens",
3639
- "name": "open"
4231
+ "description": "Fired when dialog closes (however it closed — the close button, Escape, a backdrop click, or setting `open` to `false` directly)"
3640
4232
  }
3641
4233
  ],
3642
4234
  "superclass": {
@@ -3688,7 +4280,7 @@
3688
4280
  {
3689
4281
  "kind": "variable",
3690
4282
  "name": "dividerStyles",
3691
- "default": "css` :host { display: block; } :host([orientation='vertical']) { align-self: stretch; display: inline-flex; width: auto; } /* ── Horizontal ─────────────────────────────────────────────────────────── */ :host([orientation='horizontal']) [part='base'], :host(:not([orientation])) [part='base'] { align-items: center; display: flex; width: 100%; } :host([orientation='horizontal']) [part='base']::before, :host(:not([orientation])) [part='base']::before, :host([orientation='horizontal']) [part='base']::after, :host(:not([orientation])) [part='base']::after { border-top: 1px solid var(--lt-border-default); border-top-style: var(--_divider-style, solid); content: ''; flex: 1; } /* ── Vertical ───────────────────────────────────────────────────────────── */ :host([orientation='vertical']) [part='base'] { align-items: center; display: flex; flex-direction: column; height: 100%; } :host([orientation='vertical']) [part='base']::before, :host([orientation='vertical']) [part='base']::after { border-left: 1px solid var(--lt-border-default); border-left-style: var(--_divider-style, solid); content: ''; flex: 1; } /* ── Label ──────────────────────────────────────────────────────────────── */ [part='label'] { color: var(--lt-text-subtle); font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); font-size: 0.75rem; font-weight: 600; padding-inline: var(--lt-spacing-3); white-space: nowrap; } :host([orientation='vertical']) [part='label'] { padding-block: var(--lt-spacing-3); padding-inline: 0; } /* ── Appearances ────────────────────────────────────────────────────────── */ :host([appearance='solid']) { --_divider-style: solid; } :host([appearance='dashed']) { --_divider-style: dashed; } :host([appearance='dotted']) { --_divider-style: dotted; } `"
4283
+ "default": "css` :host { display: block; } :host([orientation='vertical']) { align-self: stretch; display: inline-flex; width: auto; } /* ── Horizontal ─────────────────────────────────────────────────────────── */ :host([orientation='horizontal']) [part='base'], :host(:not([orientation])) [part='base'] { align-items: center; display: flex; width: 100%; } :host([orientation='horizontal']) [part='base']::before, :host(:not([orientation])) [part='base']::before, :host([orientation='horizontal']) [part='base']::after, :host(:not([orientation])) [part='base']::after { border-top: 1px solid var(--lt-border-default); border-top-style: var(--_divider-style, solid); content: ''; flex: 1; } /* ── Vertical ───────────────────────────────────────────────────────────── */ :host([orientation='vertical']) [part='base'] { align-items: center; display: flex; flex-direction: column; height: 100%; } :host([orientation='vertical']) [part='base']::before, :host([orientation='vertical']) [part='base']::after { border-inline-start: 1px solid var(--lt-border-default); border-inline-start-style: var(--_divider-style, solid); content: ''; flex: 1; } /* ── Label ──────────────────────────────────────────────────────────────── */ [part='label'] { color: var(--lt-text-subtle); font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); font-size: 0.75rem; font-weight: 600; padding-inline: var(--lt-spacing-3); white-space: nowrap; } :host([orientation='vertical']) [part='label'] { padding-block: var(--lt-spacing-3); padding-inline: 0; } /* ── Appearances ────────────────────────────────────────────────────────── */ :host([appearance='solid']) { --_divider-style: solid; } :host([appearance='dashed']) { --_divider-style: dashed; } :host([appearance='dotted']) { --_divider-style: dotted; } `"
3692
4284
  }
3693
4285
  ],
3694
4286
  "exports": [
@@ -3806,7 +4398,7 @@
3806
4398
  {
3807
4399
  "kind": "variable",
3808
4400
  "name": "dropdownItemStyles",
3809
- "default": "css` :host { display: block; } .item { align-items: center; background: none; border: none; border-radius: 0; color: var(--lt-text-default); cursor: pointer; display: flex; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); font-size: 0.875rem; gap: var(--lt-spacing-2); padding: var(--lt-spacing-2) var(--lt-spacing-4); text-align: left; text-decoration: none; width: 100%; } .item:hover, .item:focus-visible { background: var(--lt-bg-neutral-subtle); outline: none; } .item:active { background: var(--lt-bg-overlay); } :host([selected]) .item { background: var(--lt-bg-primary-subtle); color: var(--lt-text-primary); font-weight: 600; } :host([disabled]) { pointer-events: none; } :host([disabled]) .item { color: var(--lt-text-disabled); cursor: not-allowed; } `"
4401
+ "default": "css` :host { display: block; } .item { align-items: center; background: none; border: none; border-radius: 0; color: var(--lt-text-default); cursor: pointer; display: flex; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); font-size: 0.875rem; gap: var(--lt-spacing-2); padding: var(--lt-spacing-2) var(--lt-spacing-4); text-align: start; text-decoration: none; width: 100%; } .item:hover, .item:focus-visible { background: var(--lt-bg-neutral-subtle); outline: none; } .item:active { background: var(--lt-bg-overlay); } :host([selected]) .item { background: var(--lt-bg-primary-subtle); color: var(--lt-text-primary); font-weight: 600; } :host([disabled]) { pointer-events: none; } :host([disabled]) .item { color: var(--lt-text-disabled); cursor: not-allowed; } `"
3810
4402
  }
3811
4403
  ],
3812
4404
  "exports": [
@@ -3922,7 +4514,7 @@
3922
4514
  "type": {
3923
4515
  "text": "array"
3924
4516
  },
3925
- "default": "[ floatingPanelReset, css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .trigger-wrap { display: contents; } lt-surface.menu { display: none; min-width: 10rem; z-index: 1000; } lt-surface.menu::part(surface) { overflow: hidden; padding-block: var(--lt-dropdown-menu-padding, var(--lt-spacing-2)); } ` ]"
4517
+ "default": "[ floatingPanelReset, css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .trigger-wrap { display: contents; } lt-surface.menu { display: none; min-width: 10rem; z-index: 1000; } lt-surface.menu::part(surface) { max-height: var(--lt-dropdown-max-height, min(24rem, 60vh)); overflow-x: hidden; overflow-y: auto; padding-block: var(--lt-dropdown-menu-padding, var(--lt-spacing-2)); } ` ]"
3926
4518
  }
3927
4519
  ],
3928
4520
  "exports": [
@@ -3948,6 +4540,11 @@
3948
4540
  {
3949
4541
  "description": "Overrides the menu surface's default vertical padding.",
3950
4542
  "name": "--lt-dropdown-menu-padding"
4543
+ },
4544
+ {
4545
+ "description": "Tallest the menu grows before it scrolls.",
4546
+ "name": "--lt-dropdown-max-height",
4547
+ "default": "min(24rem, 60vh)"
3951
4548
  }
3952
4549
  ],
3953
4550
  "slots": [
@@ -4001,6 +4598,25 @@
4001
4598
  "privacy": "private",
4002
4599
  "default": "null"
4003
4600
  },
4601
+ {
4602
+ "kind": "field",
4603
+ "name": "_skipNextOpenChange",
4604
+ "type": {
4605
+ "text": "boolean"
4606
+ },
4607
+ "privacy": "private",
4608
+ "default": "true"
4609
+ },
4610
+ {
4611
+ "kind": "method",
4612
+ "name": "_syncTriggerAria",
4613
+ "privacy": "private"
4614
+ },
4615
+ {
4616
+ "kind": "field",
4617
+ "name": "_onFocusOut",
4618
+ "privacy": "private"
4619
+ },
4004
4620
  {
4005
4621
  "kind": "method",
4006
4622
  "name": "updated",
@@ -4238,7 +4854,7 @@
4238
4854
  {
4239
4855
  "kind": "variable",
4240
4856
  "name": "iconButtonStyles",
4241
- "default": "css` :host { display: inline-flex; /* Internal state props — set per variant/appearance below */ --_color: var(--lt-text-subtle); --_bg: transparent; --_border-color: transparent; --_hover-bg: var(--lt-bg-subtle); --_hover-color: var(--lt-text-default); --_active-bg: var(--lt-bg-subtle); } [part='base'] { align-items: center; background: var(--lt-icon-button-bg, var(--_bg)); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-icon-button-border-color, var(--_border-color)); box-sizing: border-box; color: var(--lt-icon-button-color, var(--_color)); cursor: pointer; display: inline-flex; justify-content: center; padding: 0; transition: background-color 120ms ease, border-color 120ms ease, transform 50ms ease; user-select: none; } [part='base']:hover:not([disabled]) { background: var(--lt-icon-button-hover-bg, var(--_hover-bg)); color: var(--lt-icon-button-hover-color, var(--lt-icon-button-color, var(--_hover-color))); } [part='base']:active { transform: translateY(1px); } [part='base']:active:not([disabled]) { background: var(--lt-icon-button-hover-bg, var(--_active-bg)); } [part='base']:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: 2px; } [part='base'][disabled] { cursor: not-allowed; opacity: 0.5; pointer-events: none; transform: none; } a[part='base'] { text-decoration: none; } /* sizes */ :host([size='sm']) [part='base'] { height: 28px; width: 28px; } :host([size='md']) [part='base'] { height: 36px; width: 36px; } :host([size='lg']) [part='base'] { height: 44px; width: 44px; } /* ── ghost ────────────────────────────────────────────────── */ :host([appearance='ghost'][variant='primary']) { --_color: var(--lt-text-primary); --_hover-bg: var(--lt-bg-primary-subtle); --_hover-color: var(--lt-text-primary); --_active-bg: var(--lt-bg-primary-subtle); } :host([appearance='ghost'][variant='secondary']) { --_color: var(--lt-text-secondary); --_hover-bg: var(--lt-bg-secondary-subtle); --_hover-color: var(--lt-text-secondary); --_active-bg: var(--lt-bg-secondary-subtle); } :host([appearance='ghost'][variant='success']) { --_color: var(--lt-text-success); --_hover-bg: var(--lt-bg-success-subtle); --_hover-color: var(--lt-text-success); --_active-bg: var(--lt-bg-success-subtle); } :host([appearance='ghost'][variant='warning']) { --_color: var(--lt-text-warning); --_hover-bg: var(--lt-bg-warning-subtle); --_hover-color: var(--lt-text-warning); --_active-bg: var(--lt-bg-warning-subtle); } :host([appearance='ghost'][variant='error']) { --_color: var(--lt-text-error); --_hover-bg: var(--lt-bg-error-subtle); --_hover-color: var(--lt-text-error); --_active-bg: var(--lt-bg-error-subtle); } :host([appearance='ghost'][variant='info']) { --_color: var(--lt-text-info); --_hover-bg: var(--lt-bg-info-subtle); --_hover-color: var(--lt-text-info); --_active-bg: var(--lt-bg-info-subtle); } /* ── filled ───────────────────────────────────────────────── */ :host([appearance='filled'][variant='primary']) { --_bg: var(--lt-interactive-primary-bg); --_color: var(--lt-text-on-primary); --_hover-bg: var(--lt-interactive-primary-bg-hover); --_hover-color: var(--lt-text-on-primary); --_active-bg: var(--lt-interactive-primary-bg-active); } :host([appearance='filled'][variant='secondary']) { --_bg: var(--lt-interactive-secondary-bg); --_color: var(--lt-text-on-secondary); --_hover-bg: var(--lt-interactive-secondary-bg-hover); --_hover-color: var(--lt-text-on-secondary); --_active-bg: var(--lt-interactive-secondary-bg-active); } :host([appearance='filled'][variant='neutral']) { --_bg: var(--lt-interactive-neutral-bg); --_color: var(--lt-color-neutral-50); --_hover-bg: var(--lt-interactive-neutral-bg-hover); --_hover-color: var(--lt-color-neutral-50); --_active-bg: var(--lt-interactive-neutral-bg-active); } :host([appearance='filled'][variant='success']) { --_bg: var(--lt-interactive-success-bg); --_color: var(--lt-text-on-success); --_hover-bg: var(--lt-interactive-success-bg-hover); --_hover-color: var(--lt-text-on-success); --_active-bg: var(--lt-interactive-success-bg-active); } :host([appearance='filled'][variant='warning']) { --_bg: var(--lt-interactive-warning-bg); --_color: var(--lt-text-on-warning); --_hover-bg: var(--lt-interactive-warning-bg-hover); --_hover-color: var(--lt-text-on-warning); --_active-bg: var(--lt-interactive-warning-bg-active); } :host([appearance='filled'][variant='error']) { --_bg: var(--lt-interactive-error-bg); --_color: var(--lt-text-on-error); --_hover-bg: var(--lt-interactive-error-bg-hover); --_hover-color: var(--lt-text-on-error); --_active-bg: var(--lt-interactive-error-bg-active); } :host([appearance='filled'][variant='info']) { --_bg: var(--lt-interactive-info-bg); --_color: var(--lt-text-on-info); --_hover-bg: var(--lt-interactive-info-bg-hover); --_hover-color: var(--lt-text-on-info); --_active-bg: var(--lt-interactive-info-bg-active); } /* ── outlined ─────────────────────────────────────────────── */ :host([appearance='outlined'][variant='primary']) { --_color: var(--lt-text-primary); --_border-color: var(--lt-border-primary-strong); --_hover-bg: var(--lt-bg-primary-subtle); --_hover-color: var(--lt-text-primary); --_active-bg: var(--lt-bg-primary-subtle); } :host([appearance='outlined'][variant='secondary']) { --_color: var(--lt-text-secondary); --_border-color: var(--lt-border-secondary-strong); --_hover-bg: var(--lt-bg-secondary-subtle); --_hover-color: var(--lt-text-secondary); --_active-bg: var(--lt-bg-secondary-subtle); } :host([appearance='outlined'][variant='neutral']) { --_color: var(--lt-text-neutral); --_border-color: var(--lt-border-strong); --_hover-bg: var(--lt-bg-subtle); --_hover-color: var(--lt-text-default); --_active-bg: var(--lt-bg-subtle); } :host([appearance='outlined'][variant='success']) { --_color: var(--lt-text-success); --_border-color: var(--lt-border-success-strong); --_hover-bg: var(--lt-bg-success-subtle); --_hover-color: var(--lt-text-success); --_active-bg: var(--lt-bg-success-subtle); } :host([appearance='outlined'][variant='warning']) { --_color: var(--lt-text-warning); --_border-color: var(--lt-border-warning-strong); --_hover-bg: var(--lt-bg-warning-subtle); --_hover-color: var(--lt-text-warning); --_active-bg: var(--lt-bg-warning-subtle); } :host([appearance='outlined'][variant='error']) { --_color: var(--lt-text-error); --_border-color: var(--lt-border-error-strong); --_hover-bg: var(--lt-bg-error-subtle); --_hover-color: var(--lt-text-error); --_active-bg: var(--lt-bg-error-subtle); } :host([appearance='outlined'][variant='info']) { --_color: var(--lt-text-info); --_border-color: var(--lt-border-info-strong); --_hover-bg: var(--lt-bg-info-subtle); --_hover-color: var(--lt-text-info); --_active-bg: var(--lt-bg-info-subtle); } /* bordered — adds a border on top of whatever appearance is active; a no-op on outlined, which already sets the same border color. */ :host([bordered][variant='primary']) { --_border-color: var(--lt-border-primary-strong); } :host([bordered][variant='secondary']) { --_border-color: var(--lt-border-secondary-strong); } :host([bordered][variant='neutral']) { --_border-color: var(--lt-border-strong); } :host([bordered][variant='success']) { --_border-color: var(--lt-border-success-strong); } :host([bordered][variant='warning']) { --_border-color: var(--lt-border-warning-strong); } :host([bordered][variant='error']) { --_border-color: var(--lt-border-error-strong); } :host([bordered][variant='info']) { --_border-color: var(--lt-border-info-strong); } /* round shape */ :host([round]) [part='base'] { border-radius: 50%; } `"
4857
+ "default": "css` :host { display: inline-flex; /* Internal state props — set per variant/appearance below */ --_color: var(--lt-text-subtle); --_bg: transparent; --_border-color: transparent; --_hover-bg: var(--lt-bg-subtle); --_hover-color: var(--lt-text-default); --_active-bg: var(--lt-bg-subtle); } [part='base'] { align-items: center; background: var(--lt-icon-button-bg, var(--_bg)); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-icon-button-border-color, var(--_border-color)); box-sizing: border-box; color: var(--lt-icon-button-color, var(--_color)); cursor: pointer; display: inline-flex; justify-content: center; padding: 0; transition: background-color 120ms ease, border-color 120ms ease, transform 50ms ease; user-select: none; } [part='base']:hover:not([disabled]) { background: var(--lt-icon-button-hover-bg, var(--_hover-bg)); color: var(--lt-icon-button-hover-color, var(--lt-icon-button-color, var(--_hover-color))); } [part='base']:active { transform: translateY(1px); } [part='base']:active:not([disabled]) { background: var(--lt-icon-button-hover-bg, var(--_active-bg)); } [part='base']:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: 2px; } [part='base'][disabled] { cursor: not-allowed; opacity: 0.5; pointer-events: none; transform: none; } a[part='base'] { text-decoration: none; } /* sizes */ :host([size='sm']) [part='base'] { height: 28px; width: 28px; } :host([size='md']) [part='base'] { height: 36px; width: 36px; } :host([size='lg']) [part='base'] { height: 44px; width: 44px; } /* ── ghost ────────────────────────────────────────────────── */ :host([appearance='ghost'][variant='primary']) { --_color: var(--lt-text-primary); --_hover-bg: var(--lt-bg-primary-subtle); --_hover-color: var(--lt-text-primary); --_active-bg: var(--lt-bg-primary-subtle); } :host([appearance='ghost'][variant='secondary']) { --_color: var(--lt-text-secondary); --_hover-bg: var(--lt-bg-secondary-subtle); --_hover-color: var(--lt-text-secondary); --_active-bg: var(--lt-bg-secondary-subtle); } :host([appearance='ghost'][variant='success']) { --_color: var(--lt-text-success); --_hover-bg: var(--lt-bg-success-subtle); --_hover-color: var(--lt-text-success); --_active-bg: var(--lt-bg-success-subtle); } :host([appearance='ghost'][variant='warning']) { --_color: var(--lt-text-warning); --_hover-bg: var(--lt-bg-warning-subtle); --_hover-color: var(--lt-text-warning); --_active-bg: var(--lt-bg-warning-subtle); } :host([appearance='ghost'][variant='error']) { --_color: var(--lt-text-error); --_hover-bg: var(--lt-bg-error-subtle); --_hover-color: var(--lt-text-error); --_active-bg: var(--lt-bg-error-subtle); } :host([appearance='ghost'][variant='info']) { --_color: var(--lt-text-info); --_hover-bg: var(--lt-bg-info-subtle); --_hover-color: var(--lt-text-info); --_active-bg: var(--lt-bg-info-subtle); } /* ── filled ───────────────────────────────────────────────── */ :host([appearance='filled'][variant='primary']) { --_bg: var(--lt-interactive-primary-bg); --_color: var(--lt-text-on-primary); --_hover-bg: var(--lt-interactive-primary-bg-hover); --_hover-color: var(--lt-text-on-primary); --_active-bg: var(--lt-interactive-primary-bg-active); } :host([appearance='filled'][variant='secondary']) { --_bg: var(--lt-interactive-secondary-bg); --_color: var(--lt-text-on-secondary); --_hover-bg: var(--lt-interactive-secondary-bg-hover); --_hover-color: var(--lt-text-on-secondary); --_active-bg: var(--lt-interactive-secondary-bg-active); } :host([appearance='filled'][variant='neutral']) { --_bg: var(--lt-interactive-neutral-bg); --_color: var(--lt-color-neutral-50); --_hover-bg: var(--lt-interactive-neutral-bg-hover); --_hover-color: var(--lt-color-neutral-50); --_active-bg: var(--lt-interactive-neutral-bg-active); } :host([appearance='filled'][variant='success']) { --_bg: var(--lt-interactive-success-bg); --_color: var(--lt-text-on-success); --_hover-bg: var(--lt-interactive-success-bg-hover); --_hover-color: var(--lt-text-on-success); --_active-bg: var(--lt-interactive-success-bg-active); } :host([appearance='filled'][variant='warning']) { --_bg: var(--lt-interactive-warning-bg); --_color: var(--lt-text-on-warning); --_hover-bg: var(--lt-interactive-warning-bg-hover); --_hover-color: var(--lt-text-on-warning); --_active-bg: var(--lt-interactive-warning-bg-active); } :host([appearance='filled'][variant='error']) { --_bg: var(--lt-interactive-error-bg); --_color: var(--lt-text-on-error); --_hover-bg: var(--lt-interactive-error-bg-hover); --_hover-color: var(--lt-text-on-error); --_active-bg: var(--lt-interactive-error-bg-active); } :host([appearance='filled'][variant='info']) { --_bg: var(--lt-interactive-info-bg); --_color: var(--lt-text-on-info); --_hover-bg: var(--lt-interactive-info-bg-hover); --_hover-color: var(--lt-text-on-info); --_active-bg: var(--lt-interactive-info-bg-active); } /* ── outlined ─────────────────────────────────────────────── */ :host([appearance='outlined'][variant='primary']) { --_color: var(--lt-text-primary); --_border-color: var(--lt-border-primary-strong); --_hover-bg: var(--lt-bg-primary-subtle); --_hover-color: var(--lt-text-primary); --_active-bg: var(--lt-bg-primary-subtle); } :host([appearance='outlined'][variant='secondary']) { --_color: var(--lt-text-secondary); --_border-color: var(--lt-border-secondary-strong); --_hover-bg: var(--lt-bg-secondary-subtle); --_hover-color: var(--lt-text-secondary); --_active-bg: var(--lt-bg-secondary-subtle); } :host([appearance='outlined'][variant='neutral']) { --_color: var(--lt-text-neutral); --_border-color: var(--lt-border-strong); --_hover-bg: var(--lt-bg-subtle); --_hover-color: var(--lt-text-default); --_active-bg: var(--lt-bg-subtle); } :host([appearance='outlined'][variant='success']) { --_color: var(--lt-text-success); --_border-color: var(--lt-border-success-strong); --_hover-bg: var(--lt-bg-success-subtle); --_hover-color: var(--lt-text-success); --_active-bg: var(--lt-bg-success-subtle); } :host([appearance='outlined'][variant='warning']) { --_color: var(--lt-text-warning); --_border-color: var(--lt-border-warning-strong); --_hover-bg: var(--lt-bg-warning-subtle); --_hover-color: var(--lt-text-warning); --_active-bg: var(--lt-bg-warning-subtle); } :host([appearance='outlined'][variant='error']) { --_color: var(--lt-text-error); --_border-color: var(--lt-border-error-strong); --_hover-bg: var(--lt-bg-error-subtle); --_hover-color: var(--lt-text-error); --_active-bg: var(--lt-bg-error-subtle); } :host([appearance='outlined'][variant='info']) { --_color: var(--lt-text-info); --_border-color: var(--lt-border-info-strong); --_hover-bg: var(--lt-bg-info-subtle); --_hover-color: var(--lt-text-info); --_active-bg: var(--lt-bg-info-subtle); } /* bordered — adds a border on top of whatever appearance is active; a no-op on outlined, which already sets the same border color. */ :host([bordered][variant='primary']) { --_border-color: var(--lt-border-primary-strong); } :host([bordered][variant='secondary']) { --_border-color: var(--lt-border-secondary-strong); } :host([bordered][variant='neutral']) { --_border-color: var(--lt-border-strong); } :host([bordered][variant='success']) { --_border-color: var(--lt-border-success-strong); } :host([bordered][variant='warning']) { --_border-color: var(--lt-border-warning-strong); } :host([bordered][variant='error']) { --_border-color: var(--lt-border-error-strong); } :host([bordered][variant='info']) { --_border-color: var(--lt-border-info-strong); } /* round shape */ :host([round]) [part='base'] { border-radius: 50%; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { [part='base'] { transition: none; } } `"
4242
4858
  }
4243
4859
  ],
4244
4860
  "exports": [
@@ -4336,6 +4952,16 @@
4336
4952
  "default": "false",
4337
4953
  "description": "Whether the button is disabled."
4338
4954
  },
4955
+ {
4956
+ "kind": "method",
4957
+ "name": "firstUpdated",
4958
+ "privacy": "protected"
4959
+ },
4960
+ {
4961
+ "kind": "field",
4962
+ "name": "_blockClickWhileDisabled",
4963
+ "privacy": "private"
4964
+ },
4339
4965
  {
4340
4966
  "kind": "field",
4341
4967
  "name": "href",
@@ -4443,7 +5069,7 @@
4443
5069
  "declarations": [
4444
5070
  {
4445
5071
  "kind": "class",
4446
- "description": "A thin wrapper around `<img>` with rounded corners, responsive fill support,\nnative lazy loading, and an error fallback mechanism.\n\nNative `load`/`error` events don't cross the shadow boundary, so they are\nre-dispatched as composed `lt-load`/`lt-error` custom events. When a load\nfails, the `fallback` slot is shown in place of the broken image; setting a\nnew `src` retries.",
5072
+ "description": "A thin wrapper around `<img>` with rounded corners, responsive fill support,\nnative lazy loading, and an error fallback mechanism.\n\nThe inner `<img>`'s `load`/`error` events don't leave the shadow root, so they\nare re-dispatched on the host under the same native names, with the `src` in\n`detail`. Like the native ones they don't bubble, so listen on `<lt-image>`\nitself. When a load fails, the `fallback` slot is shown in place of the broken\nimage; setting a new `src` retries.",
4447
5073
  "name": "Image",
4448
5074
  "cssParts": [
4449
5075
  {
@@ -4540,19 +5166,6 @@
4540
5166
  }
4541
5167
  ]
4542
5168
  },
4543
- {
4544
- "kind": "method",
4545
- "name": "_dispatch",
4546
- "privacy": "private",
4547
- "parameters": [
4548
- {
4549
- "name": "name",
4550
- "type": {
4551
- "text": "'lt-load' | 'lt-error'"
4552
- }
4553
- }
4554
- ]
4555
- },
4556
5169
  {
4557
5170
  "kind": "method",
4558
5171
  "name": "_handleLoad",
@@ -4570,24 +5183,18 @@
4570
5183
  ],
4571
5184
  "events": [
4572
5185
  {
4573
- "name": "name",
4574
- "type": {
4575
- "text": "CustomEvent"
4576
- }
4577
- },
4578
- {
5186
+ "name": "load",
4579
5187
  "type": {
4580
5188
  "text": "CustomEvent<{ src: string }>"
4581
5189
  },
4582
- "description": "Fired when the image loads successfully",
4583
- "name": "lt-load"
5190
+ "description": "Fired when the image loads successfully"
4584
5191
  },
4585
5192
  {
5193
+ "name": "error",
4586
5194
  "type": {
4587
5195
  "text": "CustomEvent<{ src: string }>"
4588
5196
  },
4589
- "description": "Fired when the image fails to load",
4590
- "name": "lt-error"
5197
+ "description": "Fired when the image fails to load"
4591
5198
  }
4592
5199
  ],
4593
5200
  "superclass": {
@@ -4763,7 +5370,7 @@
4763
5370
  {
4764
5371
  "kind": "variable",
4765
5372
  "name": "listItemStyles",
4766
- "default": "css` :host { display: list-item; margin: 0; padding: 0; } .inner { display: flex; align-items: flex-start; gap: var(--lt-spacing-2); } /* Keep the slotted content as a single flex item so rich inline markup (strong, code, multiple text runs) flows as normal prose instead of each node becoming its own shrunk flex item. min-width: 0 lets it wrap. */ .content { flex: 1 1 auto; min-width: 0; } lt-icon { flex-shrink: 0; color: var(--lt-color-neutral-500); font-size: inherit; } /* interactive rows — native button/anchor reset + states */ a.inner, button.inner { background: transparent; border: none; border-radius: var(--lt-border-radius); box-sizing: border-box; color: inherit; cursor: pointer; font: inherit; margin: 0; padding: var(--lt-spacing-2); text-align: start; text-decoration: none; transition: background-color 120ms ease; width: 100%; } a.inner:hover:not([aria-disabled='true']), button.inner:hover:not([disabled]) { background: var(--lt-list-item-hover-bg, var(--lt-bg-subtle)); } a.inner:active:not([aria-disabled='true']), button.inner:active:not([disabled]) { background: var(--lt-list-item-active-bg, var(--lt-bg-surface)); } a.inner:focus-visible, button.inner:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: -3px; } button.inner[disabled], a.inner[aria-disabled='true'] { cursor: not-allowed; opacity: 0.6; pointer-events: none; } `"
5373
+ "default": "css` :host { display: list-item; margin: 0; padding: 0; } .inner { display: flex; align-items: flex-start; gap: var(--lt-spacing-2); } /* Keep the slotted content as a single flex item so rich inline markup (strong, code, multiple text runs) flows as normal prose instead of each node becoming its own shrunk flex item. min-width: 0 lets it wrap. */ .content { flex: 1 1 auto; min-width: 0; } lt-icon { flex-shrink: 0; color: var(--lt-text-muted); font-size: inherit; } /* interactive rows — native button/anchor reset + states */ a.inner, button.inner { background: transparent; border: none; border-radius: var(--lt-border-radius); box-sizing: border-box; color: inherit; cursor: pointer; font: inherit; margin: 0; padding: var(--lt-spacing-2); text-align: start; text-decoration: none; transition: background-color 120ms ease; width: 100%; } a.inner:hover:not([aria-disabled='true']), button.inner:hover:not([disabled]) { background: var(--lt-list-item-hover-bg, var(--lt-bg-subtle)); } a.inner:active:not([aria-disabled='true']), button.inner:active:not([disabled]) { background: var(--lt-list-item-active-bg, var(--lt-bg-surface)); } a.inner:focus-visible, button.inner:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: -3px; } button.inner[disabled], a.inner[aria-disabled='true'] { cursor: not-allowed; opacity: 0.6; pointer-events: none; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { a.inner, button.inner { transition: none; } } `"
4767
5374
  }
4768
5375
  ],
4769
5376
  "exports": [
@@ -4898,7 +5505,7 @@
4898
5505
  {
4899
5506
  "kind": "variable",
4900
5507
  "name": "listStyles",
4901
- "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); --list-marker-color: var(--lt-color-neutral-500); } [part='list'] { margin: 0; padding: 0 0 0 var(--lt-spacing-5); list-style-position: outside; list-style-type: disc; color: var(--lt-text-default); } :host([type='ordered']) [part='list'] { list-style-type: decimal; } ::slotted(li), ::slotted(lt-list-item) { margin-bottom: var(--lt-spacing-2); } ::slotted(li:last-child), ::slotted(lt-list-item:last-child) { margin-bottom: 0; } ::slotted(lt-list) { display: block; margin-top: var(--lt-spacing-2); margin-bottom: var(--lt-spacing-2); padding-left: var(--lt-spacing-5); font-size: 0.9em; } /* No marker */ :host([no-marker]) [part='list'] { list-style: none; padding-left: 0; } /* Divider */ :host([divider]) ::slotted(lt-list-item) { border-bottom: 1px solid var(--lt-border-default); padding-bottom: var(--lt-spacing-2); } :host([divider]) ::slotted(lt-list-item:last-child) { border-bottom: none; padding-bottom: 0; } ::slotted(lt-list:first-child) { margin-top: var(--lt-spacing-2); } ::slotted(lt-list:last-child) { margin-bottom: 0; } [part='list'] ::slotted(li)::marker { color: var(--list-marker-color); } /* Size variants */ :host([size='sm']) [part='list'] { font-size: 0.875rem; line-height: 1.5; } :host([size='sm']) ::slotted(li), :host([size='sm']) ::slotted(lt-list-item) { margin-bottom: var(--lt-spacing-1); } :host([size='md']) [part='list'] { font-size: 1rem; line-height: 1.6; } :host([size='md']) ::slotted(li), :host([size='md']) ::slotted(lt-list-item) { margin-bottom: var(--lt-spacing-2); } :host([size='lg']) [part='list'] { font-size: 1.125rem; line-height: 1.7; } :host([size='lg']) ::slotted(li), :host([size='lg']) ::slotted(lt-list-item) { margin-bottom: var(--lt-spacing-3); } `"
5508
+ "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); --list-marker-color: var(--lt-color-neutral-500); } [part='list'] { margin: 0; padding-block: 0; padding-inline: var(--lt-spacing-5) 0; list-style-position: outside; list-style-type: disc; color: var(--lt-text-default); } :host([type='ordered']) [part='list'] { list-style-type: decimal; } ::slotted(li), ::slotted(lt-list-item) { margin-bottom: var(--lt-spacing-2); } ::slotted(li:last-child), ::slotted(lt-list-item:last-child) { margin-bottom: 0; } ::slotted(lt-list) { display: block; margin-top: var(--lt-spacing-2); margin-bottom: var(--lt-spacing-2); padding-inline-start: var(--lt-spacing-5); font-size: 0.9em; } /* No marker */ :host([no-marker]) [part='list'] { list-style: none; padding-inline-start: 0; } /* Divider */ :host([divider]) ::slotted(lt-list-item) { border-bottom: 1px solid var(--lt-border-default); padding-bottom: var(--lt-spacing-2); } :host([divider]) ::slotted(lt-list-item:last-child) { border-bottom: none; padding-bottom: 0; } ::slotted(lt-list:first-child) { margin-top: var(--lt-spacing-2); } ::slotted(lt-list:last-child) { margin-bottom: 0; } [part='list'] ::slotted(li)::marker { color: var(--list-marker-color); } /* Size variants */ :host([size='sm']) [part='list'] { font-size: 0.875rem; line-height: 1.5; } :host([size='sm']) ::slotted(li), :host([size='sm']) ::slotted(lt-list-item) { margin-bottom: var(--lt-spacing-1); } :host([size='md']) [part='list'] { font-size: 1rem; line-height: 1.6; } :host([size='md']) ::slotted(li), :host([size='md']) ::slotted(lt-list-item) { margin-bottom: var(--lt-spacing-2); } :host([size='lg']) [part='list'] { font-size: 1.125rem; line-height: 1.7; } :host([size='lg']) ::slotted(li), :host([size='lg']) ::slotted(lt-list-item) { margin-bottom: var(--lt-spacing-3); } `"
4902
5509
  }
4903
5510
  ],
4904
5511
  "exports": [
@@ -5051,7 +5658,7 @@
5051
5658
  "declarations": [
5052
5659
  {
5053
5660
  "kind": "class",
5054
- "description": "A single navigation item. Can render as an anchor link or a collapsible group header\nwhen children are slotted.\n\nWhen slotted inside `<lt-nav orientation=\"horizontal\">`, top-level items lay out in a row\nand nested children appear as a dropdown panel. In vertical mode, nested children\ncollapse/expand inline.\n\nSPA router integration: `nav-item-click` is cancelable — call `event.preventDefault()`\nto stop the anchor's native navigation, navigate programmatically, and drive the\nhighlighted item via the `active` property (which also sets `aria-current=\"page\"`).",
5661
+ "description": "A single navigation item. Can render as an anchor link or a collapsible group header\nwhen children are slotted.\n\nWhen slotted inside `<lt-nav orientation=\"horizontal\">`, top-level items lay out in a row\nand nested children appear as a dropdown panel. In vertical mode, nested children\ncollapse/expand inline.\n\nSPA router integration: items use the native `click` — listen for it on the `<lt-nav>` (or the item),\ncall `event.preventDefault()` to stop the anchor's native navigation, and read the item from\n`event.target.closest('lt-nav-item')` (its `href` and `label`). Modifier keys (`event.metaKey`, …) come\nthrough as on any link. Drive the highlighted item via the `active` property (which also sets\n`aria-current=\"page\"`).",
5055
5662
  "name": "NavItem",
5056
5663
  "slots": [
5057
5664
  {
@@ -5167,6 +5774,11 @@
5167
5774
  }
5168
5775
  ]
5169
5776
  },
5777
+ {
5778
+ "kind": "method",
5779
+ "name": "_syncInitialHeight",
5780
+ "privacy": "private"
5781
+ },
5170
5782
  {
5171
5783
  "kind": "method",
5172
5784
  "name": "updated",
@@ -5210,18 +5822,11 @@
5210
5822
  ],
5211
5823
  "events": [
5212
5824
  {
5213
- "name": "nav-item-click",
5214
- "type": {
5215
- "text": "CustomEvent<{ href: string; label: string }>"
5216
- },
5217
- "description": "Fired when the item is clicked (even when it has no href). Cancelable: `preventDefault()` stops the native anchor navigation so an SPA router can handle it."
5218
- },
5219
- {
5220
- "name": "nav-collapse",
5825
+ "name": "toggle",
5221
5826
  "type": {
5222
5827
  "text": "CustomEvent<{ open: boolean }>"
5223
5828
  },
5224
- "description": "Fired when a collapsible item is opened or closed."
5829
+ "description": "Fired when a collapsible item is opened or closed, like the native `toggle` of `<details>`."
5225
5830
  }
5226
5831
  ],
5227
5832
  "superclass": {
@@ -5255,7 +5860,7 @@
5255
5860
  {
5256
5861
  "kind": "variable",
5257
5862
  "name": "navItemStyles",
5258
- "default": "css` :host { display: contents; } .item-root { position: relative; display: flex; flex-direction: column; } /* Trigger row: link + optional chevron */ .item-trigger { display: flex; align-items: center; gap: var(--lt-spacing-2); width: 100%; padding: var(--lt-nav-item-padding, var(--lt-spacing-2) var(--lt-spacing-3)); border-radius: 6px; border: none; background: none; cursor: pointer; color: inherit; font-size: var(--lt-nav-item-font-size, 0.9375rem); font-family: inherit; text-decoration: none; text-align: left; transition: background 120ms; white-space: nowrap; } .item-trigger:hover { background: color-mix(in srgb, currentColor 10%, transparent); } .item-trigger:active { background: color-mix(in srgb, currentColor 18%, transparent); } :host([active]) .item-trigger { background: var(--lt-nav-item-active-bg, color-mix(in srgb, currentColor 15%, transparent)); color: var(--lt-nav-item-active-color, inherit); font-weight: 600; } :host([disabled]) .item-trigger { opacity: 0.4; pointer-events: none; } .label { flex: 1; } .icon-start { flex-shrink: 0; color: inherit; } /* Chevron rotates when open */ .chevron { flex-shrink: 0; color: inherit; opacity: 0.6; transition: transform 180ms ease; } :host([open]) .chevron { transform: rotate(180deg); } /* Collapsible children */ .children { overflow: hidden; height: 0; transition: height 200ms ease; } .children-inner { padding-left: var(--lt-spacing-4); padding-top: var(--lt-spacing-1); padding-bottom: var(--lt-spacing-1); display: flex; flex-direction: column; } /* In horizontal nav, top-level items lay out row-style */ :host([orientation='horizontal']) .item-root { flex-direction: row; align-items: center; } /* Horizontal children drop down as a popover-style panel */ :host([orientation='horizontal']) .children { position: absolute; top: 100%; left: 0; min-width: 160px; background: var(--lt-bg-default); color: var(--lt-color-neutral-700); border: var(--lt-border-width, 1px) solid var(--lt-color-neutral-200); border-radius: 8px; box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.08), 0 2px 4px -2px rgb(0 0 0 / 0.05); z-index: 100; height: auto !important; display: none; } :host([orientation='horizontal'][open]) .children { display: block; } :host([orientation='horizontal']) .children-inner { padding: var(--lt-spacing-2); } `"
5863
+ "default": "css` :host { display: contents; } .item-root { position: relative; display: flex; flex-direction: column; } /* Trigger row: link + optional chevron */ .item-trigger { display: flex; align-items: center; gap: var(--lt-spacing-2); width: 100%; padding: var(--lt-nav-item-padding, var(--lt-spacing-2) var(--lt-spacing-3)); border-radius: 6px; border: none; background: none; cursor: pointer; color: inherit; font-size: var(--lt-nav-item-font-size, 0.9375rem); font-family: inherit; text-decoration: none; text-align: start; transition: background 120ms; white-space: nowrap; } .item-trigger:hover { background: color-mix(in srgb, currentColor 10%, transparent); } .item-trigger:active { background: color-mix(in srgb, currentColor 18%, transparent); } :host([active]) .item-trigger { background: var(--lt-nav-item-active-bg, color-mix(in srgb, currentColor 15%, transparent)); color: var(--lt-nav-item-active-color, inherit); font-weight: 600; } :host([disabled]) .item-trigger { opacity: 0.4; pointer-events: none; } .label { flex: 1; } .icon-start { flex-shrink: 0; color: inherit; } /* Chevron rotates when open */ .chevron { flex-shrink: 0; color: inherit; opacity: 0.6; transition: transform 180ms ease; } :host([open]) .chevron { transform: rotate(180deg); } /* Collapsible children */ .children { overflow: hidden; height: 0; transition: height 200ms ease; } .children-inner { padding-inline-start: var(--lt-spacing-4); padding-top: var(--lt-spacing-1); padding-bottom: var(--lt-spacing-1); display: flex; flex-direction: column; } /* In horizontal nav, top-level items lay out row-style */ :host([orientation='horizontal']) .item-root { flex-direction: row; align-items: center; } /* Horizontal children drop down as a popover-style panel */ :host([orientation='horizontal']) .children { position: absolute; top: 100%; inset-inline-start: 0; min-width: 160px; background: var(--lt-bg-default); color: var(--lt-text-neutral); border: var(--lt-border-width, 1px) solid var(--lt-border-default); border-radius: 8px; box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.08), 0 2px 4px -2px rgb(0 0 0 / 0.05); z-index: 100; height: auto !important; display: none; } :host([orientation='horizontal'][open]) .children { display: block; } :host([orientation='horizontal']) .children-inner { padding: var(--lt-spacing-2); } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { .item-trigger, .chevron { transition: none; } /* .children's height transition can't just be removed — nav-item.ts's _handleTransitionEnd() only finalizes the open height to 'auto' (letting it respond to later content changes) once the CSS transition actually completes; transition:none fires no transitionend at all, leaving it stuck at a fixed pixel height forever. A 1ms duration is imperceptible (satisfies the reduced-motion intent) but still fires the event the component depends on — same reasoning as lt-accordion's .content. */ .children { transition: height 1ms; } } `"
5259
5864
  }
5260
5865
  ],
5261
5866
  "exports": [
@@ -5388,7 +5993,7 @@
5388
5993
  {
5389
5994
  "kind": "variable",
5390
5995
  "name": "paginationStyles",
5391
- "default": "css` :host { display: inline-flex; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } nav { align-items: center; display: flex; gap: var(--lt-spacing-1); } button { align-items: center; background: transparent; border-radius: var(--lt-border-radius); border: 1px solid transparent; color: var(--lt-text-default); cursor: pointer; display: inline-flex; font-family: inherit; font-weight: 500; justify-content: center; line-height: 1; transition: background 120ms ease, border-color 120ms ease, color 120ms ease; user-select: none; } /* Sizes */ :host([size='sm']) button { font-size: 0.75rem; height: 28px; min-width: 28px; padding: 0 var(--lt-spacing-1); } :host([size='md']) button, :host(:not([size])) button { font-size: 0.8125rem; height: 36px; min-width: 36px; padding: 0 var(--lt-spacing-2); } :host([size='lg']) button { font-size: 0.9375rem; height: 44px; min-width: 44px; padding: 0 var(--lt-spacing-3); } button:hover:not(:disabled) { background: var(--lt-bg-neutral-subtle); border-color: var(--lt-border-default); } button[aria-current='page'] { background: var(--lt-bg-primary-subtle); border-color: var(--lt-border-primary); color: var(--lt-color-primary-700); font-weight: 600; } button.ellipsis { cursor: default; pointer-events: none; } button:disabled { color: var(--lt-color-neutral-400); cursor: not-allowed; } :host([disabled]) button { color: var(--lt-color-neutral-400); cursor: not-allowed; pointer-events: none; } `"
5996
+ "default": "css` :host { display: inline-flex; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } nav { align-items: center; display: flex; gap: var(--lt-spacing-1); } button { align-items: center; background: transparent; border-radius: var(--lt-border-radius); border: 1px solid transparent; color: var(--lt-text-default); cursor: pointer; display: inline-flex; font-family: inherit; font-weight: 500; justify-content: center; line-height: 1; transition: background 120ms ease, border-color 120ms ease, color 120ms ease; user-select: none; } /* Sizes */ :host([size='sm']) button { font-size: 0.75rem; height: 28px; min-width: 28px; padding: 0 var(--lt-spacing-1); } :host([size='md']) button, :host(:not([size])) button { font-size: 0.8125rem; height: 36px; min-width: 36px; padding: 0 var(--lt-spacing-2); } :host([size='lg']) button { font-size: 0.9375rem; height: 44px; min-width: 44px; padding: 0 var(--lt-spacing-3); } button:hover:not(:disabled) { background: var(--lt-bg-neutral-subtle); border-color: var(--lt-border-default); } button[aria-current='page'] { background: var(--lt-bg-primary-subtle); border-color: var(--lt-border-primary); color: var(--lt-text-primary); font-weight: 600; } button.ellipsis { cursor: default; pointer-events: none; } button:disabled { color: var(--lt-text-disabled); cursor: not-allowed; } :host([disabled]) button { color: var(--lt-text-disabled); cursor: not-allowed; pointer-events: none; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { button { transition: none; } } `"
5392
5997
  }
5393
5998
  ],
5394
5999
  "exports": [
@@ -5453,6 +6058,44 @@
5453
6058
  "default": "false",
5454
6059
  "description": "Disable all controls."
5455
6060
  },
6061
+ {
6062
+ "kind": "field",
6063
+ "name": "labels",
6064
+ "type": {
6065
+ "text": "Partial<PaginationLabels>"
6066
+ },
6067
+ "default": "{}",
6068
+ "description": "Overridable UI text (nav landmark label, control button labels), for i18n. English defaults — override only the keys you need."
6069
+ },
6070
+ {
6071
+ "kind": "field",
6072
+ "name": "_labels",
6073
+ "type": {
6074
+ "text": "PaginationLabels"
6075
+ },
6076
+ "privacy": "private",
6077
+ "readonly": true
6078
+ },
6079
+ {
6080
+ "kind": "field",
6081
+ "name": "_total",
6082
+ "type": {
6083
+ "text": "number"
6084
+ },
6085
+ "privacy": "private",
6086
+ "description": "`total-pages` as a whole number >= 1: NaN, zero and negatives collapse to a single page.",
6087
+ "readonly": true
6088
+ },
6089
+ {
6090
+ "kind": "field",
6091
+ "name": "_current",
6092
+ "type": {
6093
+ "text": "number"
6094
+ },
6095
+ "privacy": "private",
6096
+ "description": "`page` clamped into 1.._total, so `page=\"99\"` on a 10-page set is the last page, not \"no page selected\".",
6097
+ "readonly": true
6098
+ },
5456
6099
  {
5457
6100
  "kind": "method",
5458
6101
  "name": "_go",
@@ -5547,7 +6190,7 @@
5547
6190
  {
5548
6191
  "kind": "variable",
5549
6192
  "name": "progressStyles",
5550
- "default": "css` :host { display: block; } :host { --_fill-color: var(--lt-interactive-primary-bg); } :host([variant='primary']) { --_fill-color: var(--lt-interactive-primary-bg); } :host([variant='success']) { --_fill-color: var(--lt-interactive-success-bg); } :host([variant='warning']) { --_fill-color: var(--lt-interactive-warning-bg); } :host([variant='error']) { --_fill-color: var(--lt-interactive-error-bg); } :host([variant='neutral']) { --_fill-color: var(--lt-color-neutral-600); } [part='track'] { background: var(--lt-progress-track-color, var(--lt-color-neutral-200)); border-radius: 999px; overflow: hidden; width: 100%; } [part='fill'] { background: var(--lt-progress-color, var(--_fill-color)); border-radius: 999px; height: 100%; transition: width 300ms ease; } /* ── Sizes ──────────────────────────────────────────────────────────────── */ :host([size='sm']) [part='track'] { height: var(--lt-progress-height, 4px); } :host([size='md']) [part='track'] { height: var(--lt-progress-height, 8px); } :host([size='lg']) [part='track'] { height: var(--lt-progress-height, 12px); } /* ── Indeterminate ──────────────────────────────────────────────────────── */ :host([indeterminate]) [part='fill'] { animation: indeterminate 1.5s ease-in-out infinite; width: 40%; } @keyframes indeterminate { 0% { transform: translateX(-250%); } 100% { transform: translateX(350%); } } @media (prefers-reduced-motion: reduce) { [part='fill'] { transition: none; } :host([indeterminate]) [part='fill'] { animation: none; width: 100%; } } `"
6193
+ "default": "css` :host { display: block; } :host { --_fill-color: var(--lt-interactive-primary-bg); } :host([variant='primary']) { --_fill-color: var(--lt-interactive-primary-bg); } :host([variant='success']) { --_fill-color: var(--lt-interactive-success-bg); } :host([variant='warning']) { --_fill-color: var(--lt-interactive-warning-bg); } :host([variant='error']) { --_fill-color: var(--lt-interactive-error-bg); } :host([variant='neutral']) { --_fill-color: var(--lt-interactive-neutral-bg); } [part='track'] { background: var(--lt-progress-track-color, var(--lt-bg-overlay)); border-radius: 999px; overflow: hidden; width: 100%; } [part='fill'] { background: var(--lt-progress-color, var(--_fill-color)); border-radius: 999px; height: 100%; transition: width 300ms ease; } /* ── Sizes ──────────────────────────────────────────────────────────────── */ :host([size='sm']) [part='track'] { height: var(--lt-progress-height, 4px); } :host([size='md']) [part='track'] { height: var(--lt-progress-height, 8px); } :host([size='lg']) [part='track'] { height: var(--lt-progress-height, 12px); } /* ── Indeterminate ──────────────────────────────────────────────────────── */ :host([indeterminate]) [part='fill'] { animation: indeterminate 1.5s ease-in-out infinite; width: 40%; } @keyframes indeterminate { 0% { transform: translateX(-250%); } 100% { transform: translateX(350%); } } @media (prefers-reduced-motion: reduce) { [part='fill'] { transition: none; } :host([indeterminate]) [part='fill'] { animation: none; width: 100%; } } /* ── Forced colors (Windows High Contrast) ───────────────────────────────── Under forced-colors, both the track's neutral background and the fill's variant-coloured background are flattened to Canvas, with no border on the track to fall back on — the whole bar disappears. A border on the track (its boundary) plus a Highlight-coloured fill (the OS's own \"active/selected\" system color, exempt from the flattening) keeps the progress amount legible regardless of which variant was set — forced-colors mode overrides variant branding anyway, by design. ───────────────────────────────────────── */ @media (forced-colors: active) { [part='track'] { border: 1px solid CanvasText; } [part='fill'] { background: Highlight; } } `"
5551
6194
  }
5552
6195
  ],
5553
6196
  "exports": [
@@ -5612,6 +6255,24 @@
5612
6255
  "default": "''",
5613
6256
  "description": "Accessible label for screen readers."
5614
6257
  },
6258
+ {
6259
+ "kind": "field",
6260
+ "name": "max",
6261
+ "type": {
6262
+ "text": "number"
6263
+ },
6264
+ "default": "100",
6265
+ "description": "The value `value` is measured against (0–100 becomes 0–max). Ignored when `indeterminate` is true."
6266
+ },
6267
+ {
6268
+ "kind": "field",
6269
+ "name": "valueText",
6270
+ "type": {
6271
+ "text": "string"
6272
+ },
6273
+ "default": "''",
6274
+ "description": "Overrides the spoken value with a custom string (e.g. \"3 of 5 steps\") for scales a bare percentage\ndoesn't describe well. Leave unset to let `aria-valuenow`/`aria-valuemax` speak for themselves."
6275
+ },
5615
6276
  {
5616
6277
  "kind": "field",
5617
6278
  "name": "indeterminate",
@@ -5621,6 +6282,11 @@
5621
6282
  "default": "false",
5622
6283
  "description": "When true the bar animates continuously without a set value."
5623
6284
  },
6285
+ {
6286
+ "kind": "method",
6287
+ "name": "firstUpdated",
6288
+ "privacy": "protected"
6289
+ },
5624
6290
  {
5625
6291
  "kind": "method",
5626
6292
  "name": "render"
@@ -5675,7 +6341,7 @@
5675
6341
  {
5676
6342
  "kind": "variable",
5677
6343
  "name": "radioGroupStyles",
5678
- "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .radio-group { display: flex; flex-direction: column; gap: var(--lt-spacing-2); } .label { color: var(--lt-text-default); margin-bottom: var(--lt-spacing-1); } .required-indicator { color: var(--lt-color-error-500); margin-left: var(--lt-spacing-1); } .radios-container { display: flex; gap: var(--lt-spacing-3); } :host([orientation='vertical']) .radios-container { flex-direction: column; } :host([orientation='horizontal']) .radios-container { flex-direction: row; flex-wrap: wrap; } .helper-text { color: var(--lt-text-subtle); margin-top: var(--lt-spacing-1); } .helper-text::part(base) { font-weight: 200; } :host([error]) .helper-text { color: var(--lt-text-error); } `"
6344
+ "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .radio-group { display: flex; flex-direction: column; gap: var(--lt-spacing-2); } .label { color: var(--lt-text-default); margin-bottom: var(--lt-spacing-1); } .required-indicator { color: var(--lt-text-error); margin-inline-start: var(--lt-spacing-1); } .radios-container { display: flex; gap: var(--lt-spacing-3); } :host([orientation='vertical']) .radios-container { flex-direction: column; } :host([orientation='horizontal']) .radios-container { flex-direction: row; flex-wrap: wrap; } .helper-text { color: var(--lt-text-subtle); margin-top: var(--lt-spacing-1); } .helper-text::part(base) { font-weight: 200; } :host([error]) .helper-text { color: var(--lt-text-error); } `"
5679
6345
  }
5680
6346
  ],
5681
6347
  "exports": [
@@ -5746,14 +6412,21 @@
5746
6412
  "default": "'vertical'",
5747
6413
  "description": "Layout orientation of the radio buttons."
5748
6414
  },
6415
+ {
6416
+ "kind": "field",
6417
+ "name": "_fieldIds",
6418
+ "privacy": "private",
6419
+ "readonly": true,
6420
+ "description": "Helper text displayed below the radio group.",
6421
+ "default": "''"
6422
+ },
5749
6423
  {
5750
6424
  "kind": "field",
5751
6425
  "name": "helperText",
5752
6426
  "type": {
5753
6427
  "text": "string"
5754
6428
  },
5755
- "default": "''",
5756
- "description": "Helper text displayed below the radio group."
6429
+ "default": "''"
5757
6430
  },
5758
6431
  {
5759
6432
  "kind": "field",
@@ -5784,9 +6457,10 @@
5784
6457
  },
5785
6458
  {
5786
6459
  "kind": "field",
5787
- "name": "_attached",
6460
+ "name": "_radioObserver",
5788
6461
  "privacy": "private",
5789
- "default": "new WeakSet<Radio>()"
6462
+ "readonly": true,
6463
+ "default": "new MutationObserver(() => this._syncRadios())"
5790
6464
  },
5791
6465
  {
5792
6466
  "kind": "method",
@@ -5795,13 +6469,28 @@
5795
6469
  {
5796
6470
  "kind": "method",
5797
6471
  "name": "_syncRadios",
5798
- "privacy": "private"
6472
+ "privacy": "private",
6473
+ "description": "Wires each radio's `name`, roving tabindex, and listeners, and drives `checked` from this group's `value` —\nthe direction a consumer setting `group.value = '…'` needs, since that's a plain property assignment on the\ngroup, not a native input event any individual radio would otherwise react to."
6474
+ },
6475
+ {
6476
+ "kind": "method",
6477
+ "name": "_select",
6478
+ "privacy": "private",
6479
+ "parameters": [
6480
+ {
6481
+ "name": "radio",
6482
+ "type": {
6483
+ "text": "Radio"
6484
+ }
6485
+ }
6486
+ ],
6487
+ "description": "Selects a radio (used by both the native-change and keyboard-navigation handlers below)."
5799
6488
  },
5800
6489
  {
5801
6490
  "kind": "field",
5802
6491
  "name": "handleRadioChange",
5803
6492
  "privacy": "private",
5804
- "description": "Handles change events from individual radio buttons.\nUpdates the group value and ensures only one radio is checked.",
6493
+ "description": "Handles change events from individual radio buttons.",
5805
6494
  "parameters": [
5806
6495
  {
5807
6496
  "description": "The change event from a radio button",
@@ -5809,12 +6498,32 @@
5809
6498
  }
5810
6499
  ]
5811
6500
  },
6501
+ {
6502
+ "kind": "field",
6503
+ "name": "handleRadioKeydown",
6504
+ "privacy": "private",
6505
+ "description": "Arrow keys move the roving tab stop and, per the native radiogroup's automatic-activation model, select the\nradio moved to — matching a real `<input type=\"radio\">` group, where arrowing both moves focus and checks\nthe newly-focused button. All four directions move (Right/Down forward, Left/Up back), disabled radios are\nskipped entirely, and it wraps at both ends."
6506
+ },
5812
6507
  {
5813
6508
  "kind": "method",
5814
6509
  "name": "handleSlotChange",
5815
6510
  "privacy": "private",
5816
6511
  "description": "Handles slot changes to update radios when content changes."
5817
6512
  },
6513
+ {
6514
+ "kind": "method",
6515
+ "name": "updated",
6516
+ "privacy": "protected",
6517
+ "parameters": [
6518
+ {
6519
+ "name": "changed",
6520
+ "type": {
6521
+ "text": "Map<string, unknown>"
6522
+ }
6523
+ }
6524
+ ],
6525
+ "description": "A group `value` set by the consumer (`group.value = '…'`) is a plain property assignment — it doesn't pass\nthrough any radio's own change handling, so this is what drives `checked` on the radios to match it."
6526
+ },
5818
6527
  {
5819
6528
  "kind": "method",
5820
6529
  "name": "render"
@@ -5822,11 +6531,11 @@
5822
6531
  ],
5823
6532
  "events": [
5824
6533
  {
6534
+ "name": "change",
5825
6535
  "type": {
5826
6536
  "text": "CustomEvent<{value: string}>"
5827
6537
  },
5828
- "description": "Dispatched when a radio in the group is selected",
5829
- "name": "change"
6538
+ "description": "Dispatched when a radio in the group is selected"
5830
6539
  }
5831
6540
  ],
5832
6541
  "superclass": {
@@ -5894,7 +6603,7 @@
5894
6603
  {
5895
6604
  "kind": "variable",
5896
6605
  "name": "radioStyles",
5897
- "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .radio-wrapper { align-items: center; cursor: pointer; display: inline-flex; gap: var(--lt-spacing-2); } .radio-container { display: inline-flex; position: relative; } :host([label-position='left']) .radio-wrapper { flex-direction: row-reverse; } :host([disabled]) .radio-wrapper { cursor: not-allowed; opacity: 0.6; } input[type='radio'] { appearance: none; border-radius: 50%; border: 2px solid var(--lt-border-strong); cursor: pointer; flex-shrink: 0; margin: 0; position: relative; transition: background-color 120ms ease, border-color 120ms ease; } input[type='radio']:hover:not(:disabled) { border-color: var(--lt-color-neutral-600); } input[type='radio']:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: 2px; } input[type='radio']:disabled { cursor: not-allowed; } .dot { background: white; border-radius: 50%; display: none; pointer-events: none; position: absolute; } input[type='radio']:checked ~ .dot { display: block; } .label { color: var(--lt-text-default); user-select: none; } /* Size variants */ :host([size='sm']) input[type='radio'] { height: 16px; width: 16px; } :host([size='sm']) .dot { height: 8px; width: 8px; left: 4px; top: 4px; } :host([size='sm']) .label { font-size: 0.875rem; } :host([size='md']) input[type='radio'] { height: 20px; width: 20px; } :host([size='md']) .dot { height: 10px; width: 10px; left: 5px; top: 5px; } :host([size='md']) .label { font-size: 1rem; } :host([size='lg']) input[type='radio'] { height: 24px; width: 24px; } :host([size='lg']) .dot { height: 12px; width: 12px; left: 6px; top: 6px; } :host([size='lg']) .label { font-size: 1.0625rem; } /* Variant styles */ :host([variant='primary']) input[type='radio']:checked { background: var(--lt-interactive-primary-bg); border-color: var(--lt-interactive-primary-bg); } :host([variant='primary']) input[type='radio']:checked:hover:not(:disabled) { background: var(--lt-interactive-primary-bg-hover); border-color: var(--lt-interactive-primary-bg-hover); } :host([variant='secondary']) input[type='radio']:checked { background: var(--lt-interactive-secondary-bg); border-color: var(--lt-interactive-secondary-bg); } :host([variant='secondary']) input[type='radio']:checked:hover:not(:disabled) { background: var(--lt-interactive-secondary-bg-hover); border-color: var(--lt-interactive-secondary-bg-hover); } :host([variant='success']) input[type='radio']:checked { background: var(--lt-interactive-success-bg); border-color: var(--lt-interactive-success-bg); } :host([variant='success']) input[type='radio']:checked:hover:not(:disabled) { background: var(--lt-interactive-success-bg-hover); border-color: var(--lt-interactive-success-bg-hover); } :host([variant='error']) input[type='radio']:checked { background: var(--lt-interactive-error-bg); border-color: var(--lt-interactive-error-bg); } :host([variant='error']) input[type='radio']:checked:hover:not(:disabled) { background: var(--lt-interactive-error-bg-hover); border-color: var(--lt-interactive-error-bg-hover); } :host([variant='info']) input[type='radio']:checked { background: var(--lt-interactive-info-bg); border-color: var(--lt-interactive-info-bg); } :host([variant='info']) input[type='radio']:checked:hover:not(:disabled) { background: var(--lt-interactive-info-bg-hover); border-color: var(--lt-interactive-info-bg-hover); } `"
6606
+ "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .radio-wrapper { align-items: center; cursor: pointer; display: inline-flex; gap: var(--lt-spacing-2); } .radio-container { display: inline-flex; position: relative; } :host([label-position='left']) .radio-wrapper { flex-direction: row-reverse; } /* :host(:disabled) — the browser matches this automatically for a form-associated element inside a disabled <fieldset>, no JS required; :host([disabled]) covers the component's own explicit attribute. */ :host([disabled]) .radio-wrapper, :host(:disabled) .radio-wrapper { cursor: not-allowed; opacity: 0.6; } input[type='radio'] { appearance: none; border-radius: 50%; border: 2px solid var(--lt-border-strong); cursor: pointer; flex-shrink: 0; margin: 0; position: relative; transition: background-color 120ms ease, border-color 120ms ease; } input[type='radio']:hover:not(:disabled) { border-color: var(--lt-color-neutral-600); } input[type='radio']:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: 2px; } input[type='radio']:disabled { cursor: not-allowed; } .dot { background: white; border-radius: 50%; display: none; pointer-events: none; position: absolute; } input[type='radio']:checked ~ .dot { display: block; } .label { color: var(--lt-text-default); user-select: none; } /* Size variants */ :host([size='sm']) input[type='radio'] { height: 16px; width: 16px; } :host([size='sm']) .dot { height: 8px; width: 8px; inset-inline-start: 4px; top: 4px; } :host([size='sm']) .label { font-size: 0.875rem; } :host([size='md']) input[type='radio'] { height: 20px; width: 20px; } :host([size='md']) .dot { height: 10px; width: 10px; inset-inline-start: 5px; top: 5px; } :host([size='md']) .label { font-size: 1rem; } :host([size='lg']) input[type='radio'] { height: 24px; width: 24px; } :host([size='lg']) .dot { height: 12px; width: 12px; inset-inline-start: 6px; top: 6px; } :host([size='lg']) .label { font-size: 1.0625rem; } /* Variant styles */ :host([variant='primary']) input[type='radio']:checked { background: var(--lt-interactive-primary-bg); border-color: var(--lt-interactive-primary-bg); } :host([variant='primary']) input[type='radio']:checked:hover:not(:disabled) { background: var(--lt-interactive-primary-bg-hover); border-color: var(--lt-interactive-primary-bg-hover); } :host([variant='secondary']) input[type='radio']:checked { background: var(--lt-interactive-secondary-bg); border-color: var(--lt-interactive-secondary-bg); } :host([variant='secondary']) input[type='radio']:checked:hover:not(:disabled) { background: var(--lt-interactive-secondary-bg-hover); border-color: var(--lt-interactive-secondary-bg-hover); } :host([variant='success']) input[type='radio']:checked { background: var(--lt-interactive-success-bg); border-color: var(--lt-interactive-success-bg); } :host([variant='success']) input[type='radio']:checked:hover:not(:disabled) { background: var(--lt-interactive-success-bg-hover); border-color: var(--lt-interactive-success-bg-hover); } :host([variant='error']) input[type='radio']:checked { background: var(--lt-interactive-error-bg); border-color: var(--lt-interactive-error-bg); } :host([variant='error']) input[type='radio']:checked:hover:not(:disabled) { background: var(--lt-interactive-error-bg-hover); border-color: var(--lt-interactive-error-bg-hover); } :host([variant='info']) input[type='radio']:checked { background: var(--lt-interactive-info-bg); border-color: var(--lt-interactive-info-bg); } :host([variant='info']) input[type='radio']:checked:hover:not(:disabled) { background: var(--lt-interactive-info-bg-hover); border-color: var(--lt-interactive-info-bg-hover); } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { input[type='radio'] { transition: none; } } /* ── Forced colors (Windows High Contrast) ───────────────────────────────── Under forced-colors, any author background-color (including every variant's token-resolved fill above) is flattened to Canvas — the checked indicator is a plain background:white .dot with no border of its own, so it disappears into the input's own (also-flattened) background, leaving checked and unchecked visually identical. System color keywords are exempt from that flattening and always resolve to the OS's own guaranteed-contrasting palette, regardless of which variant was selected — Highlight/HighlightText is the canonical \"selected state\" pairing (the same pair the OS uses for native text selection), unaffected by this component's own --lt-* tokens, which forced-colors mode is specifically overriding. !important is needed since a variant rule like :host([variant='primary']) input:checked outranks a bare input[type='radio']:checked in specificity — this is the standard, accepted use of !important for a forced-colors override (overriding the page's own author styling is the entire point). ─────────────────── */ @media (forced-colors: active) { input[type='radio']:checked { background: Highlight !important; border-color: Highlight !important; } .dot { background: HighlightText !important; } } `"
5898
6607
  }
5899
6608
  ],
5900
6609
  "exports": [
@@ -5932,6 +6641,15 @@
5932
6641
  "static": true,
5933
6642
  "default": "true"
5934
6643
  },
6644
+ {
6645
+ "kind": "field",
6646
+ "name": "shadowRootOptions",
6647
+ "type": {
6648
+ "text": "object"
6649
+ },
6650
+ "static": true,
6651
+ "default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true }"
6652
+ },
5935
6653
  {
5936
6654
  "kind": "field",
5937
6655
  "name": "_internals",
@@ -5940,6 +6658,44 @@
5940
6658
  },
5941
6659
  "privacy": "private"
5942
6660
  },
6661
+ {
6662
+ "kind": "field",
6663
+ "name": "_group",
6664
+ "type": {
6665
+ "text": "Set<Radio> | null"
6666
+ },
6667
+ "privacy": "private",
6668
+ "default": "null"
6669
+ },
6670
+ {
6671
+ "kind": "field",
6672
+ "name": "_default",
6673
+ "privacy": "private",
6674
+ "default": "new FormDefaultController(this, () => this.checked)"
6675
+ },
6676
+ {
6677
+ "kind": "field",
6678
+ "name": "_fieldsetDisabled",
6679
+ "privacy": "private",
6680
+ "default": "new FormDisabledController(this)"
6681
+ },
6682
+ {
6683
+ "kind": "method",
6684
+ "name": "willUpdate",
6685
+ "parameters": [
6686
+ {
6687
+ "name": "changed",
6688
+ "type": {
6689
+ "text": "PropertyValues<this>"
6690
+ }
6691
+ }
6692
+ ]
6693
+ },
6694
+ {
6695
+ "kind": "method",
6696
+ "name": "_joinGroup",
6697
+ "privacy": "private"
6698
+ },
5943
6699
  {
5944
6700
  "kind": "field",
5945
6701
  "name": "variant",
@@ -5965,7 +6721,7 @@
5965
6721
  "text": "boolean"
5966
6722
  },
5967
6723
  "default": "false",
5968
- "description": "Whether the radio is checked."
6724
+ "description": "Whether the radio is checked. Not reflected as an attribute — a native radio's `checked` _content_\nattribute stays fixed at the markup default and never tracks interaction; reflecting it live meant\n`formResetCallback` could no longer tell what the original default was. Read the property, or the `change`\nevent's `detail.checked`, instead of `[checked]`/`hasAttribute('checked')`."
5969
6725
  },
5970
6726
  {
5971
6727
  "kind": "field",
@@ -6021,6 +6777,33 @@
6021
6777
  "default": "''",
6022
6778
  "description": "Value attribute for form submission."
6023
6779
  },
6780
+ {
6781
+ "kind": "field",
6782
+ "name": "tabbable",
6783
+ "type": {
6784
+ "text": "boolean"
6785
+ },
6786
+ "default": "true",
6787
+ "description": "Whether this radio is reachable with Tab. Defaults to true for a standalone radio; `lt-radio-group` drives\nthis itself for its managed radios — a roving tabindex (only the checked radio, or the first enabled one,\nis a Tab stop), matching the native radiogroup pattern."
6788
+ },
6789
+ {
6790
+ "kind": "field",
6791
+ "name": "labels",
6792
+ "type": {
6793
+ "text": "Partial<RadioLabels>"
6794
+ },
6795
+ "default": "{}",
6796
+ "description": "Overridable UI text (the required-field validation message), for i18n. English defaults — override only the keys you need."
6797
+ },
6798
+ {
6799
+ "kind": "field",
6800
+ "name": "_labels",
6801
+ "type": {
6802
+ "text": "RadioLabels"
6803
+ },
6804
+ "privacy": "private",
6805
+ "readonly": true
6806
+ },
6024
6807
  {
6025
6808
  "kind": "method",
6026
6809
  "name": "updated"
@@ -6029,6 +6812,28 @@
6029
6812
  "kind": "method",
6030
6813
  "name": "formResetCallback"
6031
6814
  },
6815
+ {
6816
+ "kind": "method",
6817
+ "name": "formDisabledCallback",
6818
+ "parameters": [
6819
+ {
6820
+ "name": "disabled",
6821
+ "type": {
6822
+ "text": "boolean"
6823
+ }
6824
+ }
6825
+ ]
6826
+ },
6827
+ {
6828
+ "kind": "field",
6829
+ "name": "_isDisabled",
6830
+ "type": {
6831
+ "text": "boolean"
6832
+ },
6833
+ "privacy": "private",
6834
+ "description": "`this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`).",
6835
+ "readonly": true
6836
+ },
6032
6837
  {
6033
6838
  "kind": "method",
6034
6839
  "name": "checkValidity"
@@ -6134,7 +6939,7 @@
6134
6939
  "type": {
6135
6940
  "text": "array"
6136
6941
  },
6137
- "default": "[ floatingPanelReset, css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); position: relative; width: 100%; } .wrapper { display: flex; flex-direction: column; gap: var(--lt-spacing-2); } label { color: var(--lt-text-default); } .required-indicator { color: var(--lt-color-error-500); margin-left: var(--lt-spacing-1); } .select-container { position: relative; width: 100%; } .select-trigger { align-items: center; background: var(--lt-bg-subtle); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); box-sizing: border-box; cursor: pointer; display: flex; font-family: inherit; justify-content: space-between; transition: border-color 120ms ease, box-shadow 120ms ease; width: 100%; } .select-trigger:hover:not([aria-disabled='true']) { border-color: var(--lt-border-strong); } .select-trigger:focus-visible { border-color: var(--lt-interactive-primary-bg); box-shadow: 0 0 0 3px var(--lt-border-focus); outline: none; } .select-trigger[aria-disabled='true'] { cursor: not-allowed; opacity: 0.6; } .select-value { color: var(--lt-text-default); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .select-value.placeholder { color: var(--lt-text-muted); } .icon-end { color: var(--lt-text-subtle); flex-shrink: 0; transition: transform 120ms ease; } :host([open]) .icon-end { transform: rotate(180deg); } .dropdown { display: none; max-height: 300px; z-index: 1000; } .options-container { max-height: 300px; overflow: hidden auto; } .option { align-items: center; background: transparent; border: none; border-radius: var(--lt-border-radius); box-sizing: border-box; color: var(--lt-text-default); cursor: pointer; display: flex; font-family: inherit; text-align: left; transition: background-color 80ms ease; width: 100%; } .option:hover:not([disabled]) { background: var(--lt-bg-surface); } .option:focus-visible { background: var(--lt-bg-surface); outline: 2px solid var(--lt-interactive-primary-bg); outline-offset: -2px; } .option[aria-selected='true'] { background: var(--lt-bg-primary-subtle); color: var(--lt-text-primary); font-weight: 600; } .option[disabled] { color: var(--lt-text-muted); cursor: not-allowed; opacity: 0.6; } .helper-text::part(base) { font-weight: 200; } /* Size variants */ :host([size='sm']) .select-trigger { font-size: 0.875rem; height: 32px; padding: 0 var(--lt-spacing-3); } :host([size='sm']) .option { font-size: 0.875rem; padding: var(--lt-spacing-2) var(--lt-spacing-3); } :host([size='md']) .select-trigger { font-size: 1rem; height: 40px; padding: 0 var(--lt-spacing-4); } :host([size='md']) .option { font-size: 1rem; padding: var(--lt-spacing-3) var(--lt-spacing-4); } :host([size='lg']) .select-trigger { font-size: 1.0625rem; height: 48px; padding: 0 var(--lt-spacing-5); } :host([size='lg']) .option { font-size: 1.0625rem; padding: var(--lt-spacing-4) var(--lt-spacing-5); } /* Variant styles */ :host([variant='success']) .select-trigger { border-color: var(--lt-border-success-strong); } :host([variant='success']) .helper-text { color: var(--lt-text-success); } :host([variant='warning']) .select-trigger { border-color: var(--lt-border-warning-strong); } :host([variant='warning']) .helper-text { color: var(--lt-text-warning); } :host([variant='error']) .select-trigger { border-color: var(--lt-border-error-strong); } :host([variant='error']) .helper-text { color: var(--lt-text-error); } :host([variant='default']) .helper-text { color: var(--lt-text-subtle); } ` ]"
6942
+ "default": "[ floatingPanelReset, css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); position: relative; width: 100%; } .wrapper { display: flex; flex-direction: column; gap: var(--lt-spacing-2); } label { color: var(--lt-text-default); } .required-indicator { color: var(--lt-text-error); margin-inline-start: var(--lt-spacing-1); } .select-container { position: relative; width: 100%; } .select-trigger { align-items: center; background: var(--lt-bg-subtle); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); box-sizing: border-box; cursor: pointer; display: flex; font-family: inherit; justify-content: space-between; transition: border-color 120ms ease, box-shadow 120ms ease; width: 100%; } .select-trigger:hover:not([aria-disabled='true']) { border-color: var(--lt-border-strong); } .select-trigger:focus-visible { border-color: var(--lt-interactive-primary-bg); box-shadow: 0 0 0 3px var(--lt-border-focus); outline: none; } .select-trigger[aria-disabled='true'] { cursor: not-allowed; opacity: 0.6; } .select-value { color: var(--lt-text-default); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .select-value.placeholder { color: var(--lt-text-muted); } .icon-end { color: var(--lt-text-subtle); flex-shrink: 0; transition: transform 120ms ease; } :host([open]) .icon-end { transform: rotate(180deg); } .dropdown { display: none; max-height: 300px; z-index: 1000; } .options-container { max-height: 300px; overflow: hidden auto; } .option { align-items: center; background: transparent; border: none; border-radius: var(--lt-border-radius); box-sizing: border-box; color: var(--lt-text-default); cursor: pointer; display: flex; font-family: inherit; text-align: start; transition: background-color 80ms ease; width: 100%; } .option:hover:not([disabled]) { background: var(--lt-bg-surface); } .option[data-active='true'] { background: var(--lt-bg-surface); outline: 2px solid var(--lt-interactive-primary-bg); outline-offset: -2px; } .option[aria-selected='true'] { background: var(--lt-bg-primary-subtle); color: var(--lt-text-primary); font-weight: 600; } .option[disabled] { color: var(--lt-text-muted); cursor: not-allowed; opacity: 0.6; } .helper-text::part(base) { font-weight: 200; } /* Size variants */ :host([size='sm']) .select-trigger { font-size: 0.875rem; height: 32px; padding: 0 var(--lt-spacing-3); } :host([size='sm']) .option { font-size: 0.875rem; padding: var(--lt-spacing-2) var(--lt-spacing-3); } :host([size='md']) .select-trigger { font-size: 1rem; height: 40px; padding: 0 var(--lt-spacing-4); } :host([size='md']) .option { font-size: 1rem; padding: var(--lt-spacing-3) var(--lt-spacing-4); } :host([size='lg']) .select-trigger { font-size: 1.0625rem; height: 48px; padding: 0 var(--lt-spacing-5); } :host([size='lg']) .option { font-size: 1.0625rem; padding: var(--lt-spacing-4) var(--lt-spacing-5); } /* Variant styles */ :host([variant='success']) .select-trigger { border-color: var(--lt-border-success-strong); } :host([variant='success']) .helper-text { color: var(--lt-text-success); } :host([variant='warning']) .select-trigger { border-color: var(--lt-border-warning-strong); } :host([variant='warning']) .helper-text { color: var(--lt-text-warning); } :host([variant='error']) .select-trigger { border-color: var(--lt-border-error-strong); } :host([variant='error']) .helper-text { color: var(--lt-text-error); } :host([variant='default']) .helper-text { color: var(--lt-text-subtle); } /* ── Reduced motion ───────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { .select-trigger, .icon-end, .option { transition: none; } } ` ]"
6138
6943
  }
6139
6944
  ],
6140
6945
  "exports": [
@@ -6180,6 +6985,25 @@
6180
6985
  },
6181
6986
  "privacy": "private"
6182
6987
  },
6988
+ {
6989
+ "kind": "field",
6990
+ "name": "_default",
6991
+ "privacy": "private",
6992
+ "default": "new FormDefaultController(this, () => this.value)"
6993
+ },
6994
+ {
6995
+ "kind": "field",
6996
+ "name": "_fieldsetDisabled",
6997
+ "privacy": "private",
6998
+ "default": "new FormDisabledController(this)"
6999
+ },
7000
+ {
7001
+ "kind": "field",
7002
+ "name": "_uid",
7003
+ "privacy": "private",
7004
+ "readonly": true,
7005
+ "default": "`lt-select-${selectCount++}`"
7006
+ },
6183
7007
  {
6184
7008
  "kind": "field",
6185
7009
  "name": "variant",
@@ -6202,10 +7026,28 @@
6202
7026
  "kind": "field",
6203
7027
  "name": "value",
6204
7028
  "type": {
6205
- "text": "string"
7029
+ "text": "string | string[]"
6206
7030
  },
6207
7031
  "default": "''",
6208
- "description": "Current selected value."
7032
+ "description": "Current selected value. A string for a single select; with `multiple`, an array of the selected values. Not\nreflected as an attribute — read the property, or the `change` event's `detail.value`, instead of\n`getAttribute('value')`/`[value]` (consistent with the rest of the form controls; see `lt-textfield`'s\nequivalent doc comment for why)."
7033
+ },
7034
+ {
7035
+ "kind": "field",
7036
+ "name": "multiple",
7037
+ "type": {
7038
+ "text": "boolean"
7039
+ },
7040
+ "default": "false",
7041
+ "description": "Allow more than one option to be selected. The option list stays open while picking, and `value` becomes an\narray of the selected values."
7042
+ },
7043
+ {
7044
+ "kind": "field",
7045
+ "name": "_selected",
7046
+ "type": {
7047
+ "text": "string[]"
7048
+ },
7049
+ "privacy": "private",
7050
+ "readonly": true
6209
7051
  },
6210
7052
  {
6211
7053
  "kind": "field",
@@ -6272,14 +7114,42 @@
6272
7114
  },
6273
7115
  {
6274
7116
  "kind": "field",
6275
- "name": "isOpen",
7117
+ "name": "labels",
6276
7118
  "type": {
6277
- "text": "boolean"
7119
+ "text": "Partial<SelectLabels>"
7120
+ },
7121
+ "default": "{}",
7122
+ "description": "Overridable UI text (the required-field validation message), for i18n. English defaults — override only the keys you need."
7123
+ },
7124
+ {
7125
+ "kind": "field",
7126
+ "name": "_labels",
7127
+ "type": {
7128
+ "text": "SelectLabels"
7129
+ },
7130
+ "privacy": "private",
7131
+ "readonly": true
7132
+ },
7133
+ {
7134
+ "kind": "field",
7135
+ "name": "isOpen",
7136
+ "type": {
7137
+ "text": "boolean"
6278
7138
  },
6279
7139
  "privacy": "private",
6280
7140
  "default": "false",
6281
7141
  "description": "Internal state tracking whether the dropdown is open."
6282
7142
  },
7143
+ {
7144
+ "kind": "field",
7145
+ "name": "activeIndex",
7146
+ "type": {
7147
+ "text": "number"
7148
+ },
7149
+ "privacy": "private",
7150
+ "default": "-1",
7151
+ "description": "Index of the highlighted option, into `enabledOptions` below (not `options`) — the same list the render\nand the keyboard handler both use, so they can never disagree about which option is highlighted (they used\nto: the index came from the enabled-only list, but the previous focus-based highlight came from whichever\noption actually held DOM focus, decided independently)."
7152
+ },
6283
7153
  {
6284
7154
  "kind": "field",
6285
7155
  "name": "_cleanupClickOutside",
@@ -6298,6 +7168,52 @@
6298
7168
  "privacy": "private",
6299
7169
  "default": "null"
6300
7170
  },
7171
+ {
7172
+ "kind": "field",
7173
+ "name": "_fieldIds",
7174
+ "privacy": "private",
7175
+ "readonly": true
7176
+ },
7177
+ {
7178
+ "kind": "field",
7179
+ "name": "enabledOptions",
7180
+ "type": {
7181
+ "text": "SelectOption[]"
7182
+ },
7183
+ "privacy": "private",
7184
+ "readonly": true
7185
+ },
7186
+ {
7187
+ "kind": "method",
7188
+ "name": "_idFor",
7189
+ "privacy": "private",
7190
+ "return": {
7191
+ "type": {
7192
+ "text": "string"
7193
+ }
7194
+ },
7195
+ "parameters": [
7196
+ {
7197
+ "name": "option",
7198
+ "type": {
7199
+ "text": "SelectOption"
7200
+ }
7201
+ }
7202
+ ]
7203
+ },
7204
+ {
7205
+ "kind": "method",
7206
+ "name": "_preventFocusSteal",
7207
+ "privacy": "private",
7208
+ "parameters": [
7209
+ {
7210
+ "name": "e",
7211
+ "type": {
7212
+ "text": "MouseEvent"
7213
+ }
7214
+ }
7215
+ ]
7216
+ },
6301
7217
  {
6302
7218
  "kind": "method",
6303
7219
  "name": "toggleDropdown",
@@ -6351,6 +7267,18 @@
6351
7267
  },
6352
7268
  "description": "Gets the display label for the currently selected value."
6353
7269
  },
7270
+ {
7271
+ "kind": "method",
7272
+ "name": "willUpdate",
7273
+ "parameters": [
7274
+ {
7275
+ "name": "changed",
7276
+ "type": {
7277
+ "text": "PropertyValues<this>"
7278
+ }
7279
+ }
7280
+ ]
7281
+ },
6354
7282
  {
6355
7283
  "kind": "method",
6356
7284
  "name": "updated",
@@ -6367,6 +7295,28 @@
6367
7295
  "kind": "method",
6368
7296
  "name": "formResetCallback"
6369
7297
  },
7298
+ {
7299
+ "kind": "method",
7300
+ "name": "formDisabledCallback",
7301
+ "parameters": [
7302
+ {
7303
+ "name": "disabled",
7304
+ "type": {
7305
+ "text": "boolean"
7306
+ }
7307
+ }
7308
+ ]
7309
+ },
7310
+ {
7311
+ "kind": "field",
7312
+ "name": "_isDisabled",
7313
+ "type": {
7314
+ "text": "boolean"
7315
+ },
7316
+ "privacy": "private",
7317
+ "description": "`this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`).",
7318
+ "readonly": true
7319
+ },
6370
7320
  {
6371
7321
  "kind": "method",
6372
7322
  "name": "checkValidity"
@@ -6383,9 +7333,9 @@
6383
7333
  "events": [
6384
7334
  {
6385
7335
  "type": {
6386
- "text": "CustomEvent<{value: string}>"
7336
+ "text": "CustomEvent<{value: string | string[]}>"
6387
7337
  },
6388
- "description": "Dispatched when the selected value changes",
7338
+ "description": "Dispatched when the selected value changes. With `multiple`, `value` is the array of selected values.",
6389
7339
  "name": "change"
6390
7340
  }
6391
7341
  ],
@@ -6416,9 +7366,9 @@
6416
7366
  "kind": "variable",
6417
7367
  "name": "FORWARDED_ARIA_ATTRIBUTES",
6418
7368
  "type": {
6419
- "text": "[\n 'aria-pressed',\n 'aria-expanded',\n 'aria-haspopup',\n 'aria-controls',\n 'aria-current'\n]"
7369
+ "text": "[\n 'aria-pressed',\n 'aria-expanded',\n 'aria-haspopup',\n 'aria-controls',\n 'aria-current',\n 'aria-description'\n]"
6420
7370
  },
6421
- "default": "[ 'aria-pressed', 'aria-expanded', 'aria-haspopup', 'aria-controls', 'aria-current' ]",
7371
+ "default": "[ 'aria-pressed', 'aria-expanded', 'aria-haspopup', 'aria-controls', 'aria-current', 'aria-description' ]",
6422
7372
  "description": "Host `aria-*` attributes forwarded onto the internal native control.\n\nInteractive components render their semantics on a native element inside the\nshadow DOM, so ARIA attributes set on the host (`<lt-button aria-pressed=\"true\">`)\nnever reach the element screen readers actually interact with. Components that\ninstall an AriaForwardingController mirror this documented subset onto\ntheir internal control and keep it in sync as the host attributes change.\n\nNote: `aria-controls` contains an idref — it can only resolve when the referenced\nelement lives in the same tree as the internal control, so cross-shadow references\nare forwarded but may be ignored by assistive technology."
6423
7373
  },
6424
7374
  {
@@ -6494,109 +7444,434 @@
6494
7444
  {
6495
7445
  "kind": "variable",
6496
7446
  "name": "backdropFeatureStyles",
6497
- "default": "css` :host([backdrop-blur]) .backdrop, :host([backdrop-blur]) [part='overlay'] { backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); } `"
7447
+ "default": "css` :host([backdrop-blur]) dialog::backdrop { backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); } `"
7448
+ }
7449
+ ],
7450
+ "exports": [
7451
+ {
7452
+ "kind": "js",
7453
+ "name": "backdropFeatureStyles",
7454
+ "declaration": {
7455
+ "name": "backdropFeatureStyles",
7456
+ "module": "src/components/shared/backdrop.styles.ts"
7457
+ }
7458
+ }
7459
+ ]
7460
+ },
7461
+ {
7462
+ "kind": "javascript-module",
7463
+ "path": "src/components/shared/floating.ts",
7464
+ "declarations": [
7465
+ {
7466
+ "kind": "function",
7467
+ "name": "openFloating",
7468
+ "return": {
7469
+ "type": {
7470
+ "text": "Promise<() => void>"
7471
+ }
7472
+ },
7473
+ "parameters": [
7474
+ {
7475
+ "name": "reference",
7476
+ "type": {
7477
+ "text": "Element"
7478
+ }
7479
+ },
7480
+ {
7481
+ "name": "floating",
7482
+ "type": {
7483
+ "text": "HTMLElement"
7484
+ }
7485
+ },
7486
+ {
7487
+ "name": "opts",
7488
+ "optional": true,
7489
+ "type": {
7490
+ "text": "FloatingOptions"
7491
+ }
7492
+ }
7493
+ ]
7494
+ },
7495
+ {
7496
+ "kind": "function",
7497
+ "name": "closeFloating",
7498
+ "return": {
7499
+ "type": {
7500
+ "text": "void"
7501
+ }
7502
+ },
7503
+ "parameters": [
7504
+ {
7505
+ "name": "floating",
7506
+ "type": {
7507
+ "text": "HTMLElement"
7508
+ }
7509
+ },
7510
+ {
7511
+ "name": "cleanup",
7512
+ "type": {
7513
+ "text": "(() => void) | null"
7514
+ }
7515
+ }
7516
+ ]
7517
+ },
7518
+ {
7519
+ "kind": "variable",
7520
+ "name": "floatingPanelReset",
7521
+ "type": {
7522
+ "text": "CSSResult"
7523
+ },
7524
+ "default": "css` [popover] { border: 0; inset: unset; margin: 0; overflow: visible; padding: 0; position: fixed; } `"
7525
+ }
7526
+ ],
7527
+ "exports": [
7528
+ {
7529
+ "kind": "js",
7530
+ "name": "openFloating",
7531
+ "declaration": {
7532
+ "name": "openFloating",
7533
+ "module": "src/components/shared/floating.ts"
7534
+ }
7535
+ },
7536
+ {
7537
+ "kind": "js",
7538
+ "name": "closeFloating",
7539
+ "declaration": {
7540
+ "name": "closeFloating",
7541
+ "module": "src/components/shared/floating.ts"
7542
+ }
7543
+ },
7544
+ {
7545
+ "kind": "js",
7546
+ "name": "floatingPanelReset",
7547
+ "declaration": {
7548
+ "name": "floatingPanelReset",
7549
+ "module": "src/components/shared/floating.ts"
7550
+ }
7551
+ }
7552
+ ]
7553
+ },
7554
+ {
7555
+ "kind": "javascript-module",
7556
+ "path": "src/components/shared/form-default.ts",
7557
+ "declarations": [
7558
+ {
7559
+ "kind": "class",
7560
+ "description": "Captures a form-associated control's initial value the first time it connects — before any user interaction,\nor the control's own reflection, can overwrite it — so `formResetCallback` can restore what the markup\nactually asked for, the way a native `<input>`/`<select>` resets to its `defaultValue`/`defaultChecked`\ninstead of a hard-coded empty one.\n\nA reconnect (an already-upgraded element moved in the DOM) does not recapture: only the very first connect\ncounts as \"the default\", matching a real form control, which keeps its `defaultValue` fixed for its whole\nlifetime regardless of how many times it's detached and reattached.",
7561
+ "name": "FormDefaultController",
7562
+ "members": [
7563
+ {
7564
+ "kind": "field",
7565
+ "name": "_get",
7566
+ "type": {
7567
+ "text": "() => T"
7568
+ },
7569
+ "privacy": "private",
7570
+ "default": "get"
7571
+ },
7572
+ {
7573
+ "kind": "field",
7574
+ "name": "_captured",
7575
+ "type": {
7576
+ "text": "boolean"
7577
+ },
7578
+ "privacy": "private",
7579
+ "default": "false"
7580
+ },
7581
+ {
7582
+ "kind": "field",
7583
+ "name": "value",
7584
+ "type": {
7585
+ "text": "T"
7586
+ },
7587
+ "description": "The captured default. Only meaningful once the host has connected at least once."
7588
+ },
7589
+ {
7590
+ "kind": "method",
7591
+ "name": "hostConnected"
7592
+ }
7593
+ ]
7594
+ }
7595
+ ],
7596
+ "exports": [
7597
+ {
7598
+ "kind": "js",
7599
+ "name": "FormDefaultController",
7600
+ "declaration": {
7601
+ "name": "FormDefaultController",
7602
+ "module": "src/components/shared/form-default.ts"
7603
+ }
7604
+ }
7605
+ ]
7606
+ },
7607
+ {
7608
+ "kind": "javascript-module",
7609
+ "path": "src/components/shared/form-disabled.ts",
7610
+ "declarations": [
7611
+ {
7612
+ "kind": "class",
7613
+ "description": "Tracks whether this form control is disabled because it's a descendant of a disabled `<fieldset>` — kept\nseparate from the component's own explicit `disabled` property/attribute, which a consumer controls directly\nand which the fieldset toggling on or off must never overwrite in either direction. This mirrors how a native\n`<input>`'s `.disabled` IDL property only ever reflects its own attribute: a disabled fieldset makes it match\n`:disabled` and stop responding, but never touches the attribute itself, so re-enabling the fieldset can't\naccidentally un-disable an input the page explicitly disabled.\n\nThe browser already makes the host match the `:disabled`/`:enabled` CSS pseudo-classes automatically for any\nform-associated custom element the moment a fieldset ancestor's `disabled` changes — nothing has to be done\nfor that (verified in Chromium). This controller is for the *functional* side, which the platform does not\nwire up on its own: call setFieldsetDisabled from the component's own `formDisabledCallback`, and\ncombine fieldsetDisabled with the component's own `disabled` wherever that gates interaction or the\ninner native control's own `disabled`.",
7614
+ "name": "FormDisabledController",
7615
+ "members": [
7616
+ {
7617
+ "kind": "field",
7618
+ "name": "_host",
7619
+ "type": {
7620
+ "text": "ReactiveControllerHost"
7621
+ },
7622
+ "privacy": "private",
7623
+ "default": "host"
7624
+ },
7625
+ {
7626
+ "kind": "field",
7627
+ "name": "_fieldsetDisabled",
7628
+ "type": {
7629
+ "text": "boolean"
7630
+ },
7631
+ "privacy": "private",
7632
+ "default": "false"
7633
+ },
7634
+ {
7635
+ "kind": "method",
7636
+ "name": "hostConnected"
7637
+ },
7638
+ {
7639
+ "kind": "field",
7640
+ "name": "fieldsetDisabled",
7641
+ "type": {
7642
+ "text": "boolean"
7643
+ },
7644
+ "description": "Whether an ancestor `<fieldset>` is currently disabled.",
7645
+ "readonly": true
7646
+ },
7647
+ {
7648
+ "kind": "method",
7649
+ "name": "setFieldsetDisabled",
7650
+ "parameters": [
7651
+ {
7652
+ "name": "disabled",
7653
+ "type": {
7654
+ "text": "boolean"
7655
+ }
7656
+ }
7657
+ ]
7658
+ }
7659
+ ]
7660
+ }
7661
+ ],
7662
+ "exports": [
7663
+ {
7664
+ "kind": "js",
7665
+ "name": "FormDisabledController",
7666
+ "declaration": {
7667
+ "name": "FormDisabledController",
7668
+ "module": "src/components/shared/form-disabled.ts"
7669
+ }
7670
+ }
7671
+ ]
7672
+ },
7673
+ {
7674
+ "kind": "javascript-module",
7675
+ "path": "src/components/shared/form-field.ts",
7676
+ "declarations": [
7677
+ {
7678
+ "kind": "function",
7679
+ "name": "createFieldIds",
7680
+ "return": {
7681
+ "type": {
7682
+ "text": "{ helper: string }"
7683
+ }
7684
+ },
7685
+ "description": "Stable id for a field's helper text, so the control can point `aria-describedby` at it. Ids only need to be\nunique within one shadow root, but a counter keeps them unique across the page too."
7686
+ }
7687
+ ],
7688
+ "exports": [
7689
+ {
7690
+ "kind": "js",
7691
+ "name": "createFieldIds",
7692
+ "declaration": {
7693
+ "name": "createFieldIds",
7694
+ "module": "src/components/shared/form-field.ts"
7695
+ }
7696
+ }
7697
+ ]
7698
+ },
7699
+ {
7700
+ "kind": "javascript-module",
7701
+ "path": "src/components/shared/form-validity.ts",
7702
+ "declarations": [
7703
+ {
7704
+ "kind": "function",
7705
+ "name": "toValidityFlags",
7706
+ "return": {
7707
+ "type": {
7708
+ "text": "ValidityStateFlags"
7709
+ }
7710
+ },
7711
+ "parameters": [
7712
+ {
7713
+ "name": "validity",
7714
+ "type": {
7715
+ "text": "ValidityState"
7716
+ }
7717
+ }
7718
+ ],
7719
+ "description": "Copies a live `ValidityState` into a plain object with its own enumerable properties, suitable for passing to\n`ElementInternals.setValidity()`.\n\n`ValidityState`'s flags (`valueMissing`, `typeMismatch`, etc.) are getters on its prototype, not own properties\non the instance — spreading it (`{ ...validity }`) or `Object.keys(validity)` sees none of them. Real browsers'\nWebIDL dictionary conversion reads each named member individually, so passing the live object to `setValidity`\nhappens to work there; jsdom's implementation enumerates instead, so it silently sees an empty flags object and\ntreats the control as always valid. Converting explicitly avoids relying on which enumeration strategy the\nruntime uses, and is correct either way."
6498
7720
  }
6499
7721
  ],
6500
7722
  "exports": [
6501
7723
  {
6502
7724
  "kind": "js",
6503
- "name": "backdropFeatureStyles",
7725
+ "name": "toValidityFlags",
6504
7726
  "declaration": {
6505
- "name": "backdropFeatureStyles",
6506
- "module": "src/components/shared/backdrop.styles.ts"
7727
+ "name": "toValidityFlags",
7728
+ "module": "src/components/shared/form-validity.ts"
6507
7729
  }
6508
7730
  }
6509
7731
  ]
6510
7732
  },
6511
7733
  {
6512
7734
  "kind": "javascript-module",
6513
- "path": "src/components/shared/floating.ts",
7735
+ "path": "src/components/shared/roving.ts",
6514
7736
  "declarations": [
6515
7737
  {
6516
7738
  "kind": "function",
6517
- "name": "openFloating",
7739
+ "name": "enabledItems",
6518
7740
  "return": {
6519
7741
  "type": {
6520
- "text": "Promise<() => void>"
7742
+ "text": "T[]"
6521
7743
  }
6522
7744
  },
6523
7745
  "parameters": [
6524
7746
  {
6525
- "name": "reference",
7747
+ "name": "items",
6526
7748
  "type": {
6527
- "text": "Element"
7749
+ "text": "readonly T[]"
6528
7750
  }
6529
- },
7751
+ }
7752
+ ],
7753
+ "description": "Items a user can reach with the keyboard: everything not disabled, in order."
7754
+ },
7755
+ {
7756
+ "kind": "function",
7757
+ "name": "rovingTargetOf",
7758
+ "return": {
7759
+ "type": {
7760
+ "text": "T | undefined"
7761
+ }
7762
+ },
7763
+ "parameters": [
6530
7764
  {
6531
- "name": "floating",
7765
+ "name": "enabled",
6532
7766
  "type": {
6533
- "text": "HTMLElement"
7767
+ "text": "readonly T[]"
6534
7768
  }
6535
7769
  },
6536
7770
  {
6537
- "name": "opts",
6538
- "optional": true,
7771
+ "name": "value",
6539
7772
  "type": {
6540
- "text": "FloatingOptions"
7773
+ "text": "string"
6541
7774
  }
6542
7775
  }
6543
- ]
7776
+ ],
7777
+ "description": "The one item that's a Tab stop: the one matching `value`, else the first enabled item."
6544
7778
  },
6545
7779
  {
6546
7780
  "kind": "function",
6547
- "name": "closeFloating",
7781
+ "name": "stepIndex",
6548
7782
  "return": {
6549
7783
  "type": {
6550
- "text": "void"
7784
+ "text": "number"
6551
7785
  }
6552
7786
  },
6553
7787
  "parameters": [
6554
7788
  {
6555
- "name": "floating",
7789
+ "name": "index",
6556
7790
  "type": {
6557
- "text": "HTMLElement"
7791
+ "text": "number"
6558
7792
  }
6559
7793
  },
6560
7794
  {
6561
- "name": "cleanup",
7795
+ "name": "length",
6562
7796
  "type": {
6563
- "text": "(() => void) | null"
7797
+ "text": "number"
7798
+ }
7799
+ },
7800
+ {
7801
+ "name": "delta",
7802
+ "type": {
7803
+ "text": "1 | -1"
6564
7804
  }
6565
7805
  }
6566
- ]
6567
- },
6568
- {
6569
- "kind": "variable",
6570
- "name": "floatingPanelReset",
6571
- "type": {
6572
- "text": "CSSResult"
6573
- },
6574
- "default": "css` [popover] { border: 0; inset: unset; margin: 0; overflow: visible; padding: 0; position: fixed; } `"
7806
+ ],
7807
+ "description": "One step forward or back, wrapping at both ends. An index of -1 (not in the list) steps from the start."
6575
7808
  }
6576
7809
  ],
6577
7810
  "exports": [
6578
7811
  {
6579
7812
  "kind": "js",
6580
- "name": "openFloating",
7813
+ "name": "enabledItems",
6581
7814
  "declaration": {
6582
- "name": "openFloating",
6583
- "module": "src/components/shared/floating.ts"
7815
+ "name": "enabledItems",
7816
+ "module": "src/components/shared/roving.ts"
6584
7817
  }
6585
7818
  },
6586
7819
  {
6587
7820
  "kind": "js",
6588
- "name": "closeFloating",
7821
+ "name": "rovingTargetOf",
6589
7822
  "declaration": {
6590
- "name": "closeFloating",
6591
- "module": "src/components/shared/floating.ts"
7823
+ "name": "rovingTargetOf",
7824
+ "module": "src/components/shared/roving.ts"
6592
7825
  }
6593
7826
  },
6594
7827
  {
6595
7828
  "kind": "js",
6596
- "name": "floatingPanelReset",
7829
+ "name": "stepIndex",
6597
7830
  "declaration": {
6598
- "name": "floatingPanelReset",
6599
- "module": "src/components/shared/floating.ts"
7831
+ "name": "stepIndex",
7832
+ "module": "src/components/shared/roving.ts"
7833
+ }
7834
+ }
7835
+ ]
7836
+ },
7837
+ {
7838
+ "kind": "javascript-module",
7839
+ "path": "src/components/shared/scroll-lock.ts",
7840
+ "declarations": [
7841
+ {
7842
+ "kind": "function",
7843
+ "name": "lockBodyScroll",
7844
+ "return": {
7845
+ "type": {
7846
+ "text": "void"
7847
+ }
7848
+ }
7849
+ },
7850
+ {
7851
+ "kind": "function",
7852
+ "name": "unlockBodyScroll",
7853
+ "return": {
7854
+ "type": {
7855
+ "text": "void"
7856
+ }
7857
+ }
7858
+ }
7859
+ ],
7860
+ "exports": [
7861
+ {
7862
+ "kind": "js",
7863
+ "name": "lockBodyScroll",
7864
+ "declaration": {
7865
+ "name": "lockBodyScroll",
7866
+ "module": "src/components/shared/scroll-lock.ts"
7867
+ }
7868
+ },
7869
+ {
7870
+ "kind": "js",
7871
+ "name": "unlockBodyScroll",
7872
+ "declaration": {
7873
+ "name": "unlockBodyScroll",
7874
+ "module": "src/components/shared/scroll-lock.ts"
6600
7875
  }
6601
7876
  }
6602
7877
  ]
@@ -6623,7 +7898,7 @@
6623
7898
  {
6624
7899
  "kind": "variable",
6625
7900
  "name": "sidepanelStyles",
6626
- "default": "css` :host { display: contents; } /* ── Overlay ────────────────────────────────────────────────────────────── */ [part='overlay'] { position: fixed; inset: 0; background: rgba(0, 0, 0, var(--lt-sidepanel-overlay-opacity, 0.45)); z-index: 400; opacity: 0; pointer-events: none; transition: opacity 200ms ease; } /* ── Panel ──────────────────────────────────────────────────────────────── */ [part='panel'] { position: fixed; background: var(--lt-bg-default); display: flex; flex-direction: column; z-index: 401; pointer-events: none; transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1); } /* ── Anchors — initial off-screen positions ─────────────────────────────── */ :host([anchor='left']) [part='panel'], :host(:not([anchor])) [part='panel'] { inset-block: 0; left: 0; transform: translateX(-100%); box-shadow: var(--lt-sidepanel-shadow, 4px 0 24px rgba(0, 0, 0, 0.12)); } :host([anchor='right']) [part='panel'] { inset-block: 0; right: 0; transform: translateX(100%); box-shadow: var(--lt-sidepanel-shadow, -4px 0 24px rgba(0, 0, 0, 0.12)); } :host([anchor='top']) [part='panel'] { inset-inline: 0; top: 0; transform: translateY(-100%); box-shadow: var(--lt-sidepanel-shadow, 0 4px 24px rgba(0, 0, 0, 0.12)); } :host([anchor='bottom']) [part='panel'] { inset-inline: 0; bottom: 0; transform: translateY(100%); box-shadow: var(--lt-sidepanel-shadow, 0 -4px 24px rgba(0, 0, 0, 0.12)); } /* ── Open state — must come after anchors to win the cascade ────────────── */ :host([open]) [part='overlay'] { opacity: 1; pointer-events: auto; } :host([open]) [part='panel'] { transform: translate(0, 0); pointer-events: auto; } /* ── Header ─────────────────────────────────────────────────────────────── */ .header { display: flex; align-items: center; gap: var(--lt-spacing-4); padding: var(--lt-spacing-4) var(--lt-spacing-5); border-bottom: 1px solid var(--lt-border-default); flex-shrink: 0; } .panel-label { flex: 1; color: var(--lt-text-default); } .close-button { flex-shrink: 0; margin-left: auto; } /* ── Body ───────────────────────────────────────────────────────────────── */ .body { flex: 1; overflow-y: auto; padding: var(--lt-spacing-5); } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { [part='overlay'], [part='panel'] { transition: none; } } `"
7901
+ "default": "css` :host { display: contents; /* translateX/box-shadow offsets have no logical-property equivalent, unlike the inset-inline-* positioning below (which resolves automatically) — these carry the direction-dependent sign instead, flipped under :dir(rtl), so the off-screen slide direction and shadow side both stay correct without any JS reading computed direction at all. */ --_start-x: -100%; --_end-x: 100%; --_dir-sign: 1; } :host(:dir(rtl)) { --_start-x: 100%; --_end-x: -100%; --_dir-sign: -1; } /* ── Panel — the native <dialog> itself now provides the overlay too, via ::backdrop; a closed dialog is display:none automatically, so unlike the old transform-only-hidden div, a closed panel is genuinely non-interactive and out of the accessibility tree, with no extra JS needed (SPL-1). ────────────────────── */ dialog { background: var(--lt-bg-default); border: none; color: var(--lt-text-default); margin: 0; max-height: none; max-width: none; padding: 0; position: fixed; /* display is deliberately NOT set here — a closed dialog must stay display:none (the native default) for SPL-1's fix to actually hold (genuinely non-interactive, out of the accessibility tree); it's set to flex only for the open state, below. display/overlay need transition-behavior: allow-discrete so close() doesn't remove the panel (and its ::backdrop) from rendering instantly, cutting the slide-out transform transition off partway through — same reasoning as lt-dialog. */ transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1), display 250ms allow-discrete, overlay 250ms allow-discrete; } dialog::backdrop { background: rgba(0, 0, 0, 0); transition: background-color 200ms ease, display 250ms allow-discrete, overlay 250ms allow-discrete; } dialog[open]::backdrop { background: rgba(0, 0, 0, var(--lt-sidepanel-overlay-opacity, 0.45)); } /* ── Anchors — off-screen positions; dialog[open] (below) is the only thing that moves it on-screen. Fully explicit inset-inline-start/end/top/bottom (not inset-block/inline shorthand, and not omitting the opposite side to fall back to \"auto\") and an explicit height/width — a native <dialog>, even position:fixed, does not stretch to fill top:0/bottom:0 the way a plain block box would; confirmed empirically, it needs an explicit dimension on the axis inset alone doesn't constrain. ────────────────── */ :host([anchor='start']) dialog, :host(:not([anchor])) dialog { top: 0; inset-inline-end: auto; bottom: auto; inset-inline-start: 0; height: 100vh; transform: translateX(var(--_start-x)); box-shadow: var(--lt-sidepanel-shadow, calc(4px * var(--_dir-sign)) 0 24px rgba(0, 0, 0, 0.12)); } :host([anchor='end']) dialog { top: 0; inset-inline-end: 0; bottom: auto; inset-inline-start: auto; height: 100vh; transform: translateX(var(--_end-x)); box-shadow: var(--lt-sidepanel-shadow, calc(-4px * var(--_dir-sign)) 0 24px rgba(0, 0, 0, 0.12)); } :host([anchor='top']) dialog { top: 0; inset-inline-end: auto; bottom: auto; inset-inline-start: 0; width: 100vw; transform: translateY(-100%); box-shadow: var(--lt-sidepanel-shadow, 0 4px 24px rgba(0, 0, 0, 0.12)); } :host([anchor='bottom']) dialog { top: auto; inset-inline-end: auto; bottom: 0; inset-inline-start: 0; width: 100vw; transform: translateY(100%); box-shadow: var(--lt-sidepanel-shadow, 0 -4px 24px rgba(0, 0, 0, 0.12)); } dialog[open] { display: flex; flex-direction: column; } /* The transform override has to be scoped per anchor, not a bare dialog[open] — :host([anchor='end']) dialog (above) has HIGHER specificity than a plain dialog[open] (one more attribute selector, from the :host() argument), so a bare \"dialog[open] { transform: translate(0,0); }\" would lose the cascade to the anchor rule's own closed-position transform regardless of source order, leaving the panel permanently stuck off-screen. Matching each anchor rule's own specificity here guarantees the open state wins. */ :host([anchor='start']) dialog[open], :host(:not([anchor])) dialog[open], :host([anchor='end']) dialog[open], :host([anchor='top']) dialog[open], :host([anchor='bottom']) dialog[open] { transform: translate(0, 0); } /* A newly-shown dialog has no earlier rendered frame to transition from — @starting-style supplies one, per anchor, so the slide-in actually animates instead of snapping straight to the open position. */ @starting-style { :host([anchor='start']) dialog[open], :host(:not([anchor])) dialog[open] { transform: translateX(var(--_start-x)); } :host([anchor='end']) dialog[open] { transform: translateX(var(--_end-x)); } :host([anchor='top']) dialog[open] { transform: translateY(-100%); } :host([anchor='bottom']) dialog[open] { transform: translateY(100%); } } /* ── Header ─────────────────────────────────────────────────────────────── */ .header { display: flex; align-items: center; gap: var(--lt-spacing-4); padding: var(--lt-spacing-4) var(--lt-spacing-5); border-bottom: 1px solid var(--lt-border-default); flex-shrink: 0; } .panel-label { flex: 1; color: var(--lt-text-default); } .close-button { flex-shrink: 0; margin-inline-start: auto; } /* ── Body ───────────────────────────────────────────────────────────────── */ .body { flex: 1; overflow-y: auto; padding: var(--lt-spacing-5); } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { dialog, dialog::backdrop { transition: none; } } `"
6627
7902
  }
6628
7903
  ],
6629
7904
  "exports": [
@@ -6643,21 +7918,25 @@
6643
7918
  "declarations": [
6644
7919
  {
6645
7920
  "kind": "class",
6646
- "description": "A slide-in panel anchored to any edge of the viewport, with a backdrop overlay.",
7921
+ "description": "A slide-in panel anchored to any edge of the viewport, built on the native `<dialog>` element — the same\nmigration `lt-dialog` went through (DLG-1..4), applied here to fix the equivalent gaps (SPL-1/2/3): a closed\npanel is no longer just transformed off-screen while staying focusable and exposed to assistive tech\n(`display: none` when closed is native, automatic, and absolute); focus trap and restore on close both come\nfrom `showModal()`/`close()` for free — no manual focus-tracking code needed here at all, unlike `lt-dialog`,\nwhich still carries its own from before that component's migration; Escape closes only the panel that was\nactually focused, not every open panel on the page (no more `window`-level keydown listener); and `close`\nfires consistently from `updated()` whenever `open` becomes `false`, however it happened — not only when\n`hide()` was called directly.",
6647
7922
  "name": "SidePanel",
6648
7923
  "cssProperties": [
6649
7924
  {
6650
7925
  "description": "Overrides the panel's box-shadow, for all anchor positions.",
6651
7926
  "name": "--lt-sidepanel-shadow"
7927
+ },
7928
+ {
7929
+ "description": "Backdrop darkness. Set via the `overlay-opacity` property/attribute instead of this custom property directly, unless you're overriding it from outside the component.",
7930
+ "name": "--lt-sidepanel-overlay-opacity"
6652
7931
  }
6653
7932
  ],
6654
7933
  "cssParts": [
6655
7934
  {
6656
- "description": "The backdrop scrim behind the panel",
7935
+ "description": "The backdrop scrim behind the panel (the native `<dialog>`'s own `::backdrop`, exposed as a part so consumers can still target it, even though it's not a real light-DOM-visible element)",
6657
7936
  "name": "overlay"
6658
7937
  },
6659
7938
  {
6660
- "description": "The sliding panel container",
7939
+ "description": "The sliding panel container (the `<dialog>` element itself)",
6661
7940
  "name": "panel"
6662
7941
  },
6663
7942
  {
@@ -6704,8 +7983,8 @@
6704
7983
  "type": {
6705
7984
  "text": "SidePanelAnchor"
6706
7985
  },
6707
- "default": "'left'",
6708
- "description": "Edge from which the panel slides in."
7986
+ "default": "'start'",
7987
+ "description": "Edge from which the panel slides in. `'start'`/`'end'` flip with reading direction."
6709
7988
  },
6710
7989
  {
6711
7990
  "kind": "field",
@@ -6714,7 +7993,7 @@
6714
7993
  "text": "string"
6715
7994
  },
6716
7995
  "default": "'320px'",
6717
- "description": "Panel width (left/right anchors) or height (top/bottom anchors)."
7996
+ "description": "Panel width (start/end anchors) or height (top/bottom anchors)."
6718
7997
  },
6719
7998
  {
6720
7999
  "kind": "field",
@@ -6752,6 +8031,50 @@
6752
8031
  "default": "0.45",
6753
8032
  "description": "Backdrop darkness as an alpha value from 0 (transparent) to 1 (opaque)."
6754
8033
  },
8034
+ {
8035
+ "kind": "field",
8036
+ "name": "labels",
8037
+ "type": {
8038
+ "text": "Partial<SidePanelLabels>"
8039
+ },
8040
+ "default": "{}",
8041
+ "description": "Overridable UI text (the close button's accessible name), for i18n. English defaults — override only the keys you need."
8042
+ },
8043
+ {
8044
+ "kind": "field",
8045
+ "name": "_labels",
8046
+ "type": {
8047
+ "text": "SidePanelLabels"
8048
+ },
8049
+ "privacy": "private",
8050
+ "readonly": true
8051
+ },
8052
+ {
8053
+ "kind": "field",
8054
+ "name": "dialogElement",
8055
+ "type": {
8056
+ "text": "HTMLDialogElement | undefined"
8057
+ },
8058
+ "privacy": "private"
8059
+ },
8060
+ {
8061
+ "kind": "field",
8062
+ "name": "_scrollLocked",
8063
+ "type": {
8064
+ "text": "boolean"
8065
+ },
8066
+ "privacy": "private",
8067
+ "default": "false"
8068
+ },
8069
+ {
8070
+ "kind": "field",
8071
+ "name": "_skipNextOpenChange",
8072
+ "type": {
8073
+ "text": "boolean"
8074
+ },
8075
+ "privacy": "private",
8076
+ "default": "true"
8077
+ },
6755
8078
  {
6756
8079
  "kind": "method",
6757
8080
  "name": "show",
@@ -6770,15 +8093,9 @@
6770
8093
  "privacy": "public",
6771
8094
  "description": "Toggle the panel open/closed."
6772
8095
  },
6773
- {
6774
- "kind": "field",
6775
- "name": "_handleKeyDown",
6776
- "privacy": "private"
6777
- },
6778
8096
  {
6779
8097
  "kind": "method",
6780
8098
  "name": "updated",
6781
- "privacy": "protected",
6782
8099
  "return": {
6783
8100
  "type": {
6784
8101
  "text": "void"
@@ -6788,11 +8105,31 @@
6788
8105
  {
6789
8106
  "name": "changed",
6790
8107
  "type": {
6791
- "text": "PropertyValues"
8108
+ "text": "PropertyValues<this>"
6792
8109
  }
6793
8110
  }
6794
8111
  ]
6795
8112
  },
8113
+ {
8114
+ "kind": "method",
8115
+ "name": "_handleOpen",
8116
+ "privacy": "private"
8117
+ },
8118
+ {
8119
+ "kind": "method",
8120
+ "name": "_handleClose",
8121
+ "privacy": "private"
8122
+ },
8123
+ {
8124
+ "kind": "field",
8125
+ "name": "_handleNativeClose",
8126
+ "privacy": "private"
8127
+ },
8128
+ {
8129
+ "kind": "field",
8130
+ "name": "_handleDialogClick",
8131
+ "privacy": "private"
8132
+ },
6796
8133
  {
6797
8134
  "kind": "field",
6798
8135
  "name": "_offScreenTransform",
@@ -6811,6 +8148,15 @@
6811
8148
  "privacy": "private",
6812
8149
  "readonly": true
6813
8150
  },
8151
+ {
8152
+ "kind": "field",
8153
+ "name": "_hasLabel",
8154
+ "type": {
8155
+ "text": "boolean"
8156
+ },
8157
+ "privacy": "private",
8158
+ "readonly": true
8159
+ },
6814
8160
  {
6815
8161
  "kind": "method",
6816
8162
  "name": "_renderHeader",
@@ -6823,7 +8169,11 @@
6823
8169
  ],
6824
8170
  "events": [
6825
8171
  {
6826
- "description": "Fired when the user requests close (backdrop click, Escape key, or close button)",
8172
+ "description": "Fired when the panel opens",
8173
+ "name": "open"
8174
+ },
8175
+ {
8176
+ "description": "Fired when the panel closes (however it closed — the close button, Escape, a backdrop click, or setting `open` to `false` directly)",
6827
8177
  "name": "close"
6828
8178
  }
6829
8179
  ],
@@ -6876,7 +8226,7 @@
6876
8226
  {
6877
8227
  "kind": "variable",
6878
8228
  "name": "skeletonStyles",
6879
- "default": "css` :host { display: block; } [part='base'] { background: var(--lt-color-neutral-200); border-radius: var(--lt-border-radius); height: 1.25rem; overflow: hidden; width: 100%; } :host([shape='text']) [part='base'] { border-radius: 4px; height: 1em; } :host([shape='circle']) [part='base'] { border-radius: 50%; height: 2.5rem; width: 2.5rem; } :host([animated]) [part='base'] { animation: shimmer 1.5s ease-in-out infinite; background: linear-gradient( 90deg, var(--lt-color-neutral-100) 25%, var(--lt-color-neutral-200) 50%, var(--lt-color-neutral-100) 75% ); background-size: 200% 100%; } @keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } @media (prefers-reduced-motion: reduce) { :host([animated]) [part='base'] { animation: none; background: var(--lt-color-neutral-200); } } `"
8229
+ "default": "css` :host { display: block; } [part='base'] { background: var(--lt-bg-overlay); border-radius: var(--lt-border-radius); height: 1.25rem; overflow: hidden; width: 100%; } :host([shape='text']) [part='base'] { border-radius: 4px; height: 1em; } :host([shape='circle']) [part='base'] { border-radius: 50%; height: 2.5rem; width: 2.5rem; } :host([animated]) [part='base'] { animation: shimmer 1.5s ease-in-out infinite; background: linear-gradient(90deg, var(--lt-bg-surface) 25%, var(--lt-bg-overlay) 50%, var(--lt-bg-surface) 75%); background-size: 200% 100%; } @keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } @media (prefers-reduced-motion: reduce) { :host([animated]) [part='base'] { animation: none; background: var(--lt-bg-overlay); } } `"
6880
8230
  }
6881
8231
  ],
6882
8232
  "exports": [
@@ -6995,7 +8345,7 @@
6995
8345
  {
6996
8346
  "kind": "variable",
6997
8347
  "name": "sliderStyles",
6998
- "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); width: 100%; } label { color: var(--lt-text-default); display: block; margin-bottom: var(--lt-spacing-1); user-select: none; } .track-wrap { align-items: center; display: flex; width: 100%; } /* lt-tooltip fills the track-wrap so the input stays full-width */ .track-wrap lt-tooltip { display: block; width: 100%; } /* Position the tooltip above the thumb rather than the track center */ lt-tooltip::part(tooltip) { left: var(--_thumb-left, 50%); } input[type='range'] { appearance: none; background: linear-gradient( to right, var(--lt-interactive-primary-bg) var(--lt-slider-fill, 0%), var(--lt-border-strong) var(--lt-slider-fill, 0%) ); border-radius: 9999px; cursor: pointer; display: block; height: var(--lt-slider-track-height, 6px); outline: none; transition: background 0ms; width: 100%; } input[type='range']:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: 3px; } input[type='range']:hover:not(:disabled) { --lt-interactive-primary-bg: var(--lt-interactive-primary-bg-hover); } input[type='range']:active:not(:disabled) { --lt-interactive-primary-bg: var(--lt-interactive-primary-bg-active); } /* Thumb — WebKit */ input[type='range']::-webkit-slider-thumb { appearance: none; background: var(--lt-interactive-primary-bg); border-radius: 50%; border: 2px solid white; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25); cursor: pointer; height: var(--lt-slider-thumb-size, 18px); transition: transform 100ms ease; width: var(--lt-slider-thumb-size, 18px); } input[type='range']::-webkit-slider-thumb:hover { transform: scale(1.15); } input[type='range']:active::-webkit-slider-thumb { transform: scale(1.05); } /* Thumb — Firefox */ input[type='range']::-moz-range-thumb { appearance: none; background: var(--lt-interactive-primary-bg); border-radius: 50%; border: 2px solid white; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25); cursor: pointer; height: var(--lt-slider-thumb-size, 18px); transition: transform 100ms ease; width: var(--lt-slider-thumb-size, 18px); } /* Track — Firefox */ input[type='range']::-moz-range-track { background: var(--lt-border-strong); border-radius: 9999px; height: var(--lt-slider-track-height, 6px); } input[type='range']::-moz-range-progress { background: var(--lt-interactive-primary-bg); border-radius: 9999px; height: var(--lt-slider-track-height, 6px); } /* Sizes */ :host([size='sm']) { --lt-slider-track-height: 4px; --lt-slider-thumb-size: 14px; } :host([size='md']) { --lt-slider-track-height: 6px; --lt-slider-thumb-size: 18px; } :host([size='lg']) { --lt-slider-track-height: 8px; --lt-slider-thumb-size: 22px; } /* Disabled */ :host([disabled]) { opacity: 0.5; } :host([disabled]) input[type='range'] { cursor: not-allowed; pointer-events: none; } `"
8348
+ "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); width: 100%; } label { color: var(--lt-text-default); display: block; margin-bottom: var(--lt-spacing-1); user-select: none; } .track-wrap { align-items: center; display: flex; width: 100%; } /* lt-tooltip fills the track-wrap so the input stays full-width */ .track-wrap lt-tooltip { display: block; width: 100%; } /* Position the tooltip above the thumb rather than the track center. --_fill is a unitless 0–1 ratio (set from JS on :host) — computed in CSS, not from a JS-read offsetWidth, so it can never drift after a resize or when first shown from display:none (SLD-1). The thumb travels only (100% - thumb size), offset by half the thumb so it's centered on the value, matching a native range input's own thumb geometry. */ lt-tooltip::part(tooltip) { left: calc(var(--_fill, 0) * (100% - var(--lt-slider-thumb-size, 18px)) + var(--lt-slider-thumb-size, 18px) / 2); } input[type='range'] { appearance: none; background: linear-gradient( to right, var(--lt-interactive-primary-bg) calc(var(--_fill, 0) * 100%), var(--lt-border-strong) calc(var(--_fill, 0) * 100%) ); border-radius: 9999px; cursor: pointer; display: block; height: var(--lt-slider-track-height, 6px); outline: none; transition: background 0ms; width: 100%; } input[type='range']:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: 3px; } input[type='range']:hover:not(:disabled) { --lt-interactive-primary-bg: var(--lt-interactive-primary-bg-hover); } input[type='range']:active:not(:disabled) { --lt-interactive-primary-bg: var(--lt-interactive-primary-bg-active); } /* Thumb — WebKit */ input[type='range']::-webkit-slider-thumb { appearance: none; background: var(--lt-interactive-primary-bg); border-radius: 50%; border: 2px solid white; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25); cursor: pointer; height: var(--lt-slider-thumb-size, 18px); transition: transform 100ms ease; width: var(--lt-slider-thumb-size, 18px); } input[type='range']::-webkit-slider-thumb:hover { transform: scale(1.15); } input[type='range']:active::-webkit-slider-thumb { transform: scale(1.05); } /* Thumb — Firefox */ input[type='range']::-moz-range-thumb { appearance: none; background: var(--lt-interactive-primary-bg); border-radius: 50%; border: 2px solid white; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25); cursor: pointer; height: var(--lt-slider-thumb-size, 18px); transition: transform 100ms ease; width: var(--lt-slider-thumb-size, 18px); } /* Track — Firefox */ input[type='range']::-moz-range-track { background: var(--lt-border-strong); border-radius: 9999px; height: var(--lt-slider-track-height, 6px); } input[type='range']::-moz-range-progress { background: var(--lt-interactive-primary-bg); border-radius: 9999px; height: var(--lt-slider-track-height, 6px); } /* Sizes */ :host([size='sm']) { --lt-slider-track-height: 4px; --lt-slider-thumb-size: 14px; } :host([size='md']) { --lt-slider-track-height: 6px; --lt-slider-thumb-size: 18px; } :host([size='lg']) { --lt-slider-track-height: 8px; --lt-slider-thumb-size: 22px; } /* Disabled. :host(:disabled) — the browser matches this automatically for a form-associated element inside a disabled <fieldset>, no JS required; :host([disabled]) covers the component's own explicit attribute. */ :host([disabled]), :host(:disabled) { opacity: 0.5; } :host([disabled]) input[type='range'], :host(:disabled) input[type='range'] { cursor: not-allowed; pointer-events: none; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { input[type='range']::-webkit-slider-thumb, input[type='range']::-moz-range-thumb { transition: none; } } /* ── Forced colors (Windows High Contrast) ───────────────────────────────── Under forced-colors, the track's linear-gradient (WebKit/Chromium) and the Firefox ::-moz-range-track/ ::-moz-range-progress pair are all flattened to Canvas, with no border to fall back on — the whole track disappears. Restoring a visible track boundary, plus a solid thumb fill, is enough: the thumb's own position already conveys the value (the primary way a slider communicates it visually), matching how native <input type=\"range\"> itself renders under forced-colors in every engine — no attempt to also recreate the fill-amount gradient with system colors, which native sliders don't do either. System color keywords are exempt from the flattening and always resolve to the OS's own guaranteed-contrasting palette. ─────────────────────────────────────────────────────────────────────────────────────────────── */ @media (forced-colors: active) { input[type='range'] { background: Canvas; border: 1px solid ButtonText; } input[type='range']::-webkit-slider-thumb { background: Highlight; border-color: ButtonText; } input[type='range']::-moz-range-thumb { background: Highlight; border-color: ButtonText; } input[type='range']::-moz-range-track { background: Canvas; border: 1px solid ButtonText; } input[type='range']::-moz-range-progress { background: Highlight; } } `"
6999
8349
  }
7000
8350
  ],
7001
8351
  "exports": [
@@ -7041,6 +8391,18 @@
7041
8391
  },
7042
8392
  "privacy": "private"
7043
8393
  },
8394
+ {
8395
+ "kind": "field",
8396
+ "name": "_default",
8397
+ "privacy": "private",
8398
+ "default": "new FormDefaultController(this, () => this.value)"
8399
+ },
8400
+ {
8401
+ "kind": "field",
8402
+ "name": "_fieldsetDisabled",
8403
+ "privacy": "private",
8404
+ "default": "new FormDisabledController(this)"
8405
+ },
7044
8406
  {
7045
8407
  "kind": "field",
7046
8408
  "name": "size",
@@ -7096,7 +8458,8 @@
7096
8458
  "type": {
7097
8459
  "text": "number"
7098
8460
  },
7099
- "default": "0"
8461
+ "default": "0",
8462
+ "description": "Not reflected as an attribute — read the property, or the `change` event's `detail.value`, instead of\n`getAttribute('value')`/`[value]`."
7100
8463
  },
7101
8464
  {
7102
8465
  "kind": "field",
@@ -7118,15 +8481,7 @@
7118
8481
  },
7119
8482
  {
7120
8483
  "kind": "field",
7121
- "name": "input",
7122
- "type": {
7123
- "text": "HTMLInputElement"
7124
- },
7125
- "privacy": "private"
7126
- },
7127
- {
7128
- "kind": "field",
7129
- "name": "_fillPercent",
8484
+ "name": "_fillRatio",
7130
8485
  "type": {
7131
8486
  "text": "number"
7132
8487
  },
@@ -7135,13 +8490,34 @@
7135
8490
  },
7136
8491
  {
7137
8492
  "kind": "method",
7138
- "name": "_thumbSizePx",
8493
+ "name": "_sanitize",
7139
8494
  "privacy": "private",
7140
8495
  "return": {
7141
8496
  "type": {
7142
8497
  "text": "number"
7143
8498
  }
7144
- }
8499
+ },
8500
+ "parameters": [
8501
+ {
8502
+ "name": "value",
8503
+ "type": {
8504
+ "text": "number"
8505
+ }
8506
+ }
8507
+ ],
8508
+ "description": "Clamps to [min, max] and snaps to the nearest step from min, matching how a native <input type=\"range\">\nsanitizes its own value — including when `value`/`min`/`max`/`step` are set programmatically, which a native\nrange input clamps on its own internal value but this component didn't mirror onto its own `value` property\n(SLD-1: `value` wasn't clamped/stepped, so e.g. `value=150` with `max=100` produced a 150% fill and\nsubmitted \"150\" to the form even though the visible thumb was pinned at the end)."
8509
+ },
8510
+ {
8511
+ "kind": "method",
8512
+ "name": "willUpdate",
8513
+ "parameters": [
8514
+ {
8515
+ "name": "changed",
8516
+ "type": {
8517
+ "text": "PropertyValues"
8518
+ }
8519
+ }
8520
+ ]
7145
8521
  },
7146
8522
  {
7147
8523
  "kind": "method",
@@ -7151,6 +8527,28 @@
7151
8527
  "kind": "method",
7152
8528
  "name": "formResetCallback"
7153
8529
  },
8530
+ {
8531
+ "kind": "method",
8532
+ "name": "formDisabledCallback",
8533
+ "parameters": [
8534
+ {
8535
+ "name": "disabled",
8536
+ "type": {
8537
+ "text": "boolean"
8538
+ }
8539
+ }
8540
+ ]
8541
+ },
8542
+ {
8543
+ "kind": "field",
8544
+ "name": "_isDisabled",
8545
+ "type": {
8546
+ "text": "boolean"
8547
+ },
8548
+ "privacy": "private",
8549
+ "description": "`this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`).",
8550
+ "readonly": true
8551
+ },
7154
8552
  {
7155
8553
  "kind": "method",
7156
8554
  "name": "checkValidity"
@@ -7255,7 +8653,7 @@
7255
8653
  {
7256
8654
  "kind": "variable",
7257
8655
  "name": "snackbarStyles",
7258
- "default": "css` :host { display: block; bottom: 24px; left: 50%; max-width: calc(100vw - 48px); opacity: 0; position: fixed; transform: translateX(-50%) translateY(8px); transition: opacity 200ms ease, transform 200ms ease, visibility 200ms ease; visibility: hidden; width: max-content; z-index: 9000; } :host([open]) { opacity: 1; transform: translateX(-50%) translateY(0); visibility: visible; } /* ── Layout ──────────────────────────────────────────────── */ .inner { align-items: center; color: var(--lt-text-inverse); display: flex; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); font-size: 0.875rem; gap: var(--lt-spacing-2); line-height: 1.4; padding: var(--lt-spacing-3) var(--lt-spacing-4); } /* ── Variant text colors ─────────────────────────────────── */ :host([variant='success']) .inner { color: var(--lt-text-on-success); } :host([variant='warning']) .inner { color: var(--lt-text-on-warning); } :host([variant='error']) .inner { color: var(--lt-text-on-error); } :host([variant='info']) .inner { color: var(--lt-text-on-info); } /* ── Variant icon ────────────────────────────────────────── */ .variant-icon { flex-shrink: 0; font-size: 1.125rem; } /* ── Message ─────────────────────────────────────────────── */ .message { flex: 1; } /* ── Action button ───────────────────────────────────────── */ .action { background: transparent; border: none; color: inherit; cursor: pointer; font-family: inherit; font-size: 0.8125rem; font-weight: 600; letter-spacing: 0.05em; opacity: 0.85; padding: 0 var(--lt-spacing-1); text-transform: uppercase; } .action:hover { opacity: 1; } /* ── Close button ────────────────────────────────────────── */ .close { align-items: center; background: transparent; border: none; color: inherit; cursor: pointer; display: flex; flex-shrink: 0; justify-content: center; opacity: 0.7; padding: 0; } .close:hover { opacity: 1; } `"
8656
+ "default": "css` /* ── Popover ─────────────────────────────────────────────── The host itself is the popover element (no wrapped child, unlike lt-dialog/lt-sidepanel's inner <dialog>) — the browser's own [popover] UA stylesheet sets inset:0, margin:auto, width/height:fit-content, padding, border, and Canvas colors, all of which are reset below in favor of this component's own bottom-center placement. display is deliberately NOT set on the base rule — a closed (not :popover-open) popover must stay display:none (the native default) so it's genuinely non-interactive and out of the accessibility tree; it's set to block only for the open state, below. display/overlay need transition-behavior: allow-discrete so hidePopover() doesn't remove it from rendering instantly, cutting the exit transition off partway through — same reasoning as lt-dialog. ─────── */ :host { background: transparent; border: none; bottom: 24px; left: 50%; margin: 0; max-width: calc(100vw - 48px); opacity: 0; overflow: visible; padding: 0; position: fixed; right: auto; top: auto; transform: translateX(-50%) translateY(8px); transition: opacity 200ms ease, transform 200ms ease, display 200ms allow-discrete, overlay 200ms allow-discrete; width: max-content; } :host([open]) { display: block; opacity: 1; transform: translateX(-50%) translateY(0); } /* A newly-shown popover has no earlier rendered frame to transition from — @starting-style supplies one so the fade/slide-in actually animates instead of snapping straight to the open position. */ @starting-style { :host([open]) { opacity: 0; transform: translateX(-50%) translateY(8px); } } /* ── Layout ──────────────────────────────────────────────── */ .inner { align-items: center; color: var(--lt-text-inverse); display: flex; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); font-size: 0.875rem; gap: var(--lt-spacing-2); line-height: 1.4; padding: var(--lt-spacing-3) var(--lt-spacing-4); } /* ── Variant text colors ─────────────────────────────────── */ :host([variant='success']) .inner { color: var(--lt-text-on-success); } :host([variant='warning']) .inner { color: var(--lt-text-on-warning); } :host([variant='error']) .inner { color: var(--lt-text-on-error); } :host([variant='info']) .inner { color: var(--lt-text-on-info); } /* ── Variant icon ────────────────────────────────────────── */ .variant-icon { flex-shrink: 0; font-size: 1.125rem; } /* ── Message ─────────────────────────────────────────────── */ .message { flex: 1; } /* ── Action button ───────────────────────────────────────── */ .action { background: transparent; border: none; color: inherit; cursor: pointer; font-family: inherit; font-size: 0.8125rem; font-weight: 600; letter-spacing: 0.05em; padding: 0 var(--lt-spacing-1); text-transform: uppercase; } /* Text on a coloured fill is never dimmed with opacity (that blends it into the fill and lowers its contrast below whatever the on-colour was picked for), so hover is shown with an underline instead. */ .action:hover { text-decoration: underline; } /* ── Close button ────────────────────────────────────────── */ .close { align-items: center; background: transparent; border: none; color: inherit; cursor: pointer; display: flex; flex-shrink: 0; justify-content: center; min-height: 24px; /* WCAG 2.5.8 */ min-width: 24px; opacity: 0.7; padding: 0; } .close:hover { opacity: 1; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { :host { transition: none; } } `"
7259
8657
  }
7260
8658
  ],
7261
8659
  "exports": [
@@ -7275,7 +8673,7 @@
7275
8673
  "declarations": [
7276
8674
  {
7277
8675
  "kind": "class",
7278
- "description": "Brief notification that appears temporarily at the bottom of the viewport.",
8676
+ "description": "Brief notification that appears temporarily at the bottom of the viewport.\n\nRenders as a native \"manual\" popover on its own host, so it always appears in the top layer — above an open\n`lt-dialog`/`lt-sidepanel`, regardless of z-index, since top-layer content always wins over non-top-layer\ncontent no matter how high (SNK-companion to §6.1's `<dialog>` migration). Confirmed live: fully visible and\nreadable above an open modal. One narrower, unavoidable limitation (confirmed live too, not fixable from this\ncomponent's side): a native `showModal()` makes everything **outside the dialog's own subtree** inert,\nincluding a sibling popover — explicitly setting `inert = false` on the snackbar does not override it. A\nsnackbar shown while a dialog is open is visible but not clickable until the dialog closes; its own\n`duration` timer still fires normally regardless (a plain `setTimeout`, unaffected by inertness), so only a\n`duration=\"0\"` snackbar with a close/action button would be briefly stuck non-interactive in that scenario.",
7279
8677
  "name": "Snackbar",
7280
8678
  "slots": [
7281
8679
  {
@@ -7362,6 +8760,24 @@
7362
8760
  "default": "'filled'",
7363
8761
  "description": "Visual appearance of the internal surface, matching `lt-surface`'s vocabulary."
7364
8762
  },
8763
+ {
8764
+ "kind": "field",
8765
+ "name": "labels",
8766
+ "type": {
8767
+ "text": "Partial<SnackbarLabels>"
8768
+ },
8769
+ "default": "{}",
8770
+ "description": "Overridable UI text (the close button's accessible name), for i18n. English defaults — override only the keys you need."
8771
+ },
8772
+ {
8773
+ "kind": "field",
8774
+ "name": "_labels",
8775
+ "type": {
8776
+ "text": "SnackbarLabels"
8777
+ },
8778
+ "privacy": "private",
8779
+ "readonly": true
8780
+ },
7365
8781
  {
7366
8782
  "kind": "field",
7367
8783
  "name": "_timer",
@@ -7370,6 +8786,15 @@
7370
8786
  },
7371
8787
  "privacy": "private"
7372
8788
  },
8789
+ {
8790
+ "kind": "field",
8791
+ "name": "_skipNextOpenChange",
8792
+ "type": {
8793
+ "text": "boolean"
8794
+ },
8795
+ "privacy": "private",
8796
+ "default": "true"
8797
+ },
7373
8798
  {
7374
8799
  "kind": "method",
7375
8800
  "name": "show",
@@ -7394,6 +8819,11 @@
7394
8819
  }
7395
8820
  ]
7396
8821
  },
8822
+ {
8823
+ "kind": "method",
8824
+ "name": "_syncPopoverState",
8825
+ "privacy": "private"
8826
+ },
7397
8827
  {
7398
8828
  "kind": "method",
7399
8829
  "name": "_startTimer",
@@ -7631,7 +9061,7 @@
7631
9061
  {
7632
9062
  "kind": "variable",
7633
9063
  "name": "surfaceStyles",
7634
- "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .surface { background: var(--lt-surface-bg, var(--lt-bg-subtle)); border-radius: var(--lt-border-radius); box-sizing: border-box; transition: box-shadow 120ms ease, border-color 120ms ease; } /* Elevation variants */ :host([elevation='0']) .surface { box-shadow: var(--lt-elevation-0); } :host([elevation='1']) .surface { box-shadow: var(--lt-elevation-1); } :host([elevation='2']) .surface { box-shadow: var(--lt-elevation-2); } :host([elevation='3']) .surface { box-shadow: var(--lt-elevation-3); } :host([elevation='4']) .surface { box-shadow: var(--lt-elevation-4); } :host([elevation='5']) .surface { box-shadow: var(--lt-elevation-5); } /* Visual appearances */ :host([appearance='filled']) .surface { border: none; } :host([appearance='outlined']) .surface { background: var(--lt-surface-bg, transparent); border: var(--lt-border-width, 1px) solid var(--lt-border-default); } :host([appearance='outlined']:hover) .surface { border-color: var(--lt-border-strong); } `"
9064
+ "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .surface { background: var(--lt-surface-bg, var(--lt-bg-subtle)); border-radius: var(--lt-border-radius); box-sizing: border-box; transition: box-shadow 120ms ease, border-color 120ms ease; } /* Elevation variants */ :host([elevation='0']) .surface { box-shadow: var(--lt-elevation-0); } :host([elevation='1']) .surface { box-shadow: var(--lt-elevation-1); } :host([elevation='2']) .surface { box-shadow: var(--lt-elevation-2); } :host([elevation='3']) .surface { box-shadow: var(--lt-elevation-3); } :host([elevation='4']) .surface { box-shadow: var(--lt-elevation-4); } :host([elevation='5']) .surface { box-shadow: var(--lt-elevation-5); } /* Visual appearances */ :host([appearance='filled']) .surface { border: none; } :host([appearance='outlined']) .surface { background: var(--lt-surface-bg, transparent); border: var(--lt-border-width, 1px) solid var(--lt-border-default); } :host([appearance='outlined']:hover) .surface { border-color: var(--lt-border-strong); } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { .surface { transition: none; } } `"
7635
9065
  }
7636
9066
  ],
7637
9067
  "exports": [
@@ -7763,7 +9193,7 @@
7763
9193
  {
7764
9194
  "kind": "variable",
7765
9195
  "name": "switchStyles",
7766
- "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .switch-wrapper { align-items: center; cursor: pointer; display: inline-flex; gap: var(--lt-spacing-2); } :host([label-position='left']) .switch-wrapper { flex-direction: row-reverse; } :host([disabled]) .switch-wrapper { cursor: not-allowed; opacity: 0.6; } .switch-container { display: inline-flex; position: relative; } input[type='checkbox'] { appearance: none; background: var(--lt-border-default); border-radius: 999px; cursor: pointer; flex-shrink: 0; margin: 0; position: relative; transition: background-color 200ms ease; } input[type='checkbox']:hover:not(:disabled) { background: var(--lt-border-strong); } input[type='checkbox']:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: 2px; } input[type='checkbox']:disabled { cursor: not-allowed; } .thumb { background: white; border-radius: 50%; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); pointer-events: none; position: absolute; transition: left 200ms ease; } .label { color: var(--lt-text-default); user-select: none; } /* Size variants */ :host([size='sm']) input[type='checkbox'] { height: 18px; width: 32px; } :host([size='sm']) .thumb { height: 14px; width: 14px; left: 2px; top: 2px; } :host([size='sm']) input[type='checkbox']:checked ~ .thumb { left: 16px; } :host([size='sm']) .label { font-size: 0.875rem; } :host([size='md']) input[type='checkbox'] { height: 22px; width: 40px; } :host([size='md']) .thumb { height: 18px; width: 18px; left: 2px; top: 2px; } :host([size='md']) input[type='checkbox']:checked ~ .thumb { left: 20px; } :host([size='md']) .label { font-size: 1rem; } :host([size='lg']) input[type='checkbox'] { height: 26px; width: 48px; } :host([size='lg']) .thumb { height: 22px; width: 22px; left: 2px; top: 2px; } :host([size='lg']) input[type='checkbox']:checked ~ .thumb { left: 24px; } :host([size='lg']) .label { font-size: 1.0625rem; } /* Variant styles */ :host([variant='primary']) input[type='checkbox']:checked { background: var(--lt-interactive-primary-bg); } :host([variant='primary']) input[type='checkbox']:checked:hover:not(:disabled) { background: var(--lt-interactive-primary-bg-hover); } :host([variant='secondary']) input[type='checkbox']:checked { background: var(--lt-interactive-secondary-bg); } :host([variant='secondary']) input[type='checkbox']:checked:hover:not(:disabled) { background: var(--lt-interactive-secondary-bg-hover); } :host([variant='success']) input[type='checkbox']:checked { background: var(--lt-interactive-success-bg); } :host([variant='success']) input[type='checkbox']:checked:hover:not(:disabled) { background: var(--lt-interactive-success-bg-hover); } :host([variant='error']) input[type='checkbox']:checked { background: var(--lt-interactive-error-bg); } :host([variant='error']) input[type='checkbox']:checked:hover:not(:disabled) { background: var(--lt-interactive-error-bg-hover); } :host([variant='info']) input[type='checkbox']:checked { background: var(--lt-interactive-info-bg); } :host([variant='info']) input[type='checkbox']:checked:hover:not(:disabled) { background: var(--lt-interactive-info-bg-hover); } `"
9196
+ "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .switch-wrapper { align-items: center; cursor: pointer; display: inline-flex; gap: var(--lt-spacing-2); } :host([label-position='left']) .switch-wrapper { flex-direction: row-reverse; } /* :host(:disabled) — the browser matches this automatically for a form-associated element inside a disabled <fieldset>, no JS required; :host([disabled]) covers the component's own explicit attribute. */ :host([disabled]) .switch-wrapper, :host(:disabled) .switch-wrapper { cursor: not-allowed; opacity: 0.6; } .switch-container { display: inline-flex; position: relative; } input[type='checkbox'] { appearance: none; background: var(--lt-border-default); border-radius: 999px; cursor: pointer; flex-shrink: 0; margin: 0; position: relative; transition: background-color 200ms ease; } input[type='checkbox']:hover:not(:disabled) { background: var(--lt-border-strong); } input[type='checkbox']:focus-visible { outline: 3px solid var(--lt-border-focus); outline-offset: 2px; } input[type='checkbox']:disabled { cursor: not-allowed; } .thumb { background: white; border-radius: 50%; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); pointer-events: none; position: absolute; transition: left 200ms ease; } .label { color: var(--lt-text-default); user-select: none; } /* Size variants */ :host([size='sm']) input[type='checkbox'] { height: 18px; width: 32px; } :host([size='sm']) .thumb { height: 14px; width: 14px; left: 2px; top: 2px; } :host([size='sm']) input[type='checkbox']:checked ~ .thumb { left: 16px; } :host([size='sm']) .label { font-size: 0.875rem; } :host([size='md']) input[type='checkbox'] { height: 22px; width: 40px; } :host([size='md']) .thumb { height: 18px; width: 18px; left: 2px; top: 2px; } :host([size='md']) input[type='checkbox']:checked ~ .thumb { left: 20px; } :host([size='md']) .label { font-size: 1rem; } :host([size='lg']) input[type='checkbox'] { height: 26px; width: 48px; } :host([size='lg']) .thumb { height: 22px; width: 22px; left: 2px; top: 2px; } :host([size='lg']) input[type='checkbox']:checked ~ .thumb { left: 24px; } :host([size='lg']) .label { font-size: 1.0625rem; } /* Variant styles */ :host([variant='primary']) input[type='checkbox']:checked { background: var(--lt-interactive-primary-bg); } :host([variant='primary']) input[type='checkbox']:checked:hover:not(:disabled) { background: var(--lt-interactive-primary-bg-hover); } :host([variant='secondary']) input[type='checkbox']:checked { background: var(--lt-interactive-secondary-bg); } :host([variant='secondary']) input[type='checkbox']:checked:hover:not(:disabled) { background: var(--lt-interactive-secondary-bg-hover); } :host([variant='success']) input[type='checkbox']:checked { background: var(--lt-interactive-success-bg); } :host([variant='success']) input[type='checkbox']:checked:hover:not(:disabled) { background: var(--lt-interactive-success-bg-hover); } :host([variant='error']) input[type='checkbox']:checked { background: var(--lt-interactive-error-bg); } :host([variant='error']) input[type='checkbox']:checked:hover:not(:disabled) { background: var(--lt-interactive-error-bg-hover); } :host([variant='info']) input[type='checkbox']:checked { background: var(--lt-interactive-info-bg); } :host([variant='info']) input[type='checkbox']:checked:hover:not(:disabled) { background: var(--lt-interactive-info-bg-hover); } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { input[type='checkbox'], .thumb { transition: none; } } /* ── Forced colors (Windows High Contrast) ───────────────────────────────── Under forced-colors, every author background-color here (the unchecked track's neutral fill, every variant's checked fill, and the thumb's plain white) is flattened to Canvas — the track has no border of its own to fall back on, and the thumb disappears into it, leaving neither track nor thumb visible at all. System color keywords are exempt from that flattening; Highlight/HighlightText is the canonical OS \"selected state\" pairing, unaffected by which variant was selected (forced-colors overrides that anyway). !important matches every variant's own :checked rule in specificity — standard for a forced-colors override, whose entire point is overriding the page's own author styling. ─────────────────────────────── */ @media (forced-colors: active) { input[type='checkbox'] { border: 1px solid ButtonText; } input[type='checkbox']:checked { background: Highlight !important; border-color: Highlight !important; } .thumb { background: ButtonText; } input[type='checkbox']:checked ~ .thumb { background: HighlightText; } } `"
7767
9197
  }
7768
9198
  ],
7769
9199
  "exports": [
@@ -7809,6 +9239,18 @@
7809
9239
  },
7810
9240
  "privacy": "private"
7811
9241
  },
9242
+ {
9243
+ "kind": "field",
9244
+ "name": "_default",
9245
+ "privacy": "private",
9246
+ "default": "new FormDefaultController(this, () => this.checked)"
9247
+ },
9248
+ {
9249
+ "kind": "field",
9250
+ "name": "_fieldsetDisabled",
9251
+ "privacy": "private",
9252
+ "default": "new FormDisabledController(this)"
9253
+ },
7812
9254
  {
7813
9255
  "kind": "field",
7814
9256
  "name": "variant",
@@ -7834,7 +9276,7 @@
7834
9276
  "text": "boolean"
7835
9277
  },
7836
9278
  "default": "false",
7837
- "description": "Whether the switch is checked (on)."
9279
+ "description": "Whether the switch is checked (on). Not reflected as an attribute — a native checkbox's `checked` _content_\nattribute stays fixed at the markup default and never tracks interaction; reflecting it live meant\n`formResetCallback` could no longer tell what the original default was. Read the property, or the `change`\nevent's `detail.checked`, instead of `[checked]`/`hasAttribute('checked')`."
7838
9280
  },
7839
9281
  {
7840
9282
  "kind": "field",
@@ -7890,6 +9332,24 @@
7890
9332
  "default": "'on'",
7891
9333
  "description": "Value attribute for form submission."
7892
9334
  },
9335
+ {
9336
+ "kind": "field",
9337
+ "name": "labels",
9338
+ "type": {
9339
+ "text": "Partial<SwitchLabels>"
9340
+ },
9341
+ "default": "{}",
9342
+ "description": "Overridable UI text (the required-field validation message), for i18n. English defaults — override only the keys you need."
9343
+ },
9344
+ {
9345
+ "kind": "field",
9346
+ "name": "_labels",
9347
+ "type": {
9348
+ "text": "SwitchLabels"
9349
+ },
9350
+ "privacy": "private",
9351
+ "readonly": true
9352
+ },
7893
9353
  {
7894
9354
  "kind": "method",
7895
9355
  "name": "updated",
@@ -7906,6 +9366,28 @@
7906
9366
  "kind": "method",
7907
9367
  "name": "formResetCallback"
7908
9368
  },
9369
+ {
9370
+ "kind": "method",
9371
+ "name": "formDisabledCallback",
9372
+ "parameters": [
9373
+ {
9374
+ "name": "disabled",
9375
+ "type": {
9376
+ "text": "boolean"
9377
+ }
9378
+ }
9379
+ ]
9380
+ },
9381
+ {
9382
+ "kind": "field",
9383
+ "name": "_isDisabled",
9384
+ "type": {
9385
+ "text": "boolean"
9386
+ },
9387
+ "privacy": "private",
9388
+ "description": "`this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`).",
9389
+ "readonly": true
9390
+ },
7909
9391
  {
7910
9392
  "kind": "method",
7911
9393
  "name": "checkValidity"
@@ -8082,6 +9564,20 @@
8082
9564
  "privacy": "private",
8083
9565
  "description": "Reference to all slotted panel elements."
8084
9566
  },
9567
+ {
9568
+ "kind": "field",
9569
+ "name": "_uid",
9570
+ "privacy": "private",
9571
+ "readonly": true,
9572
+ "default": "`lt-tab-group-${groupCount++}`"
9573
+ },
9574
+ {
9575
+ "kind": "field",
9576
+ "name": "_tabObserver",
9577
+ "privacy": "private",
9578
+ "readonly": true,
9579
+ "default": "new MutationObserver(() => this.updateTabs())"
9580
+ },
8085
9581
  {
8086
9582
  "kind": "method",
8087
9583
  "name": "firstUpdated",
@@ -8091,13 +9587,27 @@
8091
9587
  "kind": "method",
8092
9588
  "name": "updateTabs",
8093
9589
  "privacy": "private",
8094
- "description": "Updates all tabs with the correct active state and size."
9590
+ "description": "Updates all tabs with the correct active/roving-tabindex state, size, and ARIA wiring."
8095
9591
  },
8096
9592
  {
8097
9593
  "kind": "method",
8098
9594
  "name": "updatePanels",
8099
9595
  "privacy": "private",
8100
- "description": "Updates panel visibility based on selected value."
9596
+ "description": "Updates panel visibility and ARIA wiring based on selected value."
9597
+ },
9598
+ {
9599
+ "kind": "method",
9600
+ "name": "_select",
9601
+ "privacy": "private",
9602
+ "parameters": [
9603
+ {
9604
+ "name": "tab",
9605
+ "type": {
9606
+ "text": "Tab"
9607
+ }
9608
+ }
9609
+ ],
9610
+ "description": "Selects a tab (used by both the click and keyboard-navigation handlers below)."
8101
9611
  },
8102
9612
  {
8103
9613
  "kind": "field",
@@ -8105,6 +9615,12 @@
8105
9615
  "privacy": "private",
8106
9616
  "description": "Handles click events from tabs."
8107
9617
  },
9618
+ {
9619
+ "kind": "field",
9620
+ "name": "handleTabKeydown",
9621
+ "privacy": "private",
9622
+ "description": "ArrowLeft/Right move the roving tab stop (and, per the automatic-activation model, select the tab); Home/End\njump to the first/last enabled tab. Disabled tabs are skipped entirely, matching the radiogroup/listbox\npatterns elsewhere in the DS."
9623
+ },
8108
9624
  {
8109
9625
  "kind": "method",
8110
9626
  "name": "handleSlotChange",
@@ -8132,11 +9648,11 @@
8132
9648
  ],
8133
9649
  "events": [
8134
9650
  {
9651
+ "name": "change",
8135
9652
  "type": {
8136
9653
  "text": "CustomEvent<{value: string}>"
8137
9654
  },
8138
- "description": "Dispatched when a tab is selected",
8139
- "name": "change"
9655
+ "description": "Dispatched when a tab is selected"
8140
9656
  }
8141
9657
  ],
8142
9658
  "superclass": {
@@ -8280,7 +9796,7 @@
8280
9796
  {
8281
9797
  "kind": "variable",
8282
9798
  "name": "tabStyles",
8283
- "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .tab { align-items: center; background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--lt-text-subtle); cursor: pointer; display: flex; font-family: inherit; font-size: 0.9375rem; font-weight: 600; gap: var(--lt-spacing-2); outline: none; padding: var(--lt-spacing-3) var(--lt-spacing-4); transition: color 150ms ease, border-color 150ms ease; user-select: none; white-space: nowrap; } :host(:not([disabled])):hover .tab { color: var(--lt-text-default); } :host(:focus-visible) .tab { color: var(--lt-text-primary); outline: 2px solid var(--lt-border-focus); outline-offset: 2px; } :host([active]) .tab { border-color: var(--lt-border-primary-strong); color: var(--lt-text-primary); } :host([disabled]) .tab { color: var(--lt-color-neutral-300); cursor: not-allowed; opacity: 0.5; } .icon { font-size: 1.125rem; } /* Size variants */ :host([size='sm']) .tab { font-size: 0.875rem; padding: var(--lt-spacing-2) var(--lt-spacing-3); } :host([size='sm']) .icon { font-size: 1rem; } :host([size='lg']) .tab { font-size: 1rem; padding: var(--lt-spacing-4) var(--lt-spacing-5); } :host([size='lg']) .icon { font-size: 1.25rem; } /* Pills variant (applied by parent tab-group) */ :host([data-variant='pills']) .tab { border-bottom: none; border-radius: var(--lt-border-radius); transition: color 150ms ease, background-color 150ms ease, box-shadow 150ms ease; } :host([data-variant='pills'][active]) .tab { background: var(--lt-bg-default); box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1); color: var(--lt-text-primary); } `"
9799
+ "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); } .tab { align-items: center; background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--lt-text-subtle); cursor: pointer; display: flex; font-family: inherit; font-size: 0.9375rem; font-weight: 600; gap: var(--lt-spacing-2); outline: none; padding: var(--lt-spacing-3) var(--lt-spacing-4); transition: color 150ms ease, border-color 150ms ease; user-select: none; white-space: nowrap; } :host(:not([disabled])):hover .tab { color: var(--lt-text-default); } :host(:focus-visible) .tab { color: var(--lt-text-primary); outline: 2px solid var(--lt-border-focus); outline-offset: 2px; } :host([active]) .tab { border-color: var(--lt-border-primary-strong); color: var(--lt-text-primary); } :host([disabled]) .tab { color: var(--lt-text-disabled); cursor: not-allowed; opacity: 0.5; } .icon { font-size: 1.125rem; } /* Size variants */ :host([size='sm']) .tab { font-size: 0.875rem; padding: var(--lt-spacing-2) var(--lt-spacing-3); } :host([size='sm']) .icon { font-size: 1rem; } :host([size='lg']) .tab { font-size: 1rem; padding: var(--lt-spacing-4) var(--lt-spacing-5); } :host([size='lg']) .icon { font-size: 1.25rem; } /* Pills variant (applied by parent tab-group) */ :host([data-variant='pills']) .tab { border-bottom: none; border-radius: var(--lt-border-radius); transition: color 150ms ease, background-color 150ms ease, box-shadow 150ms ease; } :host([data-variant='pills'][active]) .tab { background: var(--lt-bg-default); box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1); color: var(--lt-text-primary); } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { /* :host([data-variant='pills']) .tab must be listed explicitly, not just .tab — it outranks a bare .tab in specificity (an extra :host() attribute selector), so it would otherwise keep its own transition. */ .tab, :host([data-variant='pills']) .tab { transition: none; } } `"
8284
9800
  }
8285
9801
  ],
8286
9802
  "exports": [
@@ -8382,11 +9898,6 @@
8382
9898
  }
8383
9899
  ]
8384
9900
  },
8385
- {
8386
- "kind": "field",
8387
- "name": "_handleHostClick",
8388
- "privacy": "private"
8389
- },
8390
9901
  {
8391
9902
  "kind": "field",
8392
9903
  "name": "_handleHostKeydown",
@@ -8494,7 +10005,7 @@
8494
10005
  {
8495
10006
  "kind": "variable",
8496
10007
  "name": "tableStyles",
8497
- "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); overflow: hidden; width: 100%; } .table-container { overflow-x: auto; width: 100%; } :host([responsive-mode='scroll']) .table-container { -webkit-overflow-scrolling: touch; } table { border-collapse: collapse; width: 100%; } /* Header */ thead { background: var(--lt-bg-surface); border-bottom: 2px solid var(--lt-border-default); } th { color: var(--lt-text-default); font-weight: 600; text-align: left; white-space: nowrap; } th[data-align='center'] { text-align: center; } th[data-align='right'] { text-align: right; } /* Sortable headers */ th.sortable { cursor: pointer; user-select: none; transition: background-color 120ms ease; } th.sortable:hover { background: var(--lt-bg-overlay); } th.sortable .header-content { align-items: center; display: flex; gap: var(--lt-spacing-2); } th[data-align='center'] .header-content { justify-content: center; } th[data-align='right'] .header-content { justify-content: flex-end; } .sort-icon { color: var(--lt-text-muted); display: inline-flex; flex-shrink: 0; font-size: 0.875rem; opacity: 0; transition: opacity 120ms ease; } th.sortable:hover .sort-icon, th.sorted .sort-icon { opacity: 1; } th.sorted .sort-icon { color: var(--lt-interactive-primary-bg); } /* Body */ tbody tr { border-bottom: 1px solid var(--lt-border-default); transition: background-color 120ms ease; } tbody tr:last-child { border-bottom: none; } :host([hoverable]) tbody tr:hover { background: var(--lt-bg-surface); } :host([striped]) tbody tr:nth-child(even) { background: var(--lt-bg-surface); } :host([striped][hoverable]) tbody tr:nth-child(even):hover { background: var(--lt-bg-overlay); } td { color: var(--lt-text-default); } td[data-align='center'] { text-align: center; } td[data-align='right'] { text-align: right; } /* Density variants */ :host([density='compact']) th, :host([density='compact']) td { padding: var(--lt-spacing-2) var(--lt-spacing-3); } :host([density='normal']) th, :host([density='normal']) td { padding: var(--lt-spacing-3) var(--lt-spacing-4); } :host([density='comfortable']) th, :host([density='comfortable']) td { padding: var(--lt-spacing-4) var(--lt-spacing-5); } /* Sticky columns */ th.sticky { background: var(--lt-bg-surface); box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05); left: 0; position: sticky; z-index: 2; } td.sticky { background: var(--lt-bg-default); box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05); left: 0; position: sticky; z-index: 1; } :host([striped]) tbody tr:nth-child(even) td.sticky { background: var(--lt-bg-surface); } :host([hoverable]) tbody tr:hover td.sticky { background: var(--lt-bg-surface); } :host([striped][hoverable]) tbody tr:nth-child(even):hover td.sticky { background: var(--lt-bg-overlay); } /* Border styling */ :host([bordered]) table { border: var(--lt-border-width, 1px) solid var(--lt-border-default); } :host([bordered]) th, :host([bordered]) td { border-right: 1px solid var(--lt-border-default); } :host([bordered]) th:last-child, :host([bordered]) td:last-child { border-right: none; } /* Empty state */ .empty-state { color: var(--lt-text-subtle); padding: var(--lt-spacing-8); text-align: center; } /* Loading state */ .loading-overlay { align-items: center; background: rgba(255, 255, 255, 0.8); display: flex; height: 100%; justify-content: center; left: 0; position: absolute; top: 0; width: 100%; z-index: 10; } /* Stack mode for mobile */ @media (max-width: 768px) { :host([responsive-mode='stack']) .table-container { overflow-x: visible; } :host([responsive-mode='stack']) table, :host([responsive-mode='stack']) thead, :host([responsive-mode='stack']) tbody, :host([responsive-mode='stack']) th, :host([responsive-mode='stack']) td, :host([responsive-mode='stack']) tr { display: block; } :host([responsive-mode='stack']) thead { display: none; } :host([responsive-mode='stack']) tr { background: var(--lt-bg-subtle); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); margin-bottom: var(--lt-spacing-3); padding: var(--lt-spacing-4); } :host([responsive-mode='stack']) td { border: none; display: grid; gap: var(--lt-spacing-2); grid-template-columns: 120px 1fr; padding: var(--lt-spacing-2) 0; text-align: left; } :host([responsive-mode='stack']) td::before { content: attr(data-label); color: var(--lt-text-default); font-weight: 600; } :host([responsive-mode='stack']) td:last-child { padding-bottom: 0; } } @media (max-width: 768px) { .hide-on-mobile { display: none; } } th.sortable:focus-visible { outline: 2px solid var(--lt-interactive-primary-bg); outline-offset: -2px; } `"
10008
+ "default": "css` :host { display: block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); overflow: hidden; width: 100%; } .table-container { /* The loading overlay is absolutely positioned, so it needs this as its containing block. */ position: relative; overflow-x: auto; width: 100%; } :host([responsive-mode='scroll']) .table-container { -webkit-overflow-scrolling: touch; } table { border-collapse: collapse; width: 100%; } /* Header */ thead { background: var(--lt-bg-surface); border-bottom: 2px solid var(--lt-border-default); } th { color: var(--lt-text-default); font-weight: 600; text-align: start; white-space: nowrap; } th[data-align='center'] { text-align: center; } th[data-align='end'] { text-align: end; } /* Sortable headers */ th.sortable { cursor: pointer; padding: 0; user-select: none; } th.sortable:hover { background: var(--lt-bg-overlay); } /* The button (not the th) carries the density padding, so it — not just a slice of it — is the click target. */ th.sortable .header-content { align-items: center; background: none; border: none; color: inherit; cursor: pointer; display: flex; font: inherit; gap: var(--lt-spacing-2); transition: background-color 120ms ease; width: 100%; } th[data-align='center'] .header-content { justify-content: center; } th[data-align='end'] .header-content { justify-content: flex-end; } .sort-icon { color: var(--lt-text-muted); display: inline-flex; flex-shrink: 0; font-size: 0.875rem; opacity: 0; transition: opacity 120ms ease; } th.sortable:hover .sort-icon, th.sorted .sort-icon { opacity: 1; } th.sorted .sort-icon { color: var(--lt-interactive-primary-bg); } /* Body */ tbody tr { border-bottom: 1px solid var(--lt-border-default); transition: background-color 120ms ease; } tbody tr:last-child { border-bottom: none; } :host([hoverable]) tbody tr:hover { background: var(--lt-bg-surface); } :host([striped]) tbody tr:nth-child(even) { background: var(--lt-bg-surface); } :host([striped][hoverable]) tbody tr:nth-child(even):hover { background: var(--lt-bg-overlay); } td { color: var(--lt-text-default); } td[data-align='center'] { text-align: center; } td[data-align='end'] { text-align: end; } /* Density variants */ :host([density='compact']) th, :host([density='compact']) td { padding: var(--lt-spacing-2) var(--lt-spacing-3); } :host([density='normal']) th, :host([density='normal']) td { padding: var(--lt-spacing-3) var(--lt-spacing-4); } :host([density='comfortable']) th, :host([density='comfortable']) td { padding: var(--lt-spacing-4) var(--lt-spacing-5); } /* A sortable th's own padding moves onto its button (below), so the whole visible cell — not just the area inside the th's padding — is the click target. Matches the density rules above in specificity and comes after them in source order, so it wins the cascade regardless of selector order elsewhere in this file. */ :host th.sortable { padding: 0; } :host([density='compact']) th.sortable .header-content { padding: var(--lt-spacing-2) var(--lt-spacing-3); } :host([density='normal']) th.sortable .header-content { padding: var(--lt-spacing-3) var(--lt-spacing-4); } :host([density='comfortable']) th.sortable .header-content { padding: var(--lt-spacing-4) var(--lt-spacing-5); } /* Sticky columns */ th.sticky { background: var(--lt-bg-surface); box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05); inset-inline-start: 0; position: sticky; z-index: 2; } td.sticky { background: var(--lt-bg-default); box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05); inset-inline-start: 0; position: sticky; z-index: 1; } :host([striped]) tbody tr:nth-child(even) td.sticky { background: var(--lt-bg-surface); } :host([hoverable]) tbody tr:hover td.sticky { background: var(--lt-bg-surface); } :host([striped][hoverable]) tbody tr:nth-child(even):hover td.sticky { background: var(--lt-bg-overlay); } /* Border styling */ :host([bordered]) table { border: var(--lt-border-width, 1px) solid var(--lt-border-default); } :host([bordered]) th, :host([bordered]) td { border-inline-end: 1px solid var(--lt-border-default); } :host([bordered]) th:last-child, :host([bordered]) td:last-child { border-inline-end: none; } /* Empty state */ .empty-state { color: var(--lt-text-subtle); padding: var(--lt-spacing-8); text-align: center; } /* Loading state */ .loading-overlay { align-items: center; background: color-mix(in srgb, var(--lt-bg-default) 80%, transparent); display: flex; height: 100%; justify-content: center; inset-inline-start: 0; position: absolute; top: 0; width: 100%; z-index: 10; } /* Stack mode for mobile */ @media (max-width: 768px) { :host([responsive-mode='stack']) .table-container { overflow-x: visible; } :host([responsive-mode='stack']) table, :host([responsive-mode='stack']) thead, :host([responsive-mode='stack']) tbody, :host([responsive-mode='stack']) th, :host([responsive-mode='stack']) td, :host([responsive-mode='stack']) tr { display: block; } :host([responsive-mode='stack']) thead { display: none; } :host([responsive-mode='stack']) tr { background: var(--lt-bg-subtle); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); margin-bottom: var(--lt-spacing-3); padding: var(--lt-spacing-4); } :host([responsive-mode='stack']) td { border: none; display: grid; gap: var(--lt-spacing-2); grid-template-columns: 120px 1fr; padding: var(--lt-spacing-2) 0; text-align: start; } :host([responsive-mode='stack']) td::before { content: attr(data-label); color: var(--lt-text-default); font-weight: 600; } :host([responsive-mode='stack']) td:last-child { padding-bottom: 0; } } @media (max-width: 768px) { .hide-on-mobile { display: none; } } th.sortable .header-content:focus-visible { outline: 2px solid var(--lt-interactive-primary-bg); outline-offset: -2px; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { th.sortable .header-content, .sort-icon, tbody tr { transition: none; } } `"
8498
10009
  }
8499
10010
  ],
8500
10011
  "exports": [
@@ -8604,6 +10115,15 @@
8604
10115
  "default": "'No data available'",
8605
10116
  "description": "Message to display when there is no data."
8606
10117
  },
10118
+ {
10119
+ "kind": "field",
10120
+ "name": "label",
10121
+ "type": {
10122
+ "text": "string"
10123
+ },
10124
+ "default": "''",
10125
+ "description": "Accessible name for the table. Required when a page has more than one table, since column labels alone\ndon't tell assistive tech which table it's in."
10126
+ },
8607
10127
  {
8608
10128
  "kind": "field",
8609
10129
  "name": "rowKey",
@@ -8772,7 +10292,7 @@
8772
10292
  ],
8773
10293
  "events": [
8774
10294
  {
8775
- "name": "sort-change",
10295
+ "name": "sortchange",
8776
10296
  "type": {
8777
10297
  "text": "CustomEvent"
8778
10298
  },
@@ -8875,7 +10395,7 @@
8875
10395
  "text": "TextTag | ''"
8876
10396
  },
8877
10397
  "default": "''",
8878
- "description": "HTML tag to render. Defaults to the semantic tag for the chosen variant."
10398
+ "description": "HTML tag to render. Defaults to the semantic tag for the chosen variant; anything outside `TextTag` is ignored."
8879
10399
  },
8880
10400
  {
8881
10401
  "kind": "method",
@@ -8955,7 +10475,7 @@
8955
10475
  {
8956
10476
  "kind": "variable",
8957
10477
  "name": "textfieldStyles",
8958
- "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); width: 100%; } .wrapper { display: flex; flex-direction: column; gap: var(--lt-spacing-1); width: 100%; } label { color: var(--lt-text-subtle); } .input-container { position: relative; width: 100%; display: flex; align-items: center; gap: var(--lt-spacing-2); } .icon-start, .icon-end { color: var(--lt-text-muted); flex-shrink: 0; position: absolute; pointer-events: none; } .icon-start { left: var(--lt-spacing-3); } .icon-end { right: var(--lt-spacing-3); } .password-toggle { pointer-events: auto; cursor: pointer; transition: color 120ms ease; } .password-toggle:hover { color: var(--lt-text-default); } .variant-icon { pointer-events: none; } :host([variant='success']) .variant-icon { color: var(--lt-interactive-success-bg); } :host([variant='warning']) .variant-icon { color: var(--lt-interactive-warning-bg); } :host([variant='error']) .variant-icon, :host([data-invalid]) .variant-icon { color: var(--lt-interactive-error-bg); } input, textarea { background: var(--lt-bg-subtle); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); box-sizing: border-box; color: var(--lt-text-default); font-family: inherit; font-weight: 400; transition: border-color 120ms ease, box-shadow 120ms ease; width: 100%; } textarea { min-height: 80px; padding-block: var(--lt-spacing-3); resize: vertical; } input::placeholder, textarea::placeholder { color: var(--lt-text-muted); } input:hover:not(:disabled), textarea:hover:not(:disabled) { border-color: var(--lt-border-strong); } input:focus, textarea:focus { border-color: var(--lt-interactive-primary-bg); box-shadow: 0 0 0 3px var(--lt-bg-primary-subtle); outline: none; } input:disabled, textarea:disabled { background: var(--lt-bg-surface); color: var(--lt-text-muted); cursor: not-allowed; } /* sizes */ :host([size='sm']) input, :host([size='sm']) textarea { font-size: 0.875rem; height: 32px; padding-inline: var(--lt-spacing-3); } :host([size='sm']) input.has-start-icon, :host([size='sm']) textarea.has-start-icon { padding-left: calc(var(--lt-spacing-3) + 20px + var(--lt-spacing-2)); } :host([size='sm']) input.has-end-icon, :host([size='sm']) textarea.has-end-icon { padding-right: calc(var(--lt-spacing-3) + 20px + var(--lt-spacing-2)); } :host([size='md']) input, :host([size='md']) textarea { font-size: 1rem; height: 40px; padding-inline: var(--lt-spacing-4); } :host([size='md']) input.has-start-icon, :host([size='md']) textarea.has-start-icon { padding-left: calc(var(--lt-spacing-4) + 20px + var(--lt-spacing-2)); } :host([size='md']) input.has-end-icon, :host([size='md']) textarea.has-end-icon { padding-right: calc(var(--lt-spacing-4) + 20px + var(--lt-spacing-2)); } :host([size='lg']) input, :host([size='lg']) textarea { font-size: 1.0625rem; height: 48px; padding-inline: var(--lt-spacing-5); } :host([size='lg']) input.has-start-icon, :host([size='lg']) textarea.has-start-icon { padding-left: calc(var(--lt-spacing-5) + 24px + var(--lt-spacing-2)); } :host([size='lg']) input.has-end-icon, :host([size='lg']) textarea.has-end-icon { padding-right: calc(var(--lt-spacing-5) + 24px + var(--lt-spacing-2)); } :host([size='lg']) .icon-start, :host([size='lg']) .icon-end { width: 24px; height: 24px; } /* variants */ :host([variant='success']) input, :host([variant='success']) textarea { border-color: var(--lt-border-success-strong); } :host([variant='success']) input:focus, :host([variant='success']) textarea:focus { border-color: var(--lt-interactive-success-bg-hover); box-shadow: 0 0 0 3px var(--lt-bg-success-subtle); } :host([variant='warning']) input, :host([variant='warning']) textarea { border-color: var(--lt-border-warning-strong); } :host([variant='warning']) input:focus, :host([variant='warning']) textarea:focus { border-color: var(--lt-interactive-warning-bg-hover); box-shadow: 0 0 0 3px var(--lt-bg-warning-subtle); } :host([variant='error']) input, :host([variant='error']) textarea, :host([data-invalid]) input, :host([data-invalid]) textarea { border-color: var(--lt-border-error-strong); } :host([variant='error']) input:focus, :host([variant='error']) textarea:focus, :host([data-invalid]) input:focus, :host([data-invalid]) textarea:focus { border-color: var(--lt-interactive-error-bg-hover); box-shadow: 0 0 0 3px var(--lt-bg-error-subtle); } .helper-text { color: var(--lt-text-subtle); } .helper-text::part(base) { font-weight: 200; } :host([variant='success']) .helper-text { color: var(--lt-text-success); } :host([variant='warning']) .helper-text { color: var(--lt-text-warning); } :host([variant='error']) .helper-text, :host([data-invalid]) .helper-text { color: var(--lt-text-error); } .required-indicator { color: var(--lt-color-error-500); } :host([uppercase]) label lt-text::part(base) { font-variant-caps: small-caps; letter-spacing: 0.05rem; text-transform: lowercase; } `"
10478
+ "default": "css` :host { display: inline-block; font-family: var(--lt-typography-fontFamilyPrimary, 'Hanken Grotesk', sans-serif); width: 100%; } .wrapper { display: flex; flex-direction: column; gap: var(--lt-spacing-1); width: 100%; } label { color: var(--lt-text-subtle); } .input-container { position: relative; width: 100%; display: flex; align-items: center; gap: var(--lt-spacing-2); } .icon-start, .icon-end { color: var(--lt-text-muted); flex-shrink: 0; position: absolute; pointer-events: none; } .icon-start { inset-inline-start: var(--lt-spacing-3); } .icon-end { inset-inline-end: var(--lt-spacing-3); } /* Unlike .variant-icon (a decorative lt-icon), the password toggle is a real <button> — reset the native chrome so it reads as an inline icon, and re-declare align-items since it's no longer a plain absolutely- positioned element inheriting the .icon-start/.icon-end flex-adjacent layout by accident. */ .password-toggle { align-items: center; background: none; border: none; cursor: pointer; display: inline-flex; font: inherit; padding: 0; pointer-events: auto; transition: color 120ms ease; } .password-toggle:hover { color: var(--lt-text-default); } .password-toggle:disabled { cursor: not-allowed; opacity: 0.6; } .password-toggle:focus-visible { outline: 2px solid var(--lt-border-focus); outline-offset: 2px; } .variant-icon { pointer-events: none; } :host([variant='success']) .variant-icon { color: var(--lt-interactive-success-bg); } :host([variant='warning']) .variant-icon { color: var(--lt-interactive-warning-bg); } :host([variant='error']) .variant-icon, :host([data-invalid]) .variant-icon { color: var(--lt-interactive-error-bg); } input, textarea { background: var(--lt-bg-subtle); border-radius: var(--lt-border-radius); border: var(--lt-border-width, 1px) solid var(--lt-border-default); box-sizing: border-box; color: var(--lt-text-default); font-family: inherit; font-weight: 400; transition: border-color 120ms ease, box-shadow 120ms ease; width: 100%; } textarea { min-height: 80px; padding-block: var(--lt-spacing-3); resize: vertical; } input::placeholder, textarea::placeholder { color: var(--lt-text-muted); } input:hover:not(:disabled), textarea:hover:not(:disabled) { border-color: var(--lt-border-strong); } input:focus, textarea:focus { border-color: var(--lt-interactive-primary-bg); box-shadow: 0 0 0 3px var(--lt-bg-primary-subtle); outline: none; } input:disabled, textarea:disabled { background: var(--lt-bg-surface); color: var(--lt-text-muted); cursor: not-allowed; } /* sizes */ :host([size='sm']) input, :host([size='sm']) textarea { font-size: 0.875rem; height: 32px; padding-inline: var(--lt-spacing-3); } :host([size='sm']) input.has-start-icon, :host([size='sm']) textarea.has-start-icon { padding-inline-start: calc(var(--lt-spacing-3) + 20px + var(--lt-spacing-2)); } :host([size='sm']) input.has-end-icon, :host([size='sm']) textarea.has-end-icon { padding-inline-end: calc(var(--lt-spacing-3) + 20px + var(--lt-spacing-2)); } :host([size='md']) input, :host([size='md']) textarea { font-size: 1rem; height: 40px; padding-inline: var(--lt-spacing-4); } :host([size='md']) input.has-start-icon, :host([size='md']) textarea.has-start-icon { padding-inline-start: calc(var(--lt-spacing-4) + 20px + var(--lt-spacing-2)); } :host([size='md']) input.has-end-icon, :host([size='md']) textarea.has-end-icon { padding-inline-end: calc(var(--lt-spacing-4) + 20px + var(--lt-spacing-2)); } :host([size='lg']) input, :host([size='lg']) textarea { font-size: 1.0625rem; height: 48px; padding-inline: var(--lt-spacing-5); } :host([size='lg']) input.has-start-icon, :host([size='lg']) textarea.has-start-icon { padding-inline-start: calc(var(--lt-spacing-5) + 24px + var(--lt-spacing-2)); } :host([size='lg']) input.has-end-icon, :host([size='lg']) textarea.has-end-icon { padding-inline-end: calc(var(--lt-spacing-5) + 24px + var(--lt-spacing-2)); } :host([size='lg']) .icon-start, :host([size='lg']) .icon-end { width: 24px; height: 24px; } /* variants */ :host([variant='success']) input, :host([variant='success']) textarea { border-color: var(--lt-border-success-strong); } :host([variant='success']) input:focus, :host([variant='success']) textarea:focus { border-color: var(--lt-interactive-success-bg-hover); box-shadow: 0 0 0 3px var(--lt-bg-success-subtle); } :host([variant='warning']) input, :host([variant='warning']) textarea { border-color: var(--lt-border-warning-strong); } :host([variant='warning']) input:focus, :host([variant='warning']) textarea:focus { border-color: var(--lt-interactive-warning-bg-hover); box-shadow: 0 0 0 3px var(--lt-bg-warning-subtle); } :host([variant='error']) input, :host([variant='error']) textarea, :host([data-invalid]) input, :host([data-invalid]) textarea { border-color: var(--lt-border-error-strong); } :host([variant='error']) input:focus, :host([variant='error']) textarea:focus, :host([data-invalid]) input:focus, :host([data-invalid]) textarea:focus { border-color: var(--lt-interactive-error-bg-hover); box-shadow: 0 0 0 3px var(--lt-bg-error-subtle); } .helper-text { color: var(--lt-text-subtle); } .helper-text::part(base) { font-weight: 200; } /* .icon-end disables pointer events so decorative icons never swallow clicks; the clear button is the one real control in that slot, so it opts back in and resets native button chrome. */ .clear-button { align-items: center; background: none; border: 0; border-radius: var(--lt-border-radius, 4px); cursor: pointer; display: flex; padding: 0; pointer-events: auto; } .counter { color: var(--lt-text-subtle); display: block; text-align: end; } :host([variant='success']) .helper-text { color: var(--lt-text-success); } :host([variant='warning']) .helper-text { color: var(--lt-text-warning); } :host([variant='error']) .helper-text, :host([data-invalid]) .helper-text { color: var(--lt-text-error); } .required-indicator { color: var(--lt-text-error); } :host([uppercase]) label lt-text::part(base) { font-variant-caps: small-caps; letter-spacing: 0.05rem; text-transform: lowercase; } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { .password-toggle, input, textarea { transition: none; } } `"
8959
10479
  }
8960
10480
  ],
8961
10481
  "exports": [
@@ -9001,6 +10521,39 @@
9001
10521
  },
9002
10522
  "privacy": "private"
9003
10523
  },
10524
+ {
10525
+ "kind": "field",
10526
+ "name": "_default",
10527
+ "privacy": "private",
10528
+ "default": "new FormDefaultController(this, () => this.value)"
10529
+ },
10530
+ {
10531
+ "kind": "field",
10532
+ "name": "_fieldsetDisabled",
10533
+ "privacy": "private",
10534
+ "default": "new FormDisabledController(this)"
10535
+ },
10536
+ {
10537
+ "kind": "field",
10538
+ "name": "_uid",
10539
+ "privacy": "private",
10540
+ "readonly": true,
10541
+ "default": "`lt-textfield-${textfieldCount++}`"
10542
+ },
10543
+ {
10544
+ "kind": "field",
10545
+ "name": "_inputId",
10546
+ "privacy": "private",
10547
+ "readonly": true,
10548
+ "default": "`${this._uid}-input`"
10549
+ },
10550
+ {
10551
+ "kind": "field",
10552
+ "name": "_helperId",
10553
+ "privacy": "private",
10554
+ "readonly": true,
10555
+ "default": "`${this._uid}-helper`"
10556
+ },
9004
10557
  {
9005
10558
  "kind": "field",
9006
10559
  "name": "variant",
@@ -9035,7 +10588,7 @@
9035
10588
  "text": "string"
9036
10589
  },
9037
10590
  "default": "''",
9038
- "description": "Current value of the input."
10591
+ "description": "Current value of the input. Not reflected as an attribute: for `type=\"password\"` that would put whatever\nthe user types in plain text in the DOM (`outerHTML`, DevTools, session-replay/DOM-mutation recorders) —\nvisible via `getAttribute('value')`/`[value]` regardless of input type. Read the property, or the\n`input`/`change` event's `detail.value`, instead of an attribute selector."
9039
10592
  },
9040
10593
  {
9041
10594
  "kind": "field",
@@ -9145,6 +10698,41 @@
9145
10698
  "default": "false",
9146
10699
  "description": "Renders the label in small caps with wider letter spacing."
9147
10700
  },
10701
+ {
10702
+ "kind": "field",
10703
+ "name": "clearable",
10704
+ "type": {
10705
+ "text": "boolean"
10706
+ },
10707
+ "default": "false",
10708
+ "description": "Shows a clear button while the field has a value. Not shown for password fields, which have their own toggle."
10709
+ },
10710
+ {
10711
+ "kind": "field",
10712
+ "name": "counter",
10713
+ "type": {
10714
+ "text": "boolean"
10715
+ },
10716
+ "default": "false",
10717
+ "description": "Shows the character count as `length / max` below the field. Uses `max` as the limit, which is also enforced natively."
10718
+ },
10719
+ {
10720
+ "kind": "field",
10721
+ "name": "labels",
10722
+ "type": {
10723
+ "text": "Partial<TextfieldLabels>"
10724
+ },
10725
+ "default": "{}"
10726
+ },
10727
+ {
10728
+ "kind": "field",
10729
+ "name": "_labels",
10730
+ "type": {
10731
+ "text": "TextfieldLabels"
10732
+ },
10733
+ "privacy": "private",
10734
+ "readonly": true
10735
+ },
9148
10736
  {
9149
10737
  "kind": "field",
9150
10738
  "name": "isPasswordVisible",
@@ -9207,6 +10795,27 @@
9207
10795
  }
9208
10796
  ]
9209
10797
  },
10798
+ {
10799
+ "kind": "field",
10800
+ "name": "_showClear",
10801
+ "type": {
10802
+ "text": "boolean"
10803
+ },
10804
+ "privacy": "private",
10805
+ "description": "Handles change events from the native input or textarea element.\nUpdates the component's value property and dispatches a custom change event.",
10806
+ "parameters": [
10807
+ {
10808
+ "description": "The native change event",
10809
+ "name": "e"
10810
+ }
10811
+ ],
10812
+ "readonly": true
10813
+ },
10814
+ {
10815
+ "kind": "method",
10816
+ "name": "_clear",
10817
+ "privacy": "private"
10818
+ },
9210
10819
  {
9211
10820
  "kind": "method",
9212
10821
  "name": "handleChange",
@@ -9216,11 +10825,14 @@
9216
10825
  "name": "e",
9217
10826
  "type": {
9218
10827
  "text": "Event"
9219
- },
9220
- "description": "The native change event"
10828
+ }
9221
10829
  }
9222
- ],
9223
- "description": "Handles change events from the native input or textarea element.\nUpdates the component's value property and dispatches a custom change event."
10830
+ ]
10831
+ },
10832
+ {
10833
+ "kind": "field",
10834
+ "name": "_onKeydown",
10835
+ "privacy": "private"
9224
10836
  },
9225
10837
  {
9226
10838
  "kind": "method",
@@ -9228,6 +10840,19 @@
9228
10840
  "privacy": "private",
9229
10841
  "description": "Toggles password visibility for password-type inputs.\nSwitches between showing plain text and masked password."
9230
10842
  },
10843
+ {
10844
+ "kind": "method",
10845
+ "name": "_preventFocusSteal",
10846
+ "privacy": "private",
10847
+ "parameters": [
10848
+ {
10849
+ "name": "e",
10850
+ "type": {
10851
+ "text": "MouseEvent"
10852
+ }
10853
+ }
10854
+ ]
10855
+ },
9231
10856
  {
9232
10857
  "kind": "method",
9233
10858
  "name": "getEndIconName",
@@ -9255,6 +10880,28 @@
9255
10880
  "kind": "method",
9256
10881
  "name": "formResetCallback"
9257
10882
  },
10883
+ {
10884
+ "kind": "method",
10885
+ "name": "formDisabledCallback",
10886
+ "parameters": [
10887
+ {
10888
+ "name": "disabled",
10889
+ "type": {
10890
+ "text": "boolean"
10891
+ }
10892
+ }
10893
+ ]
10894
+ },
10895
+ {
10896
+ "kind": "field",
10897
+ "name": "_isDisabled",
10898
+ "type": {
10899
+ "text": "boolean"
10900
+ },
10901
+ "privacy": "private",
10902
+ "description": "`this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`).",
10903
+ "readonly": true
10904
+ },
9258
10905
  {
9259
10906
  "kind": "method",
9260
10907
  "name": "checkValidity"
@@ -9333,7 +10980,7 @@
9333
10980
  {
9334
10981
  "kind": "variable",
9335
10982
  "name": "tooltipStyles",
9336
- "default": "css` :host { display: inline-block; position: relative; --lt-tooltip-offset: 8px; } .tooltip { background: var(--lt-tooltip-bg, var(--lt-bg-inverse)); border-radius: 4px; color: var(--lt-tooltip-color, var(--lt-text-inverse)); opacity: 0; padding: var(--lt-spacing-1) var(--lt-spacing-2); pointer-events: none; position: absolute; transition: opacity 150ms ease, visibility 150ms ease; visibility: hidden; white-space: nowrap; z-index: 1000; } .arrow { border: 5px solid transparent; height: 0; position: absolute; width: 0; } :host(:hover) .tooltip, :host(:focus-within) .tooltip { opacity: 1; visibility: visible; } :host([disabled]) .tooltip, :host(:not([content])) .tooltip, :host([content='']) .tooltip { display: none; } /* ── Top (default) ──────────────────────────── */ :host(:not([placement])) .tooltip, :host([placement='top']) .tooltip { bottom: calc(100% + var(--lt-tooltip-offset)); left: 50%; transform: translateX(-50%); } :host(:not([placement])) .arrow, :host([placement='top']) .arrow { border-top-color: var(--lt-tooltip-bg, var(--lt-color-neutral-900)); left: 50%; top: 100%; transform: translateX(-50%); } /* ── Bottom ─────────────────────────────────── */ :host([placement='bottom']) .tooltip { left: 50%; top: calc(100% + var(--lt-tooltip-offset)); transform: translateX(-50%); } :host([placement='bottom']) .arrow { border-bottom-color: var(--lt-tooltip-bg, var(--lt-color-neutral-900)); bottom: 100%; left: 50%; transform: translateX(-50%); } /* ── Left ───────────────────────────────────── */ :host([placement='left']) .tooltip { right: calc(100% + var(--lt-tooltip-offset)); top: 50%; transform: translateY(-50%); } :host([placement='left']) .arrow { border-left-color: var(--lt-tooltip-bg, var(--lt-color-neutral-900)); left: 100%; top: 50%; transform: translateY(-50%); } /* ── Right ──────────────────────────────────── */ :host([placement='right']) .tooltip { left: calc(100% + var(--lt-tooltip-offset)); top: 50%; transform: translateY(-50%); } :host([placement='right']) .arrow { border-right-color: var(--lt-tooltip-bg, var(--lt-color-neutral-900)); right: 100%; top: 50%; transform: translateY(-50%); } `"
10983
+ "default": "css` :host { display: inline-block; position: relative; --lt-tooltip-offset: 8px; } /* The bubble is a \"manual\" popover so it renders in the top layer — above an open lt-dialog/lt-sidepanel regardless of z-index, and never clipped by an overflow:hidden ancestor. Its position is set from JS (see _reposition in tooltip.ts), since a top-layer element is positioned against the viewport, not the host. display/overlay need allow-discrete so hidePopover() doesn't cut the exit fade short — same as lt-snackbar. */ .tooltip { background: var(--lt-tooltip-bg, var(--lt-bg-inverse)); border: 0; border-radius: 4px; color: var(--lt-tooltip-color, var(--lt-text-inverse)); inset: auto; margin: 0; opacity: 0; overflow: visible; padding: var(--lt-spacing-1) var(--lt-spacing-2); pointer-events: none; position: fixed; transition: opacity 150ms ease, display 150ms allow-discrete, overlay 150ms allow-discrete; white-space: nowrap; } .tooltip:popover-open { opacity: 1; } /* A newly-shown popover has no earlier rendered frame to transition from — @starting-style supplies one so the fade-in actually animates instead of snapping straight to the open state. */ @starting-style { .tooltip:popover-open { opacity: 0; } } .arrow { border: 5px solid transparent; height: 0; position: absolute; width: 0; } :host([disabled]) .tooltip, :host(:not([content])) .tooltip, :host([content='']) .tooltip { display: none; } /* ── Arrows ─────────────────────────────────────────────────────────────── The bubble's own position is set from JS; each arrow sits on the bubble edge facing the host. Centering is direction-symmetric, so inset-inline-start:50% + translateX(-50%) is correct in both LTR and RTL. Start/end use logical properties, so they flip with the page direction without a custom-property trick. ─────────────────────────── */ /* ── Top (default) ──────────────────────────── */ :host(:not([placement])) .arrow, :host([placement='top']) .arrow { border-top-color: var(--lt-tooltip-bg, var(--lt-color-neutral-900)); inset-inline-start: 50%; top: 100%; transform: translateX(-50%); } /* ── Bottom ─────────────────────────────────── */ :host([placement='bottom']) .arrow { border-bottom-color: var(--lt-tooltip-bg, var(--lt-color-neutral-900)); bottom: 100%; inset-inline-start: 50%; transform: translateX(-50%); } /* ── Start ──────────────────────────────────── */ :host([placement='start']) .arrow { border-inline-start-color: var(--lt-tooltip-bg, var(--lt-color-neutral-900)); inset-inline-start: 100%; top: 50%; transform: translateY(-50%); } /* ── End ────────────────────────────────────── */ :host([placement='end']) .arrow { border-inline-end-color: var(--lt-tooltip-bg, var(--lt-color-neutral-900)); inset-inline-end: 100%; top: 50%; transform: translateY(-50%); } /* ── Reduced motion ─────────────────────────────────────────────────────── */ @media (prefers-reduced-motion: reduce) { .tooltip { transition: none; } } `"
9337
10984
  }
9338
10985
  ],
9339
10986
  "exports": [
@@ -9382,6 +11029,32 @@
9382
11029
  },
9383
11030
  "privacy": "private"
9384
11031
  },
11032
+ {
11033
+ "kind": "field",
11034
+ "name": "_tooltipEl",
11035
+ "type": {
11036
+ "text": "HTMLElement"
11037
+ },
11038
+ "privacy": "private"
11039
+ },
11040
+ {
11041
+ "kind": "field",
11042
+ "name": "_hovered",
11043
+ "type": {
11044
+ "text": "boolean"
11045
+ },
11046
+ "privacy": "private",
11047
+ "default": "false"
11048
+ },
11049
+ {
11050
+ "kind": "field",
11051
+ "name": "_focused",
11052
+ "type": {
11053
+ "text": "boolean"
11054
+ },
11055
+ "privacy": "private",
11056
+ "default": "false"
11057
+ },
9385
11058
  {
9386
11059
  "kind": "field",
9387
11060
  "name": "content",
@@ -9427,11 +11100,79 @@
9427
11100
  "default": "''",
9428
11101
  "description": "Text color override. Accepts a hex value (#ffffff) or a CSS token name (--lt-color-neutral-50)."
9429
11102
  },
11103
+ {
11104
+ "kind": "method",
11105
+ "name": "_describeTrigger",
11106
+ "privacy": "private"
11107
+ },
11108
+ {
11109
+ "kind": "method",
11110
+ "name": "_isShown",
11111
+ "privacy": "private",
11112
+ "return": {
11113
+ "type": {
11114
+ "text": "boolean"
11115
+ }
11116
+ }
11117
+ },
11118
+ {
11119
+ "kind": "method",
11120
+ "name": "_sync",
11121
+ "privacy": "private"
11122
+ },
11123
+ {
11124
+ "kind": "method",
11125
+ "name": "_show",
11126
+ "privacy": "private"
11127
+ },
11128
+ {
11129
+ "kind": "method",
11130
+ "name": "_hide",
11131
+ "privacy": "private"
11132
+ },
11133
+ {
11134
+ "kind": "field",
11135
+ "name": "_reposition",
11136
+ "privacy": "private"
11137
+ },
11138
+ {
11139
+ "kind": "field",
11140
+ "name": "_onPointerEnter",
11141
+ "privacy": "private"
11142
+ },
11143
+ {
11144
+ "kind": "field",
11145
+ "name": "_onPointerLeave",
11146
+ "privacy": "private"
11147
+ },
11148
+ {
11149
+ "kind": "field",
11150
+ "name": "_onFocusIn",
11151
+ "privacy": "private"
11152
+ },
11153
+ {
11154
+ "kind": "field",
11155
+ "name": "_onFocusOut",
11156
+ "privacy": "private"
11157
+ },
9430
11158
  {
9431
11159
  "kind": "method",
9432
11160
  "name": "firstUpdated",
9433
11161
  "privacy": "protected"
9434
11162
  },
11163
+ {
11164
+ "kind": "method",
11165
+ "name": "updated",
11166
+ "privacy": "protected",
11167
+ "parameters": [
11168
+ {
11169
+ "name": "changed",
11170
+ "type": {
11171
+ "text": "PropertyValues<this>"
11172
+ }
11173
+ }
11174
+ ]
11175
+ },
9435
11176
  {
9436
11177
  "kind": "method",
9437
11178
  "name": "render"