@aurodesignsystem-dev/auro-formkit 0.0.0-pr1474.4 → 0.0.0-pr1475.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.
- package/components/bibtemplate/dist/auro-bibtemplate.d.ts +7 -0
- package/components/bibtemplate/dist/index.js +9 -1
- package/components/bibtemplate/dist/registered.js +9 -1
- package/components/checkbox/demo/customize.html +2 -1
- package/components/checkbox/demo/customize.min.js +1 -1
- package/components/checkbox/demo/getting-started.min.js +1 -1
- package/components/checkbox/demo/index.min.js +1 -1
- package/components/checkbox/dist/index.js +1 -1
- package/components/checkbox/dist/registered.js +1 -1
- package/components/combobox/demo/customize.html +2 -1
- package/components/combobox/demo/customize.md +130 -106
- package/components/combobox/demo/customize.min.js +209 -16
- package/components/combobox/demo/getting-started.min.js +209 -16
- package/components/combobox/demo/index.min.js +209 -16
- package/components/combobox/dist/index.js +209 -16
- package/components/combobox/dist/registered.js +209 -16
- package/components/counter/demo/customize.min.js +208 -15
- package/components/counter/demo/index.min.js +208 -15
- package/components/counter/demo/keyboard-behavior.md +1 -0
- package/components/counter/dist/index.js +10 -2
- package/components/counter/dist/registered.js +10 -2
- package/components/datepicker/demo/accessibility.md +51 -3
- package/components/datepicker/demo/api.md +9 -0
- package/components/datepicker/demo/customize.html +2 -0
- package/components/datepicker/demo/customize.js +19 -0
- package/components/datepicker/demo/customize.md +72 -8
- package/components/datepicker/demo/customize.min.js +25690 -0
- package/components/datepicker/demo/design.md +3 -1
- package/components/datepicker/demo/index.js +2 -1
- package/components/datepicker/demo/index.md +81 -1
- package/components/datepicker/demo/index.min.js +1223 -101
- package/components/datepicker/demo/keyboard-behavior.md +201 -2
- package/components/datepicker/demo/voiceover.md +19 -12
- package/components/datepicker/dist/index.js +1155 -104
- package/components/datepicker/dist/registered.js +1155 -104
- package/components/datepicker/dist/src/auro-calendar-cell.d.ts +59 -0
- package/components/datepicker/dist/src/auro-calendar-month.d.ts +28 -0
- package/components/datepicker/dist/src/auro-calendar.d.ts +84 -0
- package/components/datepicker/dist/src/auro-datepicker.d.ts +80 -0
- package/components/datepicker/dist/src/datepickerKeyboardStrategy.d.ts +5 -3
- package/components/dropdown/demo/accessibility.md +11 -0
- package/components/dropdown/demo/api.md +1 -0
- package/components/dropdown/demo/customize.md +3 -0
- package/components/dropdown/demo/customize.min.js +198 -13
- package/components/dropdown/demo/getting-started.min.js +198 -13
- package/components/dropdown/demo/index.min.js +198 -13
- package/components/dropdown/demo/keyboard-behavior.md +1 -0
- package/components/dropdown/dist/auro-dropdown.d.ts +30 -1
- package/components/dropdown/dist/index.js +198 -13
- package/components/dropdown/dist/registered.js +198 -13
- package/components/form/demo/customize.html +6 -6
- package/components/form/demo/customize.js +0 -17
- package/components/form/demo/customize.md +51 -125
- package/components/form/demo/customize.min.js +1776 -327
- package/components/form/demo/getting-started.min.js +1776 -291
- package/components/form/demo/index.min.js +1776 -291
- package/components/form/demo/registerDemoDeps.min.js +1769 -139
- package/components/form/dist/auro-form.d.ts +5 -45
- package/components/form/dist/index.js +7 -152
- package/components/form/dist/registered.js +7 -152
- package/components/input/demo/customize.html +2 -1
- package/components/input/demo/customize.min.js +1 -1
- package/components/input/demo/getting-started.min.js +1 -1
- package/components/input/demo/index.min.js +1 -1
- package/components/input/dist/index.js +1 -1
- package/components/input/dist/registered.js +1 -1
- package/components/radio/demo/customize.min.js +2186 -0
- package/components/radio/demo/demo-support.min.js +55807 -0
- package/components/radio/demo/getting-started.js +1 -1
- package/components/radio/demo/getting-started.md +1 -1
- package/components/radio/demo/getting-started.min.js +2205 -0
- package/components/radio/demo/index.min.js +1 -1
- package/components/radio/dist/index.js +1 -1
- package/components/radio/dist/registered.js +1 -1
- package/components/select/demo/customize.html +2 -2
- package/components/select/demo/customize.min.js +208 -15
- package/components/select/demo/getting-started.min.js +208 -15
- package/components/select/demo/index.min.js +208 -15
- package/components/select/demo/keyboard-behavior.md +1 -0
- package/components/select/dist/index.js +208 -15
- package/components/select/dist/registered.js +208 -15
- package/custom-elements.json +703 -91
- package/package.json +2 -2
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @property {string | number | boolean | string[] | null} value - The value of the form element.
|
|
4
4
|
* @property {ValidityState} validity - The validity state of the form element, stored when fired from the form element.
|
|
5
5
|
* @property {boolean} required - Whether the form element is required or not.
|
|
6
|
+
* @property {HTMLElement} element - Whether the form element is required or not.
|
|
6
7
|
*/
|
|
7
8
|
/**
|
|
8
9
|
* @typedef {Object.<string, FormStateMember>} FormState - The form state.
|
|
@@ -94,22 +95,6 @@ export class AuroForm extends LitElement {
|
|
|
94
95
|
* @type {MutationObserver[]}
|
|
95
96
|
*/
|
|
96
97
|
private mutationObservers;
|
|
97
|
-
/**
|
|
98
|
-
* @private
|
|
99
|
-
* @type {MutationObserver | null}
|
|
100
|
-
*/
|
|
101
|
-
private _attributeObserver;
|
|
102
|
-
/**
|
|
103
|
-
* Handle batched MutationObserver records for `disabled` and `name`
|
|
104
|
-
* attribute changes on tracked form elements. A `name` change invalidates
|
|
105
|
-
* the formState keying — we resolve it by re-initializing state. A `disabled`
|
|
106
|
-
* change simply needs a re-render (so `value` / `validity` getters re-evaluate)
|
|
107
|
-
* and a refresh of the submit/reset button enablement.
|
|
108
|
-
* @param {MutationRecord[]} mutations - The batched mutation records.
|
|
109
|
-
* @returns {void}
|
|
110
|
-
* @private
|
|
111
|
-
*/
|
|
112
|
-
private _handleAttributeMutations;
|
|
113
98
|
/**
|
|
114
99
|
* Resets all form elements to their initial state and fires a `reset` event. The event's `detail.previousValue` contains the form values captured immediately before the reset.
|
|
115
100
|
* @returns {void}
|
|
@@ -170,35 +155,6 @@ export class AuroForm extends LitElement {
|
|
|
170
155
|
* @private
|
|
171
156
|
*/
|
|
172
157
|
private isFormElement;
|
|
173
|
-
/**
|
|
174
|
-
* Whether a given element is currently disabled. Disabled controls are excluded
|
|
175
|
-
* from submission, validity, and initial-state checks (per the HTML spec).
|
|
176
|
-
*
|
|
177
|
-
* Implementation note: we deliberately read only the attribute. Every Auro
|
|
178
|
-
* form element in `formElementTags` declares `disabled` with `reflect: true`,
|
|
179
|
-
* so the attribute and property stay in sync. Reading the attribute also
|
|
180
|
-
* lets the MutationObserver in `connectedCallback` (which is filtered to
|
|
181
|
-
* `['disabled', 'name']`) be the single source of truth for re-renders.
|
|
182
|
-
* If a future form-element type ships without attribute reflection, expand
|
|
183
|
-
* this helper to also read `element.disabled`.
|
|
184
|
-
* @param {HTMLElement | undefined | null} element - The element to check.
|
|
185
|
-
* @returns {boolean}
|
|
186
|
-
* @private
|
|
187
|
-
*/
|
|
188
|
-
private _isDisabled;
|
|
189
|
-
/**
|
|
190
|
-
* Whether the tracked form element registered under `name` is currently disabled.
|
|
191
|
-
*
|
|
192
|
-
* Performance note: this is called once per `formState` key per read of
|
|
193
|
-
* `value` / `validity` / `isInitialState`, producing O(n²) work where n is
|
|
194
|
-
* the number of tracked fields. Acceptable for typical forms (< ~50 fields).
|
|
195
|
-
* For larger forms, a future refactor should store disabled state on each
|
|
196
|
-
* `formState` entry and update it from the attribute observer instead.
|
|
197
|
-
* @param {string} name - The `name` attribute used to register the element.
|
|
198
|
-
* @returns {boolean}
|
|
199
|
-
* @private
|
|
200
|
-
*/
|
|
201
|
-
private _isNameDisabled;
|
|
202
158
|
/**
|
|
203
159
|
* Validates if an event is from a valid form element with a name.
|
|
204
160
|
* @param {Event} event - The event to validate.
|
|
@@ -310,6 +266,10 @@ export type FormStateMember = {
|
|
|
310
266
|
* - Whether the form element is required or not.
|
|
311
267
|
*/
|
|
312
268
|
required: boolean;
|
|
269
|
+
/**
|
|
270
|
+
* - Whether the form element is required or not.
|
|
271
|
+
*/
|
|
272
|
+
element: HTMLElement;
|
|
313
273
|
};
|
|
314
274
|
/**
|
|
315
275
|
* - The form state.
|
|
@@ -93,6 +93,7 @@ class AuroLibraryRuntimeUtils {
|
|
|
93
93
|
* @property {string | number | boolean | string[] | null} value - The value of the form element.
|
|
94
94
|
* @property {ValidityState} validity - The validity state of the form element, stored when fired from the form element.
|
|
95
95
|
* @property {boolean} required - Whether the form element is required or not.
|
|
96
|
+
* @property {HTMLElement} element - Whether the form element is required or not.
|
|
96
97
|
*/
|
|
97
98
|
|
|
98
99
|
/**
|
|
@@ -176,20 +177,6 @@ class AuroForm extends LitElement {
|
|
|
176
177
|
*/
|
|
177
178
|
this.mutationObservers = [];
|
|
178
179
|
|
|
179
|
-
// Single subtree observer that watches `disabled` and `name` attribute
|
|
180
|
-
// changes across all tracked form elements. The `name` watch is required:
|
|
181
|
-
// without it, renaming a tracked field at runtime leaves a stale key in
|
|
182
|
-
// `formState` that `_isNameDisabled` cannot resolve, so a renamed-but-
|
|
183
|
-
// disabled field would re-appear in `.value`.
|
|
184
|
-
/**
|
|
185
|
-
* @private
|
|
186
|
-
* @type {MutationObserver | null}
|
|
187
|
-
*/
|
|
188
|
-
this._attributeObserver = null;
|
|
189
|
-
|
|
190
|
-
/** @private */
|
|
191
|
-
this._handleAttributeMutations = this._handleAttributeMutations.bind(this);
|
|
192
|
-
|
|
193
180
|
// Bind listeners
|
|
194
181
|
/** @private */
|
|
195
182
|
this.reset = this.reset.bind(this);
|
|
@@ -258,42 +245,6 @@ class AuroForm extends LitElement {
|
|
|
258
245
|
return this._isInElementCollection(AuroForm.formElementTags, element);
|
|
259
246
|
}
|
|
260
247
|
|
|
261
|
-
/**
|
|
262
|
-
* Whether a given element is currently disabled. Disabled controls are excluded
|
|
263
|
-
* from submission, validity, and initial-state checks (per the HTML spec).
|
|
264
|
-
*
|
|
265
|
-
* Implementation note: we deliberately read only the attribute. Every Auro
|
|
266
|
-
* form element in `formElementTags` declares `disabled` with `reflect: true`,
|
|
267
|
-
* so the attribute and property stay in sync. Reading the attribute also
|
|
268
|
-
* lets the MutationObserver in `connectedCallback` (which is filtered to
|
|
269
|
-
* `['disabled', 'name']`) be the single source of truth for re-renders.
|
|
270
|
-
* If a future form-element type ships without attribute reflection, expand
|
|
271
|
-
* this helper to also read `element.disabled`.
|
|
272
|
-
* @param {HTMLElement | undefined | null} element - The element to check.
|
|
273
|
-
* @returns {boolean}
|
|
274
|
-
* @private
|
|
275
|
-
*/
|
|
276
|
-
_isDisabled(element) {
|
|
277
|
-
return Boolean(element?.hasAttribute('disabled'));
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Whether the tracked form element registered under `name` is currently disabled.
|
|
282
|
-
*
|
|
283
|
-
* Performance note: this is called once per `formState` key per read of
|
|
284
|
-
* `value` / `validity` / `isInitialState`, producing O(n²) work where n is
|
|
285
|
-
* the number of tracked fields. Acceptable for typical forms (< ~50 fields).
|
|
286
|
-
* For larger forms, a future refactor should store disabled state on each
|
|
287
|
-
* `formState` entry and update it from the attribute observer instead.
|
|
288
|
-
* @param {string} name - The `name` attribute used to register the element.
|
|
289
|
-
* @returns {boolean}
|
|
290
|
-
* @private
|
|
291
|
-
*/
|
|
292
|
-
_isNameDisabled(name) {
|
|
293
|
-
const element = this._elements.find((el) => el.getAttribute('name') === name);
|
|
294
|
-
return this._isDisabled(element);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
248
|
/**
|
|
298
249
|
* Validates if an event is from a valid form element with a name.
|
|
299
250
|
* @param {Event} event - The event to validate.
|
|
@@ -333,10 +284,6 @@ class AuroForm extends LitElement {
|
|
|
333
284
|
*/
|
|
334
285
|
get value() {
|
|
335
286
|
return Object.keys(this.formState).reduce((acc, key) => {
|
|
336
|
-
if (this._isNameDisabled(key)) {
|
|
337
|
-
return acc;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
287
|
acc[key] = this.formState[key].value;
|
|
341
288
|
return acc;
|
|
342
289
|
}, {});
|
|
@@ -371,10 +318,6 @@ class AuroForm extends LitElement {
|
|
|
371
318
|
// go through validity states and return the first invalid state (if any)
|
|
372
319
|
const invalidKey = Object.keys(this.formState).
|
|
373
320
|
find((key) => {
|
|
374
|
-
if (this._isNameDisabled(key)) {
|
|
375
|
-
return false;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
321
|
const formKey = this.formState[key];
|
|
379
322
|
// these are NOT extra parens
|
|
380
323
|
// eslint-disable-next-line no-extra-parens
|
|
@@ -401,13 +344,7 @@ class AuroForm extends LitElement {
|
|
|
401
344
|
* @private
|
|
402
345
|
*/
|
|
403
346
|
_setInitialState() {
|
|
404
|
-
const anyTainted = Object.keys(this.formState).some((key) =>
|
|
405
|
-
if (this._isNameDisabled(key)) {
|
|
406
|
-
return false;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
return this.formState[key].validity !== null || this.formState[key].value !== null;
|
|
410
|
-
});
|
|
347
|
+
const anyTainted = Object.keys(this.formState).some((key) => this.formState[key].validity !== null || this.formState[key].value !== null);
|
|
411
348
|
|
|
412
349
|
this._isInitialState = !anyTainted;
|
|
413
350
|
|
|
@@ -491,6 +428,7 @@ class AuroForm extends LitElement {
|
|
|
491
428
|
value: element.value || element.getAttribute('value'),
|
|
492
429
|
validity: element.validity || null,
|
|
493
430
|
required: element.hasAttribute('required'),
|
|
431
|
+
// element
|
|
494
432
|
};
|
|
495
433
|
|
|
496
434
|
this._elements.push(element);
|
|
@@ -573,13 +511,10 @@ class AuroForm extends LitElement {
|
|
|
573
511
|
* @returns {Promise<void>}
|
|
574
512
|
*/
|
|
575
513
|
async submit() {
|
|
576
|
-
// Force validation on
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
forEach((element) => {
|
|
581
|
-
element.validate(true);
|
|
582
|
-
});
|
|
514
|
+
// Force validation on ALL elements
|
|
515
|
+
this._elements.forEach((element) => {
|
|
516
|
+
element.validate(true);
|
|
517
|
+
});
|
|
583
518
|
|
|
584
519
|
// Wait for validation to complete and formState to update
|
|
585
520
|
await this.updateComplete;
|
|
@@ -667,11 +602,6 @@ class AuroForm extends LitElement {
|
|
|
667
602
|
*/
|
|
668
603
|
handleKeyDown(event) {
|
|
669
604
|
if (event.key === 'Enter' && this.isFormElement(event.target)) {
|
|
670
|
-
// Disabled controls do not submit a form natively.
|
|
671
|
-
if (this._isDisabled(event.target)) {
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
|
|
675
605
|
// Don't submit if it's a textarea (allow new lines)
|
|
676
606
|
if (event.target.tagName.toLowerCase() === 'textarea' ||
|
|
677
607
|
event.target.hasAttribute('textarea')) {
|
|
@@ -703,81 +633,6 @@ class AuroForm extends LitElement {
|
|
|
703
633
|
});
|
|
704
634
|
}
|
|
705
635
|
|
|
706
|
-
/**
|
|
707
|
-
* Handle batched MutationObserver records for `disabled` and `name`
|
|
708
|
-
* attribute changes on tracked form elements. A `name` change invalidates
|
|
709
|
-
* the formState keying — we resolve it by re-initializing state. A `disabled`
|
|
710
|
-
* change simply needs a re-render (so `value` / `validity` getters re-evaluate)
|
|
711
|
-
* and a refresh of the submit/reset button enablement.
|
|
712
|
-
* @param {MutationRecord[]} mutations - The batched mutation records.
|
|
713
|
-
* @returns {void}
|
|
714
|
-
* @private
|
|
715
|
-
*/
|
|
716
|
-
_handleAttributeMutations(mutations) {
|
|
717
|
-
// Only mutations on tracked FORM elements matter here. The same observer
|
|
718
|
-
// also sees attribute changes on the submit/reset buttons (which this
|
|
719
|
-
// component itself toggles via `setDisabledStateOnButtons`); reacting to
|
|
720
|
-
// those would create an infinite observer/update loop.
|
|
721
|
-
const relevant = mutations.filter((mutation) => this.isFormElement(mutation.target));
|
|
722
|
-
if (relevant.length === 0) {
|
|
723
|
-
return;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
const renameOccurred = relevant.some((mutation) => mutation.attributeName === 'name');
|
|
727
|
-
if (renameOccurred) {
|
|
728
|
-
// initializeState() rebuilds formState from scratch (re-keying any
|
|
729
|
-
// renamed element) and also dispatches `change` + refreshes button state.
|
|
730
|
-
// We also re-run _attachEventListeners() because elements that previously
|
|
731
|
-
// had no `name` were skipped by queryAuroElements() (which selects
|
|
732
|
-
// `[name]`) and therefore never received input/validation/keydown
|
|
733
|
-
// listeners. Re-attaching is safe — the listener-removal step inside
|
|
734
|
-
// _attachEventListeners() prevents duplicates on already-wired elements.
|
|
735
|
-
this.initializeState();
|
|
736
|
-
this._attachEventListeners();
|
|
737
|
-
return;
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
this.requestUpdate('formState');
|
|
741
|
-
this.setDisabledStateOnButtons();
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
/**
|
|
745
|
-
* @returns {void}
|
|
746
|
-
*/
|
|
747
|
-
connectedCallback() {
|
|
748
|
-
super.connectedCallback();
|
|
749
|
-
|
|
750
|
-
// One observer rooted at the host catches `disabled` / `name` changes on
|
|
751
|
-
// any tracked form element (light-DOM children, including those nested in
|
|
752
|
-
// wrapper elements). Cheaper than allocating an observer per element and
|
|
753
|
-
// resilient to runtime DOM mutations.
|
|
754
|
-
if (!this._attributeObserver) {
|
|
755
|
-
this._attributeObserver = new MutationObserver(this._handleAttributeMutations);
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
this._attributeObserver.observe(this, {
|
|
759
|
-
attributes: true,
|
|
760
|
-
subtree: true,
|
|
761
|
-
attributeFilter: [
|
|
762
|
-
'disabled',
|
|
763
|
-
'name'
|
|
764
|
-
]
|
|
765
|
-
});
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
/**
|
|
769
|
-
* @returns {void}
|
|
770
|
-
*/
|
|
771
|
-
disconnectedCallback() {
|
|
772
|
-
// Disconnect everything we own to avoid leaking observers (and the strong
|
|
773
|
-
// refs they hold to DOM nodes) past the form's lifetime.
|
|
774
|
-
this._attributeObserver?.disconnect();
|
|
775
|
-
this.mutationObservers.forEach((observer) => observer.disconnect());
|
|
776
|
-
this.mutationObservers = [];
|
|
777
|
-
|
|
778
|
-
super.disconnectedCallback();
|
|
779
|
-
}
|
|
780
|
-
|
|
781
636
|
/**
|
|
782
637
|
* @param {import('lit').PropertyValues} _changedProperties - Map of changed properties with their previous values.
|
|
783
638
|
* @returns {void}
|
|
@@ -93,6 +93,7 @@ class AuroLibraryRuntimeUtils {
|
|
|
93
93
|
* @property {string | number | boolean | string[] | null} value - The value of the form element.
|
|
94
94
|
* @property {ValidityState} validity - The validity state of the form element, stored when fired from the form element.
|
|
95
95
|
* @property {boolean} required - Whether the form element is required or not.
|
|
96
|
+
* @property {HTMLElement} element - Whether the form element is required or not.
|
|
96
97
|
*/
|
|
97
98
|
|
|
98
99
|
/**
|
|
@@ -176,20 +177,6 @@ class AuroForm extends LitElement {
|
|
|
176
177
|
*/
|
|
177
178
|
this.mutationObservers = [];
|
|
178
179
|
|
|
179
|
-
// Single subtree observer that watches `disabled` and `name` attribute
|
|
180
|
-
// changes across all tracked form elements. The `name` watch is required:
|
|
181
|
-
// without it, renaming a tracked field at runtime leaves a stale key in
|
|
182
|
-
// `formState` that `_isNameDisabled` cannot resolve, so a renamed-but-
|
|
183
|
-
// disabled field would re-appear in `.value`.
|
|
184
|
-
/**
|
|
185
|
-
* @private
|
|
186
|
-
* @type {MutationObserver | null}
|
|
187
|
-
*/
|
|
188
|
-
this._attributeObserver = null;
|
|
189
|
-
|
|
190
|
-
/** @private */
|
|
191
|
-
this._handleAttributeMutations = this._handleAttributeMutations.bind(this);
|
|
192
|
-
|
|
193
180
|
// Bind listeners
|
|
194
181
|
/** @private */
|
|
195
182
|
this.reset = this.reset.bind(this);
|
|
@@ -258,42 +245,6 @@ class AuroForm extends LitElement {
|
|
|
258
245
|
return this._isInElementCollection(AuroForm.formElementTags, element);
|
|
259
246
|
}
|
|
260
247
|
|
|
261
|
-
/**
|
|
262
|
-
* Whether a given element is currently disabled. Disabled controls are excluded
|
|
263
|
-
* from submission, validity, and initial-state checks (per the HTML spec).
|
|
264
|
-
*
|
|
265
|
-
* Implementation note: we deliberately read only the attribute. Every Auro
|
|
266
|
-
* form element in `formElementTags` declares `disabled` with `reflect: true`,
|
|
267
|
-
* so the attribute and property stay in sync. Reading the attribute also
|
|
268
|
-
* lets the MutationObserver in `connectedCallback` (which is filtered to
|
|
269
|
-
* `['disabled', 'name']`) be the single source of truth for re-renders.
|
|
270
|
-
* If a future form-element type ships without attribute reflection, expand
|
|
271
|
-
* this helper to also read `element.disabled`.
|
|
272
|
-
* @param {HTMLElement | undefined | null} element - The element to check.
|
|
273
|
-
* @returns {boolean}
|
|
274
|
-
* @private
|
|
275
|
-
*/
|
|
276
|
-
_isDisabled(element) {
|
|
277
|
-
return Boolean(element?.hasAttribute('disabled'));
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Whether the tracked form element registered under `name` is currently disabled.
|
|
282
|
-
*
|
|
283
|
-
* Performance note: this is called once per `formState` key per read of
|
|
284
|
-
* `value` / `validity` / `isInitialState`, producing O(n²) work where n is
|
|
285
|
-
* the number of tracked fields. Acceptable for typical forms (< ~50 fields).
|
|
286
|
-
* For larger forms, a future refactor should store disabled state on each
|
|
287
|
-
* `formState` entry and update it from the attribute observer instead.
|
|
288
|
-
* @param {string} name - The `name` attribute used to register the element.
|
|
289
|
-
* @returns {boolean}
|
|
290
|
-
* @private
|
|
291
|
-
*/
|
|
292
|
-
_isNameDisabled(name) {
|
|
293
|
-
const element = this._elements.find((el) => el.getAttribute('name') === name);
|
|
294
|
-
return this._isDisabled(element);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
248
|
/**
|
|
298
249
|
* Validates if an event is from a valid form element with a name.
|
|
299
250
|
* @param {Event} event - The event to validate.
|
|
@@ -333,10 +284,6 @@ class AuroForm extends LitElement {
|
|
|
333
284
|
*/
|
|
334
285
|
get value() {
|
|
335
286
|
return Object.keys(this.formState).reduce((acc, key) => {
|
|
336
|
-
if (this._isNameDisabled(key)) {
|
|
337
|
-
return acc;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
287
|
acc[key] = this.formState[key].value;
|
|
341
288
|
return acc;
|
|
342
289
|
}, {});
|
|
@@ -371,10 +318,6 @@ class AuroForm extends LitElement {
|
|
|
371
318
|
// go through validity states and return the first invalid state (if any)
|
|
372
319
|
const invalidKey = Object.keys(this.formState).
|
|
373
320
|
find((key) => {
|
|
374
|
-
if (this._isNameDisabled(key)) {
|
|
375
|
-
return false;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
321
|
const formKey = this.formState[key];
|
|
379
322
|
// these are NOT extra parens
|
|
380
323
|
// eslint-disable-next-line no-extra-parens
|
|
@@ -401,13 +344,7 @@ class AuroForm extends LitElement {
|
|
|
401
344
|
* @private
|
|
402
345
|
*/
|
|
403
346
|
_setInitialState() {
|
|
404
|
-
const anyTainted = Object.keys(this.formState).some((key) =>
|
|
405
|
-
if (this._isNameDisabled(key)) {
|
|
406
|
-
return false;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
return this.formState[key].validity !== null || this.formState[key].value !== null;
|
|
410
|
-
});
|
|
347
|
+
const anyTainted = Object.keys(this.formState).some((key) => this.formState[key].validity !== null || this.formState[key].value !== null);
|
|
411
348
|
|
|
412
349
|
this._isInitialState = !anyTainted;
|
|
413
350
|
|
|
@@ -491,6 +428,7 @@ class AuroForm extends LitElement {
|
|
|
491
428
|
value: element.value || element.getAttribute('value'),
|
|
492
429
|
validity: element.validity || null,
|
|
493
430
|
required: element.hasAttribute('required'),
|
|
431
|
+
// element
|
|
494
432
|
};
|
|
495
433
|
|
|
496
434
|
this._elements.push(element);
|
|
@@ -573,13 +511,10 @@ class AuroForm extends LitElement {
|
|
|
573
511
|
* @returns {Promise<void>}
|
|
574
512
|
*/
|
|
575
513
|
async submit() {
|
|
576
|
-
// Force validation on
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
forEach((element) => {
|
|
581
|
-
element.validate(true);
|
|
582
|
-
});
|
|
514
|
+
// Force validation on ALL elements
|
|
515
|
+
this._elements.forEach((element) => {
|
|
516
|
+
element.validate(true);
|
|
517
|
+
});
|
|
583
518
|
|
|
584
519
|
// Wait for validation to complete and formState to update
|
|
585
520
|
await this.updateComplete;
|
|
@@ -667,11 +602,6 @@ class AuroForm extends LitElement {
|
|
|
667
602
|
*/
|
|
668
603
|
handleKeyDown(event) {
|
|
669
604
|
if (event.key === 'Enter' && this.isFormElement(event.target)) {
|
|
670
|
-
// Disabled controls do not submit a form natively.
|
|
671
|
-
if (this._isDisabled(event.target)) {
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
|
|
675
605
|
// Don't submit if it's a textarea (allow new lines)
|
|
676
606
|
if (event.target.tagName.toLowerCase() === 'textarea' ||
|
|
677
607
|
event.target.hasAttribute('textarea')) {
|
|
@@ -703,81 +633,6 @@ class AuroForm extends LitElement {
|
|
|
703
633
|
});
|
|
704
634
|
}
|
|
705
635
|
|
|
706
|
-
/**
|
|
707
|
-
* Handle batched MutationObserver records for `disabled` and `name`
|
|
708
|
-
* attribute changes on tracked form elements. A `name` change invalidates
|
|
709
|
-
* the formState keying — we resolve it by re-initializing state. A `disabled`
|
|
710
|
-
* change simply needs a re-render (so `value` / `validity` getters re-evaluate)
|
|
711
|
-
* and a refresh of the submit/reset button enablement.
|
|
712
|
-
* @param {MutationRecord[]} mutations - The batched mutation records.
|
|
713
|
-
* @returns {void}
|
|
714
|
-
* @private
|
|
715
|
-
*/
|
|
716
|
-
_handleAttributeMutations(mutations) {
|
|
717
|
-
// Only mutations on tracked FORM elements matter here. The same observer
|
|
718
|
-
// also sees attribute changes on the submit/reset buttons (which this
|
|
719
|
-
// component itself toggles via `setDisabledStateOnButtons`); reacting to
|
|
720
|
-
// those would create an infinite observer/update loop.
|
|
721
|
-
const relevant = mutations.filter((mutation) => this.isFormElement(mutation.target));
|
|
722
|
-
if (relevant.length === 0) {
|
|
723
|
-
return;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
const renameOccurred = relevant.some((mutation) => mutation.attributeName === 'name');
|
|
727
|
-
if (renameOccurred) {
|
|
728
|
-
// initializeState() rebuilds formState from scratch (re-keying any
|
|
729
|
-
// renamed element) and also dispatches `change` + refreshes button state.
|
|
730
|
-
// We also re-run _attachEventListeners() because elements that previously
|
|
731
|
-
// had no `name` were skipped by queryAuroElements() (which selects
|
|
732
|
-
// `[name]`) and therefore never received input/validation/keydown
|
|
733
|
-
// listeners. Re-attaching is safe — the listener-removal step inside
|
|
734
|
-
// _attachEventListeners() prevents duplicates on already-wired elements.
|
|
735
|
-
this.initializeState();
|
|
736
|
-
this._attachEventListeners();
|
|
737
|
-
return;
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
this.requestUpdate('formState');
|
|
741
|
-
this.setDisabledStateOnButtons();
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
/**
|
|
745
|
-
* @returns {void}
|
|
746
|
-
*/
|
|
747
|
-
connectedCallback() {
|
|
748
|
-
super.connectedCallback();
|
|
749
|
-
|
|
750
|
-
// One observer rooted at the host catches `disabled` / `name` changes on
|
|
751
|
-
// any tracked form element (light-DOM children, including those nested in
|
|
752
|
-
// wrapper elements). Cheaper than allocating an observer per element and
|
|
753
|
-
// resilient to runtime DOM mutations.
|
|
754
|
-
if (!this._attributeObserver) {
|
|
755
|
-
this._attributeObserver = new MutationObserver(this._handleAttributeMutations);
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
this._attributeObserver.observe(this, {
|
|
759
|
-
attributes: true,
|
|
760
|
-
subtree: true,
|
|
761
|
-
attributeFilter: [
|
|
762
|
-
'disabled',
|
|
763
|
-
'name'
|
|
764
|
-
]
|
|
765
|
-
});
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
/**
|
|
769
|
-
* @returns {void}
|
|
770
|
-
*/
|
|
771
|
-
disconnectedCallback() {
|
|
772
|
-
// Disconnect everything we own to avoid leaking observers (and the strong
|
|
773
|
-
// refs they hold to DOM nodes) past the form's lifetime.
|
|
774
|
-
this._attributeObserver?.disconnect();
|
|
775
|
-
this.mutationObservers.forEach((observer) => observer.disconnect());
|
|
776
|
-
this.mutationObservers = [];
|
|
777
|
-
|
|
778
|
-
super.disconnectedCallback();
|
|
779
|
-
}
|
|
780
|
-
|
|
781
636
|
/**
|
|
782
637
|
* @param {import('lit').PropertyValues} _changedProperties - Map of changed properties with their previous values.
|
|
783
638
|
* @returns {void}
|
|
@@ -42,11 +42,12 @@
|
|
|
42
42
|
<script src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-icon@latest/+esm" type="module"></script>
|
|
43
43
|
<script src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-button@latest/+esm" type="module"></script>
|
|
44
44
|
<script src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-formkit@latest/auro-radio/+esm" type="module"></script>
|
|
45
|
-
<script type="module"
|
|
45
|
+
<script type="module">
|
|
46
46
|
import { renderPage } from './demo-support.min.js';
|
|
47
47
|
await renderPage('./customize.md');
|
|
48
48
|
import { initExamples } from "./customize.min.js";
|
|
49
49
|
initExamples();
|
|
50
50
|
</script>
|
|
51
|
+
<script src="./customize.min.js" data-demo-script="true" type="module"></script>
|
|
51
52
|
</body>
|
|
52
53
|
</html>
|
|
@@ -6614,7 +6614,7 @@ class AuroHelpText extends LitElement {
|
|
|
6614
6614
|
}
|
|
6615
6615
|
}
|
|
6616
6616
|
|
|
6617
|
-
var formkitVersion = '
|
|
6617
|
+
var formkitVersion = '202605182147';
|
|
6618
6618
|
|
|
6619
6619
|
// Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
6620
6620
|
// See LICENSE in the project root for license information.
|
|
@@ -6614,7 +6614,7 @@ class AuroHelpText extends LitElement {
|
|
|
6614
6614
|
}
|
|
6615
6615
|
}
|
|
6616
6616
|
|
|
6617
|
-
var formkitVersion = '
|
|
6617
|
+
var formkitVersion = '202605182147';
|
|
6618
6618
|
|
|
6619
6619
|
// Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
6620
6620
|
// See LICENSE in the project root for license information.
|