@swiftwc/ui 0.0.0-dev.11 → 0.0.0-dev.111
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/css-data/en.json +28 -0
- package/generated/buses/alert-dialog.d.ts +2 -0
- package/generated/buses/alert-dialog.js +1 -0
- package/generated/buses/confirmation-dialog.d.ts +2 -0
- package/generated/buses/confirmation-dialog.js +1 -0
- package/generated/buses/index.d.ts +6 -0
- package/generated/buses/index.js +6 -0
- package/generated/buses/lifecycle-observer.d.ts +2 -0
- package/generated/buses/lifecycle-observer.js +1 -0
- package/generated/client/index.d.ts +24 -10
- package/generated/client/index.js +179 -194
- package/generated/components/alert-dialog.d.ts +11 -0
- package/generated/components/alert-dialog.js +94 -0
- package/generated/components/body-view.d.ts +8 -0
- package/generated/components/body-view.js +6 -2
- package/generated/components/bordered-button.d.ts +10 -0
- package/generated/components/bordered-button.js +36 -3
- package/generated/components/bordered-prominent-button.d.ts +10 -0
- package/generated/components/bordered-prominent-button.js +36 -3
- package/generated/components/borderless-button.d.ts +9 -1
- package/generated/components/borderless-button.js +29 -11
- package/generated/components/color-scheme.d.ts +12 -0
- package/generated/components/color-scheme.js +51 -0
- package/generated/components/confirmation-dialog.d.ts +4 -1
- package/generated/components/confirmation-dialog.js +38 -32
- package/generated/components/content-unavailable.d.ts +30 -0
- package/generated/components/content-unavailable.js +79 -0
- package/generated/components/date-picker.d.ts +21 -15
- package/generated/components/date-picker.js +126 -88
- package/generated/components/detail-placeholder.d.ts +11 -0
- package/generated/components/detail-placeholder.js +15 -0
- package/generated/components/disclosure-group.d.ts +8 -0
- package/generated/components/disclosure-group.js +18 -7
- package/generated/components/fine-tooltip.d.ts +15 -0
- package/generated/components/fine-tooltip.js +108 -0
- package/generated/components/form-view.d.ts +10 -0
- package/generated/components/form-view.js +8 -3
- package/generated/components/glass-button.d.ts +10 -0
- package/generated/components/glass-button.js +36 -3
- package/generated/components/glass-prominent-button.d.ts +10 -0
- package/generated/components/glass-prominent-button.js +36 -3
- package/generated/components/h-divider.d.ts +11 -0
- package/generated/components/h-divider.js +15 -0
- package/generated/components/h-stack.d.ts +22 -0
- package/generated/components/h-stack.js +24 -0
- package/generated/components/image-view.d.ts +18 -0
- package/generated/components/image-view.js +65 -0
- package/generated/components/index.d.ts +15 -3
- package/generated/components/index.js +15 -3
- package/generated/components/label-view.d.ts +19 -1
- package/generated/components/label-view.js +63 -62
- package/generated/components/labeled-content.d.ts +33 -0
- package/generated/components/labeled-content.js +160 -0
- package/generated/components/list-view.d.ts +14 -0
- package/generated/components/list-view.js +12 -17
- package/generated/components/menu-view.d.ts +12 -1
- package/generated/components/menu-view.js +63 -65
- package/generated/components/navigation-large-title.d.ts +11 -0
- package/generated/components/navigation-large-title.js +11 -5
- package/generated/components/navigation-split-view.d.ts +9 -1
- package/generated/components/navigation-split-view.js +10 -6
- package/generated/components/navigation-stack.d.ts +9 -1
- package/generated/components/navigation-stack.js +13 -11
- package/generated/components/navigation-title.d.ts +11 -1
- package/generated/components/navigation-title.js +58 -55
- package/generated/components/picker-view.d.ts +48 -7
- package/generated/components/picker-view.js +971 -261
- package/generated/components/plain-button.js +3 -3
- package/generated/components/progress-view.d.ts +20 -0
- package/generated/components/progress-view.js +120 -0
- package/generated/components/screen-view.js +2 -1
- package/generated/components/scroll-view-proxy.d.ts +13 -0
- package/generated/components/scroll-view-proxy.js +15 -0
- package/generated/components/scroll-view.d.ts +13 -1
- package/generated/components/scroll-view.js +140 -97
- package/generated/components/search-view.d.ts +12 -0
- package/generated/components/search-view.js +24 -0
- package/generated/components/section-view.d.ts +13 -1
- package/generated/components/section-view.js +38 -58
- package/generated/components/sheet-view.d.ts +4 -2
- package/generated/components/sheet-view.js +10 -39
- package/generated/components/sidebar-toggle.d.ts +9 -1
- package/generated/components/sidebar-toggle.js +46 -69
- package/generated/components/sidebar-view.d.ts +3 -0
- package/generated/components/sidebar-view.js +16 -9
- package/generated/components/sticky-container.d.ts +6 -1
- package/generated/components/sticky-container.js +9 -7
- package/generated/components/tab-bar.d.ts +3 -0
- package/generated/components/tab-bar.js +17 -13
- package/generated/components/tab-item.d.ts +3 -0
- package/generated/components/tab-item.js +20 -13
- package/generated/components/tab-view.d.ts +13 -4
- package/generated/components/tab-view.js +25 -89
- package/generated/components/table-view.d.ts +19 -0
- package/generated/components/table-view.js +88 -107
- package/generated/components/text-field.d.ts +19 -6
- package/generated/components/text-field.js +127 -99
- package/generated/components/text-view.d.ts +11 -0
- package/generated/components/text-view.js +16 -0
- package/generated/components/toggle-view.d.ts +43 -0
- package/generated/components/toggle-view.js +366 -0
- package/generated/components/tool-bar-item-group.d.ts +8 -0
- package/generated/components/tool-bar-item-group.js +22 -4
- package/generated/components/tool-bar-item.d.ts +12 -1
- package/generated/components/tool-bar-item.js +57 -10
- package/generated/components/tool-bar.d.ts +19 -0
- package/generated/components/tool-bar.js +48 -33
- package/generated/components/v-divider.d.ts +11 -0
- package/generated/components/v-divider.js +15 -0
- package/generated/components/v-keyboard.d.ts +8 -1
- package/generated/components/v-keyboard.js +11 -9
- package/generated/components/v-stack.d.ts +20 -0
- package/generated/components/v-stack.js +18 -2
- package/generated/css/index.css +4617 -1266
- package/generated/events/alert-dialog.d.ts +13 -0
- package/generated/events/alert-dialog.js +1 -0
- package/generated/events/confirmation-dialog.d.ts +7 -2
- package/generated/events/date-picker.d.ts +6 -1
- package/generated/events/index.d.ts +2 -0
- package/generated/events/index.js +2 -0
- package/generated/events/lifecycle-observer.d.ts +10 -2
- package/generated/events/picker-view.d.ts +22 -1
- package/generated/events/scroll-view.d.ts +10 -2
- package/generated/events/tab-view.d.ts +38 -8
- package/generated/events/text-field.d.ts +6 -1
- package/generated/events/toggle-view.d.ts +14 -0
- package/generated/events/toggle-view.js +1 -0
- package/generated/i18n/index.d.ts +19 -10
- package/generated/i18n/index.js +79 -54
- package/generated/i18n/locales/el.d.ts +16 -0
- package/generated/i18n/locales/el.js +16 -0
- package/generated/i18n/locales/en.d.ts +16 -0
- package/generated/i18n/locales/en.js +16 -0
- package/generated/i18n/locales/index.d.ts +4 -0
- package/generated/i18n/locales/index.js +4 -0
- package/generated/internal/class/css-style-observer.js +2 -2
- package/generated/internal/class/form-associated-base.d.ts +0 -4
- package/generated/internal/class/form-associated-base.js +22 -39
- package/generated/internal/class/mutation-observer-set.d.ts +9 -0
- package/generated/internal/class/mutation-observer-set.js +42 -0
- package/generated/internal/class/mutation-observer-singleton.js +18 -0
- package/generated/internal/class/navigation-view.d.ts +1 -1
- package/generated/internal/class/navigation-view.js +36 -43
- package/generated/internal/decorators/adaptive-slot.d.ts +1 -0
- package/generated/internal/decorators/adaptive-slot.js +47 -0
- package/generated/internal/decorators/custom-element.d.ts +1 -1
- package/generated/internal/decorators/custom-element.js +2 -1
- package/generated/internal/decorators/index.d.ts +6 -0
- package/generated/internal/decorators/index.js +6 -0
- package/generated/internal/decorators/microtask-on-connected.d.ts +39 -0
- package/generated/internal/decorators/microtask-on-connected.js +67 -0
- package/generated/internal/flags.d.ts +4 -0
- package/generated/internal/flags.js +1 -0
- package/generated/internal/privateNamespace.d.ts +10 -0
- package/generated/internal/privateNamespace.js +159 -1
- package/generated/internal/utils/$.d.ts +9 -0
- package/generated/internal/utils/$.js +11 -0
- package/generated/internal/utils/compare-big-decimals.js +7 -17
- package/generated/internal/utils/debug.d.ts +1 -0
- package/generated/internal/utils/debug.js +4 -0
- package/generated/internal/utils/define-translations.d.ts +1 -0
- package/generated/internal/utils/define-translations.js +3 -0
- package/generated/internal/utils/ensure-placeholder.d.ts +1 -0
- package/generated/internal/utils/ensure-placeholder.js +41 -0
- package/generated/internal/utils/index.d.ts +39 -2
- package/generated/internal/utils/index.js +39 -3
- package/generated/internal/utils/is-inside.d.ts +1 -0
- package/generated/internal/utils/is-inside.js +4 -0
- package/generated/internal/utils/kebab-case.js +6 -9
- package/generated/internal/utils/list-active.js +67 -12
- package/generated/internal/utils/touch-glass.js +5 -5
- package/generated/internal/vendor/morphdom.d.ts +6 -0
- package/generated/internal/vendor/morphdom.js +720 -0
- package/generated/morphdom/index.d.ts +8 -0
- package/generated/morphdom/index.js +8 -0
- package/generated/morphdom/morph.d.ts +4 -0
- package/generated/morphdom/morph.js +10 -0
- package/generated/morphdom/query-morph.d.ts +5 -0
- package/generated/morphdom/query-morph.js +12 -0
- package/generated/morphdom/render-to-string.d.ts +12 -0
- package/generated/morphdom/render-to-string.js +48 -0
- package/generated/morphdom/unsafe-html.d.ts +2 -0
- package/generated/morphdom/unsafe-html.js +4 -0
- package/generated/namespace-browser/base.d.ts +12 -3
- package/generated/namespace-browser/base.js +41 -18
- package/generated/namespace-browser/event.d.ts +10 -0
- package/generated/namespace-browser/event.js +1 -0
- package/generated/snapshot/index.d.ts +3 -1
- package/generated/snapshot/index.js +23 -2
- package/generated/tpl/html.d.ts +5 -0
- package/generated/tpl/html.js +7 -0
- package/generated/tpl/index.d.ts +6 -0
- package/generated/tpl/index.js +6 -0
- package/generated/tpl/is-template-result.d.ts +3 -0
- package/generated/tpl/is-template-result.js +1 -0
- package/generated/tpl/render.d.ts +2 -0
- package/generated/tpl/render.js +132 -0
- package/html-data/en.json +2620 -0
- package/package.json +32 -7
- package/scss/_components.scss +15 -0
- package/scss/_functions.scss +10 -0
- package/scss/_maps.scss +293 -0
- package/scss/_mixins.scss +4 -0
- package/scss/_transitions.scss +6 -1
- package/scss/_utils.scss +2 -0
- package/scss/_vars.scss +9 -115
- package/scss/base/_layout.scss +17 -7
- package/scss/base/_reboot.scss +34 -1
- package/scss/base/_root.scss +143 -124
- package/scss/colors/_index.scss +328 -88
- package/scss/components/_alert-dialog.scss +111 -0
- package/scss/components/_bordered-button.scss +37 -0
- package/scss/components/_bordered-prominent-button.scss +46 -0
- package/scss/components/_borderless-button.scss +26 -0
- package/scss/components/_confirmation-dialog.scss +41 -49
- package/scss/components/_content-unavailable.scss +57 -0
- package/scss/components/_date-picker.scss +15 -15
- package/scss/components/_detail-placeholder.scss +1 -3
- package/scss/components/_disclosure-group.scss +85 -34
- package/scss/components/_fine-tooltip.scss +84 -0
- package/scss/components/_form-view.scss +63 -24
- package/scss/components/_glass-button.scss +37 -0
- package/scss/components/_glass-prominent-button.scss +47 -0
- package/scss/components/_group-box.scss +27 -0
- package/scss/components/_h-flex-stack.scss +23 -0
- package/scss/components/_h-stack.scss +6 -17
- package/scss/components/_image-view.scss +20 -0
- package/scss/components/_index.scss +69 -36
- package/scss/components/_label-view copy.scss.txt +420 -0
- package/scss/components/_label-view.scss +105 -120
- package/scss/components/_label-view.scss.txt +536 -0
- package/scss/components/_labeled-content.scss +67 -1
- package/scss/components/_list-view.scss +70 -29
- package/scss/components/_menu-view.scss +96 -61
- package/scss/components/_navigation-large-title.scss +23 -0
- package/scss/components/_navigation-split-view.scss +3 -3
- package/scss/components/_navigation-title.scss +1 -1
- package/scss/components/_picker-view.scss +270 -63
- package/scss/components/_plain-button.scss +8 -0
- package/scss/components/_progress-view.scss +98 -0
- package/scss/components/_scroll-view-proxy.scss +24 -22
- package/scss/components/_scroll-view-toolbars.scss +8 -2
- package/scss/components/_scroll-view.scss +16 -0
- package/scss/components/_search-view.scss +23 -0
- package/scss/components/_section-view.scss +23 -22
- package/scss/components/_sheet-view.scss +16 -6
- package/scss/components/_sidebar-toggle.scss +1 -4
- package/scss/components/_sticky-container.scss +1 -1
- package/scss/components/_tab-bar.scss +17 -3
- package/scss/components/_tab-view.scss +12 -2
- package/scss/components/_table-column.scss +4 -2
- package/scss/components/_table-row.scss +71 -3
- package/scss/components/_table-view.scss +27 -18
- package/scss/components/_text-field.scss +37 -17
- package/scss/components/_text-view.scss +57 -0
- package/scss/components/_toggle-view.scss +171 -0
- package/scss/components/_tool-bar-item.scss +34 -82
- package/scss/components/_tool-bar.scss +77 -57
- package/scss/components/_v-stack.scss +8 -2
- package/scss/final/_touch-glass.scss +31 -0
- package/scss/mixins/_button.scss +44 -0
- package/scss/mixins/_color.scss +16 -0
- package/scss/mixins/_dialog.scss +1 -0
- package/scss/mixins/_index.scss +73 -5
- package/scss/placeholders/_buttons.scss +46 -11
- package/scss/placeholders/_lists.scss +159 -126
- package/scss/transitions/_alert-dialog.scss +18 -0
- package/scss/transitions/_confirmation-dialog.scss +8 -0
- package/scss/transitions/_fine-tooltip.scss +21 -0
- package/scss/transitions/_menu-view.scss +17 -15
- package/scss/transitions/_progress-view.scss +23 -0
- package/scss/transitions/_sheet-view.scss +30 -0
- package/scss/transitions/_tab-bar.scss +6 -5
- package/scss/utils/_background.scss +52 -0
- package/scss/utils/_frame.scss +59 -40
- package/scss/utils/_index.scss +45 -56
- package/scss/utils/_scroll-view.scss +1 -1
- package/scss/utils/_spacing.scss +1 -1
- package/scss/utils/_stacks.scss +34 -164
- package/generated/confirmation-dialog/index.d.ts +0 -1
- package/generated/confirmation-dialog/index.js +0 -1
- package/generated/internal/utils/cash/index.d.ts +0 -22
- package/generated/internal/utils/cash/index.js +0 -23
- package/generated/lifecycle-observer/index.d.ts +0 -1
- package/generated/lifecycle-observer/index.js +0 -1
- package/scss/transitions/_dialog.scss +0 -28
- package/web-components.html-data/en.json +0 -330
- /package/generated/internal/utils/{cash/ancestors.d.ts → ancestors.d.ts} +0 -0
- /package/generated/internal/utils/{cash/ancestors.js → ancestors.js} +0 -0
- /package/generated/internal/utils/{cash/next-all.d.ts → next-all.d.ts} +0 -0
- /package/generated/internal/utils/{cash/next-all.js → next-all.js} +0 -0
- /package/generated/internal/utils/{cash/next.d.ts → next.d.ts} +0 -0
- /package/generated/internal/utils/{cash/next.js → next.js} +0 -0
- /package/generated/internal/utils/{cash/prev-all.d.ts → prev-all.d.ts} +0 -0
- /package/generated/internal/utils/{cash/prev-all.js → prev-all.js} +0 -0
- /package/generated/internal/utils/{cash/prev.d.ts → prev.d.ts} +0 -0
- /package/generated/internal/utils/{cash/prev.js → prev.js} +0 -0
- /package/generated/internal/utils/{cash/prop.d.ts → prop.d.ts} +0 -0
- /package/generated/internal/utils/{cash/prop.js → prop.js} +0 -0
- /package/generated/internal/utils/{cash/siblings.d.ts → siblings.d.ts} +0 -0
- /package/generated/internal/utils/{cash/siblings.js → siblings.js} +0 -0
|
@@ -1,60 +1,553 @@
|
|
|
1
1
|
var _a;
|
|
2
|
+
import { I18n } from '../i18n';
|
|
2
3
|
import { CleanupRegistry } from '../internal/class/cleanup-registry';
|
|
3
|
-
import { FormAssociatedBase, getInternals
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
import { FormAssociatedBase, getInternals } from '../internal/class/form-associated-base';
|
|
5
|
+
import { MutationObserverSet } from '../internal/class/mutation-observer-set';
|
|
6
|
+
import { NavigationPath } from '../internal/class/navigation-path';
|
|
7
|
+
import { queryInsertPosition, startViewTransition } from '../internal/privateNamespace';
|
|
8
|
+
import { $, ancestors, debug, kebabCase, onoff } from '../internal/utils';
|
|
9
|
+
import { queryMorph } from '../morphdom';
|
|
10
|
+
import { html, render } from '../tpl';
|
|
11
|
+
const pickerStyles = ['menu', 'inline', 'navigation-link', 'sheet', 'automatic'];
|
|
12
|
+
const update = (path, node, overwrite = true) => {
|
|
13
|
+
debug(`PickerView: update`);
|
|
14
|
+
if (!(path instanceof NavigationPath))
|
|
15
|
+
throw new Error('invalid view');
|
|
16
|
+
const { component, page } = path;
|
|
17
|
+
if (!component)
|
|
18
|
+
return;
|
|
19
|
+
const position = queryInsertPosition(component); //'afterend'
|
|
20
|
+
// const lookFor = 'beforebegin' === position ? 'previousElementSibling' : 'nextElementSibling'
|
|
21
|
+
if (page)
|
|
22
|
+
page.insertAdjacentElement(position, node);
|
|
23
|
+
};
|
|
24
|
+
const reflectSpawnedPage = (current, source) => {
|
|
25
|
+
debug(`PickerView: reflectSpawnedPage`);
|
|
26
|
+
const { page: oldSv, toolBarConfig: oldToolbar } = new NavigationPath(current).hydrate(), { page: newSv, toolBarConfig: newToolbar } = new NavigationPath(source).hydrate();
|
|
27
|
+
const oldList = oldSv?.querySelector('list-view'), newList = newSv?.querySelector('list-view'), oldBackBtn = oldToolbar?.at(0)?.querySelector('button'), newBackBtn = newToolbar?.at(0)?.querySelector('button');
|
|
28
|
+
// pre replace list (always exists)
|
|
29
|
+
const oldOpenedDetails = [...(oldList?.querySelectorAll('list-view details[open]>summary') ?? [])].map((item) => item.textContent.trim());
|
|
30
|
+
// replace list (always exists)
|
|
31
|
+
if (oldList && newList)
|
|
32
|
+
oldList.replaceWith(newList);
|
|
33
|
+
// post replace list (always exists)
|
|
34
|
+
for (const label of oldOpenedDetails)
|
|
35
|
+
for (const summary of newList?.querySelectorAll('list-view details>summary') ?? [])
|
|
36
|
+
if (summary.textContent.trim() === label) {
|
|
37
|
+
summary.parentElement?.setAttribute('open', 'open');
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
// replace backbtns (always exist)
|
|
41
|
+
if (oldBackBtn && newBackBtn)
|
|
42
|
+
oldBackBtn.replaceWith(newBackBtn);
|
|
43
|
+
// overwrite navtitle (always exists)
|
|
44
|
+
oldSv?.setAttribute('navigation-inline-title', newSv?.getAttribute('navigation-inline-title') ?? '');
|
|
45
|
+
// replace search (if exists)
|
|
46
|
+
oldList?.style.setProperty('--list--sticky-block-size', newList?.style.getPropertyValue('--list--sticky-block-size') ?? '');
|
|
47
|
+
// replace search (if exists)
|
|
48
|
+
const oldSearch = oldSv?.querySelector('sticky-container'), newSearch = newSv?.querySelector('sticky-container');
|
|
49
|
+
// if already exists, DO NOTHING dont mess up the input element
|
|
50
|
+
if (newSearch) {
|
|
51
|
+
if (!oldSearch)
|
|
52
|
+
oldSv?.insertAdjacentHTML('afterend', `<sticky-container edge="navbar" style="order: -1" padding>
|
|
53
|
+
<v-stack spacing="0" alignment="fill">
|
|
54
|
+
<input is="search-view" placeholder="Search">
|
|
55
|
+
<!--<button type="button">Filters</button>-->
|
|
56
|
+
</v-stack>
|
|
57
|
+
</sticky-container>`);
|
|
58
|
+
}
|
|
59
|
+
else
|
|
60
|
+
oldSearch?.remove();
|
|
61
|
+
};
|
|
62
|
+
const extractTag = (node) => {
|
|
63
|
+
debug(`PickerView: extractTag`);
|
|
64
|
+
return node instanceof HTMLOptionElement ? (((node.getAttribute('value') ?? node.textContent?.trim()) || node.getAttribute('label')) ?? '') : (node.value ?? '');
|
|
65
|
+
}, extractLabel = (node) => {
|
|
66
|
+
debug(`PickerView: extractLabelFromGroup`);
|
|
67
|
+
if (node instanceof Element)
|
|
68
|
+
if (node instanceof HTMLOptionElement)
|
|
69
|
+
return (node.getAttribute('label') ?? node.getAttribute('value') ?? node.textContent?.trim()) || null;
|
|
70
|
+
else
|
|
71
|
+
return node.getAttribute('DATALIST' === node.tagName ? 'data-label' : 'label');
|
|
72
|
+
else
|
|
73
|
+
return node.title ?? node.value ?? null;
|
|
74
|
+
// return node instanceof Element ? node.getAttribute('DATALIST' === node.tagName ? 'data-label' : 'label') : (node.title ?? node.value ?? null)
|
|
75
|
+
}, extractIcon = (node) => {
|
|
76
|
+
debug(`PickerView: extractIcon`);
|
|
77
|
+
// return node instanceof Element ? node.getAttribute('data-system-image') : (node.systemImage ?? null)
|
|
78
|
+
if (node instanceof Element)
|
|
79
|
+
return node.getAttribute('data-system-image');
|
|
80
|
+
else
|
|
81
|
+
return node.systemImage ?? null;
|
|
82
|
+
}, extractSubtitle = (node) => {
|
|
83
|
+
debug(`PickerView: extractSubtitle`);
|
|
84
|
+
if (node instanceof Element)
|
|
85
|
+
return node.getAttribute('data-subtitle');
|
|
86
|
+
else
|
|
87
|
+
return node.subtitle ?? null;
|
|
88
|
+
};
|
|
89
|
+
const allLeaves = (node) => node.children.every((c) => 0 === c.children.length);
|
|
90
|
+
const parseDictionary = (value) => {
|
|
91
|
+
let dictionary = [];
|
|
92
|
+
try {
|
|
93
|
+
dictionary = JSON.parse(value ?? '[]');
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
console.error('invalid-dictionary');
|
|
97
|
+
}
|
|
98
|
+
return dictionary;
|
|
99
|
+
};
|
|
100
|
+
const indexGroups = (nodes, parentPath = '') => {
|
|
101
|
+
const map = new Map();
|
|
102
|
+
nodes.forEach((node, i) => {
|
|
103
|
+
const id = parentPath ? `${parentPath}.${i}` : `${i}`;
|
|
104
|
+
map.set(id, node); // no DOM write — works identically for Element and DictEntry
|
|
105
|
+
const children = node instanceof Element ? Array.from(node.children) : node.children;
|
|
106
|
+
for (const [cid, cnode] of indexGroups(children, id))
|
|
107
|
+
map.set(cid, cnode);
|
|
108
|
+
});
|
|
109
|
+
return map;
|
|
110
|
+
};
|
|
111
|
+
const collectLeafValues = (node) => (node.children.length ? node.children.flatMap(collectLeafValues) : [node.value]);
|
|
112
|
+
/**
|
|
113
|
+
* @summary A control that selects one value from a set of options.
|
|
114
|
+
*
|
|
115
|
+
* @attr {menu|inline|navigation-link|sheet|automatic} picker-style
|
|
116
|
+
*
|
|
117
|
+
* @attr help — Adds a help tooltip to the trigger of the picker, if style supports one
|
|
118
|
+
*
|
|
119
|
+
* @attr {DictEntry[]} dictionary — Renders all options using this array
|
|
120
|
+
*
|
|
121
|
+
* @attr {vertical|horizontal|auto} label-value-placement
|
|
122
|
+
*
|
|
123
|
+
* @slot — The default slot.
|
|
124
|
+
* @slot label
|
|
125
|
+
* @slot list
|
|
126
|
+
* @slot {HTMLOptionElement[]} validity-options
|
|
127
|
+
*/
|
|
8
128
|
export class PickerView extends FormAssociatedBase {
|
|
9
129
|
static get ATTR() {
|
|
10
130
|
return {
|
|
11
|
-
PLACEHOLDER: '
|
|
131
|
+
PLACEHOLDER: 'prompt',
|
|
132
|
+
PLACEHOLDER_ICON: 'prompt-icon',
|
|
12
133
|
LABEL: 'label',
|
|
13
134
|
PICKER_STYLE: 'picker-style',
|
|
14
135
|
SELECTION: 'selection',
|
|
136
|
+
SEARCHABLE: 'searchable',
|
|
137
|
+
CURRENT_VALUE_LABEL: 'current-value-label',
|
|
138
|
+
CURRENT_VALUE_ICON: 'current-value-icon',
|
|
139
|
+
TRIGGER_HELP: 'help',
|
|
140
|
+
DICTIONARY: 'dictionary',
|
|
141
|
+
REQUIRED: 'required',
|
|
15
142
|
};
|
|
16
143
|
}
|
|
17
144
|
static get observedAttributes() {
|
|
18
145
|
return Object.values(this.ATTR);
|
|
19
146
|
}
|
|
20
147
|
static #templates = new Map();
|
|
148
|
+
#spawn;
|
|
149
|
+
#makeGroupClickHandler(el, groupId) {
|
|
150
|
+
return async (evt) => {
|
|
151
|
+
evt.stopImmediatePropagation();
|
|
152
|
+
evt.preventDefault();
|
|
153
|
+
const { target } = evt;
|
|
154
|
+
if (!(target instanceof HTMLElement))
|
|
155
|
+
return;
|
|
156
|
+
const newPage = this.#spawnPage(el instanceof Element ? Array.from(el.children) : el.children, 'body-view', groupId, this.hasAttribute('searchable'), extractLabel(el));
|
|
157
|
+
if (!newPage)
|
|
158
|
+
return;
|
|
159
|
+
newPage.dataset.groupId = groupId; // <-- tag the spawned page
|
|
160
|
+
const path = new NavigationPath(target)?.hydrate();
|
|
161
|
+
await startViewTransition(target, 'forwards', async () => {
|
|
162
|
+
update(path, newPage);
|
|
163
|
+
this.#reflectSelectionOnButtons();
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
#spawnPage = (elements, tag, parentGroupId, searchable = false, title) => {
|
|
168
|
+
debug(`${_a.name} #spawnPage`);
|
|
169
|
+
const body = tag === 'sheet-view'
|
|
170
|
+
? $(html `<dialog is="sheet-view">
|
|
171
|
+
<scroll-view>
|
|
172
|
+
<v-stack placement="leading fill">
|
|
173
|
+
<list-view preferred-expanded-style="inset"></list-view>
|
|
174
|
+
</v-stack>
|
|
175
|
+
</scroll-view>
|
|
176
|
+
<tool-bar>
|
|
177
|
+
<tool-bar-item slot="top-bar-leading">
|
|
178
|
+
<button type="button" tabindex="0">
|
|
179
|
+
<label-view system-image="x"></label-view>
|
|
180
|
+
</button>
|
|
181
|
+
</tool-bar-item>
|
|
182
|
+
</tool-bar>
|
|
183
|
+
</dialog>`, '>1')
|
|
184
|
+
: $(html `<body-view>
|
|
185
|
+
<scroll-view>
|
|
186
|
+
<v-stack placement="leading fill">
|
|
187
|
+
<list-view preferred-expanded-style="inset"></list-view>
|
|
188
|
+
</v-stack>
|
|
189
|
+
</scroll-view>
|
|
190
|
+
<tool-bar>
|
|
191
|
+
<tool-bar-item slot="top-bar-leading">
|
|
192
|
+
<button type="button" tabindex="0">
|
|
193
|
+
<label-view system-image="caret-left"></label-view>
|
|
194
|
+
</button>
|
|
195
|
+
</tool-bar-item>
|
|
196
|
+
</tool-bar>
|
|
197
|
+
</body-view>`, '>1'), sv = body.querySelector('scroll-view'), list = body.querySelector('list-view'), backBtn = body.querySelector('button');
|
|
198
|
+
if (title)
|
|
199
|
+
sv?.setAttribute('navigation-inline-title', title);
|
|
200
|
+
if (searchable) {
|
|
201
|
+
list?.style.setProperty('--list--sticky-block-size', '70px');
|
|
202
|
+
list?.insertAdjacentHTML('afterend', `<sticky-container edge="navbar" style="order: -1" padding>
|
|
203
|
+
<v-stack spacing="0" alignment="fill">
|
|
204
|
+
<input is="search-view" placeholder="Search">
|
|
205
|
+
<!--<button type="button">Filters</button>-->
|
|
206
|
+
</v-stack>
|
|
207
|
+
</sticky-container>`);
|
|
208
|
+
const searchInput = sv?.querySelector('input'); // FIXME: compoennt is=search-view??
|
|
209
|
+
searchInput?.addEventListener('focus', ({ target }) => {
|
|
210
|
+
if (this.#spawn)
|
|
211
|
+
this.dispatchEvent(new CustomEvent('picker:searchfocus', {
|
|
212
|
+
detail: { element: this.#spawn, search: target instanceof HTMLInputElement ? target.value : '' },
|
|
213
|
+
bubbles: true,
|
|
214
|
+
composed: true,
|
|
215
|
+
}));
|
|
216
|
+
});
|
|
217
|
+
searchInput?.addEventListener('blur', ({ target }) => {
|
|
218
|
+
if (this.#spawn)
|
|
219
|
+
this.dispatchEvent(new CustomEvent('picker:searchblur', {
|
|
220
|
+
detail: { element: this.#spawn, search: target instanceof HTMLInputElement ? target.value : '' },
|
|
221
|
+
bubbles: true,
|
|
222
|
+
composed: true,
|
|
223
|
+
}));
|
|
224
|
+
});
|
|
225
|
+
searchInput?.addEventListener('input', ({ target }) => {
|
|
226
|
+
if (this.#spawn)
|
|
227
|
+
this.dispatchEvent(new CustomEvent('picker:searchinput', {
|
|
228
|
+
detail: { element: this.#spawn, search: target instanceof HTMLInputElement ? target.value : '' },
|
|
229
|
+
bubbles: true,
|
|
230
|
+
composed: true,
|
|
231
|
+
}));
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
backBtn?.setAttribute('help', I18n.t('ButtonRole').Back);
|
|
235
|
+
backBtn?.addEventListener('click', async (evt) => {
|
|
236
|
+
evt.stopImmediatePropagation();
|
|
237
|
+
evt.preventDefault();
|
|
238
|
+
const { target } = evt;
|
|
239
|
+
if (!(target instanceof HTMLElement))
|
|
240
|
+
return;
|
|
241
|
+
const { component } = new NavigationPath(target)?.hydrate();
|
|
242
|
+
await startViewTransition(target, 'backwards', async () => {
|
|
243
|
+
component?.remove();
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
for (const [i, el] of elements.entries()) {
|
|
247
|
+
if (el instanceof Element)
|
|
248
|
+
switch (el.tagName) {
|
|
249
|
+
case 'OPTGROUP': {
|
|
250
|
+
const group = _a.#wrapOptgroupTag(el);
|
|
251
|
+
_a.#reflectButtons([...el.children], group);
|
|
252
|
+
for (const btn of group.querySelectorAll(':scope>button'))
|
|
253
|
+
btn.addEventListener('click', this.#handlePageBtnClick);
|
|
254
|
+
list?.appendChild(group);
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
case 'OPTION': {
|
|
258
|
+
const btn = _a.#wrapOptionTag(el);
|
|
259
|
+
btn.addEventListener('click', this.#handlePageBtnClick);
|
|
260
|
+
list?.appendChild(btn);
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
default: {
|
|
264
|
+
const btn = _a.#wrapOptionSpawnTag(el);
|
|
265
|
+
const groupId = parentGroupId ? `${parentGroupId}.${i}` : `${i}`;
|
|
266
|
+
// const btn = $<HTMLButtonElement>(
|
|
267
|
+
// `<button type="button" tabindex="0" navigation-link><h-stack distribution="leading" template="auto spacer"><label-view data-role="check" style="visibility: hidden"><image-view slot="icon" system-name="check"></image-view></label-view><label-view><span></span></label-view></h-stack></button>`,
|
|
268
|
+
// '>1'
|
|
269
|
+
// ),
|
|
270
|
+
// label = btn.querySelector<LabelView>(':scope>h-stack>label-view:nth-child(2)')
|
|
271
|
+
// const node = el as HTMLElement
|
|
272
|
+
// if (label && node.dataset.label) renderLabelTitle(label, node.dataset.label) //label?.setAttribute('title', el.dataset.label)
|
|
273
|
+
btn.dataset.groupId = groupId;
|
|
274
|
+
btn.addEventListener('click', this.#makeGroupClickHandler(el, groupId));
|
|
275
|
+
list?.appendChild(btn);
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
if (el.children.length)
|
|
281
|
+
if (allLeaves(el)) {
|
|
282
|
+
const group = _a.#wrapOptgroupTag(el);
|
|
283
|
+
_a.#reflectButtons(el.children, group);
|
|
284
|
+
for (const btn of group.querySelectorAll(':scope>button'))
|
|
285
|
+
btn.addEventListener('click', this.#handlePageBtnClick);
|
|
286
|
+
list?.appendChild(group);
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
const btn = _a.#wrapOptionSpawnTag(el);
|
|
290
|
+
const groupId = parentGroupId ? `${parentGroupId}.${i}` : `${i}`;
|
|
291
|
+
btn.dataset.groupId = groupId;
|
|
292
|
+
btn.addEventListener('click', this.#makeGroupClickHandler(el, groupId));
|
|
293
|
+
list?.appendChild(btn);
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
const btn = _a.#wrapOptionTag(el);
|
|
297
|
+
btn.addEventListener('click', this.#handlePageBtnClick);
|
|
298
|
+
list?.appendChild(btn);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return body;
|
|
303
|
+
};
|
|
304
|
+
#resyncSpawnedPages = (freshRoot) => {
|
|
305
|
+
if (!this.#spawn)
|
|
306
|
+
return;
|
|
307
|
+
const groupMap = indexGroups(freshRoot);
|
|
308
|
+
for (const el of this.#spawn.querySelectorAll('body-view')) {
|
|
309
|
+
const depth = ancestors('body-view,[is=sheet-view]', el).indexOf(this.#spawn);
|
|
310
|
+
if (0 >= depth)
|
|
311
|
+
continue;
|
|
312
|
+
const groupId = el.dataset.groupId;
|
|
313
|
+
const source = groupId ? groupMap.get(groupId) : undefined;
|
|
314
|
+
if (!source) {
|
|
315
|
+
el.remove();
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
const children = source instanceof Element ? Array.from(source.children) : source.children;
|
|
319
|
+
const title = source instanceof Element ? extractLabel(source) : (source.title ?? null);
|
|
320
|
+
const newPage = this.#spawnPage(children, 'body-view', groupId, this.hasAttribute('searchable'), title);
|
|
321
|
+
newPage.dataset.groupId = groupId;
|
|
322
|
+
reflectSpawnedPage(el, newPage);
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
#renderButtons(input) {
|
|
326
|
+
debug(`${_a.name} #renderButtons`);
|
|
327
|
+
switch (input.mode) {
|
|
328
|
+
case 'dictionary': {
|
|
329
|
+
const flattenDictionary = (tree) => {
|
|
330
|
+
const out1 = {}, out2 = {}, stack = [tree], idx = [0];
|
|
331
|
+
while (stack.length) {
|
|
332
|
+
const frame = stack[stack.length - 1], i = idx[idx.length - 1];
|
|
333
|
+
if (i >= frame.length) {
|
|
334
|
+
stack.pop();
|
|
335
|
+
idx.pop();
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
idx[idx.length - 1]++;
|
|
339
|
+
const { value, title, systemImage, children } = frame[i];
|
|
340
|
+
out1[value] = title;
|
|
341
|
+
out2[value] = systemImage;
|
|
342
|
+
if (children.length) {
|
|
343
|
+
stack.push(children);
|
|
344
|
+
idx.push(0);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return { labels: out1, icons: out2 };
|
|
348
|
+
};
|
|
349
|
+
this.#lastRenderedLabelMap = flattenDictionary(input.source).labels;
|
|
350
|
+
this.#lastRenderedIconMap = flattenDictionary(input.source).icons;
|
|
351
|
+
// const collectLeafValues = (node: DictEntry): string[] => (node.children.length ? node.children.flatMap(collectLeafValues) : [node.value])
|
|
352
|
+
// collectGroups = (nodes: DictEntry[]): string[][] => {
|
|
353
|
+
// const groups: string[][] = []
|
|
354
|
+
// const walk = (list: DictEntry[]) => {
|
|
355
|
+
// for (const node of list) {
|
|
356
|
+
// if (!node.children.length) continue
|
|
357
|
+
// if (!allLeaves(node)) groups.push(collectLeafValues(node))
|
|
358
|
+
// walk(node.children)
|
|
359
|
+
// }
|
|
360
|
+
// }
|
|
361
|
+
// walk(nodes)
|
|
362
|
+
// return groups
|
|
363
|
+
// }
|
|
364
|
+
this.#lastIndexedRoot = input.source; //this.#lastRenderedGroupMap = collectGroups(dictionary)
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
case 'list': {
|
|
368
|
+
this.#lastRenderedLabelMap = {};
|
|
369
|
+
this.#lastRenderedIconMap = {};
|
|
370
|
+
for (const el of input.source)
|
|
371
|
+
if (el.matches('option')) {
|
|
372
|
+
const k = extractTag(el);
|
|
373
|
+
this.#lastRenderedLabelMap[k] = el.getAttribute('label') ?? undefined;
|
|
374
|
+
this.#lastRenderedIconMap[k] = extractIcon(el) ?? undefined;
|
|
375
|
+
}
|
|
376
|
+
else
|
|
377
|
+
for (const opt of el.querySelectorAll('option')) {
|
|
378
|
+
const k = extractTag(opt);
|
|
379
|
+
this.#lastRenderedLabelMap[k] = opt.getAttribute('label') ?? undefined;
|
|
380
|
+
this.#lastRenderedIconMap[k] = extractIcon(opt) ?? undefined;
|
|
381
|
+
}
|
|
382
|
+
this.#lastIndexedRoot = input.source;
|
|
383
|
+
// this.#lastRenderedGroupMap = assigned.flatMap<string[]>((el) =>
|
|
384
|
+
// [...(el.matches('datalist') ? [el as HTMLDataListElement] : []), ...el.querySelectorAll<HTMLDataListElement>('datalist')].map((dl) =>
|
|
385
|
+
// Array.from(dl.options).map((opt) => extractTagFromOption(opt))
|
|
386
|
+
// )
|
|
387
|
+
// )
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
switch (this.pickerStyle) {
|
|
392
|
+
case 'sheet':
|
|
393
|
+
case 'navigation-link': {
|
|
394
|
+
// current value label only
|
|
395
|
+
const currentValueLabel = this.querySelector(':scope>label-view:not([slot])') ?? this.appendChild($(html `<label-view></label-view>`, '>1'));
|
|
396
|
+
// reset state
|
|
397
|
+
// if (currentValueLabel) {
|
|
398
|
+
// renderLabelIcon(currentValueLabel, 'dots-three') // overwritten
|
|
399
|
+
// renderLabelTitle(currentValueLabel, this.#currentValueLabel) // overwritten
|
|
400
|
+
// }
|
|
401
|
+
// clear all siblings
|
|
402
|
+
for (const el of this.querySelectorAll(':scope>:not([slot])'))
|
|
403
|
+
if (currentValueLabel !== el)
|
|
404
|
+
el.remove();
|
|
405
|
+
CleanupRegistry.unregister(this, 'trigger');
|
|
406
|
+
CleanupRegistry.register(this, onoff('click', this.#handleTriggerClick, currentValueLabel).on(), 'trigger');
|
|
407
|
+
if (this.hasAttribute(this.constructor.ATTR.TRIGGER_HELP))
|
|
408
|
+
currentValueLabel?.setAttribute(this.constructor.ATTR.TRIGGER_HELP, this.getAttribute(this.constructor.ATTR.TRIGGER_HELP) ?? '');
|
|
409
|
+
// rebuild snapshot(tree)
|
|
410
|
+
if (!this.#spawn)
|
|
411
|
+
break;
|
|
412
|
+
// rerender level 0
|
|
413
|
+
reflectSpawnedPage(this.#spawn, this.#spawnPage(input.source, 'DIALOG' === this.#spawn.tagName ? 'sheet-view' : 'body-view', undefined, this.hasAttribute('searchable'), this.getAttribute('label')));
|
|
414
|
+
this.#resyncSpawnedPages(input.source);
|
|
415
|
+
// // FIXME:
|
|
416
|
+
// for (const el of this.#spawn.querySelectorAll<HTMLElement>('body-view')) {
|
|
417
|
+
// const depth = $.ancestors('body-view,[is=sheet-view]', el).indexOf(this.#spawn)
|
|
418
|
+
// if (0 >= depth) continue
|
|
419
|
+
// const datalist = this.querySelector<HTMLElement>(`:scope>${Array.from({ length: depth }, () => 'datalist').join('>')}`)
|
|
420
|
+
// if (!datalist) {
|
|
421
|
+
// el.remove()
|
|
422
|
+
// break
|
|
423
|
+
// }
|
|
424
|
+
// reflectSpawnedElement(el, this.#spawnPage(Array.from(datalist.children), 'body-view', this.hasAttribute('searchable'), datalist.dataset.label))
|
|
425
|
+
// }
|
|
426
|
+
break;
|
|
427
|
+
}
|
|
428
|
+
case 'menu': {
|
|
429
|
+
const menu = this.querySelector(':scope>menu-view:not([slot])') ?? this.appendChild($(html `<menu-view></menu-view>`, '>1'));
|
|
430
|
+
// reset state
|
|
431
|
+
menu.innerHTML = '';
|
|
432
|
+
menu.tabIndex = 0;
|
|
433
|
+
// clear all siblings
|
|
434
|
+
for (const el of this.querySelectorAll(':scope>:not([slot])'))
|
|
435
|
+
if (menu !== el)
|
|
436
|
+
el.remove();
|
|
437
|
+
const currentValueLabel = menu.querySelector(':scope>label-view[slot=label]') ?? menu.appendChild($(html `<label-view slot="label"></label-view>`, '>1'));
|
|
438
|
+
// if (currentValueLabel) {
|
|
439
|
+
// renderLabelIcon(currentValueLabel, 'dots-three') // overwritten
|
|
440
|
+
// renderLabelTitle(currentValueLabel, this.#currentValueLabel) // overwritten
|
|
441
|
+
// }
|
|
442
|
+
if (this.hasAttribute(this.constructor.ATTR.TRIGGER_HELP))
|
|
443
|
+
currentValueLabel?.setAttribute(this.constructor.ATTR.TRIGGER_HELP, this.getAttribute(this.constructor.ATTR.TRIGGER_HELP) ?? '');
|
|
444
|
+
_a.#reflectButtons(input.source, menu);
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
case 'inline':
|
|
448
|
+
default: {
|
|
449
|
+
const sectionTpl = html `<section-view></section-view>`;
|
|
450
|
+
const inlineList = this.querySelector(':scope>list-view:not([slot])') ?? this.appendChild($(html `<list-view>${sectionTpl}</list-view>`, '>1')), section = inlineList.querySelector(':scope>section-view') ?? inlineList.appendChild($(sectionTpl, '>1'));
|
|
451
|
+
// reset state
|
|
452
|
+
section.innerHTML = '';
|
|
453
|
+
// clear all siblings
|
|
454
|
+
for (const el of this.querySelectorAll(':scope>:not([slot])'))
|
|
455
|
+
if (inlineList !== el)
|
|
456
|
+
el.remove();
|
|
457
|
+
// add label as a plain element
|
|
458
|
+
const value = this.getAttribute(this.constructor.ATTR.LABEL);
|
|
459
|
+
if (value) {
|
|
460
|
+
const hStack = $(html `<h-stack distribution="leading" template="auto spacer"
|
|
461
|
+
><label-view data-role="check" style="visibility: hidden"><image-view slot="icon" system-name="check"></image-view></label-view><label-view><span></span></label-view
|
|
462
|
+
></h-stack>`, '>1');
|
|
463
|
+
queryMorph('label-view:nth-child(2)', html `<label-view>${value ? html `<span>${value}</span>` : null}</label-view>`, hStack);
|
|
464
|
+
// if (label) renderLabelTitle(label, value) //label.setAttribute('title', value)
|
|
465
|
+
section.insertAdjacentElement('beforeend', hStack);
|
|
466
|
+
}
|
|
467
|
+
if ('dictionary' === input.mode)
|
|
468
|
+
_a.#reflectButtons(input.source.filter((el) => 0 === el.children.length), section);
|
|
469
|
+
else
|
|
470
|
+
_a.#reflectButtons(input.source.filter((el) => el.matches('option')), section);
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
this.#reflectSelectionOnButtons();
|
|
475
|
+
this.#reflectSelectionOnCurrentValueLabel();
|
|
476
|
+
}
|
|
477
|
+
#renderDictionary = (dictionary) => {
|
|
478
|
+
debug(`${_a.name} ⚡️ mutation`);
|
|
479
|
+
this.#renderButtons({ mode: 'dictionary', source: dictionary });
|
|
480
|
+
};
|
|
481
|
+
#renderSlotted = (entries) => {
|
|
482
|
+
debug(`${_a.name} ⚡️ mutation`);
|
|
483
|
+
this.#renderButtons({ mode: 'list', source: this.#slots?.get('list')?.assignedElements({ flatten: true }) ?? [] });
|
|
484
|
+
};
|
|
485
|
+
#renderValidityMsgs = (entries) => {
|
|
486
|
+
debug(`${_a.name} ⚡️ mutation`);
|
|
487
|
+
this.setValidity(this.validity, this.validationMessage);
|
|
488
|
+
};
|
|
21
489
|
#lastRenderedStyle; //string | null
|
|
22
490
|
#shadowRoot;
|
|
491
|
+
#slots = new Map();
|
|
492
|
+
#validityObservers = new MutationObserverSet(this.#renderValidityMsgs);
|
|
493
|
+
#observers = new MutationObserverSet(this.#renderSlotted);
|
|
23
494
|
#customValidity = '';
|
|
24
|
-
#validitiesSlot;
|
|
25
|
-
#datalistSlot;
|
|
26
|
-
#tagSlot;
|
|
27
|
-
#trackedElements = new Set();
|
|
28
495
|
#selection = '';
|
|
496
|
+
get selection() {
|
|
497
|
+
return this.#selection;
|
|
498
|
+
}
|
|
499
|
+
set selection(v) {
|
|
500
|
+
if (Object.is(this.#selection, v))
|
|
501
|
+
return;
|
|
502
|
+
this.#selection = v;
|
|
503
|
+
this.#reflectSelectionOnButtons();
|
|
504
|
+
this.#reflectSelectionOnCurrentValueLabel();
|
|
505
|
+
this.#sendValueToForm();
|
|
506
|
+
}
|
|
507
|
+
#lastRenderedLabelMap = {};
|
|
508
|
+
#lastRenderedIconMap = {};
|
|
509
|
+
#lastIndexedRoot = [];
|
|
510
|
+
get #currentValueLabel() {
|
|
511
|
+
return ((this.getAttribute(this.constructor.ATTR.CURRENT_VALUE_LABEL) ?? '').replaceAll('{{selection}}', this.#selection).replaceAll('{{currentValueLabel}}', this.#selection) ||
|
|
512
|
+
this.#lastRenderedLabelMap[this.#selection]);
|
|
513
|
+
}
|
|
514
|
+
get #currentValueIcon() {
|
|
515
|
+
return (this.getAttribute(this.constructor.ATTR.CURRENT_VALUE_ICON) ?? '') || this.#lastRenderedIconMap[this.#selection];
|
|
516
|
+
}
|
|
29
517
|
get #internals() {
|
|
30
518
|
return getInternals(this);
|
|
31
519
|
}
|
|
32
520
|
get template() {
|
|
33
|
-
// const style = this.getAttribute((this.constructor as typeof PickerView).ATTR.PICKER_STYLE) ?? ''
|
|
34
521
|
if (!_a.#templates.has(this.pickerStyle))
|
|
35
522
|
switch (this.pickerStyle) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
523
|
+
case 'sheet':
|
|
524
|
+
case 'navigation-link':
|
|
525
|
+
_a.#templates.set(this.pickerStyle, $(html `
|
|
526
|
+
<label part="root picker-stack">
|
|
527
|
+
<div part="root picker-label-stack">
|
|
528
|
+
<slot name="label"></slot>
|
|
529
|
+
</div>
|
|
530
|
+
<div part="root picker-input-stack">
|
|
531
|
+
<slot></slot>
|
|
532
|
+
</div>
|
|
533
|
+
<slot name="list" hidden></slot>
|
|
534
|
+
<slot name="validity-options" hidden></slot>
|
|
535
|
+
</label>
|
|
536
|
+
`));
|
|
537
|
+
break;
|
|
43
538
|
case 'menu':
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
</label>
|
|
57
|
-
`, ''));
|
|
539
|
+
_a.#templates.set(this.pickerStyle, $(html `
|
|
540
|
+
<label part="root picker-stack">
|
|
541
|
+
<div part="root picker-label-stack">
|
|
542
|
+
<slot name="label"></slot>
|
|
543
|
+
</div>
|
|
544
|
+
<div part="root picker-input-stack">
|
|
545
|
+
<slot></slot>
|
|
546
|
+
</div>
|
|
547
|
+
<slot name="list" hidden></slot>
|
|
548
|
+
<slot name="validity-options" hidden></slot>
|
|
549
|
+
</label>
|
|
550
|
+
`));
|
|
58
551
|
// break
|
|
59
552
|
// case 'compact':
|
|
60
553
|
// PickerView.#templates.set(
|
|
@@ -96,25 +589,23 @@ export class PickerView extends FormAssociatedBase {
|
|
|
96
589
|
// <option value="0" label="0%"></option>
|
|
97
590
|
// </datalist>
|
|
98
591
|
// </div>
|
|
99
|
-
// <slot name="
|
|
592
|
+
// <slot name="list" hidden></slot>
|
|
100
593
|
// </label>`,
|
|
101
594
|
// })
|
|
102
595
|
// )
|
|
103
596
|
// break
|
|
104
597
|
case 'inline':
|
|
105
598
|
default:
|
|
106
|
-
_a.#templates.set(this.pickerStyle, $(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
<slot name="validity-options" hidden></slot>
|
|
117
|
-
</label>`, ''));
|
|
599
|
+
_a.#templates.set(this.pickerStyle, $(html ` <label part="root picker-stack">
|
|
600
|
+
<div part="root picker-label-stack">
|
|
601
|
+
<slot name="label"></slot>
|
|
602
|
+
</div>
|
|
603
|
+
<div part="root picker-input-stack">
|
|
604
|
+
<slot></slot>
|
|
605
|
+
</div>
|
|
606
|
+
<slot name="list" hidden></slot>
|
|
607
|
+
<slot name="validity-options" hidden></slot>
|
|
608
|
+
</label>`));
|
|
118
609
|
break;
|
|
119
610
|
}
|
|
120
611
|
return _a.#templates.get(this.pickerStyle);
|
|
@@ -122,97 +613,99 @@ export class PickerView extends FormAssociatedBase {
|
|
|
122
613
|
constructor() {
|
|
123
614
|
super();
|
|
124
615
|
this.#shadowRoot = this.attachShadow({ mode: 'closed' });
|
|
125
|
-
// this.#render() // Snapshot.waitReady.then(this.#render.bind(this))
|
|
126
|
-
}
|
|
127
|
-
connectedCallback() {
|
|
128
|
-
console.debug(`${_a.name} ⚡️ connect`);
|
|
129
|
-
CleanupRegistry.register(this, onoff('click', this.#handleClick, this).on());
|
|
130
|
-
if (!this.hasAttribute(this.constructor.ATTR.PICKER_STYLE))
|
|
131
|
-
this.#render(); // will be picked up by attr-change!
|
|
132
|
-
// finally
|
|
133
|
-
if (!this.hasAttribute('selection'))
|
|
134
|
-
return;
|
|
135
|
-
this.#selection = this.getAttribute('selection') ?? '';
|
|
136
|
-
this.#sendValueToForm(false);
|
|
137
|
-
}
|
|
138
|
-
disconnectedCallback() {
|
|
139
|
-
console.debug(`${_a.name} ⚡️ disconnect`);
|
|
140
|
-
CleanupRegistry.unregister(this);
|
|
141
|
-
observers.clearObservationsSet(this.#trackedElements);
|
|
142
616
|
}
|
|
143
617
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
144
|
-
|
|
618
|
+
debug(`${_a.name} ⚡️ attr-change [${name}] ("${oldValue}" → "${newValue}")`);
|
|
145
619
|
switch (name) {
|
|
146
620
|
case this.constructor.ATTR.PLACEHOLDER:
|
|
147
|
-
|
|
621
|
+
case this.constructor.ATTR.PLACEHOLDER_ICON:
|
|
622
|
+
if (oldValue === newValue)
|
|
623
|
+
break;
|
|
624
|
+
this.#reflectSelectionOnCurrentValueLabel(); //this.#reflectPlaceholder(newValue)
|
|
148
625
|
break;
|
|
149
626
|
case this.constructor.ATTR.LABEL:
|
|
150
627
|
this.#reflectLabel(newValue);
|
|
151
|
-
this.#sendValueToForm()
|
|
628
|
+
// this.#sendValueToForm()
|
|
152
629
|
break;
|
|
153
630
|
case this.constructor.ATTR.PICKER_STYLE:
|
|
154
631
|
if (oldValue === newValue)
|
|
155
632
|
break;
|
|
156
633
|
this.#render();
|
|
157
|
-
|
|
634
|
+
break;
|
|
635
|
+
case this.constructor.ATTR.SEARCHABLE:
|
|
636
|
+
if (oldValue === newValue)
|
|
637
|
+
break;
|
|
638
|
+
this.#renderSlotted([]);
|
|
639
|
+
break;
|
|
640
|
+
case this.constructor.ATTR.CURRENT_VALUE_LABEL:
|
|
641
|
+
case this.constructor.ATTR.CURRENT_VALUE_ICON:
|
|
642
|
+
// if (oldValue === newValue) break
|
|
643
|
+
this.#reflectSelectionOnCurrentValueLabel();
|
|
644
|
+
break;
|
|
645
|
+
case this.constructor.ATTR.TRIGGER_HELP:
|
|
646
|
+
// if (oldValue === newValue) break
|
|
647
|
+
this.#reflectTriggerHelp();
|
|
648
|
+
break;
|
|
649
|
+
case this.constructor.ATTR.DICTIONARY:
|
|
650
|
+
if (oldValue === newValue)
|
|
651
|
+
break;
|
|
652
|
+
this.#renderDictionary(parseDictionary(newValue));
|
|
653
|
+
break;
|
|
654
|
+
case this.constructor.ATTR.REQUIRED:
|
|
655
|
+
if (oldValue === newValue)
|
|
656
|
+
break;
|
|
657
|
+
this.#sendValueToForm(false);
|
|
158
658
|
break;
|
|
159
659
|
case this.constructor.ATTR.SELECTION:
|
|
160
660
|
// nothing happens
|
|
161
661
|
break;
|
|
162
662
|
}
|
|
163
663
|
}
|
|
664
|
+
disconnectedCallback() {
|
|
665
|
+
debug(`${_a.name} ⚡️ disconnect`);
|
|
666
|
+
CleanupRegistry.unregister(this);
|
|
667
|
+
this.#validityObservers.unobserveAll();
|
|
668
|
+
this.#observers.unobserveAll();
|
|
669
|
+
}
|
|
670
|
+
connectedCallback() {
|
|
671
|
+
debug(`${_a.name} ⚡️ connect`);
|
|
672
|
+
CleanupRegistry.register(this, onoff('localechange', () => {
|
|
673
|
+
this.#renderSlotted([]);
|
|
674
|
+
}, I18n.on).on());
|
|
675
|
+
CleanupRegistry.register(this, onoff('click', this.#handleClick, this).on());
|
|
676
|
+
if (!this.hasAttribute(this.constructor.ATTR.PICKER_STYLE))
|
|
677
|
+
this.#render(); // skip if already rendered by attr-change during upgrade!
|
|
678
|
+
// finally
|
|
679
|
+
if (!this.hasAttribute('selection'))
|
|
680
|
+
return;
|
|
681
|
+
this.#selection = this.getAttribute('selection') ?? '';
|
|
682
|
+
this.#sendValueToForm(false);
|
|
683
|
+
}
|
|
164
684
|
get pickerStyle() {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
: 'automatic';
|
|
685
|
+
const attr = this.constructor.ATTR.PICKER_STYLE;
|
|
686
|
+
return pickerStyles.includes(this.getAttribute(attr) ?? '') ? this.getAttribute(attr) : 'automatic';
|
|
168
687
|
}
|
|
169
688
|
#render() {
|
|
170
|
-
|
|
171
|
-
if (!this.isConnected)
|
|
172
|
-
return;
|
|
689
|
+
debug(`${_a.name} ⚡️ #render (${this.pickerStyle})`);
|
|
173
690
|
// const style = this.getAttribute((this.constructor as typeof PickerView).ATTR.PICKER_STYLE)
|
|
174
691
|
if (this.#lastRenderedStyle === this.pickerStyle)
|
|
175
692
|
return; // skip if already applied
|
|
176
693
|
this.#lastRenderedStyle = this.pickerStyle;
|
|
177
694
|
// clear shadow DOM
|
|
178
695
|
this.#shadowRoot.replaceChildren(document.importNode(this.template, true));
|
|
179
|
-
this
|
|
180
|
-
|
|
181
|
-
|
|
696
|
+
CleanupRegistry.unregister(this, 'slots');
|
|
697
|
+
for (const slot of this.#shadowRoot.querySelectorAll('slot'))
|
|
698
|
+
this.#slots?.set(slot.name, slot);
|
|
699
|
+
CleanupRegistry.register(this, () => {
|
|
700
|
+
this.#slots = new Map();
|
|
701
|
+
}, 'slots');
|
|
182
702
|
CleanupRegistry.unregister(this, 'validities');
|
|
183
|
-
CleanupRegistry.register(this, onoff(
|
|
703
|
+
CleanupRegistry.register(this, onoff('slotchange', this.#handleValiditiesSlotchange, this.#slots?.get('validity-options')).on(), 'validities');
|
|
184
704
|
CleanupRegistry.unregister(this, 'datalist'); //off1()
|
|
185
|
-
CleanupRegistry.register(this, onoff('slotchange', this.#
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
//
|
|
189
|
-
// if (0 < (this.#tagSlot?.assignedElements({ flatten: true }) ?? []).length) this.#handleTagMutation()
|
|
190
|
-
//this.getAttribute((this.constructor as typeof PickerView).ATTR.PICKER_STYLE)) {
|
|
191
|
-
switch (this.pickerStyle
|
|
192
|
-
// case 'menu':
|
|
193
|
-
// // if (0 < (this.#datalistSlot?.assignedElements({ flatten: true }) ?? []).length) this.#handleMenuDatalistMutation()
|
|
194
|
-
// break
|
|
195
|
-
// case 'gg':
|
|
196
|
-
// // reattach input listener
|
|
197
|
-
// const input = this.#shadowRoot.querySelector('input')
|
|
198
|
-
// if (input) {
|
|
199
|
-
// input.addEventListener('input', () => {
|
|
200
|
-
// this.#internals!.setFormValue(input.value)
|
|
201
|
-
// })
|
|
202
|
-
// // restore placeholder if set
|
|
203
|
-
// const placeholder = this.getAttribute((this.constructor as typeof PickerView).ATTR.PLACEHOLDER)
|
|
204
|
-
// if (placeholder) input.setAttribute('placeholder', placeholder)
|
|
205
|
-
// }
|
|
206
|
-
// // restore label if set
|
|
207
|
-
// const label = this.getAttribute((this.constructor as typeof PickerView).ATTR.LABEL)
|
|
208
|
-
// if (label) this.#reflectLabel(label)
|
|
209
|
-
// break
|
|
210
|
-
// case 'inline':
|
|
211
|
-
// default:
|
|
212
|
-
// // if (0 < (this.#datalistSlot?.assignedElements({ flatten: true }) ?? []).length) this.#handleInlineDatalistMutation()
|
|
213
|
-
// break
|
|
214
|
-
) {
|
|
215
|
-
}
|
|
705
|
+
CleanupRegistry.register(this, onoff('slotchange', this.#handleListSlotchange, this.#slots?.get('list')).on(), 'datalist');
|
|
706
|
+
// #renderSlotted should run automatically now by slotchange initial event
|
|
707
|
+
// switch (this.pickerStyle) {
|
|
708
|
+
// }
|
|
216
709
|
}
|
|
217
710
|
#sendValueToForm = (dispatchEvent = true) => {
|
|
218
711
|
// input.value has already been updated/synced !!
|
|
@@ -233,159 +726,370 @@ export class PickerView extends FormAssociatedBase {
|
|
|
233
726
|
if (dispatchEvent)
|
|
234
727
|
this.dispatchEvent(new CustomEvent('selection', { detail: { selection: this.#selection }, bubbles: true, composed: true }));
|
|
235
728
|
};
|
|
236
|
-
#
|
|
237
|
-
|
|
238
|
-
|
|
729
|
+
#handleTriggerClick = async ({ type, target }) => {
|
|
730
|
+
debug(`${_a.name} ⚡️ ${type}`);
|
|
731
|
+
if (!(target instanceof HTMLElement))
|
|
732
|
+
return;
|
|
733
|
+
this.#spawn?.remove?.();
|
|
734
|
+
const level0 = this.#spawnPage(this.hasAttribute(this.constructor.ATTR.DICTIONARY) ? parseDictionary(this.getAttribute('dictionary')) : (this.#slots?.get('list')?.assignedElements() ?? []), 'sheet' === this.pickerStyle ? 'sheet-view' : 'body-view', undefined, this.hasAttribute('searchable'), this.getAttribute('label'));
|
|
735
|
+
if (!level0)
|
|
736
|
+
return;
|
|
737
|
+
const path = new NavigationPath(target)?.hydrate();
|
|
738
|
+
await startViewTransition(target, 'forwards', async () => {
|
|
739
|
+
this.#spawn = level0;
|
|
740
|
+
update(path, level0);
|
|
741
|
+
this.#reflectSelectionOnButtons();
|
|
742
|
+
});
|
|
743
|
+
};
|
|
744
|
+
#handlePageBtnClick = async (evt) => {
|
|
745
|
+
debug(`${_a.name} ⚡️ ${evt?.type}`);
|
|
746
|
+
evt.stopImmediatePropagation();
|
|
747
|
+
evt.preventDefault();
|
|
748
|
+
const { currentTarget: btn } = evt;
|
|
749
|
+
if (!(btn instanceof HTMLElement))
|
|
750
|
+
return;
|
|
751
|
+
// const btn = target.closest('button')
|
|
752
|
+
// if (!btn) return
|
|
753
|
+
const proceed = () => {
|
|
754
|
+
this.#spawn?.remove();
|
|
755
|
+
this.#selection = btn.getAttribute('value') ?? '';
|
|
756
|
+
this.#reflectSelectionOnButtons();
|
|
757
|
+
this.#reflectSelectionOnCurrentValueLabel();
|
|
758
|
+
this.#sendValueToForm();
|
|
759
|
+
};
|
|
760
|
+
const { body } = new NavigationPath(this.#spawn)?.hydrate();
|
|
761
|
+
if (!body)
|
|
762
|
+
return proceed();
|
|
763
|
+
await startViewTransition(body, 'backwards', async () => {
|
|
764
|
+
proceed();
|
|
765
|
+
});
|
|
766
|
+
};
|
|
767
|
+
#handleClick({ type, target }) {
|
|
768
|
+
debug(`${_a.name} ⚡️ ${type}`);
|
|
769
|
+
if (!(target instanceof HTMLElement))
|
|
770
|
+
return;
|
|
771
|
+
const btn = target.closest('button');
|
|
239
772
|
if (!btn)
|
|
240
773
|
return;
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
else {
|
|
245
|
-
this.#selection = btn.textContent; //this.dispatchEvent(new CustomEvent('selection', { detail: { tag: btn.textContent }, bubbles: true, composed: true }))
|
|
246
|
-
}
|
|
774
|
+
this.#selection = btn.getAttribute('value') ?? '';
|
|
775
|
+
this.#reflectSelectionOnButtons();
|
|
776
|
+
this.#reflectSelectionOnCurrentValueLabel();
|
|
247
777
|
this.#sendValueToForm();
|
|
248
778
|
}
|
|
249
|
-
#
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
//
|
|
256
|
-
|
|
257
|
-
// }
|
|
258
|
-
// for (const el of assigned) {
|
|
259
|
-
// if (!this.#trackedElements.has(el))
|
|
260
|
-
// observers.observe(el, this.#handleTagMutation, {
|
|
261
|
-
// attributes: true,
|
|
262
|
-
// characterData: true,
|
|
263
|
-
// subtree: true,
|
|
264
|
-
// childList: true,
|
|
265
|
-
// // attributeFilter: ['value', 'label'],
|
|
266
|
-
// })
|
|
267
|
-
// this.#trackedElements.add(el)
|
|
268
|
-
// }
|
|
269
|
-
if (0 < assigned.length)
|
|
270
|
-
this.#handleTagMutation();
|
|
779
|
+
#handleValiditiesSlotchange = ({ type, target: slot }) => {
|
|
780
|
+
debug(`${_a.name} ⚡️ ${type}`);
|
|
781
|
+
if (!(slot instanceof HTMLSlotElement))
|
|
782
|
+
return;
|
|
783
|
+
const assigned = slot.assignedElements();
|
|
784
|
+
this.#validityObservers.syncObservations(assigned, ['value', 'label']);
|
|
785
|
+
// if (0 < assigned.length)
|
|
786
|
+
this.#renderValidityMsgs([]);
|
|
271
787
|
};
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
788
|
+
#handleListSlotchange = ({ type, target: slot }) => {
|
|
789
|
+
debug(`${_a.name} ⚡️ ${type}`);
|
|
790
|
+
if (!(slot instanceof HTMLSlotElement))
|
|
791
|
+
return;
|
|
792
|
+
const assigned = slot.assignedElements();
|
|
793
|
+
this.#observers.syncObservations(assigned);
|
|
794
|
+
// if (0 < assigned.length)
|
|
795
|
+
this.#renderSlotted([]);
|
|
796
|
+
};
|
|
797
|
+
static #wrapOptionSpawnTag(node) {
|
|
798
|
+
debug(`${_a.name} #wrapOptionSpawnTag`);
|
|
799
|
+
const title = extractLabel(node), subtitle = extractSubtitle(node), icon = extractIcon(node);
|
|
800
|
+
const mount = document.createElement('div');
|
|
801
|
+
render(html `<button type="button" tabindex="0" navigation-link>
|
|
802
|
+
<h-stack distribution="leading" template="auto spacer">
|
|
803
|
+
<label-view data-role="check" style="visibility: hidden">
|
|
804
|
+
<image-view slot="icon" system-name="check"></image-view>
|
|
805
|
+
</label-view>
|
|
806
|
+
<h-stack distribution="fill" template="${icon ? 'auto spacer' : null}">
|
|
807
|
+
${icon ? html `<label-view system-image="${icon}"></label-view>` : null}
|
|
808
|
+
<v-stack spacing="3" alignment="fill">
|
|
809
|
+
<label-view title="${title}"></label-view>
|
|
810
|
+
${subtitle ? html `<label-view foreground="secondary" font="callout" title="${subtitle}"></label-view>` : null}
|
|
811
|
+
</v-stack>
|
|
812
|
+
</h-stack>
|
|
813
|
+
</h-stack>
|
|
814
|
+
</button>`, mount);
|
|
815
|
+
// const btn = $<HTMLButtonElement>(
|
|
816
|
+
// `<button type="button" tabindex="0" navigation-link><h-stack distribution="leading" template="auto spacer"><label-view data-role="check" style="visibility: hidden"><image-view slot="icon" system-name="check"></image-view></label-view><label-view><span></span></label-view></h-stack></button>`,
|
|
817
|
+
// '>1'
|
|
818
|
+
// ),
|
|
819
|
+
// hStack = btn.querySelector<LabelView>(':scope>h-stack') ?? undefined
|
|
820
|
+
// renderLabel(
|
|
821
|
+
// ':scope>label-view:nth-child(2)',
|
|
822
|
+
// `<label-view><span></span></label-view>`,
|
|
823
|
+
// hStack,
|
|
824
|
+
// extractLabelFromGroup(node as HTMLDataListElement),
|
|
825
|
+
// extractImgFromGroup(node as HTMLDataListElement)
|
|
826
|
+
// )
|
|
827
|
+
// // label = btn.querySelector<LabelView>(':scope>h-stack>label-view:nth-child(2)')
|
|
828
|
+
// // if (label) {
|
|
829
|
+
// // const lbl = extractLabelFromGroup(node as HTMLDataListElement),
|
|
830
|
+
// // img =extractImgFromGroup(node as HTMLDataListElement)
|
|
831
|
+
// // if(lbl) renderLabelTitle(label, node.dataset.label) //label?.setAttribute('title', el.dataset.label)
|
|
832
|
+
// // }
|
|
833
|
+
return mount.firstElementChild; //btn
|
|
293
834
|
}
|
|
294
|
-
#
|
|
295
|
-
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
835
|
+
static #wrapOptionTag(node) {
|
|
836
|
+
debug(`${_a.name} #wrapOptionTag`);
|
|
837
|
+
const tag = extractTag(node), title = extractLabel(node), subtitle = extractSubtitle(node), icon = extractIcon(node);
|
|
838
|
+
const mount = document.createElement('div');
|
|
839
|
+
render(html `<button type="button" tabindex="0" value="${tag}">
|
|
840
|
+
<h-stack distribution="leading" template="auto spacer">
|
|
841
|
+
<label-view data-role="check">
|
|
842
|
+
<image-view slot="icon" system-name="check"></image-view>
|
|
843
|
+
</label-view>
|
|
844
|
+
<h-stack distribution="fill" template="${icon ? 'auto spacer' : null}">
|
|
845
|
+
${icon ? html `<label-view system-image="${icon}"></label-view>` : null}
|
|
846
|
+
<v-stack spacing="3" alignment="fill">
|
|
847
|
+
<label-view title="${title}"></label-view>
|
|
848
|
+
${subtitle ? html `<label-view foreground="secondary" font="callout" title="${subtitle}"></label-view>` : null}
|
|
849
|
+
</v-stack>
|
|
850
|
+
</h-stack>
|
|
851
|
+
</h-stack>
|
|
852
|
+
</button>`, mount);
|
|
853
|
+
// const btn = $(
|
|
854
|
+
// `<button type="button" tabindex="0"><h-stack distribution="leading" template="auto spacer"><label-view data-role="check"><image-view slot="icon" system-name="check"></image-view></label-view></h-stack></button>`,
|
|
855
|
+
// '>1'
|
|
856
|
+
// ),
|
|
857
|
+
// hStack = btn.querySelector<HTMLElement>(':scope>h-stack')
|
|
858
|
+
// // chevron = hStack?.querySelector<HTMLElement>(':scope>label-view')
|
|
859
|
+
// btn.setAttribute('value', extractTagFromOption(node))
|
|
860
|
+
// // if (selection !== btn.getAttribute('value')) chevron?.style.setProperty('visibility', 'hidden')
|
|
861
|
+
// const label = $<LabelView>(`<label-view></label-view>`, '>1')
|
|
862
|
+
// renderLabelTitle(label, extractLabel(node)) // label.querySelector('span')!.textContent = extractCurrentValueFromOption(node) //label.setAttribute('title', extractCurrentValueFromOption(node))
|
|
863
|
+
// renderLabelIcon(label, extractIcon(node))
|
|
864
|
+
// hStack?.appendChild(label)
|
|
865
|
+
return mount.firstElementChild; //btn
|
|
866
|
+
}
|
|
867
|
+
static #wrapOptgroupTag(node) {
|
|
868
|
+
debug(`${_a.name} #wrapOptgroupTag`);
|
|
869
|
+
const title = extractLabel(node), subtitle = extractSubtitle(node), icon = extractIcon(node);
|
|
870
|
+
const mount = document.createElement('div');
|
|
871
|
+
render(html `<details is="disclosure-group" disclosure-style="marker-trailing">
|
|
872
|
+
<summary>
|
|
873
|
+
<h-stack distribution="leading" template="auto spacer">
|
|
874
|
+
<label-view data-role="check" style="visibility: hidden">
|
|
875
|
+
<image-view slot="icon" system-name="check"></image-view>
|
|
876
|
+
</label-view>
|
|
877
|
+
<h-stack distribution="fill" template="${icon ? 'auto spacer' : null}">
|
|
878
|
+
${icon ? html `<label-view system-image="${icon}"></label-view>` : null}
|
|
879
|
+
<v-stack spacing="3" alignment="fill">
|
|
880
|
+
<label-view title="${title}"></label-view>
|
|
881
|
+
${subtitle ? html `<label-view foreground="secondary" font="callout" title="${subtitle}"></label-view>` : null}
|
|
882
|
+
</v-stack>
|
|
883
|
+
</h-stack>
|
|
884
|
+
</h-stack>
|
|
885
|
+
</summary>
|
|
886
|
+
</details>`, mount);
|
|
887
|
+
return mount.firstElementChild;
|
|
888
|
+
// const labelT = `<label-view><span></span></label-view>`,
|
|
889
|
+
// summaryT = `<summary><h-stack distribution="leading" template="auto spacer"><label-view data-role="check" style="visibility: hidden"><image-view slot="icon" system-name="check"></image-view></label-view>${labelT}</h-stack></summary>`
|
|
890
|
+
// const group = $(`<details is="disclosure-group" disclosure-style="marker-trailing">${summaryT}</details>`, '>1'), // NOTE: already applied, here it covers spawned sheets
|
|
891
|
+
// hStack = group.querySelector(':scope>summary>h-stack') ?? undefined // ?? group.appendChild($(summaryT, '>1'))
|
|
892
|
+
// // summaryLabel = summary.querySelector(':scope>label-view') ?? summary.appendChild($(labelT, '>1'))
|
|
893
|
+
// // if (node.hasAttribute('label')) summaryLabel.setAttribute('title', node.getAttribute('label') ?? '')
|
|
894
|
+
// // if (node.hasAttribute('data-system-image')) summaryLabel.setAttribute('system-image', node.getAttribute('data-system-image') ?? '')
|
|
895
|
+
// renderLabel(':scope>label-view:nth-child(2)', labelT, hStack, extractLabel(node), extractIcon(node))
|
|
896
|
+
// return group
|
|
897
|
+
}
|
|
898
|
+
// static #reflectButtons(nodes: Element[], container: Element): void
|
|
899
|
+
// static #reflectButtons(nodes: Dictionary, container: Element): void
|
|
900
|
+
static #reflectButtons(nodes, container) {
|
|
901
|
+
debug(`${_a.name} #reflectButtons`);
|
|
902
|
+
for (const node of nodes)
|
|
903
|
+
if (node instanceof Element)
|
|
904
|
+
switch (node.tagName) {
|
|
905
|
+
case 'DATALIST': {
|
|
906
|
+
const title = extractLabel(node), subtitle = extractSubtitle(node), icon = extractIcon(node);
|
|
907
|
+
const mount = document.createElement('div');
|
|
908
|
+
render(html `<menu-view tabindex="0">
|
|
909
|
+
<h-stack slot="label" distribution="leading" template="auto spacer">
|
|
910
|
+
<label-view data-role="check" style="visibility: hidden">
|
|
911
|
+
<image-view slot="icon" system-name="check"></image-view>
|
|
912
|
+
</label-view>
|
|
913
|
+
<h-stack distribution="fill" template="${icon ? 'auto spacer' : null}">
|
|
914
|
+
${icon ? html `<label-view system-image="${icon}"></label-view>` : null}
|
|
915
|
+
<v-stack spacing="3" alignment="fill">
|
|
916
|
+
<label-view title="${title}"></label-view>
|
|
917
|
+
${subtitle ? html `<label-view foreground="secondary" font="callout" title="${subtitle}"></label-view>` : null}
|
|
918
|
+
</v-stack>
|
|
919
|
+
</h-stack>
|
|
920
|
+
</h-stack>
|
|
921
|
+
</menu-view>`, mount);
|
|
922
|
+
const group = mount.firstElementChild;
|
|
923
|
+
// const group = $(
|
|
924
|
+
// `<menu-view tabindex="0"><h-stack slot="label" distribution="leading" template="auto spacer"><label-view data-role="check" style="visibility: hidden"><image-view slot="icon" system-name="check"></image-view></label-view><label-view><span></span></label-view></h-stack></menu-view>`,
|
|
925
|
+
// '>1'
|
|
926
|
+
// ),
|
|
927
|
+
// hStack = group.querySelector(':scope>h-stack[slot=label]') ?? undefined
|
|
928
|
+
// // label = group.querySelector(':scope>label-view[slot=label]') ?? group.appendChild($(`<label-view slot="label"></label-view>`, '>1'))
|
|
929
|
+
// // if (node.hasAttribute('data-label')) label.setAttribute('title', node.getAttribute('data-label') ?? '')
|
|
930
|
+
// // if (node.hasAttribute('data-system-image')) label.setAttribute('system-image', node.getAttribute('data-system-image') ?? '')
|
|
931
|
+
// renderLabel(':scope>label-view:nth-child(2)', `<label-view><span></span></label-view>`, hStack, extractLabel(node as HTMLDataListElement), extractIcon(node as HTMLDataListElement))
|
|
932
|
+
_a.#reflectButtons([...node.children], group);
|
|
933
|
+
container.appendChild(group);
|
|
934
|
+
break;
|
|
935
|
+
}
|
|
936
|
+
case 'OPTGROUP': {
|
|
937
|
+
const group = _a.#wrapOptgroupTag(node);
|
|
938
|
+
_a.#reflectButtons([...node.children], group);
|
|
939
|
+
container.appendChild(group);
|
|
940
|
+
break;
|
|
941
|
+
}
|
|
942
|
+
case 'OPTION':
|
|
943
|
+
default: {
|
|
944
|
+
container.appendChild(_a.#wrapOptionTag(node));
|
|
945
|
+
break;
|
|
946
|
+
}
|
|
318
947
|
}
|
|
948
|
+
else {
|
|
949
|
+
if (node.children.length)
|
|
950
|
+
if (allLeaves(node)) {
|
|
951
|
+
const group = _a.#wrapOptgroupTag(node);
|
|
952
|
+
_a.#reflectButtons(node.children, group);
|
|
953
|
+
container.appendChild(group);
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
const title = extractLabel(node), subtitle = extractSubtitle(node), icon = extractIcon(node);
|
|
957
|
+
const mount = document.createElement('div');
|
|
958
|
+
render(html `<menu-view tabindex="0">
|
|
959
|
+
<h-stack slot="label" distribution="leading" template="auto spacer">
|
|
960
|
+
<label-view data-role="check" style="visibility: hidden">
|
|
961
|
+
<image-view slot="icon" system-name="check"></image-view>
|
|
962
|
+
</label-view>
|
|
963
|
+
<h-stack distribution="fill" template="${icon ? 'auto spacer' : null}">
|
|
964
|
+
${icon ? html `<label-view system-image="${icon}"></label-view>` : null}
|
|
965
|
+
<v-stack spacing="3" alignment="fill">
|
|
966
|
+
<label-view title="${title}"></label-view>
|
|
967
|
+
${subtitle ? html `<label-view foreground="secondary" font="callout" title="${subtitle}"></label-view>` : null}
|
|
968
|
+
</v-stack>
|
|
969
|
+
</h-stack>
|
|
970
|
+
</h-stack>
|
|
971
|
+
</menu-view>`, mount);
|
|
972
|
+
const group = mount.firstElementChild;
|
|
973
|
+
// const group = $(`<menu-view tabindex="0"></menu-view>`, '>1')
|
|
974
|
+
// renderLabel(':scope>label-view[slot=label]', `<label-view slot="label"><span></span></label-view>`, group, extractLabel(node), extractIcon(node))
|
|
975
|
+
_a.#reflectButtons(node.children, group);
|
|
976
|
+
container.appendChild(group);
|
|
977
|
+
}
|
|
319
978
|
else
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
section.insertAdjacentElement('beforeend', _a.wrapTag(el, sourceSlot?.name));
|
|
323
|
-
// let possibleLv = this.#slot?.assignedElements({ flatten: true })[0]
|
|
324
|
-
// if ('LIST-VIEW' !== possibleLv?.tagName) possibleLv = this.appendChild(document.createElement('list-view'))
|
|
325
|
-
// const sv = document.createElement('section-view')
|
|
326
|
-
// sv.setAttribute('header', 'section-header')
|
|
327
|
-
// possibleLv.appendChild(sv)
|
|
328
|
-
// for (const el of PickerView.sourceNodes(sourceSlot) ?? []) sv.insertAdjacentElement('beforeend', PickerView.wrapTag(el, sourceSlot?.name))
|
|
329
|
-
// for (const el of this.querySelectorAll(':scope>:not([slot])')) el.remove()
|
|
330
|
-
// for (const el of PickerView.sourceNodes(sourceSlot) ?? []) {
|
|
331
|
-
// const btn = document.createElement('button')
|
|
332
|
-
// btn.type = 'button'
|
|
333
|
-
// btn.tabIndex = 0
|
|
334
|
-
// btn.appendChild(PickerView.wrapTag(el, sourceSlot?.name))
|
|
335
|
-
// this.insertAdjacentElement('beforeend', btn)
|
|
336
|
-
// }
|
|
337
|
-
break;
|
|
338
|
-
}
|
|
339
|
-
};
|
|
340
|
-
#reflectPlaceholder(value) {
|
|
341
|
-
const input = this.#shadowRoot.querySelector('input');
|
|
342
|
-
if (input) {
|
|
343
|
-
if (value)
|
|
344
|
-
input.setAttribute('placeholder', value);
|
|
345
|
-
else
|
|
346
|
-
input.removeAttribute('placeholder');
|
|
347
|
-
}
|
|
979
|
+
container.appendChild(_a.#wrapOptionTag(node));
|
|
980
|
+
}
|
|
348
981
|
}
|
|
982
|
+
// #reflectPlaceholder(value: string | null) {
|
|
983
|
+
// debug(`#reflectPlaceholder`)
|
|
984
|
+
// const input = this.#shadowRoot.querySelector('input')
|
|
985
|
+
// if (input) {
|
|
986
|
+
// if (value) input.setAttribute((this.constructor as typeof PickerView).ATTR.PLACEHOLDER, value)
|
|
987
|
+
// else input.removeAttribute((this.constructor as typeof PickerView).ATTR.PLACEHOLDER)
|
|
988
|
+
// }
|
|
989
|
+
// }
|
|
349
990
|
#reflectLabel(value) {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
991
|
+
debug(`${_a.name} #reflectLabel`);
|
|
992
|
+
queryMorph('[slot=label]', html `<label-view slot="label">${value ? html `<span>${value}</span>` : null}</label-view>`, this);
|
|
993
|
+
this.#renderSlotted([]);
|
|
994
|
+
}
|
|
995
|
+
#reflectSelectionOnButtons() {
|
|
996
|
+
debug(`${_a.name} #reflectSelectionOnButtons`);
|
|
997
|
+
self.requestAnimationFrame(() => {
|
|
998
|
+
this.ariaCurrent = this.#selection;
|
|
999
|
+
const groupMap = indexGroups(this.#lastIndexedRoot);
|
|
1000
|
+
const groupContainsSelection = (source) => source instanceof Element ? [...source.querySelectorAll('option')].some((opt) => extractTag(opt) === this.#selection) : collectLeafValues(source).includes(this.#selection);
|
|
1001
|
+
const syncButtons = (root) => {
|
|
1002
|
+
// 1. plain value buttons — unchanged
|
|
1003
|
+
for (const el of root.querySelectorAll('button[value]:not([slot])'))
|
|
1004
|
+
// $.prop('visibility', el.getAttribute('value') === this.#selection ? 'visible' : 'hidden', el.querySelector<HTMLElement>('label-view[data-role="check"]'))
|
|
1005
|
+
el.querySelector('label-view[data-role="check"]')?.style.setProperty('visibility', el.getAttribute('value') === this.#selection ? 'visible' : 'hidden');
|
|
1006
|
+
// 2. details/optgroups — unchanged
|
|
1007
|
+
for (const details of root.querySelectorAll('details[is="disclosure-group"]')) {
|
|
1008
|
+
const hasSelectedDescendant = [...details.querySelectorAll('button[value]')].some((btn) => btn.getAttribute('value') === this.#selection);
|
|
1009
|
+
details.querySelector(':scope>summary label-view[data-role="check"]')?.style.setProperty('visibility', hasSelectedDescendant ? 'visible' : 'hidden');
|
|
1010
|
+
}
|
|
1011
|
+
// 3. nav-link buttons — resolved by groupId, same map used for resync
|
|
1012
|
+
for (const btn of root.querySelectorAll('button[navigation-link]:not([value])')) {
|
|
1013
|
+
const source = btn.dataset.groupId ? groupMap.get(btn.dataset.groupId) : undefined;
|
|
1014
|
+
const hasSelectedDescendant = source ? groupContainsSelection(source) : false;
|
|
1015
|
+
btn.querySelector('label-view[data-role="check"]')?.style.setProperty('visibility', hasSelectedDescendant ? 'visible' : 'hidden');
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
1018
|
+
syncButtons(this);
|
|
1019
|
+
if (this.#spawn)
|
|
1020
|
+
syncButtons(this.#spawn);
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Overwrite cvlabel with the label prop of the current(find[value === #selection]) option/dictentry
|
|
1025
|
+
*/
|
|
1026
|
+
#reflectSelectionOnCurrentValueLabel() {
|
|
1027
|
+
debug(`${_a.name} #reflectSelectionOnCurrentValueLabel`);
|
|
1028
|
+
self.requestAnimationFrame(() => {
|
|
1029
|
+
switch (this.pickerStyle) {
|
|
1030
|
+
case 'sheet':
|
|
1031
|
+
case 'navigation-link': {
|
|
1032
|
+
const currentValueLabel = this.querySelector(':scope>label-view:not([slot])');
|
|
1033
|
+
if (!currentValueLabel)
|
|
1034
|
+
break;
|
|
1035
|
+
// if (!cvl) currentValueLabel.setAttribute('foreground', 'secondary')
|
|
1036
|
+
// else currentValueLabel.removeAttribute('foreground')
|
|
1037
|
+
const title = this.#currentValueLabel || this.#selection || this.getAttribute(this.constructor.ATTR.PLACEHOLDER), systemImage = this.#currentValueIcon || this.getAttribute(this.constructor.ATTR.PLACEHOLDER_ICON);
|
|
1038
|
+
queryMorph(':not([slot])', html `<span>${title}</span>`, currentValueLabel, { removeIf: !title });
|
|
1039
|
+
queryMorph('[slot=icon]', html `<image-view slot="icon" system-name="${systemImage}"></image-view>`, currentValueLabel, { removeIf: !systemImage });
|
|
1040
|
+
// morph(
|
|
1041
|
+
// htmx`<label-view>${systemImage ? htmx`<image-view slot="icon" system-name="${systemImage}"></image-view>` : null}${title ? htmx`<span>${title}</span>` : null}</label-view>`,
|
|
1042
|
+
// currentValueLabel
|
|
1043
|
+
// ) NOTE: not this bc/ help tooltip right now is added to trigger label and this mangles it
|
|
1044
|
+
break;
|
|
1045
|
+
}
|
|
1046
|
+
case 'menu': {
|
|
1047
|
+
const currentValueLabel = this.querySelector(':scope>menu-view:not([slot])>label-view[slot=label]');
|
|
1048
|
+
if (!currentValueLabel)
|
|
1049
|
+
break;
|
|
1050
|
+
// if (!cvl) currentValueLabel.setAttribute('foreground', 'secondary')
|
|
1051
|
+
// else currentValueLabel.removeAttribute('foreground')
|
|
1052
|
+
const title = this.#currentValueLabel || this.#selection || this.getAttribute(this.constructor.ATTR.PLACEHOLDER), systemImage = this.#currentValueIcon || this.getAttribute(this.constructor.ATTR.PLACEHOLDER_ICON);
|
|
1053
|
+
queryMorph(':not([slot])', html `<span>${title}</span>`, currentValueLabel, { removeIf: !title });
|
|
1054
|
+
queryMorph('[slot=icon]', html `<image-view slot="icon" system-name="${systemImage}"></image-view>`, currentValueLabel, { removeIf: !systemImage });
|
|
1055
|
+
// morph(
|
|
1056
|
+
// htmx`<label-view slot="label">${systemImage ? htmx`<image-view slot="icon" system-name="${systemImage}"></image-view>` : null}${title ? htmx`<span>${title}</span>` : null}</label-view>`,
|
|
1057
|
+
// currentValueLabel
|
|
1058
|
+
// ) NOTE: not this bc/ help tooltip right now is added to trigger label and this mangles it
|
|
1059
|
+
break;
|
|
1060
|
+
}
|
|
1061
|
+
case 'inline':
|
|
1062
|
+
default: {
|
|
1063
|
+
//
|
|
1064
|
+
break;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
#reflectTriggerHelp() {
|
|
1070
|
+
debug(`${_a.name} #reflectTriggerHelp`);
|
|
1071
|
+
let trigger;
|
|
1072
|
+
switch (this.pickerStyle) {
|
|
1073
|
+
case 'sheet':
|
|
1074
|
+
case 'navigation-link': {
|
|
1075
|
+
trigger = this.querySelector(':scope>label-view:not([slot])') ?? undefined;
|
|
1076
|
+
}
|
|
1077
|
+
case 'menu': {
|
|
1078
|
+
trigger = this.querySelector(':scope>menu-view:not([slot])>label-view[slot=label]') ?? undefined;
|
|
1079
|
+
}
|
|
1080
|
+
case 'inline':
|
|
1081
|
+
default: {
|
|
1082
|
+
//udnefined
|
|
1083
|
+
}
|
|
365
1084
|
}
|
|
1085
|
+
if (this.hasAttribute(this.constructor.ATTR.TRIGGER_HELP))
|
|
1086
|
+
trigger?.setAttribute(this.constructor.ATTR.TRIGGER_HELP, this.getAttribute(this.constructor.ATTR.TRIGGER_HELP) ?? '');
|
|
366
1087
|
else
|
|
367
|
-
|
|
368
|
-
this.#handleTagMutation();
|
|
369
|
-
// const el =
|
|
370
|
-
// (this.#labelSlot?.assignedElements({ flatten: true })[0] as HTMLElement) ??
|
|
371
|
-
// (() => {
|
|
372
|
-
// const el = document.createElement('span')
|
|
373
|
-
// el.slot = 'label'
|
|
374
|
-
// return this.appendChild(el)
|
|
375
|
-
// })()
|
|
376
|
-
// el.textContent = value ?? '' // el.replaceChildren(escapeHTMLPolicy.createHTML(newValue))
|
|
377
|
-
// break
|
|
378
|
-
// }
|
|
379
|
-
// const assigned = this.#labelSlot?.assignedElements({ flatten: true }) as HTMLElement[] | undefined
|
|
380
|
-
// let el = assigned?.[0]
|
|
381
|
-
// if (!el) {
|
|
382
|
-
// el = document.createElement('span')
|
|
383
|
-
// el.slot = 'label'
|
|
384
|
-
// this.append(el)
|
|
385
|
-
// }
|
|
386
|
-
// el.textContent = value ?? ''
|
|
1088
|
+
trigger?.removeAttribute(this.constructor.ATTR.TRIGGER_HELP);
|
|
387
1089
|
}
|
|
388
|
-
|
|
1090
|
+
/**
|
|
1091
|
+
* Form participation property
|
|
1092
|
+
*/
|
|
389
1093
|
get name() {
|
|
390
1094
|
return this.getAttribute('name') ?? this.getAttribute('label') ?? this.querySelector(':scope>[slot=label]')?.textContent ?? '';
|
|
391
1095
|
}
|
|
@@ -396,16 +1100,16 @@ export class PickerView extends FormAssociatedBase {
|
|
|
396
1100
|
const key = k; // ✅ type-safe cast
|
|
397
1101
|
if (true !== flags[key])
|
|
398
1102
|
continue;
|
|
399
|
-
for (const el of this.#
|
|
1103
|
+
for (const el of this.#slots?.get('validity-options')?.assignedElements({ flatten: true }) ?? []) {
|
|
400
1104
|
if (!el.matches('option'))
|
|
401
1105
|
continue;
|
|
402
|
-
const
|
|
403
|
-
if (`${kebabCase(key)}` ===
|
|
404
|
-
message =
|
|
1106
|
+
const { label, value } = el;
|
|
1107
|
+
if (`${kebabCase(key)}` === value) {
|
|
1108
|
+
message = label;
|
|
405
1109
|
break;
|
|
406
1110
|
}
|
|
407
|
-
else if (`${kebabCase(key)}:${message}` ===
|
|
408
|
-
message =
|
|
1111
|
+
else if (`${kebabCase(key)}:${message}` === value) {
|
|
1112
|
+
message = label;
|
|
409
1113
|
break;
|
|
410
1114
|
}
|
|
411
1115
|
}
|
|
@@ -418,7 +1122,7 @@ export class PickerView extends FormAssociatedBase {
|
|
|
418
1122
|
message = kebabCase(key);
|
|
419
1123
|
break;
|
|
420
1124
|
}
|
|
421
|
-
|
|
1125
|
+
debug(`${_a.name} ⚡️ validity-change`);
|
|
422
1126
|
return this.#internals.setValidity(flags, this.#customValidity || message, anchor);
|
|
423
1127
|
};
|
|
424
1128
|
setCustomValidity = (message) => {
|
|
@@ -428,15 +1132,21 @@ export class PickerView extends FormAssociatedBase {
|
|
|
428
1132
|
else
|
|
429
1133
|
this.#sendValueToForm(false);
|
|
430
1134
|
};
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
}
|
|
434
|
-
|
|
1135
|
+
formStateRestoreCallback(state, reason) {
|
|
1136
|
+
//
|
|
1137
|
+
}
|
|
1138
|
+
formAssociatedCallback(form) {
|
|
1139
|
+
this.#sendValueToForm(false);
|
|
1140
|
+
}
|
|
1141
|
+
formDisabledCallback(disabled) {
|
|
435
1142
|
for (const btn of this.#shadowRoot.querySelectorAll('button'))
|
|
436
1143
|
btn.toggleAttribute('disabled', !disabled);
|
|
437
|
-
}
|
|
438
|
-
formResetCallback
|
|
1144
|
+
}
|
|
1145
|
+
formResetCallback() {
|
|
439
1146
|
this.#selection = '';
|
|
440
|
-
|
|
1147
|
+
this.#reflectSelectionOnButtons();
|
|
1148
|
+
this.#reflectSelectionOnCurrentValueLabel();
|
|
1149
|
+
this.#sendValueToForm(false);
|
|
1150
|
+
}
|
|
441
1151
|
}
|
|
442
1152
|
_a = PickerView;
|