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