@swiftwc/ui 0.0.0-dev.37 → 0.0.0-dev.39
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/generated/client/index.js +5 -3
- package/generated/components/alert-dialog.js +17 -9
- package/generated/components/body-view.js +5 -3
- package/generated/components/bordered-button.js +7 -4
- package/generated/components/bordered-prominent-button.js +7 -4
- package/generated/components/borderless-button.js +7 -4
- package/generated/components/confirmation-dialog.js +17 -9
- package/generated/components/content-unavailable-view.js +7 -4
- package/generated/components/date-picker.js +34 -23
- package/generated/components/disclosure-group.js +9 -5
- package/generated/components/fine-tooltip.js +7 -4
- package/generated/components/form-view.js +5 -3
- package/generated/components/glass-button.js +7 -4
- package/generated/components/glass-prominent-button.js +7 -4
- package/generated/components/label-view.js +7 -4
- package/generated/components/list-view.js +5 -3
- package/generated/components/menu-view.js +19 -10
- package/generated/components/navigation-large-title.js +9 -5
- package/generated/components/navigation-split-view.js +7 -4
- package/generated/components/navigation-stack.js +7 -4
- package/generated/components/navigation-title.js +7 -4
- package/generated/components/picker-view.d.ts +1 -0
- package/generated/components/picker-view.js +185 -83
- package/generated/components/plain-button.js +5 -3
- package/generated/components/progress-view.js +11 -8
- package/generated/components/screen-view.js +3 -2
- package/generated/components/scroll-view-proxy.js +5 -3
- package/generated/components/scroll-view.js +17 -9
- package/generated/components/search-view.js +7 -4
- package/generated/components/section-view.js +7 -5
- package/generated/components/sheet-view.js +11 -6
- package/generated/components/sidebar-toggle.js +9 -5
- package/generated/components/sidebar-view.js +3 -2
- package/generated/components/sticky-container.js +5 -3
- package/generated/components/tab-bar.js +7 -4
- package/generated/components/tab-item.js +15 -8
- package/generated/components/tab-view.js +14 -8
- package/generated/components/table-view.js +13 -8
- package/generated/components/text-field.js +27 -17
- package/generated/components/tool-bar-item-group.js +5 -3
- package/generated/components/tool-bar-item.js +7 -4
- package/generated/components/tool-bar.js +7 -4
- package/generated/components/v-keyboard.js +9 -5
- package/generated/components/v-stack.js +5 -3
- package/generated/css/index.css +6 -2
- package/generated/events/picker-view.d.ts +1 -0
- package/generated/internal/class/css-style-observer.js +3 -2
- package/generated/internal/class/form-associated-base.js +7 -5
- package/generated/internal/class/navigation-view.js +5 -3
- package/generated/internal/decorators/adaptive-slot.js +7 -4
- package/generated/internal/privateNamespace.js +22 -13
- package/generated/internal/utils/dev-flags.d.ts +3 -0
- package/generated/internal/utils/dev-flags.js +5 -0
- package/generated/internal/utils/index.d.ts +1 -1
- package/generated/internal/utils/index.js +1 -1
- package/generated/snapshot/index.js +5 -3
- package/package.json +1 -1
- package/scss/base/_layout.scss +6 -7
- package/generated/internal/utils/debug.d.ts +0 -1
- package/generated/internal/utils/debug.js +0 -3
|
@@ -5,7 +5,7 @@ import { FormAssociatedBase, getInternals } from '../internal/class/form-associa
|
|
|
5
5
|
import { MutationObserverSet } from '../internal/class/mutation-observer-set';
|
|
6
6
|
import { NavigationPath } from '../internal/class/navigation-path';
|
|
7
7
|
import { queryInsertPosition, startViewTransition } from '../internal/privateNamespace';
|
|
8
|
-
import { $,
|
|
8
|
+
import { $, devFlags, kebabCase, onoff } from '../internal/utils';
|
|
9
9
|
const pickerStyles = ['menu', 'inline', 'navigation-link', 'sheet', 'automatic'];
|
|
10
10
|
const update = (path, node, overwrite = true) => {
|
|
11
11
|
if (!(path instanceof NavigationPath))
|
|
@@ -18,23 +18,32 @@ const update = (path, node, overwrite = true) => {
|
|
|
18
18
|
if (page)
|
|
19
19
|
page.insertAdjacentElement(position, node);
|
|
20
20
|
};
|
|
21
|
-
const
|
|
22
|
-
const { page:
|
|
23
|
-
const
|
|
24
|
-
// pre replace
|
|
25
|
-
const oldOpenedDetails = [...(
|
|
26
|
-
// replace
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
oldBackBtn.replaceWith(newBackBtn);
|
|
31
|
-
// post replace
|
|
21
|
+
const reflectSpawnedElement = (current, source) => {
|
|
22
|
+
const { page: oldSv, toolBarConfig: oldToolbar } = new NavigationPath(current).hydrate(), { page: newSv, toolBarConfig: newToolbar } = new NavigationPath(source).hydrate();
|
|
23
|
+
const oldVStack = oldSv?.querySelector(':scope>v-stack'), newVStack = newSv?.querySelector(':scope>v-stack'), oldBackBtn = oldToolbar?.at(0)?.querySelector('button'), newBackBtn = newToolbar?.at(0)?.querySelector('button');
|
|
24
|
+
// pre replace list (always exist)
|
|
25
|
+
const oldOpenedDetails = [...(oldVStack?.querySelectorAll('list-view details[open]>summary') ?? [])].map((item) => item.textContent.trim());
|
|
26
|
+
// replace list (always exist)
|
|
27
|
+
if (oldVStack && newVStack)
|
|
28
|
+
oldVStack.replaceWith(newVStack);
|
|
29
|
+
// post replace list (always exist)
|
|
32
30
|
for (const label of oldOpenedDetails)
|
|
33
|
-
for (const summary of
|
|
31
|
+
for (const summary of newVStack?.querySelectorAll('list-view details>summary') ?? [])
|
|
34
32
|
if (summary.textContent.trim() === label) {
|
|
35
33
|
summary.parentElement?.setAttribute('open', 'open');
|
|
36
34
|
break;
|
|
37
35
|
}
|
|
36
|
+
// replace backbtns (always exist)
|
|
37
|
+
if (oldBackBtn && newBackBtn)
|
|
38
|
+
oldBackBtn.replaceWith(newBackBtn);
|
|
39
|
+
// overwrite navtitle (always exist)
|
|
40
|
+
oldSv?.setAttribute('navigation-inline-title', newSv?.getAttribute('navigation-inline-title') ?? '');
|
|
41
|
+
};
|
|
42
|
+
const extractTagFromOption = (node) => {
|
|
43
|
+
return ((node.getAttribute('value') ?? node.textContent?.trim()) || node.getAttribute('label')) ?? '';
|
|
44
|
+
};
|
|
45
|
+
const extractCurrentValueFromOption = (node) => {
|
|
46
|
+
return (node.getAttribute('label') ?? node.getAttribute('value') ?? node.textContent?.trim()) || '';
|
|
38
47
|
};
|
|
39
48
|
export class PickerView extends FormAssociatedBase {
|
|
40
49
|
static get ATTR() {
|
|
@@ -44,6 +53,7 @@ export class PickerView extends FormAssociatedBase {
|
|
|
44
53
|
PICKER_STYLE: 'picker-style',
|
|
45
54
|
SELECTION: 'selection',
|
|
46
55
|
SEARCHABLE: 'searchable',
|
|
56
|
+
CURRENT_VALUE_LABEL: 'current-value-label',
|
|
47
57
|
};
|
|
48
58
|
}
|
|
49
59
|
static get observedAttributes() {
|
|
@@ -51,7 +61,7 @@ export class PickerView extends FormAssociatedBase {
|
|
|
51
61
|
}
|
|
52
62
|
static #templates = new Map();
|
|
53
63
|
#spawn;
|
|
54
|
-
#
|
|
64
|
+
#spawnPage = (tag, searchable = false, title, node) => {
|
|
55
65
|
const body = $(`<${'sheet-view' === tag ? 'dialog is="sheet-view"' : 'body-view'}><scroll-view><v-stack placement="leading fill"><list-view preferred-expanded-style="inset"></list-view></v-stack></scroll-view><tool-bar><tool-bar-item slot="top-bar-leading"><button type="button" tabindex="0"><label-view system-image="caret-left"></label-view></button></tool-bar-item></tool-bar></${'sheet-view' === tag ? 'dialog' : 'body-view'}>`, '>1'), sv = body.querySelector('scroll-view'), list = body.querySelector('list-view'), backBtn = body.querySelector('button');
|
|
56
66
|
if (title)
|
|
57
67
|
sv?.setAttribute('navigation-inline-title', title);
|
|
@@ -63,18 +73,30 @@ export class PickerView extends FormAssociatedBase {
|
|
|
63
73
|
<button type="button">Filters</button>
|
|
64
74
|
</v-stack>
|
|
65
75
|
</sticky-container>`);
|
|
66
|
-
const searchInput = sv?.querySelector('input
|
|
76
|
+
const searchInput = sv?.querySelector('input'); // FIXME: compoennt is=search-view??
|
|
67
77
|
searchInput?.addEventListener('focus', (evt) => {
|
|
68
78
|
if (this.#spawn)
|
|
69
|
-
this.dispatchEvent(new CustomEvent('picker:searchfocus', {
|
|
79
|
+
this.dispatchEvent(new CustomEvent('picker:searchfocus', {
|
|
80
|
+
detail: { element: this.#spawn, search: evt.target instanceof HTMLInputElement && evt.target ? evt.target.value : '' },
|
|
81
|
+
bubbles: true,
|
|
82
|
+
composed: true,
|
|
83
|
+
}));
|
|
70
84
|
});
|
|
71
85
|
searchInput?.addEventListener('blur', (evt) => {
|
|
72
86
|
if (this.#spawn)
|
|
73
|
-
this.dispatchEvent(new CustomEvent('picker:searchblur', {
|
|
87
|
+
this.dispatchEvent(new CustomEvent('picker:searchblur', {
|
|
88
|
+
detail: { element: this.#spawn, search: evt.target instanceof HTMLInputElement && evt.target ? evt.target.value : '' },
|
|
89
|
+
bubbles: true,
|
|
90
|
+
composed: true,
|
|
91
|
+
}));
|
|
74
92
|
});
|
|
75
93
|
searchInput?.addEventListener('input', (evt) => {
|
|
76
94
|
if (this.#spawn)
|
|
77
|
-
this.dispatchEvent(new CustomEvent('picker:searchinput', {
|
|
95
|
+
this.dispatchEvent(new CustomEvent('picker:searchinput', {
|
|
96
|
+
detail: { element: this.#spawn, search: evt.target instanceof HTMLInputElement && evt.target ? evt.target.value : '' },
|
|
97
|
+
bubbles: true,
|
|
98
|
+
composed: true,
|
|
99
|
+
}));
|
|
78
100
|
});
|
|
79
101
|
}
|
|
80
102
|
backBtn?.setAttribute('help', I18n.t('ButtonRole').Back);
|
|
@@ -98,13 +120,13 @@ export class PickerView extends FormAssociatedBase {
|
|
|
98
120
|
const details = _a.#wrapOptgroupTag(el);
|
|
99
121
|
_a.#reflectButtons([...el.children], details);
|
|
100
122
|
for (const btn of details.querySelectorAll(':scope>button'))
|
|
101
|
-
btn.addEventListener('click', this.#
|
|
123
|
+
btn.addEventListener('click', this.#handlePageBtnClick);
|
|
102
124
|
list?.appendChild(details);
|
|
103
125
|
break;
|
|
104
126
|
}
|
|
105
127
|
case 'OPTION': {
|
|
106
128
|
const btn = _a.#wrapOptionTag(el);
|
|
107
|
-
btn.addEventListener('click', this.#
|
|
129
|
+
btn.addEventListener('click', this.#handlePageBtnClick);
|
|
108
130
|
list?.appendChild(btn);
|
|
109
131
|
break;
|
|
110
132
|
}
|
|
@@ -118,12 +140,13 @@ export class PickerView extends FormAssociatedBase {
|
|
|
118
140
|
const { target } = evt;
|
|
119
141
|
if (!(target instanceof HTMLElement && target))
|
|
120
142
|
return;
|
|
121
|
-
const newPage = this.#
|
|
143
|
+
const newPage = this.#spawnPage('body-view', this.hasAttribute('searchable'), el.dataset.label, el);
|
|
122
144
|
if (!newPage)
|
|
123
145
|
return;
|
|
124
146
|
const path = new NavigationPath(target)?.hydrate();
|
|
125
147
|
await startViewTransition(target, 'forwards', async () => {
|
|
126
148
|
update(path, newPage);
|
|
149
|
+
this.#reflectSelectionOnButtons();
|
|
127
150
|
});
|
|
128
151
|
});
|
|
129
152
|
list?.appendChild(btn);
|
|
@@ -133,22 +156,28 @@ export class PickerView extends FormAssociatedBase {
|
|
|
133
156
|
}
|
|
134
157
|
return body;
|
|
135
158
|
};
|
|
136
|
-
#
|
|
137
|
-
|
|
159
|
+
#renderSlotted = (entries) => {
|
|
160
|
+
if (devFlags.debug)
|
|
161
|
+
console.debug(`${_a.name} ⚡️ mutation`);
|
|
138
162
|
switch (this.pickerStyle) {
|
|
139
163
|
case 'sheet':
|
|
140
164
|
case 'navigation-link': {
|
|
141
|
-
// label
|
|
142
|
-
const
|
|
143
|
-
|
|
165
|
+
// current value label only
|
|
166
|
+
const currentValueLabel = this.querySelector(':scope>label-view:not([slot])') ?? this.appendChild($(`<label-view></label-view>`, '>1'));
|
|
167
|
+
// reset state
|
|
168
|
+
currentValueLabel.setAttribute('system-image', 'dots-three'); // overwritten
|
|
169
|
+
currentValueLabel.setAttribute('title', this.#selection); // overwritten
|
|
170
|
+
// clear all siblings
|
|
171
|
+
for (const el of this.querySelectorAll(':scope>:not([slot])'))
|
|
172
|
+
if (currentValueLabel !== el)
|
|
173
|
+
el.remove();
|
|
144
174
|
CleanupRegistry.unregister(this, 'trigger');
|
|
145
|
-
CleanupRegistry.register(this, onoff('click', this.#handleTriggerClick,
|
|
146
|
-
this.appendChild(label);
|
|
175
|
+
CleanupRegistry.register(this, onoff('click', this.#handleTriggerClick, currentValueLabel).on(), 'trigger');
|
|
147
176
|
// rebuild snapshot(tree)
|
|
148
177
|
if (!this.#spawn)
|
|
149
178
|
break;
|
|
150
179
|
// rerender level 0
|
|
151
|
-
|
|
180
|
+
reflectSpawnedElement(this.#spawn, this.#spawnPage('body-view', this.hasAttribute('searchable'), this.getAttribute('label')));
|
|
152
181
|
for (const el of this.#spawn.querySelectorAll('body-view')) {
|
|
153
182
|
const depth = $.ancestors('body-view,[is=sheet-view]', el).indexOf(this.#spawn);
|
|
154
183
|
if (0 >= depth)
|
|
@@ -158,43 +187,58 @@ export class PickerView extends FormAssociatedBase {
|
|
|
158
187
|
el.remove();
|
|
159
188
|
break;
|
|
160
189
|
}
|
|
161
|
-
|
|
190
|
+
reflectSpawnedElement(el, this.#spawnPage('body-view', this.hasAttribute('searchable'), datalist.dataset.label, datalist));
|
|
162
191
|
}
|
|
163
192
|
break;
|
|
164
193
|
}
|
|
165
194
|
case 'menu': {
|
|
166
|
-
const menu = this.querySelector(':scope>menu-view:not([slot])') ?? this.appendChild($(`<menu-view
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
195
|
+
const menu = this.querySelector(':scope>menu-view:not([slot])') ?? this.appendChild($(`<menu-view></menu-view>`, '>1'));
|
|
196
|
+
// reset state
|
|
197
|
+
menu.innerHTML = '';
|
|
198
|
+
menu.tabIndex = 0;
|
|
199
|
+
// clear all siblings
|
|
200
|
+
for (const el of this.querySelectorAll(':scope>:not([slot])'))
|
|
201
|
+
if (menu !== el)
|
|
202
|
+
el.remove();
|
|
203
|
+
const currentValueLabel = menu.querySelector(':scope>label-view[slot=label]') ?? menu.appendChild($(`<label-view slot="label"></label-view>`, '>1'));
|
|
204
|
+
currentValueLabel.setAttribute('system-image', 'dots-three'); // overwritten
|
|
205
|
+
currentValueLabel.setAttribute('title', this.#selection); // overwritten
|
|
170
206
|
_a.#reflectButtons([...(this.#slots?.get('list')?.assignedElements() ?? [])], menu);
|
|
171
207
|
break;
|
|
172
208
|
}
|
|
173
209
|
case 'inline':
|
|
174
210
|
default: {
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
211
|
+
const sectionTpl = `<section-view></section-view>`;
|
|
212
|
+
const inlineList = this.querySelector(':scope>list-view:not([slot])') ?? this.appendChild($(`<list-view>${sectionTpl}</list-view>`, '>1')), section = inlineList.querySelector(':scope>section-view') ?? inlineList.appendChild($(sectionTpl, '>1'));
|
|
213
|
+
// reset state
|
|
214
|
+
section.innerHTML = '';
|
|
215
|
+
// clear all siblings
|
|
216
|
+
for (const el of this.querySelectorAll(':scope>:not([slot])'))
|
|
217
|
+
if (inlineList !== el)
|
|
218
|
+
el.remove();
|
|
219
|
+
const value = this.getAttribute(this.constructor.ATTR.LABEL);
|
|
220
|
+
if (value) {
|
|
221
|
+
const label = $(`<label-view></label-view>`, '>1');
|
|
222
|
+
label.setAttribute('title', value);
|
|
223
|
+
section.insertAdjacentElement('beforeend', label);
|
|
183
224
|
}
|
|
184
225
|
_a.#reflectButtons([...(this.#slots?.get('list')?.assignedElements({ flatten: true }) ?? [])].filter((el) => el.matches('option')), section);
|
|
185
226
|
break;
|
|
186
227
|
}
|
|
187
228
|
}
|
|
229
|
+
this.#reflectSelectionOnButtons();
|
|
230
|
+
this.#reflectCurrentValueLabel();
|
|
188
231
|
};
|
|
189
232
|
#renderValidityMsgs = (entries) => {
|
|
190
|
-
|
|
233
|
+
if (devFlags.debug)
|
|
234
|
+
console.debug(`${_a.name} ⚡️ mutation`);
|
|
191
235
|
this.setValidity(this.validity, this.validationMessage);
|
|
192
236
|
};
|
|
193
237
|
#lastRenderedStyle; //string | null
|
|
194
238
|
#shadowRoot;
|
|
195
239
|
#slots = new Map();
|
|
196
240
|
#validityObservers = new MutationObserverSet(this.#renderValidityMsgs);
|
|
197
|
-
#observers = new MutationObserverSet(this.#
|
|
241
|
+
#observers = new MutationObserverSet(this.#renderSlotted);
|
|
198
242
|
#customValidity = '';
|
|
199
243
|
#selection = '';
|
|
200
244
|
get #internals() {
|
|
@@ -299,9 +343,10 @@ export class PickerView extends FormAssociatedBase {
|
|
|
299
343
|
this.#shadowRoot = this.attachShadow({ mode: 'closed' });
|
|
300
344
|
}
|
|
301
345
|
connectedCallback() {
|
|
302
|
-
|
|
346
|
+
if (devFlags.debug)
|
|
347
|
+
console.debug(`${_a.name} ⚡️ connect`);
|
|
303
348
|
CleanupRegistry.register(this, onoff('localechange', () => {
|
|
304
|
-
this.#
|
|
349
|
+
this.#renderSlotted([]);
|
|
305
350
|
}, I18n.on).on());
|
|
306
351
|
CleanupRegistry.register(this, onoff('click', this.#handleClick, this).on());
|
|
307
352
|
if (!this.hasAttribute(this.constructor.ATTR.PICKER_STYLE))
|
|
@@ -313,20 +358,22 @@ export class PickerView extends FormAssociatedBase {
|
|
|
313
358
|
this.#sendValueToForm(false);
|
|
314
359
|
}
|
|
315
360
|
disconnectedCallback() {
|
|
316
|
-
|
|
361
|
+
if (devFlags.debug)
|
|
362
|
+
console.debug(`${_a.name} ⚡️ disconnect`);
|
|
317
363
|
CleanupRegistry.unregister(this);
|
|
318
364
|
this.#validityObservers.unobserveAll();
|
|
319
365
|
this.#observers.unobserveAll();
|
|
320
366
|
}
|
|
321
367
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
322
|
-
|
|
368
|
+
if (devFlags.debug)
|
|
369
|
+
console.debug(`${_a.name} ⚡️ attr-change [${name}] ("${oldValue}" → "${newValue}")`);
|
|
323
370
|
switch (name) {
|
|
324
371
|
case this.constructor.ATTR.PLACEHOLDER:
|
|
325
372
|
this.#reflectPlaceholder(newValue);
|
|
326
373
|
break;
|
|
327
374
|
case this.constructor.ATTR.LABEL:
|
|
328
375
|
this.#reflectLabel(newValue);
|
|
329
|
-
this.#sendValueToForm()
|
|
376
|
+
// this.#sendValueToForm()
|
|
330
377
|
break;
|
|
331
378
|
case this.constructor.ATTR.PICKER_STYLE:
|
|
332
379
|
if (oldValue === newValue)
|
|
@@ -336,7 +383,11 @@ export class PickerView extends FormAssociatedBase {
|
|
|
336
383
|
case this.constructor.ATTR.SEARCHABLE:
|
|
337
384
|
if (oldValue === newValue)
|
|
338
385
|
break;
|
|
339
|
-
this.#
|
|
386
|
+
this.#renderSlotted([]);
|
|
387
|
+
break;
|
|
388
|
+
case this.constructor.ATTR.CURRENT_VALUE_LABEL:
|
|
389
|
+
// if (oldValue === newValue) break
|
|
390
|
+
this.#reflectCurrentValueLabel();
|
|
340
391
|
break;
|
|
341
392
|
case this.constructor.ATTR.SELECTION:
|
|
342
393
|
// nothing happens
|
|
@@ -344,14 +395,12 @@ export class PickerView extends FormAssociatedBase {
|
|
|
344
395
|
}
|
|
345
396
|
}
|
|
346
397
|
get pickerStyle() {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
: 'automatic';
|
|
398
|
+
const attr = this.constructor.ATTR.PICKER_STYLE;
|
|
399
|
+
return pickerStyles.includes(this.getAttribute(attr) ?? '') ? this.getAttribute(attr) : 'automatic';
|
|
350
400
|
}
|
|
351
401
|
#render() {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
return;
|
|
402
|
+
if (devFlags.debug)
|
|
403
|
+
console.debug(`${_a.name} ⚡️ render (${this.pickerStyle})`);
|
|
355
404
|
// const style = this.getAttribute((this.constructor as typeof PickerView).ATTR.PICKER_STYLE)
|
|
356
405
|
if (this.#lastRenderedStyle === this.pickerStyle)
|
|
357
406
|
return; // skip if already applied
|
|
@@ -368,6 +417,7 @@ export class PickerView extends FormAssociatedBase {
|
|
|
368
417
|
CleanupRegistry.register(this, onoff('slotchange', this.#handleValiditiesSlotchange, this.#slots?.get('validity-options')).on(), 'validities');
|
|
369
418
|
CleanupRegistry.unregister(this, 'datalist'); //off1()
|
|
370
419
|
CleanupRegistry.register(this, onoff('slotchange', this.#handleListSlotchange, this.#slots?.get('list')).on(), 'datalist');
|
|
420
|
+
// #renderSlotted should run automatically now by slotchange initial event
|
|
371
421
|
// switch (this.pickerStyle) {
|
|
372
422
|
// }
|
|
373
423
|
}
|
|
@@ -391,32 +441,36 @@ export class PickerView extends FormAssociatedBase {
|
|
|
391
441
|
this.dispatchEvent(new CustomEvent('selection', { detail: { selection: this.#selection }, bubbles: true, composed: true }));
|
|
392
442
|
};
|
|
393
443
|
#handleTriggerClick = async ({ type, target }) => {
|
|
394
|
-
|
|
444
|
+
if (devFlags.debug)
|
|
445
|
+
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
395
446
|
if (!(target instanceof HTMLElement && target))
|
|
396
447
|
return;
|
|
397
448
|
this.#spawn?.remove?.();
|
|
398
|
-
const level0 = this.#
|
|
449
|
+
const level0 = this.#spawnPage('sheet' === this.pickerStyle ? 'sheet-view' : 'body-view', this.hasAttribute('searchable'), this.getAttribute('label'));
|
|
399
450
|
if (!level0)
|
|
400
451
|
return;
|
|
401
452
|
const path = new NavigationPath(target)?.hydrate();
|
|
402
453
|
await startViewTransition(target, 'forwards', async () => {
|
|
403
454
|
this.#spawn = level0;
|
|
404
455
|
update(path, level0);
|
|
456
|
+
this.#reflectSelectionOnButtons();
|
|
405
457
|
});
|
|
406
458
|
};
|
|
407
|
-
#
|
|
408
|
-
|
|
459
|
+
#handlePageBtnClick = async (evt) => {
|
|
460
|
+
if (devFlags.debug)
|
|
461
|
+
console.debug(`${_a.name} ⚡️ ${evt?.type}`);
|
|
409
462
|
evt.stopImmediatePropagation();
|
|
410
463
|
evt.preventDefault();
|
|
411
|
-
const {
|
|
412
|
-
if (!(
|
|
413
|
-
return;
|
|
414
|
-
const btn = target.closest('button');
|
|
415
|
-
if (!btn)
|
|
464
|
+
const { currentTarget: btn } = evt;
|
|
465
|
+
if (!(btn instanceof HTMLElement && btn))
|
|
416
466
|
return;
|
|
467
|
+
// const btn = target.closest('button')
|
|
468
|
+
// if (!btn) return
|
|
417
469
|
const proceed = () => {
|
|
418
470
|
this.#spawn?.remove();
|
|
419
|
-
this.#selection = btn.getAttribute('value') ??
|
|
471
|
+
this.#selection = btn.getAttribute('value') ?? '';
|
|
472
|
+
this.#reflectSelectionOnButtons();
|
|
473
|
+
this.#reflectCurrentValueLabel();
|
|
420
474
|
this.#sendValueToForm();
|
|
421
475
|
};
|
|
422
476
|
const { body } = new NavigationPath(this.#spawn)?.hydrate();
|
|
@@ -427,39 +481,46 @@ export class PickerView extends FormAssociatedBase {
|
|
|
427
481
|
});
|
|
428
482
|
};
|
|
429
483
|
#handleClick({ type, target }) {
|
|
430
|
-
|
|
484
|
+
if (devFlags.debug)
|
|
485
|
+
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
431
486
|
if (!(target instanceof HTMLElement && target))
|
|
432
487
|
return;
|
|
433
488
|
const btn = target.closest('button');
|
|
434
489
|
if (!btn)
|
|
435
490
|
return;
|
|
436
|
-
this.#selection = btn.getAttribute('value') ??
|
|
491
|
+
this.#selection = btn.getAttribute('value') ?? '';
|
|
492
|
+
this.#reflectSelectionOnButtons();
|
|
493
|
+
this.#reflectCurrentValueLabel();
|
|
437
494
|
this.#sendValueToForm();
|
|
438
495
|
}
|
|
439
496
|
#handleValiditiesSlotchange = ({ type, target: slot }) => {
|
|
440
|
-
|
|
497
|
+
if (devFlags.debug)
|
|
498
|
+
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
441
499
|
if (!(slot instanceof HTMLSlotElement && slot))
|
|
442
500
|
return;
|
|
443
501
|
const assigned = slot.assignedElements();
|
|
444
502
|
this.#validityObservers.syncObservations(assigned, ['value', 'label']);
|
|
445
|
-
if (0 < assigned.length)
|
|
446
|
-
|
|
503
|
+
// if (0 < assigned.length)
|
|
504
|
+
this.#renderValidityMsgs([]);
|
|
447
505
|
};
|
|
448
506
|
#handleListSlotchange = ({ type, target: slot }) => {
|
|
449
|
-
|
|
507
|
+
if (devFlags.debug)
|
|
508
|
+
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
450
509
|
if (!(slot instanceof HTMLSlotElement && slot))
|
|
451
510
|
return;
|
|
452
511
|
const assigned = slot.assignedElements();
|
|
453
512
|
this.#observers.syncObservations(assigned);
|
|
454
|
-
if (0 < assigned.length)
|
|
455
|
-
|
|
513
|
+
// if (0 < assigned.length)
|
|
514
|
+
this.#renderSlotted([]);
|
|
456
515
|
};
|
|
457
516
|
static #wrapOptionTag(node) {
|
|
458
|
-
const btn = $(`<button type="button" tabindex="0"></button>`, '>1');
|
|
459
|
-
|
|
517
|
+
const btn = $(`<button type="button" tabindex="0"><h-stack template="auto spacer"><label-view system-image="check"></label-view></h-stack></button>`, '>1'), hStack = btn.querySelector(':scope>h-stack');
|
|
518
|
+
// chevron = hStack?.querySelector<HTMLElement>(':scope>label-view')
|
|
519
|
+
btn.setAttribute('value', extractTagFromOption(node));
|
|
520
|
+
// if (selection !== btn.getAttribute('value')) chevron?.style.setProperty('visibility', 'hidden')
|
|
460
521
|
const label = $(`<label-view></label-view>`, '>1');
|
|
461
|
-
label.setAttribute('title',
|
|
462
|
-
|
|
522
|
+
label.setAttribute('title', extractCurrentValueFromOption(node));
|
|
523
|
+
hStack?.appendChild(label);
|
|
463
524
|
return btn;
|
|
464
525
|
}
|
|
465
526
|
static #wrapOptgroupTag(node) {
|
|
@@ -507,14 +568,51 @@ export class PickerView extends FormAssociatedBase {
|
|
|
507
568
|
}
|
|
508
569
|
}
|
|
509
570
|
#reflectLabel(value) {
|
|
510
|
-
let label = this.querySelector(':scope>[slot=label]');
|
|
571
|
+
let label = this.querySelector(':scope>label-view[slot=label]');
|
|
511
572
|
if (value) {
|
|
512
|
-
label ??= this.appendChild($(`<
|
|
513
|
-
label.
|
|
573
|
+
label ??= this.appendChild($(`<label-view slot="label"></label-view>`, '>1'));
|
|
574
|
+
label.setAttribute('foreground', 'secondary');
|
|
575
|
+
label.setAttribute('title', value);
|
|
514
576
|
}
|
|
515
577
|
else
|
|
516
578
|
label?.remove();
|
|
517
|
-
this.#
|
|
579
|
+
this.#renderSlotted([]);
|
|
580
|
+
}
|
|
581
|
+
#reflectSelectionOnButtons() {
|
|
582
|
+
// walk all rendered buttons (inline has buttons in list, menu has buttons in menu-view)
|
|
583
|
+
for (const el of this.querySelectorAll('button[value]:not([slot])'))
|
|
584
|
+
el.querySelector('label-view[system-image="check"]')?.style.setProperty('visibility', el.getAttribute('value') === this.#selection ? 'visible' : 'hidden');
|
|
585
|
+
// also sync the spawn (sheet/navigation) if open
|
|
586
|
+
if (this.#spawn)
|
|
587
|
+
for (const el of this.#spawn.querySelectorAll('list-view button[value]:not([slot])'))
|
|
588
|
+
el.querySelector('label-view[system-image="check"]')?.style.setProperty('visibility', el.getAttribute('value') === this.#selection ? 'visible' : 'hidden');
|
|
589
|
+
}
|
|
590
|
+
#reflectCurrentValueLabel() {
|
|
591
|
+
const selectedTag = this.#slots
|
|
592
|
+
?.get('list')
|
|
593
|
+
?.assignedElements({ flatten: true })
|
|
594
|
+
.flatMap((el) => [...(el.matches('option') ? [el] : []), ...el.querySelectorAll('option')])
|
|
595
|
+
.find((el) => this.#selection === extractTagFromOption(el)), cvl = selectedTag ? extractCurrentValueFromOption(selectedTag) : '', final = (this.getAttribute('current-value-label') ?? '').replaceAll('{{selection}}', this.#selection).replaceAll('{{currentValueLabel}}', this.#selection) || cvl || this.#selection;
|
|
596
|
+
switch (this.pickerStyle) {
|
|
597
|
+
case 'sheet':
|
|
598
|
+
case 'navigation-link': {
|
|
599
|
+
const currentValueLabel = this.querySelector(':scope>label-view:not([slot])');
|
|
600
|
+
currentValueLabel?.setAttribute('system-image', 'dots-three');
|
|
601
|
+
currentValueLabel?.setAttribute('title', final);
|
|
602
|
+
break;
|
|
603
|
+
}
|
|
604
|
+
case 'menu': {
|
|
605
|
+
const currentValueLabel = this.querySelector(':scope>menu-view:not([slot])>label-view[slot=label]');
|
|
606
|
+
currentValueLabel?.setAttribute('system-image', 'dots-three');
|
|
607
|
+
currentValueLabel?.setAttribute('title', final);
|
|
608
|
+
break;
|
|
609
|
+
}
|
|
610
|
+
case 'inline':
|
|
611
|
+
default: {
|
|
612
|
+
//
|
|
613
|
+
break;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
518
616
|
}
|
|
519
617
|
// Optional: form participation properties
|
|
520
618
|
get name() {
|
|
@@ -549,7 +647,8 @@ export class PickerView extends FormAssociatedBase {
|
|
|
549
647
|
message = kebabCase(key);
|
|
550
648
|
break;
|
|
551
649
|
}
|
|
552
|
-
|
|
650
|
+
if (devFlags.debug)
|
|
651
|
+
console.debug(`${_a.name} ⚡️ validity-change`);
|
|
553
652
|
return this.#internals.setValidity(flags, this.#customValidity || message, anchor);
|
|
554
653
|
};
|
|
555
654
|
setCustomValidity = (message) => {
|
|
@@ -568,6 +667,9 @@ export class PickerView extends FormAssociatedBase {
|
|
|
568
667
|
};
|
|
569
668
|
formResetCallback = () => {
|
|
570
669
|
this.#selection = '';
|
|
670
|
+
this.#reflectSelectionOnButtons();
|
|
671
|
+
this.#reflectCurrentValueLabel();
|
|
672
|
+
this.#sendValueToForm();
|
|
571
673
|
};
|
|
572
674
|
}
|
|
573
675
|
_a = PickerView;
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { CleanupRegistry } from '../internal/class/cleanup-registry';
|
|
2
|
-
import {
|
|
2
|
+
import { devFlags, onoff } from '../internal/utils';
|
|
3
3
|
import { ButtonBase } from '../namespace-browser/base';
|
|
4
4
|
export class PlainButton extends ButtonBase {
|
|
5
5
|
constructor() {
|
|
6
6
|
super();
|
|
7
7
|
}
|
|
8
8
|
static polyfillDisconnectedCallback(el) {
|
|
9
|
-
|
|
9
|
+
if (devFlags.debug)
|
|
10
|
+
console.debug(`${PlainButton.name} ⚡️ disconnect`);
|
|
10
11
|
CleanupRegistry.unregister(el);
|
|
11
12
|
}
|
|
12
13
|
static polyfillConnectedCallback(el) {
|
|
13
|
-
|
|
14
|
+
if (devFlags.debug)
|
|
15
|
+
console.debug(`${PlainButton.name} ⚡️ connect`);
|
|
14
16
|
el.tabIndex = 0;
|
|
15
17
|
CleanupRegistry.register(el, onoff('click', PlainButton.#handleClick, el).on());
|
|
16
18
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var _a;
|
|
2
2
|
import { CleanupRegistry } from '../internal/class/cleanup-registry';
|
|
3
3
|
import { CSSStyleObserver } from '../internal/class/css-style-observer';
|
|
4
|
-
import { $,
|
|
4
|
+
import { $, devFlags } from '../internal/utils';
|
|
5
5
|
import { Snapshot } from '../snapshot';
|
|
6
6
|
const progressViewStyles = ['circular', 'linear'];
|
|
7
7
|
/**
|
|
@@ -55,11 +55,13 @@ export class ProgressView extends HTMLElement {
|
|
|
55
55
|
this.#shadowRoot = this.attachShadow({ mode: 'closed' });
|
|
56
56
|
}
|
|
57
57
|
disconnectedCallback() {
|
|
58
|
-
|
|
58
|
+
if (devFlags.debug)
|
|
59
|
+
console.debug(`${_a.name} ⚡️ disconnect`);
|
|
59
60
|
CleanupRegistry.unregister(this);
|
|
60
61
|
}
|
|
61
62
|
connectedCallback() {
|
|
62
|
-
|
|
63
|
+
if (devFlags.debug)
|
|
64
|
+
console.debug(`${_a.name} ⚡️ connect`);
|
|
63
65
|
this.#cssStyleObserver = new CSSStyleObserver({
|
|
64
66
|
properties: ['--progress-view-style-index'],
|
|
65
67
|
});
|
|
@@ -67,7 +69,8 @@ export class ProgressView extends HTMLElement {
|
|
|
67
69
|
Snapshot.waitReady.then(() => self.requestAnimationFrame(this.#handleStyleChange));
|
|
68
70
|
}
|
|
69
71
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
70
|
-
|
|
72
|
+
if (devFlags.debug)
|
|
73
|
+
console.debug(`${_a.name} ⚡️ attr-change [${name}] ("${oldValue}" → "${newValue}")`);
|
|
71
74
|
switch (name) {
|
|
72
75
|
case 'label': {
|
|
73
76
|
const label = this.querySelector(':scope>label-view:not([slot])') ?? this.appendChild($(`<label-view foreground="secondary"></label-view>`, '>1'));
|
|
@@ -91,7 +94,8 @@ export class ProgressView extends HTMLElement {
|
|
|
91
94
|
}
|
|
92
95
|
}
|
|
93
96
|
#handleStyleChange = () => {
|
|
94
|
-
|
|
97
|
+
if (devFlags.debug)
|
|
98
|
+
console.debug(`${_a.name} ⚡️ style`);
|
|
95
99
|
const raw = self.getComputedStyle(this).getPropertyValue('--progress-view-style-index').trim();
|
|
96
100
|
const newValue = progressViewStyles[Number(raw)] ?? progressViewStyles[0];
|
|
97
101
|
if (newValue === this.#progressViewStyle)
|
|
@@ -100,9 +104,8 @@ export class ProgressView extends HTMLElement {
|
|
|
100
104
|
this.#render();
|
|
101
105
|
};
|
|
102
106
|
#render() {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return;
|
|
107
|
+
if (devFlags.debug)
|
|
108
|
+
console.debug(`${_a.name} ⚡️ render (${this.#progressViewStyle})`);
|
|
106
109
|
if (this.#lastRenderedStyle === this.#progressViewStyle)
|
|
107
110
|
return; // skip if already applied
|
|
108
111
|
this.#lastRenderedStyle = this.#progressViewStyle;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { devFlags } from '../internal/utils';
|
|
2
2
|
import { DialogBase } from '../namespace-browser/base';
|
|
3
3
|
export class ScreenView extends DialogBase {
|
|
4
4
|
constructor() {
|
|
5
5
|
super();
|
|
6
6
|
}
|
|
7
7
|
disconnectedCallback() {
|
|
8
|
-
|
|
8
|
+
if (devFlags.debug)
|
|
9
|
+
console.debug(`${ScreenView.name} ⚡️ disconnect`);
|
|
9
10
|
}
|
|
10
11
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { devFlags } from '../internal/utils';
|
|
2
2
|
/**
|
|
3
3
|
* @summary A wrapper to {hv}-stacks
|
|
4
4
|
*/
|
|
@@ -7,9 +7,11 @@ export class ScrollViewProxy extends HTMLElement {
|
|
|
7
7
|
super();
|
|
8
8
|
}
|
|
9
9
|
disconnectedCallback() {
|
|
10
|
-
|
|
10
|
+
if (devFlags.debug)
|
|
11
|
+
console.debug(`${ScrollViewProxy.name} ⚡️ disconnect`);
|
|
11
12
|
}
|
|
12
13
|
connectedCallback() {
|
|
13
|
-
|
|
14
|
+
if (devFlags.debug)
|
|
15
|
+
console.debug(`${ScrollViewProxy.name} ⚡️ connect`);
|
|
14
16
|
}
|
|
15
17
|
}
|