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
@@ -1,23 +1,23 @@
1
- import { LitElement as b, css as u, html as l } from "lit";
2
- import { n as i } from "../../../property-CemaeiRl.js";
1
+ import { LitElement as u, css as b, html as l } from "lit";
2
+ import { n as a } from "../../../property-CemaeiRl.js";
3
3
  import { o as c } from "../../../if-defined-C8i28hSj.js";
4
- import { createFormControlIds as f, isHorizontalLabel as p, buildAriaDescribedBy as y } from "../../../shared/form-control-utils.js";
5
- import { formControlStyles as _ } from "../../../shared/form-control-styles.js";
6
- import { FaceMixin as v } from "../../../shared/face-mixin.js";
7
- var m = Object.defineProperty, a = (d, t, r, o) => {
8
- for (var s = void 0, n = d.length - 1, g; n >= 0; n--)
9
- (g = d[n]) && (s = g(t, r, s) || s);
10
- return s && m(t, r, s), s;
4
+ import { createFormControlIds as y, isHorizontalLabel as p, buildAriaDescribedBy as _ } from "../../../shared/form-control-utils.js";
5
+ import { formControlStyles as f } from "../../../shared/form-control-styles.js";
6
+ import { FaceMixin as m } from "../../../shared/face-mixin.js";
7
+ var v = Object.defineProperty, s = (d, e, i, o) => {
8
+ for (var r = void 0, n = d.length - 1, g; n >= 0; n--)
9
+ (g = d[n]) && (r = g(e, i, r) || r);
10
+ return r && v(e, i, r), r;
11
11
  };
12
- const h = class h extends v(b) {
12
+ const h = class h extends m(u) {
13
13
  constructor() {
14
- super(), this._toggleId = "", this._labelId = "", this._helperId = "", this._errorId = "", this.labelPosition = "top", this._handleClick = (r) => {
15
- this.onClick && this.onClick(r), this._performToggle(r);
16
- }, this._handleKeydown = (r) => {
17
- (r.key === " " || r.key === "Enter") && (r.preventDefault(), this._performToggle(r));
18
- }, this._performToggle = (r) => {
14
+ super(), this._toggleId = "", this._labelId = "", this._helperId = "", this._errorId = "", this.labelPosition = "top", this._handleClick = (i) => {
15
+ this.onClick && this.onClick(i), this._performToggle(i);
16
+ }, this._handleKeydown = (i) => {
17
+ (i.key === " " || i.key === "Enter") && (i.preventDefault(), this._performToggle(i));
18
+ }, this._performToggle = (i) => {
19
19
  if (this.disabled || this.readonly) {
20
- r.preventDefault();
20
+ i.preventDefault();
21
21
  return;
22
22
  }
23
23
  this.checked = !this.checked, this._internals.setFormValue(this.checked ? this.value || "on" : null), this._syncValidity(), this._syncStates();
@@ -32,8 +32,8 @@ const h = class h extends v(b) {
32
32
  });
33
33
  this.dispatchEvent(o), this.onToggleChange && this.onToggleChange(o);
34
34
  };
35
- const t = f("toggle");
36
- this._toggleId = t.inputId, this._labelId = t.labelId, this._helperId = t.helperId, this._errorId = t.errorId, this.label = "", this.labelHidden = !1, this.noLabel = !1, this.checked = !1, this.size = "md", this.variant = "default", this.disabled = !1, this.readonly = !1, this.required = !1, this.invalid = !1, this.errorMessage = "", this.helpText = "", this.value = "", this.validationMessages = void 0;
35
+ const e = y("toggle");
36
+ this._toggleId = e.inputId, this._labelId = e.labelId, this._helperId = e.helperId, this._errorId = e.errorId, this.label = "", this.labelHidden = !1, this.noLabel = !1, this.checked = !1, this.size = "md", this.variant = "default", this.disabled = !1, this.readonly = !1, this.required = !1, this.invalid = !1, this.errorMessage = "", this.helpText = "", this.value = "", this.validationMessages = void 0;
37
37
  }
38
38
  // ─── FACE ─────────────────────────────────────────────────────────────────
39
39
  /**
@@ -43,6 +43,14 @@ const h = class h extends v(b) {
43
43
  formResetCallback() {
44
44
  this.checked = !1, this._internals.setFormValue(null), this._internals.setValidity({}), this._syncStates();
45
45
  }
46
+ /**
47
+ * FACE lifecycle: called on session restore or browser autofill.
48
+ * Restores checked state from the previously saved form value.
49
+ * A non-null state means the toggle was on; null means it was off.
50
+ */
51
+ formStateRestoreCallback(e, i) {
52
+ this.checked = e !== null, this._internals.setFormValue(this.checked ? this.value || "on" : null), this._syncValidity(), this._syncStates();
53
+ }
46
54
  /**
47
55
  * Sync validity state to ElementInternals.
48
56
  * Toggle has no inner <input> to delegate to, so required validation
@@ -71,20 +79,20 @@ const h = class h extends v(b) {
71
79
  this._setState("checked", this.checked), this._setState("disabled", this.disabled), this._setState("readonly", this.readonly), this._setState("required", this.required), this._setState("invalid", !this._internals.validity.valid);
72
80
  }
73
81
  // ─── End FACE ─────────────────────────────────────────────────────────────
74
- updated(t) {
75
- super.updated(t), (t.has("disabled") || t.has("readonly")) && this._syncStates();
82
+ updated(e) {
83
+ super.updated(e), (e.has("disabled") || e.has("readonly")) && this._syncStates();
76
84
  }
77
85
  firstUpdated() {
78
86
  this._internals.setFormValue(this.checked ? this.value || "on" : null), this._syncValidity(), this._syncStates(), !this.label && !this.noLabel && console.warn("AgToggle: label property is required for accessibility.");
79
87
  }
80
88
  renderLabel() {
81
89
  if (!this.label || this.noLabel) return "";
82
- const t = [];
83
- return p(this.labelPosition) ? (t.push("ag-form-control__label--horizontal"), t.push(`ag-form-control__label--${this.labelPosition}`)) : this.labelPosition === "bottom" && t.push(`ag-form-control__label--${this.labelPosition}`), l`
90
+ const e = [];
91
+ return p(this.labelPosition) ? (e.push("ag-form-control__label--horizontal"), e.push(`ag-form-control__label--${this.labelPosition}`)) : this.labelPosition === "bottom" && e.push(`ag-form-control__label--${this.labelPosition}`), l`
84
92
  <label
85
93
  id=${this._labelId}
86
94
  for=${this._toggleId}
87
- class="ag-form-control__label ${this.labelHidden ? "ag-form-control__label--hidden" : ""} ${this.required ? "ag-form-control__label--required" : ""} ${t.join(" ")}"
95
+ class="ag-form-control__label ${this.labelHidden ? "ag-form-control__label--hidden" : ""} ${this.required ? "ag-form-control__label--required" : ""} ${e.join(" ")}"
88
96
  part="ag-toggle-label"
89
97
  >
90
98
  ${this.label}
@@ -92,22 +100,22 @@ const h = class h extends v(b) {
92
100
  `;
93
101
  }
94
102
  render() {
95
- const t = y({
103
+ const e = _({
96
104
  helperId: this._helperId,
97
105
  errorId: this._errorId,
98
106
  hasHelper: !!this.helpText && !this.invalid,
99
107
  hasError: !!this.invalid && !!this.errorMessage
100
- }), r = this.helpText && !this.invalid ? l`<div class="ag-form-control__helper" id="${this._helperId}">
108
+ }), i = this.helpText && !this.invalid ? l`<div class="ag-form-control__helper" id="${this._helperId}">
101
109
  ${this.helpText}
102
110
  </div>` : "", o = this.invalid && this.errorMessage ? l`<div class="ag-form-control__error" id="${this._errorId}">
103
111
  ${this.errorMessage}
104
- </div>` : "", s = l`
112
+ </div>` : "", r = l`
105
113
  <button
106
114
  id="${this._toggleId}"
107
115
  role="switch"
108
116
  aria-checked="${this.checked}"
109
117
  aria-labelledby="${c(this.label && !this.noLabel ? this._labelId : void 0)}"
110
- aria-describedby="${c(t)}"
118
+ aria-describedby="${c(e)}"
111
119
  ?disabled="${this.disabled}"
112
120
  class="ag-toggle ag-toggle--${this.size} ag-toggle--${this.variant}"
113
121
  part="ag-toggle-button"
@@ -127,26 +135,26 @@ const h = class h extends v(b) {
127
135
  return p(this.labelPosition) ? l`
128
136
  <div class="ag-form-control--horizontal">
129
137
  ${this.renderLabel()}
130
- ${s}
138
+ ${r}
131
139
  </div>
132
- ${r}
140
+ ${i}
133
141
  ${o}
134
142
  ` : this.labelPosition === "bottom" ? l`
135
- ${s}
136
143
  ${r}
144
+ ${i}
137
145
  ${o}
138
146
  ${this.renderLabel()}
139
147
  ` : l`
140
148
  ${this.renderLabel()}
141
- ${s}
142
149
  ${r}
150
+ ${i}
143
151
  ${o}
144
152
  `;
145
153
  }
146
154
  };
147
155
  h.styles = [
148
- _,
149
- u`
156
+ f,
157
+ b`
150
158
  /* MINIMALIST & THEMEABLE - Styling via --ag-* design tokens */
151
159
  :host {
152
160
  /* Block for label positioning support */
@@ -308,58 +316,58 @@ h.styles = [
308
316
  }
309
317
  `
310
318
  ];
311
- let e = h;
312
- a([
313
- i({ type: String })
314
- ], e.prototype, "label");
315
- a([
316
- i({ type: String, attribute: "label-position" })
317
- ], e.prototype, "labelPosition");
318
- a([
319
- i({ type: Boolean, attribute: "label-hidden" })
320
- ], e.prototype, "labelHidden");
321
- a([
322
- i({ type: Boolean, attribute: "no-label" })
323
- ], e.prototype, "noLabel");
324
- a([
325
- i({ type: Boolean, reflect: !0 })
326
- ], e.prototype, "checked");
327
- a([
328
- i({ type: String, reflect: !0 })
329
- ], e.prototype, "size");
330
- a([
331
- i({ type: String, reflect: !0 })
332
- ], e.prototype, "variant");
333
- a([
334
- i({ type: Boolean, reflect: !0 })
335
- ], e.prototype, "disabled");
336
- a([
337
- i({ type: Boolean, reflect: !0 })
338
- ], e.prototype, "readonly");
339
- a([
340
- i({ type: Boolean, reflect: !0 })
341
- ], e.prototype, "required");
342
- a([
343
- i({ type: Boolean, reflect: !0 })
344
- ], e.prototype, "invalid");
345
- a([
346
- i({ type: String, attribute: "error-message" })
347
- ], e.prototype, "errorMessage");
348
- a([
349
- i({ type: String, attribute: "help-text" })
350
- ], e.prototype, "helpText");
351
- a([
352
- i({ type: String })
353
- ], e.prototype, "value");
354
- a([
355
- i({ attribute: !1 })
356
- ], e.prototype, "onClick");
357
- a([
358
- i({ attribute: !1 })
359
- ], e.prototype, "validationMessages");
360
- a([
361
- i({ attribute: !1 })
362
- ], e.prototype, "onToggleChange");
319
+ let t = h;
320
+ s([
321
+ a({ type: String })
322
+ ], t.prototype, "label");
323
+ s([
324
+ a({ type: String, attribute: "label-position" })
325
+ ], t.prototype, "labelPosition");
326
+ s([
327
+ a({ type: Boolean, attribute: "label-hidden" })
328
+ ], t.prototype, "labelHidden");
329
+ s([
330
+ a({ type: Boolean, attribute: "no-label" })
331
+ ], t.prototype, "noLabel");
332
+ s([
333
+ a({ type: Boolean, reflect: !0 })
334
+ ], t.prototype, "checked");
335
+ s([
336
+ a({ type: String, reflect: !0 })
337
+ ], t.prototype, "size");
338
+ s([
339
+ a({ type: String, reflect: !0 })
340
+ ], t.prototype, "variant");
341
+ s([
342
+ a({ type: Boolean, reflect: !0 })
343
+ ], t.prototype, "disabled");
344
+ s([
345
+ a({ type: Boolean, reflect: !0 })
346
+ ], t.prototype, "readonly");
347
+ s([
348
+ a({ type: Boolean, reflect: !0 })
349
+ ], t.prototype, "required");
350
+ s([
351
+ a({ type: Boolean, reflect: !0 })
352
+ ], t.prototype, "invalid");
353
+ s([
354
+ a({ type: String, attribute: "error-message" })
355
+ ], t.prototype, "errorMessage");
356
+ s([
357
+ a({ type: String, attribute: "help-text" })
358
+ ], t.prototype, "helpText");
359
+ s([
360
+ a({ type: String })
361
+ ], t.prototype, "value");
362
+ s([
363
+ a({ attribute: !1 })
364
+ ], t.prototype, "onClick");
365
+ s([
366
+ a({ attribute: !1 })
367
+ ], t.prototype, "validationMessages");
368
+ s([
369
+ a({ attribute: !1 })
370
+ ], t.prototype, "onToggleChange");
363
371
  export {
364
- e as AgToggle
372
+ t as AgToggle
365
373
  };
@@ -64,6 +64,11 @@ export declare class FaceMixinInterface {
64
64
  formDisabledCallback(disabled: boolean): void;
65
65
  /** FACE lifecycle — called on form reset; subclasses should override */
66
66
  formResetCallback(): void;
67
+ /**
68
+ * FACE lifecycle — called when the browser restores session state or autofills.
69
+ * Subclasses should override to restore their own state from the saved value.
70
+ */
71
+ formStateRestoreCallback(state: File | string | FormData | null, mode: 'restore' | 'autocomplete'): void;
67
72
  /**
68
73
  * Toggle a custom state in ElementInternals.states (CustomStateSet).
69
74
  * Enables :state() pseudo-class targeting from external CSS.
@@ -1 +1 @@
1
- {"version":3,"file":"face-mixin.d.ts","sourceRoot":"","sources":["../../src/shared/face-mixin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAKjC,KAAK,WAAW,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAErD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,gBAAgB,EAC3B,OAAO,EAAE,gBAAgB,GAAG,mBAAmB,GAAG,iBAAiB,GAAG,IAAI,GAAG,SAAS,GACrF,IAAI,CAQN;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,OAAO,kBAAkB;IACrC,iEAAiE;IACjE,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACxC,qFAAqF;IACrF,SAAS,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACvC,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IACtC,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,qDAAqD;IACrD,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,8DAA8D;IAC9D,aAAa,IAAI,OAAO;IACxB,qDAAqD;IACrD,cAAc,IAAI,OAAO;IACzB,wEAAwE;IACxE,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAC7C,wEAAwE;IACxE,iBAAiB,IAAI,IAAI;IACzB;;;;OAIG;IACH,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;CAC1D;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,WAAW,CAAC,UAAU,CAAC,EAAE,YAAY,CAAC,KA6GvC,WAAW,CAAC,kBAAkB,CAAC,GAAG,CACpE,CAAC"}
1
+ {"version":3,"file":"face-mixin.d.ts","sourceRoot":"","sources":["../../src/shared/face-mixin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAKjC,KAAK,WAAW,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAErD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,gBAAgB,EAC3B,OAAO,EAAE,gBAAgB,GAAG,mBAAmB,GAAG,iBAAiB,GAAG,IAAI,GAAG,SAAS,GACrF,IAAI,CAQN;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,OAAO,kBAAkB;IACrC,iEAAiE;IACjE,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACxC,qFAAqF;IACrF,SAAS,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACvC,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IACtC,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,qDAAqD;IACrD,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,8DAA8D;IAC9D,aAAa,IAAI,OAAO;IACxB,qDAAqD;IACrD,cAAc,IAAI,OAAO;IACzB,wEAAwE;IACxE,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAC7C,wEAAwE;IACxE,iBAAiB,IAAI,IAAI;IACzB;;;OAGG;IACH,wBAAwB,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,QAAQ,GAAG,IAAI,EAAE,IAAI,EAAE,SAAS,GAAG,cAAc,GAAG,IAAI;IACxG;;;;OAIG;IACH,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;CAC1D;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,WAAW,CAAC,UAAU,CAAC,EAAE,YAAY,CAAC,KAkJvC,WAAW,CAAC,kBAAkB,CAAC,GAAG,CACpE,CAAC"}
@@ -1,18 +1,18 @@
1
1
  import "lit";
2
- import { n } from "../property-CemaeiRl.js";
3
- var l = Object.defineProperty, d = (e, t, r, o) => {
4
- for (var i = void 0, s = e.length - 1, a; s >= 0; s--)
5
- (a = e[s]) && (i = a(t, r, i) || i);
6
- return i && l(t, r, i), i;
2
+ import { n as l } from "../property-CemaeiRl.js";
3
+ var n = Object.defineProperty, d = (i, e, s, o) => {
4
+ for (var t = void 0, a = i.length - 1, r; a >= 0; a--)
5
+ (r = i[a]) && (t = r(e, s, t) || t);
6
+ return t && n(e, s, t), t;
7
7
  };
8
- function c(e, t) {
9
- t && (t.validity.valid ? e.setValidity({}) : e.setValidity(t.validity, t.validationMessage, t));
8
+ function _(i, e) {
9
+ e && (e.validity.valid ? i.setValidity({}) : i.setValidity(e.validity, e.validationMessage, e));
10
10
  }
11
- const y = (e) => {
12
- const r = class r extends e {
11
+ const c = (i) => {
12
+ const s = class s extends i {
13
13
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
- constructor(...i) {
15
- super(...i), this.name = "", this._internals = this.attachInternals();
14
+ constructor(...t) {
15
+ super(...t), this._ownDisabled = !1, this._parentDisabled = !1, this.name = "", this._internals = this.attachInternals();
16
16
  }
17
17
  /** The parent <form> element, or null if not inside a form. */
18
18
  get form() {
@@ -40,13 +40,12 @@ const y = (e) => {
40
40
  }
41
41
  /**
42
42
  * FACE lifecycle: called when a <fieldset disabled> ancestor is toggled.
43
- * Syncs the component's own `disabled` property so it renders correctly.
44
- *
45
- * Note: this only fires for inherited disabled state (via fieldset), not
46
- * for the element's own `disabled` attribute — both paths must be handled.
43
+ * Separates parent-disabled state from the element's own `disabled` attribute
44
+ * so re-enabling a fieldset does not accidentally re-enable an intentionally
45
+ * disabled control.
47
46
  */
48
- formDisabledCallback(i) {
49
- this.disabled = i;
47
+ formDisabledCallback(t) {
48
+ t ? (this._ownDisabled = this.disabled, this._parentDisabled = !0, this.disabled = !0) : (this._parentDisabled = !1, this.disabled = this._ownDisabled);
50
49
  }
51
50
  /**
52
51
  * FACE lifecycle: called when the parent form is reset.
@@ -55,6 +54,21 @@ const y = (e) => {
55
54
  */
56
55
  formResetCallback() {
57
56
  }
57
+ /**
58
+ * FACE lifecycle: called when the browser restores form state from session history
59
+ * (back/forward navigation) or when the browser autofills the field.
60
+ *
61
+ * `state` is the value that was previously passed to setFormValue():
62
+ * - a string for single-value controls
63
+ * - a FormData for multi-value controls (multi-select, checkbox groups)
64
+ * - null if the control had no value
65
+ *
66
+ * `mode` is 'restore' for session-history restores and 'autocomplete' for autofill.
67
+ *
68
+ * Default is a no-op. Subclasses should override to restore their own state.
69
+ */
70
+ formStateRestoreCallback(t, a) {
71
+ }
58
72
  /**
59
73
  * Toggle a custom state in ElementInternals.states (CustomStateSet).
60
74
  *
@@ -70,17 +84,17 @@ const y = (e) => {
70
84
  * @param state State name, e.g. 'checked', 'disabled', 'invalid'
71
85
  * @param active True to add the state, false to remove it
72
86
  */
73
- _setState(i, s) {
74
- this._internals.states && (s ? this._internals.states.add(i) : this._internals.states.delete(i));
87
+ _setState(t, a) {
88
+ this._internals.states && (a ? this._internals.states.add(t) : this._internals.states.delete(t));
75
89
  }
76
90
  };
77
- r.formAssociated = !0;
78
- let t = r;
91
+ s.formAssociated = !0;
92
+ let e = s;
79
93
  return d([
80
- n({ type: String, reflect: !0 })
81
- ], t.prototype, "name"), t;
94
+ l({ type: String, reflect: !0 })
95
+ ], e.prototype, "name"), e;
82
96
  };
83
97
  export {
84
- y as FaceMixin,
85
- c as syncInnerInputValidity
98
+ c as FaceMixin,
99
+ _ as syncInnerInputValidity
86
100
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agnosticui-core",
3
- "version": "2.0.0-alpha.21",
3
+ "version": "2.0.0-alpha.22",
4
4
  "author": "AgnosticUI",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -364,6 +364,22 @@ export class AgCheckbox extends FaceMixin(LitElement) implements CheckboxProps {
364
364
  this._syncStates();
365
365
  }
366
366
 
367
+ /**
368
+ * FACE lifecycle: called on session restore or browser autofill.
369
+ * Restores checked state from the previously saved form value.
370
+ * A non-null state means the checkbox was checked; null means unchecked.
371
+ */
372
+ override formStateRestoreCallback(
373
+ state: File | string | FormData | null,
374
+ _mode: 'restore' | 'autocomplete'
375
+ ): void {
376
+ this.checked = state !== null;
377
+ this.indeterminate = false;
378
+ this._internals.setFormValue(this.checked ? (this.value || 'on') : null);
379
+ this._syncValidity();
380
+ this._syncStates();
381
+ }
382
+
367
383
  /**
368
384
  * Sync validity to ElementInternals by delegating to the inner
369
385
  * <input type="checkbox">. Required validation is handled natively
@@ -759,6 +759,14 @@ export class AgCombobox extends FaceMixin(LitElement) implements ComboboxProps {
759
759
  this._syncFormValue();
760
760
  this._syncValidity();
761
761
  }
762
+ if (
763
+ changedProperties.has('disabled') ||
764
+ changedProperties.has('readonly') ||
765
+ changedProperties.has('required') ||
766
+ changedProperties.has('value')
767
+ ) {
768
+ this._syncStates();
769
+ }
762
770
  }
763
771
 
764
772
  // Public methods
@@ -994,6 +1002,7 @@ export class AgCombobox extends FaceMixin(LitElement) implements ComboboxProps {
994
1002
  override firstUpdated() {
995
1003
  this._syncFormValue();
996
1004
  this._syncValidity();
1005
+ this._syncStates();
997
1006
  }
998
1007
 
999
1008
  /**
@@ -1005,6 +1014,50 @@ export class AgCombobox extends FaceMixin(LitElement) implements ComboboxProps {
1005
1014
  this._selectionChanged();
1006
1015
  this._internals.setFormValue(null);
1007
1016
  this._internals.setValidity({});
1017
+ this._syncStates();
1018
+ }
1019
+
1020
+ /**
1021
+ * FACE lifecycle: called on session restore or browser autofill.
1022
+ * Restores the selected option(s) by matching saved values against this.options.
1023
+ * Single: state is a string. Multiple: state is FormData.
1024
+ */
1025
+ override formStateRestoreCallback(
1026
+ state: File | string | FormData | null,
1027
+ _mode: 'restore' | 'autocomplete'
1028
+ ): void {
1029
+ if (state === null) {
1030
+ this._selectedOptions = [];
1031
+ } else if (state instanceof FormData) {
1032
+ const values = new Set(Array.from(state.getAll(this.name)) as string[]);
1033
+ this._selectedOptions = this.options.filter(opt => values.has(opt.value));
1034
+ } else if (typeof state === 'string') {
1035
+ const found = this.options.find(opt => opt.value === state);
1036
+ this._selectedOptions = found ? [found] : [];
1037
+ }
1038
+ this._selectionChanged();
1039
+ this._syncFormValue();
1040
+ this._syncValidity();
1041
+ this._syncStates();
1042
+ }
1043
+
1044
+ /**
1045
+ * Sync CustomStateSet states so :state() pseudo-classes work from external CSS.
1046
+ *
1047
+ * Must be called AFTER _syncValidity() so that :state(invalid) reads the
1048
+ * freshly-updated _internals.validity.valid value.
1049
+ *
1050
+ * Exposed states:
1051
+ * :state(disabled) — combobox is disabled
1052
+ * :state(readonly) — combobox is read-only
1053
+ * :state(required) — combobox is required
1054
+ * :state(invalid) — FACE constraint validation is failing
1055
+ */
1056
+ private _syncStates(): void {
1057
+ this._setState('disabled', this.disabled);
1058
+ this._setState('readonly', this.readonly);
1059
+ this._setState('required', this.required);
1060
+ this._setState('invalid', !this._internals.validity.valid);
1008
1061
  }
1009
1062
 
1010
1063
  // ─── End FACE ─────────────────────────────────────────────────────────────
@@ -164,10 +164,20 @@ export class AgnosticDialog extends LitElement implements DialogProps {
164
164
  const currentCount = parseInt(document.body.getAttribute('data-dialog-count') || '0', 10);
165
165
 
166
166
  if (currentCount === 0) {
167
- // First dialog - store original overflow and lock scroll
167
+ // First dialog - lock scroll on body (propagates to viewport) and reserve
168
+ // the scrollbar gutter on both body and html. The visible scrollbar belongs
169
+ // to the html element in most browsers/frameworks (including VitePress), so
170
+ // scrollbar-gutter: stable must be applied there to prevent layout shift.
171
+ const html = document.documentElement;
168
172
  document.body.setAttribute('data-dialog-original-overflow',
169
173
  document.body.style.overflow || '');
174
+ document.body.setAttribute('data-dialog-original-scrollbar-gutter',
175
+ document.body.style.scrollbarGutter || '');
176
+ document.body.setAttribute('data-dialog-original-html-scrollbar-gutter',
177
+ html.style.scrollbarGutter || '');
170
178
  document.body.style.overflow = 'hidden';
179
+ document.body.style.scrollbarGutter = 'stable';
180
+ html.style.scrollbarGutter = 'stable';
171
181
  document.body.setAttribute('data-dialog-scroll-locked', '');
172
182
  }
173
183
 
@@ -181,10 +191,17 @@ export class AgnosticDialog extends LitElement implements DialogProps {
181
191
  document.body.setAttribute('data-dialog-count', newCount.toString());
182
192
 
183
193
  if (newCount === 0) {
184
- // Last dialog closing - restore original overflow
194
+ // Last dialog closing - restore all saved styles
195
+ const html = document.documentElement;
185
196
  const originalOverflow = document.body.getAttribute('data-dialog-original-overflow');
197
+ const originalScrollbarGutter = document.body.getAttribute('data-dialog-original-scrollbar-gutter');
198
+ const originalHtmlScrollbarGutter = document.body.getAttribute('data-dialog-original-html-scrollbar-gutter');
186
199
  document.body.style.overflow = originalOverflow || '';
200
+ document.body.style.scrollbarGutter = originalScrollbarGutter || '';
201
+ html.style.scrollbarGutter = originalHtmlScrollbarGutter || '';
187
202
  document.body.removeAttribute('data-dialog-original-overflow');
203
+ document.body.removeAttribute('data-dialog-original-scrollbar-gutter');
204
+ document.body.removeAttribute('data-dialog-original-html-scrollbar-gutter');
188
205
  document.body.removeAttribute('data-dialog-scroll-locked');
189
206
  document.body.removeAttribute('data-dialog-count');
190
207
  }
@@ -9,12 +9,26 @@ import {
9
9
  } from '../core/Dialog';
10
10
 
11
11
  /**
12
- * React-specific props for Dialog
12
+ * React-specific props for Dialog.
13
+ *
14
+ * Includes onOpenChange for controlled-component support. This is necessary
15
+ * because the underlying Lit web component manages its own open state internally
16
+ * (e.g. it sets this.open = false on Escape or backdrop click). @lit/react's
17
+ * createComponent only bridges DOM events -> React props, so without explicitly
18
+ * calling onOpenChange(false) on close/cancel, React's state never learns the
19
+ * dialog closed. The stale open={true} is then re-applied on the next render,
20
+ * causing previously dismissed dialogs to reappear behind newer ones.
13
21
  */
14
22
  export interface ReactDialogProps extends DialogProps {
15
23
  children?: React.ReactNode;
16
24
  className?: string;
17
25
  id?: string;
26
+ /**
27
+ * Called with the new open state whenever the dialog opens or closes.
28
+ * Wire this to your React state setter (e.g. onOpenChange={setIsOpen}) so
29
+ * React stays in sync when the dialog closes itself internally.
30
+ */
31
+ onOpenChange?: (open: boolean) => void;
18
32
  }
19
33
 
20
34
  /**
@@ -31,8 +45,9 @@ export interface DialogFooterProps {
31
45
  children?: React.ReactNode;
32
46
  }
33
47
 
34
- // Create Dialog component with @lit/react
35
- export const ReactDialog = createComponent({
48
+ // Raw @lit/react bridge — maps Lit custom events to React prop callbacks.
49
+ // Does NOT handle onOpenChange; that requires the wrapper below.
50
+ const _ReactDialogBase = createComponent({
36
51
  tagName: 'ag-dialog',
37
52
  elementClass: AgnosticDialog,
38
53
  react: React,
@@ -43,6 +58,48 @@ export const ReactDialog = createComponent({
43
58
  },
44
59
  });
45
60
 
61
+ /**
62
+ * ReactDialog wraps _ReactDialogBase to add onOpenChange support.
63
+ *
64
+ * The Lit element fires "dialog-close" when the close button is clicked and
65
+ * "dialog-cancel" when the user presses Escape or clicks the backdrop. Both
66
+ * mean the dialog is now closed. We intercept those two events and call
67
+ * onOpenChange(false) so React state reflects the new closed state immediately,
68
+ * preventing the stale open={true} from being pushed back into the element on
69
+ * the next render.
70
+ */
71
+ export const ReactDialog = React.forwardRef<AgnosticDialog, ReactDialogProps>(
72
+ ({ onOpenChange, onDialogOpen, onDialogClose, onDialogCancel, ...props }, ref) => {
73
+ const handleDialogOpen = (event: DialogOpenEvent) => {
74
+ onDialogOpen?.(event);
75
+ onOpenChange?.(true);
76
+ };
77
+
78
+ // Both close and cancel mean the dialog is no longer open — notify React.
79
+ const handleDialogClose = (event: DialogCloseEvent) => {
80
+ onDialogClose?.(event);
81
+ onOpenChange?.(false);
82
+ };
83
+
84
+ const handleDialogCancel = (event: DialogCancelEvent) => {
85
+ onDialogCancel?.(event);
86
+ onOpenChange?.(false);
87
+ };
88
+
89
+ return (
90
+ <_ReactDialogBase
91
+ ref={ref}
92
+ onDialogOpen={handleDialogOpen}
93
+ onDialogClose={handleDialogClose}
94
+ onDialogCancel={handleDialogCancel}
95
+ {...props}
96
+ />
97
+ );
98
+ }
99
+ );
100
+
101
+ ReactDialog.displayName = 'ReactDialog';
102
+
46
103
  // Helper components for slots (simple React components)
47
104
  export const DialogHeader: React.FC<DialogHeaderProps> = ({ children }) => {
48
105
  return <div slot="header">{children}</div>;