@momentum-design/components 0.28.2 → 0.28.4

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 (40) hide show
  1. package/dist/browser/index.js +169 -157
  2. package/dist/browser/index.js.map +4 -4
  3. package/dist/components/avatar/avatar.component.js +4 -4
  4. package/dist/components/avatar/avatar.styles.js +20 -20
  5. package/dist/components/buttonsimple/buttonsimple.component.d.ts +1 -7
  6. package/dist/components/buttonsimple/buttonsimple.component.js +6 -13
  7. package/dist/components/checkbox/checkbox.component.d.ts +26 -13
  8. package/dist/components/checkbox/checkbox.component.js +62 -22
  9. package/dist/components/formfieldgroup/formfieldgroup.component.js +2 -1
  10. package/dist/components/input/input.component.d.ts +59 -72
  11. package/dist/components/input/input.component.js +85 -100
  12. package/dist/components/radio/radio.component.d.ts +51 -36
  13. package/dist/components/radio/radio.component.js +126 -46
  14. package/dist/components/radio/radio.styles.js +4 -0
  15. package/dist/components/radiogroup/radiogroup.component.d.ts +7 -2
  16. package/dist/components/radiogroup/radiogroup.component.js +26 -3
  17. package/dist/components/themeprovider/themeprovider.component.d.ts +1 -1
  18. package/dist/components/themeprovider/themeprovider.component.js +1 -1
  19. package/dist/components/toggle/toggle.component.d.ts +43 -24
  20. package/dist/components/toggle/toggle.component.js +79 -31
  21. package/dist/components/toggle/toggle.constants.d.ts +1 -0
  22. package/dist/components/toggle/toggle.constants.js +1 -0
  23. package/dist/components/virtualizedlist/virtualizedlist.component.js +2 -2
  24. package/dist/components/virtualizedlist/virtualizedlist.styles.js +9 -11
  25. package/dist/custom-elements.json +1471 -570
  26. package/dist/react/index.d.ts +1 -1
  27. package/dist/react/index.js +1 -1
  28. package/dist/react/themeprovider/index.d.ts +1 -1
  29. package/dist/react/themeprovider/index.js +1 -1
  30. package/dist/utils/mixins/FormInternalsMixin.d.ts +38 -0
  31. package/dist/utils/mixins/FormInternalsMixin.js +79 -0
  32. package/package.json +1 -1
  33. package/dist/utils/mixins/NameMixin.d.ts +0 -6
  34. package/dist/utils/mixins/NameMixin.js +0 -29
  35. package/dist/utils/mixins/ReadonlyMixin.d.ts +0 -6
  36. package/dist/utils/mixins/ReadonlyMixin.js +0 -29
  37. package/dist/utils/mixins/RequiredMixin.d.ts +0 -6
  38. package/dist/utils/mixins/RequiredMixin.js +0 -29
  39. package/dist/utils/mixins/ValueMixin.d.ts +0 -6
  40. package/dist/utils/mixins/ValueMixin.js +0 -28
@@ -7,15 +7,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
+ /* eslint-disable no-param-reassign */
10
11
  import { html, nothing } from 'lit';
11
12
  import { property } from 'lit/decorators.js';
12
13
  import { ifDefined } from 'lit/directives/if-defined.js';
13
- import { v4 as uuidv4 } from 'uuid';
14
- import { NameMixin } from '../../utils/mixins/NameMixin';
15
- import { ValueMixin } from '../../utils/mixins/ValueMixin';
16
14
  import styles from './radio.styles';
17
15
  import FormfieldWrapper from '../formfieldwrapper/formfieldwrapper.component';
18
16
  import { DataAriaLabelMixin } from '../../utils/mixins/DataAriaLabelMixin';
17
+ import { FormInternalsMixin } from '../../utils/mixins/FormInternalsMixin';
19
18
  import { DEFAULTS as FORMFIELD_DEFAULTS } from '../formfieldwrapper/formfieldwrapper.constants';
20
19
  /**
21
20
  * Radio allow users to select single options from a list or turn an item/feature on or off.
@@ -47,11 +46,7 @@ import { DEFAULTS as FORMFIELD_DEFAULTS } from '../formfieldwrapper/formfieldwra
47
46
  * when active and disabled
48
47
  *
49
48
  */
50
- class Radio extends NameMixin(ValueMixin(DataAriaLabelMixin(FormfieldWrapper))) {
51
- /** @internal */
52
- get form() {
53
- return this.internals.form;
54
- }
49
+ class Radio extends FormInternalsMixin(DataAriaLabelMixin(FormfieldWrapper)) {
55
50
  constructor() {
56
51
  super();
57
52
  /**
@@ -66,41 +61,117 @@ class Radio extends NameMixin(ValueMixin(DataAriaLabelMixin(FormfieldWrapper)))
66
61
  * @default false
67
62
  */
68
63
  this.readonly = false;
69
- /** @internal */
70
- this.internals = this.attachInternals();
71
- this.id = `mdc-input-${uuidv4()}`;
72
- }
73
- /**
74
- * Updates the form value to reflect the current state of the radio.
75
- * If checked, the value is set to the user-provided value.
76
- * If unchecked, the value is set to null.
77
- */
78
- setFormValue() {
79
- this.internals.setFormValue(this.checked ? this.value : null);
64
+ /**
65
+ * Automatically focus on the element when the page loads.
66
+ * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus)
67
+ * @default false
68
+ */
69
+ this.autofocus = false;
70
+ // Radio does not contain helpTextType property.
71
+ this.helpTextType = undefined;
80
72
  }
81
73
  firstUpdated() {
82
74
  this.updateTabIndex();
83
75
  }
84
76
  /**
85
- * Returns all radios within the same group (name).
86
- */
77
+ * Returns all radios within the same group (name).
78
+ */
87
79
  getAllRadiosWithinSameGroup() {
88
80
  return Array.from(document.querySelectorAll(`mdc-radio[name="${this.name}"]`));
89
81
  }
90
82
  /**
91
- * The 'change' event does not bubble up through the shadow DOM as it was not composed.
92
- * Therefore, we need to re-dispatch the same event to ensure it is propagated correctly.
93
- * Read more: https://developer.mozilla.org/en-US/docs/Web/API/Event/composed
94
- */
83
+ * The 'change' event does not bubble up through the shadow DOM as it was not composed.
84
+ * Therefore, we need to re-dispatch the same event to ensure it is propagated correctly.
85
+ * Read more: https://developer.mozilla.org/en-US/docs/Web/API/Event/composed
86
+ */
95
87
  dispatchChangeEvent(event) {
96
88
  const EventConstructor = event.constructor;
97
89
  this.dispatchEvent(new EventConstructor(event.type, event));
98
90
  }
91
+ /** @internal */
92
+ formResetCallback() {
93
+ const radios = this.getAllRadiosWithinSameGroup();
94
+ radios.forEach((radio) => {
95
+ radio.checked = false;
96
+ });
97
+ this.updateComplete.then(() => {
98
+ this.setActualFormValue();
99
+ }).catch((error) => {
100
+ if (this.onerror) {
101
+ this.onerror(error);
102
+ }
103
+ });
104
+ }
105
+ /** @internal */
106
+ formStateRestoreCallback(state) {
107
+ if (this.value === state && state !== '') {
108
+ this.checked = true;
109
+ }
110
+ }
111
+ /**
112
+ * @internal
113
+ */
114
+ setComponentValidity(isValid) {
115
+ if (isValid) {
116
+ this.internals.setValidity({});
117
+ }
118
+ else if (this.requiredLabel && !this.checked) {
119
+ if (this.validationMessage) {
120
+ this.inputElement.setCustomValidity(this.validationMessage);
121
+ }
122
+ else {
123
+ this.inputElement.setCustomValidity('');
124
+ }
125
+ this.setValidity();
126
+ }
127
+ this.updateTabIndex();
128
+ }
99
129
  /**
100
- * Handles the change event on the radio element.
101
- * This will toggle the state of the radio element.
102
- * Dispatches the change event.
130
+ * Sets the validity of the group of radios.
131
+ * @param radios - Array of radios of the same group
132
+ * @param isValid - Boolean value to set the validity of the group
103
133
  */
134
+ setGroupValidity(radios, isValid) {
135
+ this.updateComplete.then(() => {
136
+ radios.forEach((radio) => {
137
+ radio.setComponentValidity(isValid);
138
+ });
139
+ }).catch((error) => {
140
+ if (this.onerror) {
141
+ this.onerror(error);
142
+ }
143
+ });
144
+ }
145
+ /**
146
+ * Updates the form value to reflect the current state of the radio.
147
+ * If checked, the value is set to the user-provided value.
148
+ * If unchecked, the value is set to null.
149
+ */
150
+ setActualFormValue() {
151
+ let actualValue = '';
152
+ if (this.checked) {
153
+ actualValue = !this.value ? 'on' : this.value;
154
+ }
155
+ else {
156
+ actualValue = null;
157
+ }
158
+ const radios = this.getAllRadiosWithinSameGroup();
159
+ if (this.checked) {
160
+ this.setGroupValidity(radios, true);
161
+ }
162
+ else {
163
+ const anyRequired = radios.some((r) => r.requiredLabel);
164
+ const anyChecked = !!radios.find((r) => r.checked);
165
+ const isInvalid = anyRequired && !anyChecked;
166
+ this.setGroupValidity(radios, !isInvalid);
167
+ }
168
+ this.internals.setFormValue(actualValue);
169
+ }
170
+ /**
171
+ * Handles the change event on the radio element.
172
+ * This will toggle the state of the radio element.
173
+ * Dispatches the change event.
174
+ */
104
175
  handleChange(event) {
105
176
  var _a;
106
177
  if (this.disabled || this.readonly)
@@ -113,7 +184,6 @@ class Radio extends NameMixin(ValueMixin(DataAriaLabelMixin(FormfieldWrapper)))
113
184
  */
114
185
  const radioElement = (_a = radio.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('input');
115
186
  if (radioElement) {
116
- // eslint-disable-next-line no-param-reassign
117
187
  radio.checked = false;
118
188
  radioElement.checked = false;
119
189
  }
@@ -123,26 +193,26 @@ class Radio extends NameMixin(ValueMixin(DataAriaLabelMixin(FormfieldWrapper)))
123
193
  if (inputElement) {
124
194
  inputElement.checked = true;
125
195
  }
126
- this.updateTabIndex();
127
196
  this.dispatchChangeEvent(event);
128
197
  }
129
198
  /**
130
- * Updates the state of the radio button at the specified index within the enabled radios.
131
- * Focuses the radio button and triggers the change event if the radio button is not read-only.
132
- *
133
- * @param enabledRadios - An array of enabled radio buttons within the same group.
134
- * @param index - The index of the radio button to be updated within the enabled radios array.
135
- * @param event - The event that triggered the update.
136
- */
199
+ * Updates the state of the radio button at the specified index within the enabled radios.
200
+ * Focuses the radio button and triggers the change event if the radio button is not read-only.
201
+ *
202
+ * @param enabledRadios - An array of enabled radio buttons within the same group.
203
+ * @param index - The index of the radio button to be updated within the enabled radios array.
204
+ * @param event - The event that triggered the update.
205
+ */
137
206
  updateRadio(enabledRadios, index, event) {
138
207
  var _a, _b;
139
208
  (_b = (_a = enabledRadios[index].shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('input')) === null || _b === void 0 ? void 0 : _b.focus();
140
209
  enabledRadios[index].handleChange(event);
141
210
  }
142
211
  /**
143
- * Handles the keydown event (Arrow Up/Down/Left/Right) on the radio element.
144
- */
212
+ * Handles the keydown event (Arrow Up/Down/Left/Right) on the radio element.
213
+ */
145
214
  handleKeyDown(event) {
215
+ var _a;
146
216
  if (this.disabled)
147
217
  return;
148
218
  const radios = this.getAllRadiosWithinSameGroup();
@@ -158,13 +228,19 @@ class Radio extends NameMixin(ValueMixin(DataAriaLabelMixin(FormfieldWrapper)))
158
228
  const prevIndex = (currentIndex - 1 + enabledRadios.length) % enabledRadios.length;
159
229
  this.updateRadio(enabledRadios, prevIndex, event);
160
230
  }
231
+ else if (event.key === ' ') {
232
+ this.updateRadio(enabledRadios, currentIndex, event);
233
+ }
161
234
  this.updateTabIndex();
235
+ if (event.key === 'Enter') {
236
+ (_a = this.form) === null || _a === void 0 ? void 0 : _a.requestSubmit();
237
+ }
162
238
  }
163
239
  /**
164
- * Update tab index for all radios in the same group (name)
165
- * If any radio group is checked, it will have a tab index of 0
166
- * If no radio group is checked, the first enabled radio will have a tab index of 0
167
- */
240
+ * Update tab index for all radios in the same group (name)
241
+ * If any radio group is checked, it will have a tab index of 0
242
+ * If no radio group is checked, the first enabled radio will have a tab index of 0
243
+ */
168
244
  updateTabIndex() {
169
245
  const radios = this.getAllRadiosWithinSameGroup();
170
246
  const checked = radios.find((radio) => radio.checked);
@@ -186,7 +262,7 @@ class Radio extends NameMixin(ValueMixin(DataAriaLabelMixin(FormfieldWrapper)))
186
262
  update(changedProperties) {
187
263
  super.update(changedProperties);
188
264
  if (changedProperties.has('checked')) {
189
- this.setFormValue();
265
+ this.setActualFormValue();
190
266
  }
191
267
  }
192
268
  render() {
@@ -199,8 +275,10 @@ class Radio extends NameMixin(ValueMixin(DataAriaLabelMixin(FormfieldWrapper)))
199
275
  id="${this.id}"
200
276
  type="radio"
201
277
  role="radio"
278
+ ?autofocus="${this.autofocus}"
202
279
  name="${ifDefined(this.name)}"
203
280
  value="${ifDefined(this.value)}"
281
+ ?required="${!!this.requiredLabel}"
204
282
  @change=${this.handleChange}
205
283
  @keydown=${this.handleKeyDown}
206
284
  ?checked=${this.checked}
@@ -221,8 +299,6 @@ class Radio extends NameMixin(ValueMixin(DataAriaLabelMixin(FormfieldWrapper)))
221
299
  `;
222
300
  }
223
301
  }
224
- /** @internal */
225
- Radio.formAssociated = true;
226
302
  Radio.styles = [...FormfieldWrapper.styles, ...styles];
227
303
  __decorate([
228
304
  property({ type: Boolean, reflect: true }),
@@ -232,4 +308,8 @@ __decorate([
232
308
  property({ type: Boolean, reflect: true }),
233
309
  __metadata("design:type", Object)
234
310
  ], Radio.prototype, "readonly", void 0);
311
+ __decorate([
312
+ property({ type: Boolean, reflect: true }),
313
+ __metadata("design:type", Object)
314
+ ], Radio.prototype, "autofocus", void 0);
235
315
  export default Radio;
@@ -158,5 +158,9 @@ const styles = [hostFitContentStyles, css `
158
158
  justify-content: center;
159
159
  gap: 0.25rem;
160
160
  }
161
+ :host::part(required-label){
162
+ display: none;
163
+ }
164
+
161
165
  `, ...hostFocusRingStyles(true)];
162
166
  export default styles;
@@ -1,6 +1,5 @@
1
1
  import { CSSResult } from 'lit';
2
2
  import FormfieldGroup from '../formfieldgroup';
3
- declare const RadioGroup_base: import("../../utils/mixins/index.types").Constructor<import("../../utils/mixins/NameMixin").NameMixinInterface> & typeof FormfieldGroup;
4
3
  /**
5
4
  * `mdc-radiogroup` - This is the wrapper component for radio buttons which are grouped together.
6
5
  * It can have a header text and a description. It enables users to select a single option from a set of options.
@@ -11,7 +10,13 @@ declare const RadioGroup_base: import("../../utils/mixins/index.types").Construc
11
10
  * @cssproperty --mdc-radiogroup-description-text-normal - color of the description text
12
11
  *
13
12
  */
14
- declare class RadioGroup extends RadioGroup_base {
13
+ declare class RadioGroup extends FormfieldGroup {
14
+ /**
15
+ * Name of the radio group.
16
+ * They are used to group elements in a form together.
17
+ * @default ''
18
+ */
19
+ name: string;
15
20
  constructor();
16
21
  /**
17
22
  * Using name property to group the radio buttons together.
@@ -1,4 +1,13 @@
1
- import { NameMixin } from '../../utils/mixins/NameMixin';
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { property } from 'lit/decorators.js';
2
11
  import FormfieldGroup from '../formfieldgroup';
3
12
  import { TAG_NAME as RADIO_TAGNAME } from '../radio/radio.constants';
4
13
  /**
@@ -11,9 +20,15 @@ import { TAG_NAME as RADIO_TAGNAME } from '../radio/radio.constants';
11
20
  * @cssproperty --mdc-radiogroup-description-text-normal - color of the description text
12
21
  *
13
22
  */
14
- class RadioGroup extends NameMixin(FormfieldGroup) {
23
+ class RadioGroup extends FormfieldGroup {
15
24
  constructor() {
16
25
  super();
26
+ /**
27
+ * Name of the radio group.
28
+ * They are used to group elements in a form together.
29
+ * @default ''
30
+ */
31
+ this.name = '';
17
32
  // This is used to set the role of the component as `radiogroup`.
18
33
  /** @internal */
19
34
  this.isRadio = true;
@@ -24,8 +39,16 @@ class RadioGroup extends NameMixin(FormfieldGroup) {
24
39
  */
25
40
  firstUpdated() {
26
41
  var _a, _b, _c, _d, _e;
27
- (_e = (_d = (_c = (_b = Array.from(((_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('slot')) || [])) === null || _b === void 0 ? void 0 : _b.flatMap((slot) => slot.assignedElements({ flatten: true }))) === null || _c === void 0 ? void 0 : _c.filter((el) => el.tagName.toLowerCase() === RADIO_TAGNAME)) === null || _d === void 0 ? void 0 : _d.filter((radio) => !radio.hasAttribute('name'))) === null || _e === void 0 ? void 0 : _e.forEach((radio) => radio.setAttribute('name', this.name));
42
+ (_e = (_d = (_c = (_b = Array.from(((_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('slot')) || [])) === null || _b === void 0 ? void 0 : _b.flatMap((slot) => slot.assignedElements({ flatten: true }))) === null || _c === void 0 ? void 0 : _c.filter((el) => el.tagName.toLowerCase() === RADIO_TAGNAME)) === null || _d === void 0 ? void 0 : _d.filter((radio) => !radio.hasAttribute('name'))) === null || _e === void 0 ? void 0 : _e.forEach((radio) => {
43
+ radio.setAttribute('name', this.name);
44
+ if (this.requiredLabel)
45
+ radio.setAttribute('required-label', this.requiredLabel);
46
+ });
28
47
  }
29
48
  }
30
49
  RadioGroup.styles = [...FormfieldGroup.styles];
50
+ __decorate([
51
+ property({ type: String }),
52
+ __metadata("design:type", Object)
53
+ ], RadioGroup.prototype, "name", void 0);
31
54
  export default RadioGroup;
@@ -25,7 +25,7 @@ import ThemeProviderContext from './themeprovider.context';
25
25
  * @cssproperty --mdc-themeprovider-letter-spacing-adjustment - Option to override the default letter-spacing,
26
26
  * default: `-0.25px` (this is to match the old CiscoSans)
27
27
  * @cssproperty --mdc-themeprovider-font-feature-settings - Option to override the font feature settings,
28
- * default: `normal`
28
+ * default: `"ss02" on`
29
29
  * @cssproperty --mdc-themeprovider-scrollbar-track-color - Option to override the color of the scrollbar track.
30
30
  * @cssproperty --mdc-themeprovider-scrollbar-thumb-color - Option to override the color of the scrollbar thumb.
31
31
  * @cssproperty --mdc-themeprovider-scrollbar-thumb-hover-color - Option to override the color of the
@@ -36,7 +36,7 @@ import styles from './themeprovider.styles';
36
36
  * @cssproperty --mdc-themeprovider-letter-spacing-adjustment - Option to override the default letter-spacing,
37
37
  * default: `-0.25px` (this is to match the old CiscoSans)
38
38
  * @cssproperty --mdc-themeprovider-font-feature-settings - Option to override the font feature settings,
39
- * default: `normal`
39
+ * default: `"ss02" on`
40
40
  * @cssproperty --mdc-themeprovider-scrollbar-track-color - Option to override the color of the scrollbar track.
41
41
  * @cssproperty --mdc-themeprovider-scrollbar-thumb-color - Option to override the color of the scrollbar thumb.
42
42
  * @cssproperty --mdc-themeprovider-scrollbar-thumb-hover-color - Option to override the color of the
@@ -1,7 +1,8 @@
1
1
  import { CSSResult, PropertyValueMap } from 'lit';
2
2
  import FormfieldWrapper from '../formfieldwrapper';
3
3
  import { ToggleSize } from './toggle.types';
4
- declare const Toggle_base: import("../../utils/mixins/index.types").Constructor<import("../../utils/mixins/NameMixin").NameMixinInterface> & import("../../utils/mixins/index.types").Constructor<import("../../utils/mixins/ValueMixin").ValueMixinInterface> & import("../../utils/mixins/index.types").Constructor<import("../../utils/mixins/DataAriaLabelMixin").DataAriaLabelMixinInterface> & typeof FormfieldWrapper;
4
+ import { AssociatedFormControl } from '../../utils/mixins/FormInternalsMixin';
5
+ declare const Toggle_base: import("../../utils/mixins/index.types").Constructor<import("../../utils/mixins/FormInternalsMixin").FormInternalsMixinInterface> & import("../../utils/mixins/index.types").Constructor<import("../../utils/mixins/DataAriaLabelMixin").DataAriaLabelMixinInterface> & typeof FormfieldWrapper;
5
6
  /**
6
7
  * Toggle Component is an interactive control used to switch between two mutually exclusive options,
7
8
  * such as On/Off, Active/Inactive. These are commonly used in settings panels, forms, and preference selections
@@ -38,7 +39,7 @@ declare const Toggle_base: import("../../utils/mixins/index.types").Constructor<
38
39
  * @cssproperty --mdc-toggle-label-color-disabled - color of the toggle label and help text in disabled state
39
40
  *
40
41
  */
41
- declare class Toggle extends Toggle_base {
42
+ declare class Toggle extends Toggle_base implements AssociatedFormControl {
42
43
  /**
43
44
  * Determines whether the toggle is active or inactive.
44
45
  * @default false
@@ -51,36 +52,54 @@ declare class Toggle extends Toggle_base {
51
52
  * @default default
52
53
  */
53
54
  size: ToggleSize;
54
- /** @internal */
55
- private internals;
56
- /** @internal */
57
- static formAssociated: boolean;
58
- /** @internal */
59
- get form(): HTMLFormElement | null;
55
+ /**
56
+ * Automatically focus on the element when the page loads.
57
+ * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus)
58
+ * @default false
59
+ */
60
+ autofocus: boolean;
60
61
  constructor();
62
+ /** @internal
63
+ * Resets the checkbox to its initial state.
64
+ * The checked property is set to false.
65
+ */
66
+ formResetCallback(): void;
67
+ /** @internal */
68
+ formStateRestoreCallback(state: string): void;
61
69
  /**
62
- * Updates the form value to reflect the current state of the toggle.
63
- * If toggle is switched on, the value is set to either the user-provided value or 'isActive' if no value is provided.
64
- * If toggle is switched off, the value is set to null.
65
- */
70
+ * Manages the required state of the checkbox.
71
+ * If the checkbox is not checked and the requiredLabel property is set, then the checkbox is invalid.
72
+ */
73
+ private manageRequired;
74
+ /**
75
+ * Updates the form value to reflect the current state of the toggle.
76
+ * If toggle is switched on, the value is set to either the user-provided value or 'isActive' if no value is provided.
77
+ * If toggle is switched off, the value is set to null.
78
+ */
66
79
  private setFormValue;
67
80
  /**
68
- * Toggles the state of the toggle element.
69
- * If the element is not disabled, then the checked property is toggled.
70
- */
81
+ * Toggles the state of the toggle element.
82
+ * If the element is not disabled, then the checked property is toggled.
83
+ */
71
84
  private toggleState;
72
85
  /**
73
- * Toggles the state of the toggle element.
74
- * and dispatch the new change event.
75
- */
86
+ * Handles the keydown event on the toggle element.
87
+ * When the user presses Enter, the form is submitted.
88
+ * @param event - The keyboard event.
89
+ */
90
+ private handleKeyDown;
91
+ /**
92
+ * Toggles the state of the toggle element.
93
+ * and dispatch the new change event.
94
+ */
76
95
  private handleChange;
77
96
  /**
78
- * Sets the size attribute for the toggle component.
79
- * If the provided size is not included in the TOGGLE_SIZE,
80
- * it defaults to the value specified in DEFAULTS.SIZE.
81
- *
82
- * @param size - The size to set.
83
- */
97
+ * Sets the size attribute for the toggle component.
98
+ * If the provided size is not included in the TOGGLE_SIZE,
99
+ * it defaults to the value specified in DEFAULTS.SIZE.
100
+ *
101
+ * @param size - The size to set.
102
+ */
84
103
  private setToggleSize;
85
104
  update(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
86
105
  render(): import("lit-html").TemplateResult<1>;
@@ -10,14 +10,12 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  import { html } from 'lit';
11
11
  import { property } from 'lit/decorators.js';
12
12
  import { ifDefined } from 'lit/directives/if-defined.js';
13
- import { v4 as uuidv4 } from 'uuid';
14
13
  import styles from './toggle.styles';
15
14
  import FormfieldWrapper from '../formfieldwrapper';
16
- import { ValueMixin } from '../../utils/mixins/ValueMixin';
17
- import { NameMixin } from '../../utils/mixins/NameMixin';
18
15
  import { DEFAULTS as FORMFIELD_DEFAULTS } from '../formfieldwrapper/formfieldwrapper.constants';
19
16
  import { DEFAULTS, ICON_NAME, ICON_SIZE_IN_REM, TOGGLE_SIZE } from './toggle.constants';
20
17
  import { DataAriaLabelMixin } from '../../utils/mixins/DataAriaLabelMixin';
18
+ import { FormInternalsMixin } from '../../utils/mixins/FormInternalsMixin';
21
19
  /**
22
20
  * Toggle Component is an interactive control used to switch between two mutually exclusive options,
23
21
  * such as On/Off, Active/Inactive. These are commonly used in settings panels, forms, and preference selections
@@ -54,11 +52,7 @@ import { DataAriaLabelMixin } from '../../utils/mixins/DataAriaLabelMixin';
54
52
  * @cssproperty --mdc-toggle-label-color-disabled - color of the toggle label and help text in disabled state
55
53
  *
56
54
  */
57
- class Toggle extends NameMixin(ValueMixin(DataAriaLabelMixin(FormfieldWrapper))) {
58
- /** @internal */
59
- get form() {
60
- return this.internals.form;
61
- }
55
+ class Toggle extends FormInternalsMixin(DataAriaLabelMixin(FormfieldWrapper)) {
62
56
  constructor() {
63
57
  super();
64
58
  /**
@@ -73,50 +67,98 @@ class Toggle extends NameMixin(ValueMixin(DataAriaLabelMixin(FormfieldWrapper)))
73
67
  * @default default
74
68
  */
75
69
  this.size = DEFAULTS.SIZE;
76
- /** @internal */
77
- this.internals = this.attachInternals();
70
+ /**
71
+ * Automatically focus on the element when the page loads.
72
+ * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus)
73
+ * @default false
74
+ */
75
+ this.autofocus = false;
78
76
  // Toggle does not contain helpTextType property.
79
77
  this.helpTextType = undefined;
80
- this.id = `mdc-input-${uuidv4()}`;
78
+ }
79
+ /** @internal
80
+ * Resets the checkbox to its initial state.
81
+ * The checked property is set to false.
82
+ */
83
+ formResetCallback() {
84
+ this.checked = false;
85
+ }
86
+ /** @internal */
87
+ formStateRestoreCallback(state) {
88
+ if (state) {
89
+ this.checked = true;
90
+ }
91
+ }
92
+ /**
93
+ * Manages the required state of the checkbox.
94
+ * If the checkbox is not checked and the requiredLabel property is set, then the checkbox is invalid.
95
+ */
96
+ manageRequired() {
97
+ if (!this.checked && this.requiredLabel) {
98
+ if (this.validationMessage) {
99
+ this.inputElement.setCustomValidity(this.validationMessage);
100
+ }
101
+ else {
102
+ this.inputElement.setCustomValidity('');
103
+ }
104
+ this.setValidity();
105
+ }
106
+ else {
107
+ this.internals.setValidity({});
108
+ }
81
109
  }
82
110
  /**
83
- * Updates the form value to reflect the current state of the toggle.
84
- * If toggle is switched on, the value is set to either the user-provided value or 'isActive' if no value is provided.
85
- * If toggle is switched off, the value is set to null.
86
- */
111
+ * Updates the form value to reflect the current state of the toggle.
112
+ * If toggle is switched on, the value is set to either the user-provided value or 'isActive' if no value is provided.
113
+ * If toggle is switched off, the value is set to null.
114
+ */
87
115
  setFormValue() {
88
116
  let actualValue = null;
89
117
  if (this.checked) {
90
118
  actualValue = !this.value ? 'isActive' : this.value;
91
119
  }
120
+ else {
121
+ actualValue = null;
122
+ }
123
+ this.manageRequired();
92
124
  this.internals.setFormValue(actualValue);
93
125
  }
94
126
  /**
95
- * Toggles the state of the toggle element.
96
- * If the element is not disabled, then the checked property is toggled.
97
- */
127
+ * Toggles the state of the toggle element.
128
+ * If the element is not disabled, then the checked property is toggled.
129
+ */
98
130
  toggleState() {
99
131
  if (!this.disabled) {
100
132
  this.checked = !this.checked;
101
133
  }
102
134
  }
103
135
  /**
104
- * Toggles the state of the toggle element.
105
- * and dispatch the new change event.
106
- */
136
+ * Handles the keydown event on the toggle element.
137
+ * When the user presses Enter, the form is submitted.
138
+ * @param event - The keyboard event.
139
+ */
140
+ handleKeyDown(event) {
141
+ var _a;
142
+ if (event.key === 'Enter') {
143
+ (_a = this.form) === null || _a === void 0 ? void 0 : _a.requestSubmit();
144
+ }
145
+ }
146
+ /**
147
+ * Toggles the state of the toggle element.
148
+ * and dispatch the new change event.
149
+ */
107
150
  handleChange(event) {
108
151
  this.toggleState();
109
- // Re-dispatch the existing event instead of creating a new one since change event doesn't bubble out of shadow dom
110
152
  const EventConstructor = event.constructor;
111
153
  this.dispatchEvent(new EventConstructor(event.type, event));
112
154
  }
113
155
  /**
114
- * Sets the size attribute for the toggle component.
115
- * If the provided size is not included in the TOGGLE_SIZE,
116
- * it defaults to the value specified in DEFAULTS.SIZE.
117
- *
118
- * @param size - The size to set.
119
- */
156
+ * Sets the size attribute for the toggle component.
157
+ * If the provided size is not included in the TOGGLE_SIZE,
158
+ * it defaults to the value specified in DEFAULTS.SIZE.
159
+ *
160
+ * @param size - The size to set.
161
+ */
120
162
  setToggleSize(size) {
121
163
  this.setAttribute('size', Object.values(TOGGLE_SIZE).includes(size) ? size : DEFAULTS.SIZE);
122
164
  }
@@ -138,14 +180,18 @@ class Toggle extends NameMixin(ValueMixin(DataAriaLabelMixin(FormfieldWrapper)))
138
180
  type="checkbox"
139
181
  class="mdc-toggle__input"
140
182
  role="switch"
183
+ ?autofocus="${this.autofocus}"
184
+ ?required="${!!this.requiredLabel}"
141
185
  name="${ifDefined(this.name)}"
142
186
  value="${ifDefined(this.value)}"
143
187
  .checked="${this.checked}"
188
+ aria-checked="${this.checked}"
144
189
  .disabled="${this.disabled}"
145
- aria-describedby="${FORMFIELD_DEFAULTS.HELPER_TEXT_ID}"
190
+ aria-describedby="${ifDefined(this.helpText ? FORMFIELD_DEFAULTS.HELPER_TEXT_ID : '')}"
146
191
  aria-label="${(_a = this.dataAriaLabel) !== null && _a !== void 0 ? _a : ''}"
147
192
  tabindex="${this.disabled ? -1 : 0}"
148
193
  @change="${this.handleChange}"
194
+ @keydown="${this.handleKeyDown}"
149
195
  />
150
196
  <div class="mdc-toggle__slider">
151
197
  <mdc-icon
@@ -161,8 +207,6 @@ class Toggle extends NameMixin(ValueMixin(DataAriaLabelMixin(FormfieldWrapper)))
161
207
  `;
162
208
  }
163
209
  }
164
- /** @internal */
165
- Toggle.formAssociated = true;
166
210
  Toggle.styles = [...FormfieldWrapper.styles, ...styles];
167
211
  __decorate([
168
212
  property({ type: Boolean, reflect: true }),
@@ -172,4 +216,8 @@ __decorate([
172
216
  property({ type: String, reflect: true }),
173
217
  __metadata("design:type", String)
174
218
  ], Toggle.prototype, "size", void 0);
219
+ __decorate([
220
+ property({ type: Boolean, reflect: true }),
221
+ __metadata("design:type", Object)
222
+ ], Toggle.prototype, "autofocus", void 0);
175
223
  export default Toggle;