@swiftwc/ui 0.0.0-dev.20 → 0.0.0-dev.22

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 (113) hide show
  1. package/generated/buses/alert-dialog.d.ts +2 -0
  2. package/generated/buses/alert-dialog.js +1 -0
  3. package/generated/buses/confirmation-dialog.d.ts +2 -0
  4. package/generated/buses/confirmation-dialog.js +1 -0
  5. package/generated/buses/index.d.ts +6 -0
  6. package/generated/buses/index.js +6 -0
  7. package/generated/buses/lifecycle-observer.d.ts +2 -0
  8. package/generated/buses/lifecycle-observer.js +1 -0
  9. package/generated/client/index.d.ts +17 -4
  10. package/generated/client/index.js +83 -32
  11. package/generated/components/alert-dialog.d.ts +8 -0
  12. package/generated/components/alert-dialog.js +94 -0
  13. package/generated/components/bordered-button.d.ts +6 -0
  14. package/generated/components/bordered-button.js +22 -1
  15. package/generated/components/bordered-prominent-button.d.ts +6 -0
  16. package/generated/components/bordered-prominent-button.js +22 -1
  17. package/generated/components/borderless-button.d.ts +5 -1
  18. package/generated/components/borderless-button.js +13 -7
  19. package/generated/components/confirmation-dialog.d.ts +1 -1
  20. package/generated/components/confirmation-dialog.js +26 -20
  21. package/generated/components/content-unavailable-view.js +2 -2
  22. package/generated/components/date-picker.js +24 -10
  23. package/generated/components/disclosure-group.js +4 -1
  24. package/generated/components/glass-button.d.ts +6 -0
  25. package/generated/components/glass-button.js +22 -1
  26. package/generated/components/glass-prominent-button.d.ts +6 -0
  27. package/generated/components/glass-prominent-button.js +22 -1
  28. package/generated/components/index.d.ts +1 -0
  29. package/generated/components/index.js +1 -0
  30. package/generated/components/label-view.js +3 -35
  31. package/generated/components/menu-view.js +12 -7
  32. package/generated/components/navigation-title.js +4 -4
  33. package/generated/components/picker-view.js +35 -25
  34. package/generated/components/scroll-view.js +27 -13
  35. package/generated/components/section-view.js +3 -3
  36. package/generated/components/sheet-view.d.ts +1 -2
  37. package/generated/components/sheet-view.js +38 -22
  38. package/generated/components/sidebar-toggle.js +6 -4
  39. package/generated/components/sidebar-view.js +10 -4
  40. package/generated/components/sticky-container.js +3 -1
  41. package/generated/components/tab-bar.js +10 -4
  42. package/generated/components/tab-item.js +3 -1
  43. package/generated/components/tab-view.js +11 -8
  44. package/generated/components/table-view.js +22 -10
  45. package/generated/components/text-field.js +37 -32
  46. package/generated/components/tool-bar-item-group.js +17 -0
  47. package/generated/components/tool-bar-item.js +20 -1
  48. package/generated/components/tool-bar.d.ts +12 -0
  49. package/generated/components/tool-bar.js +20 -7
  50. package/generated/components/v-stack.d.ts +5 -0
  51. package/generated/components/v-stack.js +5 -0
  52. package/generated/css/index.css +377 -86
  53. package/generated/events/alert-dialog.d.ts +8 -0
  54. package/generated/events/alert-dialog.js +1 -0
  55. package/generated/events/confirmation-dialog.d.ts +2 -2
  56. package/generated/events/index.d.ts +1 -0
  57. package/generated/events/index.js +1 -0
  58. package/generated/events/tab-view.d.ts +6 -2
  59. package/generated/i18n/locales/el.d.ts +9 -0
  60. package/generated/i18n/locales/el.js +9 -0
  61. package/generated/i18n/locales/en.d.ts +9 -0
  62. package/generated/i18n/locales/en.js +9 -0
  63. package/generated/internal/class/css-style-observer.js +1 -1
  64. package/generated/internal/class/form-associated-base.js +4 -1
  65. package/generated/internal/class/navigation-view.js +4 -4
  66. package/generated/internal/utils/button-role.d.ts +1 -0
  67. package/generated/internal/utils/button-role.js +39 -0
  68. package/generated/internal/utils/cash/index.d.ts +4 -3
  69. package/generated/internal/utils/cash/index.js +6 -4
  70. package/generated/internal/utils/index.d.ts +2 -0
  71. package/generated/internal/utils/index.js +2 -0
  72. package/generated/internal/utils/is-inside.d.ts +1 -0
  73. package/generated/internal/utils/is-inside.js +4 -0
  74. package/generated/internal/utils/list-active.js +15 -5
  75. package/generated/snapshot/index.d.ts +2 -0
  76. package/generated/snapshot/index.js +21 -0
  77. package/package.json +7 -4
  78. package/scss/_components.scss +2 -0
  79. package/scss/_functions.scss +10 -0
  80. package/scss/_transitions.scss +1 -0
  81. package/scss/_vars.scss +5 -0
  82. package/scss/base/_reboot.scss +10 -0
  83. package/scss/colors/_index.scss +39 -21
  84. package/scss/components/_alert-dialog.scss +106 -0
  85. package/scss/components/_bordered-button.scss +14 -0
  86. package/scss/components/_bordered-prominent-button.scss +13 -0
  87. package/scss/components/_borderless-button.scss +4 -0
  88. package/scss/components/_confirmation-dialog.scss +39 -39
  89. package/scss/components/_content-unavailable-view.scss +1 -1
  90. package/scss/components/_disclosure-group.scss +80 -33
  91. package/scss/components/_glass-button.scss +14 -0
  92. package/scss/components/_glass-prominent-button.scss +14 -0
  93. package/scss/components/_h-stack.scss +3 -13
  94. package/scss/components/_index.scss +1 -0
  95. package/scss/components/_label-view.scss +42 -16
  96. package/scss/components/_label-view.scss.txt +536 -0
  97. package/scss/components/_sheet-view.scss +13 -3
  98. package/scss/components/_tab-bar.scss +5 -0
  99. package/scss/components/_tool-bar-item.scss +19 -0
  100. package/scss/components/_tool-bar.scss +25 -0
  101. package/scss/components/_v-stack.scss +3 -13
  102. package/scss/final/_touch-glass.scss +7 -0
  103. package/scss/mixins/_index.scss +17 -0
  104. package/scss/placeholders/_buttons.scss +87 -10
  105. package/scss/transitions/_alert-dialog.scss +19 -0
  106. package/scss/transitions/_tab-bar.scss +6 -5
  107. package/scss/utils/_frame.scss +7 -0
  108. package/web-components.html-data/en.json +81 -13
  109. package/generated/confirmation-dialog/index.d.ts +0 -1
  110. package/generated/confirmation-dialog/index.js +0 -1
  111. package/generated/lifecycle-observer/index.d.ts +0 -1
  112. package/generated/lifecycle-observer/index.js +0 -1
  113. package/scss/components/_components.scss +0 -76
@@ -1,8 +1,8 @@
1
1
  var _a;
2
+ import { lifecycleObserver } from '../buses';
2
3
  import { CleanupRegistry } from '../internal/class/cleanup-registry';
3
4
  import { ResizeObserverSingleton } from '../internal/class/resize-observer-singleton';
4
5
  import { $, frame, onoff, slowHideShow } from '../internal/utils';
5
- import { LifecycleObserver } from '../lifecycle-observer';
6
6
  const observers = new ResizeObserverSingleton();
7
7
  export class ScrollView extends HTMLElement {
8
8
  static get observedAttributes() {
@@ -21,10 +21,11 @@ export class ScrollView extends HTMLElement {
21
21
  <div part="root scroll-view-toolbar-stack">
22
22
  <slot name="bottom-bar-principal"></slot>
23
23
  </div>
24
- </div>`, ''));
24
+ </div>`));
25
25
  }
26
26
  #shadowRoot;
27
- #navbarPrincipalSlot;
27
+ #slots = new Map();
28
+ // #navbarPrincipalSlot?: HTMLSlotElement
28
29
  #isMidScroll;
29
30
  #lastScrollTop = 0;
30
31
  // #stopRecordingScrollTop?: boolean = false
@@ -33,13 +34,17 @@ export class ScrollView extends HTMLElement {
33
34
  super();
34
35
  this.#shadowRoot = this.attachShadow({ mode: 'closed' });
35
36
  this.#shadowRoot.appendChild(document.importNode(this.constructor.template, true));
36
- this.#navbarPrincipalSlot = this.#shadowRoot.querySelector('slot[name=top-bar-principal]') ?? undefined;
37
+ for (const slot of this.#shadowRoot.querySelectorAll('slot'))
38
+ this.#slots?.set(slot.name, slot);
39
+ CleanupRegistry.register(this, () => {
40
+ this.#slots = new Map();
41
+ });
37
42
  }
38
43
  disconnectedCallback() {
39
44
  console.debug(`${_a.name} ⚡️ disconnect`);
40
45
  CleanupRegistry.unregister(this);
41
46
  observers.unobserve(this);
42
- frame().then(() => LifecycleObserver.dispatchEvent(new CustomEvent('pagehide', { detail: { page: this }, bubbles: true, composed: true })));
47
+ frame().then(() => lifecycleObserver.dispatchEvent(new CustomEvent('pagehide', { detail: { page: this }, bubbles: true, composed: true })));
43
48
  }
44
49
  connectedCallback() {
45
50
  console.debug(`${_a.name} ⚡️ connect`);
@@ -51,7 +56,7 @@ export class ScrollView extends HTMLElement {
51
56
  { types: 'scroll', listener: this.#handleScroll, addOptions: { passive: true } },
52
57
  { types: 'scrollend', listener: this.#handleScrollend, addOptions: { passive: true } },
53
58
  ], this).on());
54
- frame().then(() => LifecycleObserver.dispatchEvent(new CustomEvent('pageshow', { detail: { page: this }, bubbles: true, composed: true })));
59
+ frame().then(() => lifecycleObserver.dispatchEvent(new CustomEvent('pageshow', { detail: { page: this }, bubbles: true, composed: true })));
55
60
  observers.observe(this, this.#handleMeasure.bind(this));
56
61
  // frame(this).then((r) => {
57
62
  // if (!r) return
@@ -84,7 +89,7 @@ export class ScrollView extends HTMLElement {
84
89
  break; // iREPAINT ALERT! if (0 === this.offsetHeight + this.offsetWidth) break
85
90
  if (!this.#isMidScroll)
86
91
  break;
87
- const title = this.#navbarPrincipalSlot?.assignedElements({ flatten: true })?.at(0);
92
+ const title = this.#slots?.get('top-bar-principal')?.assignedElements({ flatten: true })?.at(0);
88
93
  slowHideShow('largeinline' === `${oldValue}${newValue}` ? 'show' : 'hide', title);
89
94
  break;
90
95
  }
@@ -94,7 +99,10 @@ export class ScrollView extends HTMLElement {
94
99
  if (!this.#isMidScroll)
95
100
  this.#isMidScroll = true;
96
101
  // if (this.#stopRecordingScrollTop) return
97
- this.#lastScrollTop = evt.target.scrollTop;
102
+ const target = evt.target instanceof HTMLElement && evt.target;
103
+ if (!target)
104
+ return;
105
+ this.#lastScrollTop = target.scrollTop;
98
106
  };
99
107
  #handleScrollend = (evt) => {
100
108
  console.debug(`${_a.name} ⚡️ ${evt?.type}`);
@@ -120,7 +128,10 @@ export class ScrollView extends HTMLElement {
120
128
  };
121
129
  #handleTabReveal = (evt) => {
122
130
  console.debug(`${_a.name} ⚡️ ${evt?.type}`);
123
- if (!evt.target?.contains(this))
131
+ const target = evt.target instanceof HTMLElement && evt.target;
132
+ if (!target)
133
+ return;
134
+ if (!target.contains(this))
124
135
  return;
125
136
  if (this.closest('[hidden]'))
126
137
  return;
@@ -149,7 +160,10 @@ export class ScrollView extends HTMLElement {
149
160
  };
150
161
  #handleTabBeforeswap = (evt) => {
151
162
  console.debug(`${_a.name} ⚡️ ${evt?.type}`);
152
- if (!evt.target?.contains(this))
163
+ const target = evt.target instanceof HTMLElement && evt.target;
164
+ if (!target)
165
+ return;
166
+ if (!target.contains(this))
153
167
  return;
154
168
  if (this.closest('[hidden]'))
155
169
  return;
@@ -167,17 +181,17 @@ export class ScrollView extends HTMLElement {
167
181
  }
168
182
  #renderNavTitle = (title, subtitle) => {
169
183
  const vStack = this.querySelector(':scope>[slot=top-bar-principal]') ??
170
- this.appendChild($(`<v-stack spacing="0" alignment="fill" slot="top-bar-principal"><label-view line-limit="1" truncation-mode="tail" font="headline"></label-view><label-view line-limit="1" truncation-mode="tail" font="callout"></label-view></v-stack>`));
184
+ this.appendChild($(`<v-stack spacing="0" alignment="fill" slot="top-bar-principal"><label-view line-limit="1" truncation-mode="tail" font="headline"></label-view><label-view line-limit="1" truncation-mode="tail" font="callout"></label-view></v-stack>`, '>1'));
171
185
  let titleLabel = vStack.querySelector(':scope>label-view:nth-child(1)');
172
186
  if (title) {
173
- titleLabel ??= vStack.appendChild($(`<label-view line-limit="1" truncation-mode="tail" font="headline"></label-view>`));
187
+ titleLabel ??= vStack.appendChild($(`<label-view line-limit="1" truncation-mode="tail" font="headline"></label-view>`, '>1'));
174
188
  titleLabel.setAttribute('title', title);
175
189
  }
176
190
  else
177
191
  titleLabel?.remove();
178
192
  let subtitleLabel = vStack.querySelector(':scope>label-view:nth-child(2)');
179
193
  if (subtitle) {
180
- subtitleLabel ??= vStack.appendChild($(`<label-view line-limit="1" truncation-mode="tail" font="callout"></label-view>`));
194
+ subtitleLabel ??= vStack.appendChild($(`<label-view line-limit="1" truncation-mode="tail" font="callout"></label-view>`, '>1'));
181
195
  subtitleLabel.setAttribute('title', subtitle);
182
196
  }
183
197
  else
@@ -14,7 +14,7 @@ export class SectionView extends HTMLElement {
14
14
  </div>
15
15
  <div part="root section-footer-stack">
16
16
  <slot name="footer"></slot>
17
- </div>`, ''));
17
+ </div>`));
18
18
  // <div class="sticky-sentinel" style="grid-area:sentinel;inline-size:100%;block-size:0.1px;pointer-events:none;"></div>
19
19
  }
20
20
  #shadowRoot;
@@ -60,7 +60,7 @@ export class SectionView extends HTMLElement {
60
60
  case 'header':
61
61
  let header = this.querySelector(':scope>[slot=header]');
62
62
  if (newValue) {
63
- header ??= this.appendChild($(`<header slot="header"><label-view line-limit="1" truncation-mode="tail" font="callout"></label-view></header>`));
63
+ header ??= this.appendChild($(`<header slot="header"><label-view line-limit="1" truncation-mode="tail" font="callout"></label-view></header>`, '>1'));
64
64
  header.querySelector('label-view')?.setAttribute('title', newValue);
65
65
  }
66
66
  else
@@ -69,7 +69,7 @@ export class SectionView extends HTMLElement {
69
69
  case 'footer':
70
70
  let footer = this.querySelector(':scope>[slot=footer]');
71
71
  if (newValue) {
72
- footer ??= this.appendChild($(`<footer slot="footer"><label-view line-limit="1" truncation-mode="tail" font="callout"></label-view></footer>`));
72
+ footer ??= this.appendChild($(`<footer slot="footer"><label-view line-limit="1" truncation-mode="tail" font="callout"></label-view></footer>`, '>1'));
73
73
  footer.querySelector('label-view')?.setAttribute('title', newValue);
74
74
  }
75
75
  else
@@ -1,9 +1,8 @@
1
1
  import { DialogBase } from '../namespace-browser/base';
2
2
  export declare class SheetView extends DialogBase {
3
3
  #private;
4
- static get observedAttributes(): string[];
5
4
  constructor();
6
5
  static polyfillDisconnectedCallback(el: SheetView): void;
7
6
  static polyfillConnectedCallback(el: SheetView): void;
8
- static polyfillAttributeChangedCallback([{ attributeName, target, oldValue }]: Pick<MutationRecord, 'attributeName' | 'oldValue' | 'target'>[]): Promise<void>;
7
+ static polyfillAttributeChangedCallback([{ attributeName, target, oldValue }]: Pick<MutationRecord, 'attributeName' | 'oldValue' | 'target'>[]): void;
9
8
  }
@@ -3,9 +3,9 @@ import { onoff } from '../internal/utils';
3
3
  import { DialogBase } from '../namespace-browser/base';
4
4
  import { Snapshot } from '../snapshot';
5
5
  export class SheetView extends DialogBase {
6
- static get observedAttributes() {
7
- return ['fine-presentation-large-adaptation'];
8
- }
6
+ // static get observedAttributes() {
7
+ // return ['fine-presentation-large-adaptation']
8
+ // }
9
9
  constructor() {
10
10
  super();
11
11
  }
@@ -20,24 +20,38 @@ export class SheetView extends DialogBase {
20
20
  { types: 'keydown', listener: SheetView.#handleKeydown },
21
21
  ], el).on());
22
22
  el.autofocus = true;
23
+ if (!self.matchMedia('(pointer: fine)').matches)
24
+ return;
25
+ const handler1 = this.#handleMediaChange.bind(null, el);
26
+ CleanupRegistry.register(el, onoff('fine_dialog_sheet:change', handler1, Snapshot.on).on());
27
+ Snapshot.waitReady.then(() => {
28
+ this.#handleMediaChange(el, new MediaQueryListEvent(`media-change`, {
29
+ matches: Snapshot.breakpoints?.get('fine_dialog_sheet'),
30
+ })); // Initial check
31
+ });
23
32
  }
24
- static async polyfillAttributeChangedCallback([{ attributeName, target, oldValue }]) {
33
+ static polyfillAttributeChangedCallback([{ attributeName, target, oldValue }]) {
25
34
  console.debug(`${SheetView.name} ⚡️ attr-change [${attributeName}] ("${oldValue}" → "${target.getAttribute(attributeName ?? '')}")`);
26
- await Snapshot.waitReady; // NOTE: wait for config
27
- switch (attributeName) {
28
- case 'fine-presentation-large-adaptation':
29
- const node = target;
30
- CleanupRegistry.unregister(node, 'mediaquery');
31
- if ('bottom-bar' !== target.getAttribute(attributeName ?? ''))
32
- break;
33
- const mediaQueryList = self.matchMedia(`(pointer: fine) and (min-width: ${Snapshot.config['ipad-sheet-view-inline-size']}) and (min-height: ${Snapshot.config['ipad-sheet-view-height']})`);
34
- SheetView.#handleMediaChange(node, new MediaQueryListEvent(`media-change`, {
35
- matches: mediaQueryList.matches,
36
- })); // Initial check
37
- const handler1 = SheetView.#handleMediaChange.bind(null, node);
38
- CleanupRegistry.register(node, onoff('change', handler1, mediaQueryList).on(), 'mediaquery');
39
- break;
40
- }
35
+ // // NOTE: wait for config
36
+ // Snapshot.waitReady.then(() => {
37
+ // switch (attributeName) {
38
+ // case 'fine-presentation-large-adaptation':
39
+ // const node = target instanceof HTMLDialogElement && target
40
+ // if (!node) break
41
+ // CleanupRegistry.unregister(node, 'mediaquery')
42
+ // if ('bottom-bar' !== target.getAttribute(attributeName ?? '')) break
43
+ // const mediaQueryList = self.matchMedia(`(pointer: fine) and (min-width: ${Snapshot.config!['ipad-sheet-view-inline-size']}) and (min-height: ${Snapshot.config!['ipad-sheet-view-height']})`)
44
+ // SheetView.#handleMediaChange(
45
+ // node,
46
+ // new MediaQueryListEvent(`media-change`, {
47
+ // matches: mediaQueryList.matches,
48
+ // })
49
+ // ) // Initial check
50
+ // const handler1 = SheetView.#handleMediaChange.bind(null, node)
51
+ // CleanupRegistry.register(node, onoff('change', handler1 as unknown as EventListener, mediaQueryList).on(), 'mediaquery')
52
+ // break
53
+ // }
54
+ // })
41
55
  }
42
56
  static #handleKeydown = (evt) => {
43
57
  console.debug(`${SheetView.name} ⚡️ ${evt?.type} (${evt.key})`);
@@ -56,9 +70,11 @@ export class SheetView extends DialogBase {
56
70
  static #handleMediaChange = (el, evt) => {
57
71
  console.debug(`${SheetView.name} ⚡️ ${evt?.type}`);
58
72
  if (evt.matches)
59
- for (const item of el.querySelectorAll(':scope>tool-bar>[slot^="top-bar-"]')) {
60
- item.dataset.previousSlot = item.getAttribute('slot') ?? '';
61
- item.slot = 'bottom-bar-trailing';
73
+ for (const item of el.querySelectorAll(':scope>tool-bar>[slot^="top-bar-"],:scope>tool-bar>[slot="cancellation-action"],:scope>tool-bar>[slot="primary-action"],:scope>tool-bar>[slot="confirmation-action"],:scope>tool-bar>[slot="destructive-action"]')) {
74
+ const newSlot = item.slot.endsWith('leading') ? 'bottom-bar-leading' : 'bottom-bar-trailing';
75
+ if (item.slot !== newSlot)
76
+ item.dataset.previousSlot = item.slot;
77
+ item.slot = newSlot;
62
78
  }
63
79
  else
64
80
  for (const item of el.querySelectorAll(':scope>tool-bar>[data-previous-slot]')) {
@@ -23,14 +23,14 @@ export class SidebarToggle extends HTMLElement {
23
23
  CleanupRegistry.unregister(this);
24
24
  }
25
25
  static query(target) {
26
- const container = target?.closest('navigation-split-view,tab-view'), sideBar = container?.querySelector(':scope > [is=sidebar-view]');
26
+ const container = target?.closest('navigation-split-view,tab-view'), sideBar = container?.querySelector(':scope>[is=sidebar-view]');
27
27
  return { container, sideBar };
28
28
  }
29
29
  // This triggers on show/hide of any of sidebar-toggle elements
30
30
  static #handleMeasure(entry) {
31
31
  console.debug(`${_a.name} ⚡️ measure`);
32
- const { target } = entry ?? {};
33
- if (!(target instanceof HTMLElement))
32
+ const target = entry?.target instanceof HTMLElement && entry.target;
33
+ if (!target)
34
34
  return;
35
35
  // set/remove css var/prop to parent based on shown/hidden
36
36
  const tv = target.parentElement;
@@ -67,7 +67,9 @@ export class SidebarToggle extends HTMLElement {
67
67
  }
68
68
  #handleClick(evt) {
69
69
  console.debug(`${_a.name} ⚡️ ${evt?.type}`);
70
- const { target } = evt;
70
+ const target = evt?.target instanceof HTMLElement && evt.target;
71
+ if (!target)
72
+ return;
71
73
  if (!target?.closest('button'))
72
74
  return;
73
75
  const { sideBar } = _a.query(target);
@@ -12,9 +12,12 @@ export class SidebarView extends DialogBase {
12
12
  static polyfillConnectedCallback(el) {
13
13
  CleanupRegistry.register(el, onoff('click', SidebarView.#handleClick, el).on());
14
14
  CleanupRegistry.register(el, onoff(touchGlass(el, (t) => t, (evt) => {
15
- if (evt.target.matches('[is=sidebar-view]'))
15
+ const target = evt.target instanceof HTMLElement && evt.target;
16
+ if (!target)
17
+ return true;
18
+ if (target.matches('[is=sidebar-view]'))
16
19
  return false;
17
- if (evt.target.closest('tool-bar-item'))
20
+ if (target.closest('tool-bar-item'))
18
21
  return false;
19
22
  return true;
20
23
  }), el).on());
@@ -23,7 +26,10 @@ export class SidebarView extends DialogBase {
23
26
  /** Autoclose on click outside. */
24
27
  static #handleClick = async (evt) => {
25
28
  console.debug(`${SidebarView.name} ⚡️ ${evt?.type}`);
26
- if ('DIALOG' === evt.target.tagName && 'sidebar-view' === evt.target.getAttribute('is'))
27
- evt?.target?.close?.();
29
+ const target = evt.target instanceof HTMLElement && evt.target;
30
+ if (!target)
31
+ return;
32
+ if (target instanceof HTMLDialogElement && 'sidebar-view' === target.getAttribute('is'))
33
+ target.close?.();
28
34
  };
29
35
  }
@@ -14,7 +14,9 @@ export class StickyContainer extends HTMLElement {
14
14
  CleanupRegistry.unregister(this);
15
15
  }
16
16
  #handleTransitionrun = ({ target, propertyName, pseudoElement }) => {
17
- if ('--stuck' !== propertyName || '::before' !== pseudoElement || !target?.matches('sticky-container'))
17
+ if (!(target instanceof HTMLElement && target))
18
+ return;
19
+ if ('--stuck' !== propertyName || '::before' !== pseudoElement || !target.matches('sticky-container'))
18
20
  return;
19
21
  const stuck = self.getComputedStyle(this, 'before').getPropertyValue('--stuck');
20
22
  this.toggleAttribute('stuck', '1' === stuck);
@@ -20,9 +20,12 @@ export class TabBar extends DialogBase {
20
20
  // if (!r) return
21
21
  CleanupRegistry.register(el, onoff('click', TabBar.#handleClick, el).on());
22
22
  CleanupRegistry.register(el, onoff(touchGlass(el, (t) => t, (evt) => {
23
- if (evt.target.matches('[is=tab-bar]'))
23
+ const target = evt.target instanceof HTMLElement && evt.target;
24
+ if (!target)
25
+ return true;
26
+ if (target.matches('[is=tab-bar]'))
24
27
  return false;
25
- if (evt.target.closest('tool-bar-item'))
28
+ if (target.closest('tool-bar-item'))
26
29
  return false;
27
30
  return true;
28
31
  }), el).on());
@@ -30,7 +33,10 @@ export class TabBar extends DialogBase {
30
33
  }
31
34
  static #handleClick = async (evt) => {
32
35
  console.debug(`${TabBar.name} ⚡️ ${evt?.type}`);
33
- if ('DIALOG' === evt.target.tagName && 'tab-bar' === evt.target.getAttribute('is'))
34
- evt?.target?.close?.();
36
+ const target = evt.target instanceof HTMLElement && evt.target;
37
+ if (!target)
38
+ return;
39
+ if (target instanceof HTMLDialogElement && 'tab-bar' === target.getAttribute('is'))
40
+ target.close?.();
35
41
  };
36
42
  }
@@ -63,7 +63,9 @@ export class TabItem extends ButtonBase {
63
63
  };
64
64
  static #handleClick = async (evt) => {
65
65
  console.debug(`${TabItem.name} ⚡️ ${evt?.type}`);
66
- const btn = evt.currentTarget;
66
+ const btn = evt.currentTarget instanceof HTMLElement && evt.currentTarget;
67
+ if (!btn)
68
+ return;
67
69
  // const tag = btn.getAttribute('value')
68
70
  // if (!tag) return // sidebartoggle > tab-item //throw new DOMException(`Attribute "tag" is set but invalid`, 'InvalidStateError')
69
71
  const tv = btn.closest('tab-view');
@@ -73,7 +73,10 @@ export class TabView extends HTMLElement {
73
73
  // })
74
74
  }
75
75
  #handleSummaryClick = (evt) => {
76
- const summary = evt.target.closest('summary');
76
+ const target = evt.target instanceof HTMLElement && evt.target;
77
+ if (!target)
78
+ return;
79
+ const summary = target.closest('summary');
77
80
  if (!summary)
78
81
  return;
79
82
  if (0 === $.siblings('[aria-selected=true]', summary).length)
@@ -86,7 +89,7 @@ export class TabView extends HTMLElement {
86
89
  const style = self.getComputedStyle(form);
87
90
  if ('sidebar' !== style.getPropertyValue('--list-style'))
88
91
  return;
89
- this.#addAnimations();
92
+ this.#addAnimations(new CustomEvent('beforetabreveal', { detail: { tag: '', ms: cssTime(`${this.computedStyleMap().get(`--tabbar-after-tabreveal-duration`)}`) }, bubbles: true, composed: true }));
90
93
  };
91
94
  #handleTabViewPagereveal = (evt) => {
92
95
  console.debug(`${_a.name} ⚡️ ${evt?.type}`);
@@ -199,28 +202,28 @@ export class TabView extends HTMLElement {
199
202
  throw new Error('selectedTab[] must be in order of parent>child. You provided an element that contains the previous sibling.');
200
203
  //
201
204
  const selectors = [':not(:is(:scope>{{tag}}))', ':is(:scope>{{tag}})']; // first nested ones, then root ones
205
+ const ms = cssTime(`${this.computedStyleMap().get(`--tabbar-after-tabreveal-duration`)}`);
202
206
  for (const selector of selectors)
203
207
  for (const ns of this.querySelectorAll(`navigation-stack:not([hidden])${selector.replace('{{tag}}', 'navigation-stack')},navigation-split-view:not([hidden])${selector.replace('{{tag}}', 'navigation-split-view')}`)) {
204
208
  if (!tabs.some((tab) => !ns.contains(tab)))
205
209
  continue; // shouldRun
206
- ns.dispatchEvent(new CustomEvent('beforetabswap', { detail: { tag: ns.id }, bubbles: true, composed: true }));
210
+ ns.dispatchEvent(new CustomEvent('beforetabswap', { detail: { tag: ns.id, ms }, bubbles: true, composed: true }));
207
211
  ns.hidden = true; // triggers
208
212
  }
209
213
  for (const selector of selectors.reverse())
210
214
  for (const ns of this.querySelectorAll(`navigation-stack[hidden]${selector.replace('{{tag}}', 'navigation-stack')},navigation-split-view[hidden]${selector.replace('{{tag}}', 'navigation-split-view')}`)) {
211
215
  if (!tabs.some((tab) => ns.contains(tab)))
212
216
  continue; // shouldRun
213
- ns.dispatchEvent(new CustomEvent('beforetabreveal', { detail: { tag: ns.id }, bubbles: true, composed: true }));
217
+ ns.dispatchEvent(new CustomEvent('beforetabreveal', { detail: { tag: ns.id, ms }, bubbles: true, composed: true }));
214
218
  ns.hidden = false; // triggers
215
219
  }
216
220
  }
217
- #addAnimations = () => {
221
+ #addAnimations = (evt) => {
218
222
  this.setAttribute('js-aftertabreveal', '');
223
+ // const ms = cssTime(`${this.computedStyleMap().get(`--tabbar-after-tabreveal-duration`)}`)
219
224
  this.#afterTabRevealDelay.next(() => {
220
225
  this.removeAttribute('js-aftertabreveal');
221
- }, cssTime(`${this.computedStyleMap().get(`--tabbar-after-tabreveal-duration`)}`));
222
- // this.removeAttribute('js-aftertabreveal')
223
- // this.#afterTabRevealDelay = undefined
226
+ }, evt.detail.ms);
224
227
  };
225
228
  #handleSelectionChange = (evt) => {
226
229
  this.#triggerToggleEvent(evt);
@@ -39,18 +39,24 @@ export class TableView extends HTMLElement {
39
39
  <slot name="footer-trailing"></slot>
40
40
  </div>
41
41
  </div>
42
- </div>`, ''));
42
+ </div>`));
43
43
  }
44
44
  #shadowRoot;
45
- #colSlot;
45
+ #slots = new Map();
46
+ // #colSlot?: HTMLSlotElement
46
47
  // #slot?: HTMLSlotElement
47
48
  constructor() {
48
49
  super();
49
50
  this.#shadowRoot = this.attachShadow({ mode: 'closed' });
50
51
  this.#shadowRoot.appendChild(document.importNode(this.constructor.template, true));
51
- this.#colSlot = this.#shadowRoot.querySelector('slot[name=column]') ?? undefined;
52
+ for (const slot of this.#shadowRoot.querySelectorAll('slot'))
53
+ this.#slots?.set(slot.name, slot);
54
+ CleanupRegistry.register(this, () => {
55
+ this.#slots = new Map();
56
+ });
57
+ // this.#colSlot = this.#shadowRoot.querySelector<HTMLSlotElement>('slot[name=column]') ?? undefined
52
58
  // this.#slot = this.#shadowRoot.querySelector<HTMLSlotElement>('slot:not([name])') ?? undefined
53
- this.#colSlot?.addEventListener('slotchange', this.#handleSlotchange);
59
+ this.#slots?.get('column')?.addEventListener('slotchange', this.#handleSlotchange);
54
60
  // this.append(
55
61
  // document.createRange().createContextualFragment(`<menu-view slot="header-trailing">
56
62
  // <label-view slot="label" title="Delete"></label-view>
@@ -103,25 +109,28 @@ export class TableView extends HTMLElement {
103
109
  }
104
110
  #handleSlotchange = (evt) => {
105
111
  console.debug(`${_a.name} ⚡️ ${evt?.type}`);
106
- const slot = evt.target, assigned = slot.assignedElements({ flatten: true });
112
+ const slot = evt.target instanceof HTMLSlotElement && evt.target;
113
+ if (!slot)
114
+ return;
115
+ const assigned = slot.assignedElements({ flatten: true });
107
116
  observers.syncObservations(this.#trackedElements, assigned, this.#handleTagMutation);
108
117
  if (0 < assigned.length)
109
118
  this.#handleTagMutation();
110
119
  };
111
120
  #handleTagMutation = (entry) => {
112
121
  console.debug(`${_a.name} ⚡️ mutation`);
113
- // const sourceSlot = 0 < (this.#colSlot?.assignedElements({ flatten: true }) ?? []).length ? this.#colSlot : this.#colSlot
122
+ // const sourceSlot = 0 < (this.#slots?.get('column')?.assignedElements({ flatten: true }) ?? []).length ? this.#slots?.get('column') : this.#slots?.get('column')
114
123
  // const menu = this.querySelector(':scope>menu-view:not([slot])') ?? this.appendChild($(`<menu-view></menu-view>`))
115
124
  // menu.innerHTML = `<label-view slot="label" system-image="dots-three" title="rtyty"></label-view>`
116
125
  // for (const el of sourceSlot?.assignedElements({ flatten: true }) ?? []) menu.insertAdjacentElement('beforeend', TableView.wrapTag(el, sourceSlot?.name))
117
126
  //
118
127
  if (!this.#compactToolbarItem) {
119
- this.#compactToolbarItem = $(`<menu-view tabindex="0" slot="header-trailing"></menu-view>`);
128
+ this.#compactToolbarItem = $(`<menu-view tabindex="0" slot="header-trailing"></menu-view>`, '>1');
120
129
  CleanupRegistry.unregister(this, 'compact_toolbar');
121
130
  CleanupRegistry.register(this, onoff('click', this.#handleMenuClick, this.#compactToolbarItem).on(), 'compact_toolbar');
122
131
  }
123
132
  this.#compactToolbarItem.innerHTML = `<label-view slot="label" system-image="dots-three"></label-view>`;
124
- for (const node of this.#colSlot?.assignedElements({ flatten: true }) ?? []) {
133
+ for (const node of this.#slots?.get('column')?.assignedElements({ flatten: true }) ?? []) {
125
134
  if (!node.matches('[is=table-column]'))
126
135
  continue;
127
136
  const btn = $(`<button type="button" tabindex="0">
@@ -129,7 +138,7 @@ export class TableView extends HTMLElement {
129
138
  <label-view></label-view>
130
139
  <label-view font="callout" foreground="secondary"></label-view>
131
140
  </v-stack>
132
- </button>`), title = btn.querySelector('label-view:first-child'), subTitle = btn.querySelector('label-view:last-child');
141
+ </button>`, '>1'), title = btn.querySelector('label-view:first-child'), subTitle = btn.querySelector('label-view:last-child');
133
142
  title?.setAttribute('title', node.textContent.trim());
134
143
  subTitle?.setAttribute('title', node.ariaSort ?? '');
135
144
  this.#compactToolbarItem.appendChild(btn);
@@ -164,7 +173,10 @@ export class TableView extends HTMLElement {
164
173
  }
165
174
  };
166
175
  #handleMenuClick = (evt) => {
167
- const btn = evt.target.closest('button');
176
+ const target = evt.target instanceof HTMLElement && evt.target;
177
+ if (!target)
178
+ return;
179
+ const btn = target.closest('button');
168
180
  if (!btn)
169
181
  return;
170
182
  const siblings = [...(btn.parentNode?.querySelectorAll(':scope>button') ?? [])];
@@ -23,12 +23,13 @@ export class TextField extends FormAssociatedBase {
23
23
  <input type="text" part="root input text-field-form-input">
24
24
  </div>
25
25
  <slot name="validity-options" hidden></slot>
26
- </label>`, ''));
26
+ </label>`));
27
27
  }
28
28
  #shadowRoot;
29
29
  // #internals: ElementInternals
30
30
  #customValidity = '';
31
- #validitiesSlot;
31
+ // #validitiesSlot?: HTMLSlotElement
32
+ #slots = new Map();
32
33
  #input;
33
34
  get #internals() {
34
35
  return getInternals(this);
@@ -37,9 +38,13 @@ export class TextField extends FormAssociatedBase {
37
38
  super();
38
39
  this.#shadowRoot = this.attachShadow({ mode: 'closed' });
39
40
  this.#shadowRoot.appendChild(document.importNode(this.constructor.template, true));
40
- this.#validitiesSlot = this.#shadowRoot.querySelector('slot[name=validity-options]') ?? undefined;
41
+ for (const slot of this.#shadowRoot.querySelectorAll('slot'))
42
+ this.#slots?.set(slot.name, slot);
43
+ CleanupRegistry.register(this, () => {
44
+ this.#slots = new Map();
45
+ });
41
46
  CleanupRegistry.unregister(this, 'validities');
42
- CleanupRegistry.register(this, onoff(makeSlotchangeHandler(this), this.#validitiesSlot).on(), 'validities');
47
+ CleanupRegistry.register(this, onoff(makeSlotchangeHandler(this), this.#slots?.get('validity-options')).on(), 'validities');
43
48
  this.#input = this.#shadowRoot.querySelector('input') ?? undefined;
44
49
  CleanupRegistry.register(this, onoff([{ types: 'focusin', listener: this.#handleFocusin }], this).on());
45
50
  CleanupRegistry.register(this, onoff([
@@ -137,7 +142,7 @@ export class TextField extends FormAssociatedBase {
137
142
  case 'label':
138
143
  let label = this.querySelector(':scope>[slot=label]');
139
144
  if (newValue) {
140
- label ??= this.appendChild($(`<span slot="label" foreground="secondary"></span>`));
145
+ label ??= this.appendChild($(`<span slot="label" foreground="secondary"></span>`, '>1'));
141
146
  label.textContent = newValue;
142
147
  }
143
148
  else
@@ -217,7 +222,7 @@ export class TextField extends FormAssociatedBase {
217
222
  };
218
223
  #handleInputPaste = (evt) => {
219
224
  console.debug(`${_a.name} ⚡️ ${evt?.type}`);
220
- const input = evt.target;
225
+ const input = evt.target instanceof HTMLInputElement && evt.target;
221
226
  if (!input)
222
227
  return;
223
228
  evt.preventDefault();
@@ -287,40 +292,40 @@ export class TextField extends FormAssociatedBase {
287
292
  const allowedSignsRegex2 = /^[+-]?$|^[+-]?(\d+([.,]\d*)?|[.,]\d*)$/, // allow single '+' or '-', then allow only one ',' or '.' and finally only digits
288
293
  digitsDecimalsOnlyRegex = /^(\d+([.,]\d*)?|[.,]\d*)?$/; // allow only one ',' or '.' and finally only digits
289
294
  return (this.negativeNumbersAllowed ? allowedSignsRegex2 : digitsDecimalsOnlyRegex).test(str);
290
- // // console.log(isValidDecimal("")); // true
291
- // // console.log(isValidDecimal("+")); // true
292
- // // console.log(isValidDecimal("-")); // true
293
- // // console.log(isValidDecimal("123")); // true
294
- // // console.log(isValidDecimal("+123")); // true
295
- // // console.log(isValidDecimal("-456")); // true
296
- // // console.log(isValidDecimal("12.34")); // true
297
- // // console.log(isValidDecimal("-0,56")); // true
298
- // // console.log(isValidDecimal(".78")); // true
299
- // // console.log(isValidDecimal(",9")); // true
300
- // // console.log(isValidDecimal("12.3.4")); // false
301
- // // console.log(isValidDecimal("12,3,4")); // false
302
- // // console.log(isValidDecimal("12-3")); // false
303
- // // console.log(isValidDecimal("12a")); // false
295
+ // // isValidDecimal(""); // true
296
+ // // isValidDecimal("+"); // true
297
+ // // isValidDecimal("-"); // true
298
+ // // isValidDecimal("123"); // true
299
+ // // isValidDecimal("+123"); // true
300
+ // // isValidDecimal("-456"); // true
301
+ // // isValidDecimal("12.34"); // true
302
+ // // isValidDecimal("-0,56"); // true
303
+ // // isValidDecimal(".78"); // true
304
+ // // isValidDecimal(",9"); // true
305
+ // // isValidDecimal("12.3.4"); // false
306
+ // // isValidDecimal("12,3,4"); // false
307
+ // // isValidDecimal("12-3"); // false
308
+ // // isValidDecimal("12a"); // false
304
309
  case 'number-pad':
305
310
  const allowedSignsRegex = /^([+-]|\d+|[+-]\d+)?$/, // allow single '+' or '-', then allow only digits
306
311
  digitsOnlyRegex = /^(\d+)?$/; // allow only digits
307
312
  return (this.negativeNumbersAllowed ? allowedSignsRegex : digitsOnlyRegex).test(str);
308
- // // console.log(isValidInteger("")); // true
309
- // // console.log(isValidInteger("+")); // true
310
- // // console.log(isValidInteger("-")); // true
311
- // // console.log(isValidInteger("123")); // true
312
- // // console.log(isValidInteger("+123")); // true
313
- // // console.log(isValidInteger("-456")); // true
314
- // // console.log(isValidInteger("12-3")); // false
315
- // // console.log(isValidInteger("++123")); // false
316
- // // console.log(isValidInteger("123a")); // false
313
+ // // isValidInteger(""); // true
314
+ // // isValidInteger("+"); // true
315
+ // // isValidInteger("-"); // true
316
+ // // isValidInteger("123"); // true
317
+ // // isValidInteger("+123"); // true
318
+ // // isValidInteger("-456"); // true
319
+ // // isValidInteger("12-3"); // false
320
+ // // isValidInteger("++123"); // false
321
+ // // isValidInteger("123a"); // false
317
322
  default:
318
323
  return true;
319
324
  }
320
325
  };
321
326
  #handleInputBeforeinput = (evt) => {
322
327
  console.debug(`${_a.name} ⚡️ ${evt?.type}`);
323
- const input = evt.target;
328
+ const input = evt.target instanceof HTMLInputElement && evt.target;
324
329
  if (!input)
325
330
  return;
326
331
  if ('insertText' !== evt.inputType)
@@ -355,7 +360,7 @@ export class TextField extends FormAssociatedBase {
355
360
  };
356
361
  #handleInputBlur = (evt) => {
357
362
  console.debug(`${_a.name} ⚡️ ${evt?.type}`);
358
- const input = evt.target;
363
+ const input = evt.target instanceof HTMLInputElement && evt.target;
359
364
  if (!input)
360
365
  return;
361
366
  if (0 === input.value.length)
@@ -426,7 +431,7 @@ export class TextField extends FormAssociatedBase {
426
431
  const key = k; // ✅ type-safe cast
427
432
  if (true !== flags[key])
428
433
  continue;
429
- for (const el of this.#validitiesSlot?.assignedElements({ flatten: true }) ?? []) {
434
+ for (const el of this.#slots?.get('validity-options')?.assignedElements({ flatten: true }) ?? []) {
430
435
  if (!el.matches('option'))
431
436
  continue;
432
437
  const option = el;