agnosticui-core 2.0.0-alpha.21 → 2.0.0-alpha.22

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 (53) hide show
  1. package/dist/components/Checkbox/core/_Checkbox.d.ts +6 -0
  2. package/dist/components/Checkbox/core/_Checkbox.d.ts.map +1 -1
  3. package/dist/components/Checkbox/core/_Checkbox.js +44 -36
  4. package/dist/components/Combobox/core/_Combobox.d.ts +19 -0
  5. package/dist/components/Combobox/core/_Combobox.d.ts.map +1 -1
  6. package/dist/components/Combobox/core/_Combobox.js +154 -122
  7. package/dist/components/Combobox/vue/VueCombobox.vue.d.ts +1 -1
  8. package/dist/components/Dialog/core/_dialog.d.ts.map +1 -1
  9. package/dist/components/Dialog/core/_dialog.js +176 -166
  10. package/dist/components/Dialog/react/ReactDialog.d.ts +27 -8
  11. package/dist/components/Dialog/react/ReactDialog.d.ts.map +1 -1
  12. package/dist/components/Dialog/react/ReactDialog.js +32 -10
  13. package/dist/components/Input/core/_Input.d.ts +19 -0
  14. package/dist/components/Input/core/_Input.d.ts.map +1 -1
  15. package/dist/components/Input/core/_Input.js +34 -9
  16. package/dist/components/Radio/core/_Radio.d.ts +5 -0
  17. package/dist/components/Radio/core/_Radio.d.ts.map +1 -1
  18. package/dist/components/Radio/core/_Radio.js +38 -31
  19. package/dist/components/Rating/core/_Rating.d.ts +18 -0
  20. package/dist/components/Rating/core/_Rating.d.ts.map +1 -1
  21. package/dist/components/Rating/core/_Rating.js +90 -68
  22. package/dist/components/Select/core/_Select.d.ts +19 -0
  23. package/dist/components/Select/core/_Select.d.ts.map +1 -1
  24. package/dist/components/Select/core/_Select.js +102 -65
  25. package/dist/components/SelectionButtonGroup/core/_SelectionButtonGroup.d.ts +18 -0
  26. package/dist/components/SelectionButtonGroup/core/_SelectionButtonGroup.d.ts.map +1 -1
  27. package/dist/components/SelectionButtonGroup/core/_SelectionButtonGroup.js +54 -32
  28. package/dist/components/SelectionCardGroup/core/_SelectionCardGroup.d.ts +18 -0
  29. package/dist/components/SelectionCardGroup/core/_SelectionCardGroup.d.ts.map +1 -1
  30. package/dist/components/SelectionCardGroup/core/_SelectionCardGroup.js +61 -39
  31. package/dist/components/Slider/core/_Slider.d.ts +20 -0
  32. package/dist/components/Slider/core/_Slider.d.ts.map +1 -1
  33. package/dist/components/Slider/core/_Slider.js +132 -104
  34. package/dist/components/Toggle/core/_Toggle.d.ts +6 -0
  35. package/dist/components/Toggle/core/_Toggle.d.ts.map +1 -1
  36. package/dist/components/Toggle/core/_Toggle.js +94 -86
  37. package/dist/shared/face-mixin.d.ts +5 -0
  38. package/dist/shared/face-mixin.d.ts.map +1 -1
  39. package/dist/shared/face-mixin.js +39 -25
  40. package/package.json +1 -1
  41. package/src/components/Checkbox/core/_Checkbox.ts +16 -0
  42. package/src/components/Combobox/core/_Combobox.ts +53 -0
  43. package/src/components/Dialog/core/_dialog.ts +19 -2
  44. package/src/components/Dialog/react/ReactDialog.tsx +60 -3
  45. package/src/components/Input/core/_Input.ts +47 -0
  46. package/src/components/Radio/core/_Radio.ts +14 -0
  47. package/src/components/Rating/core/_Rating.ts +42 -0
  48. package/src/components/Select/core/_Select.ts +57 -0
  49. package/src/components/SelectionButtonGroup/core/_SelectionButtonGroup.ts +48 -0
  50. package/src/components/SelectionCardGroup/core/_SelectionCardGroup.ts +48 -0
  51. package/src/components/Slider/core/_Slider.ts +53 -0
  52. package/src/components/Toggle/core/_Toggle.ts +15 -0
  53. package/src/shared/face-mixin.ts +48 -6
@@ -496,6 +496,40 @@ export class AgInput extends FaceMixin(LitElement) implements InputProps {
496
496
  this.value = '';
497
497
  this._internals.setFormValue('');
498
498
  this._internals.setValidity({});
499
+ this._syncStates();
500
+ }
501
+
502
+ /**
503
+ * FACE lifecycle: called on session restore or browser autofill.
504
+ * Restores the input value from the previously saved form state.
505
+ */
506
+ override formStateRestoreCallback(
507
+ state: File | string | FormData | null,
508
+ _mode: 'restore' | 'autocomplete'
509
+ ): void {
510
+ this.value = typeof state === 'string' ? state : '';
511
+ this._internals.setFormValue(this.value);
512
+ this._syncValidity();
513
+ this._syncStates();
514
+ }
515
+
516
+ /**
517
+ * Sync CustomStateSet states so :state() pseudo-classes work from external CSS.
518
+ *
519
+ * Must be called AFTER _syncValidity() so that :state(invalid) reads the
520
+ * freshly-updated _internals.validity.valid value.
521
+ *
522
+ * Exposed states:
523
+ * :state(disabled) — input is disabled
524
+ * :state(readonly) — input is read-only
525
+ * :state(required) — input is required
526
+ * :state(invalid) — FACE constraint validation is failing
527
+ */
528
+ private _syncStates(): void {
529
+ this._setState('disabled', this.disabled);
530
+ this._setState('readonly', this.readonly);
531
+ this._setState('required', this.required);
532
+ this._setState('invalid', !this._internals.validity.valid);
499
533
  }
500
534
 
501
535
  /**
@@ -678,10 +712,23 @@ export class AgInput extends FaceMixin(LitElement) implements InputProps {
678
712
  `;
679
713
  }
680
714
 
715
+ override updated(changedProperties: Map<string, unknown>) {
716
+ super.updated(changedProperties);
717
+ if (
718
+ changedProperties.has('disabled') ||
719
+ changedProperties.has('readonly') ||
720
+ changedProperties.has('required') ||
721
+ changedProperties.has('invalid')
722
+ ) {
723
+ this._syncStates();
724
+ }
725
+ }
726
+
681
727
  override firstUpdated() {
682
728
  // FACE: set initial form value and sync validity after first render
683
729
  this._internals.setFormValue(this.value ?? '');
684
730
  this._syncValidity();
731
+ this._syncStates();
685
732
 
686
733
  // Initial check for slot content
687
734
  setTimeout(() => {
@@ -405,6 +405,20 @@ export class AgRadio extends FaceMixin(LitElement) implements RadioProps {
405
405
  this._syncStates();
406
406
  }
407
407
 
408
+ /**
409
+ * FACE lifecycle: called on session restore or browser autofill.
410
+ * Restores checked state: checked when the saved state matches this radio's value.
411
+ */
412
+ override formStateRestoreCallback(
413
+ state: File | string | FormData | null,
414
+ _mode: 'restore' | 'autocomplete'
415
+ ): void {
416
+ this.checked = state === this.value;
417
+ this._syncFormValue();
418
+ this._syncValidity();
419
+ this._syncStates();
420
+ }
421
+
408
422
  /**
409
423
  * Sync CustomStateSet states so :state() pseudo-classes work from external CSS.
410
424
  *
@@ -184,6 +184,7 @@ export class AgRating extends FaceMixin(LitElement) {
184
184
  override firstUpdated() {
185
185
  this._syncFormValue();
186
186
  this._syncValidity();
187
+ this._syncStates();
187
188
  }
188
189
 
189
190
  override updated(changedProperties: Map<string, unknown>) {
@@ -192,6 +193,14 @@ export class AgRating extends FaceMixin(LitElement) {
192
193
  this._syncFormValue();
193
194
  this._syncValidity();
194
195
  }
196
+ if (
197
+ changedProperties.has('value') ||
198
+ changedProperties.has('readonly') ||
199
+ changedProperties.has('required') ||
200
+ changedProperties.has('invalid')
201
+ ) {
202
+ this._syncStates();
203
+ }
195
204
  }
196
205
 
197
206
  /**
@@ -202,6 +211,39 @@ export class AgRating extends FaceMixin(LitElement) {
202
211
  this.value = 0;
203
212
  this._internals.setFormValue(null);
204
213
  this._internals.setValidity({});
214
+ this._syncStates();
215
+ }
216
+
217
+ /**
218
+ * FACE lifecycle: called on session restore or browser autofill.
219
+ * Restores the rating value from the previously saved form state.
220
+ * The state is a numeric string (e.g. "3" or "3.5"), or null for no rating.
221
+ */
222
+ override formStateRestoreCallback(
223
+ state: File | string | FormData | null,
224
+ _mode: 'restore' | 'autocomplete'
225
+ ): void {
226
+ this.value = typeof state === 'string' ? parseFloat(state) : 0;
227
+ this._syncFormValue();
228
+ this._syncValidity();
229
+ this._syncStates();
230
+ }
231
+
232
+ /**
233
+ * Sync CustomStateSet states so :state() pseudo-classes work from external CSS.
234
+ *
235
+ * Must be called AFTER _syncValidity() so that :state(invalid) reads the
236
+ * freshly-updated _internals.validity.valid value.
237
+ *
238
+ * Exposed states:
239
+ * :state(readonly) — rating is read-only
240
+ * :state(required) — rating is required
241
+ * :state(invalid) — FACE constraint validation is failing
242
+ */
243
+ private _syncStates(): void {
244
+ this._setState('readonly', this.readonly);
245
+ this._setState('required', this.required);
246
+ this._setState('invalid', !this._internals.validity.valid);
205
247
  }
206
248
 
207
249
  // ─── End FACE ─────────────────────────────────────────────────────────────
@@ -114,6 +114,51 @@ export class Select extends FaceMixin(LitElement) implements SelectProps {
114
114
  }
115
115
  this._syncFormValue();
116
116
  this._internals.setValidity({});
117
+ this._syncStates();
118
+ }
119
+
120
+ /**
121
+ * FACE lifecycle: called on session restore or browser autofill.
122
+ * Restores the selected option(s) from the previously saved form state.
123
+ * Uses updateComplete to ensure options are in the DOM before restoring.
124
+ */
125
+ override formStateRestoreCallback(
126
+ state: File | string | FormData | null,
127
+ _mode: 'restore' | 'autocomplete'
128
+ ): void {
129
+ this.updateComplete.then(() => {
130
+ if (!this.selectElement) return;
131
+ if (this.multiple && state instanceof FormData) {
132
+ const restored = new Set(Array.from(state.values()) as string[]);
133
+ Array.from(this.selectElement.options).forEach(opt => {
134
+ opt.selected = restored.has(opt.value);
135
+ });
136
+ } else if (typeof state === 'string') {
137
+ Array.from(this.selectElement.options).forEach(opt => {
138
+ opt.selected = opt.value === state;
139
+ });
140
+ }
141
+ this._syncFormValue();
142
+ this._syncValidity();
143
+ this._syncStates();
144
+ });
145
+ }
146
+
147
+ /**
148
+ * Sync CustomStateSet states so :state() pseudo-classes work from external CSS.
149
+ *
150
+ * Must be called AFTER _syncValidity() so that :state(invalid) reads the
151
+ * freshly-updated _internals.validity.valid value.
152
+ *
153
+ * Exposed states:
154
+ * :state(disabled) — select is disabled
155
+ * :state(required) — select is required
156
+ * :state(invalid) — FACE constraint validation is failing
157
+ */
158
+ private _syncStates(): void {
159
+ this._setState('disabled', this.disabled);
160
+ this._setState('required', this.required);
161
+ this._setState('invalid', !this._internals.validity.valid);
117
162
  }
118
163
 
119
164
  /**
@@ -144,6 +189,17 @@ export class Select extends FaceMixin(LitElement) implements SelectProps {
144
189
 
145
190
  // ─── End FACE ─────────────────────────────────────────────────────────────
146
191
 
192
+ override updated(changedProperties: Map<string, unknown>) {
193
+ super.updated(changedProperties);
194
+ if (
195
+ changedProperties.has('disabled') ||
196
+ changedProperties.has('required') ||
197
+ changedProperties.has('invalid')
198
+ ) {
199
+ this._syncStates();
200
+ }
201
+ }
202
+
147
203
  protected firstUpdated() {
148
204
  // Ensure options are moved after first render
149
205
  this.handleSlotChange();
@@ -157,6 +213,7 @@ export class Select extends FaceMixin(LitElement) implements SelectProps {
157
213
  // FACE: set initial form value and sync validity after options are in place
158
214
  this._syncFormValue();
159
215
  this._syncValidity();
216
+ this._syncStates();
160
217
  }
161
218
 
162
219
  private handleSlotChange() {
@@ -215,6 +215,46 @@ export class AgSelectionButtonGroup extends FaceMixin(LitElement) implements Sel
215
215
  this._internals.setFormValue(null);
216
216
  this._syncValidity();
217
217
  this._syncChildButtons();
218
+ this._syncStates();
219
+ }
220
+
221
+ /**
222
+ * FACE lifecycle: called on session restore or browser autofill.
223
+ * Restores selected value(s) from the previously saved form state.
224
+ * Radio mode: state is a single string. Checkbox mode: state is FormData.
225
+ */
226
+ override formStateRestoreCallback(
227
+ state: File | string | FormData | null,
228
+ _mode: 'restore' | 'autocomplete'
229
+ ): void {
230
+ if (state === null) {
231
+ this._internalSelectedValues = [];
232
+ } else if (state instanceof FormData) {
233
+ this._internalSelectedValues = Array.from(state.getAll(this.name)) as string[];
234
+ } else if (typeof state === 'string') {
235
+ this._internalSelectedValues = [state];
236
+ }
237
+ this._syncFormValue();
238
+ this._syncValidity();
239
+ this._syncChildButtons();
240
+ this._syncStates();
241
+ }
242
+
243
+ /**
244
+ * Sync CustomStateSet states so :state() pseudo-classes work from external CSS.
245
+ *
246
+ * Must be called AFTER _syncValidity() so that :state(invalid) reads the
247
+ * freshly-updated _internals.validity.valid value.
248
+ *
249
+ * Exposed states:
250
+ * :state(disabled) — group is disabled
251
+ * :state(required) — group is required
252
+ * :state(invalid) — FACE constraint validation is failing
253
+ */
254
+ private _syncStates(): void {
255
+ this._setState('disabled', this.disabled);
256
+ this._setState('required', this.required);
257
+ this._setState('invalid', !this._internals.validity.valid);
218
258
  }
219
259
 
220
260
  // ─── End FACE ─────────────────────────────────────────────────────────────
@@ -260,12 +300,20 @@ export class AgSelectionButtonGroup extends FaceMixin(LitElement) implements Sel
260
300
  } else if (changedProperties.has('required')) {
261
301
  this._syncValidity();
262
302
  }
303
+ if (
304
+ changedProperties.has('disabled') ||
305
+ changedProperties.has('required') ||
306
+ changedProperties.has('_internalSelectedValues')
307
+ ) {
308
+ this._syncStates();
309
+ }
263
310
  }
264
311
 
265
312
  override firstUpdated() {
266
313
  this._syncChildButtons();
267
314
  this._syncFormValue();
268
315
  this._syncValidity();
316
+ this._syncStates();
269
317
  }
270
318
 
271
319
  private _getButtons(): AgSelectionButton[] {
@@ -192,6 +192,46 @@ export class AgSelectionCardGroup extends FaceMixin(LitElement) implements Selec
192
192
  this._internals.setFormValue(null);
193
193
  this._syncValidity();
194
194
  this._syncChildCards();
195
+ this._syncStates();
196
+ }
197
+
198
+ /**
199
+ * FACE lifecycle: called on session restore or browser autofill.
200
+ * Restores selected value(s) from the previously saved form state.
201
+ * Radio mode: state is a single string. Checkbox mode: state is FormData.
202
+ */
203
+ override formStateRestoreCallback(
204
+ state: File | string | FormData | null,
205
+ _mode: 'restore' | 'autocomplete'
206
+ ): void {
207
+ if (state === null) {
208
+ this._internalSelectedValues = [];
209
+ } else if (state instanceof FormData) {
210
+ this._internalSelectedValues = Array.from(state.getAll(this.name)) as string[];
211
+ } else if (typeof state === 'string') {
212
+ this._internalSelectedValues = [state];
213
+ }
214
+ this._syncFormValue();
215
+ this._syncValidity();
216
+ this._syncChildCards();
217
+ this._syncStates();
218
+ }
219
+
220
+ /**
221
+ * Sync CustomStateSet states so :state() pseudo-classes work from external CSS.
222
+ *
223
+ * Must be called AFTER _syncValidity() so that :state(invalid) reads the
224
+ * freshly-updated _internals.validity.valid value.
225
+ *
226
+ * Exposed states:
227
+ * :state(disabled) — group is disabled
228
+ * :state(required) — group is required
229
+ * :state(invalid) — FACE constraint validation is failing
230
+ */
231
+ private _syncStates(): void {
232
+ this._setState('disabled', this.disabled);
233
+ this._setState('required', this.required);
234
+ this._setState('invalid', !this._internals.validity.valid);
195
235
  }
196
236
 
197
237
  // ─── End FACE ─────────────────────────────────────────────────────────────
@@ -235,12 +275,20 @@ export class AgSelectionCardGroup extends FaceMixin(LitElement) implements Selec
235
275
  } else if (changedProperties.has('required')) {
236
276
  this._syncValidity();
237
277
  }
278
+ if (
279
+ changedProperties.has('disabled') ||
280
+ changedProperties.has('required') ||
281
+ changedProperties.has('_internalSelectedValues')
282
+ ) {
283
+ this._syncStates();
284
+ }
238
285
  }
239
286
 
240
287
  override firstUpdated() {
241
288
  this._syncChildCards();
242
289
  this._syncFormValue();
243
290
  this._syncValidity();
291
+ this._syncStates();
244
292
  }
245
293
 
246
294
  private _getCards(): AgSelectionCard[] {
@@ -671,12 +671,25 @@ export class AgSlider extends FaceMixin(LitElement) implements SliderProps {
671
671
 
672
672
  // ─── FACE ─────────────────────────────────────────────────────────────────
673
673
 
674
+ override updated(changedProperties: Map<string, unknown>) {
675
+ super.updated(changedProperties);
676
+ if (
677
+ changedProperties.has('disabled') ||
678
+ changedProperties.has('readonly') ||
679
+ changedProperties.has('required') ||
680
+ changedProperties.has('invalid')
681
+ ) {
682
+ this._syncStates();
683
+ }
684
+ }
685
+
674
686
  override firstUpdated() {
675
687
  // Capture default value for formResetCallback, then set initial form value
676
688
  this._defaultValue = Array.isArray(this.value)
677
689
  ? ([...this.value] as [number, number])
678
690
  : this.value;
679
691
  this._updateFormValue();
692
+ this._syncStates();
680
693
  }
681
694
 
682
695
  /**
@@ -688,6 +701,46 @@ export class AgSlider extends FaceMixin(LitElement) implements SliderProps {
688
701
  ? ([...this._defaultValue] as [number, number])
689
702
  : this._defaultValue;
690
703
  this._updateFormValue();
704
+ this._syncStates();
705
+ }
706
+
707
+ /**
708
+ * FACE lifecycle: called on session restore or browser autofill.
709
+ * Restores the slider value from the previously saved FormData.
710
+ * Single mode: one entry (name, valueStr). Dual mode: two entries.
711
+ */
712
+ override formStateRestoreCallback(
713
+ state: File | string | FormData | null,
714
+ _mode: 'restore' | 'autocomplete'
715
+ ): void {
716
+ if (!(state instanceof FormData) || !this.name) return;
717
+ const entries = Array.from(state.getAll(this.name)) as string[];
718
+ if (this.dual && entries.length === 2) {
719
+ this.value = [parseFloat(entries[0]), parseFloat(entries[1])];
720
+ } else if (entries.length === 1) {
721
+ this.value = parseFloat(entries[0]);
722
+ }
723
+ this._updateFormValue();
724
+ this._syncStates();
725
+ }
726
+
727
+ /**
728
+ * Sync CustomStateSet states so :state() pseudo-classes work from external CSS.
729
+ *
730
+ * Must be called AFTER _updateFormValue() (which also calls setValidity) so
731
+ * that :state(invalid) reads the freshly-updated _internals.validity.valid value.
732
+ *
733
+ * Exposed states:
734
+ * :state(disabled) — slider is disabled
735
+ * :state(readonly) — slider is read-only
736
+ * :state(required) — slider is required
737
+ * :state(invalid) — FACE constraint validation is failing
738
+ */
739
+ private _syncStates(): void {
740
+ this._setState('disabled', this.disabled);
741
+ this._setState('readonly', this.readonly);
742
+ this._setState('required', this.required);
743
+ this._setState('invalid', !this._internals.validity.valid);
691
744
  }
692
745
 
693
746
  // ─── End FACE ─────────────────────────────────────────────────────────────
@@ -396,6 +396,21 @@ export class AgToggle extends FaceMixin(LitElement) implements ToggleProps {
396
396
  this._syncStates();
397
397
  }
398
398
 
399
+ /**
400
+ * FACE lifecycle: called on session restore or browser autofill.
401
+ * Restores checked state from the previously saved form value.
402
+ * A non-null state means the toggle was on; null means it was off.
403
+ */
404
+ override formStateRestoreCallback(
405
+ state: File | string | FormData | null,
406
+ _mode: 'restore' | 'autocomplete'
407
+ ): void {
408
+ this.checked = state !== null;
409
+ this._internals.setFormValue(this.checked ? (this.value || 'on') : null);
410
+ this._syncValidity();
411
+ this._syncStates();
412
+ }
413
+
399
414
  /**
400
415
  * Sync validity state to ElementInternals.
401
416
  * Toggle has no inner <input> to delegate to, so required validation
@@ -106,6 +106,11 @@ export declare class FaceMixinInterface {
106
106
  formDisabledCallback(disabled: boolean): void;
107
107
  /** FACE lifecycle — called on form reset; subclasses should override */
108
108
  formResetCallback(): void;
109
+ /**
110
+ * FACE lifecycle — called when the browser restores session state or autofills.
111
+ * Subclasses should override to restore their own state from the saved value.
112
+ */
113
+ formStateRestoreCallback(state: File | string | FormData | null, mode: 'restore' | 'autocomplete'): void;
109
114
  /**
110
115
  * Toggle a custom state in ElementInternals.states (CustomStateSet).
111
116
  * Enables :state() pseudo-class targeting from external CSS.
@@ -135,6 +140,16 @@ export const FaceMixin = <T extends Constructor<LitElement>>(superClass: T) => {
135
140
  */
136
141
  protected _internals!: ElementInternals;
137
142
 
143
+ /**
144
+ * The disabled state the user set on this element itself (via attribute or property),
145
+ * captured before a <fieldset disabled> ancestor overwrites it.
146
+ * Restored when the fieldset is re-enabled so the two sources don't stomp each other.
147
+ */
148
+ private _ownDisabled = false;
149
+
150
+ /** True while a <fieldset disabled> ancestor is disabling this element. */
151
+ private _parentDisabled = false;
152
+
138
153
  /**
139
154
  * The name under which this control's value is submitted with the parent form.
140
155
  * Mirrors the standard `name` attribute on native form controls.
@@ -182,14 +197,21 @@ export const FaceMixin = <T extends Constructor<LitElement>>(superClass: T) => {
182
197
 
183
198
  /**
184
199
  * FACE lifecycle: called when a <fieldset disabled> ancestor is toggled.
185
- * Syncs the component's own `disabled` property so it renders correctly.
186
- *
187
- * Note: this only fires for inherited disabled state (via fieldset), not
188
- * for the element's own `disabled` attribute — both paths must be handled.
200
+ * Separates parent-disabled state from the element's own `disabled` attribute
201
+ * so re-enabling a fieldset does not accidentally re-enable an intentionally
202
+ * disabled control.
189
203
  */
190
204
  formDisabledCallback(disabled: boolean): void {
191
- // `disabled` is declared on each subclass via @property; cast to access it
192
- (this as unknown as { disabled: boolean }).disabled = disabled;
205
+ if (disabled) {
206
+ // Save the user's own disabled state before the fieldset takes over.
207
+ this._ownDisabled = (this as unknown as { disabled: boolean }).disabled;
208
+ this._parentDisabled = true;
209
+ (this as unknown as { disabled: boolean }).disabled = true;
210
+ } else {
211
+ this._parentDisabled = false;
212
+ // Restore only the user-set state — do not blindly set false.
213
+ (this as unknown as { disabled: boolean }).disabled = this._ownDisabled;
214
+ }
193
215
  }
194
216
 
195
217
  /**
@@ -201,6 +223,26 @@ export const FaceMixin = <T extends Constructor<LitElement>>(superClass: T) => {
201
223
  // no-op default — override in subclass
202
224
  }
203
225
 
226
+ /**
227
+ * FACE lifecycle: called when the browser restores form state from session history
228
+ * (back/forward navigation) or when the browser autofills the field.
229
+ *
230
+ * `state` is the value that was previously passed to setFormValue():
231
+ * - a string for single-value controls
232
+ * - a FormData for multi-value controls (multi-select, checkbox groups)
233
+ * - null if the control had no value
234
+ *
235
+ * `mode` is 'restore' for session-history restores and 'autocomplete' for autofill.
236
+ *
237
+ * Default is a no-op. Subclasses should override to restore their own state.
238
+ */
239
+ formStateRestoreCallback(
240
+ _state: File | string | FormData | null,
241
+ _mode: 'restore' | 'autocomplete'
242
+ ): void {
243
+ // no-op default — override in subclass
244
+ }
245
+
204
246
  /**
205
247
  * Toggle a custom state in ElementInternals.states (CustomStateSet).
206
248
  *