@phcdevworks/spectre-components 0.0.1 → 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 (61) hide show
  1. package/dist/base-DQtCQ-dP.d.cts +22 -0
  2. package/dist/base-DQtCQ-dP.d.ts +22 -0
  3. package/dist/button.cjs +149 -124
  4. package/dist/button.cjs.map +1 -1
  5. package/dist/button.d.cts +15 -40
  6. package/dist/button.d.ts +15 -40
  7. package/dist/button.js +150 -125
  8. package/dist/button.js.map +1 -1
  9. package/dist/checkbox.cjs +140 -25
  10. package/dist/checkbox.cjs.map +1 -1
  11. package/dist/checkbox.d.cts +32 -32
  12. package/dist/checkbox.d.ts +32 -32
  13. package/dist/checkbox.js +141 -26
  14. package/dist/checkbox.js.map +1 -1
  15. package/dist/fieldset.cjs +96 -50
  16. package/dist/fieldset.cjs.map +1 -1
  17. package/dist/fieldset.d.cts +24 -36
  18. package/dist/fieldset.d.ts +24 -36
  19. package/dist/fieldset.js +96 -50
  20. package/dist/fieldset.js.map +1 -1
  21. package/dist/form-iI7vV-3W.d.cts +6 -0
  22. package/dist/form-iI7vV-3W.d.ts +6 -0
  23. package/dist/index.cjs +298 -826
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +5 -2
  26. package/dist/index.d.ts +5 -2
  27. package/dist/index.js +300 -827
  28. package/dist/index.js.map +1 -1
  29. package/dist/input.cjs +70 -59
  30. package/dist/input.cjs.map +1 -1
  31. package/dist/input.d.cts +25 -36
  32. package/dist/input.d.ts +25 -36
  33. package/dist/input.js +70 -59
  34. package/dist/input.js.map +1 -1
  35. package/dist/label.cjs +101 -38
  36. package/dist/label.cjs.map +1 -1
  37. package/dist/label.d.cts +16 -20
  38. package/dist/label.d.ts +16 -20
  39. package/dist/label.js +101 -38
  40. package/dist/label.js.map +1 -1
  41. package/dist/projectable-DcnBRiko.d.cts +17 -0
  42. package/dist/projectable-SzbPvXfM.d.ts +17 -0
  43. package/dist/radio.cjs +140 -25
  44. package/dist/radio.cjs.map +1 -1
  45. package/dist/radio.d.cts +32 -32
  46. package/dist/radio.d.ts +32 -32
  47. package/dist/radio.js +141 -26
  48. package/dist/radio.js.map +1 -1
  49. package/dist/select.cjs +142 -113
  50. package/dist/select.cjs.map +1 -1
  51. package/dist/select.d.cts +23 -41
  52. package/dist/select.d.ts +23 -41
  53. package/dist/select.js +143 -113
  54. package/dist/select.js.map +1 -1
  55. package/dist/textarea.cjs +24 -223
  56. package/dist/textarea.cjs.map +1 -1
  57. package/dist/textarea.d.cts +20 -32
  58. package/dist/textarea.d.ts +20 -32
  59. package/dist/textarea.js +24 -223
  60. package/dist/textarea.js.map +1 -1
  61. package/package.json +11 -11
package/dist/index.js CHANGED
@@ -1,59 +1,15 @@
1
- import { LitElement, nothing, html } from 'lit';
1
+ import { LitElement, html, nothing } from 'lit';
2
2
  import { ifDefined } from 'lit/directives/if-defined.js';
3
3
  import { getButtonClasses, getInputClasses } from '@phcdevworks/spectre-ui';
4
4
  import { live } from 'lit/directives/live.js';
5
5
 
6
6
  // src/components/button/sp-button.ts
7
- var spectreButtonVariants = [
8
- "primary",
9
- "secondary",
10
- "ghost",
11
- "danger",
12
- "success",
13
- "cta",
14
- "accent"
15
- ];
16
- var spectreButtonSizes = ["sm", "md", "lg"];
17
- var spectreButtonTypes = ["button", "submit", "reset"];
18
- function isButtonVariant(value) {
19
- return spectreButtonVariants.includes(value);
20
- }
21
- function isButtonSize(value) {
22
- return spectreButtonSizes.includes(value);
23
- }
24
- function isButtonType(value) {
25
- return spectreButtonTypes.includes(value);
26
- }
27
- function hasMeaningfulContent(nodes) {
28
- return nodes.some((node) => {
29
- if (node.nodeType === Node.ELEMENT_NODE) {
30
- return true;
31
- }
32
- if (node.nodeType === Node.TEXT_NODE) {
33
- return (node.textContent?.trim().length ?? 0) > 0;
34
- }
35
- return false;
36
- });
37
- }
38
- var SpectreButtonElement = class extends LitElement {
7
+ var SpectreBaseElement = class extends LitElement {
39
8
  constructor() {
40
9
  super(...arguments);
41
10
  this.ariaLabel = null;
42
11
  this.ariaLabelledBy = null;
43
12
  this.ariaDescribedBy = null;
44
- this.autofocus = false;
45
- this.disabled = false;
46
- this.fullWidth = false;
47
- this.loading = false;
48
- this.loadingLabel = "Loading";
49
- this.pill = false;
50
- this.size = "md";
51
- this.title = "";
52
- this.type = "button";
53
- this.variant = "primary";
54
- // Native slot projection is a Shadow DOM feature, so in light DOM we keep
55
- // host-provided content reactive by tracking and reusing the host nodes.
56
- this.projectedContent = [];
57
13
  }
58
14
  get id() {
59
15
  return this._id ?? "";
@@ -69,6 +25,8 @@ var SpectreButtonElement = class extends LitElement {
69
25
  }
70
26
  this.requestUpdate();
71
27
  }
28
+ // Spectre components intentionally render in light DOM so the global
29
+ // `@phcdevworks/spectre-ui` styling contract can apply directly.
72
30
  createRenderRoot() {
73
31
  return this;
74
32
  }
@@ -78,8 +36,6 @@ var SpectreButtonElement = class extends LitElement {
78
36
  if (hostId !== null) {
79
37
  this.id = hostId;
80
38
  }
81
- this.syncProjectedContent();
82
- this.startContentObserver();
83
39
  }
84
40
  getAttribute(qualifiedName) {
85
41
  if (qualifiedName === "id") {
@@ -107,10 +63,147 @@ var SpectreButtonElement = class extends LitElement {
107
63
  }
108
64
  super.removeAttribute(qualifiedName);
109
65
  }
66
+ get forwardedAriaLabel() {
67
+ const value = this.ariaLabel?.trim();
68
+ return value ? value : void 0;
69
+ }
70
+ get forwardedAriaLabelledBy() {
71
+ const value = this.ariaLabelledBy?.trim();
72
+ return value ? value : void 0;
73
+ }
74
+ get forwardedAriaDescribedBy() {
75
+ const value = this.ariaDescribedBy?.trim();
76
+ return value ? value : void 0;
77
+ }
78
+ };
79
+ SpectreBaseElement.properties = {
80
+ ariaLabel: { attribute: "aria-label", type: String },
81
+ ariaLabelledBy: { attribute: "aria-labelledby", type: String },
82
+ ariaDescribedBy: { attribute: "aria-describedby", type: String }
83
+ };
84
+
85
+ // src/utils/dom.ts
86
+ function hasMeaningfulContent(nodes) {
87
+ return nodes.some((node) => {
88
+ if (node.nodeType === Node.ELEMENT_NODE) {
89
+ return true;
90
+ }
91
+ if (node.nodeType === Node.TEXT_NODE) {
92
+ return (node.textContent?.trim().length ?? 0) > 0;
93
+ }
94
+ return false;
95
+ });
96
+ }
97
+
98
+ // src/utils/projectable.ts
99
+ var SpectreProjectableElement = class extends SpectreBaseElement {
100
+ constructor() {
101
+ super(...arguments);
102
+ this.projectedContent = [];
103
+ }
104
+ get hasProjectedContent() {
105
+ return hasMeaningfulContent(this.projectedContent);
106
+ }
107
+ connectedCallback() {
108
+ super.connectedCallback();
109
+ this.syncProjectedContent();
110
+ this.startContentObserver();
111
+ }
110
112
  disconnectedCallback() {
111
113
  this.stopContentObserver();
112
114
  super.disconnectedCallback();
113
115
  }
116
+ update(changedProperties) {
117
+ this.stopContentObserver();
118
+ super.update(changedProperties);
119
+ this.startContentObserver();
120
+ }
121
+ syncProjectedContent() {
122
+ const nextProjectedContent = [];
123
+ const sourceNodes = [
124
+ ...this.childNodes,
125
+ ...this.getContentContainer()?.childNodes ?? []
126
+ ];
127
+ sourceNodes.forEach((node) => {
128
+ if (!this.isInternalNode(node) && !nextProjectedContent.includes(node)) {
129
+ nextProjectedContent.push(node);
130
+ }
131
+ });
132
+ const hasChanged = nextProjectedContent.length !== this.projectedContent.length || nextProjectedContent.some((node, index) => node !== this.projectedContent[index]);
133
+ if (hasChanged) {
134
+ this.projectedContent = nextProjectedContent;
135
+ }
136
+ return hasChanged;
137
+ }
138
+ startContentObserver() {
139
+ if (this.contentObserver) {
140
+ return;
141
+ }
142
+ this.contentObserver = new MutationObserver((mutations) => {
143
+ const isInternalMovement = mutations.every(
144
+ (mutation) => Array.from(mutation.removedNodes).every(
145
+ (node) => this.isInternalNode(node) || this.contains(node)
146
+ ) && Array.from(mutation.addedNodes).every((node) => this.isInternalNode(node))
147
+ );
148
+ if (isInternalMovement) {
149
+ return;
150
+ }
151
+ if (this.syncProjectedContent()) {
152
+ this.requestUpdate();
153
+ }
154
+ });
155
+ this.contentObserver.observe(this, { childList: true });
156
+ }
157
+ stopContentObserver() {
158
+ this.contentObserver?.disconnect();
159
+ this.contentObserver = void 0;
160
+ }
161
+ };
162
+ var spectreButtonVariants = [
163
+ "primary",
164
+ "secondary",
165
+ "ghost",
166
+ "danger",
167
+ "success",
168
+ "cta",
169
+ "accent"
170
+ ];
171
+ var spectreButtonSizes = ["sm", "md", "lg"];
172
+ var spectreButtonTypes = ["button", "submit", "reset"];
173
+ function isButtonVariant(value) {
174
+ return spectreButtonVariants.includes(value);
175
+ }
176
+ function isButtonSize(value) {
177
+ return spectreButtonSizes.includes(value);
178
+ }
179
+ function isButtonType(value) {
180
+ return spectreButtonTypes.includes(value);
181
+ }
182
+ var SpectreButtonElement = class extends SpectreProjectableElement {
183
+ constructor() {
184
+ super(...arguments);
185
+ this.autofocus = false;
186
+ this.disabled = false;
187
+ this.fullWidth = false;
188
+ this.loading = false;
189
+ this.loadingLabel = "Loading";
190
+ this.pill = false;
191
+ this.size = "md";
192
+ this.title = "";
193
+ this.type = "button";
194
+ this.variant = "primary";
195
+ this.value = "";
196
+ }
197
+ getContentContainer() {
198
+ return this.querySelector("[data-sp-button-native]");
199
+ }
200
+ isInternalNode(node) {
201
+ if (node.nodeType !== Node.ELEMENT_NODE) {
202
+ return false;
203
+ }
204
+ const el = node;
205
+ return el.hasAttribute("data-sp-button-native") || el.hasAttribute("data-sp-button-loading-label") || el.hasAttribute("data-sp-button-label-fallback");
206
+ }
114
207
  willUpdate(changedProperties) {
115
208
  if (changedProperties.has("variant") && !isButtonVariant(this.variant)) {
116
209
  this.variant = "primary";
@@ -126,11 +219,9 @@ var SpectreButtonElement = class extends LitElement {
126
219
  this.loadingLabel = "Loading";
127
220
  }
128
221
  }
129
- }
130
- update(changedProperties) {
131
- this.stopContentObserver();
132
- super.update(changedProperties);
133
- this.startContentObserver();
222
+ if (changedProperties.has("value") && this.value == null) {
223
+ this.value = "";
224
+ }
134
225
  }
135
226
  get buttonClasses() {
136
227
  return getButtonClasses({
@@ -145,89 +236,24 @@ var SpectreButtonElement = class extends LitElement {
145
236
  get isDisabled() {
146
237
  return this.disabled || this.loading;
147
238
  }
148
- get hasProjectedContent() {
149
- return hasMeaningfulContent(this.projectedContent);
150
- }
151
239
  get visibleLabelFallback() {
152
240
  const trimmedLabel = this.label?.trim();
153
241
  return trimmedLabel ? trimmedLabel : void 0;
154
242
  }
155
- get forwardedAriaLabel() {
156
- const ariaLabel = this.ariaLabel?.trim();
157
- return ariaLabel ? ariaLabel : void 0;
158
- }
159
- get forwardedAriaLabelledBy() {
160
- const ariaLabelledBy = this.ariaLabelledBy?.trim();
161
- return ariaLabelledBy ? ariaLabelledBy : void 0;
162
- }
163
- get forwardedAriaDescribedBy() {
164
- const ariaDescribedBy = this.ariaDescribedBy?.trim();
165
- return ariaDescribedBy ? ariaDescribedBy : void 0;
166
- }
167
- startContentObserver() {
168
- if (this.contentObserver) {
169
- return;
170
- }
171
- this.contentObserver = new MutationObserver((mutations) => {
172
- const isInternalMovement = mutations.every((mutation) => {
173
- return Array.from(mutation.removedNodes).every(
174
- (node) => this.isInternalButtonNode(node) || this.contains(node)
175
- ) && Array.from(mutation.addedNodes).every((node) => this.isInternalButtonNode(node));
176
- });
177
- if (isInternalMovement) {
178
- return;
179
- }
180
- if (this.syncProjectedContent()) {
181
- this.requestUpdate();
182
- }
183
- });
184
- this.contentObserver.observe(this, {
185
- childList: true
186
- });
187
- }
188
- stopContentObserver() {
189
- this.contentObserver?.disconnect();
190
- this.contentObserver = void 0;
191
- }
192
- syncProjectedContent() {
193
- const nextProjectedContent = [];
194
- Array.from(this.childNodes).forEach((node) => {
195
- if (this.isInternalButtonNode(node)) {
196
- this.projectedContent.forEach((pNode) => {
197
- if (pNode.parentNode !== this && this.contains(pNode)) {
198
- nextProjectedContent.push(pNode);
199
- }
200
- });
201
- } else {
202
- nextProjectedContent.push(node);
203
- }
204
- });
205
- const hasChanged = nextProjectedContent.length !== this.projectedContent.length || nextProjectedContent.some((node, index) => node !== this.projectedContent[index]);
206
- if (hasChanged) {
207
- this.projectedContent = nextProjectedContent;
208
- }
209
- return hasChanged;
210
- }
211
- isInternalButtonNode(node) {
212
- return node.nodeType === Node.ELEMENT_NODE && node.hasAttribute("data-sp-button-native");
213
- }
214
- get nativeButton() {
215
- return this.querySelector("[data-sp-button-native]");
216
- }
217
243
  focus(options) {
218
- this.nativeButton?.focus(options);
244
+ this.getContentContainer()?.focus(options);
219
245
  }
220
246
  blur() {
221
- this.nativeButton?.blur();
247
+ this.getContentContainer()?.blur();
222
248
  }
223
249
  renderButtonContent() {
224
250
  if (this.loading) {
225
- return this.loadingLabel;
251
+ return html`<span data-sp-button-loading-label>${this.loadingLabel}</span>`;
226
252
  }
227
253
  if (this.hasProjectedContent) {
228
254
  return this.projectedContent;
229
255
  }
230
- return this.visibleLabelFallback ?? "";
256
+ return this.visibleLabelFallback ? html`<span data-sp-button-label-fallback>${this.visibleLabelFallback}</span>` : nothing;
231
257
  }
232
258
  render() {
233
259
  return html`
@@ -240,6 +266,7 @@ var SpectreButtonElement = class extends LitElement {
240
266
  class=${this.buttonClasses}
241
267
  data-sp-button-native
242
268
  ?disabled=${this.isDisabled}
269
+ form=${ifDefined(this.form)}
243
270
  id=${ifDefined(this.id || void 0)}
244
271
  name=${ifDefined(this.name)}
245
272
  title=${ifDefined(this.title || void 0)}
@@ -252,11 +279,9 @@ var SpectreButtonElement = class extends LitElement {
252
279
  }
253
280
  };
254
281
  SpectreButtonElement.properties = {
255
- ariaLabel: { attribute: "aria-label", type: String },
256
- ariaLabelledBy: { attribute: "aria-labelledby", type: String },
257
- ariaDescribedBy: { attribute: "aria-describedby", type: String },
258
282
  autofocus: { type: Boolean, reflect: true },
259
283
  disabled: { type: Boolean, reflect: true },
284
+ form: { type: String },
260
285
  fullWidth: { attribute: "full-width", type: Boolean, reflect: true },
261
286
  label: { type: String, reflect: true },
262
287
  loading: { type: Boolean, reflect: true },
@@ -277,6 +302,10 @@ function defineSpectreButton(tagName = "sp-button") {
277
302
  customElements.define(tagName, SpectreButtonElement);
278
303
  return SpectreButtonElement;
279
304
  }
305
+ var spectreInputSizes = ["sm", "md", "lg"];
306
+ function isInputSize(value) {
307
+ return spectreInputSizes.includes(value);
308
+ }
280
309
  var spectreInputTypes = [
281
310
  "text",
282
311
  "email",
@@ -291,19 +320,12 @@ var spectreInputTypes = [
291
320
  "time",
292
321
  "week"
293
322
  ];
294
- var spectreInputSizes = ["sm", "md", "lg"];
295
323
  function isInputType(value) {
296
324
  return spectreInputTypes.includes(value);
297
325
  }
298
- function isInputSize(value) {
299
- return spectreInputSizes.includes(value);
300
- }
301
- var SpectreInputElement = class extends LitElement {
326
+ var SpectreInputElement = class extends SpectreBaseElement {
302
327
  constructor() {
303
328
  super(...arguments);
304
- this.ariaLabel = null;
305
- this.ariaLabelledBy = null;
306
- this.ariaDescribedBy = null;
307
329
  this.autofocus = false;
308
330
  this.disabled = false;
309
331
  this.fullWidth = false;
@@ -318,65 +340,15 @@ var SpectreInputElement = class extends LitElement {
318
340
  this.type = "text";
319
341
  this.value = "";
320
342
  }
321
- get id() {
322
- return this._id ?? "";
323
- }
324
- set id(value) {
325
- if ((this._id ?? "") === value) {
326
- return;
327
- }
328
- this._id = value;
329
- const host = this;
330
- if (HTMLElement.prototype.hasAttribute.call(host, "id")) {
331
- HTMLElement.prototype.removeAttribute.call(host, "id");
343
+ willUpdate(changedProperties) {
344
+ if (changedProperties.has("size") && !isInputSize(this.size)) {
345
+ this.size = "md";
332
346
  }
333
- this.requestUpdate();
334
- }
335
- createRenderRoot() {
336
- return this;
337
- }
338
- connectedCallback() {
339
- super.connectedCallback();
340
- const hostId = super.getAttribute("id");
341
- if (hostId !== null) {
342
- this.id = hostId;
347
+ if (changedProperties.has("type") && !isInputType(this.type)) {
348
+ this.type = "text";
343
349
  }
344
- }
345
- getAttribute(qualifiedName) {
346
- if (qualifiedName === "id") {
347
- return this.id || null;
348
- }
349
- return super.getAttribute(qualifiedName);
350
- }
351
- hasAttribute(qualifiedName) {
352
- if (qualifiedName === "id") {
353
- return this.id !== "";
354
- }
355
- return super.hasAttribute(qualifiedName);
356
- }
357
- setAttribute(qualifiedName, value) {
358
- if (qualifiedName === "id") {
359
- this.id = value;
360
- return;
361
- }
362
- super.setAttribute(qualifiedName, value);
363
- }
364
- removeAttribute(qualifiedName) {
365
- if (qualifiedName === "id") {
366
- this.id = "";
367
- return;
368
- }
369
- super.removeAttribute(qualifiedName);
370
- }
371
- willUpdate(changedProperties) {
372
- if (changedProperties.has("size") && !isInputSize(this.size)) {
373
- this.size = "md";
374
- }
375
- if (changedProperties.has("type") && !isInputType(this.type)) {
376
- this.type = "text";
377
- }
378
- if (changedProperties.has("value") && this.value == null) {
379
- this.value = "";
350
+ if (changedProperties.has("value") && this.value == null) {
351
+ this.value = "";
380
352
  }
381
353
  if (changedProperties.has("maxlength")) {
382
354
  if (this.maxlength == null || !Number.isInteger(this.maxlength) || this.maxlength < 0) {
@@ -403,18 +375,6 @@ var SpectreInputElement = class extends LitElement {
403
375
  get nativeInput() {
404
376
  return this.querySelector("[data-sp-input-native]");
405
377
  }
406
- get forwardedAriaLabel() {
407
- const ariaLabel = this.ariaLabel?.trim();
408
- return ariaLabel ? ariaLabel : void 0;
409
- }
410
- get forwardedAriaLabelledBy() {
411
- const ariaLabelledBy = this.ariaLabelledBy?.trim();
412
- return ariaLabelledBy ? ariaLabelledBy : void 0;
413
- }
414
- get forwardedAriaDescribedBy() {
415
- const ariaDescribedBy = this.ariaDescribedBy?.trim();
416
- return ariaDescribedBy ? ariaDescribedBy : void 0;
417
- }
418
378
  handleInput(event) {
419
379
  const input = event.currentTarget;
420
380
  this.value = input.value;
@@ -442,6 +402,7 @@ var SpectreInputElement = class extends LitElement {
442
402
  class=${this.inputClasses}
443
403
  data-sp-input-native
444
404
  ?disabled=${this.isDisabled}
405
+ form=${ifDefined(this.form)}
445
406
  ?readonly=${this.readonly}
446
407
  ?required=${this.required}
447
408
  id=${ifDefined(this.id || void 0)}
@@ -463,27 +424,25 @@ var SpectreInputElement = class extends LitElement {
463
424
  }
464
425
  };
465
426
  SpectreInputElement.properties = {
466
- ariaLabel: { attribute: "aria-label", type: String },
467
- ariaLabelledBy: { attribute: "aria-labelledby", type: String },
468
- ariaDescribedBy: { attribute: "aria-describedby", type: String },
469
- autocomplete: { type: String },
427
+ autocomplete: { type: String, reflect: true },
470
428
  autofocus: { type: Boolean, reflect: true },
471
429
  disabled: { type: Boolean, reflect: true },
430
+ form: { type: String },
472
431
  fullWidth: { attribute: "full-width", type: Boolean, reflect: true },
473
- inputmode: { type: String },
432
+ inputmode: { type: String, reflect: true },
474
433
  invalid: { type: Boolean, reflect: true },
475
434
  loading: { type: Boolean, reflect: true },
476
- max: { type: String },
477
- maxlength: { type: Number },
478
- min: { type: String },
479
- minlength: { type: Number },
480
- name: { type: String },
435
+ max: { type: String, reflect: true },
436
+ maxlength: { type: Number, reflect: true },
437
+ min: { type: String, reflect: true },
438
+ minlength: { type: Number, reflect: true },
439
+ name: { type: String, reflect: true },
481
440
  pill: { type: Boolean, reflect: true },
482
- placeholder: { type: String },
441
+ placeholder: { type: String, reflect: true },
483
442
  readonly: { type: Boolean, reflect: true },
484
443
  required: { type: Boolean, reflect: true },
485
444
  size: { type: String, reflect: true },
486
- step: { type: String },
445
+ step: { type: String, reflect: true },
487
446
  success: { type: Boolean, reflect: true },
488
447
  title: { type: String, reflect: true },
489
448
  type: { type: String, reflect: true },
@@ -498,12 +457,9 @@ function defineSpectreInput(tagName = "sp-input") {
498
457
  return SpectreInputElement;
499
458
  }
500
459
  var DEFAULT_ROWS = 2;
501
- var SpectreTextareaElement = class extends LitElement {
460
+ var SpectreTextareaElement = class extends SpectreBaseElement {
502
461
  constructor() {
503
462
  super(...arguments);
504
- this.ariaLabel = null;
505
- this.ariaLabelledBy = null;
506
- this.ariaDescribedBy = null;
507
463
  this.autofocus = false;
508
464
  this.disabled = false;
509
465
  this.fullWidth = false;
@@ -518,56 +474,6 @@ var SpectreTextareaElement = class extends LitElement {
518
474
  this.title = "";
519
475
  this.value = "";
520
476
  }
521
- get id() {
522
- return this._id ?? "";
523
- }
524
- set id(value) {
525
- if ((this._id ?? "") === value) {
526
- return;
527
- }
528
- this._id = value;
529
- const host = this;
530
- if (HTMLElement.prototype.hasAttribute.call(host, "id")) {
531
- HTMLElement.prototype.removeAttribute.call(host, "id");
532
- }
533
- this.requestUpdate();
534
- }
535
- createRenderRoot() {
536
- return this;
537
- }
538
- connectedCallback() {
539
- super.connectedCallback();
540
- const hostId = super.getAttribute("id");
541
- if (hostId !== null) {
542
- this.id = hostId;
543
- }
544
- }
545
- getAttribute(qualifiedName) {
546
- if (qualifiedName === "id") {
547
- return this.id || null;
548
- }
549
- return super.getAttribute(qualifiedName);
550
- }
551
- hasAttribute(qualifiedName) {
552
- if (qualifiedName === "id") {
553
- return this.id !== "";
554
- }
555
- return super.hasAttribute(qualifiedName);
556
- }
557
- setAttribute(qualifiedName, value) {
558
- if (qualifiedName === "id") {
559
- this.id = value;
560
- return;
561
- }
562
- super.setAttribute(qualifiedName, value);
563
- }
564
- removeAttribute(qualifiedName) {
565
- if (qualifiedName === "id") {
566
- this.id = "";
567
- return;
568
- }
569
- super.removeAttribute(qualifiedName);
570
- }
571
477
  willUpdate(changedProperties) {
572
478
  if (changedProperties.has("size") && !isInputSize(this.size)) {
573
479
  this.size = "md";
@@ -605,18 +511,6 @@ var SpectreTextareaElement = class extends LitElement {
605
511
  get nativeTextarea() {
606
512
  return this.querySelector("[data-sp-textarea-native]");
607
513
  }
608
- get forwardedAriaLabel() {
609
- const ariaLabel = this.ariaLabel?.trim();
610
- return ariaLabel ? ariaLabel : void 0;
611
- }
612
- get forwardedAriaLabelledBy() {
613
- const ariaLabelledBy = this.ariaLabelledBy?.trim();
614
- return ariaLabelledBy ? ariaLabelledBy : void 0;
615
- }
616
- get forwardedAriaDescribedBy() {
617
- const ariaDescribedBy = this.ariaDescribedBy?.trim();
618
- return ariaDescribedBy ? ariaDescribedBy : void 0;
619
- }
620
514
  handleInput(event) {
621
515
  const textarea = event.currentTarget;
622
516
  this.value = textarea.value;
@@ -644,6 +538,7 @@ var SpectreTextareaElement = class extends LitElement {
644
538
  class=${this.textareaClasses}
645
539
  data-sp-textarea-native
646
540
  ?disabled=${this.isDisabled}
541
+ form=${ifDefined(this.form)}
647
542
  inputmode=${ifDefined(this.inputmode)}
648
543
  ?readonly=${this.readonly}
649
544
  ?required=${this.required}
@@ -662,21 +557,19 @@ var SpectreTextareaElement = class extends LitElement {
662
557
  }
663
558
  };
664
559
  SpectreTextareaElement.properties = {
665
- ariaLabel: { attribute: "aria-label", type: String },
666
- ariaLabelledBy: { attribute: "aria-labelledby", type: String },
667
- ariaDescribedBy: { attribute: "aria-describedby", type: String },
668
- autocomplete: { type: String },
560
+ autocomplete: { type: String, reflect: true },
669
561
  autofocus: { type: Boolean, reflect: true },
670
562
  disabled: { type: Boolean, reflect: true },
563
+ form: { type: String },
671
564
  fullWidth: { attribute: "full-width", type: Boolean, reflect: true },
672
- inputmode: { type: String },
565
+ inputmode: { type: String, reflect: true },
673
566
  invalid: { type: Boolean, reflect: true },
674
567
  loading: { type: Boolean, reflect: true },
675
- maxlength: { type: Number },
676
- minlength: { type: Number },
677
- name: { type: String },
568
+ maxlength: { type: Number, reflect: true },
569
+ minlength: { type: Number, reflect: true },
570
+ name: { type: String, reflect: true },
678
571
  pill: { type: Boolean, reflect: true },
679
- placeholder: { type: String },
572
+ placeholder: { type: String, reflect: true },
680
573
  readonly: { type: Boolean, reflect: true },
681
574
  required: { type: Boolean, reflect: true },
682
575
  rows: { type: Number },
@@ -693,26 +586,9 @@ function defineSpectreTextarea(tagName = "sp-textarea") {
693
586
  customElements.define(tagName, SpectreTextareaElement);
694
587
  return SpectreTextareaElement;
695
588
  }
696
- var spectreSelectSizes = ["sm", "md", "lg"];
697
- function isSelectSize(value) {
698
- return spectreSelectSizes.includes(value);
699
- }
700
- function isSelectableContent(node) {
701
- if (node.nodeType === Node.ELEMENT_NODE) {
702
- const tagName = node.tagName;
703
- return tagName === "OPTION" || tagName === "OPTGROUP";
704
- }
705
- if (node.nodeType === Node.TEXT_NODE) {
706
- return (node.textContent?.trim().length ?? 0) > 0;
707
- }
708
- return false;
709
- }
710
- var SpectreSelectElement = class extends LitElement {
589
+ var SpectreSelectElement = class extends SpectreProjectableElement {
711
590
  constructor() {
712
591
  super(...arguments);
713
- this.ariaLabel = null;
714
- this.ariaLabelledBy = null;
715
- this.ariaDescribedBy = null;
716
592
  this.autofocus = false;
717
593
  this.disabled = false;
718
594
  this.fullWidth = false;
@@ -724,91 +600,42 @@ var SpectreSelectElement = class extends LitElement {
724
600
  this.success = false;
725
601
  this.title = "";
726
602
  this.value = "";
727
- this.projectedOptions = [];
728
- }
729
- get id() {
730
- return this._id ?? "";
731
- }
732
- set id(value) {
733
- if ((this._id ?? "") === value) {
734
- return;
735
- }
736
- this._id = value;
737
- const host = this;
738
- if (HTMLElement.prototype.hasAttribute.call(host, "id")) {
739
- HTMLElement.prototype.removeAttribute.call(host, "id");
740
- }
741
- this.requestUpdate();
742
- }
743
- createRenderRoot() {
744
- return this;
745
- }
746
- connectedCallback() {
747
- super.connectedCallback();
748
- const hostId = super.getAttribute("id");
749
- if (hostId !== null) {
750
- this.id = hostId;
751
- }
752
- this.syncProjectedOptions();
753
- this.startContentObserver();
754
- }
755
- disconnectedCallback() {
756
- this.stopContentObserver();
757
- super.disconnectedCallback();
758
- }
759
- getAttribute(qualifiedName) {
760
- if (qualifiedName === "id") {
761
- return this.id || null;
762
- }
763
- return super.getAttribute(qualifiedName);
764
603
  }
765
- hasAttribute(qualifiedName) {
766
- if (qualifiedName === "id") {
767
- return this.id !== "";
768
- }
769
- return super.hasAttribute(qualifiedName);
770
- }
771
- setAttribute(qualifiedName, value) {
772
- if (qualifiedName === "id") {
773
- this.id = value;
774
- return;
775
- }
776
- super.setAttribute(qualifiedName, value);
604
+ getContentContainer() {
605
+ return this.querySelector("[data-sp-select-native]");
777
606
  }
778
- removeAttribute(qualifiedName) {
779
- if (qualifiedName === "id") {
780
- this.id = "";
781
- return;
607
+ isInternalNode(node) {
608
+ if (node.nodeType !== Node.ELEMENT_NODE) {
609
+ return false;
782
610
  }
783
- super.removeAttribute(qualifiedName);
611
+ const el = node;
612
+ return el.hasAttribute("data-sp-select-native");
784
613
  }
785
614
  willUpdate(changedProperties) {
786
- if (changedProperties.has("size") && !isSelectSize(this.size)) {
615
+ if (changedProperties.has("size") && !isInputSize(this.size)) {
787
616
  this.size = "md";
788
617
  }
789
618
  if (changedProperties.has("value") && this.value == null) {
790
619
  this.value = "";
791
620
  }
792
621
  }
793
- update(changedProperties) {
794
- this.stopContentObserver();
795
- super.update(changedProperties);
796
- this.startContentObserver();
797
- }
798
622
  updated(changedProperties) {
799
623
  super.updated(changedProperties);
800
- const nativeSelect = this.nativeSelect;
624
+ const nativeSelect = this.getContentContainer();
801
625
  if (!nativeSelect) {
802
626
  return;
803
627
  }
804
628
  if (this.value !== "" && nativeSelect.value !== this.value) {
805
629
  nativeSelect.value = this.value;
806
- return;
807
630
  }
808
631
  if (this.value === "" && !this.hasAttribute("value")) {
809
632
  const nativeValue = nativeSelect.value ?? "";
810
- if (nativeValue !== "") {
811
- this.value = nativeValue;
633
+ if (nativeValue !== "" && nativeValue !== this.value) {
634
+ this.updateComplete.then(() => {
635
+ if (this.value === "" && !this.hasAttribute("value")) {
636
+ this.value = nativeValue;
637
+ }
638
+ });
812
639
  }
813
640
  }
814
641
  }
@@ -823,70 +650,6 @@ var SpectreSelectElement = class extends LitElement {
823
650
  get isDisabled() {
824
651
  return this.disabled || this.loading;
825
652
  }
826
- get nativeSelect() {
827
- return this.querySelector("[data-sp-select-native]");
828
- }
829
- get forwardedAriaLabel() {
830
- const ariaLabel = this.ariaLabel?.trim();
831
- return ariaLabel ? ariaLabel : void 0;
832
- }
833
- get forwardedAriaLabelledBy() {
834
- const ariaLabelledBy = this.ariaLabelledBy?.trim();
835
- return ariaLabelledBy ? ariaLabelledBy : void 0;
836
- }
837
- get forwardedAriaDescribedBy() {
838
- const ariaDescribedBy = this.ariaDescribedBy?.trim();
839
- return ariaDescribedBy ? ariaDescribedBy : void 0;
840
- }
841
- startContentObserver() {
842
- if (this.contentObserver) {
843
- return;
844
- }
845
- this.contentObserver = new MutationObserver((mutations) => {
846
- const isInternalMovement = mutations.every((mutation) => {
847
- return Array.from(mutation.removedNodes).every(
848
- (node) => this.isInternalSelectNode(node) || this.contains(node)
849
- ) && Array.from(mutation.addedNodes).every((node) => this.isInternalSelectNode(node));
850
- });
851
- if (isInternalMovement) {
852
- return;
853
- }
854
- if (this.syncProjectedOptions()) {
855
- this.requestUpdate();
856
- }
857
- });
858
- this.contentObserver.observe(this, {
859
- childList: true
860
- });
861
- }
862
- stopContentObserver() {
863
- this.contentObserver?.disconnect();
864
- this.contentObserver = void 0;
865
- }
866
- syncProjectedOptions() {
867
- const nextProjectedOptions = [];
868
- Array.from(this.childNodes).forEach((node) => {
869
- if (this.isInternalSelectNode(node)) {
870
- this.projectedOptions.forEach((projectedNode) => {
871
- if (projectedNode.parentNode !== this && this.contains(projectedNode)) {
872
- nextProjectedOptions.push(projectedNode);
873
- }
874
- });
875
- return;
876
- }
877
- if (isSelectableContent(node)) {
878
- nextProjectedOptions.push(node);
879
- }
880
- });
881
- const hasChanged = nextProjectedOptions.length !== this.projectedOptions.length || nextProjectedOptions.some((node, index) => node !== this.projectedOptions[index]);
882
- if (hasChanged) {
883
- this.projectedOptions = nextProjectedOptions;
884
- }
885
- return hasChanged;
886
- }
887
- isInternalSelectNode(node) {
888
- return node.nodeType === Node.ELEMENT_NODE && node.hasAttribute("data-sp-select-native");
889
- }
890
653
  handleInput(event) {
891
654
  const select = event.currentTarget;
892
655
  this.value = select.value;
@@ -896,10 +659,10 @@ var SpectreSelectElement = class extends LitElement {
896
659
  this.value = select.value;
897
660
  }
898
661
  focus(options) {
899
- this.nativeSelect?.focus(options);
662
+ this.getContentContainer()?.focus(options);
900
663
  }
901
664
  blur() {
902
- this.nativeSelect?.blur();
665
+ this.getContentContainer()?.blur();
903
666
  }
904
667
  render() {
905
668
  return html`
@@ -909,10 +672,12 @@ var SpectreSelectElement = class extends LitElement {
909
672
  aria-invalid=${ifDefined(this.invalid ? "true" : void 0)}
910
673
  aria-label=${ifDefined(this.forwardedAriaLabel)}
911
674
  aria-labelledby=${ifDefined(this.forwardedAriaLabelledBy)}
675
+ autocomplete=${ifDefined(this.autocomplete)}
912
676
  ?autofocus=${this.autofocus}
913
677
  class=${this.selectClasses}
914
678
  data-sp-select-native
915
679
  ?disabled=${this.isDisabled}
680
+ form=${ifDefined(this.form)}
916
681
  id=${ifDefined(this.id || void 0)}
917
682
  name=${ifDefined(this.name)}
918
683
  ?required=${this.required}
@@ -921,21 +686,20 @@ var SpectreSelectElement = class extends LitElement {
921
686
  @change=${this.handleChange}
922
687
  @input=${this.handleInput}
923
688
  >
924
- ${this.projectedOptions.length > 0 ? this.projectedOptions : nothing}
689
+ ${this.hasProjectedContent ? this.projectedContent : nothing}
925
690
  </select>
926
691
  `;
927
692
  }
928
693
  };
929
694
  SpectreSelectElement.properties = {
930
- ariaLabel: { attribute: "aria-label", type: String },
931
- ariaLabelledBy: { attribute: "aria-labelledby", type: String },
932
- ariaDescribedBy: { attribute: "aria-describedby", type: String },
695
+ autocomplete: { type: String, reflect: true },
933
696
  autofocus: { type: Boolean, reflect: true },
934
697
  disabled: { type: Boolean, reflect: true },
698
+ form: { type: String },
935
699
  fullWidth: { attribute: "full-width", type: Boolean, reflect: true },
936
700
  invalid: { type: Boolean, reflect: true },
937
701
  loading: { type: Boolean, reflect: true },
938
- name: { type: String },
702
+ name: { type: String, reflect: true },
939
703
  pill: { type: Boolean, reflect: true },
940
704
  required: { type: Boolean, reflect: true },
941
705
  size: { type: String, reflect: true },
@@ -951,90 +715,43 @@ function defineSpectreSelect(tagName = "sp-select") {
951
715
  customElements.define(tagName, SpectreSelectElement);
952
716
  return SpectreSelectElement;
953
717
  }
954
- var SpectreCheckboxElement = class extends LitElement {
718
+ var SpectreCheckboxElement = class extends SpectreProjectableElement {
955
719
  constructor() {
956
720
  super(...arguments);
957
- this.ariaLabel = null;
958
- this.ariaLabelledBy = null;
959
- this.ariaDescribedBy = null;
960
721
  this.autofocus = false;
961
722
  this.checked = false;
962
723
  this.disabled = false;
963
724
  this.invalid = false;
964
- this.label = "";
725
+ this.loading = false;
965
726
  this.required = false;
727
+ this.success = false;
966
728
  this.title = "";
967
729
  this.value = "on";
968
730
  }
969
- get id() {
970
- return this._id ?? "";
731
+ getContentContainer() {
732
+ return this.querySelector("[data-sp-checkbox-label]");
971
733
  }
972
- set id(value) {
973
- if ((this._id ?? "") === value) {
974
- return;
975
- }
976
- this._id = value;
977
- const host = this;
978
- if (HTMLElement.prototype.hasAttribute.call(host, "id")) {
979
- HTMLElement.prototype.removeAttribute.call(host, "id");
734
+ isInternalNode(node) {
735
+ if (node.nodeType !== Node.ELEMENT_NODE) {
736
+ return false;
980
737
  }
981
- this.requestUpdate();
982
- }
983
- createRenderRoot() {
984
- return this;
738
+ const el = node;
739
+ return el.hasAttribute("data-sp-checkbox-label") || el.hasAttribute("data-sp-checkbox-native") || el.hasAttribute("data-sp-checkbox-label-fallback") || el.hasAttribute("data-sp-checkbox-indicator");
985
740
  }
986
- connectedCallback() {
987
- super.connectedCallback();
988
- const hostId = super.getAttribute("id");
989
- if (hostId !== null) {
990
- this.id = hostId;
741
+ willUpdate(changedProperties) {
742
+ if (changedProperties.has("value") && this.value == null) {
743
+ this.value = "on";
991
744
  }
992
745
  }
993
- getAttribute(qualifiedName) {
994
- if (qualifiedName === "id") {
995
- return this.id || null;
996
- }
997
- return super.getAttribute(qualifiedName);
746
+ get nativeInput() {
747
+ return this.querySelector("[data-sp-checkbox-native]");
998
748
  }
999
- hasAttribute(qualifiedName) {
1000
- if (qualifiedName === "id") {
1001
- return this.id !== "";
1002
- }
1003
- return super.hasAttribute(qualifiedName);
749
+ get isDisabled() {
750
+ return this.disabled || this.loading;
1004
751
  }
1005
- setAttribute(qualifiedName, value) {
1006
- if (qualifiedName === "id") {
1007
- this.id = value;
1008
- return;
1009
- }
1010
- super.setAttribute(qualifiedName, value);
1011
- }
1012
- removeAttribute(qualifiedName) {
1013
- if (qualifiedName === "id") {
1014
- this.id = "";
1015
- return;
1016
- }
1017
- super.removeAttribute(qualifiedName);
1018
- }
1019
- willUpdate(changedProperties) {
1020
- if (changedProperties.has("value") && this.value == null) {
1021
- this.value = "on";
1022
- }
1023
- }
1024
- get nativeInput() {
1025
- return this.querySelector("[data-sp-checkbox-native]");
1026
- }
1027
- get forwardedAriaLabel() {
1028
- const value = this.ariaLabel?.trim();
1029
- return value ? value : void 0;
1030
- }
1031
- get forwardedAriaLabelledBy() {
1032
- const value = this.ariaLabelledBy?.trim();
1033
- return value ? value : void 0;
1034
- }
1035
- get forwardedAriaDescribedBy() {
1036
- const value = this.ariaDescribedBy?.trim();
1037
- return value ? value : void 0;
752
+ get visibleLabelFallback() {
753
+ const trimmedLabel = this.label?.trim();
754
+ return trimmedLabel ? trimmedLabel : void 0;
1038
755
  }
1039
756
  handleInput(event) {
1040
757
  const input = event.currentTarget;
@@ -1051,17 +768,20 @@ var SpectreCheckboxElement = class extends LitElement {
1051
768
  this.nativeInput?.blur();
1052
769
  }
1053
770
  render() {
771
+ const labelContent = this.hasProjectedContent ? this.projectedContent : this.visibleLabelFallback ? html`<span class='sp-label' data-sp-checkbox-label-fallback>${this.visibleLabelFallback}</span>` : nothing;
1054
772
  return html`
1055
- <label>
773
+ <label data-sp-checkbox-label>
1056
774
  <input
775
+ aria-busy=${this.loading ? "true" : "false"}
1057
776
  aria-describedby=${ifDefined(this.forwardedAriaDescribedBy)}
1058
777
  aria-invalid=${ifDefined(this.invalid ? "true" : void 0)}
1059
778
  aria-label=${ifDefined(this.forwardedAriaLabel)}
1060
779
  aria-labelledby=${ifDefined(this.forwardedAriaLabelledBy)}
1061
780
  ?autofocus=${this.autofocus}
1062
781
  data-sp-checkbox-native
1063
- ?checked=${this.checked}
1064
- ?disabled=${this.disabled}
782
+ .checked=${live(this.checked)}
783
+ ?disabled=${this.isDisabled}
784
+ form=${ifDefined(this.form)}
1065
785
  id=${ifDefined(this.id || void 0)}
1066
786
  name=${ifDefined(this.name)}
1067
787
  ?required=${this.required}
@@ -1071,22 +791,23 @@ var SpectreCheckboxElement = class extends LitElement {
1071
791
  @change=${this.handleChange}
1072
792
  @input=${this.handleInput}
1073
793
  />
1074
- <span class='sp-label'>${this.label}</span>
794
+ <span class="sp-checkbox-indicator" data-sp-checkbox-indicator></span>
795
+ ${labelContent}
1075
796
  </label>
1076
797
  `;
1077
798
  }
1078
799
  };
1079
800
  SpectreCheckboxElement.properties = {
1080
- ariaLabel: { attribute: "aria-label", type: String },
1081
- ariaLabelledBy: { attribute: "aria-labelledby", type: String },
1082
- ariaDescribedBy: { attribute: "aria-describedby", type: String },
1083
801
  autofocus: { type: Boolean, reflect: true },
1084
802
  checked: { type: Boolean, reflect: true },
1085
803
  disabled: { type: Boolean, reflect: true },
804
+ form: { type: String },
1086
805
  invalid: { type: Boolean, reflect: true },
806
+ loading: { type: Boolean, reflect: true },
1087
807
  label: { type: String, reflect: true },
1088
- name: { type: String },
808
+ name: { type: String, reflect: true },
1089
809
  required: { type: Boolean, reflect: true },
810
+ success: { type: Boolean, reflect: true },
1090
811
  title: { type: String, reflect: true },
1091
812
  value: { type: String }
1092
813
  };
@@ -1098,70 +819,28 @@ function defineSpectreCheckbox(tagName = "sp-checkbox") {
1098
819
  customElements.define(tagName, SpectreCheckboxElement);
1099
820
  return SpectreCheckboxElement;
1100
821
  }
1101
- var SpectreRadioElement = class extends LitElement {
822
+ var SpectreRadioElement = class extends SpectreProjectableElement {
1102
823
  constructor() {
1103
824
  super(...arguments);
1104
- this.ariaLabel = null;
1105
- this.ariaLabelledBy = null;
1106
- this.ariaDescribedBy = null;
1107
825
  this.autofocus = false;
1108
826
  this.checked = false;
1109
827
  this.disabled = false;
1110
828
  this.invalid = false;
1111
- this.label = "";
829
+ this.loading = false;
1112
830
  this.required = false;
831
+ this.success = false;
1113
832
  this.title = "";
1114
833
  this.value = "on";
1115
834
  }
1116
- get id() {
1117
- return this._id ?? "";
1118
- }
1119
- set id(value) {
1120
- if ((this._id ?? "") === value) {
1121
- return;
1122
- }
1123
- this._id = value;
1124
- const host = this;
1125
- if (HTMLElement.prototype.hasAttribute.call(host, "id")) {
1126
- HTMLElement.prototype.removeAttribute.call(host, "id");
1127
- }
1128
- this.requestUpdate();
1129
- }
1130
- createRenderRoot() {
1131
- return this;
1132
- }
1133
- connectedCallback() {
1134
- super.connectedCallback();
1135
- const hostId = super.getAttribute("id");
1136
- if (hostId !== null) {
1137
- this.id = hostId;
1138
- }
1139
- }
1140
- getAttribute(qualifiedName) {
1141
- if (qualifiedName === "id") {
1142
- return this.id || null;
1143
- }
1144
- return super.getAttribute(qualifiedName);
1145
- }
1146
- hasAttribute(qualifiedName) {
1147
- if (qualifiedName === "id") {
1148
- return this.id !== "";
1149
- }
1150
- return super.hasAttribute(qualifiedName);
835
+ getContentContainer() {
836
+ return this.querySelector("[data-sp-radio-label]");
1151
837
  }
1152
- setAttribute(qualifiedName, value) {
1153
- if (qualifiedName === "id") {
1154
- this.id = value;
1155
- return;
1156
- }
1157
- super.setAttribute(qualifiedName, value);
1158
- }
1159
- removeAttribute(qualifiedName) {
1160
- if (qualifiedName === "id") {
1161
- this.id = "";
1162
- return;
838
+ isInternalNode(node) {
839
+ if (node.nodeType !== Node.ELEMENT_NODE) {
840
+ return false;
1163
841
  }
1164
- super.removeAttribute(qualifiedName);
842
+ const el = node;
843
+ return el.hasAttribute("data-sp-radio-label") || el.hasAttribute("data-sp-radio-native") || el.hasAttribute("data-sp-radio-label-fallback") || el.hasAttribute("data-sp-radio-indicator");
1165
844
  }
1166
845
  willUpdate(changedProperties) {
1167
846
  if (changedProperties.has("value") && this.value == null) {
@@ -1171,17 +850,12 @@ var SpectreRadioElement = class extends LitElement {
1171
850
  get nativeInput() {
1172
851
  return this.querySelector("[data-sp-radio-native]");
1173
852
  }
1174
- get forwardedAriaLabel() {
1175
- const value = this.ariaLabel?.trim();
1176
- return value ? value : void 0;
1177
- }
1178
- get forwardedAriaLabelledBy() {
1179
- const value = this.ariaLabelledBy?.trim();
1180
- return value ? value : void 0;
853
+ get isDisabled() {
854
+ return this.disabled || this.loading;
1181
855
  }
1182
- get forwardedAriaDescribedBy() {
1183
- const value = this.ariaDescribedBy?.trim();
1184
- return value ? value : void 0;
856
+ get visibleLabelFallback() {
857
+ const trimmedLabel = this.label?.trim();
858
+ return trimmedLabel ? trimmedLabel : void 0;
1185
859
  }
1186
860
  handleInput(event) {
1187
861
  const input = event.currentTarget;
@@ -1198,17 +872,20 @@ var SpectreRadioElement = class extends LitElement {
1198
872
  this.nativeInput?.blur();
1199
873
  }
1200
874
  render() {
875
+ const labelContent = this.hasProjectedContent ? this.projectedContent : this.visibleLabelFallback ? html`<span class='sp-label' data-sp-radio-label-fallback>${this.visibleLabelFallback}</span>` : nothing;
1201
876
  return html`
1202
- <label>
877
+ <label data-sp-radio-label>
1203
878
  <input
879
+ aria-busy=${this.loading ? "true" : "false"}
1204
880
  aria-describedby=${ifDefined(this.forwardedAriaDescribedBy)}
1205
881
  aria-invalid=${ifDefined(this.invalid ? "true" : void 0)}
1206
882
  aria-label=${ifDefined(this.forwardedAriaLabel)}
1207
883
  aria-labelledby=${ifDefined(this.forwardedAriaLabelledBy)}
1208
884
  ?autofocus=${this.autofocus}
1209
885
  data-sp-radio-native
1210
- ?checked=${this.checked}
1211
- ?disabled=${this.disabled}
886
+ .checked=${live(this.checked)}
887
+ ?disabled=${this.isDisabled}
888
+ form=${ifDefined(this.form)}
1212
889
  id=${ifDefined(this.id || void 0)}
1213
890
  name=${ifDefined(this.name)}
1214
891
  ?required=${this.required}
@@ -1218,22 +895,23 @@ var SpectreRadioElement = class extends LitElement {
1218
895
  @change=${this.handleChange}
1219
896
  @input=${this.handleInput}
1220
897
  />
1221
- <span class='sp-label'>${this.label}</span>
898
+ <span class="sp-radio-indicator" data-sp-radio-indicator></span>
899
+ ${labelContent}
1222
900
  </label>
1223
901
  `;
1224
902
  }
1225
903
  };
1226
904
  SpectreRadioElement.properties = {
1227
- ariaLabel: { attribute: "aria-label", type: String },
1228
- ariaLabelledBy: { attribute: "aria-labelledby", type: String },
1229
- ariaDescribedBy: { attribute: "aria-describedby", type: String },
1230
905
  autofocus: { type: Boolean, reflect: true },
1231
906
  checked: { type: Boolean, reflect: true },
1232
907
  disabled: { type: Boolean, reflect: true },
908
+ form: { type: String },
1233
909
  invalid: { type: Boolean, reflect: true },
910
+ loading: { type: Boolean, reflect: true },
1234
911
  label: { type: String, reflect: true },
1235
- name: { type: String },
912
+ name: { type: String, reflect: true },
1236
913
  required: { type: Boolean, reflect: true },
914
+ success: { type: Boolean, reflect: true },
1237
915
  title: { type: String, reflect: true },
1238
916
  value: { type: String }
1239
917
  };
@@ -1245,142 +923,48 @@ function defineSpectreRadio(tagName = "sp-radio") {
1245
923
  customElements.define(tagName, SpectreRadioElement);
1246
924
  return SpectreRadioElement;
1247
925
  }
1248
- var SpectreLabelElement = class extends LitElement {
926
+ var SpectreLabelElement = class extends SpectreProjectableElement {
1249
927
  constructor() {
1250
928
  super(...arguments);
1251
- this.projectedContent = [];
1252
- }
1253
- get id() {
1254
- return this._id ?? "";
1255
- }
1256
- set id(value) {
1257
- if ((this._id ?? "") === value) {
1258
- return;
1259
- }
1260
- this._id = value;
1261
- const host = this;
1262
- if (HTMLElement.prototype.hasAttribute.call(host, "id")) {
1263
- HTMLElement.prototype.removeAttribute.call(host, "id");
1264
- }
1265
- this.requestUpdate();
1266
- }
1267
- createRenderRoot() {
1268
- return this;
1269
- }
1270
- connectedCallback() {
1271
- super.connectedCallback();
1272
- const hostId = super.getAttribute("id");
1273
- if (hostId !== null) {
1274
- this.id = hostId;
1275
- }
1276
- this.syncProjectedContent();
1277
- this.startContentObserver();
1278
- }
1279
- disconnectedCallback() {
1280
- this.stopContentObserver();
1281
- super.disconnectedCallback();
1282
- }
1283
- getAttribute(qualifiedName) {
1284
- if (qualifiedName === "id") {
1285
- return this.id || null;
1286
- }
1287
- return super.getAttribute(qualifiedName);
1288
- }
1289
- hasAttribute(qualifiedName) {
1290
- if (qualifiedName === "id") {
1291
- return this.id !== "";
1292
- }
1293
- return super.hasAttribute(qualifiedName);
1294
- }
1295
- setAttribute(qualifiedName, value) {
1296
- if (qualifiedName === "id") {
1297
- this.id = value;
1298
- return;
1299
- }
1300
- super.setAttribute(qualifiedName, value);
1301
- }
1302
- removeAttribute(qualifiedName) {
1303
- if (qualifiedName === "id") {
1304
- this.id = "";
1305
- return;
1306
- }
1307
- super.removeAttribute(qualifiedName);
1308
- }
1309
- update(changedProperties) {
1310
- this.stopContentObserver();
1311
- super.update(changedProperties);
1312
- this.startContentObserver();
929
+ this.title = "";
1313
930
  }
1314
- get nativeLabel() {
931
+ getContentContainer() {
1315
932
  return this.querySelector("[data-sp-label-native]");
1316
933
  }
1317
- startContentObserver() {
1318
- if (this.contentObserver) {
1319
- return;
1320
- }
1321
- this.contentObserver = new MutationObserver((mutations) => {
1322
- const isInternalMovement = mutations.every((mutation) => {
1323
- return Array.from(mutation.removedNodes).every(
1324
- (node) => this.isInternalLabelNode(node) || this.contains(node)
1325
- ) && Array.from(mutation.addedNodes).every((node) => this.isInternalLabelNode(node));
1326
- });
1327
- if (isInternalMovement) {
1328
- return;
1329
- }
1330
- if (this.syncProjectedContent()) {
1331
- this.requestUpdate();
1332
- }
1333
- });
1334
- this.contentObserver.observe(this, { childList: true });
1335
- }
1336
- stopContentObserver() {
1337
- this.contentObserver?.disconnect();
1338
- this.contentObserver = void 0;
1339
- }
1340
- syncProjectedContent() {
1341
- const nextProjectedContent = [];
1342
- Array.from(this.childNodes).forEach((node) => {
1343
- if (this.isInternalLabelNode(node)) {
1344
- this.projectedContent.forEach((projectedNode) => {
1345
- if (projectedNode.parentNode !== this && this.contains(projectedNode)) {
1346
- nextProjectedContent.push(projectedNode);
1347
- }
1348
- });
1349
- return;
1350
- }
1351
- nextProjectedContent.push(node);
1352
- });
1353
- if (nextProjectedContent.length === this.projectedContent.length && nextProjectedContent.every((node, index) => node === this.projectedContent[index])) {
934
+ isInternalNode(node) {
935
+ if (node.nodeType !== Node.ELEMENT_NODE) {
1354
936
  return false;
1355
937
  }
1356
- this.projectedContent = nextProjectedContent;
1357
- return true;
1358
- }
1359
- isInternalLabelNode(node) {
1360
- return node === this.nativeLabel;
938
+ const el = node;
939
+ return el.hasAttribute("data-sp-label-native");
1361
940
  }
1362
941
  focus(options) {
1363
- this.nativeLabel?.focus(options);
942
+ this.getContentContainer()?.focus(options);
1364
943
  }
1365
944
  blur() {
1366
- this.nativeLabel?.blur();
945
+ this.getContentContainer()?.blur();
1367
946
  }
1368
947
  render() {
1369
948
  return html`
1370
949
  <label
950
+ aria-describedby=${ifDefined(this.forwardedAriaDescribedBy)}
951
+ aria-label=${ifDefined(this.forwardedAriaLabel)}
952
+ aria-labelledby=${ifDefined(this.forwardedAriaLabelledBy)}
1371
953
  class='sp-label'
1372
954
  data-sp-label-native
1373
955
  for=${ifDefined(this.htmlFor)}
1374
956
  id=${ifDefined(this.id || void 0)}
1375
957
  tabindex='-1'
958
+ title=${ifDefined(this.title || void 0)}
1376
959
  >
1377
- ${this.projectedContent.length > 0 ? this.projectedContent : nothing}
960
+ ${this.hasProjectedContent ? this.projectedContent : nothing}
1378
961
  </label>
1379
962
  `;
1380
963
  }
1381
964
  };
1382
965
  SpectreLabelElement.properties = {
1383
- htmlFor: { attribute: "for", type: String }
966
+ htmlFor: { attribute: "for", type: String, reflect: true },
967
+ title: { type: String, reflect: true }
1384
968
  };
1385
969
  function defineSpectreLabel(tagName = "sp-label") {
1386
970
  const existingElement = customElements.get(tagName);
@@ -1390,142 +974,28 @@ function defineSpectreLabel(tagName = "sp-label") {
1390
974
  customElements.define(tagName, SpectreLabelElement);
1391
975
  return SpectreLabelElement;
1392
976
  }
1393
- var SpectreFieldsetElement = class extends LitElement {
977
+ var SpectreFieldsetElement = class extends SpectreProjectableElement {
1394
978
  constructor() {
1395
979
  super(...arguments);
1396
- this.ariaLabel = null;
1397
- this.ariaLabelledBy = null;
1398
- this.ariaDescribedBy = null;
1399
980
  this.disabled = false;
1400
981
  this.legend = "";
1401
- this.projectedContent = [];
1402
- }
1403
- get id() {
1404
- return this._id ?? "";
1405
- }
1406
- set id(value) {
1407
- if ((this._id ?? "") === value) {
1408
- return;
1409
- }
1410
- this._id = value;
1411
- const host = this;
1412
- if (HTMLElement.prototype.hasAttribute.call(host, "id")) {
1413
- HTMLElement.prototype.removeAttribute.call(host, "id");
1414
- }
1415
- this.requestUpdate();
1416
- }
1417
- createRenderRoot() {
1418
- return this;
1419
- }
1420
- connectedCallback() {
1421
- super.connectedCallback();
1422
- const hostId = super.getAttribute("id");
1423
- if (hostId !== null) {
1424
- this.id = hostId;
1425
- }
1426
- this.syncProjectedContent();
1427
- this.startContentObserver();
1428
- }
1429
- disconnectedCallback() {
1430
- this.stopContentObserver();
1431
- super.disconnectedCallback();
1432
- }
1433
- getAttribute(qualifiedName) {
1434
- if (qualifiedName === "id") {
1435
- return this.id || null;
1436
- }
1437
- return super.getAttribute(qualifiedName);
1438
- }
1439
- hasAttribute(qualifiedName) {
1440
- if (qualifiedName === "id") {
1441
- return this.id !== "";
1442
- }
1443
- return super.hasAttribute(qualifiedName);
1444
- }
1445
- setAttribute(qualifiedName, value) {
1446
- if (qualifiedName === "id") {
1447
- this.id = value;
1448
- return;
1449
- }
1450
- super.setAttribute(qualifiedName, value);
1451
- }
1452
- removeAttribute(qualifiedName) {
1453
- if (qualifiedName === "id") {
1454
- this.id = "";
1455
- return;
1456
- }
1457
- super.removeAttribute(qualifiedName);
1458
- }
1459
- update(changedProperties) {
1460
- this.stopContentObserver();
1461
- super.update(changedProperties);
1462
- this.startContentObserver();
982
+ this.title = "";
1463
983
  }
1464
- get nativeFieldset() {
984
+ getContentContainer() {
1465
985
  return this.querySelector("[data-sp-fieldset-native]");
1466
986
  }
1467
- get forwardedAriaLabel() {
1468
- const value = this.ariaLabel?.trim();
1469
- return value ? value : void 0;
1470
- }
1471
- get forwardedAriaLabelledBy() {
1472
- const value = this.ariaLabelledBy?.trim();
1473
- return value ? value : void 0;
1474
- }
1475
- get forwardedAriaDescribedBy() {
1476
- const value = this.ariaDescribedBy?.trim();
1477
- return value ? value : void 0;
1478
- }
1479
- startContentObserver() {
1480
- if (this.contentObserver) {
1481
- return;
1482
- }
1483
- this.contentObserver = new MutationObserver((mutations) => {
1484
- const isInternalMovement = mutations.every((mutation) => {
1485
- return Array.from(mutation.removedNodes).every(
1486
- (node) => this.isInternalFieldsetNode(node) || this.contains(node)
1487
- ) && Array.from(mutation.addedNodes).every((node) => this.isInternalFieldsetNode(node));
1488
- });
1489
- if (isInternalMovement) {
1490
- return;
1491
- }
1492
- if (this.syncProjectedContent()) {
1493
- this.requestUpdate();
1494
- }
1495
- });
1496
- this.contentObserver.observe(this, { childList: true });
1497
- }
1498
- stopContentObserver() {
1499
- this.contentObserver?.disconnect();
1500
- this.contentObserver = void 0;
1501
- }
1502
- syncProjectedContent() {
1503
- const nextProjectedContent = [];
1504
- Array.from(this.childNodes).forEach((node) => {
1505
- if (this.isInternalFieldsetNode(node)) {
1506
- this.projectedContent.forEach((projectedNode) => {
1507
- if (projectedNode.parentNode !== this && this.contains(projectedNode)) {
1508
- nextProjectedContent.push(projectedNode);
1509
- }
1510
- });
1511
- return;
1512
- }
1513
- nextProjectedContent.push(node);
1514
- });
1515
- if (nextProjectedContent.length === this.projectedContent.length && nextProjectedContent.every((node, index) => node === this.projectedContent[index])) {
987
+ isInternalNode(node) {
988
+ if (node.nodeType !== Node.ELEMENT_NODE) {
1516
989
  return false;
1517
990
  }
1518
- this.projectedContent = nextProjectedContent;
1519
- return true;
1520
- }
1521
- isInternalFieldsetNode(node) {
1522
- return node === this.nativeFieldset;
991
+ const el = node;
992
+ return el.hasAttribute("data-sp-fieldset-native") || el.hasAttribute("data-sp-fieldset-legend");
1523
993
  }
1524
994
  focus(options) {
1525
- this.nativeFieldset?.focus(options);
995
+ this.getContentContainer()?.focus(options);
1526
996
  }
1527
997
  blur() {
1528
- this.nativeFieldset?.blur();
998
+ this.getContentContainer()?.blur();
1529
999
  }
1530
1000
  render() {
1531
1001
  return html`
@@ -1535,20 +1005,23 @@ var SpectreFieldsetElement = class extends LitElement {
1535
1005
  aria-labelledby=${ifDefined(this.forwardedAriaLabelledBy)}
1536
1006
  data-sp-fieldset-native
1537
1007
  ?disabled=${this.disabled}
1008
+ form=${ifDefined(this.form)}
1538
1009
  id=${ifDefined(this.id || void 0)}
1010
+ name=${ifDefined(this.name)}
1011
+ title=${ifDefined(this.title || void 0)}
1539
1012
  >
1540
- ${this.legend ? html`<legend class='sp-label'>${this.legend}</legend>` : nothing}
1541
- ${this.projectedContent.length > 0 ? this.projectedContent : nothing}
1013
+ ${this.legend ? html`<legend class='sp-label' data-sp-fieldset-legend>${this.legend}</legend>` : nothing}
1014
+ ${this.hasProjectedContent ? this.projectedContent : nothing}
1542
1015
  </fieldset>
1543
1016
  `;
1544
1017
  }
1545
1018
  };
1546
1019
  SpectreFieldsetElement.properties = {
1547
- ariaLabel: { attribute: "aria-label", type: String },
1548
- ariaLabelledBy: { attribute: "aria-labelledby", type: String },
1549
- ariaDescribedBy: { attribute: "aria-describedby", type: String },
1550
1020
  disabled: { type: Boolean, reflect: true },
1551
- legend: { type: String, reflect: true }
1021
+ form: { type: String },
1022
+ legend: { type: String, reflect: true },
1023
+ name: { type: String, reflect: true },
1024
+ title: { type: String, reflect: true }
1552
1025
  };
1553
1026
  function defineSpectreFieldset(tagName = "sp-fieldset") {
1554
1027
  const existingElement = customElements.get(tagName);
@@ -1571,6 +1044,6 @@ function defineSpectreComponents() {
1571
1044
  defineSpectreFieldset();
1572
1045
  }
1573
1046
 
1574
- export { SpectreButtonElement, SpectreCheckboxElement, SpectreFieldsetElement, SpectreInputElement, SpectreLabelElement, SpectreRadioElement, SpectreSelectElement, SpectreTextareaElement, defineSpectreButton, defineSpectreCheckbox, defineSpectreComponents, defineSpectreFieldset, defineSpectreInput, defineSpectreLabel, defineSpectreRadio, defineSpectreSelect, defineSpectreTextarea, spectreButtonSizes, spectreButtonTypes, spectreButtonVariants, spectreInputSizes, spectreInputTypes, spectreSelectSizes };
1047
+ export { SpectreButtonElement, SpectreCheckboxElement, SpectreFieldsetElement, SpectreInputElement, SpectreLabelElement, SpectreRadioElement, SpectreSelectElement, SpectreTextareaElement, defineSpectreButton, defineSpectreCheckbox, defineSpectreComponents, defineSpectreFieldset, defineSpectreInput, defineSpectreLabel, defineSpectreRadio, defineSpectreSelect, defineSpectreTextarea, spectreButtonSizes, spectreButtonTypes, spectreButtonVariants, spectreInputSizes, spectreInputTypes };
1575
1048
  //# sourceMappingURL=index.js.map
1576
1049
  //# sourceMappingURL=index.js.map