@optionfactory/ful 1.0.13 → 1.0.15

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/dist/ful.mjs CHANGED
@@ -1267,7 +1267,12 @@ class Bindings {
1267
1267
  });
1268
1268
  fieldErrors.forEach(e => {
1269
1269
  const name = e.context.replace("[", ".").replace("].", ".").replace("]", "");
1270
- form.querySelectorAll(`[name='${CSS.escape(name)}']`).forEach(input => input.setCustomValidity?.(e.reason));
1270
+ const parts = name.split(".");
1271
+ for (let i = parts.length; i != 0; --i) {
1272
+ const prefix = parts.slice(0, i).join(".");
1273
+ const suffix = parts.slice(i, parts.length).join(".");
1274
+ form.querySelectorAll(`[name='${CSS.escape(prefix)}']`).forEach(input => input.setCustomValidity?.(e.reason, suffix));
1275
+ }
1271
1276
  });
1272
1277
  form.querySelectorAll("ful-errors").forEach(el => {
1273
1278
  const hel = /** @type HTMLElement} */ (el);
@@ -1386,7 +1391,9 @@ class Form extends ParsedElement {
1386
1391
  this.spinner(false);
1387
1392
  }
1388
1393
  }
1389
-
1394
+ reset(){
1395
+ this.form.reset();
1396
+ }
1390
1397
  spinner(spin) {
1391
1398
  this.querySelectorAll('ful-spinner').forEach(el => {
1392
1399
  const hel = /** @type HTMLElement */ (el);
@@ -1431,11 +1438,16 @@ class Input extends ParsedElement {
1431
1438
  this.internals = this.attachInternals();
1432
1439
  this.internals.role = 'presentation';
1433
1440
  }
1434
- render({ slots }) {
1441
+ render({ slots, observed, disabled }) {
1435
1442
  const type = this.getAttribute("type") ?? 'text';
1436
1443
  const fragment = this.template().withOverlay({ type, slots }).render();
1437
1444
  this.#input = fragment.querySelector("input,textarea");
1445
+
1438
1446
  Attributes.forward('input-', this, this.#input);
1447
+ this.disabled = disabled;
1448
+ this.readonly = observed.readonly;
1449
+ this.value = observed.value;
1450
+
1439
1451
  this.#input.addEventListener('change', (evt) => {
1440
1452
  evt.stopPropagation();
1441
1453
  this.dispatchEvent(new CustomEvent('change', {
@@ -1465,6 +1477,12 @@ class Input extends ParsedElement {
1465
1477
  set readonly(v) {
1466
1478
  this.#input.readOnly = v;
1467
1479
  }
1480
+ get disabled(){
1481
+ return this.#input.hasAttribute('disabled');
1482
+ }
1483
+ set disabled(d){
1484
+ Attributes.toggle(this.#input, 'disabled', d);
1485
+ }
1468
1486
  focus(options) {
1469
1487
  this.#input.focus(options);
1470
1488
  }
@@ -1477,6 +1495,9 @@ class Input extends ParsedElement {
1477
1495
  this.internals.setValidity({ customError: true }, " ");
1478
1496
  this.#fieldError.innerText = error;
1479
1497
  }
1498
+ formResetCallback(){
1499
+ this.value = this.getAttribute("value");
1500
+ }
1480
1501
  }
1481
1502
 
1482
1503
  class CompleteSelectLoader {
@@ -1677,7 +1698,7 @@ class Dropdown extends ParsedElement {
1677
1698
  }
1678
1699
 
1679
1700
  class Select extends ParsedElement {
1680
- static observed = ['value:csvm']
1701
+ static observed = ['value:csvm', 'readonly:presence']
1681
1702
  static slots = true
1682
1703
  static template = `
1683
1704
  <label class="form-label">{{{{ slots.default }}}}</label>
@@ -1716,13 +1737,18 @@ class Select extends ParsedElement {
1716
1737
  this.internals = this.attachInternals();
1717
1738
  this.internals.role = 'presentation';
1718
1739
  }
1719
- async render({ slots, observed }) {
1740
+ async render({ slots, observed, disabled }) {
1720
1741
  const name = this.getAttribute("name");
1721
1742
  this.#loader = Loaders.fromAttributes(this, 'loaders:select', { options: slots.options });
1722
1743
  await this.#loader.prefetch?.();
1723
1744
  const fragment = this.template().withOverlay({ slots, name }).render();
1724
1745
  this.#input = fragment.querySelector('input');
1725
1746
  this.#badges = fragment.querySelector('badges');
1747
+
1748
+ this.value = observed.value;
1749
+ this.disabled = disabled;
1750
+ this.readonly = observed.readonly;
1751
+
1726
1752
  this.#ddmenu = fragment.querySelector('ful-dropdown');
1727
1753
  this.#multiple = this.hasAttribute("multiple");
1728
1754
  const label = fragment.querySelector('label');
@@ -1731,7 +1757,6 @@ class Select extends ParsedElement {
1731
1757
  this.#input.ariaDescribedByElements = [this.#fieldError];
1732
1758
  this.#input.ariaLabelledByElements = [label];
1733
1759
 
1734
-
1735
1760
  const self = this;
1736
1761
  const [dload, abortdload] = timing.debounce(400, () => self.#ddmenu.show(() => self.#loader.load(self.#input.value)));
1737
1762
  this.addEventListener('click', (/** @type any */e) => {
@@ -1824,6 +1849,11 @@ class Select extends ParsedElement {
1824
1849
  this.#badges.append(...badges);
1825
1850
  }
1826
1851
  set value(value) {
1852
+ if(value === null){
1853
+ this.#values = new Map();
1854
+ this.#syncBadges();
1855
+ return;
1856
+ }
1827
1857
  (async () => {
1828
1858
  const entries = await (this.#multiple ? this.#loader.exact(...value) : this.#loader.exact(value));
1829
1859
  this.#values = new Map(entries);
@@ -1851,7 +1881,7 @@ class Select extends ParsedElement {
1851
1881
  }
1852
1882
 
1853
1883
  class RadioGroup extends ParsedElement {
1854
- static observed = ['value'];
1884
+ static observed = ['value', 'readonly:presence'];
1855
1885
  static slots = true;
1856
1886
  static template = `
1857
1887
  <fieldset>
@@ -1876,6 +1906,7 @@ class RadioGroup extends ParsedElement {
1876
1906
  </fieldset>
1877
1907
  `;
1878
1908
  static formAssociated = true;
1909
+ #fieldset;
1879
1910
  #fieldError;
1880
1911
  #firstRadio;
1881
1912
  #booleanType;
@@ -1884,7 +1915,7 @@ class RadioGroup extends ParsedElement {
1884
1915
  this.internals = this.attachInternals();
1885
1916
  this.internals.role = 'radiogroup';
1886
1917
  }
1887
- render({ slots }) {
1918
+ render({ slots, observed, disabled }) {
1888
1919
  const name = this.getAttribute('name') ?? Attributes.uid('ful-radiogroup');
1889
1920
  const radioEls = Array.from(slots.default.querySelectorAll('ful-radio'));
1890
1921
  const inputsAndLabels = radioEls.map(el => {
@@ -1911,6 +1942,10 @@ class RadioGroup extends ParsedElement {
1911
1942
 
1912
1943
  radioEls.forEach(el => el.remove());
1913
1944
  this.template().withOverlay({ name, slots, inputsAndLabels }).renderTo(this);
1945
+ this.#fieldset = this.firstElementChild;
1946
+ this.disabled = disabled;
1947
+ this.readonly = observed.readonly;
1948
+ this.value = observed.value;
1914
1949
  this.#fieldError = this.querySelector('ful-field-error');
1915
1950
  this.ariaDescribedByElements = [this.#fieldError];
1916
1951
  this.#firstRadio = this.querySelector('input[type=radio]');
@@ -1933,7 +1968,19 @@ class RadioGroup extends ParsedElement {
1933
1968
  if (el) {
1934
1969
  el.checked = true;
1935
1970
  }
1971
+ }
1972
+ get readonly(){
1973
+ return this.#fieldset.inert;
1974
+ }
1975
+ set readonly(v) {
1976
+ this.#fieldset.inert = v;
1977
+ }
1978
+ get disabled(){
1979
+ return this.#fieldset.hasAttribute('disabled');
1936
1980
  }
1981
+ set disabled(d){
1982
+ Attributes.toggle(this.#fieldset, 'disabled', d);
1983
+ }
1937
1984
  focus(options) {
1938
1985
  this.#firstRadio.focus(options);
1939
1986
  }
@@ -1949,7 +1996,7 @@ class RadioGroup extends ParsedElement {
1949
1996
  }
1950
1997
 
1951
1998
  class Checkbox extends ParsedElement {
1952
- static observed = ['value:bool'];
1999
+ static observed = ['value:bool', 'readonly:presence'];
1953
2000
  static slots = true;
1954
2001
  static template = `
1955
2002
  <div data-tpl-class="klass">
@@ -1960,6 +2007,7 @@ class Checkbox extends ParsedElement {
1960
2007
  </div>
1961
2008
  <ful-field-error></ful-field-error>
1962
2009
  `;
2010
+ #container;
1963
2011
  #input;
1964
2012
  #fieldError;
1965
2013
  static formAssociated = true;
@@ -1968,11 +2016,15 @@ class Checkbox extends ParsedElement {
1968
2016
  this.internals = this.attachInternals();
1969
2017
  this.internals.role = 'presentation';
1970
2018
  }
1971
- render({ slots }) {
2019
+ render({ slots, observed, disabled }) {
1972
2020
  const klass = this.getAttribute('type') == 'switch' ? "form-check form-switch" : "form-check";
1973
2021
  const fragment = this.template().withOverlay({ slots, klass }).render();
2022
+ this.#container = fragment.firstElementChild;
1974
2023
  this.#input = fragment.querySelector("input");
1975
2024
  Attributes.forward('input-', this, this.#input);
2025
+ this.disabled = disabled;
2026
+ this.readonly = observed.readonly;
2027
+ this.value = observed.value;
1976
2028
  this.#input.addEventListener('change', (evt) => {
1977
2029
  evt.stopPropagation();
1978
2030
  this.dispatchEvent(new CustomEvent('change', {
@@ -1984,7 +2036,13 @@ class Checkbox extends ParsedElement {
1984
2036
  }));
1985
2037
  });
1986
2038
  const label = fragment.querySelector('label');
1987
- label.addEventListener('click', () => { this.focus(); this.value = !this.value; });
2039
+ label.addEventListener('click', () => {
2040
+ this.focus();
2041
+ if (this.disabled || this.readonly) {
2042
+ return;
2043
+ }
2044
+ this.value = !this.value;
2045
+ });
1988
2046
  this.#fieldError = fragment.querySelector('ful-field-error');
1989
2047
  this.#input.ariaDescribedByElements = [this.#fieldError];
1990
2048
  this.#input.ariaLabelledByElements = [label];
@@ -1996,6 +2054,18 @@ class Checkbox extends ParsedElement {
1996
2054
  set value(value) {
1997
2055
  this.#input.checked = value;
1998
2056
  }
2057
+ get readonly(){
2058
+ return this.#container.inert;
2059
+ }
2060
+ set readonly(v) {
2061
+ this.#container.inert = v;
2062
+ }
2063
+ get disabled() {
2064
+ return this.#input.hasAttribute('disabled');
2065
+ }
2066
+ set disabled(d) {
2067
+ Attributes.toggle(this.#input, 'disabled', d);
2068
+ }
1999
2069
  focus(options) {
2000
2070
  this.#input.focus(options);
2001
2071
  }