@optionfactory/ful 1.0.12 → 1.0.14
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.css +1 -1
- package/dist/ful.css.map +1 -1
- package/dist/ful.iife.js +178 -98
- package/dist/ful.iife.js.map +1 -1
- package/dist/ful.iife.min.js +1 -1
- package/dist/ful.iife.min.js.map +1 -1
- package/dist/ful.min.mjs +1 -1
- package/dist/ful.min.mjs.map +1 -1
- package/dist/ful.mjs +178 -98
- package/dist/ful.mjs.map +1 -1
- package/package.json +2 -2
package/dist/ful.mjs
CHANGED
|
@@ -1386,7 +1386,9 @@ class Form extends ParsedElement {
|
|
|
1386
1386
|
this.spinner(false);
|
|
1387
1387
|
}
|
|
1388
1388
|
}
|
|
1389
|
-
|
|
1389
|
+
reset(){
|
|
1390
|
+
this.form.reset();
|
|
1391
|
+
}
|
|
1390
1392
|
spinner(spin) {
|
|
1391
1393
|
this.querySelectorAll('ful-spinner').forEach(el => {
|
|
1392
1394
|
const hel = /** @type HTMLElement */ (el);
|
|
@@ -1412,16 +1414,16 @@ class Input extends ParsedElement {
|
|
|
1412
1414
|
static observed = ['value', 'readonly:presence'];
|
|
1413
1415
|
static slots = true;
|
|
1414
1416
|
static template = `
|
|
1415
|
-
<label
|
|
1417
|
+
<label class="form-label">{{{{ slots.default }}}}</label>
|
|
1416
1418
|
<div class="input-group">
|
|
1417
1419
|
<span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>
|
|
1418
1420
|
{{{{ slots.before }}}}
|
|
1419
|
-
<input data-tpl-if="type != 'textarea'" class="form-control" data-tpl-
|
|
1420
|
-
<textarea data-tpl-if="type == 'textarea'" class="form-control"
|
|
1421
|
+
<input data-tpl-if="type != 'textarea'" class="form-control" data-tpl-type="type" placeholder=" " form="">
|
|
1422
|
+
<textarea data-tpl-if="type == 'textarea'" class="form-control" placeholder=" " form=""></textarea>
|
|
1421
1423
|
{{{{ slots.after }}}}
|
|
1422
1424
|
<span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>
|
|
1423
1425
|
</div>
|
|
1424
|
-
<ful-field-error
|
|
1426
|
+
<ful-field-error></ful-field-error>
|
|
1425
1427
|
`;
|
|
1426
1428
|
static formAssociated = true;
|
|
1427
1429
|
#input;
|
|
@@ -1429,15 +1431,18 @@ class Input extends ParsedElement {
|
|
|
1429
1431
|
constructor() {
|
|
1430
1432
|
super();
|
|
1431
1433
|
this.internals = this.attachInternals();
|
|
1432
|
-
this.internals.role = '
|
|
1434
|
+
this.internals.role = 'presentation';
|
|
1433
1435
|
}
|
|
1434
|
-
render({ slots }) {
|
|
1435
|
-
const id = Attributes.uid('ful-input');
|
|
1436
|
-
const fieldErrorId = `${id}-error`;
|
|
1436
|
+
render({ slots, observed, disabled }) {
|
|
1437
1437
|
const type = this.getAttribute("type") ?? 'text';
|
|
1438
|
-
const fragment = this.template().withOverlay({
|
|
1438
|
+
const fragment = this.template().withOverlay({ type, slots }).render();
|
|
1439
1439
|
this.#input = fragment.querySelector("input,textarea");
|
|
1440
|
+
|
|
1440
1441
|
Attributes.forward('input-', this, this.#input);
|
|
1442
|
+
this.disabled = disabled;
|
|
1443
|
+
this.readonly = observed.readonly;
|
|
1444
|
+
this.value = observed.value;
|
|
1445
|
+
|
|
1441
1446
|
this.#input.addEventListener('change', (evt) => {
|
|
1442
1447
|
evt.stopPropagation();
|
|
1443
1448
|
this.dispatchEvent(new CustomEvent('change', {
|
|
@@ -1448,7 +1453,11 @@ class Input extends ParsedElement {
|
|
|
1448
1453
|
}
|
|
1449
1454
|
}));
|
|
1450
1455
|
});
|
|
1456
|
+
const label = fragment.querySelector('label');
|
|
1457
|
+
label.addEventListener('click', () => this.focus());
|
|
1451
1458
|
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
1459
|
+
this.#input.ariaDescribedByElements = [this.#fieldError];
|
|
1460
|
+
this.#input.ariaLabelledByElements = [label];
|
|
1452
1461
|
this.replaceChildren(fragment);
|
|
1453
1462
|
}
|
|
1454
1463
|
get value() {
|
|
@@ -1463,6 +1472,12 @@ class Input extends ParsedElement {
|
|
|
1463
1472
|
set readonly(v) {
|
|
1464
1473
|
this.#input.readOnly = v;
|
|
1465
1474
|
}
|
|
1475
|
+
get disabled(){
|
|
1476
|
+
return this.#input.hasAttribute('disabled');
|
|
1477
|
+
}
|
|
1478
|
+
set disabled(d){
|
|
1479
|
+
Attributes.toggle(this.#input, 'disabled', d);
|
|
1480
|
+
}
|
|
1466
1481
|
focus(options) {
|
|
1467
1482
|
this.#input.focus(options);
|
|
1468
1483
|
}
|
|
@@ -1475,6 +1490,9 @@ class Input extends ParsedElement {
|
|
|
1475
1490
|
this.internals.setValidity({ customError: true }, " ");
|
|
1476
1491
|
this.#fieldError.innerText = error;
|
|
1477
1492
|
}
|
|
1493
|
+
formResetCallback(){
|
|
1494
|
+
this.value = this.getAttribute("value");
|
|
1495
|
+
}
|
|
1478
1496
|
}
|
|
1479
1497
|
|
|
1480
1498
|
class CompleteSelectLoader {
|
|
@@ -1564,11 +1582,9 @@ class OptionsSlotSelectLoader {
|
|
|
1564
1582
|
this.#data = data;
|
|
1565
1583
|
}
|
|
1566
1584
|
async exact(...keys) {
|
|
1567
|
-
await timing.sleep(500);
|
|
1568
1585
|
return this.#data.filter(([k, v]) => keys.includes(k));
|
|
1569
1586
|
}
|
|
1570
1587
|
async load(needle) {
|
|
1571
|
-
await timing.sleep(500);
|
|
1572
1588
|
return this.#data.filter(([k, v]) => v.includes(needle?.toLowerCase()));
|
|
1573
1589
|
}
|
|
1574
1590
|
}
|
|
@@ -1677,22 +1693,22 @@ class Dropdown extends ParsedElement {
|
|
|
1677
1693
|
}
|
|
1678
1694
|
|
|
1679
1695
|
class Select extends ParsedElement {
|
|
1680
|
-
static observed = ['value:csvm']
|
|
1696
|
+
static observed = ['value:csvm', 'readonly:presence']
|
|
1681
1697
|
static slots = true
|
|
1682
1698
|
static template = `
|
|
1683
|
-
<label
|
|
1699
|
+
<label class="form-label">{{{{ slots.default }}}}</label>
|
|
1684
1700
|
<div class="input-group flex-nowrap" tabindex="-1">
|
|
1685
1701
|
<span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>
|
|
1686
1702
|
{{{{ slots.before }}}}
|
|
1687
1703
|
<div class="ful-select-input">
|
|
1688
1704
|
<badges></badges>
|
|
1689
|
-
<input
|
|
1705
|
+
<input type="text" form="">
|
|
1690
1706
|
</div>
|
|
1691
1707
|
{{{{ slots.after }}}}
|
|
1692
1708
|
<span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>
|
|
1693
1709
|
</div>
|
|
1694
1710
|
<ful-dropdown hidden></ful-dropdown>
|
|
1695
|
-
<ful-field-error
|
|
1711
|
+
<ful-field-error></ful-field-error>
|
|
1696
1712
|
`;
|
|
1697
1713
|
static mappers = {
|
|
1698
1714
|
"csvm": (v, name, el) => {
|
|
@@ -1714,20 +1730,27 @@ class Select extends ParsedElement {
|
|
|
1714
1730
|
constructor() {
|
|
1715
1731
|
super();
|
|
1716
1732
|
this.internals = this.attachInternals();
|
|
1717
|
-
this.internals.role = '
|
|
1733
|
+
this.internals.role = 'presentation';
|
|
1718
1734
|
}
|
|
1719
|
-
async render({ slots, observed }) {
|
|
1735
|
+
async render({ slots, observed, disabled }) {
|
|
1720
1736
|
const name = this.getAttribute("name");
|
|
1721
|
-
const id = Attributes.uid('ful-select');
|
|
1722
|
-
const fieldErrorId = id + "-error";
|
|
1723
1737
|
this.#loader = Loaders.fromAttributes(this, 'loaders:select', { options: slots.options });
|
|
1724
1738
|
await this.#loader.prefetch?.();
|
|
1725
|
-
const fragment = this.template().withOverlay({ slots, name
|
|
1739
|
+
const fragment = this.template().withOverlay({ slots, name }).render();
|
|
1726
1740
|
this.#input = fragment.querySelector('input');
|
|
1727
1741
|
this.#badges = fragment.querySelector('badges');
|
|
1742
|
+
|
|
1743
|
+
this.value = observed.value;
|
|
1744
|
+
this.disabled = disabled;
|
|
1745
|
+
this.readonly = observed.readonly;
|
|
1746
|
+
|
|
1728
1747
|
this.#ddmenu = fragment.querySelector('ful-dropdown');
|
|
1729
1748
|
this.#multiple = this.hasAttribute("multiple");
|
|
1749
|
+
const label = fragment.querySelector('label');
|
|
1750
|
+
label.addEventListener('click', () => this.focus());
|
|
1730
1751
|
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
1752
|
+
this.#input.ariaDescribedByElements = [this.#fieldError];
|
|
1753
|
+
this.#input.ariaLabelledByElements = [label];
|
|
1731
1754
|
|
|
1732
1755
|
const self = this;
|
|
1733
1756
|
const [dload, abortdload] = timing.debounce(400, () => self.#ddmenu.show(() => self.#loader.load(self.#input.value)));
|
|
@@ -1821,6 +1844,11 @@ class Select extends ParsedElement {
|
|
|
1821
1844
|
this.#badges.append(...badges);
|
|
1822
1845
|
}
|
|
1823
1846
|
set value(value) {
|
|
1847
|
+
if(value === null){
|
|
1848
|
+
this.#values = new Map();
|
|
1849
|
+
this.#syncBadges();
|
|
1850
|
+
return;
|
|
1851
|
+
}
|
|
1824
1852
|
(async () => {
|
|
1825
1853
|
const entries = await (this.#multiple ? this.#loader.exact(...value) : this.#loader.exact(value));
|
|
1826
1854
|
this.#values = new Map(entries);
|
|
@@ -1848,10 +1876,10 @@ class Select extends ParsedElement {
|
|
|
1848
1876
|
}
|
|
1849
1877
|
|
|
1850
1878
|
class RadioGroup extends ParsedElement {
|
|
1851
|
-
static observed = ['value'];
|
|
1879
|
+
static observed = ['value', 'readonly:presence'];
|
|
1852
1880
|
static slots = true;
|
|
1853
1881
|
static template = `
|
|
1854
|
-
<fieldset
|
|
1882
|
+
<fieldset>
|
|
1855
1883
|
<legend class="form-label">
|
|
1856
1884
|
{{{{ slots.default }}}}
|
|
1857
1885
|
</legend>
|
|
@@ -1866,13 +1894,14 @@ class RadioGroup extends ParsedElement {
|
|
|
1866
1894
|
</label>
|
|
1867
1895
|
</div>
|
|
1868
1896
|
</section>
|
|
1869
|
-
<ful-field-error
|
|
1897
|
+
<ful-field-error></ful-field-error>
|
|
1870
1898
|
<footer data-tpl-if="slots.footer">
|
|
1871
1899
|
{{{{ slots.footer }}}}
|
|
1872
1900
|
</footer>
|
|
1873
1901
|
</fieldset>
|
|
1874
1902
|
`;
|
|
1875
1903
|
static formAssociated = true;
|
|
1904
|
+
#fieldset;
|
|
1876
1905
|
#fieldError;
|
|
1877
1906
|
#firstRadio;
|
|
1878
1907
|
#booleanType;
|
|
@@ -1881,7 +1910,7 @@ class RadioGroup extends ParsedElement {
|
|
|
1881
1910
|
this.internals = this.attachInternals();
|
|
1882
1911
|
this.internals.role = 'radiogroup';
|
|
1883
1912
|
}
|
|
1884
|
-
render({ slots }) {
|
|
1913
|
+
render({ slots, observed, disabled }) {
|
|
1885
1914
|
const name = this.getAttribute('name') ?? Attributes.uid('ful-radiogroup');
|
|
1886
1915
|
const radioEls = Array.from(slots.default.querySelectorAll('ful-radio'));
|
|
1887
1916
|
const inputsAndLabels = radioEls.map(el => {
|
|
@@ -1907,9 +1936,13 @@ class RadioGroup extends ParsedElement {
|
|
|
1907
1936
|
});
|
|
1908
1937
|
|
|
1909
1938
|
radioEls.forEach(el => el.remove());
|
|
1910
|
-
|
|
1911
|
-
this
|
|
1939
|
+
this.template().withOverlay({ name, slots, inputsAndLabels }).renderTo(this);
|
|
1940
|
+
this.#fieldset = this.firstElementChild;
|
|
1941
|
+
this.disabled = disabled;
|
|
1942
|
+
this.readonly = observed.readonly;
|
|
1943
|
+
this.value = observed.value;
|
|
1912
1944
|
this.#fieldError = this.querySelector('ful-field-error');
|
|
1945
|
+
this.ariaDescribedByElements = [this.#fieldError];
|
|
1913
1946
|
this.#firstRadio = this.querySelector('input[type=radio]');
|
|
1914
1947
|
this.#booleanType = this.getAttribute('type') === 'boolean';
|
|
1915
1948
|
}
|
|
@@ -1930,7 +1963,19 @@ class RadioGroup extends ParsedElement {
|
|
|
1930
1963
|
if (el) {
|
|
1931
1964
|
el.checked = true;
|
|
1932
1965
|
}
|
|
1966
|
+
}
|
|
1967
|
+
get readonly(){
|
|
1968
|
+
return this.#fieldset.inert;
|
|
1969
|
+
}
|
|
1970
|
+
set readonly(v) {
|
|
1971
|
+
this.#fieldset.inert = v;
|
|
1972
|
+
}
|
|
1973
|
+
get disabled(){
|
|
1974
|
+
return this.#fieldset.hasAttribute('disabled');
|
|
1933
1975
|
}
|
|
1976
|
+
set disabled(d){
|
|
1977
|
+
Attributes.toggle(this.#fieldset, 'disabled', d);
|
|
1978
|
+
}
|
|
1934
1979
|
focus(options) {
|
|
1935
1980
|
this.#firstRadio.focus(options);
|
|
1936
1981
|
}
|
|
@@ -1946,34 +1991,35 @@ class RadioGroup extends ParsedElement {
|
|
|
1946
1991
|
}
|
|
1947
1992
|
|
|
1948
1993
|
class Checkbox extends ParsedElement {
|
|
1949
|
-
static observed = ['value:bool'];
|
|
1994
|
+
static observed = ['value:bool', 'readonly:presence'];
|
|
1950
1995
|
static slots = true;
|
|
1951
1996
|
static template = `
|
|
1952
1997
|
<div data-tpl-class="klass">
|
|
1953
1998
|
<div class="input-container">
|
|
1954
|
-
<input
|
|
1999
|
+
<input class="form-check-input" type="checkbox" role="switch" form="" placeholder=" ">
|
|
1955
2000
|
</div>
|
|
1956
|
-
<label
|
|
2001
|
+
<label class="form-check-label">{{{{ slots.default }}}}</label>
|
|
1957
2002
|
</div>
|
|
1958
|
-
<ful-field-error
|
|
2003
|
+
<ful-field-error></ful-field-error>
|
|
1959
2004
|
`;
|
|
2005
|
+
#container;
|
|
1960
2006
|
#input;
|
|
1961
2007
|
#fieldError;
|
|
1962
2008
|
static formAssociated = true;
|
|
1963
2009
|
constructor() {
|
|
1964
2010
|
super();
|
|
1965
2011
|
this.internals = this.attachInternals();
|
|
1966
|
-
this.internals.role = '
|
|
2012
|
+
this.internals.role = 'presentation';
|
|
1967
2013
|
}
|
|
1968
|
-
render({ slots }) {
|
|
1969
|
-
const id = Attributes.uid("ful-checkbox");
|
|
1970
|
-
const fieldErrorId = id + "-error";
|
|
2014
|
+
render({ slots, observed, disabled }) {
|
|
1971
2015
|
const klass = this.getAttribute('type') == 'switch' ? "form-check form-switch" : "form-check";
|
|
1972
|
-
|
|
1973
|
-
|
|
2016
|
+
const fragment = this.template().withOverlay({ slots, klass }).render();
|
|
2017
|
+
this.#container = fragment.firstElementChild;
|
|
1974
2018
|
this.#input = fragment.querySelector("input");
|
|
1975
2019
|
Attributes.forward('input-', this, this.#input);
|
|
1976
|
-
this
|
|
2020
|
+
this.disabled = disabled;
|
|
2021
|
+
this.readonly = observed.readonly;
|
|
2022
|
+
this.value = observed.value;
|
|
1977
2023
|
this.#input.addEventListener('change', (evt) => {
|
|
1978
2024
|
evt.stopPropagation();
|
|
1979
2025
|
this.dispatchEvent(new CustomEvent('change', {
|
|
@@ -1983,7 +2029,18 @@ class Checkbox extends ParsedElement {
|
|
|
1983
2029
|
value: this.value
|
|
1984
2030
|
}
|
|
1985
2031
|
}));
|
|
1986
|
-
});
|
|
2032
|
+
});
|
|
2033
|
+
const label = fragment.querySelector('label');
|
|
2034
|
+
label.addEventListener('click', () => {
|
|
2035
|
+
this.focus();
|
|
2036
|
+
if (this.disabled || this.readonly) {
|
|
2037
|
+
return;
|
|
2038
|
+
}
|
|
2039
|
+
this.value = !this.value;
|
|
2040
|
+
});
|
|
2041
|
+
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
2042
|
+
this.#input.ariaDescribedByElements = [this.#fieldError];
|
|
2043
|
+
this.#input.ariaLabelledByElements = [label];
|
|
1987
2044
|
this.replaceChildren(fragment);
|
|
1988
2045
|
}
|
|
1989
2046
|
get value() {
|
|
@@ -1992,6 +2049,18 @@ class Checkbox extends ParsedElement {
|
|
|
1992
2049
|
set value(value) {
|
|
1993
2050
|
this.#input.checked = value;
|
|
1994
2051
|
}
|
|
2052
|
+
get readonly(){
|
|
2053
|
+
return this.#container.inert;
|
|
2054
|
+
}
|
|
2055
|
+
set readonly(v) {
|
|
2056
|
+
this.#container.inert = v;
|
|
2057
|
+
}
|
|
2058
|
+
get disabled() {
|
|
2059
|
+
return this.#input.hasAttribute('disabled');
|
|
2060
|
+
}
|
|
2061
|
+
set disabled(d) {
|
|
2062
|
+
Attributes.toggle(this.#input, 'disabled', d);
|
|
2063
|
+
}
|
|
1995
2064
|
focus(options) {
|
|
1996
2065
|
this.#input.focus(options);
|
|
1997
2066
|
}
|
|
@@ -2215,48 +2284,50 @@ class Table extends ParsedElement {
|
|
|
2215
2284
|
<ful-form data-tpl-if="slots.filters">
|
|
2216
2285
|
{{{{ slots.filters }}}}
|
|
2217
2286
|
</ful-form>
|
|
2218
|
-
<
|
|
2219
|
-
<
|
|
2220
|
-
|
|
2221
|
-
<
|
|
2222
|
-
<
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
<
|
|
2231
|
-
<
|
|
2232
|
-
<
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
<
|
|
2241
|
-
<
|
|
2242
|
-
<
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
<
|
|
2248
|
-
<
|
|
2249
|
-
<
|
|
2250
|
-
<
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2287
|
+
<div class="table-wrapper">
|
|
2288
|
+
<table class="table">
|
|
2289
|
+
<caption data-tpl-if="slots.caption">{{{{ slots.caption }}}}</caption>
|
|
2290
|
+
<thead>
|
|
2291
|
+
<tr>
|
|
2292
|
+
<th data-tpl-each="schema" scope="col" data-tpl-class="title.classes">
|
|
2293
|
+
{{{{ title.fragment }}}}
|
|
2294
|
+
<ful-sorter data-tpl-if="sorter || order" data-tpl-sorter="sorter" data-tpl-order="order"></ful-sorter>
|
|
2295
|
+
</th>
|
|
2296
|
+
</tr>
|
|
2297
|
+
</thead>
|
|
2298
|
+
<tbody></tbody>
|
|
2299
|
+
<tbody data-ref="no-autoload">
|
|
2300
|
+
<tr>
|
|
2301
|
+
<td data-tpl-colspan="schema.length" class="text-center align-middle p-4">
|
|
2302
|
+
<i class="bi bi-search" style="font-size: 40px; color: #BDC3CA"></i>
|
|
2303
|
+
<p class="mt-3 mb-0" style="color: #BDC3CA">
|
|
2304
|
+
Avvia la ricerca per visualizzare i risultati...
|
|
2305
|
+
</p>
|
|
2306
|
+
</td>
|
|
2307
|
+
</tr>
|
|
2308
|
+
</tbody>
|
|
2309
|
+
<tbody data-ref="loading" hidden>
|
|
2310
|
+
<tr>
|
|
2311
|
+
<td data-tpl-colspan="schema.length" class="text-center align-middle p-4">
|
|
2312
|
+
<ful-spinner class="big"></ful-spinner>
|
|
2313
|
+
</td>
|
|
2314
|
+
</tr>
|
|
2315
|
+
</tbody>
|
|
2316
|
+
<tbody data-ref="feedback" hidden>
|
|
2317
|
+
<tr>
|
|
2318
|
+
<td data-tpl-colspan="schema.length" class="text-center align-middle p-4">
|
|
2319
|
+
<div class="alert alert-danger">
|
|
2320
|
+
<p>Errore nel caricamento della tabella:</p>
|
|
2321
|
+
<p class="mb-0" data-ref="feedback-error"></p>
|
|
2322
|
+
</div>
|
|
2323
|
+
</td>
|
|
2324
|
+
</tr>
|
|
2325
|
+
</tbody>
|
|
2326
|
+
<tfoot data-tpl-if="slots.footer">
|
|
2327
|
+
{{{{ slots.footer }}}}
|
|
2328
|
+
</tfoot>
|
|
2329
|
+
</table>
|
|
2330
|
+
</div>
|
|
2260
2331
|
<ful-pagination current="0" total="1"></ful-pagination>
|
|
2261
2332
|
`;
|
|
2262
2333
|
static templates = {
|
|
@@ -2285,7 +2356,8 @@ class Table extends ParsedElement {
|
|
|
2285
2356
|
const template = this.template();
|
|
2286
2357
|
const schema = TableSchemaParser.parse(slots.default, template);
|
|
2287
2358
|
const fragment = template.withOverlay({ slots, schema }).render();
|
|
2288
|
-
const
|
|
2359
|
+
const tableWrapper = /** @type HTMLTableElement */ (Nodes.queryChildren(fragment, '.table-wrapper'));
|
|
2360
|
+
const table = /** @type HTMLTableElement */ (tableWrapper.querySelector("table"));
|
|
2289
2361
|
Attributes.forward('table-', this, table);
|
|
2290
2362
|
this.#schema = schema;
|
|
2291
2363
|
this.#body = table.querySelector(':scope > tbody');
|
|
@@ -2378,7 +2450,7 @@ class InstantFilter extends ParsedElement {
|
|
|
2378
2450
|
static observed = ["value:json"];
|
|
2379
2451
|
static slots = true;
|
|
2380
2452
|
static template = `
|
|
2381
|
-
<label
|
|
2453
|
+
<label class="form-label" data-tpl-if="label">{{{{ label }}}}</label>
|
|
2382
2454
|
<div class="input-group">
|
|
2383
2455
|
<button data-ref="operator" class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false" value="LTE" form="">≼</button>
|
|
2384
2456
|
<ul class="dropdown-menu">
|
|
@@ -2390,7 +2462,7 @@ class InstantFilter extends ParsedElement {
|
|
|
2390
2462
|
<li><a class="dropdown-item" role="button" value="GTE">≽</a></li>
|
|
2391
2463
|
<li><a class="dropdown-item" role="button" value="BETWEEN">↔</a></li>
|
|
2392
2464
|
</ul>
|
|
2393
|
-
<input data-
|
|
2465
|
+
<input data-ref="value1" type="datetime-local" class="form-control" form="">
|
|
2394
2466
|
<input data-ref="value2" type="datetime-local" class="form-control" form="" hidden>
|
|
2395
2467
|
<span class="input-group-text"><i class="bi bi-search"></i></span>
|
|
2396
2468
|
</div>
|
|
@@ -2406,15 +2478,18 @@ class InstantFilter extends ParsedElement {
|
|
|
2406
2478
|
this.internals = this.attachInternals();
|
|
2407
2479
|
}
|
|
2408
2480
|
render({ slots }) {
|
|
2409
|
-
const id = Attributes.uid('instant-filter');
|
|
2410
2481
|
const label = Fragments.toHtml(slots.default.cloneNode(true)).trim().length === 0 ? null : slots.default;
|
|
2411
2482
|
const name = this.getAttribute("name");
|
|
2412
|
-
const fragment = this.template().withOverlay({
|
|
2483
|
+
const fragment = this.template().withOverlay({ label, name }).render(this);
|
|
2413
2484
|
this.#operator = fragment.querySelector('[data-ref=operator]');
|
|
2414
2485
|
this.#value1 = fragment.querySelector('[data-ref=value1]');
|
|
2415
2486
|
this.#value2 = fragment.querySelector('[data-ref=value2]');
|
|
2487
|
+
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
2488
|
+
const labelEl = fragment.querySelector('label');
|
|
2489
|
+
labelEl?.addEventListener('click', () => this.focus());
|
|
2490
|
+
this.#value1.ariaDescribedByElements = [this.#fieldError];
|
|
2491
|
+
this.#value1.ariaLabelledByElements = labelEl ? [labelEl] : [];
|
|
2416
2492
|
this.replaceChildren(fragment);
|
|
2417
|
-
this.#fieldError = this.querySelector('ful-field-error');
|
|
2418
2493
|
this.addEventListener('click', (evt) => {
|
|
2419
2494
|
const target = /** @type HTMLElement */ (evt.target);
|
|
2420
2495
|
if (!target.matches('ul > li > a')) {
|
|
@@ -2477,7 +2552,7 @@ class LocalDateFilter extends ParsedElement {
|
|
|
2477
2552
|
static observed = ["value:json"];
|
|
2478
2553
|
static slots = true;
|
|
2479
2554
|
static template = `
|
|
2480
|
-
<label
|
|
2555
|
+
<label class="form-label" data-tpl-if="label">{{{{ label }}}}</label>
|
|
2481
2556
|
<div class="input-group">
|
|
2482
2557
|
<button data-ref="operator" class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false" value="EQ" form="">=</button>
|
|
2483
2558
|
<ul class="dropdown-menu">
|
|
@@ -2489,10 +2564,9 @@ class LocalDateFilter extends ParsedElement {
|
|
|
2489
2564
|
<li><a class="dropdown-item" role="button" value="GTE">≽</a></li>
|
|
2490
2565
|
<li><a class="dropdown-item" role="button" value="BETWEEN">↔</a></li>
|
|
2491
2566
|
</ul>
|
|
2492
|
-
<input data-
|
|
2567
|
+
<input data-ref="value1" type="date" class="form-control" form="">
|
|
2493
2568
|
<input data-ref="value2" type="date" class="form-control" form="" hidden>
|
|
2494
2569
|
<span class="input-group-text"><i class="bi bi-search"></i></span>
|
|
2495
|
-
|
|
2496
2570
|
</div>
|
|
2497
2571
|
<ful-field-error></ful-field-error>
|
|
2498
2572
|
`;
|
|
@@ -2506,15 +2580,18 @@ class LocalDateFilter extends ParsedElement {
|
|
|
2506
2580
|
this.internals = this.attachInternals();
|
|
2507
2581
|
}
|
|
2508
2582
|
render({ slots }) {
|
|
2509
|
-
const id = Attributes.uid('instant-filter');
|
|
2510
2583
|
const label = Fragments.toHtml(slots.default.cloneNode(true)).trim().length === 0 ? null : slots.default;
|
|
2511
2584
|
const name = this.getAttribute("name");
|
|
2512
|
-
const fragment = this.template().withOverlay({
|
|
2585
|
+
const fragment = this.template().withOverlay({ label, name }).render(this);
|
|
2513
2586
|
this.#operator = fragment.querySelector('[data-ref=operator]');
|
|
2514
2587
|
this.#value1 = fragment.querySelector('[data-ref=value1]');
|
|
2515
2588
|
this.#value2 = fragment.querySelector('[data-ref=value2]');
|
|
2589
|
+
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
2590
|
+
const labelEl = fragment.querySelector('label');
|
|
2591
|
+
labelEl?.addEventListener('click', () => this.focus());
|
|
2592
|
+
this.#value1.ariaDescribedByElements = [this.#fieldError];
|
|
2593
|
+
this.#value1.ariaLabelledByElements = labelEl ? [labelEl] : [];
|
|
2516
2594
|
this.replaceChildren(fragment);
|
|
2517
|
-
this.#fieldError = this.querySelector('ful-field-error');
|
|
2518
2595
|
this.addEventListener('click', (evt) => {
|
|
2519
2596
|
const target = /** @type HTMLElement */(evt.target);
|
|
2520
2597
|
if (!target.matches('ul > li > a')) {
|
|
@@ -2567,7 +2644,7 @@ class TextFilter extends ParsedElement {
|
|
|
2567
2644
|
static observed = ["value:json"];
|
|
2568
2645
|
static slots = true;
|
|
2569
2646
|
static template = `
|
|
2570
|
-
<label
|
|
2647
|
+
<label class="form-label" data-tpl-if="label">{{{{ label }}}}</label>
|
|
2571
2648
|
<div class="input-group">
|
|
2572
2649
|
<button data-ref="operator" class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false" value="CONTAINS" form="">…a…</button>
|
|
2573
2650
|
<ul class="dropdown-menu">
|
|
@@ -2576,7 +2653,7 @@ class TextFilter extends ParsedElement {
|
|
|
2576
2653
|
<li><a class="dropdown-item" role="button" value="ENDS_WITH">…a</a></li>
|
|
2577
2654
|
<li><a class="dropdown-item" role="button" value="EQ">=</a></li>
|
|
2578
2655
|
</ul>
|
|
2579
|
-
<input data-
|
|
2656
|
+
<input data-ref="value" type="text" class="form-control" form="">
|
|
2580
2657
|
<span class="input-group-text"><i class="bi bi-search"></i></span>
|
|
2581
2658
|
</div>
|
|
2582
2659
|
<ful-field-error></ful-field-error>
|
|
@@ -2590,14 +2667,17 @@ class TextFilter extends ParsedElement {
|
|
|
2590
2667
|
this.internals = this.attachInternals();
|
|
2591
2668
|
}
|
|
2592
2669
|
render({ slots }) {
|
|
2593
|
-
const id = Attributes.uid('string-filter');
|
|
2594
2670
|
const label = Fragments.toHtml(slots.default.cloneNode(true)).trim().length === 0 ? null : slots.default;
|
|
2595
2671
|
const name = this.getAttribute("name");
|
|
2596
|
-
const fragment = this.template().withOverlay({
|
|
2672
|
+
const fragment = this.template().withOverlay({ label, name }).render(this);
|
|
2597
2673
|
this.#operator = fragment.querySelector('[data-ref=operator]');
|
|
2598
2674
|
this.#value = fragment.querySelector('[data-ref=value]');
|
|
2675
|
+
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
2676
|
+
const labelEl = fragment.querySelector('label');
|
|
2677
|
+
labelEl?.addEventListener('click', () => this.focus());
|
|
2678
|
+
this.#value.ariaDescribedByElements = [this.#fieldError];
|
|
2679
|
+
this.#value.ariaLabelledByElements = labelEl ? [labelEl] : [];
|
|
2599
2680
|
this.replaceChildren(fragment);
|
|
2600
|
-
this.#fieldError = this.querySelector('ful-field-error');
|
|
2601
2681
|
this.addEventListener('click', (evt) => {
|
|
2602
2682
|
const target = /** @type HTMLElement */(evt.target);
|
|
2603
2683
|
if (!target.matches('ul > li > a')) {
|