@optionfactory/ful 1.0.12 → 1.0.13
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.iife.js +105 -90
- 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 +105 -90
- package/dist/ful.mjs.map +1 -1
- package/package.json +1 -1
package/dist/ful.mjs
CHANGED
|
@@ -1412,16 +1412,16 @@ class Input extends ParsedElement {
|
|
|
1412
1412
|
static observed = ['value', 'readonly:presence'];
|
|
1413
1413
|
static slots = true;
|
|
1414
1414
|
static template = `
|
|
1415
|
-
<label
|
|
1415
|
+
<label class="form-label">{{{{ slots.default }}}}</label>
|
|
1416
1416
|
<div class="input-group">
|
|
1417
1417
|
<span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>
|
|
1418
1418
|
{{{{ slots.before }}}}
|
|
1419
|
-
<input data-tpl-if="type != 'textarea'" class="form-control" data-tpl-
|
|
1420
|
-
<textarea data-tpl-if="type == 'textarea'" class="form-control"
|
|
1419
|
+
<input data-tpl-if="type != 'textarea'" class="form-control" data-tpl-type="type" placeholder=" " form="">
|
|
1420
|
+
<textarea data-tpl-if="type == 'textarea'" class="form-control" placeholder=" " form=""></textarea>
|
|
1421
1421
|
{{{{ slots.after }}}}
|
|
1422
1422
|
<span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>
|
|
1423
1423
|
</div>
|
|
1424
|
-
<ful-field-error
|
|
1424
|
+
<ful-field-error></ful-field-error>
|
|
1425
1425
|
`;
|
|
1426
1426
|
static formAssociated = true;
|
|
1427
1427
|
#input;
|
|
@@ -1429,13 +1429,11 @@ class Input extends ParsedElement {
|
|
|
1429
1429
|
constructor() {
|
|
1430
1430
|
super();
|
|
1431
1431
|
this.internals = this.attachInternals();
|
|
1432
|
-
this.internals.role = '
|
|
1432
|
+
this.internals.role = 'presentation';
|
|
1433
1433
|
}
|
|
1434
1434
|
render({ slots }) {
|
|
1435
|
-
const id = Attributes.uid('ful-input');
|
|
1436
|
-
const fieldErrorId = `${id}-error`;
|
|
1437
1435
|
const type = this.getAttribute("type") ?? 'text';
|
|
1438
|
-
const fragment = this.template().withOverlay({
|
|
1436
|
+
const fragment = this.template().withOverlay({ type, slots }).render();
|
|
1439
1437
|
this.#input = fragment.querySelector("input,textarea");
|
|
1440
1438
|
Attributes.forward('input-', this, this.#input);
|
|
1441
1439
|
this.#input.addEventListener('change', (evt) => {
|
|
@@ -1448,7 +1446,11 @@ class Input extends ParsedElement {
|
|
|
1448
1446
|
}
|
|
1449
1447
|
}));
|
|
1450
1448
|
});
|
|
1449
|
+
const label = fragment.querySelector('label');
|
|
1450
|
+
label.addEventListener('click', () => this.focus());
|
|
1451
1451
|
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
1452
|
+
this.#input.ariaDescribedByElements = [this.#fieldError];
|
|
1453
|
+
this.#input.ariaLabelledByElements = [label];
|
|
1452
1454
|
this.replaceChildren(fragment);
|
|
1453
1455
|
}
|
|
1454
1456
|
get value() {
|
|
@@ -1564,11 +1566,9 @@ class OptionsSlotSelectLoader {
|
|
|
1564
1566
|
this.#data = data;
|
|
1565
1567
|
}
|
|
1566
1568
|
async exact(...keys) {
|
|
1567
|
-
await timing.sleep(500);
|
|
1568
1569
|
return this.#data.filter(([k, v]) => keys.includes(k));
|
|
1569
1570
|
}
|
|
1570
1571
|
async load(needle) {
|
|
1571
|
-
await timing.sleep(500);
|
|
1572
1572
|
return this.#data.filter(([k, v]) => v.includes(needle?.toLowerCase()));
|
|
1573
1573
|
}
|
|
1574
1574
|
}
|
|
@@ -1680,19 +1680,19 @@ class Select extends ParsedElement {
|
|
|
1680
1680
|
static observed = ['value:csvm']
|
|
1681
1681
|
static slots = true
|
|
1682
1682
|
static template = `
|
|
1683
|
-
<label
|
|
1683
|
+
<label class="form-label">{{{{ slots.default }}}}</label>
|
|
1684
1684
|
<div class="input-group flex-nowrap" tabindex="-1">
|
|
1685
1685
|
<span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>
|
|
1686
1686
|
{{{{ slots.before }}}}
|
|
1687
1687
|
<div class="ful-select-input">
|
|
1688
1688
|
<badges></badges>
|
|
1689
|
-
<input
|
|
1689
|
+
<input type="text" form="">
|
|
1690
1690
|
</div>
|
|
1691
1691
|
{{{{ slots.after }}}}
|
|
1692
1692
|
<span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>
|
|
1693
1693
|
</div>
|
|
1694
1694
|
<ful-dropdown hidden></ful-dropdown>
|
|
1695
|
-
<ful-field-error
|
|
1695
|
+
<ful-field-error></ful-field-error>
|
|
1696
1696
|
`;
|
|
1697
1697
|
static mappers = {
|
|
1698
1698
|
"csvm": (v, name, el) => {
|
|
@@ -1714,20 +1714,23 @@ class Select extends ParsedElement {
|
|
|
1714
1714
|
constructor() {
|
|
1715
1715
|
super();
|
|
1716
1716
|
this.internals = this.attachInternals();
|
|
1717
|
-
this.internals.role = '
|
|
1717
|
+
this.internals.role = 'presentation';
|
|
1718
1718
|
}
|
|
1719
1719
|
async render({ slots, observed }) {
|
|
1720
1720
|
const name = this.getAttribute("name");
|
|
1721
|
-
const id = Attributes.uid('ful-select');
|
|
1722
|
-
const fieldErrorId = id + "-error";
|
|
1723
1721
|
this.#loader = Loaders.fromAttributes(this, 'loaders:select', { options: slots.options });
|
|
1724
1722
|
await this.#loader.prefetch?.();
|
|
1725
|
-
const fragment = this.template().withOverlay({ slots, name
|
|
1723
|
+
const fragment = this.template().withOverlay({ slots, name }).render();
|
|
1726
1724
|
this.#input = fragment.querySelector('input');
|
|
1727
1725
|
this.#badges = fragment.querySelector('badges');
|
|
1728
1726
|
this.#ddmenu = fragment.querySelector('ful-dropdown');
|
|
1729
1727
|
this.#multiple = this.hasAttribute("multiple");
|
|
1728
|
+
const label = fragment.querySelector('label');
|
|
1729
|
+
label.addEventListener('click', () => this.focus());
|
|
1730
1730
|
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
1731
|
+
this.#input.ariaDescribedByElements = [this.#fieldError];
|
|
1732
|
+
this.#input.ariaLabelledByElements = [label];
|
|
1733
|
+
|
|
1731
1734
|
|
|
1732
1735
|
const self = this;
|
|
1733
1736
|
const [dload, abortdload] = timing.debounce(400, () => self.#ddmenu.show(() => self.#loader.load(self.#input.value)));
|
|
@@ -1851,7 +1854,7 @@ class RadioGroup extends ParsedElement {
|
|
|
1851
1854
|
static observed = ['value'];
|
|
1852
1855
|
static slots = true;
|
|
1853
1856
|
static template = `
|
|
1854
|
-
<fieldset
|
|
1857
|
+
<fieldset>
|
|
1855
1858
|
<legend class="form-label">
|
|
1856
1859
|
{{{{ slots.default }}}}
|
|
1857
1860
|
</legend>
|
|
@@ -1866,7 +1869,7 @@ class RadioGroup extends ParsedElement {
|
|
|
1866
1869
|
</label>
|
|
1867
1870
|
</div>
|
|
1868
1871
|
</section>
|
|
1869
|
-
<ful-field-error
|
|
1872
|
+
<ful-field-error></ful-field-error>
|
|
1870
1873
|
<footer data-tpl-if="slots.footer">
|
|
1871
1874
|
{{{{ slots.footer }}}}
|
|
1872
1875
|
</footer>
|
|
@@ -1907,9 +1910,9 @@ class RadioGroup extends ParsedElement {
|
|
|
1907
1910
|
});
|
|
1908
1911
|
|
|
1909
1912
|
radioEls.forEach(el => el.remove());
|
|
1910
|
-
|
|
1911
|
-
this.template().withOverlay({ name, fieldErrorId, slots, inputsAndLabels }).renderTo(this);
|
|
1913
|
+
this.template().withOverlay({ name, slots, inputsAndLabels }).renderTo(this);
|
|
1912
1914
|
this.#fieldError = this.querySelector('ful-field-error');
|
|
1915
|
+
this.ariaDescribedByElements = [this.#fieldError];
|
|
1913
1916
|
this.#firstRadio = this.querySelector('input[type=radio]');
|
|
1914
1917
|
this.#booleanType = this.getAttribute('type') === 'boolean';
|
|
1915
1918
|
}
|
|
@@ -1951,11 +1954,11 @@ class Checkbox extends ParsedElement {
|
|
|
1951
1954
|
static template = `
|
|
1952
1955
|
<div data-tpl-class="klass">
|
|
1953
1956
|
<div class="input-container">
|
|
1954
|
-
<input
|
|
1957
|
+
<input class="form-check-input" type="checkbox" role="switch" form="" placeholder=" ">
|
|
1955
1958
|
</div>
|
|
1956
|
-
<label
|
|
1959
|
+
<label class="form-check-label">{{{{ slots.default }}}}</label>
|
|
1957
1960
|
</div>
|
|
1958
|
-
<ful-field-error
|
|
1961
|
+
<ful-field-error></ful-field-error>
|
|
1959
1962
|
`;
|
|
1960
1963
|
#input;
|
|
1961
1964
|
#fieldError;
|
|
@@ -1963,17 +1966,13 @@ class Checkbox extends ParsedElement {
|
|
|
1963
1966
|
constructor() {
|
|
1964
1967
|
super();
|
|
1965
1968
|
this.internals = this.attachInternals();
|
|
1966
|
-
this.internals.role = '
|
|
1969
|
+
this.internals.role = 'presentation';
|
|
1967
1970
|
}
|
|
1968
1971
|
render({ slots }) {
|
|
1969
|
-
const id = Attributes.uid("ful-checkbox");
|
|
1970
|
-
const fieldErrorId = id + "-error";
|
|
1971
1972
|
const klass = this.getAttribute('type') == 'switch' ? "form-check form-switch" : "form-check";
|
|
1972
|
-
|
|
1973
|
-
const fragment = this.template().withOverlay({ slots, klass, id, fieldErrorId }).render();
|
|
1973
|
+
const fragment = this.template().withOverlay({ slots, klass }).render();
|
|
1974
1974
|
this.#input = fragment.querySelector("input");
|
|
1975
1975
|
Attributes.forward('input-', this, this.#input);
|
|
1976
|
-
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
1977
1976
|
this.#input.addEventListener('change', (evt) => {
|
|
1978
1977
|
evt.stopPropagation();
|
|
1979
1978
|
this.dispatchEvent(new CustomEvent('change', {
|
|
@@ -1983,7 +1982,12 @@ class Checkbox extends ParsedElement {
|
|
|
1983
1982
|
value: this.value
|
|
1984
1983
|
}
|
|
1985
1984
|
}));
|
|
1986
|
-
});
|
|
1985
|
+
});
|
|
1986
|
+
const label = fragment.querySelector('label');
|
|
1987
|
+
label.addEventListener('click', () => { this.focus(); this.value = !this.value; });
|
|
1988
|
+
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
1989
|
+
this.#input.ariaDescribedByElements = [this.#fieldError];
|
|
1990
|
+
this.#input.ariaLabelledByElements = [label];
|
|
1987
1991
|
this.replaceChildren(fragment);
|
|
1988
1992
|
}
|
|
1989
1993
|
get value() {
|
|
@@ -2215,48 +2219,50 @@ class Table extends ParsedElement {
|
|
|
2215
2219
|
<ful-form data-tpl-if="slots.filters">
|
|
2216
2220
|
{{{{ slots.filters }}}}
|
|
2217
2221
|
</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
|
-
|
|
2222
|
+
<div class="table-wrapper">
|
|
2223
|
+
<table class="table">
|
|
2224
|
+
<caption data-tpl-if="slots.caption">{{{{ slots.caption }}}}</caption>
|
|
2225
|
+
<thead>
|
|
2226
|
+
<tr>
|
|
2227
|
+
<th data-tpl-each="schema" scope="col" data-tpl-class="title.classes">
|
|
2228
|
+
{{{{ title.fragment }}}}
|
|
2229
|
+
<ful-sorter data-tpl-if="sorter || order" data-tpl-sorter="sorter" data-tpl-order="order"></ful-sorter>
|
|
2230
|
+
</th>
|
|
2231
|
+
</tr>
|
|
2232
|
+
</thead>
|
|
2233
|
+
<tbody></tbody>
|
|
2234
|
+
<tbody data-ref="no-autoload">
|
|
2235
|
+
<tr>
|
|
2236
|
+
<td data-tpl-colspan="schema.length" class="text-center align-middle p-4">
|
|
2237
|
+
<i class="bi bi-search" style="font-size: 40px; color: #BDC3CA"></i>
|
|
2238
|
+
<p class="mt-3 mb-0" style="color: #BDC3CA">
|
|
2239
|
+
Avvia la ricerca per visualizzare i risultati...
|
|
2240
|
+
</p>
|
|
2241
|
+
</td>
|
|
2242
|
+
</tr>
|
|
2243
|
+
</tbody>
|
|
2244
|
+
<tbody data-ref="loading" hidden>
|
|
2245
|
+
<tr>
|
|
2246
|
+
<td data-tpl-colspan="schema.length" class="text-center align-middle p-4">
|
|
2247
|
+
<ful-spinner class="big"></ful-spinner>
|
|
2248
|
+
</td>
|
|
2249
|
+
</tr>
|
|
2250
|
+
</tbody>
|
|
2251
|
+
<tbody data-ref="feedback" hidden>
|
|
2252
|
+
<tr>
|
|
2253
|
+
<td data-tpl-colspan="schema.length" class="text-center align-middle p-4">
|
|
2254
|
+
<div class="alert alert-danger">
|
|
2255
|
+
<p>Errore nel caricamento della tabella:</p>
|
|
2256
|
+
<p class="mb-0" data-ref="feedback-error"></p>
|
|
2257
|
+
</div>
|
|
2258
|
+
</td>
|
|
2259
|
+
</tr>
|
|
2260
|
+
</tbody>
|
|
2261
|
+
<tfoot data-tpl-if="slots.footer">
|
|
2262
|
+
{{{{ slots.footer }}}}
|
|
2263
|
+
</tfoot>
|
|
2264
|
+
</table>
|
|
2265
|
+
</div>
|
|
2260
2266
|
<ful-pagination current="0" total="1"></ful-pagination>
|
|
2261
2267
|
`;
|
|
2262
2268
|
static templates = {
|
|
@@ -2285,7 +2291,8 @@ class Table extends ParsedElement {
|
|
|
2285
2291
|
const template = this.template();
|
|
2286
2292
|
const schema = TableSchemaParser.parse(slots.default, template);
|
|
2287
2293
|
const fragment = template.withOverlay({ slots, schema }).render();
|
|
2288
|
-
const
|
|
2294
|
+
const tableWrapper = /** @type HTMLTableElement */ (Nodes.queryChildren(fragment, '.table-wrapper'));
|
|
2295
|
+
const table = /** @type HTMLTableElement */ (tableWrapper.querySelector("table"));
|
|
2289
2296
|
Attributes.forward('table-', this, table);
|
|
2290
2297
|
this.#schema = schema;
|
|
2291
2298
|
this.#body = table.querySelector(':scope > tbody');
|
|
@@ -2378,7 +2385,7 @@ class InstantFilter extends ParsedElement {
|
|
|
2378
2385
|
static observed = ["value:json"];
|
|
2379
2386
|
static slots = true;
|
|
2380
2387
|
static template = `
|
|
2381
|
-
<label
|
|
2388
|
+
<label class="form-label" data-tpl-if="label">{{{{ label }}}}</label>
|
|
2382
2389
|
<div class="input-group">
|
|
2383
2390
|
<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
2391
|
<ul class="dropdown-menu">
|
|
@@ -2390,7 +2397,7 @@ class InstantFilter extends ParsedElement {
|
|
|
2390
2397
|
<li><a class="dropdown-item" role="button" value="GTE">≽</a></li>
|
|
2391
2398
|
<li><a class="dropdown-item" role="button" value="BETWEEN">↔</a></li>
|
|
2392
2399
|
</ul>
|
|
2393
|
-
<input data-
|
|
2400
|
+
<input data-ref="value1" type="datetime-local" class="form-control" form="">
|
|
2394
2401
|
<input data-ref="value2" type="datetime-local" class="form-control" form="" hidden>
|
|
2395
2402
|
<span class="input-group-text"><i class="bi bi-search"></i></span>
|
|
2396
2403
|
</div>
|
|
@@ -2406,15 +2413,18 @@ class InstantFilter extends ParsedElement {
|
|
|
2406
2413
|
this.internals = this.attachInternals();
|
|
2407
2414
|
}
|
|
2408
2415
|
render({ slots }) {
|
|
2409
|
-
const id = Attributes.uid('instant-filter');
|
|
2410
2416
|
const label = Fragments.toHtml(slots.default.cloneNode(true)).trim().length === 0 ? null : slots.default;
|
|
2411
2417
|
const name = this.getAttribute("name");
|
|
2412
|
-
const fragment = this.template().withOverlay({
|
|
2418
|
+
const fragment = this.template().withOverlay({ label, name }).render(this);
|
|
2413
2419
|
this.#operator = fragment.querySelector('[data-ref=operator]');
|
|
2414
2420
|
this.#value1 = fragment.querySelector('[data-ref=value1]');
|
|
2415
2421
|
this.#value2 = fragment.querySelector('[data-ref=value2]');
|
|
2422
|
+
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
2423
|
+
const labelEl = fragment.querySelector('label');
|
|
2424
|
+
labelEl?.addEventListener('click', () => this.focus());
|
|
2425
|
+
this.#value1.ariaDescribedByElements = [this.#fieldError];
|
|
2426
|
+
this.#value1.ariaLabelledByElements = labelEl ? [labelEl] : [];
|
|
2416
2427
|
this.replaceChildren(fragment);
|
|
2417
|
-
this.#fieldError = this.querySelector('ful-field-error');
|
|
2418
2428
|
this.addEventListener('click', (evt) => {
|
|
2419
2429
|
const target = /** @type HTMLElement */ (evt.target);
|
|
2420
2430
|
if (!target.matches('ul > li > a')) {
|
|
@@ -2477,7 +2487,7 @@ class LocalDateFilter extends ParsedElement {
|
|
|
2477
2487
|
static observed = ["value:json"];
|
|
2478
2488
|
static slots = true;
|
|
2479
2489
|
static template = `
|
|
2480
|
-
<label
|
|
2490
|
+
<label class="form-label" data-tpl-if="label">{{{{ label }}}}</label>
|
|
2481
2491
|
<div class="input-group">
|
|
2482
2492
|
<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
2493
|
<ul class="dropdown-menu">
|
|
@@ -2489,10 +2499,9 @@ class LocalDateFilter extends ParsedElement {
|
|
|
2489
2499
|
<li><a class="dropdown-item" role="button" value="GTE">≽</a></li>
|
|
2490
2500
|
<li><a class="dropdown-item" role="button" value="BETWEEN">↔</a></li>
|
|
2491
2501
|
</ul>
|
|
2492
|
-
<input data-
|
|
2502
|
+
<input data-ref="value1" type="date" class="form-control" form="">
|
|
2493
2503
|
<input data-ref="value2" type="date" class="form-control" form="" hidden>
|
|
2494
2504
|
<span class="input-group-text"><i class="bi bi-search"></i></span>
|
|
2495
|
-
|
|
2496
2505
|
</div>
|
|
2497
2506
|
<ful-field-error></ful-field-error>
|
|
2498
2507
|
`;
|
|
@@ -2506,15 +2515,18 @@ class LocalDateFilter extends ParsedElement {
|
|
|
2506
2515
|
this.internals = this.attachInternals();
|
|
2507
2516
|
}
|
|
2508
2517
|
render({ slots }) {
|
|
2509
|
-
const id = Attributes.uid('instant-filter');
|
|
2510
2518
|
const label = Fragments.toHtml(slots.default.cloneNode(true)).trim().length === 0 ? null : slots.default;
|
|
2511
2519
|
const name = this.getAttribute("name");
|
|
2512
|
-
const fragment = this.template().withOverlay({
|
|
2520
|
+
const fragment = this.template().withOverlay({ label, name }).render(this);
|
|
2513
2521
|
this.#operator = fragment.querySelector('[data-ref=operator]');
|
|
2514
2522
|
this.#value1 = fragment.querySelector('[data-ref=value1]');
|
|
2515
2523
|
this.#value2 = fragment.querySelector('[data-ref=value2]');
|
|
2524
|
+
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
2525
|
+
const labelEl = fragment.querySelector('label');
|
|
2526
|
+
labelEl?.addEventListener('click', () => this.focus());
|
|
2527
|
+
this.#value1.ariaDescribedByElements = [this.#fieldError];
|
|
2528
|
+
this.#value1.ariaLabelledByElements = labelEl ? [labelEl] : [];
|
|
2516
2529
|
this.replaceChildren(fragment);
|
|
2517
|
-
this.#fieldError = this.querySelector('ful-field-error');
|
|
2518
2530
|
this.addEventListener('click', (evt) => {
|
|
2519
2531
|
const target = /** @type HTMLElement */(evt.target);
|
|
2520
2532
|
if (!target.matches('ul > li > a')) {
|
|
@@ -2567,7 +2579,7 @@ class TextFilter extends ParsedElement {
|
|
|
2567
2579
|
static observed = ["value:json"];
|
|
2568
2580
|
static slots = true;
|
|
2569
2581
|
static template = `
|
|
2570
|
-
<label
|
|
2582
|
+
<label class="form-label" data-tpl-if="label">{{{{ label }}}}</label>
|
|
2571
2583
|
<div class="input-group">
|
|
2572
2584
|
<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
2585
|
<ul class="dropdown-menu">
|
|
@@ -2576,7 +2588,7 @@ class TextFilter extends ParsedElement {
|
|
|
2576
2588
|
<li><a class="dropdown-item" role="button" value="ENDS_WITH">…a</a></li>
|
|
2577
2589
|
<li><a class="dropdown-item" role="button" value="EQ">=</a></li>
|
|
2578
2590
|
</ul>
|
|
2579
|
-
<input data-
|
|
2591
|
+
<input data-ref="value" type="text" class="form-control" form="">
|
|
2580
2592
|
<span class="input-group-text"><i class="bi bi-search"></i></span>
|
|
2581
2593
|
</div>
|
|
2582
2594
|
<ful-field-error></ful-field-error>
|
|
@@ -2590,14 +2602,17 @@ class TextFilter extends ParsedElement {
|
|
|
2590
2602
|
this.internals = this.attachInternals();
|
|
2591
2603
|
}
|
|
2592
2604
|
render({ slots }) {
|
|
2593
|
-
const id = Attributes.uid('string-filter');
|
|
2594
2605
|
const label = Fragments.toHtml(slots.default.cloneNode(true)).trim().length === 0 ? null : slots.default;
|
|
2595
2606
|
const name = this.getAttribute("name");
|
|
2596
|
-
const fragment = this.template().withOverlay({
|
|
2607
|
+
const fragment = this.template().withOverlay({ label, name }).render(this);
|
|
2597
2608
|
this.#operator = fragment.querySelector('[data-ref=operator]');
|
|
2598
2609
|
this.#value = fragment.querySelector('[data-ref=value]');
|
|
2610
|
+
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
2611
|
+
const labelEl = fragment.querySelector('label');
|
|
2612
|
+
labelEl?.addEventListener('click', () => this.focus());
|
|
2613
|
+
this.#value.ariaDescribedByElements = [this.#fieldError];
|
|
2614
|
+
this.#value.ariaLabelledByElements = labelEl ? [labelEl] : [];
|
|
2599
2615
|
this.replaceChildren(fragment);
|
|
2600
|
-
this.#fieldError = this.querySelector('ful-field-error');
|
|
2601
2616
|
this.addEventListener('click', (evt) => {
|
|
2602
2617
|
const target = /** @type HTMLElement */(evt.target);
|
|
2603
2618
|
if (!target.matches('ul > li > a')) {
|