@latty-ds/web 0.10.3 → 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 (101) hide show
  1. package/custom-elements.json +1970 -229
  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 +127 -20
  6. package/dist/components/avatar/avatar.d.ts +2 -0
  7. package/dist/components/avatar/index.js +10 -3
  8. package/dist/components/badge/index.js +1 -1
  9. package/dist/components/breadcrumb/breadcrumb.d.ts +4 -0
  10. package/dist/components/breadcrumb/breadcrumb.types.d.ts +5 -0
  11. package/dist/components/breadcrumb/index.js +20 -3
  12. package/dist/components/button/button.d.ts +33 -0
  13. package/dist/components/button/index.js +138 -15
  14. package/dist/components/calendar/calendar.d.ts +15 -7
  15. package/dist/components/calendar/calendar.types.d.ts +17 -1
  16. package/dist/components/calendar/index.js +80 -27
  17. package/dist/components/checkbox/checkbox.d.ts +14 -2
  18. package/dist/components/checkbox/checkbox.types.d.ts +5 -0
  19. package/dist/components/checkbox/index.js +82 -5
  20. package/dist/components/chip/chip.d.ts +4 -1
  21. package/dist/components/chip/chip.types.d.ts +5 -0
  22. package/dist/components/chip/index.js +29 -1
  23. package/dist/components/color-input/color-input.d.ts +11 -2
  24. package/dist/components/color-input/color-input.types.d.ts +5 -0
  25. package/dist/components/color-input/index.js +92 -8
  26. package/dist/components/combobox/combobox.d.ts +18 -2
  27. package/dist/components/combobox/combobox.types.d.ts +7 -0
  28. package/dist/components/combobox/index.js +164 -23
  29. package/dist/components/date-input/date-input.d.ts +22 -7
  30. package/dist/components/date-input/date-input.types.d.ts +7 -0
  31. package/dist/components/date-input/index.js +218 -55
  32. package/dist/components/datepicker/datepicker.d.ts +9 -1
  33. package/dist/components/datepicker/index.js +108 -15
  34. package/dist/components/dialog/dialog.d.ts +39 -19
  35. package/dist/components/dialog/dialog.types.d.ts +5 -0
  36. package/dist/components/dialog/index.js +240 -93
  37. package/dist/components/divider/index.js +2 -2
  38. package/dist/components/dropdown/dropdown-item.d.ts +1 -1
  39. package/dist/components/dropdown/dropdown.d.ts +4 -0
  40. package/dist/components/dropdown/index.js +43 -3
  41. package/dist/components/icon-button/icon-button.d.ts +4 -0
  42. package/dist/components/icon-button/index.js +39 -4
  43. package/dist/components/image/image.d.ts +7 -7
  44. package/dist/components/image/index.js +6 -11
  45. package/dist/components/list/index.js +14 -4
  46. package/dist/components/nav/index.js +37 -17
  47. package/dist/components/nav/nav-item.d.ts +8 -8
  48. package/dist/components/pagination/index.js +57 -16
  49. package/dist/components/pagination/pagination.d.ts +8 -1
  50. package/dist/components/pagination/pagination.types.d.ts +15 -0
  51. package/dist/components/progress/index.js +44 -6
  52. package/dist/components/progress/progress.d.ts +12 -0
  53. package/dist/components/radio/index.js +148 -9
  54. package/dist/components/radio/radio.d.ts +34 -2
  55. package/dist/components/radio/radio.types.d.ts +5 -0
  56. package/dist/components/radio-group/index.js +120 -29
  57. package/dist/components/radio-group/radio-group.d.ts +27 -2
  58. package/dist/components/select/index.js +197 -44
  59. package/dist/components/select/select.d.ts +38 -4
  60. package/dist/components/select/select.types.d.ts +5 -0
  61. package/dist/components/shared/aria-forwarding.d.ts +1 -1
  62. package/dist/components/shared/form-default.d.ts +30 -0
  63. package/dist/components/shared/form-disabled.d.ts +40 -0
  64. package/dist/components/shared/form-field.d.ts +7 -0
  65. package/dist/components/shared/form-validity.d.ts +17 -0
  66. package/dist/components/shared/roving.d.ts +11 -0
  67. package/dist/components/shared/scroll-lock.d.ts +2 -0
  68. package/dist/components/sidepanel/index.js +278 -75
  69. package/dist/components/sidepanel/sidepanel.d.ts +32 -10
  70. package/dist/components/sidepanel/sidepanel.types.d.ts +10 -1
  71. package/dist/components/skeleton/index.js +3 -8
  72. package/dist/components/slider/index.js +307 -75
  73. package/dist/components/slider/slider.d.ts +16 -3
  74. package/dist/components/snackbar/index.js +82 -9
  75. package/dist/components/snackbar/snackbar.d.ts +17 -1
  76. package/dist/components/snackbar/snackbar.types.d.ts +5 -0
  77. package/dist/components/surface/index.js +8 -0
  78. package/dist/components/switch/index.js +101 -5
  79. package/dist/components/switch/switch.d.ts +13 -2
  80. package/dist/components/switch/switch.types.d.ts +5 -0
  81. package/dist/components/tab/index.js +15 -14
  82. package/dist/components/tab/tab.d.ts +0 -1
  83. package/dist/components/tab-group/index.js +102 -30
  84. package/dist/components/tab-group/tab-group.d.ts +17 -2
  85. package/dist/components/table/index.js +105 -61
  86. package/dist/components/table/table.d.ts +8 -2
  87. package/dist/components/table/table.types.d.ts +4 -3
  88. package/dist/components/text/index.js +16 -1
  89. package/dist/components/text/text.d.ts +1 -1
  90. package/dist/components/textfield/index.js +243 -35
  91. package/dist/components/textfield/textfield.d.ts +24 -2
  92. package/dist/components/textfield/textfield.types.d.ts +11 -0
  93. package/dist/components/tooltip/index.js +176 -49
  94. package/dist/components/tooltip/tooltip.d.ts +17 -0
  95. package/dist/components/tooltip/tooltip.types.d.ts +5 -1
  96. package/dist/index.cjs +2467 -692
  97. package/dist/index.js +2478 -699
  98. package/dist/manifest.json +202 -32
  99. package/dist/utils/dev-warn.d.ts +5 -0
  100. package/dist/utils/index.d.ts +1 -0
  101. package/package.json +4 -8
@@ -34,6 +34,13 @@ __decorateClass([
34
34
  property({ reflect: true })
35
35
  ], ThemeableElement.prototype, "theme", 2);
36
36
 
37
+ // src/utils/dev-warn.ts
38
+ var devWarn = (tag, message) => {
39
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
40
+ console.warn(`[${tag}] ${message}`);
41
+ }
42
+ };
43
+
37
44
  // src/components/checkbox/checkbox.ts
38
45
  import { customElement, property as property2, query } from "lit/decorators.js";
39
46
 
@@ -62,7 +69,10 @@ var checkboxStyles = css`
62
69
  flex-direction: row-reverse;
63
70
  }
64
71
 
65
- :host([disabled]) .checkbox-wrapper {
72
+ /* :host(:disabled) — the browser matches this automatically for a form-associated element inside a
73
+ disabled <fieldset>, no JS required; :host([disabled]) covers the component's own explicit attribute. */
74
+ :host([disabled]) .checkbox-wrapper,
75
+ :host(:disabled) .checkbox-wrapper {
66
76
  cursor: not-allowed;
67
77
  opacity: 0.6;
68
78
  }
@@ -195,13 +205,63 @@ var checkboxStyles = css`
195
205
  background: var(--lt-interactive-info-bg-hover);
196
206
  border-color: var(--lt-interactive-info-bg-hover);
197
207
  }
208
+
209
+ /* ── Reduced motion ─────────────────────────────────────────────────────── */
210
+
211
+ @media (prefers-reduced-motion: reduce) {
212
+ input[type='checkbox'] {
213
+ transition: none;
214
+ }
215
+ }
198
216
  `;
199
217
 
218
+ // src/components/shared/form-default.ts
219
+ var FormDefaultController = class {
220
+ constructor(host, get) {
221
+ this._captured = false;
222
+ this._get = get;
223
+ host.addController(this);
224
+ }
225
+ hostConnected() {
226
+ if (this._captured) return;
227
+ this._captured = true;
228
+ this.value = this._get();
229
+ }
230
+ };
231
+
232
+ // src/components/shared/form-disabled.ts
233
+ var FormDisabledController = class {
234
+ constructor(host) {
235
+ this._fieldsetDisabled = false;
236
+ this._host = host;
237
+ host.addController(this);
238
+ }
239
+ // No-op — this controller has no connect-time work of its own (formDisabledCallback drives it instead), but
240
+ // ReactiveController's members are all optional, and a class satisfying an all-optional interface with no
241
+ // members in common is a TS error (TS2559); this gives it one.
242
+ hostConnected() {
243
+ }
244
+ /** Whether an ancestor `<fieldset>` is currently disabled. */
245
+ get fieldsetDisabled() {
246
+ return this._fieldsetDisabled;
247
+ }
248
+ setFieldsetDisabled(disabled) {
249
+ if (this._fieldsetDisabled === disabled) return;
250
+ this._fieldsetDisabled = disabled;
251
+ this._host.requestUpdate();
252
+ }
253
+ };
254
+
200
255
  // src/components/checkbox/checkbox.ts
201
256
  import "@latty-ds/icons";
257
+ var DEFAULT_LABELS = {
258
+ validationMessage: "Please check this box"
259
+ };
202
260
  var Checkbox = class extends ThemeableElement {
203
261
  constructor() {
204
262
  super();
263
+ this._default = new FormDefaultController(this, () => this.checked);
264
+ this._fieldsetDisabled = new FormDisabledController(this);
205
265
  this.variant = "primary";
206
266
  this.size = "md";
207
267
  this.checked = false;
@@ -212,21 +272,32 @@ var Checkbox = class extends ThemeableElement {
212
272
  this.labelPosition = "right";
213
273
  this.name = "";
214
274
  this.value = "on";
275
+ this.labels = {};
215
276
  this._internals = this.attachInternals();
216
277
  }
278
+ get _labels() {
279
+ return { ...DEFAULT_LABELS, ...this.labels };
280
+ }
217
281
  updated(changedProperties) {
218
282
  if (changedProperties.has("indeterminate") && this.input) {
219
283
  this.input.indeterminate = this.indeterminate;
220
284
  }
221
285
  this._internals.setFormValue(this.checked ? this.value : null);
222
286
  if (this.required && !this.checked && this.input) {
223
- this._internals.setValidity({ valueMissing: true }, "Please check this box", this.input);
287
+ this._internals.setValidity({ valueMissing: true }, this._labels.validationMessage, this.input);
224
288
  } else {
225
289
  this._internals.setValidity({});
226
290
  }
227
291
  }
228
292
  formResetCallback() {
229
- this.checked = false;
293
+ this.checked = this._default.value;
294
+ }
295
+ formDisabledCallback(disabled) {
296
+ this._fieldsetDisabled.setFieldsetDisabled(disabled);
297
+ }
298
+ /** `this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`). */
299
+ get _isDisabled() {
300
+ return this.disabled || this._fieldsetDisabled.fieldsetDisabled;
230
301
  }
231
302
  checkValidity() {
232
303
  return this._internals.checkValidity();
@@ -269,6 +340,9 @@ var Checkbox = class extends ThemeableElement {
269
340
  }
270
341
  return html``;
271
342
  }
343
+ firstUpdated() {
344
+ if (!this.label) devWarn("lt-checkbox", "no `label` \u2014 the checkbox has no accessible name");
345
+ }
272
346
  render() {
273
347
  return html`
274
348
  <label class="checkbox-wrapper">
@@ -276,7 +350,7 @@ var Checkbox = class extends ThemeableElement {
276
350
  <input
277
351
  type="checkbox"
278
352
  .checked=${this.checked}
279
- ?disabled=${this.disabled}
353
+ ?disabled=${this._isDisabled}
280
354
  ?required=${this.required}
281
355
  name=${this.name}
282
356
  value=${this.value}
@@ -300,7 +374,7 @@ __decorateClass([
300
374
  property2({ reflect: true })
301
375
  ], Checkbox.prototype, "size", 2);
302
376
  __decorateClass([
303
- property2({ type: Boolean, reflect: true })
377
+ property2({ type: Boolean })
304
378
  ], Checkbox.prototype, "checked", 2);
305
379
  __decorateClass([
306
380
  property2({ type: Boolean, reflect: true })
@@ -323,6 +397,9 @@ __decorateClass([
323
397
  __decorateClass([
324
398
  property2({ reflect: true })
325
399
  ], Checkbox.prototype, "value", 2);
400
+ __decorateClass([
401
+ property2({ type: Object })
402
+ ], Checkbox.prototype, "labels", 2);
326
403
  __decorateClass([
327
404
  query('input[type="checkbox"]')
328
405
  ], Checkbox.prototype, "input", 2);
@@ -1,6 +1,6 @@
1
1
  import { ThemeableElement } from '../../base';
2
2
  import '@latty-ds/icons';
3
- import type { ChipVariant, ChipSize, ChipAppearance } from './chip.types';
3
+ import type { ChipVariant, ChipSize, ChipAppearance, ChipLabels } from './chip.types';
4
4
  /**
5
5
  * Compact label element for tags, filters, and attributes.
6
6
  *
@@ -29,6 +29,9 @@ export declare class Chip extends ThemeableElement {
29
29
  deletable: boolean;
30
30
  /** Background color override. Accepts a hex value (#1a1a2e) or a CSS token name (--lt-color-primary-600). */
31
31
  background: string;
32
+ /** Overridable UI text (the delete button's accessible name), for i18n. English defaults — override only the keys you need. */
33
+ labels: Partial<ChipLabels>;
34
+ private get _labels();
32
35
  private get _deleteIconSize();
33
36
  private _handleDelete;
34
37
  render(): import("lit").TemplateResult<1>;
@@ -1,3 +1,8 @@
1
1
  export type ChipVariant = 'primary' | 'secondary' | 'neutral' | 'success' | 'warning' | 'error' | 'info';
2
2
  export type ChipSize = 'sm' | 'md' | 'lg';
3
3
  export type ChipAppearance = 'filled' | 'outlined';
4
+ /** Overridable UI text, for i18n — English defaults; override only the keys you need. */
5
+ export interface ChipLabels {
6
+ /** Accessible label for the delete/remove button. */
7
+ remove: string;
8
+ }
@@ -82,6 +82,10 @@ var chipStyles = css`
82
82
  display: inline-flex;
83
83
  flex-shrink: 0;
84
84
  justify-content: center;
85
+ /* WCAG 2.5.8: a 24px target. The negative margin gives the extra size back, so the chip layout is unchanged. */
86
+ margin: -6px;
87
+ min-height: 24px;
88
+ min-width: 24px;
85
89
  opacity: 0.6;
86
90
  padding: 0;
87
91
  transition:
@@ -89,6 +93,11 @@ var chipStyles = css`
89
93
  background-color 120ms ease;
90
94
  }
91
95
 
96
+ /* The large chip's icon is 16px rather than 12px, so it needs less negative margin to keep the same layout. */
97
+ :host([size='lg']) .delete {
98
+ margin: -4px;
99
+ }
100
+
92
101
  .delete:hover:not(:disabled) {
93
102
  opacity: 1;
94
103
  }
@@ -210,6 +219,15 @@ var chipStyles = css`
210
219
  border-color: var(--lt-border-info-strong);
211
220
  color: var(--lt-text-info);
212
221
  }
222
+
223
+ /* ── Reduced motion ─────────────────────────────────────────────────────── */
224
+
225
+ @media (prefers-reduced-motion: reduce) {
226
+ span[part='base'],
227
+ .delete {
228
+ transition: none;
229
+ }
230
+ }
213
231
  `;
214
232
 
215
233
  // src/components/chip/chip.ts
@@ -222,6 +240,9 @@ var dispatch = (host, name, detail, init) => host.dispatchEvent(new CustomEvent(
222
240
  var resolveColorValue = (value) => value.startsWith("--") ? `var(${value})` : value;
223
241
 
224
242
  // src/components/chip/chip.ts
243
+ var DEFAULT_LABELS = {
244
+ remove: "Remove"
245
+ };
225
246
  var Chip = class extends ThemeableElement {
226
247
  constructor() {
227
248
  super(...arguments);
@@ -231,6 +252,10 @@ var Chip = class extends ThemeableElement {
231
252
  this.disabled = false;
232
253
  this.deletable = false;
233
254
  this.background = "";
255
+ this.labels = {};
256
+ }
257
+ get _labels() {
258
+ return { ...DEFAULT_LABELS, ...this.labels };
234
259
  }
235
260
  get _deleteIconSize() {
236
261
  return this.size === "lg" ? "sm" : "xs";
@@ -249,7 +274,7 @@ var Chip = class extends ThemeableElement {
249
274
  class="delete"
250
275
  part="delete-button"
251
276
  ?disabled=${this.disabled}
252
- aria-label="Remove"
277
+ aria-label=${this._labels.remove}
253
278
  @click=${this._handleDelete}
254
279
  >
255
280
  <lt-icon name="xmark" size=${this._deleteIconSize}></lt-icon>
@@ -278,6 +303,9 @@ __decorateClass([
278
303
  __decorateClass([
279
304
  property2({ reflect: true })
280
305
  ], Chip.prototype, "background", 2);
306
+ __decorateClass([
307
+ property2({ type: Object })
308
+ ], Chip.prototype, "labels", 2);
281
309
  Chip = __decorateClass([
282
310
  customElement("lt-chip")
283
311
  ], Chip);
@@ -1,5 +1,5 @@
1
1
  import { ThemeableElement } from '../../base';
2
- import { ColorInputFormat, ColorInputSize } from './color-input.types';
2
+ import { ColorInputFormat, ColorInputSize, type ColorInputLabels } from './color-input.types';
3
3
  import '@latty-ds/icons';
4
4
  import '../text/text';
5
5
  /**
@@ -21,10 +21,13 @@ export declare class ColorInput extends ThemeableElement {
21
21
  static styles: import("lit").CSSResult;
22
22
  static formAssociated: boolean;
23
23
  private _internals;
24
+ private _default;
25
+ private _fieldsetDisabled;
24
26
  constructor();
25
27
  /**
26
28
  * The current color value. Accepts hex (`#7c3aed`), rgb (`rgb(124, 58, 237)`),
27
- * or hsl (`hsl(263, 70%, 58%)`). Emitted values match the `format` prop.
29
+ * or hsl (`hsl(263, 70%, 58%)`). Emitted values match the `format` prop. Not reflected as an attribute —
30
+ * read the property, or the `change` event's `detail.value`, instead of `getAttribute('value')`/`[value]`.
28
31
  * @default ''
29
32
  */
30
33
  value: string;
@@ -63,8 +66,14 @@ export declare class ColorInput extends ThemeableElement {
63
66
  * @default 'md'
64
67
  */
65
68
  size: ColorInputSize;
69
+ /** Overridable UI text (the required-field validation message), for i18n. English defaults — override only the keys you need. */
70
+ labels: Partial<ColorInputLabels>;
71
+ private get _labels();
66
72
  updated(): void;
67
73
  formResetCallback(): void;
74
+ formDisabledCallback(disabled: boolean): void;
75
+ /** `this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`). */
76
+ private get _isDisabled();
68
77
  checkValidity(): boolean;
69
78
  reportValidity(): boolean;
70
79
  private _handleChange;
@@ -1,2 +1,7 @@
1
1
  export type ColorInputSize = 'sm' | 'md' | 'lg';
2
2
  export type ColorInputFormat = 'hex' | 'rgb' | 'hsl';
3
+ /** Overridable UI text for `lt-color-input`, for i18n. */
4
+ export interface ColorInputLabels {
5
+ /** Validation message shown when a required field has no color selected. */
6
+ validationMessage: string;
7
+ }
@@ -53,7 +53,10 @@ var colorInputStyles = css`
53
53
  cursor: pointer;
54
54
  }
55
55
 
56
- :host([disabled]) .wrapper {
56
+ /* :host(:disabled) — the browser matches this automatically for a form-associated element inside a disabled
57
+ <fieldset>, no JS required; :host([disabled]) covers the component's own explicit attribute. */
58
+ :host([disabled]) .wrapper,
59
+ :host(:disabled) .wrapper {
57
60
  cursor: not-allowed;
58
61
  }
59
62
 
@@ -86,7 +89,8 @@ var colorInputStyles = css`
86
89
  outline: none;
87
90
  }
88
91
 
89
- :host([disabled]) .input-container {
92
+ :host([disabled]) .input-container,
93
+ :host(:disabled) .input-container {
90
94
  background: var(--lt-bg-surface);
91
95
  }
92
96
 
@@ -117,7 +121,8 @@ var colorInputStyles = css`
117
121
  color: var(--lt-text-muted);
118
122
  }
119
123
 
120
- :host([disabled]) .display-value {
124
+ :host([disabled]) .display-value,
125
+ :host(:disabled) .display-value {
121
126
  color: var(--lt-text-muted);
122
127
  }
123
128
 
@@ -185,8 +190,53 @@ var colorInputStyles = css`
185
190
  width: 24px;
186
191
  height: 24px;
187
192
  }
193
+
194
+ /* ── Reduced motion ─────────────────────────────────────────────────────── */
195
+
196
+ @media (prefers-reduced-motion: reduce) {
197
+ .input-container {
198
+ transition: none;
199
+ }
200
+ }
188
201
  `;
189
202
 
203
+ // src/components/shared/form-default.ts
204
+ var FormDefaultController = class {
205
+ constructor(host, get) {
206
+ this._captured = false;
207
+ this._get = get;
208
+ host.addController(this);
209
+ }
210
+ hostConnected() {
211
+ if (this._captured) return;
212
+ this._captured = true;
213
+ this.value = this._get();
214
+ }
215
+ };
216
+
217
+ // src/components/shared/form-disabled.ts
218
+ var FormDisabledController = class {
219
+ constructor(host) {
220
+ this._fieldsetDisabled = false;
221
+ this._host = host;
222
+ host.addController(this);
223
+ }
224
+ // No-op — this controller has no connect-time work of its own (formDisabledCallback drives it instead), but
225
+ // ReactiveController's members are all optional, and a class satisfying an all-optional interface with no
226
+ // members in common is a TS error (TS2559); this gives it one.
227
+ hostConnected() {
228
+ }
229
+ /** Whether an ancestor `<fieldset>` is currently disabled. */
230
+ get fieldsetDisabled() {
231
+ return this._fieldsetDisabled;
232
+ }
233
+ setFieldsetDisabled(disabled) {
234
+ if (this._fieldsetDisabled === disabled) return;
235
+ this._fieldsetDisabled = disabled;
236
+ this._host.requestUpdate();
237
+ }
238
+ };
239
+
190
240
  // src/components/color-input/color-input.ts
191
241
  import "@latty-ds/icons";
192
242
 
@@ -359,6 +409,20 @@ var textStyles = css2`
359
409
  `;
360
410
 
361
411
  // src/components/text/text.ts
412
+ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
413
+ "h1",
414
+ "h2",
415
+ "h3",
416
+ "h4",
417
+ "h5",
418
+ "h6",
419
+ "p",
420
+ "span",
421
+ "div",
422
+ "label",
423
+ "strong",
424
+ "em"
425
+ ]);
362
426
  var VARIANT_TAG = {
363
427
  "display-2xl": "p",
364
428
  "display-xl": "p",
@@ -383,7 +447,8 @@ var Text = class extends ThemeableElement {
383
447
  this.as = "";
384
448
  }
385
449
  render() {
386
- const tag = unsafeStatic(this.as || VARIANT_TAG[this.variant] || "p");
450
+ const requested = this.as && ALLOWED_TAGS.has(this.as) ? this.as : "";
451
+ const tag = unsafeStatic(requested || VARIANT_TAG[this.variant] || "p");
387
452
  return html`<${tag} part="base"><slot></slot></${tag}>`;
388
453
  }
389
454
  };
@@ -456,9 +521,14 @@ function formatColor(hex, format) {
456
521
  }
457
522
  return hex;
458
523
  }
524
+ var DEFAULT_LABELS = {
525
+ validationMessage: "Please select a color"
526
+ };
459
527
  var ColorInput = class extends ThemeableElement {
460
528
  constructor() {
461
529
  super();
530
+ this._default = new FormDefaultController(this, () => this.value);
531
+ this._fieldsetDisabled = new FormDisabledController(this);
462
532
  this.value = "";
463
533
  this.format = "hex";
464
534
  this.label = "";
@@ -467,19 +537,30 @@ var ColorInput = class extends ThemeableElement {
467
537
  this.required = false;
468
538
  this.name = "";
469
539
  this.size = "md";
540
+ this.labels = {};
470
541
  this._internals = this.attachInternals();
471
542
  }
543
+ get _labels() {
544
+ return { ...DEFAULT_LABELS, ...this.labels };
545
+ }
472
546
  updated() {
473
547
  this._internals.setFormValue(this.value || null);
474
548
  const input = this.shadowRoot?.querySelector('input[type="color"]');
475
549
  if (this.required && !this.value && input) {
476
- this._internals.setValidity({ valueMissing: true }, "Please select a color", input);
550
+ this._internals.setValidity({ valueMissing: true }, this._labels.validationMessage, input);
477
551
  } else {
478
552
  this._internals.setValidity({});
479
553
  }
480
554
  }
481
555
  formResetCallback() {
482
- this.value = "";
556
+ this.value = this._default.value;
557
+ }
558
+ formDisabledCallback(disabled) {
559
+ this._fieldsetDisabled.setFieldsetDisabled(disabled);
560
+ }
561
+ /** `this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`). */
562
+ get _isDisabled() {
563
+ return this.disabled || this._fieldsetDisabled.fieldsetDisabled;
483
564
  }
484
565
  checkValidity() {
485
566
  return this._internals.checkValidity();
@@ -513,7 +594,7 @@ var ColorInput = class extends ThemeableElement {
513
594
  class="native-picker"
514
595
  .value=${hex || "#000000"}
515
596
  name=${ifDefined(this.name || void 0)}
516
- ?disabled=${this.disabled}
597
+ ?disabled=${this._isDisabled}
517
598
  aria-label=${this.label || this.placeholder}
518
599
  @change=${this._handleChange}
519
600
  />
@@ -525,7 +606,7 @@ var ColorInput = class extends ThemeableElement {
525
606
  ColorInput.styles = colorInputStyles;
526
607
  ColorInput.formAssociated = true;
527
608
  __decorateClass([
528
- property3({ reflect: true })
609
+ property3()
529
610
  ], ColorInput.prototype, "value", 2);
530
611
  __decorateClass([
531
612
  property3({ reflect: true })
@@ -548,6 +629,9 @@ __decorateClass([
548
629
  __decorateClass([
549
630
  property3({ reflect: true })
550
631
  ], ColorInput.prototype, "size", 2);
632
+ __decorateClass([
633
+ property3({ type: Object })
634
+ ], ColorInput.prototype, "labels", 2);
551
635
  ColorInput = __decorateClass([
552
636
  customElement2("lt-color-input")
553
637
  ], ColorInput);
@@ -1,5 +1,5 @@
1
1
  import { ThemeableElement } from '../../base';
2
- import type { ComboboxOption, ComboboxSize, ComboboxVariant } from './combobox.types';
2
+ import type { ComboboxOption, ComboboxSize, ComboboxVariant, ComboboxLabels } from './combobox.types';
3
3
  import '@latty-ds/icons';
4
4
  import '../text/text';
5
5
  /**
@@ -22,10 +22,15 @@ export declare class Combobox extends ThemeableElement {
22
22
  static styles: import("lit").CSSResult[];
23
23
  static formAssociated: boolean;
24
24
  private _internals;
25
+ private _default;
26
+ private _fieldsetDisabled;
27
+ private readonly _uid;
25
28
  constructor();
26
29
  /** Array of selectable options. Set as a JS property (`.options`). */
27
30
  options: ComboboxOption[];
28
- /** Currently selected value. */
31
+ /** Currently selected value. Not reflected as an attribute — read the property, or the `change` event's
32
+ * `detail.value`, instead of `getAttribute('value')`/`[value]` (consistent with the rest of the form
33
+ * controls; see `lt-textfield`'s equivalent doc comment for why). */
29
34
  value: string;
30
35
  /** Field label displayed above the input. */
31
36
  label: string;
@@ -43,23 +48,34 @@ export declare class Combobox extends ThemeableElement {
43
48
  required: boolean;
44
49
  /** Name used in form submission. */
45
50
  name: string;
51
+ /** Overridable UI text (validation message, "no results" text), for i18n. English defaults — override only the keys you need. */
52
+ labels: Partial<ComboboxLabels>;
53
+ private get _labels();
46
54
  private query;
47
55
  private open;
48
56
  private activeIndex;
49
57
  private _cleanupClickOutside;
50
58
  private _floatingCleanup;
59
+ private readonly _fieldIds;
51
60
  private get selectedLabel();
52
61
  private get filtered();
62
+ private get enabledOpts();
63
+ private _idFor;
64
+ private _preventFocusSteal;
53
65
  private openDropdown;
54
66
  private closeDropdown;
55
67
  private selectOption;
56
68
  private handleInput;
57
69
  private handleFocus;
58
70
  private handleKeydown;
71
+ private _onFocusOut;
59
72
  connectedCallback(): void;
60
73
  disconnectedCallback(): void;
61
74
  updated(): void;
62
75
  formResetCallback(): void;
76
+ formDisabledCallback(disabled: boolean): void;
77
+ /** `this.disabled` combined with an ancestor `<fieldset>`'s own disabled state (see `FormDisabledController`). */
78
+ private get _isDisabled();
63
79
  checkValidity(): boolean;
64
80
  reportValidity(): boolean;
65
81
  render(): import("lit").TemplateResult<1>;
@@ -5,3 +5,10 @@ export interface ComboboxOption {
5
5
  label: string;
6
6
  disabled?: boolean;
7
7
  }
8
+ /** Overridable UI text for `lt-combobox`, for i18n. */
9
+ export interface ComboboxLabels {
10
+ /** Validation message shown when a required combobox has no option selected. */
11
+ validationMessage: string;
12
+ /** Shown in the dropdown when no options match the current search text. */
13
+ noResults: string;
14
+ }