@swiftwc/ui 0.0.0-dev.38 → 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 +32 -19
- 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 +181 -77
- package/generated/components/plain-button.js +5 -3
- package/generated/components/progress-view.js +11 -6
- 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 -4
- 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 +11 -6
- package/generated/components/text-field.js +25 -15
- 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);
|
|
@@ -66,15 +76,27 @@ export class PickerView extends FormAssociatedBase {
|
|
|
66
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,12 +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
|
-
|
|
402
|
+
if (devFlags.debug)
|
|
403
|
+
console.debug(`${_a.name} ⚡️ render (${this.pickerStyle})`);
|
|
353
404
|
// const style = this.getAttribute((this.constructor as typeof PickerView).ATTR.PICKER_STYLE)
|
|
354
405
|
if (this.#lastRenderedStyle === this.pickerStyle)
|
|
355
406
|
return; // skip if already applied
|
|
@@ -366,6 +417,7 @@ export class PickerView extends FormAssociatedBase {
|
|
|
366
417
|
CleanupRegistry.register(this, onoff('slotchange', this.#handleValiditiesSlotchange, this.#slots?.get('validity-options')).on(), 'validities');
|
|
367
418
|
CleanupRegistry.unregister(this, 'datalist'); //off1()
|
|
368
419
|
CleanupRegistry.register(this, onoff('slotchange', this.#handleListSlotchange, this.#slots?.get('list')).on(), 'datalist');
|
|
420
|
+
// #renderSlotted should run automatically now by slotchange initial event
|
|
369
421
|
// switch (this.pickerStyle) {
|
|
370
422
|
// }
|
|
371
423
|
}
|
|
@@ -389,32 +441,36 @@ export class PickerView extends FormAssociatedBase {
|
|
|
389
441
|
this.dispatchEvent(new CustomEvent('selection', { detail: { selection: this.#selection }, bubbles: true, composed: true }));
|
|
390
442
|
};
|
|
391
443
|
#handleTriggerClick = async ({ type, target }) => {
|
|
392
|
-
|
|
444
|
+
if (devFlags.debug)
|
|
445
|
+
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
393
446
|
if (!(target instanceof HTMLElement && target))
|
|
394
447
|
return;
|
|
395
448
|
this.#spawn?.remove?.();
|
|
396
|
-
const level0 = this.#
|
|
449
|
+
const level0 = this.#spawnPage('sheet' === this.pickerStyle ? 'sheet-view' : 'body-view', this.hasAttribute('searchable'), this.getAttribute('label'));
|
|
397
450
|
if (!level0)
|
|
398
451
|
return;
|
|
399
452
|
const path = new NavigationPath(target)?.hydrate();
|
|
400
453
|
await startViewTransition(target, 'forwards', async () => {
|
|
401
454
|
this.#spawn = level0;
|
|
402
455
|
update(path, level0);
|
|
456
|
+
this.#reflectSelectionOnButtons();
|
|
403
457
|
});
|
|
404
458
|
};
|
|
405
|
-
#
|
|
406
|
-
|
|
459
|
+
#handlePageBtnClick = async (evt) => {
|
|
460
|
+
if (devFlags.debug)
|
|
461
|
+
console.debug(`${_a.name} ⚡️ ${evt?.type}`);
|
|
407
462
|
evt.stopImmediatePropagation();
|
|
408
463
|
evt.preventDefault();
|
|
409
|
-
const {
|
|
410
|
-
if (!(
|
|
411
|
-
return;
|
|
412
|
-
const btn = target.closest('button');
|
|
413
|
-
if (!btn)
|
|
464
|
+
const { currentTarget: btn } = evt;
|
|
465
|
+
if (!(btn instanceof HTMLElement && btn))
|
|
414
466
|
return;
|
|
467
|
+
// const btn = target.closest('button')
|
|
468
|
+
// if (!btn) return
|
|
415
469
|
const proceed = () => {
|
|
416
470
|
this.#spawn?.remove();
|
|
417
|
-
this.#selection = btn.getAttribute('value') ??
|
|
471
|
+
this.#selection = btn.getAttribute('value') ?? '';
|
|
472
|
+
this.#reflectSelectionOnButtons();
|
|
473
|
+
this.#reflectCurrentValueLabel();
|
|
418
474
|
this.#sendValueToForm();
|
|
419
475
|
};
|
|
420
476
|
const { body } = new NavigationPath(this.#spawn)?.hydrate();
|
|
@@ -425,17 +481,21 @@ export class PickerView extends FormAssociatedBase {
|
|
|
425
481
|
});
|
|
426
482
|
};
|
|
427
483
|
#handleClick({ type, target }) {
|
|
428
|
-
|
|
484
|
+
if (devFlags.debug)
|
|
485
|
+
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
429
486
|
if (!(target instanceof HTMLElement && target))
|
|
430
487
|
return;
|
|
431
488
|
const btn = target.closest('button');
|
|
432
489
|
if (!btn)
|
|
433
490
|
return;
|
|
434
|
-
this.#selection = btn.getAttribute('value') ??
|
|
491
|
+
this.#selection = btn.getAttribute('value') ?? '';
|
|
492
|
+
this.#reflectSelectionOnButtons();
|
|
493
|
+
this.#reflectCurrentValueLabel();
|
|
435
494
|
this.#sendValueToForm();
|
|
436
495
|
}
|
|
437
496
|
#handleValiditiesSlotchange = ({ type, target: slot }) => {
|
|
438
|
-
|
|
497
|
+
if (devFlags.debug)
|
|
498
|
+
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
439
499
|
if (!(slot instanceof HTMLSlotElement && slot))
|
|
440
500
|
return;
|
|
441
501
|
const assigned = slot.assignedElements();
|
|
@@ -444,20 +504,23 @@ export class PickerView extends FormAssociatedBase {
|
|
|
444
504
|
this.#renderValidityMsgs([]);
|
|
445
505
|
};
|
|
446
506
|
#handleListSlotchange = ({ type, target: slot }) => {
|
|
447
|
-
|
|
507
|
+
if (devFlags.debug)
|
|
508
|
+
console.debug(`${_a.name} ⚡️ ${type}`);
|
|
448
509
|
if (!(slot instanceof HTMLSlotElement && slot))
|
|
449
510
|
return;
|
|
450
511
|
const assigned = slot.assignedElements();
|
|
451
512
|
this.#observers.syncObservations(assigned);
|
|
452
513
|
// if (0 < assigned.length)
|
|
453
|
-
this.#
|
|
514
|
+
this.#renderSlotted([]);
|
|
454
515
|
};
|
|
455
516
|
static #wrapOptionTag(node) {
|
|
456
|
-
const btn = $(`<button type="button" tabindex="0"></button>`, '>1');
|
|
457
|
-
|
|
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')
|
|
458
521
|
const label = $(`<label-view></label-view>`, '>1');
|
|
459
|
-
label.setAttribute('title',
|
|
460
|
-
|
|
522
|
+
label.setAttribute('title', extractCurrentValueFromOption(node));
|
|
523
|
+
hStack?.appendChild(label);
|
|
461
524
|
return btn;
|
|
462
525
|
}
|
|
463
526
|
static #wrapOptgroupTag(node) {
|
|
@@ -505,14 +568,51 @@ export class PickerView extends FormAssociatedBase {
|
|
|
505
568
|
}
|
|
506
569
|
}
|
|
507
570
|
#reflectLabel(value) {
|
|
508
|
-
let label = this.querySelector(':scope>[slot=label]');
|
|
571
|
+
let label = this.querySelector(':scope>label-view[slot=label]');
|
|
509
572
|
if (value) {
|
|
510
|
-
label ??= this.appendChild($(`<
|
|
511
|
-
label.
|
|
573
|
+
label ??= this.appendChild($(`<label-view slot="label"></label-view>`, '>1'));
|
|
574
|
+
label.setAttribute('foreground', 'secondary');
|
|
575
|
+
label.setAttribute('title', value);
|
|
512
576
|
}
|
|
513
577
|
else
|
|
514
578
|
label?.remove();
|
|
515
|
-
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
|
+
}
|
|
516
616
|
}
|
|
517
617
|
// Optional: form participation properties
|
|
518
618
|
get name() {
|
|
@@ -547,7 +647,8 @@ export class PickerView extends FormAssociatedBase {
|
|
|
547
647
|
message = kebabCase(key);
|
|
548
648
|
break;
|
|
549
649
|
}
|
|
550
|
-
|
|
650
|
+
if (devFlags.debug)
|
|
651
|
+
console.debug(`${_a.name} ⚡️ validity-change`);
|
|
551
652
|
return this.#internals.setValidity(flags, this.#customValidity || message, anchor);
|
|
552
653
|
};
|
|
553
654
|
setCustomValidity = (message) => {
|
|
@@ -566,6 +667,9 @@ export class PickerView extends FormAssociatedBase {
|
|
|
566
667
|
};
|
|
567
668
|
formResetCallback = () => {
|
|
568
669
|
this.#selection = '';
|
|
670
|
+
this.#reflectSelectionOnButtons();
|
|
671
|
+
this.#reflectCurrentValueLabel();
|
|
672
|
+
this.#sendValueToForm();
|
|
569
673
|
};
|
|
570
674
|
}
|
|
571
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,7 +104,8 @@ export class ProgressView extends HTMLElement {
|
|
|
100
104
|
this.#render();
|
|
101
105
|
};
|
|
102
106
|
#render() {
|
|
103
|
-
|
|
107
|
+
if (devFlags.debug)
|
|
108
|
+
console.debug(`${_a.name} ⚡️ render (${this.#progressViewStyle})`);
|
|
104
109
|
if (this.#lastRenderedStyle === this.#progressViewStyle)
|
|
105
110
|
return; // skip if already applied
|
|
106
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
|
}
|