@solid-design-system/components 1.19.0 → 1.21.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 (134) hide show
  1. package/dist/components/es/accordion-group.js +1 -1
  2. package/dist/components/es/accordion.js +1 -1
  3. package/dist/components/es/brandshape.js +1 -1
  4. package/dist/components/es/button.js +1 -1
  5. package/dist/components/es/carousel.js +2 -2
  6. package/dist/components/es/drawer.js +1 -1
  7. package/dist/components/es/dropdown.js +1 -1
  8. package/dist/components/es/form.js +1 -0
  9. package/dist/components/es/icon.js +3 -3
  10. package/dist/components/es/if-defined.js +2 -2
  11. package/dist/components/es/link.js +1 -1
  12. package/dist/components/es/lit-element.js +4 -4
  13. package/dist/components/es/navigation-item.js +2 -2
  14. package/dist/components/es/popup.js +1 -1
  15. package/dist/components/es/query-assigned-elements.js +6 -0
  16. package/dist/components/es/query.js +7 -2
  17. package/dist/components/es/radio-group.js +1 -0
  18. package/dist/components/es/radio.js +1 -0
  19. package/dist/components/es/solid-components2.js +1 -1
  20. package/dist/components/es/solid-element.js +2 -12
  21. package/dist/components/es/state.js +1 -1
  22. package/dist/components/es/static.js +1 -1
  23. package/dist/components/es/tag.js +1 -1
  24. package/dist/components/es/teaser.js +1 -1
  25. package/dist/components/es/video.js +1 -1
  26. package/dist/components/umd/solid-components.js +18 -18
  27. package/dist/custom-elements.json +1 -1
  28. package/dist/package/_components/button-group/button-group.d.ts +19 -0
  29. package/dist/package/_components/button-group/button-group.js +76 -0
  30. package/dist/package/_components/button-group/button-group.styles.d.ts +2 -0
  31. package/dist/package/_components/button-group/button-group.styles.js +6 -0
  32. package/dist/package/components/button/button.d.ts +4 -0
  33. package/dist/package/components/button/button.js +25 -3
  34. package/dist/package/components/radio/radio.d.ts +27 -0
  35. package/dist/package/components/radio/radio.js +130 -0
  36. package/dist/package/components/radio-group/radio-group.d.ts +52 -0
  37. package/dist/package/components/radio-group/radio-group.js +321 -0
  38. package/dist/package/internal/form.d.ts +7 -1
  39. package/dist/package/internal/form.js +110 -49
  40. package/dist/package/internal/solid-element.d.ts +2 -0
  41. package/dist/package/node_modules/.pnpm/{@shoelace-style_localize@3.1.0 → @shoelace-style_localize@3.1.2}/node_modules/@shoelace-style/localize/dist/index.js +1 -1
  42. package/dist/package/solid-components.d.ts +2 -0
  43. package/dist/package/solid-components.js +12 -8
  44. package/dist/package/styles/tailwind.css.js +1 -1
  45. package/dist/package/translations/en.js +1 -1
  46. package/dist/package/utilities/localize.js +1 -1
  47. package/dist/versioned-components/es/accordion-group.js +1 -1
  48. package/dist/versioned-components/es/accordion.js +1 -1
  49. package/dist/versioned-components/es/badge.js +1 -1
  50. package/dist/versioned-components/es/brandshape.js +1 -1
  51. package/dist/versioned-components/es/button.js +1 -1
  52. package/dist/versioned-components/es/carousel-item.js +1 -1
  53. package/dist/versioned-components/es/carousel.js +3 -3
  54. package/dist/versioned-components/es/divider.js +1 -1
  55. package/dist/versioned-components/es/drawer.js +1 -1
  56. package/dist/versioned-components/es/dropdown.js +1 -1
  57. package/dist/versioned-components/es/form.js +1 -0
  58. package/dist/versioned-components/es/icon.js +3 -3
  59. package/dist/versioned-components/es/if-defined.js +2 -2
  60. package/dist/versioned-components/es/include.js +1 -1
  61. package/dist/versioned-components/es/link.js +1 -1
  62. package/dist/versioned-components/es/lit-element.js +4 -4
  63. package/dist/versioned-components/es/navigation-item.js +2 -2
  64. package/dist/versioned-components/es/popup.js +1 -1
  65. package/dist/versioned-components/es/query-assigned-elements.js +6 -0
  66. package/dist/versioned-components/es/query.js +7 -2
  67. package/dist/versioned-components/es/radio-group.js +1 -0
  68. package/dist/versioned-components/es/radio.js +1 -0
  69. package/dist/versioned-components/es/solid-components2.js +1 -1
  70. package/dist/versioned-components/es/solid-element.js +2 -12
  71. package/dist/versioned-components/es/spinner.js +1 -1
  72. package/dist/versioned-components/es/state.js +1 -1
  73. package/dist/versioned-components/es/static.js +1 -1
  74. package/dist/versioned-components/es/tag.js +1 -1
  75. package/dist/versioned-components/es/teaser.js +1 -1
  76. package/dist/versioned-components/es/video.js +1 -1
  77. package/dist/versioned-package/_components/button-group/button-group.d.ts +19 -0
  78. package/dist/versioned-package/_components/button-group/button-group.js +76 -0
  79. package/dist/versioned-package/_components/button-group/button-group.styles.d.ts +2 -0
  80. package/dist/versioned-package/_components/button-group/button-group.styles.js +6 -0
  81. package/dist/versioned-package/components/accordion/accordion.d.ts +1 -1
  82. package/dist/versioned-package/components/accordion/accordion.js +2 -2
  83. package/dist/versioned-package/components/accordion-group/accordion-group.d.ts +1 -1
  84. package/dist/versioned-package/components/accordion-group/accordion-group.js +3 -3
  85. package/dist/versioned-package/components/badge/badge.d.ts +1 -1
  86. package/dist/versioned-package/components/badge/badge.js +1 -1
  87. package/dist/versioned-package/components/brandshape/brandshape.d.ts +1 -1
  88. package/dist/versioned-package/components/brandshape/brandshape.js +1 -1
  89. package/dist/versioned-package/components/button/button.d.ts +5 -1
  90. package/dist/versioned-package/components/button/button.js +29 -7
  91. package/dist/versioned-package/components/carousel/carousel.d.ts +1 -1
  92. package/dist/versioned-package/components/carousel/carousel.js +6 -6
  93. package/dist/versioned-package/components/carousel-item/carousel-item.d.ts +1 -1
  94. package/dist/versioned-package/components/carousel-item/carousel-item.js +1 -1
  95. package/dist/versioned-package/components/divider/divider.d.ts +1 -1
  96. package/dist/versioned-package/components/divider/divider.js +2 -2
  97. package/dist/versioned-package/components/drawer/drawer.d.ts +1 -1
  98. package/dist/versioned-package/components/drawer/drawer.js +2 -2
  99. package/dist/versioned-package/components/dropdown/dropdown.d.ts +1 -1
  100. package/dist/versioned-package/components/dropdown/dropdown.js +6 -6
  101. package/dist/versioned-package/components/icon/icon.d.ts +1 -1
  102. package/dist/versioned-package/components/icon/icon.js +1 -1
  103. package/dist/versioned-package/components/include/include.d.ts +1 -1
  104. package/dist/versioned-package/components/include/include.js +1 -1
  105. package/dist/versioned-package/components/link/link.d.ts +1 -1
  106. package/dist/versioned-package/components/link/link.js +2 -2
  107. package/dist/versioned-package/components/navigation-item/navigation-item.d.ts +1 -1
  108. package/dist/versioned-package/components/navigation-item/navigation-item.js +3 -3
  109. package/dist/versioned-package/components/popup/popup.d.ts +1 -1
  110. package/dist/versioned-package/components/popup/popup.js +1 -1
  111. package/dist/versioned-package/components/radio/radio.d.ts +27 -0
  112. package/dist/versioned-package/components/radio/radio.js +130 -0
  113. package/dist/versioned-package/components/radio-group/radio-group.d.ts +52 -0
  114. package/dist/versioned-package/components/radio-group/radio-group.js +321 -0
  115. package/dist/versioned-package/components/spinner/spinner.d.ts +1 -1
  116. package/dist/versioned-package/components/spinner/spinner.js +1 -1
  117. package/dist/versioned-package/components/tag/tag.d.ts +1 -1
  118. package/dist/versioned-package/components/tag/tag.js +2 -2
  119. package/dist/versioned-package/components/teaser/teaser.js +1 -1
  120. package/dist/versioned-package/components/video/video.d.ts +1 -1
  121. package/dist/versioned-package/components/video/video.js +2 -2
  122. package/dist/versioned-package/internal/form.d.ts +7 -1
  123. package/dist/versioned-package/internal/form.js +110 -49
  124. package/dist/versioned-package/internal/solid-element.d.ts +2 -0
  125. package/dist/versioned-package/node_modules/.pnpm/{@shoelace-style_localize@3.1.0 → @shoelace-style_localize@3.1.2}/node_modules/@shoelace-style/localize/dist/index.js +1 -1
  126. package/dist/versioned-package/solid-components.d.ts +2 -0
  127. package/dist/versioned-package/solid-components.js +12 -8
  128. package/dist/versioned-package/styles/tailwind.css.js +1 -1
  129. package/dist/versioned-package/translations/en.js +1 -1
  130. package/dist/versioned-package/utilities/localize.js +1 -1
  131. package/dist/versioned-styles/solid-styles.css +1 -1
  132. package/dist/vscode.html-custom-data.json +201 -21
  133. package/dist/web-types.json +910 -122
  134. package/package.json +51 -56
@@ -0,0 +1,321 @@
1
+ import { css, html } from "lit";
2
+ import { customElement } from "../../internal/register-custom-element.js";
3
+ import { FormControlController, customErrorValidityState, valueMissingValidityState, validValidityState } from "../../internal/form.js";
4
+ import { HasSlotController } from "../../internal/slot.js";
5
+ import { query, state, property } from "lit/decorators.js";
6
+ import { watch } from "../../internal/watch.js";
7
+ import componentStyles from "../../styles/component.styles.js";
8
+ import cx from "classix";
9
+ import SdButtonGroup from "../../_components/button-group/button-group.js";
10
+ import SolidElement from "../../internal/solid-element.js";
11
+ var __defProp = Object.defineProperty;
12
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
+ var __decorateClass = (decorators, target, key, kind) => {
14
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
15
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
16
+ if (decorator = decorators[i])
17
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
18
+ if (kind && result)
19
+ __defProp(target, key, result);
20
+ return result;
21
+ };
22
+ let SdRadioGroup = class extends SolidElement {
23
+ constructor() {
24
+ super(...arguments);
25
+ this.formControlController = new FormControlController(this);
26
+ this.hasSlotController = new HasSlotController(this, "label", "error-text");
27
+ this.customValidityMessage = "";
28
+ this.hasButtonGroup = false;
29
+ this.defaultValue = "";
30
+ this.invalid = false;
31
+ this.errorText = "";
32
+ this.label = "";
33
+ this.name = "option";
34
+ this.value = "";
35
+ this.size = "lg";
36
+ this.form = "";
37
+ this.required = false;
38
+ this.orientation = "vertical";
39
+ }
40
+ /** Gets the validity state object */
41
+ get validity() {
42
+ const isRequiredAndEmpty = this.required && !this.value;
43
+ const hasCustomValidityMessage = this.customValidityMessage !== "";
44
+ if (hasCustomValidityMessage) {
45
+ this.invalid = true;
46
+ return customErrorValidityState;
47
+ } else if (isRequiredAndEmpty) {
48
+ this.invalid = true;
49
+ return valueMissingValidityState;
50
+ }
51
+ this.invalid = false;
52
+ return validValidityState;
53
+ }
54
+ /** Gets the validation message */
55
+ get validationMessage() {
56
+ const isRequiredAndEmpty = this.required && !this.value;
57
+ const hasCustomValidityMessage = this.customValidityMessage !== "";
58
+ if (hasCustomValidityMessage) {
59
+ console.log("this.customValidityMessage", this.customValidityMessage);
60
+ return this.customValidityMessage;
61
+ } else if (isRequiredAndEmpty) {
62
+ console.log("this.validationInput.validationMessage", this.validationInput);
63
+ return this.validationInput.validationMessage;
64
+ }
65
+ return "";
66
+ }
67
+ connectedCallback() {
68
+ super.connectedCallback();
69
+ this.defaultValue = this.value;
70
+ }
71
+ firstUpdated() {
72
+ this.formControlController.updateValidity();
73
+ }
74
+ getAllRadios() {
75
+ return [...this.querySelectorAll("sd-radio, sd-radio-button")];
76
+ }
77
+ handleRadioClick(event) {
78
+ const target = event.target.closest("sd-radio, sd-radio-button");
79
+ const radios = this.getAllRadios();
80
+ const oldValue = this.value;
81
+ if (target.disabled) {
82
+ return;
83
+ }
84
+ this.value = target.value;
85
+ radios.forEach((radio) => radio.checked = radio === target);
86
+ if (this.value !== oldValue) {
87
+ this.emit("sd-change");
88
+ this.emit("sd-input");
89
+ }
90
+ }
91
+ handleKeyDown(event) {
92
+ if (!["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", " "].includes(event.key)) {
93
+ return;
94
+ }
95
+ const radios = this.getAllRadios().filter((radio) => !radio.disabled);
96
+ const checkedRadio = radios.find((radio) => radio.checked) ?? radios[0];
97
+ const incr = event.key === " " ? 0 : ["ArrowUp", "ArrowLeft"].includes(event.key) ? -1 : 1;
98
+ const oldValue = this.value;
99
+ let index = radios.indexOf(checkedRadio) + incr;
100
+ if (index < 0) {
101
+ index = radios.length - 1;
102
+ }
103
+ if (index > radios.length - 1) {
104
+ index = 0;
105
+ }
106
+ this.getAllRadios().forEach((radio) => {
107
+ radio.checked = false;
108
+ if (!this.hasButtonGroup) {
109
+ radio.tabIndex = -1;
110
+ }
111
+ });
112
+ this.value = radios[index].value;
113
+ radios[index].checked = true;
114
+ if (!this.hasButtonGroup) {
115
+ radios[index].tabIndex = 0;
116
+ radios[index].focus();
117
+ } else {
118
+ radios[index].shadowRoot.querySelector("button").focus();
119
+ }
120
+ if (this.value !== oldValue) {
121
+ this.emit("sd-change");
122
+ this.emit("sd-input");
123
+ }
124
+ event.preventDefault();
125
+ }
126
+ handleLabelClick() {
127
+ const radios = this.getAllRadios();
128
+ const checked = radios.find((radio) => radio.checked);
129
+ const radioToFocus = checked || radios[0];
130
+ if (radioToFocus) {
131
+ radioToFocus.focus();
132
+ }
133
+ }
134
+ handleInvalid(event) {
135
+ this.formControlController.setValidity(false);
136
+ this.formControlController.emitInvalidEvent(event);
137
+ }
138
+ async syncRadioElements() {
139
+ var _a, _b;
140
+ const radios = this.getAllRadios();
141
+ await Promise.all(
142
+ // Sync the checked state and size
143
+ radios.map(async (radio) => {
144
+ await radio.updateComplete;
145
+ radio.checked = radio.value === this.value;
146
+ radio.size = this.size;
147
+ radio.invalid = this.invalid;
148
+ })
149
+ );
150
+ this.hasButtonGroup = radios.some((radio) => radio.tagName.toLowerCase() === "sd-radio-button");
151
+ if (!radios.some((radio) => radio.checked)) {
152
+ if (this.hasButtonGroup) {
153
+ const buttonRadio = (_a = radios[0].shadowRoot) == null ? void 0 : _a.querySelector("button");
154
+ if (buttonRadio) {
155
+ buttonRadio.tabIndex = 0;
156
+ }
157
+ } else {
158
+ radios[0].tabIndex = 0;
159
+ }
160
+ }
161
+ if (this.hasButtonGroup) {
162
+ const buttonGroup = (_b = this.shadowRoot) == null ? void 0 : _b.querySelector("sd-button-group");
163
+ if (buttonGroup) {
164
+ buttonGroup.disableRole = true;
165
+ }
166
+ }
167
+ }
168
+ syncRadios() {
169
+ if (customElements.get("sd-radio") && customElements.get("sd-radio-button")) {
170
+ this.syncRadioElements();
171
+ return;
172
+ }
173
+ if (customElements.get("sd-radio")) {
174
+ this.syncRadioElements();
175
+ } else {
176
+ customElements.whenDefined("sd-radio").then(() => this.syncRadios());
177
+ }
178
+ if (customElements.get("sd-radio-button")) {
179
+ this.syncRadioElements();
180
+ } else {
181
+ customElements.whenDefined("sd-radio-button").then(() => this.syncRadios());
182
+ }
183
+ }
184
+ updateCheckedRadio() {
185
+ const radios = this.getAllRadios();
186
+ radios.forEach((radio) => radio.checked = radio.value === this.value);
187
+ this.formControlController.setValidity(this.validity.valid);
188
+ }
189
+ handleSizeChange() {
190
+ this.syncRadios();
191
+ }
192
+ handleInvalidChange() {
193
+ this.syncRadios();
194
+ }
195
+ handleValueChange() {
196
+ if (this.hasUpdated) {
197
+ this.updateCheckedRadio();
198
+ this.reportValidity();
199
+ }
200
+ }
201
+ /** Checks for validity but does not show a validation message. Returns `true` when valid and `false` when invalid. */
202
+ checkValidity() {
203
+ const isRequiredAndEmpty = this.required && !this.value;
204
+ const hasCustomValidityMessage = this.customValidityMessage !== "";
205
+ if (isRequiredAndEmpty || hasCustomValidityMessage) {
206
+ this.formControlController.emitInvalidEvent();
207
+ return false;
208
+ }
209
+ return true;
210
+ }
211
+ /** Gets the associated form, if one exists. */
212
+ getForm() {
213
+ return this.formControlController.getForm();
214
+ }
215
+ /** Checks for validity and shows the browser's validation message if the control is invalid. */
216
+ // TODO: https://github.com/solid-design-system/solid/issues/501
217
+ reportValidity() {
218
+ const isValid = this.validity.valid;
219
+ this.errorText = this.customValidityMessage || isValid ? "" : this.validationInput.validationMessage;
220
+ this.formControlController.setValidity(isValid);
221
+ this.validationInput.hidden = true;
222
+ clearTimeout(this.validationTimeout);
223
+ if (!isValid) {
224
+ this.validationInput.hidden = false;
225
+ this.validationInput.reportValidity();
226
+ this.validationTimeout = setTimeout(() => this.validationInput.hidden = true, 1e4);
227
+ }
228
+ return isValid;
229
+ }
230
+ /** Sets a custom validation message. Pass an empty string to restore validity. */
231
+ setCustomValidity(message = "") {
232
+ this.customValidityMessage = message;
233
+ this.errorText = message;
234
+ this.validationInput.setCustomValidity(message);
235
+ this.formControlController.updateValidity();
236
+ }
237
+ render() {
238
+ const hasLabelSlot = this.hasSlotController.test("label");
239
+ const hasErrorTextSlot = this.hasSlotController.test("error-text");
240
+ const hasLabel = this.label ? true : !!hasLabelSlot;
241
+ const hasErrorText = this.errorText ? true : !!hasErrorTextSlot;
242
+ const defaultSlot = html`<slot @slotchange="${this.syncRadios}" @click="${this.handleRadioClick}" @keydown="${this.handleKeyDown}"></slot>`;
243
+ return html`<fieldset part="form-control" class="${cx(
244
+ "form-control form-control--radio-group border-0 p-0 m-0",
245
+ hasLabel && "form-control--has-label",
246
+ hasErrorText && "text-error",
247
+ {
248
+ /* sizes, fonts */
249
+ sm: "text-sm",
250
+ lg: "text-base"
251
+ }[this.size]
252
+ )}" role="radiogroup" aria-labelledby="label" aria-errormessage="error-text"><label part="form-control-label" id="label" class="form-control__label mb-2 hidden p-0 font-bold leading-normal text-black" aria-hidden="${!hasLabel}" @click="${this.handleLabelClick}"><slot name="label">${this.label}</slot></label><div part="form-control-input" class="${cx(
253
+ "form-control-input flex",
254
+ this.invalid && "form-control-input--invalid text-error",
255
+ {
256
+ vertical: "form-control-input--vertical flex-col",
257
+ horizontal: "form-control-input--horizontal flex-row"
258
+ }[this.orientation]
259
+ )}"><div class="sr-only"><div id="error-message" aria-live="assertive">${this.errorText}</div><label class="radio-group__validation"><input type="text" class="radio-group__validation-input" ?required="${this.required}" tabindex="-1" hidden @invalid="${this.handleInvalid}"></label></div>${defaultSlot}</div></fieldset>`;
260
+ }
261
+ };
262
+ SdRadioGroup.dependencies = { "sd-button-group": SdButtonGroup };
263
+ SdRadioGroup.styles = [
264
+ componentStyles,
265
+ SolidElement.styles,
266
+ css`:host{display:block}.form-control-input--vertical ::slotted(sd-radio){margin-bottom:8px;display:flex}.form-control-input--vertical ::slotted(sd-radio:last-of-type){margin-bottom:0}.form-control-input--horizontal ::slotted(sd-radio){margin-right:24px}.form-control-input--horizontal ::slotted(sd-radio:last-of-type){margin-right:0}.form-control--has-label .form-control__label{display:flex}:host([required]) .form-control--has-label .form-control__label::after{content:'*';margin-left:2px}`
267
+ ];
268
+ __decorateClass([
269
+ query("slot:not([name])")
270
+ ], SdRadioGroup.prototype, "defaultSlot", 2);
271
+ __decorateClass([
272
+ query(".radio-group__validation-input")
273
+ ], SdRadioGroup.prototype, "validationInput", 2);
274
+ __decorateClass([
275
+ state()
276
+ ], SdRadioGroup.prototype, "hasButtonGroup", 2);
277
+ __decorateClass([
278
+ state()
279
+ ], SdRadioGroup.prototype, "defaultValue", 2);
280
+ __decorateClass([
281
+ state()
282
+ ], SdRadioGroup.prototype, "invalid", 2);
283
+ __decorateClass([
284
+ state()
285
+ ], SdRadioGroup.prototype, "errorText", 2);
286
+ __decorateClass([
287
+ property()
288
+ ], SdRadioGroup.prototype, "label", 2);
289
+ __decorateClass([
290
+ property()
291
+ ], SdRadioGroup.prototype, "name", 2);
292
+ __decorateClass([
293
+ property({ reflect: true })
294
+ ], SdRadioGroup.prototype, "value", 2);
295
+ __decorateClass([
296
+ property({ reflect: true })
297
+ ], SdRadioGroup.prototype, "size", 2);
298
+ __decorateClass([
299
+ property({ reflect: true })
300
+ ], SdRadioGroup.prototype, "form", 2);
301
+ __decorateClass([
302
+ property({ type: Boolean, reflect: true })
303
+ ], SdRadioGroup.prototype, "required", 2);
304
+ __decorateClass([
305
+ property({ reflect: true })
306
+ ], SdRadioGroup.prototype, "orientation", 2);
307
+ __decorateClass([
308
+ watch("size", { waitUntilFirstUpdate: true })
309
+ ], SdRadioGroup.prototype, "handleSizeChange", 1);
310
+ __decorateClass([
311
+ watch("invalid", { waitUntilFirstUpdate: true })
312
+ ], SdRadioGroup.prototype, "handleInvalidChange", 1);
313
+ __decorateClass([
314
+ watch("value")
315
+ ], SdRadioGroup.prototype, "handleValueChange", 1);
316
+ SdRadioGroup = __decorateClass([
317
+ customElement("sd-radio-group")
318
+ ], SdRadioGroup);
319
+ export {
320
+ SdRadioGroup as default
321
+ };
@@ -10,6 +10,7 @@ export interface FormControlControllerOptions {
10
10
  disabled: (input: SolidFormControl) => boolean;
11
11
  reportValidity: (input: SolidFormControl) => boolean;
12
12
  setValue: (input: SolidFormControl, value: unknown) => void;
13
+ assumeInteractionOn: string[];
13
14
  }
14
15
  export declare class FormControlController implements ReactiveController {
15
16
  host: SolidFormControl & ReactiveControllerHost;
@@ -24,12 +25,17 @@ export declare class FormControlController implements ReactiveController {
24
25
  private handleFormData;
25
26
  private handleFormSubmit;
26
27
  private handleFormReset;
27
- private handleUserInput;
28
+ private handleInteraction;
28
29
  private reportFormValidity;
29
30
  private setUserInteracted;
30
31
  private doAction;
32
+ getForm(): HTMLFormElement | null;
31
33
  reset(invoker?: HTMLInputElement | SdButton): void;
32
34
  submit(invoker?: HTMLInputElement | SdButton): void;
33
35
  setValidity(isValid: boolean): void;
34
36
  updateValidity(): void;
37
+ emitInvalidEvent(originalInvalidEvent?: Event): void;
35
38
  }
39
+ export declare const validValidityState: ValidityState;
40
+ export declare const valueMissingValidityState: ValidityState;
41
+ export declare const customErrorValidityState: ValidityState;
@@ -1,8 +1,52 @@
1
1
  const formCollections = /* @__PURE__ */ new WeakMap();
2
- const userInteractedControls = /* @__PURE__ */ new WeakMap();
3
2
  const reportValidityOverloads = /* @__PURE__ */ new WeakMap();
3
+ const userInteractedControls = /* @__PURE__ */ new WeakMap();
4
+ const interactions = /* @__PURE__ */ new WeakMap();
4
5
  class FormControlController {
5
6
  constructor(host, options) {
7
+ this.handleFormData = (event) => {
8
+ const disabled = this.options.disabled(this.host);
9
+ const name = this.options.name(this.host);
10
+ const value = this.options.value(this.host);
11
+ const isButton = this.host.tagName.toLowerCase() === "sd-button";
12
+ if (!disabled && !isButton && typeof name === "string" && name.length > 0 && typeof value !== "undefined") {
13
+ if (Array.isArray(value)) {
14
+ value.forEach((val) => {
15
+ event.formData.append(name, val.toString());
16
+ });
17
+ } else {
18
+ event.formData.append(name, value.toString());
19
+ }
20
+ }
21
+ };
22
+ this.handleFormSubmit = (event) => {
23
+ var _a;
24
+ const disabled = this.options.disabled(this.host);
25
+ const reportValidity = this.options.reportValidity;
26
+ if (this.form && !this.form.noValidate) {
27
+ (_a = formCollections.get(this.form)) == null ? void 0 : _a.forEach((control) => {
28
+ this.setUserInteracted(control, true);
29
+ });
30
+ }
31
+ if (this.form && !this.form.noValidate && !disabled && !reportValidity(this.host)) {
32
+ event.preventDefault();
33
+ event.stopImmediatePropagation();
34
+ }
35
+ };
36
+ this.handleFormReset = () => {
37
+ this.options.setValue(this.host, this.options.defaultValue(this.host));
38
+ this.setUserInteracted(this.host, false);
39
+ interactions.set(this.host, []);
40
+ };
41
+ this.handleInteraction = (event) => {
42
+ const emittedEvents = interactions.get(this.host);
43
+ if (!emittedEvents.includes(event.type)) {
44
+ emittedEvents.push(event.type);
45
+ }
46
+ if (emittedEvents.length === this.options.assumeInteractionOn.length) {
47
+ this.setUserInteracted(this.host, true);
48
+ }
49
+ };
6
50
  (this.host = host).addController(this);
7
51
  this.options = {
8
52
  form: (input) => {
@@ -21,26 +65,29 @@ class FormControlController {
21
65
  disabled: (input) => input.disabled ?? false,
22
66
  reportValidity: (input) => typeof input.reportValidity === "function" ? input.reportValidity() : true,
23
67
  setValue: (input, value) => input.value = value,
68
+ assumeInteractionOn: ["sd-input"],
24
69
  ...options
25
70
  };
26
- this.handleFormData = this.handleFormData.bind(this);
27
- this.handleFormSubmit = this.handleFormSubmit.bind(this);
28
- this.handleFormReset = this.handleFormReset.bind(this);
29
- this.reportFormValidity = this.reportFormValidity.bind(this);
30
- this.handleUserInput = this.handleUserInput.bind(this);
31
71
  }
32
72
  hostConnected() {
33
73
  const form = this.options.form(this.host);
34
74
  if (form) {
35
75
  this.attachForm(form);
36
76
  }
37
- this.host.addEventListener("sd-input", this.handleUserInput);
77
+ interactions.set(this.host, []);
78
+ this.options.assumeInteractionOn.forEach((event) => {
79
+ this.host.addEventListener(event, this.handleInteraction);
80
+ });
38
81
  }
39
82
  hostDisconnected() {
40
83
  this.detachForm();
41
- this.host.removeEventListener("sd-input", this.handleUserInput);
84
+ interactions.delete(this.host);
85
+ this.options.assumeInteractionOn.forEach((event) => {
86
+ this.host.removeEventListener(event, this.handleInteraction);
87
+ });
42
88
  }
43
89
  hostUpdated() {
90
+ var _a;
44
91
  const form = this.options.form(this.host);
45
92
  if (!form) {
46
93
  this.detachForm();
@@ -50,7 +97,7 @@ class FormControlController {
50
97
  this.attachForm(form);
51
98
  }
52
99
  if (this.host.hasUpdated) {
53
- this.setValidity(this.host.checkValidity());
100
+ this.setValidity((_a = this.host) == null ? void 0 : _a.validity.valid);
54
101
  }
55
102
  }
56
103
  attachForm(form) {
@@ -86,43 +133,6 @@ class FormControlController {
86
133
  }
87
134
  this.form = void 0;
88
135
  }
89
- handleFormData(event) {
90
- const disabled = this.options.disabled(this.host);
91
- const name = this.options.name(this.host);
92
- const value = this.options.value(this.host);
93
- const isButton = this.host.tagName.toLowerCase() === "sd-button";
94
- if (!disabled && !isButton && typeof name === "string" && name.length > 0 && typeof value !== "undefined") {
95
- if (Array.isArray(value)) {
96
- value.forEach((val) => {
97
- event.formData.append(name, val.toString());
98
- });
99
- } else {
100
- event.formData.append(name, value.toString());
101
- }
102
- }
103
- }
104
- handleFormSubmit(event) {
105
- var _a;
106
- const disabled = this.options.disabled(this.host);
107
- const reportValidity = this.options.reportValidity;
108
- if (this.form && !this.form.noValidate) {
109
- (_a = formCollections.get(this.form)) == null ? void 0 : _a.forEach((control) => {
110
- this.setUserInteracted(control, true);
111
- });
112
- }
113
- if (this.form && !this.form.noValidate && !disabled && !reportValidity(this.host)) {
114
- event.preventDefault();
115
- event.stopImmediatePropagation();
116
- }
117
- }
118
- handleFormReset() {
119
- this.options.setValue(this.host, this.options.defaultValue(this.host));
120
- this.setUserInteracted(this.host, false);
121
- }
122
- async handleUserInput() {
123
- await this.host.updateComplete;
124
- this.setUserInteracted(this.host, true);
125
- }
126
136
  reportFormValidity() {
127
137
  if (this.form && !this.form.noValidate) {
128
138
  const elements = this.form.querySelectorAll("*");
@@ -164,6 +174,10 @@ class FormControlController {
164
174
  button.remove();
165
175
  }
166
176
  }
177
+ /** Returns the associated `<form>` element, if one exists. */
178
+ getForm() {
179
+ return this.form ?? null;
180
+ }
167
181
  /** Resets the form, restoring all the control to their default value */
168
182
  reset(invoker) {
169
183
  this.doAction("reset", invoker);
@@ -198,15 +212,62 @@ class FormControlController {
198
212
  }
199
213
  }
200
214
  /**
201
- * Updates the form control's validity based on the current value of `host.checkValidity()`. Call this when anything
215
+ * Updates the form control's validity based on the current value of `host.validity.valid`. Call this when anything
202
216
  * that affects constraint validation changes so the component receives the correct validity states.
203
217
  */
204
218
  updateValidity() {
205
219
  const host = this.host;
206
- this.setValidity(host.checkValidity());
220
+ this.setValidity(host == null ? void 0 : host.validity.valid);
221
+ }
222
+ /**
223
+ * Dispatches a non-bubbling, cancelable custom event of type `sl-invalid`.
224
+ * If the `sl-invalid` event will be cancelled then the original `invalid`
225
+ * event (which may have been passed as argument) will also be cancelled.
226
+ * If no original `invalid` event has been passed then the `sl-invalid`
227
+ * event will be cancelled before being dispatched.
228
+ */
229
+ emitInvalidEvent(originalInvalidEvent) {
230
+ const slInvalidEvent = new CustomEvent("sd-invalid", {
231
+ bubbles: false,
232
+ composed: false,
233
+ cancelable: true,
234
+ detail: {}
235
+ });
236
+ if (!originalInvalidEvent) {
237
+ slInvalidEvent.preventDefault();
238
+ }
239
+ if (!this.host.dispatchEvent(slInvalidEvent)) {
240
+ originalInvalidEvent == null ? void 0 : originalInvalidEvent.preventDefault();
241
+ }
207
242
  }
208
243
  }
244
+ const validValidityState = Object.freeze({
245
+ badInput: false,
246
+ customError: false,
247
+ patternMismatch: false,
248
+ rangeOverflow: false,
249
+ rangeUnderflow: false,
250
+ stepMismatch: false,
251
+ tooLong: false,
252
+ tooShort: false,
253
+ typeMismatch: false,
254
+ valid: true,
255
+ valueMissing: false
256
+ });
257
+ const valueMissingValidityState = Object.freeze({
258
+ ...validValidityState,
259
+ valid: false,
260
+ valueMissing: true
261
+ });
262
+ const customErrorValidityState = Object.freeze({
263
+ ...validValidityState,
264
+ valid: false,
265
+ customError: true
266
+ });
209
267
  export {
210
268
  FormControlController,
211
- formCollections
269
+ customErrorValidityState,
270
+ formCollections,
271
+ validValidityState,
272
+ valueMissingValidityState
212
273
  };
@@ -20,6 +20,8 @@ export interface SolidFormControl extends SolidElement {
20
20
  required?: boolean;
21
21
  minlength?: number;
22
22
  maxlength?: number;
23
+ readonly validity?: ValidityState;
24
+ readonly validationMessage?: string;
23
25
  checkValidity: () => boolean;
24
26
  reportValidity: () => boolean;
25
27
  setCustomValidity: (message: string) => void;
@@ -50,7 +50,7 @@ let LocalizeController$1 = class LocalizeController {
50
50
  }
51
51
  getTranslationData(lang) {
52
52
  var _a, _b;
53
- const locale = new Intl.Locale(lang);
53
+ const locale = new Intl.Locale(lang.replace(/_/g, "-"));
54
54
  const language = locale === null || locale === void 0 ? void 0 : locale.language.toLowerCase();
55
55
  const region = (_b = (_a = locale === null || locale === void 0 ? void 0 : locale.region) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : "";
56
56
  const primary = translations.get(`${language}-${region}`);
@@ -13,6 +13,8 @@ export { default as SdInclude } from './components/include/include';
13
13
  export { default as SdLink } from './components/link/link';
14
14
  export { default as SdNavigationItem } from './components/navigation-item/navigation-item';
15
15
  export { default as SdPopup } from './components/popup/popup';
16
+ export { default as SdRadio } from './components/radio/radio';
17
+ export { default as SdRadioGroup } from './components/radio-group/radio-group';
16
18
  export { default as SdSpinner } from './components/spinner/spinner';
17
19
  export { default as SdTag } from './components/tag/tag';
18
20
  export { default as SdTeaser } from './components/teaser/teaser';
@@ -13,10 +13,12 @@ import { default as default13 } from "./components/include/include.js";
13
13
  import { default as default14 } from "./components/link/link.js";
14
14
  import { default as default15 } from "./components/navigation-item/navigation-item.js";
15
15
  import { default as default16 } from "./components/popup/popup.js";
16
- import { default as default17 } from "./components/spinner/spinner.js";
17
- import { default as default18 } from "./components/tag/tag.js";
18
- import { default as default19 } from "./components/teaser/teaser.js";
19
- import { default as default20 } from "./components/video/video.js";
16
+ import { default as default17 } from "./components/radio/radio.js";
17
+ import { default as default18 } from "./components/radio-group/radio-group.js";
18
+ import { default as default19 } from "./components/spinner/spinner.js";
19
+ import { default as default20 } from "./components/tag/tag.js";
20
+ import { default as default21 } from "./components/teaser/teaser.js";
21
+ import { default as default22 } from "./components/video/video.js";
20
22
  import { registerIconLibrary, unregisterIconLibrary } from "./components/icon/library.js";
21
23
  import { LocalizeController } from "./utilities/localize.js";
22
24
  export {
@@ -36,10 +38,12 @@ export {
36
38
  default14 as SdLink,
37
39
  default15 as SdNavigationItem,
38
40
  default16 as SdPopup,
39
- default17 as SdSpinner,
40
- default18 as SdTag,
41
- default19 as SdTeaser,
42
- default20 as SdVideo,
41
+ default17 as SdRadio,
42
+ default18 as SdRadioGroup,
43
+ default19 as SdSpinner,
44
+ default20 as SdTag,
45
+ default21 as SdTeaser,
46
+ default22 as SdVideo,
43
47
  registerIconLibrary,
44
48
  unregisterIconLibrary
45
49
  };