@swiftwc/ui 0.0.0-dev.21 → 0.0.0-dev.23

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.
Files changed (74) hide show
  1. package/generated/client/index.d.ts +1 -1
  2. package/generated/client/index.js +97 -32
  3. package/generated/components/bordered-button.d.ts +4 -0
  4. package/generated/components/bordered-button.js +8 -1
  5. package/generated/components/bordered-prominent-button.d.ts +4 -0
  6. package/generated/components/bordered-prominent-button.js +8 -1
  7. package/generated/components/borderless-button.d.ts +4 -0
  8. package/generated/components/borderless-button.js +8 -1
  9. package/generated/components/date-picker.js +10 -4
  10. package/generated/components/fine-tooltip.d.ts +7 -0
  11. package/generated/components/fine-tooltip.js +93 -0
  12. package/generated/components/glass-button.d.ts +4 -0
  13. package/generated/components/glass-button.js +8 -1
  14. package/generated/components/glass-prominent-button.d.ts +4 -0
  15. package/generated/components/glass-prominent-button.js +8 -1
  16. package/generated/components/index.d.ts +1 -0
  17. package/generated/components/index.js +1 -0
  18. package/generated/components/label-view.js +1 -33
  19. package/generated/components/picker-view.js +19 -15
  20. package/generated/components/scroll-view.js +8 -3
  21. package/generated/components/sheet-view.d.ts +0 -1
  22. package/generated/components/sheet-view.js +19 -7
  23. package/generated/components/sidebar-toggle.js +1 -1
  24. package/generated/components/tab-view.js +7 -7
  25. package/generated/components/table-view.js +11 -5
  26. package/generated/components/text-field.js +9 -4
  27. package/generated/components/tool-bar-item-group.d.ts +0 -2
  28. package/generated/components/tool-bar-item-group.js +15 -26
  29. package/generated/components/tool-bar-item.js +22 -19
  30. package/generated/components/tool-bar.d.ts +12 -0
  31. package/generated/components/tool-bar.js +19 -6
  32. package/generated/css/index.css +485 -198
  33. package/generated/events/tab-view.d.ts +6 -2
  34. package/generated/internal/class/css-style-observer.js +1 -1
  35. package/generated/internal/utils/button-role.d.ts +1 -1
  36. package/generated/internal/utils/button-role.js +33 -8
  37. package/generated/internal/utils/index.d.ts +0 -1
  38. package/generated/internal/utils/index.js +0 -1
  39. package/package.json +1 -1
  40. package/scss/_components.scss +2 -0
  41. package/scss/_mixins.scss +4 -0
  42. package/scss/_transitions.scss +2 -0
  43. package/scss/_vars.scss +5 -0
  44. package/scss/base/_reboot.scss +15 -0
  45. package/scss/base/_root.scss +63 -67
  46. package/scss/colors/_index.scss +82 -33
  47. package/scss/components/_alert-dialog.scss +4 -5
  48. package/scss/components/_bordered-button.scss +14 -0
  49. package/scss/components/_bordered-prominent-button.scss +13 -0
  50. package/scss/components/_borderless-button.scss +4 -0
  51. package/scss/components/_confirmation-dialog.scss +1 -1
  52. package/scss/components/_content-unavailable-view.scss +1 -1
  53. package/scss/components/_disclosure-group.scss +80 -33
  54. package/scss/components/_fine-tooltip.scss +82 -0
  55. package/scss/components/_glass-button.scss +14 -0
  56. package/scss/components/_glass-prominent-button.scss +14 -0
  57. package/scss/components/_index.scss +21 -20
  58. package/scss/components/_label-view.scss +42 -16
  59. package/scss/components/_label-view.scss.txt +536 -0
  60. package/scss/components/_menu-view.scss +17 -0
  61. package/scss/components/_navigation-split-view.scss +3 -3
  62. package/scss/components/_sheet-view.scss +12 -12
  63. package/scss/components/_tab-bar.scss +5 -0
  64. package/scss/components/_tool-bar-item.scss +71 -53
  65. package/scss/components/_tool-bar.scss +25 -0
  66. package/scss/mixins/_button.scss +42 -0
  67. package/scss/mixins/_color.scss +16 -0
  68. package/scss/mixins/_index.scss +1 -1
  69. package/scss/placeholders/_buttons.scss +40 -48
  70. package/scss/transitions/_fine-tooltip.scss +21 -0
  71. package/scss/transitions/_tab-bar.scss +6 -5
  72. package/web-components.html-data/en.json +18 -16
  73. package/generated/internal/utils/toolbar-repositioner.d.ts +0 -1
  74. package/generated/internal/utils/toolbar-repositioner.js +0 -12
@@ -17,7 +17,7 @@ export declare const alert: (title?: string, message?: string, actions?: {
17
17
  role?: string;
18
18
  }[], options?: {
19
19
  titleVisibility?: boolean;
20
- }) => Promise<any>;
20
+ }) => Promise<void>;
21
21
  export declare const confirmationDialog: (trigger: HTMLElement, title: string, actions?: {
22
22
  label?: string;
23
23
  image?: string;
@@ -101,6 +101,69 @@ if (0 < polyfills.size) {
101
101
  }
102
102
  // SECTION: Safari polyfill
103
103
  document.addEventListener('touchstart', () => { }, { passive: true });
104
+ // SECTION
105
+ const handleHelp = ({ target, relatedTarget }) => {
106
+ if (!(target instanceof HTMLElement && target))
107
+ return;
108
+ const trigger = target.closest('[help]');
109
+ if (!trigger)
110
+ return;
111
+ if (relatedTarget instanceof HTMLElement && relatedTarget && trigger.contains(relatedTarget))
112
+ return;
113
+ const newAnchorName = `--help-${self.crypto.randomUUID()}`;
114
+ const tooltip = $(`<fine-tooltip></fine-tooltip>`, '>1');
115
+ trigger.style.setProperty('anchor-name', newAnchorName);
116
+ tooltip.style.setProperty('position-anchor', newAnchorName);
117
+ document.body.appendChild(tooltip);
118
+ // setInterval(() => {
119
+ // trigger.setAttribute('help', trigger.getAttribute('help') + 'h')
120
+ // }, 2000)
121
+ // console.log(999, trigger)
122
+ }, handleDone = ({ target, relatedTarget }) => {
123
+ if (!(target instanceof HTMLElement && target))
124
+ return;
125
+ const trigger = target.closest('[help]');
126
+ if (!trigger)
127
+ return;
128
+ if (relatedTarget instanceof HTMLElement && relatedTarget && trigger.contains(relatedTarget))
129
+ return;
130
+ const anchorName = trigger.style.anchorName;
131
+ if (!anchorName.startsWith('--help-'))
132
+ return;
133
+ // for (const el of document.querySelectorAll<HTMLElement>(`[style*="--help-${CSS.escape(anchorName)}"][help]`)) el.style.removeProperty('anchor-name') //trigger.style.removeProperty('anchor-name')
134
+ // for (const el of document.querySelectorAll(`[style*="${CSS.escape(anchorName)}"]:not([help])`)) el.remove()
135
+ // return
136
+ // }
137
+ const tooltip = document.querySelector(`[style*="${CSS.escape(anchorName)}"]:not([help])`);
138
+ if (!tooltip)
139
+ return;
140
+ // for (const el of document.querySelectorAll<HTMLElement>(`[style*="--help-${CSS.escape(anchorName)}"][help]`)) el.style.removeProperty('anchor-name') //trigger.style.removeProperty('anchor-name')
141
+ // for (const el of document.querySelectorAll(`[style*="${CSS.escape(anchorName)}"]:not([help])`)) el.remove()
142
+ // return
143
+ // }
144
+ // trigger.style.removeProperty('anchor-name')
145
+ tooltip.hidePopover(); // tooltip.remove?.()
146
+ };
147
+ const mediaQueryList = self.matchMedia(`(pointer: fine)`);
148
+ mediaQueryList.addEventListener('change', ({ matches }) => {
149
+ for (const [k, v] of [
150
+ ['pointerover', handleHelp],
151
+ ['pointerout', handleDone],
152
+ ])
153
+ document.removeEventListener(k, v);
154
+ if (matches)
155
+ for (const [k, v] of [
156
+ ['pointerover', handleHelp],
157
+ ['pointerout', handleDone],
158
+ ])
159
+ document.addEventListener(k, v, { passive: true });
160
+ });
161
+ if (mediaQueryList.matches)
162
+ for (const [k, v] of [
163
+ ['pointerover', handleHelp],
164
+ ['pointerout', handleDone],
165
+ ])
166
+ document.addEventListener(k, v, { passive: true });
104
167
  // SECTION: Transitions
105
168
  const cleanup = (lm, type) => {
106
169
  let arr = [Snapshot.config['vt-fwd-class-name'], 'fwdd', 'fwn', 'fwnn', 'bwd', 'bwdd', 'bwn', 'bwnn'];
@@ -253,39 +316,41 @@ export const startViewTransition = async (target, type = 'forwards', updateCallb
253
316
  }
254
317
  };
255
318
  export const alert = async (title, message, actions, options) => {
256
- const dialog = $(`<dialog is="alert-dialog"></dialog>`, '>1'), vStack = dialog.querySelector(':scope>v-stack') ?? dialog.appendChild($(`<v-stack spacing="1" alignment="fill"></v-stack>`, '>1'));
257
- if (title) {
258
- const label = $(`<label-view font="headline"></label-view>`, '>1');
259
- label.setAttribute('title', title);
260
- vStack.insertAdjacentElement('beforeend', label);
261
- }
262
- if (message) {
263
- const label = $(`<label-view foreground="secondary" font="callout"></label-view>`, '>1');
264
- label.setAttribute('title', message);
265
- vStack.insertAdjacentElement('beforeend', label);
266
- }
267
- for (const [index, action] of (actions ?? []).entries()) {
268
- const btn = $(`<button type="button" tabindex="0" is="bordered-button"></button>`, '>1');
269
- btn.setAttribute('value', `${index}`);
270
- if (action?.role)
271
- btn.setAttribute('role', action.role);
272
- if (action.label || action.image) {
273
- const label = $(`<label-view title="${action.label}"></label-view>`, '>1');
274
- if (action.label)
275
- label.setAttribute('title', action.label);
276
- if (action.image)
277
- label.setAttribute('system-image', action.image);
278
- btn.appendChild(label);
319
+ await navigator.locks.request('alert:', async () => {
320
+ const dialog = $(`<dialog is="alert-dialog"></dialog>`, '>1'), vStack = dialog.querySelector(':scope>v-stack') ?? dialog.appendChild($(`<v-stack spacing="1" alignment="fill"></v-stack>`, '>1'));
321
+ if (title) {
322
+ const label = $(`<label-view font="headline"></label-view>`, '>1');
323
+ label.setAttribute('title', title);
324
+ vStack.insertAdjacentElement('beforeend', label);
279
325
  }
280
- dialog.insertAdjacentElement('beforeend', btn);
281
- }
282
- document.body.insertAdjacentElement('beforeend', dialog);
283
- dialog.showModal();
284
- const { promise, resolve } = Promise.withResolvers(), off = onoff('alert:return', (evt) => {
285
- off();
286
- resolve(evt.detail.returnValue);
287
- }, alertDialog, { once: true }).on();
288
- return promise;
326
+ if (message) {
327
+ const label = $(`<label-view foreground="secondary" font="callout"></label-view>`, '>1');
328
+ label.setAttribute('title', message);
329
+ vStack.insertAdjacentElement('beforeend', label);
330
+ }
331
+ for (const [index, action] of (actions ?? []).entries()) {
332
+ const btn = $(`<button type="button" tabindex="0" is="bordered-button"></button>`, '>1');
333
+ btn.setAttribute('value', `${index}`);
334
+ if (action?.role)
335
+ btn.setAttribute('role', action.role);
336
+ if (action.label || action.image) {
337
+ const label = $(`<label-view></label-view>`, '>1');
338
+ if (action.label)
339
+ label.setAttribute('title', action.label);
340
+ if (action.image)
341
+ label.setAttribute('system-image', action.image);
342
+ btn.appendChild(label);
343
+ }
344
+ dialog.insertAdjacentElement('beforeend', btn);
345
+ }
346
+ document.body.insertAdjacentElement('beforeend', dialog);
347
+ dialog.showModal();
348
+ const { promise, resolve } = Promise.withResolvers(), off = onoff('alert:return', (evt) => {
349
+ off();
350
+ resolve(evt.detail.returnValue);
351
+ }, alertDialog, { once: true }).on();
352
+ return promise;
353
+ });
289
354
  };
290
355
  export const confirmationDialog = async (trigger, title, actions, options) => {
291
356
  const newAnchorName = `--confirmation-dialog-${self.crypto.randomUUID()}`;
@@ -1,4 +1,8 @@
1
1
  import { ButtonBase } from '../namespace-browser/base';
2
+ /**
3
+ * @slot overlay
4
+ *
5
+ */
2
6
  export declare class BorderedButton extends ButtonBase {
3
7
  #private;
4
8
  static get observedAttributes(): string[];
@@ -1,6 +1,11 @@
1
1
  import { CleanupRegistry } from '../internal/class/cleanup-registry';
2
2
  import { buttonRole, onoff } from '../internal/utils';
3
3
  import { ButtonBase } from '../namespace-browser/base';
4
+ import { Snapshot } from '../snapshot';
5
+ /**
6
+ * @slot overlay
7
+ *
8
+ */
4
9
  export class BorderedButton extends ButtonBase {
5
10
  static get observedAttributes() {
6
11
  return ['role'];
@@ -24,7 +29,9 @@ export class BorderedButton extends ButtonBase {
24
29
  return;
25
30
  switch (attributeName) {
26
31
  case 'role':
27
- buttonRole(target, attributeName);
32
+ Snapshot.waitReady.then(() => {
33
+ buttonRole(target, target.getAttribute(attributeName));
34
+ });
28
35
  break;
29
36
  }
30
37
  }
@@ -1,4 +1,8 @@
1
1
  import { ButtonBase } from '../namespace-browser/base';
2
+ /**
3
+ * @slot overlay
4
+ *
5
+ */
2
6
  export declare class BorderedProminentButton extends ButtonBase {
3
7
  #private;
4
8
  static get observedAttributes(): string[];
@@ -1,6 +1,11 @@
1
1
  import { CleanupRegistry } from '../internal/class/cleanup-registry';
2
2
  import { buttonRole, onoff } from '../internal/utils';
3
3
  import { ButtonBase } from '../namespace-browser/base';
4
+ import { Snapshot } from '../snapshot';
5
+ /**
6
+ * @slot overlay
7
+ *
8
+ */
4
9
  export class BorderedProminentButton extends ButtonBase {
5
10
  static get observedAttributes() {
6
11
  return ['role'];
@@ -24,7 +29,9 @@ export class BorderedProminentButton extends ButtonBase {
24
29
  return;
25
30
  switch (attributeName) {
26
31
  case 'role':
27
- buttonRole(target, attributeName);
32
+ Snapshot.waitReady.then(() => {
33
+ buttonRole(target, target.getAttribute(attributeName));
34
+ });
28
35
  break;
29
36
  }
30
37
  }
@@ -1,4 +1,8 @@
1
1
  import { ButtonBase } from '../namespace-browser/base';
2
+ /**
3
+ * @slot overlay
4
+ *
5
+ */
2
6
  export declare class BorderlessButton extends ButtonBase {
3
7
  #private;
4
8
  static get observedAttributes(): string[];
@@ -1,6 +1,11 @@
1
1
  import { CleanupRegistry } from '../internal/class/cleanup-registry';
2
2
  import { buttonRole, onoff } from '../internal/utils';
3
3
  import { ButtonBase } from '../namespace-browser/base';
4
+ import { Snapshot } from '../snapshot';
5
+ /**
6
+ * @slot overlay
7
+ *
8
+ */
4
9
  export class BorderlessButton extends ButtonBase {
5
10
  static get observedAttributes() {
6
11
  return ['role'];
@@ -24,7 +29,9 @@ export class BorderlessButton extends ButtonBase {
24
29
  return;
25
30
  switch (attributeName) {
26
31
  case 'role':
27
- buttonRole(target, attributeName);
32
+ Snapshot.waitReady.then(() => {
33
+ buttonRole(target, target.getAttribute(attributeName));
34
+ });
28
35
  break;
29
36
  }
30
37
  }
@@ -26,7 +26,8 @@ export class DatePicker extends FormAssociatedBase {
26
26
  // #lastRenderedStyle?: DatePickerStyle //string | null
27
27
  #shadowRoot;
28
28
  #customValidity = '';
29
- #validitiesSlot;
29
+ #slots = new Map();
30
+ // #validitiesSlot?: HTMLSlotElement
30
31
  #inputs = [];
31
32
  get #internals() {
32
33
  return getInternals(this);
@@ -123,9 +124,14 @@ export class DatePicker extends FormAssociatedBase {
123
124
  // this.#lastRenderedStyle = this.datePickerStyle
124
125
  // clear shadow DOM
125
126
  this.#shadowRoot.replaceChildren(document.importNode(this.template, true));
126
- this.#validitiesSlot = this.#shadowRoot.querySelector('slot[name=validity-options]') ?? undefined;
127
+ CleanupRegistry.unregister(this, 'slots');
128
+ for (const slot of this.#shadowRoot.querySelectorAll('slot'))
129
+ this.#slots?.set(slot.name, slot);
130
+ CleanupRegistry.register(this, () => {
131
+ this.#slots = new Map();
132
+ }, 'slots');
127
133
  CleanupRegistry.unregister(this, 'validities');
128
- CleanupRegistry.register(this, onoff(makeSlotchangeHandler(this), this.#validitiesSlot).on(), 'validities');
134
+ CleanupRegistry.register(this, onoff(makeSlotchangeHandler(this), this.#slots?.get('validity-options')).on(), 'validities');
129
135
  switch (this.datePickerStyle) {
130
136
  default:
131
137
  const [yyyy = '', mm = '', dd = ''] = new Date().toISOString().split('T').shift()?.split('-') ?? [], map = { year: yyyy, month: mm, day: dd };
@@ -385,7 +391,7 @@ export class DatePicker extends FormAssociatedBase {
385
391
  const key = k; // ✅ type-safe cast
386
392
  if (true !== flags[key])
387
393
  continue;
388
- for (const el of this.#validitiesSlot?.assignedElements({ flatten: true }) ?? []) {
394
+ for (const el of this.#slots?.get('validity-options')?.assignedElements({ flatten: true }) ?? []) {
389
395
  if (!el.matches('option'))
390
396
  continue;
391
397
  const option = el;
@@ -0,0 +1,7 @@
1
+ export declare class FineTooltip extends HTMLElement {
2
+ #private;
3
+ constructor();
4
+ connectedCallback(): void;
5
+ disconnectedCallback(): void;
6
+ hidePopover(): void;
7
+ }
@@ -0,0 +1,93 @@
1
+ var _a;
2
+ import { CleanupRegistry } from '../internal/class/cleanup-registry';
3
+ import { $, onoff } from '../internal/utils';
4
+ export class FineTooltip extends HTMLElement {
5
+ constructor() {
6
+ super();
7
+ }
8
+ #handleMutation = (mutations) => {
9
+ for (const { target, attributeName } of mutations)
10
+ if (target instanceof HTMLElement && target && attributeName)
11
+ this.#render(target.getAttribute(attributeName));
12
+ };
13
+ #handleMeasure = ([{ target, borderBoxSize }]) => {
14
+ console.debug(`${_a.name} ⚡️ measure`);
15
+ if (target.hasAttribute('closing'))
16
+ return;
17
+ if (!(target instanceof HTMLElement && target))
18
+ return;
19
+ const { top } = target.getBoundingClientRect();
20
+ const vpHeight = self.visualViewport?.height ?? 0, blockSize = borderBoxSize.at(0)?.blockSize ?? 0;
21
+ if (top > vpHeight - blockSize - 50) {
22
+ target.style.setProperty('position-area', 'top center');
23
+ target.style.setProperty('transform-origin', 'bottom');
24
+ }
25
+ };
26
+ #observer = new MutationObserver(this.#handleMutation);
27
+ #resizeObserver = new ResizeObserver(this.#handleMeasure);
28
+ get #queryTrigger() {
29
+ const positionAnchor = this.style.positionAnchor;
30
+ if (!positionAnchor.startsWith('--help-'))
31
+ return;
32
+ const trigger = document.querySelector(`[style*="${CSS.escape(positionAnchor)}"][help]`);
33
+ return trigger ?? undefined;
34
+ }
35
+ #render = (str) => {
36
+ const label = this.querySelector(':scope>label-view') ?? this.appendChild($(`<label-view></label-view>`, '>1'));
37
+ if (str)
38
+ label.setAttribute('title', str);
39
+ else
40
+ label.removeAttribute('title');
41
+ };
42
+ connectedCallback() {
43
+ console.debug(`${_a.name} ⚡️ connect`);
44
+ this.removeAttribute('closing');
45
+ this.popover = 'manual';
46
+ this.inert = true;
47
+ CleanupRegistry.register(this, onoff('toggle', this.#handleToggle, this).on());
48
+ CleanupRegistry.register(this, onoff('beforetoggle', this.#handleBeforetoggle, this).on());
49
+ this.showPopover();
50
+ }
51
+ disconnectedCallback() {
52
+ console.debug(`${_a.name} ⚡️ disconnect`);
53
+ this.#resizeObserver.unobserve(this);
54
+ this.#observer?.disconnect();
55
+ this.#queryTrigger?.style.removeProperty('anchor-name');
56
+ CleanupRegistry.unregister(this);
57
+ }
58
+ #handleToggle = ({ newState }) => {
59
+ if ('closed' !== newState)
60
+ return;
61
+ this.remove();
62
+ };
63
+ #handleBeforetoggle = (evt) => {
64
+ if ('open' !== evt.newState)
65
+ return;
66
+ const trigger = this.#queryTrigger;
67
+ if (!trigger) {
68
+ evt.preventDefault();
69
+ this.remove();
70
+ return;
71
+ }
72
+ else {
73
+ this.#render(trigger.getAttribute('help'));
74
+ this.#observer.observe(trigger, {
75
+ attributes: true,
76
+ attributeFilter: ['help'],
77
+ });
78
+ this.#resizeObserver.observe(this);
79
+ }
80
+ this.toggleAttribute('open', 'open' === evt.newState);
81
+ };
82
+ hidePopover() {
83
+ if (this.hasAttribute('closing'))
84
+ return;
85
+ this.setAttribute('closing', '');
86
+ Promise.allSettled(this.getAnimations().map(({ finished }) => finished)).then(() => {
87
+ if (!this.hasAttribute('closing'))
88
+ return;
89
+ this?.remove();
90
+ });
91
+ }
92
+ }
93
+ _a = FineTooltip;
@@ -1,4 +1,8 @@
1
1
  import { ButtonBase } from '../namespace-browser/base';
2
+ /**
3
+ * @slot overlay
4
+ *
5
+ */
2
6
  export declare class GlassButton extends ButtonBase {
3
7
  static get observedAttributes(): string[];
4
8
  constructor();
@@ -1,6 +1,11 @@
1
1
  import { CleanupRegistry } from '../internal/class/cleanup-registry';
2
2
  import { buttonRole, onoff, touchGlass } from '../internal/utils';
3
3
  import { ButtonBase } from '../namespace-browser/base';
4
+ import { Snapshot } from '../snapshot';
5
+ /**
6
+ * @slot overlay
7
+ *
8
+ */
4
9
  export class GlassButton extends ButtonBase {
5
10
  static get observedAttributes() {
6
11
  return ['role'];
@@ -24,7 +29,9 @@ export class GlassButton extends ButtonBase {
24
29
  return;
25
30
  switch (attributeName) {
26
31
  case 'role':
27
- buttonRole(target, attributeName);
32
+ Snapshot.waitReady.then(() => {
33
+ buttonRole(target, target.getAttribute(attributeName));
34
+ });
28
35
  break;
29
36
  }
30
37
  }
@@ -1,4 +1,8 @@
1
1
  import { ButtonBase } from '../namespace-browser/base';
2
+ /**
3
+ * @slot overlay
4
+ *
5
+ */
2
6
  export declare class GlassProminentButton extends ButtonBase {
3
7
  static get observedAttributes(): string[];
4
8
  constructor();
@@ -1,6 +1,11 @@
1
1
  import { CleanupRegistry } from '../internal/class/cleanup-registry';
2
2
  import { buttonRole, onoff, touchGlass } from '../internal/utils';
3
3
  import { ButtonBase } from '../namespace-browser/base';
4
+ import { Snapshot } from '../snapshot';
5
+ /**
6
+ * @slot overlay
7
+ *
8
+ */
4
9
  export class GlassProminentButton extends ButtonBase {
5
10
  static get observedAttributes() {
6
11
  return ['role'];
@@ -24,7 +29,9 @@ export class GlassProminentButton extends ButtonBase {
24
29
  return;
25
30
  switch (attributeName) {
26
31
  case 'role':
27
- buttonRole(target, attributeName);
32
+ Snapshot.waitReady.then(() => {
33
+ buttonRole(target, target.getAttribute(attributeName));
34
+ });
28
35
  break;
29
36
  }
30
37
  }
@@ -7,6 +7,7 @@ export * from './confirmation-dialog';
7
7
  export * from './content-unavailable-view';
8
8
  export * from './date-picker';
9
9
  export * from './disclosure-group';
10
+ export * from './fine-tooltip';
10
11
  export * from './form-view';
11
12
  export * from './glass-button';
12
13
  export * from './glass-prominent-button';
@@ -7,6 +7,7 @@ export * from './confirmation-dialog';
7
7
  export * from './content-unavailable-view';
8
8
  export * from './date-picker';
9
9
  export * from './disclosure-group';
10
+ export * from './fine-tooltip';
10
11
  export * from './form-view';
11
12
  export * from './glass-button';
12
13
  export * from './glass-prominent-button';
@@ -14,50 +14,28 @@ export class LabelView extends HTMLElement {
14
14
  </div>`));
15
15
  }
16
16
  #shadowRoot;
17
- // #imgSlot?: HTMLSlotElement
18
- // #slot?: HTMLSlotElement
19
17
  constructor() {
20
18
  super();
21
19
  this.#shadowRoot = this.attachShadow({ mode: 'closed' });
22
- // Snapshot.waitReady.then(() => {
23
20
  this.#shadowRoot.appendChild(document.importNode(this.constructor.template, true));
24
- // // this.#imgSlot = this.#shadowRoot.querySelector<HTMLSlotElement>('slot[name=image]') ?? undefined
25
- // // this.#slot = this.#shadowRoot.querySelector<HTMLSlotElement>('slot:not([name])') ?? undefined
26
- //
27
- // // this.#slot?.addEventListener('slotchange', this.#handleSlotchange)
28
- // // // this.#imgSlot?.addEventListener('slotchange', this.#handleSlotchange)
29
- // // // this.#handleSlotchange(new CustomEvent('slotchange'))
30
- // })
31
21
  }
32
22
  disconnectedCallback() {
33
23
  console.debug(`${LabelView.name} ⚡️ disconnect`);
34
- // this.#slot?.removeEventListener('slotchange', this.#handleSlotchange)
35
24
  }
36
25
  connectedCallback() {
37
26
  console.debug(`${LabelView.name} ⚡️ connect`);
38
27
  }
39
28
  attributeChangedCallback(name, oldValue, newValue) {
40
29
  console.debug(`${LabelView.name} ⚡️ attr-change [${name}] ("${oldValue}" → "${newValue}")`);
41
- // Snapshot.waitReady.then(() => {
42
30
  switch (name) {
43
31
  case 'system-image':
44
32
  let image = this.querySelector(':scope>[slot=image]');
45
33
  if (newValue) {
46
- image ??= this.appendChild($(`<i slot="image"></i>`, '>1'));
34
+ image ??= this.appendChild($(`<i slot="image" style="line-height: 1.05"></i>`, '>1'));
47
35
  image.setAttribute('class', `ph ph-${newValue}`);
48
36
  }
49
37
  else
50
38
  image?.remove();
51
- // // const imgSlot = this.#shadowRoot.querySelector<HTMLSlotElement>('slot[name=image]')
52
- // // if (!imgSlot) break
53
- // const assigned = this.#imgSlot!.assignedElements({ flatten: true }) as HTMLElement[]
54
- // let el = assigned[0] as HTMLElement | undefined
55
- // if (!el) {
56
- // el = document.createElement('i')
57
- // el.slot = 'image'
58
- // this.append(el)
59
- // }
60
- // el.setAttribute('class', `ph ph-${newValue}`)
61
39
  break;
62
40
  case 'title':
63
41
  let title = this.querySelector(':scope>:not([slot])');
@@ -67,17 +45,7 @@ export class LabelView extends HTMLElement {
67
45
  }
68
46
  else
69
47
  title?.remove();
70
- // // const titleSlot = this.#shadowRoot.querySelector<HTMLSlotElement>('slot:not([name])')
71
- // // if (!titleSlot) break
72
- // const title = this.#slot!.assignedElements({ flatten: true }) as HTMLElement[]
73
- // let el2 = title[0] as HTMLElement | undefined
74
- // if (!el2) {
75
- // el2 = document.createElement('span')
76
- // this.append(el2)
77
- // }
78
- // el2.textContent = newValue //el2.replaceChildren(escapeHTMLPolicy.createHTML(newValue))
79
48
  break;
80
49
  }
81
- // })
82
50
  }
83
51
  }
@@ -21,9 +21,10 @@ export class PickerView extends FormAssociatedBase {
21
21
  #lastRenderedStyle; //string | null
22
22
  #shadowRoot;
23
23
  #customValidity = '';
24
- #validitiesSlot;
25
- #datalistSlot;
26
- #tagSlot;
24
+ #slots = new Map();
25
+ // #validitiesSlot?: HTMLSlotElement
26
+ // #datalistSlot?: HTMLSlotElement
27
+ // #tagSlot?: HTMLSlotElement
27
28
  #trackedElements = new Set();
28
29
  #selection = '';
29
30
  get #internals() {
@@ -176,21 +177,24 @@ export class PickerView extends FormAssociatedBase {
176
177
  this.#lastRenderedStyle = this.pickerStyle;
177
178
  // clear shadow DOM
178
179
  this.#shadowRoot.replaceChildren(document.importNode(this.template, true));
179
- this.#validitiesSlot = this.#shadowRoot.querySelector('slot[name=validity-options]') ?? undefined;
180
- this.#datalistSlot = this.#shadowRoot.querySelector('slot[name=options]') ?? undefined;
181
- this.#tagSlot = this.#shadowRoot.querySelector('slot[name=tag]') ?? undefined;
180
+ CleanupRegistry.unregister(this, 'slots');
181
+ for (const slot of this.#shadowRoot.querySelectorAll('slot'))
182
+ this.#slots?.set(slot.name, slot);
183
+ CleanupRegistry.register(this, () => {
184
+ this.#slots = new Map();
185
+ }, 'slots');
182
186
  CleanupRegistry.unregister(this, 'validities');
183
- CleanupRegistry.register(this, onoff(makeSlotchangeHandler(this), this.#validitiesSlot).on(), 'validities');
187
+ CleanupRegistry.register(this, onoff(makeSlotchangeHandler(this), this.#slots?.get('validity-options')).on(), 'validities');
184
188
  CleanupRegistry.unregister(this, 'datalist'); //off1()
185
- CleanupRegistry.register(this, onoff('slotchange', this.#handleSlotchange, this.#datalistSlot).on(), 'datalist');
189
+ CleanupRegistry.register(this, onoff('slotchange', this.#handleSlotchange, this.#slots?.get('options')).on(), 'datalist');
186
190
  CleanupRegistry.unregister(this, 'tags'); //off2()
187
- CleanupRegistry.register(this, onoff('slotchange', this.#handleSlotchange, this.#tagSlot).on(), 'tags');
188
- // if (0 < (this.#datalistSlot?.assignedElements({ flatten: true }) ?? []).length) this.#handleTagMutation()
189
- // if (0 < (this.#tagSlot?.assignedElements({ flatten: true }) ?? []).length) this.#handleTagMutation()
191
+ CleanupRegistry.register(this, onoff('slotchange', this.#handleSlotchange, this.#slots?.get('tag')).on(), 'tags');
192
+ // if (0 < (this.#slots?.get('options')?.assignedElements({ flatten: true }) ?? []).length) this.#handleTagMutation()
193
+ // if (0 < (this.#slots?.get('tag')?.assignedElements({ flatten: true }) ?? []).length) this.#handleTagMutation()
190
194
  //this.getAttribute((this.constructor as typeof PickerView).ATTR.PICKER_STYLE)) {
191
195
  switch (this.pickerStyle
192
196
  // case 'menu':
193
- // // if (0 < (this.#datalistSlot?.assignedElements({ flatten: true }) ?? []).length) this.#handleMenuDatalistMutation()
197
+ // // if (0 < (this.#slots?.get('options')?.assignedElements({ flatten: true }) ?? []).length) this.#handleMenuDatalistMutation()
194
198
  // break
195
199
  // case 'gg':
196
200
  // // reattach input listener
@@ -209,7 +213,7 @@ export class PickerView extends FormAssociatedBase {
209
213
  // break
210
214
  // case 'inline':
211
215
  // default:
212
- // // if (0 < (this.#datalistSlot?.assignedElements({ flatten: true }) ?? []).length) this.#handleInlineDatalistMutation()
216
+ // // if (0 < (this.#slots?.get('options')?.assignedElements({ flatten: true }) ?? []).length) this.#handleInlineDatalistMutation()
213
217
  // break
214
218
  ) {
215
219
  }
@@ -299,7 +303,7 @@ export class PickerView extends FormAssociatedBase {
299
303
  }
300
304
  #handleTagMutation = (entry) => {
301
305
  console.debug(`${_a.name} ⚡️ mutation`);
302
- const sourceSlot = 0 < (this.#datalistSlot?.assignedElements({ flatten: true }) ?? []).length ? this.#datalistSlot : this.#tagSlot;
306
+ const sourceSlot = 0 < (this.#slots?.get('options')?.assignedElements({ flatten: true }) ?? []).length ? this.#slots?.get('options') : this.#slots?.get('tag');
303
307
  // switch (this.getAttribute((this.constructor as typeof PickerView).ATTR.PICKER_STYLE)) {
304
308
  switch (this.pickerStyle) {
305
309
  case 'menu':
@@ -402,7 +406,7 @@ export class PickerView extends FormAssociatedBase {
402
406
  const key = k; // ✅ type-safe cast
403
407
  if (true !== flags[key])
404
408
  continue;
405
- for (const el of this.#validitiesSlot?.assignedElements({ flatten: true }) ?? []) {
409
+ for (const el of this.#slots?.get('validity-options')?.assignedElements({ flatten: true }) ?? []) {
406
410
  if (!el.matches('option'))
407
411
  continue;
408
412
  const option = el;