@swiftwc/ui 0.0.0-dev.99 → 1.0.0-canary.1

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 (209) hide show
  1. package/generated/client/index.js +8 -9
  2. package/generated/components/alert-dialog.js +9 -17
  3. package/generated/components/bordered-button.js +4 -7
  4. package/generated/components/bordered-prominent-button.js +4 -7
  5. package/generated/components/borderless-button.js +4 -7
  6. package/generated/components/color-scheme.js +4 -7
  7. package/generated/components/confirmation-dialog.js +9 -17
  8. package/generated/components/content-unavailable.d.ts +1 -1
  9. package/generated/components/content-unavailable.js +5 -8
  10. package/generated/components/{body-view.d.ts → content-view.d.ts} +2 -2
  11. package/generated/components/content-view.js +15 -0
  12. package/generated/components/date-picker.js +13 -25
  13. package/generated/components/detail-placeholder.d.ts +11 -0
  14. package/generated/components/detail-placeholder.js +15 -0
  15. package/generated/components/disclosure-group.js +5 -9
  16. package/generated/components/fine-tooltip.js +4 -7
  17. package/generated/components/form-view.js +3 -5
  18. package/generated/components/glass-button.js +4 -7
  19. package/generated/components/glass-prominent-button.js +4 -7
  20. package/generated/components/h-divider.d.ts +11 -0
  21. package/generated/components/h-divider.js +15 -0
  22. package/generated/components/h-flex-stack.d.ts +16 -0
  23. package/generated/components/h-flex-stack.js +18 -0
  24. package/generated/components/h-stack.js +3 -5
  25. package/generated/components/image-view.js +4 -7
  26. package/generated/components/index.d.ts +7 -1
  27. package/generated/components/index.js +7 -1
  28. package/generated/components/label-view.d.ts +2 -2
  29. package/generated/components/label-view.js +6 -9
  30. package/generated/components/labeled-content.d.ts +7 -1
  31. package/generated/components/labeled-content.js +32 -32
  32. package/generated/components/list-view.d.ts +5 -1
  33. package/generated/components/list-view.js +8 -6
  34. package/generated/components/menu-view.d.ts +1 -1
  35. package/generated/components/menu-view.js +11 -20
  36. package/generated/components/navigation-large-title.d.ts +0 -1
  37. package/generated/components/navigation-large-title.js +5 -10
  38. package/generated/components/navigation-split-view.js +4 -7
  39. package/generated/components/navigation-stack.js +4 -7
  40. package/generated/components/navigation-title.js +4 -7
  41. package/generated/components/picker-view.d.ts +4 -21
  42. package/generated/components/picker-view.js +374 -326
  43. package/generated/components/plain-button.js +3 -5
  44. package/generated/components/progress-view.d.ts +1 -1
  45. package/generated/components/progress-view.js +7 -12
  46. package/generated/components/screen-view.js +2 -3
  47. package/generated/components/scroll-view-proxy.js +3 -5
  48. package/generated/components/scroll-view.d.ts +1 -1
  49. package/generated/components/scroll-view.js +10 -17
  50. package/generated/components/search-view.js +4 -7
  51. package/generated/components/section-view.d.ts +1 -1
  52. package/generated/components/section-view.js +5 -8
  53. package/generated/components/sheet-view.js +6 -11
  54. package/generated/components/sidebar-toggle.js +5 -9
  55. package/generated/components/sidebar-view.js +2 -3
  56. package/generated/components/sticky-container.js +3 -5
  57. package/generated/components/tab-bar.js +4 -7
  58. package/generated/components/tab-item.js +8 -15
  59. package/generated/components/tab-view.js +19 -23
  60. package/generated/components/table-view.d.ts +1 -1
  61. package/generated/components/table-view.js +7 -12
  62. package/generated/components/text-field.js +10 -19
  63. package/generated/components/text-view.d.ts +11 -0
  64. package/generated/components/text-view.js +16 -0
  65. package/generated/components/toggle-view.d.ts +2 -0
  66. package/generated/components/toggle-view.js +33 -37
  67. package/generated/components/tool-bar-item-group.js +3 -5
  68. package/generated/components/tool-bar-item.js +4 -7
  69. package/generated/components/tool-bar.js +4 -7
  70. package/generated/components/v-divider.d.ts +11 -0
  71. package/generated/components/v-divider.js +15 -0
  72. package/generated/components/v-flex-stack.d.ts +16 -0
  73. package/generated/components/v-flex-stack.js +18 -0
  74. package/generated/components/v-keyboard.js +8 -12
  75. package/generated/components/v-stack.js +3 -5
  76. package/generated/css/index.css +762 -418
  77. package/generated/internal/class/css-style-observer.js +2 -3
  78. package/generated/internal/class/form-associated-base.js +6 -8
  79. package/generated/internal/class/navigation-path.js +2 -2
  80. package/generated/internal/class/navigation-view.js +3 -5
  81. package/generated/internal/decorators/adaptive-slot.js +4 -7
  82. package/generated/internal/decorators/microtask-on-connected.d.ts +2 -2
  83. package/generated/internal/decorators/microtask-on-connected.js +2 -2
  84. package/generated/internal/dev-flags.d.ts +4 -0
  85. package/generated/internal/dev-flags.js +1 -0
  86. package/generated/internal/privateNamespace.d.ts +2 -2
  87. package/generated/internal/privateNamespace.js +15 -24
  88. package/generated/internal/utils/$.d.ts +9 -0
  89. package/generated/internal/utils/$.js +11 -0
  90. package/generated/internal/utils/debug.d.ts +1 -0
  91. package/generated/internal/utils/debug.js +4 -0
  92. package/generated/internal/utils/index.d.ts +36 -2
  93. package/generated/internal/utils/index.js +36 -5
  94. package/generated/internal/utils/is-inside.js +1 -1
  95. package/generated/snapshot/index.js +3 -5
  96. package/{web-components.html-data → html-data}/en.json +155 -54
  97. package/package.json +24 -20
  98. package/scss/_components.scss +1 -1
  99. package/scss/_maps.scss +3 -1
  100. package/scss/_utils.scss +3 -1
  101. package/scss/_vars.scss +1 -0
  102. package/scss/base/_layout.scss +8 -8
  103. package/scss/base/_reboot.scss +4 -29
  104. package/scss/base/_root.scss +27 -12
  105. package/scss/colors/_index.scss +66 -1
  106. package/scss/components/_alert-dialog.scss +3 -3
  107. package/scss/components/_bordered-button.scss +2 -2
  108. package/scss/components/_bordered-prominent-button.scss +3 -3
  109. package/scss/components/_borderless-button.scss +2 -2
  110. package/scss/components/_confirmation-dialog.scss +1 -1
  111. package/scss/components/_content-unavailable.scss +1 -1
  112. package/scss/components/{_body-view.scss → _content-view.scss} +2 -2
  113. package/scss/components/_date-picker.scss +1 -1
  114. package/scss/components/_detail-placeholder.scss +5 -5
  115. package/scss/components/_disclosure-group.scss +2 -2
  116. package/scss/components/_fine-tooltip.scss +1 -1
  117. package/scss/components/_form-view.scss +3 -3
  118. package/scss/components/_full-screen.scss +1 -1
  119. package/scss/components/_glass-button.scss +2 -2
  120. package/scss/components/_glass-prominent-button.scss +3 -3
  121. package/scss/components/_group-box.scss +1 -1
  122. package/scss/components/_h-divider.scss +1 -1
  123. package/scss/components/_h-flex-stack.scss +3 -1
  124. package/scss/components/_h-stack.scss +1 -1
  125. package/scss/components/_image-view.scss +1 -1
  126. package/scss/components/_index.scss +34 -24
  127. package/scss/components/_label-view.scss +1 -1
  128. package/scss/components/_labeled-content.scss +1 -1
  129. package/scss/components/_list-view.scss +3 -3
  130. package/scss/components/_menu-view.scss +3 -3
  131. package/scss/components/_navigation-large-title.scss +15 -9
  132. package/scss/components/_navigation-split-view.scss +18 -18
  133. package/scss/components/_navigation-stack.scss +1 -1
  134. package/scss/components/_navigation-title.scss +1 -1
  135. package/scss/components/_picker-view.scss +159 -119
  136. package/scss/components/_plain-button.scss +2 -2
  137. package/scss/components/_progress-view.scss +1 -1
  138. package/scss/components/_scroll-view-proxy.scss +1 -1
  139. package/scss/components/_scroll-view-toolbars.scss +1 -1
  140. package/scss/components/_scroll-view.scss +2 -2
  141. package/scss/components/_search-view.scss +1 -1
  142. package/scss/components/_section-view.scss +1 -1
  143. package/scss/components/_sheet-view.scss +2 -2
  144. package/scss/components/_sidebar-toggle.scss +1 -1
  145. package/scss/components/_sidebar-view.scss +2 -2
  146. package/scss/components/_sticky-container.scss +1 -1
  147. package/scss/components/_tab-bar.scss +1 -1
  148. package/scss/components/_tab-item.scss +1 -1
  149. package/scss/components/_tab-view.scss +23 -15
  150. package/scss/components/_table-column.scss +1 -1
  151. package/scss/components/_table-row.scss +1 -1
  152. package/scss/components/_table-view.scss +1 -1
  153. package/scss/components/_text-field.scss +1 -1
  154. package/scss/components/_text-view.scss +1 -1
  155. package/scss/components/_toggle-view.scss +41 -21
  156. package/scss/components/_tool-bar-item-group.scss +1 -1
  157. package/scss/components/_tool-bar-item.scss +2 -2
  158. package/scss/components/_tool-bar.scss +2 -2
  159. package/scss/components/_v-divider.scss +1 -1
  160. package/scss/components/_v-flex-stack.scss +3 -1
  161. package/scss/components/_v-keyboard.scss +1 -1
  162. package/scss/components/_v-stack.scss +1 -1
  163. package/scss/final/_touch-glass.scss +2 -2
  164. package/scss/mixins/_index.scss +2 -2
  165. package/scss/placeholders/_buttons.scss +5 -5
  166. package/scss/placeholders/_lists.scss +3 -3
  167. package/scss/transitions/_alert-dialog.scss +1 -1
  168. package/scss/transitions/_bwd.navbar.scss +1 -1
  169. package/scss/transitions/_bwd.scss +3 -3
  170. package/scss/transitions/_confirmation-dialog.scss +1 -1
  171. package/scss/transitions/_disclosure-group.scss +1 -1
  172. package/scss/transitions/_fine-tooltip.scss +1 -1
  173. package/scss/transitions/_fwd.navbar.scss +1 -1
  174. package/scss/transitions/_fwd.scss +1 -1
  175. package/scss/transitions/_glass-button.scss +1 -1
  176. package/scss/transitions/_glass-prominent-button.scss +1 -1
  177. package/scss/transitions/_index.scss +1 -1
  178. package/scss/transitions/_menu-view.scss +1 -1
  179. package/scss/transitions/_navigation-split-view.scss +1 -1
  180. package/scss/transitions/_progress-view.scss +1 -1
  181. package/scss/transitions/_sheet-view.scss +1 -1
  182. package/scss/transitions/_sidebar-view.scss +1 -1
  183. package/scss/transitions/_tab-bar.scss +1 -1
  184. package/scss/utils/_background.scss +52 -0
  185. package/scss/utils/_frame.scss +2 -2
  186. package/scss/utils/_index.scss +33 -8
  187. package/scss/utils/_spacing.scss +1 -1
  188. package/scss/utils/_stacks.scss +5 -3
  189. package/generated/components/body-view.js +0 -17
  190. package/generated/internal/utils/cash/index.d.ts +0 -24
  191. package/generated/internal/utils/cash/index.js +0 -27
  192. package/generated/internal/utils/dev-flags.d.ts +0 -3
  193. package/generated/internal/utils/dev-flags.js +0 -5
  194. /package/{web-components.css-data → css-data}/en.json +0 -0
  195. /package/generated/internal/utils/{cash/ancestors.d.ts → ancestors.d.ts} +0 -0
  196. /package/generated/internal/utils/{cash/ancestors.js → ancestors.js} +0 -0
  197. /package/generated/internal/utils/{cash/next-all.d.ts → next-all.d.ts} +0 -0
  198. /package/generated/internal/utils/{cash/next-all.js → next-all.js} +0 -0
  199. /package/generated/internal/utils/{cash/next.d.ts → next.d.ts} +0 -0
  200. /package/generated/internal/utils/{cash/next.js → next.js} +0 -0
  201. /package/generated/internal/utils/{cash/prev-all.d.ts → prev-all.d.ts} +0 -0
  202. /package/generated/internal/utils/{cash/prev-all.js → prev-all.js} +0 -0
  203. /package/generated/internal/utils/{cash/prev.d.ts → prev.d.ts} +0 -0
  204. /package/generated/internal/utils/{cash/prev.js → prev.js} +0 -0
  205. /package/generated/internal/utils/{cash/prop.d.ts → prop.d.ts} +0 -0
  206. /package/generated/internal/utils/{cash/prop.js → prop.js} +0 -0
  207. /package/generated/internal/utils/{cash/siblings.d.ts → siblings.d.ts} +0 -0
  208. /package/generated/internal/utils/{cash/siblings.js → siblings.js} +0 -0
  209. /package/scss/utils/{_scroll-view.scss → _scroll-view.scss.txt} +0 -0
@@ -5,13 +5,12 @@ 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 { $, devFlags, kebabCase, onoff } from '../internal/utils';
8
+ import { $, ancestors, debug, kebabCase, onoff } from '../internal/utils';
9
9
  import { queryMorph } from '../morphdom';
10
10
  import { html, render } from '../tpl';
11
- const pickerStyles = ['menu', 'inline', 'navigation-link', 'sheet', 'automatic'];
11
+ const pickerStyles = ['menu', 'inline', 'navigation-link', 'sheet', 'radio-group', 'automatic'];
12
12
  const update = (path, node, overwrite = true) => {
13
- if (devFlags.debug)
14
- console.debug(`PickerView: update`);
13
+ debug(`PickerView: update`);
15
14
  if (!(path instanceof NavigationPath))
16
15
  throw new Error('invalid view');
17
16
  const { component, page } = path;
@@ -23,8 +22,7 @@ const update = (path, node, overwrite = true) => {
23
22
  page.insertAdjacentElement(position, node);
24
23
  };
25
24
  const reflectSpawnedPage = (current, source) => {
26
- if (devFlags.debug)
27
- console.debug(`PickerView: reflectSpawnedPage`);
25
+ debug(`PickerView: reflectSpawnedPage`);
28
26
  const { page: oldSv, toolBarConfig: oldToolbar } = new NavigationPath(current).hydrate(), { page: newSv, toolBarConfig: newToolbar } = new NavigationPath(source).hydrate();
29
27
  const oldList = oldSv?.querySelector('list-view'), newList = newSv?.querySelector('list-view'), oldBackBtn = oldToolbar?.at(0)?.querySelector('button'), newBackBtn = newToolbar?.at(0)?.querySelector('button');
30
28
  // pre replace list (always exists)
@@ -62,12 +60,10 @@ const reflectSpawnedPage = (current, source) => {
62
60
  oldSearch?.remove();
63
61
  };
64
62
  const extractTag = (node) => {
65
- if (devFlags.debug)
66
- console.debug(`PickerView: extractTag`);
63
+ debug(`PickerView: extractTag`);
67
64
  return node instanceof HTMLOptionElement ? (((node.getAttribute('value') ?? node.textContent?.trim()) || node.getAttribute('label')) ?? '') : (node.value ?? '');
68
65
  }, extractLabel = (node) => {
69
- if (devFlags.debug)
70
- console.debug(`PickerView: extractLabelFromGroup`);
66
+ debug(`PickerView: extractLabelFromGroup`);
71
67
  if (node instanceof Element)
72
68
  if (node instanceof HTMLOptionElement)
73
69
  return (node.getAttribute('label') ?? node.getAttribute('value') ?? node.textContent?.trim()) || null;
@@ -77,16 +73,14 @@ const extractTag = (node) => {
77
73
  return node.title ?? node.value ?? null;
78
74
  // return node instanceof Element ? node.getAttribute('DATALIST' === node.tagName ? 'data-label' : 'label') : (node.title ?? node.value ?? null)
79
75
  }, extractIcon = (node) => {
80
- if (devFlags.debug)
81
- console.debug(`PickerView: extractIcon`);
76
+ debug(`PickerView: extractIcon`);
82
77
  // return node instanceof Element ? node.getAttribute('data-system-image') : (node.systemImage ?? null)
83
78
  if (node instanceof Element)
84
79
  return node.getAttribute('data-system-image');
85
80
  else
86
81
  return node.systemImage ?? null;
87
82
  }, extractSubtitle = (node) => {
88
- if (devFlags.debug)
89
- console.debug(`PickerView: extractSubtitle`);
83
+ debug(`PickerView: extractSubtitle`);
90
84
  if (node instanceof Element)
91
85
  return node.getAttribute('data-subtitle');
92
86
  else
@@ -115,42 +109,73 @@ const indexGroups = (nodes, parentPath = '') => {
115
109
  return map;
116
110
  };
117
111
  const collectLeafValues = (node) => (node.children.length ? node.children.flatMap(collectLeafValues) : [node.value]);
112
+ const flattenDictionary = (tree) => {
113
+ const out1 = {}, out2 = {}, stack = [tree], idx = [0];
114
+ while (stack.length) {
115
+ const frame = stack[stack.length - 1], i = idx[idx.length - 1];
116
+ if (i >= frame.length) {
117
+ stack.pop();
118
+ idx.pop();
119
+ continue;
120
+ }
121
+ idx[idx.length - 1]++;
122
+ const { value, title, systemImage, children } = frame[i];
123
+ out1[value] = title;
124
+ out2[value] = systemImage;
125
+ if (children.length) {
126
+ stack.push(children);
127
+ idx.push(0);
128
+ }
129
+ }
130
+ return { labels: out1, icons: out2 };
131
+ };
118
132
  /**
119
133
  * @summary A control that selects one value from a set of options.
120
134
  *
121
- * @attr {menu|inline|navigation-link|sheet|automatic} picker-style
122
- *
123
- * @attr help — Adds a help tooltip to the trigger of the picker, if style supports one
124
- *
125
- * @attr {DictEntry[]} dictionary — Renders all options using this array
126
- *
127
135
  * @attr {vertical|horizontal|auto} label-value-placement
128
136
  *
129
- * @slot — The default slot.
137
+ * @attr {boolean} horizontal-radio-group-layout
138
+ *
139
+ * @slot — The default slot
130
140
  * @slot label
131
141
  * @slot list
132
142
  * @slot {HTMLOptionElement[]} validity-options
133
143
  */
134
144
  export class PickerView extends FormAssociatedBase {
135
- static get ATTR() {
136
- return {
137
- PLACEHOLDER: 'prompt',
138
- PLACEHOLDER_ICON: 'prompt-icon',
139
- LABEL: 'label',
140
- PICKER_STYLE: 'picker-style',
141
- SELECTION: 'selection',
142
- SEARCHABLE: 'searchable',
143
- CURRENT_VALUE_LABEL: 'current-value-label',
144
- CURRENT_VALUE_ICON: 'current-value-icon',
145
- TRIGGER_HELP: 'help',
146
- DICTIONARY: 'dictionary',
147
- REQUIRED: 'required',
148
- };
149
- }
150
145
  static get observedAttributes() {
151
- return Object.values(this.ATTR);
146
+ return [
147
+ 'prompt',
148
+ 'prompt-icon',
149
+ 'label',
150
+ 'name',
151
+ /**
152
+ * @type {menu|inline|navigation-link|sheet|automatic}
153
+ */
154
+ 'picker-style',
155
+ 'selection',
156
+ /**
157
+ * @type {boolean}
158
+ */
159
+ 'searchable',
160
+ 'current-value-label',
161
+ 'current-value-icon',
162
+ /**
163
+ * Adds a help tooltip to the trigger of the picker, if style supports one
164
+ */
165
+ 'help',
166
+ /**
167
+ * Renders all options using this array
168
+ * @type {DictEntry[]}
169
+ */
170
+ 'dictionary',
171
+ /**
172
+ * @type {boolean}
173
+ */
174
+ 'required',
175
+ ];
152
176
  }
153
177
  static #templates = new Map();
178
+ #guuid = self.crypto.randomUUID();
154
179
  #spawn;
155
180
  #makeGroupClickHandler(el, groupId) {
156
181
  return async (evt) => {
@@ -159,7 +184,7 @@ export class PickerView extends FormAssociatedBase {
159
184
  const { target } = evt;
160
185
  if (!(target instanceof HTMLElement))
161
186
  return;
162
- const newPage = this.#spawnPage(el instanceof Element ? Array.from(el.children) : el.children, 'body-view', groupId, this.hasAttribute('searchable'), extractLabel(el));
187
+ const newPage = this.#spawnPage(el instanceof Element ? Array.from(el.children) : el.children, 'content-view', groupId, this.hasAttribute('searchable'), extractLabel(el));
163
188
  if (!newPage)
164
189
  return;
165
190
  newPage.dataset.groupId = groupId; // <-- tag the spawned page
@@ -171,9 +196,36 @@ export class PickerView extends FormAssociatedBase {
171
196
  };
172
197
  }
173
198
  #spawnPage = (elements, tag, parentGroupId, searchable = false, title) => {
174
- if (devFlags.debug)
175
- console.debug(`${_a.name} #spawnPage`);
176
- const body = $(html `<${'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="${'sheet-view' === tag ? 'x' : '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');
199
+ debug(`${_a.name} #spawnPage`);
200
+ const body = tag === 'sheet-view'
201
+ ? $(html `<dialog is="sheet-view">
202
+ <scroll-view>
203
+ <v-stack placement="leading fill">
204
+ <list-view preferred-expanded-style="inset"></list-view>
205
+ </v-stack>
206
+ </scroll-view>
207
+ <tool-bar>
208
+ <tool-bar-item slot="top-bar-leading">
209
+ <button type="button" tabindex="0">
210
+ <label-view system-image="x"></label-view>
211
+ </button>
212
+ </tool-bar-item>
213
+ </tool-bar>
214
+ </dialog>`, '>1')
215
+ : $(html `<content-view>
216
+ <scroll-view>
217
+ <v-stack placement="leading fill">
218
+ <list-view preferred-expanded-style="inset"></list-view>
219
+ </v-stack>
220
+ </scroll-view>
221
+ <tool-bar>
222
+ <tool-bar-item slot="top-bar-leading">
223
+ <button type="button" tabindex="0">
224
+ <label-view system-image="caret-left"></label-view>
225
+ </button>
226
+ </tool-bar-item>
227
+ </tool-bar>
228
+ </content-view>`, '>1'), sv = body.querySelector('scroll-view'), list = body.querySelector('list-view'), backBtn = body.querySelector('button');
177
229
  if (title)
178
230
  sv?.setAttribute('navigation-inline-title', title);
179
231
  if (searchable) {
@@ -226,15 +278,15 @@ export class PickerView extends FormAssociatedBase {
226
278
  if (el instanceof Element)
227
279
  switch (el.tagName) {
228
280
  case 'OPTGROUP': {
229
- const group = _a.#wrapOptgroupTag(el);
230
- _a.#reflectButtons([...el.children], group);
281
+ const group = this.#wrapOptgroupTag(el);
282
+ this.#reflectButtons([...el.children], group);
231
283
  for (const btn of group.querySelectorAll(':scope>button'))
232
284
  btn.addEventListener('click', this.#handlePageBtnClick);
233
285
  list?.appendChild(group);
234
286
  break;
235
287
  }
236
288
  case 'OPTION': {
237
- const btn = _a.#wrapOptionTag(el);
289
+ const btn = this.#wrapOptionTag(el);
238
290
  btn.addEventListener('click', this.#handlePageBtnClick);
239
291
  list?.appendChild(btn);
240
292
  break;
@@ -258,8 +310,8 @@ export class PickerView extends FormAssociatedBase {
258
310
  else {
259
311
  if (el.children.length)
260
312
  if (allLeaves(el)) {
261
- const group = _a.#wrapOptgroupTag(el);
262
- _a.#reflectButtons(el.children, group);
313
+ const group = this.#wrapOptgroupTag(el);
314
+ this.#reflectButtons(el.children, group);
263
315
  for (const btn of group.querySelectorAll(':scope>button'))
264
316
  btn.addEventListener('click', this.#handlePageBtnClick);
265
317
  list?.appendChild(group);
@@ -272,7 +324,7 @@ export class PickerView extends FormAssociatedBase {
272
324
  list?.appendChild(btn);
273
325
  }
274
326
  else {
275
- const btn = _a.#wrapOptionTag(el);
327
+ const btn = this.#wrapOptionTag(el);
276
328
  btn.addEventListener('click', this.#handlePageBtnClick);
277
329
  list?.appendChild(btn);
278
330
  }
@@ -284,8 +336,8 @@ export class PickerView extends FormAssociatedBase {
284
336
  if (!this.#spawn)
285
337
  return;
286
338
  const groupMap = indexGroups(freshRoot);
287
- for (const el of this.#spawn.querySelectorAll('body-view')) {
288
- const depth = $.ancestors('body-view,[is=sheet-view]', el).indexOf(this.#spawn);
339
+ for (const el of this.#spawn.querySelectorAll('content-view')) {
340
+ const depth = ancestors('content-view,[is=sheet-view]', el).indexOf(this.#spawn);
289
341
  if (0 >= depth)
290
342
  continue;
291
343
  const groupId = el.dataset.groupId;
@@ -296,38 +348,18 @@ export class PickerView extends FormAssociatedBase {
296
348
  }
297
349
  const children = source instanceof Element ? Array.from(source.children) : source.children;
298
350
  const title = source instanceof Element ? extractLabel(source) : (source.title ?? null);
299
- const newPage = this.#spawnPage(children, 'body-view', groupId, this.hasAttribute('searchable'), title);
351
+ const newPage = this.#spawnPage(children, 'content-view', groupId, this.hasAttribute('searchable'), title);
300
352
  newPage.dataset.groupId = groupId;
301
353
  reflectSpawnedPage(el, newPage);
302
354
  }
303
355
  };
304
356
  #renderButtons(input) {
305
- if (devFlags.debug)
306
- console.debug(`${_a.name} #renderButtons`);
357
+ debug(`${_a.name} #renderButtons`);
307
358
  switch (input.mode) {
308
359
  case 'dictionary': {
309
- const flattenDictionary = (tree) => {
310
- const out1 = {}, out2 = {}, stack = [tree], idx = [0];
311
- while (stack.length) {
312
- const frame = stack[stack.length - 1], i = idx[idx.length - 1];
313
- if (i >= frame.length) {
314
- stack.pop();
315
- idx.pop();
316
- continue;
317
- }
318
- idx[idx.length - 1]++;
319
- const { value, title, systemImage, children } = frame[i];
320
- out1[value] = title;
321
- out2[value] = systemImage;
322
- if (children.length) {
323
- stack.push(children);
324
- idx.push(0);
325
- }
326
- }
327
- return { labels: out1, icons: out2 };
328
- };
329
- this.#lastRenderedLabelMap = flattenDictionary(input.source).labels;
330
- this.#lastRenderedIconMap = flattenDictionary(input.source).icons;
360
+ const { labels, icons } = flattenDictionary(input.source);
361
+ this.#lastRenderedLabelMap = labels;
362
+ this.#lastRenderedIconMap = icons;
331
363
  // const collectLeafValues = (node: DictEntry): string[] => (node.children.length ? node.children.flatMap(collectLeafValues) : [node.value])
332
364
  // collectGroups = (nodes: DictEntry[]): string[][] => {
333
365
  // const groups: string[][] = []
@@ -384,24 +416,24 @@ export class PickerView extends FormAssociatedBase {
384
416
  el.remove();
385
417
  CleanupRegistry.unregister(this, 'trigger');
386
418
  CleanupRegistry.register(this, onoff('click', this.#handleTriggerClick, currentValueLabel).on(), 'trigger');
387
- if (this.hasAttribute(this.constructor.ATTR.TRIGGER_HELP))
388
- currentValueLabel?.setAttribute(this.constructor.ATTR.TRIGGER_HELP, this.getAttribute(this.constructor.ATTR.TRIGGER_HELP) ?? '');
419
+ if (this.hasAttribute('help'))
420
+ currentValueLabel?.setAttribute('help', this.getAttribute('help') ?? '');
389
421
  // rebuild snapshot(tree)
390
422
  if (!this.#spawn)
391
423
  break;
392
424
  // rerender level 0
393
- reflectSpawnedPage(this.#spawn, this.#spawnPage(input.source, 'DIALOG' === this.#spawn.tagName ? 'sheet-view' : 'body-view', undefined, this.hasAttribute('searchable'), this.getAttribute('label')));
425
+ reflectSpawnedPage(this.#spawn, this.#spawnPage(input.source, 'DIALOG' === this.#spawn.tagName ? 'sheet-view' : 'content-view', undefined, this.hasAttribute('searchable'), this.getAttribute('label')));
394
426
  this.#resyncSpawnedPages(input.source);
395
427
  // // FIXME:
396
- // for (const el of this.#spawn.querySelectorAll<HTMLElement>('body-view')) {
397
- // const depth = $.ancestors('body-view,[is=sheet-view]', el).indexOf(this.#spawn)
428
+ // for (const el of this.#spawn.querySelectorAll<HTMLElement>('content-view')) {
429
+ // const depth = $.ancestors('content-view,[is=sheet-view]', el).indexOf(this.#spawn)
398
430
  // if (0 >= depth) continue
399
431
  // const datalist = this.querySelector<HTMLElement>(`:scope>${Array.from({ length: depth }, () => 'datalist').join('>')}`)
400
432
  // if (!datalist) {
401
433
  // el.remove()
402
434
  // break
403
435
  // }
404
- // reflectSpawnedElement(el, this.#spawnPage(Array.from(datalist.children), 'body-view', this.hasAttribute('searchable'), datalist.dataset.label))
436
+ // reflectSpawnedElement(el, this.#spawnPage(Array.from(datalist.children), 'content-view', this.hasAttribute('searchable'), datalist.dataset.label))
405
437
  // }
406
438
  break;
407
439
  }
@@ -419,9 +451,21 @@ export class PickerView extends FormAssociatedBase {
419
451
  // renderLabelIcon(currentValueLabel, 'dots-three') // overwritten
420
452
  // renderLabelTitle(currentValueLabel, this.#currentValueLabel) // overwritten
421
453
  // }
422
- if (this.hasAttribute(this.constructor.ATTR.TRIGGER_HELP))
423
- currentValueLabel?.setAttribute(this.constructor.ATTR.TRIGGER_HELP, this.getAttribute(this.constructor.ATTR.TRIGGER_HELP) ?? '');
424
- _a.#reflectButtons(input.source, menu);
454
+ if (this.hasAttribute('help'))
455
+ currentValueLabel?.setAttribute('help', this.getAttribute('help') ?? '');
456
+ this.#reflectButtons(input.source, menu);
457
+ break;
458
+ }
459
+ case 'radio-group': {
460
+ // capture
461
+ // const stack = this.querySelector<HTMLElement>(':scope>v-stack:not([slot])') ?? this.appendChild<HTMLElement>($(html`<v-stack></v-stack>`, '>1'))
462
+ // reset state
463
+ // stack.innerHTML = ''
464
+ // clear all siblings
465
+ for (const el of this.querySelectorAll(':scope>:not([slot])'))
466
+ el.remove();
467
+ // add buttons
468
+ this.#reflectButtons(input.source, this);
425
469
  break;
426
470
  }
427
471
  case 'inline':
@@ -435,38 +479,38 @@ export class PickerView extends FormAssociatedBase {
435
479
  if (inlineList !== el)
436
480
  el.remove();
437
481
  // add label as a plain element
438
- const value = this.getAttribute(this.constructor.ATTR.LABEL);
482
+ const value = this.getAttribute('label');
439
483
  if (value) {
440
- const hStack = $(html `<h-stack distribution="leading" template="auto spacer"
441
- ><label-view data-role="check" style="visibility: hidden"><image-view slot="icon" system-name="check"></image-view></label-view><label-view><span></span></label-view
442
- ></h-stack>`, '>1');
484
+ const hStack = $(html `<h-stack distribution="leading" template="auto spacer">
485
+ <label-view data-role="check" style="visibility: hidden">
486
+ <image-view slot="icon" system-name="check"></image-view>
487
+ </label-view>
488
+ <label-view><span></span></label-view>
489
+ </h-stack>`, '>1');
443
490
  queryMorph('label-view:nth-child(2)', html `<label-view>${value ? html `<span>${value}</span>` : null}</label-view>`, hStack);
444
491
  // if (label) renderLabelTitle(label, value) //label.setAttribute('title', value)
445
492
  section.insertAdjacentElement('beforeend', hStack);
446
493
  }
447
494
  if ('dictionary' === input.mode)
448
- _a.#reflectButtons(input.source.filter((el) => 0 === el.children.length), section);
495
+ this.#reflectButtons(input.source.filter((el) => 0 === el.children.length), section);
449
496
  else
450
- _a.#reflectButtons(input.source.filter((el) => el.matches('option')), section);
497
+ this.#reflectButtons(input.source.filter((el) => el.matches('option')), section);
451
498
  break;
452
499
  }
453
500
  }
454
501
  this.#reflectSelectionOnButtons();
455
502
  this.#reflectSelectionOnCurrentValueLabel();
456
503
  }
457
- #renderDictionary = (dictionary) => {
458
- if (devFlags.debug)
459
- console.debug(`${_a.name} ⚡️ mutation`);
460
- this.#renderButtons({ mode: 'dictionary', source: dictionary });
461
- };
504
+ // #renderDictionary = (dictionary: Dictionary) => {
505
+ // debug(`${PickerView.name} ⚡️ mutation`)
506
+ // this.#renderButtons({ mode: 'dictionary', source: dictionary })
507
+ // }
462
508
  #renderSlotted = (entries) => {
463
- if (devFlags.debug)
464
- console.debug(`${_a.name} ⚡️ mutation`);
465
- this.#renderButtons({ mode: 'list', source: this.#slots?.get('list')?.assignedElements({ flatten: true }) ?? [] });
509
+ debug(`${_a.name} ⚡️ mutation`);
510
+ this.#renderButtons(this.#resolveSource()); //this.#renderButtons({ mode: 'list', source: this.#slots?.get('list')?.assignedElements({ flatten: true }) ?? [] })
466
511
  };
467
512
  #renderValidityMsgs = (entries) => {
468
- if (devFlags.debug)
469
- console.debug(`${_a.name} ⚡️ mutation`);
513
+ debug(`${_a.name} ⚡️ mutation`);
470
514
  this.setValidity(this.validity, this.validationMessage);
471
515
  };
472
516
  #lastRenderedStyle; //string | null
@@ -491,11 +535,10 @@ export class PickerView extends FormAssociatedBase {
491
535
  #lastRenderedIconMap = {};
492
536
  #lastIndexedRoot = [];
493
537
  get #currentValueLabel() {
494
- return ((this.getAttribute(this.constructor.ATTR.CURRENT_VALUE_LABEL) ?? '').replaceAll('{{selection}}', this.#selection).replaceAll('{{currentValueLabel}}', this.#selection) ||
495
- this.#lastRenderedLabelMap[this.#selection]);
538
+ return ((this.getAttribute('current-value-label') ?? '').replaceAll('{{selection}}', this.#selection).replaceAll('{{currentValueLabel}}', this.#selection) || this.#lastRenderedLabelMap[this.#selection]);
496
539
  }
497
540
  get #currentValueIcon() {
498
- return (this.getAttribute(this.constructor.ATTR.CURRENT_VALUE_ICON) ?? '') || this.#lastRenderedIconMap[this.#selection];
541
+ return (this.getAttribute('current-value-icon') ?? '') || this.#lastRenderedIconMap[this.#selection];
499
542
  }
500
543
  get #internals() {
501
544
  return getInternals(this);
@@ -531,32 +574,46 @@ export class PickerView extends FormAssociatedBase {
531
574
  <slot name="validity-options" hidden></slot>
532
575
  </label>
533
576
  `));
534
- // break
535
- // case 'compact':
536
- // PickerView.#templates.set(
537
- // style,
538
- // Object.assign(document.createElement('template'), {
539
- // innerHTML: String.raw`
540
- // <label part="compact-picker">
541
- // <input type="text" part="compact-input">
542
- // </label>
543
- // `,
544
- // })
545
- // )
546
- // break
547
- // case 'fancy':
548
- // PickerView.#templates.set(
549
- // style,
550
- // Object.assign(document.createElement('template'), {
551
- // innerHTML: String.raw`
552
- // <div part="fancy-picker">
553
- // <span>Fancy Picker</span>
554
- // <input type="text" part="fancy-input">
555
- // </div>
556
- // `,
557
- // })
558
- // )
559
577
  break;
578
+ case 'radio-group':
579
+ _a.#templates.set(this.pickerStyle, $(html `
580
+ <label part="root picker-stack">
581
+ <div part="root picker-label-stack">
582
+ <slot name="label"></slot>
583
+ </div>
584
+ <div part="root picker-input-stack">
585
+ <slot></slot>
586
+ </div>
587
+ <slot name="list" hidden></slot>
588
+ <slot name="validity-options" hidden></slot>
589
+ </label>
590
+ `));
591
+ break;
592
+ // break
593
+ // case 'compact':
594
+ // PickerView.#templates.set(
595
+ // style,
596
+ // Object.assign(document.createElement('template'), {
597
+ // innerHTML: String.raw`
598
+ // <label part="compact-picker">
599
+ // <input type="text" part="compact-input">
600
+ // </label>
601
+ // `,
602
+ // })
603
+ // )
604
+ // break
605
+ // case 'fancy':
606
+ // PickerView.#templates.set(
607
+ // style,
608
+ // Object.assign(document.createElement('template'), {
609
+ // innerHTML: String.raw`
610
+ // <div part="fancy-picker">
611
+ // <span>Fancy Picker</span>
612
+ // <input type="text" part="fancy-input">
613
+ // </div>
614
+ // `,
615
+ // })
616
+ // )
560
617
  // case 'gg':
561
618
  // PickerView.#templates.set(
562
619
  // style,
@@ -598,68 +655,75 @@ export class PickerView extends FormAssociatedBase {
598
655
  this.#shadowRoot = this.attachShadow({ mode: 'closed' });
599
656
  }
600
657
  attributeChangedCallback(name, oldValue, newValue) {
601
- if (devFlags.debug)
602
- console.debug(`${_a.name} ⚡️ attr-change [${name}] ("${oldValue}" → "${newValue}")`);
658
+ debug(`${_a.name} ⚡️ attr-change [${name}] ("${oldValue}" → "${newValue}")`);
603
659
  switch (name) {
604
- case this.constructor.ATTR.PLACEHOLDER:
605
- case this.constructor.ATTR.PLACEHOLDER_ICON:
660
+ // case 'horizontal-radio-group-layout':
661
+ // if (oldValue === newValue) break
662
+ // this.#renderSlotted([])
663
+ // break
664
+ case 'prompt':
665
+ case 'prompt-icon':
606
666
  if (oldValue === newValue)
607
667
  break;
608
668
  this.#reflectSelectionOnCurrentValueLabel(); //this.#reflectPlaceholder(newValue)
609
669
  break;
610
- case this.constructor.ATTR.LABEL:
670
+ case 'label':
611
671
  this.#reflectLabel(newValue);
612
672
  // this.#sendValueToForm()
613
673
  break;
614
- case this.constructor.ATTR.PICKER_STYLE:
674
+ case 'picker-style':
615
675
  if (oldValue === newValue)
616
676
  break;
617
677
  this.#render();
618
678
  break;
619
- case this.constructor.ATTR.SEARCHABLE:
679
+ case 'searchable':
620
680
  if (oldValue === newValue)
621
681
  break;
622
682
  this.#renderSlotted([]);
623
683
  break;
624
- case this.constructor.ATTR.CURRENT_VALUE_LABEL:
625
- case this.constructor.ATTR.CURRENT_VALUE_ICON:
684
+ case 'current-value-label':
685
+ case 'current-value-icon':
626
686
  // if (oldValue === newValue) break
627
687
  this.#reflectSelectionOnCurrentValueLabel();
628
688
  break;
629
- case this.constructor.ATTR.TRIGGER_HELP:
689
+ case 'help':
630
690
  // if (oldValue === newValue) break
631
691
  this.#reflectTriggerHelp();
632
692
  break;
633
- case this.constructor.ATTR.DICTIONARY:
693
+ case 'dictionary':
634
694
  if (oldValue === newValue)
635
695
  break;
636
- this.#renderDictionary(parseDictionary(newValue));
696
+ this.#renderSlotted([]); // re-resolve: dictionary present → wins; removed → falls back to slotted //this.#renderDictionary(parseDictionary(newValue))
637
697
  break;
638
- case this.constructor.ATTR.REQUIRED:
698
+ case 'name':
699
+ case 'required':
639
700
  if (oldValue === newValue)
640
701
  break;
641
702
  this.#sendValueToForm(false);
642
703
  break;
643
- case this.constructor.ATTR.SELECTION:
644
- // nothing happens
704
+ case 'selection':
705
+ if (oldValue === newValue)
706
+ break;
707
+ this.#selection = newValue ?? '';
708
+ // FIXME: What about other callbacks from this.#selection=???? Somehow they run correctly
709
+ this.#sendValueToForm(false);
645
710
  break;
646
711
  }
647
712
  }
648
713
  disconnectedCallback() {
649
- if (devFlags.debug)
650
- console.debug(`${_a.name} ⚡️ disconnect`);
714
+ debug(`${_a.name} ⚡️ disconnect`);
651
715
  CleanupRegistry.unregister(this);
652
716
  this.#validityObservers.unobserveAll();
653
717
  this.#observers.unobserveAll();
654
718
  }
655
719
  connectedCallback() {
656
- if (devFlags.debug)
657
- console.debug(`${_a.name} ⚡️ connect`);
720
+ debug(`${_a.name} ⚡️ connect`);
658
721
  CleanupRegistry.register(this, onoff('localechange', () => {
659
722
  this.#renderSlotted([]);
660
723
  }, I18n.on).on());
661
724
  CleanupRegistry.register(this, onoff('click', this.#handleClick, this).on());
662
- if (!this.hasAttribute(this.constructor.ATTR.PICKER_STYLE))
725
+ CleanupRegistry.register(this, onoff('input', this.#handleInput, this).on());
726
+ if (!this.hasAttribute('picker-style'))
663
727
  this.#render(); // skip if already rendered by attr-change during upgrade!
664
728
  // finally
665
729
  if (!this.hasAttribute('selection'))
@@ -668,13 +732,17 @@ export class PickerView extends FormAssociatedBase {
668
732
  this.#sendValueToForm(false);
669
733
  }
670
734
  get pickerStyle() {
671
- const attr = this.constructor.ATTR.PICKER_STYLE;
735
+ const attr = 'picker-style';
672
736
  return pickerStyles.includes(this.getAttribute(attr) ?? '') ? this.getAttribute(attr) : 'automatic';
673
737
  }
738
+ #resolveSource() {
739
+ if (this.hasAttribute('dictionary'))
740
+ return { mode: 'dictionary', source: parseDictionary(this.getAttribute('dictionary')) };
741
+ return { mode: 'list', source: this.#slots?.get('list')?.assignedElements({ flatten: true }) ?? [] };
742
+ }
674
743
  #render() {
675
- if (devFlags.debug)
676
- console.debug(`${_a.name} ⚡️ #render (${this.pickerStyle})`);
677
- // const style = this.getAttribute((this.constructor as typeof PickerView).ATTR.PICKER_STYLE)
744
+ debug(`${_a.name} ⚡️ #render (${this.pickerStyle})`);
745
+ // const style = this.getAttribute('picker-style')
678
746
  if (this.#lastRenderedStyle === this.pickerStyle)
679
747
  return; // skip if already applied
680
748
  this.#lastRenderedStyle = this.pickerStyle;
@@ -714,12 +782,13 @@ export class PickerView extends FormAssociatedBase {
714
782
  this.dispatchEvent(new CustomEvent('selection', { detail: { selection: this.#selection }, bubbles: true, composed: true }));
715
783
  };
716
784
  #handleTriggerClick = async ({ type, target }) => {
717
- if (devFlags.debug)
718
- console.debug(`${_a.name} ⚡️ ${type}`);
785
+ debug(`${_a.name} ⚡️ ${type}`);
719
786
  if (!(target instanceof HTMLElement))
720
787
  return;
721
788
  this.#spawn?.remove?.();
722
- const level0 = this.#spawnPage(this.hasAttribute(this.constructor.ATTR.DICTIONARY) ? parseDictionary(this.getAttribute('dictionary')) : (this.#slots?.get('list')?.assignedElements() ?? []), 'sheet' === this.pickerStyle ? 'sheet-view' : 'body-view', undefined, this.hasAttribute('searchable'), this.getAttribute('label'));
789
+ const { source } = this.#resolveSource();
790
+ const level0 = this.#spawnPage(source, // this.hasAttribute('dictionary') ? parseDictionary(this.getAttribute('dictionary')) : (this.#slots?.get('list')?.assignedElements() ?? []),
791
+ 'sheet' === this.pickerStyle ? 'sheet-view' : 'content-view', undefined, this.hasAttribute('searchable'), this.getAttribute('label'));
723
792
  if (!level0)
724
793
  return;
725
794
  const path = new NavigationPath(target)?.hydrate();
@@ -730,8 +799,7 @@ export class PickerView extends FormAssociatedBase {
730
799
  });
731
800
  };
732
801
  #handlePageBtnClick = async (evt) => {
733
- if (devFlags.debug)
734
- console.debug(`${_a.name} ⚡️ ${evt?.type}`);
802
+ debug(`${_a.name} ⚡️ ${evt?.type}`);
735
803
  evt.stopImmediatePropagation();
736
804
  evt.preventDefault();
737
805
  const { currentTarget: btn } = evt;
@@ -754,8 +822,7 @@ export class PickerView extends FormAssociatedBase {
754
822
  });
755
823
  };
756
824
  #handleClick({ type, target }) {
757
- if (devFlags.debug)
758
- console.debug(`${_a.name} ⚡️ ${type}`);
825
+ debug(`${_a.name} ⚡️ ${type}`);
759
826
  if (!(target instanceof HTMLElement))
760
827
  return;
761
828
  const btn = target.closest('button');
@@ -766,9 +833,24 @@ export class PickerView extends FormAssociatedBase {
766
833
  this.#reflectSelectionOnCurrentValueLabel();
767
834
  this.#sendValueToForm();
768
835
  }
836
+ #handleInput({ type, target }) {
837
+ debug(`${_a.name} ⚡️ ${type}`);
838
+ if (!(target instanceof HTMLElement))
839
+ return;
840
+ switch (this.pickerStyle) {
841
+ case 'radio-group':
842
+ const radio = target.closest('input[type="radio"]');
843
+ if (!radio)
844
+ return;
845
+ this.#selection = radio.getAttribute('value') ?? '';
846
+ this.#reflectSelectionOnButtons();
847
+ this.#reflectSelectionOnCurrentValueLabel();
848
+ this.#sendValueToForm();
849
+ break;
850
+ }
851
+ }
769
852
  #handleValiditiesSlotchange = ({ type, target: slot }) => {
770
- if (devFlags.debug)
771
- console.debug(`${_a.name} ⚡️ ${type}`);
853
+ debug(`${_a.name} ⚡️ ${type}`);
772
854
  if (!(slot instanceof HTMLSlotElement))
773
855
  return;
774
856
  const assigned = slot.assignedElements();
@@ -777,8 +859,7 @@ export class PickerView extends FormAssociatedBase {
777
859
  this.#renderValidityMsgs([]);
778
860
  };
779
861
  #handleListSlotchange = ({ type, target: slot }) => {
780
- if (devFlags.debug)
781
- console.debug(`${_a.name} ⚡️ ${type}`);
862
+ debug(`${_a.name} ⚡️ ${type}`);
782
863
  if (!(slot instanceof HTMLSlotElement))
783
864
  return;
784
865
  const assigned = slot.assignedElements();
@@ -787,8 +868,7 @@ export class PickerView extends FormAssociatedBase {
787
868
  this.#renderSlotted([]);
788
869
  };
789
870
  static #wrapOptionSpawnTag(node) {
790
- if (devFlags.debug)
791
- console.debug(`${_a.name} #wrapOptionSpawnTag`);
871
+ debug(`${_a.name} #wrapOptionSpawnTag`);
792
872
  const title = extractLabel(node), subtitle = extractSubtitle(node), icon = extractIcon(node);
793
873
  const mount = document.createElement('div');
794
874
  render(html `<button type="button" tabindex="0" navigation-link>
@@ -796,212 +876,180 @@ export class PickerView extends FormAssociatedBase {
796
876
  <label-view data-role="check" style="visibility: hidden">
797
877
  <image-view slot="icon" system-name="check"></image-view>
798
878
  </label-view>
799
- <h-stack distribution="fill" template="${icon ? 'auto spacer' : null}">
800
- ${icon ? html `<label-view system-image="${icon}"></label-view>` : null}
801
- <v-stack spacing="3" alignment="fill">
802
- <label-view title="${title}"></label-view>
803
- ${subtitle ? html `<label-view foreground="secondary" font="callout" title="${subtitle}"></label-view>` : null}
804
- </v-stack>
805
- </h-stack>
879
+ ${_a.#morphITSLabel({ title, subtitle, icon })}
806
880
  </h-stack>
807
881
  </button>`, mount);
808
- // const btn = $<HTMLButtonElement>(
809
- // `<button type="button" tabindex="0" navigation-link><h-stack distribution="leading" template="auto spacer"><label-view data-role="check" style="visibility: hidden"><image-view slot="icon" system-name="check"></image-view></label-view><label-view><span></span></label-view></h-stack></button>`,
810
- // '>1'
811
- // ),
812
- // hStack = btn.querySelector<LabelView>(':scope>h-stack') ?? undefined
813
- // renderLabel(
814
- // ':scope>label-view:nth-child(2)',
815
- // `<label-view><span></span></label-view>`,
816
- // hStack,
817
- // extractLabelFromGroup(node as HTMLDataListElement),
818
- // extractImgFromGroup(node as HTMLDataListElement)
819
- // )
820
- // // label = btn.querySelector<LabelView>(':scope>h-stack>label-view:nth-child(2)')
821
- // // if (label) {
822
- // // const lbl = extractLabelFromGroup(node as HTMLDataListElement),
823
- // // img =extractImgFromGroup(node as HTMLDataListElement)
824
- // // if(lbl) renderLabelTitle(label, node.dataset.label) //label?.setAttribute('title', el.dataset.label)
825
- // // }
826
882
  return mount.firstElementChild; //btn
827
883
  }
828
- static #wrapOptionTag(node) {
829
- if (devFlags.debug)
830
- console.debug(`${_a.name} #wrapOptionTag`);
884
+ #wrapOptionTag(node) {
885
+ debug(`${_a.name} #wrapOptionTag`);
831
886
  const tag = extractTag(node), title = extractLabel(node), subtitle = extractSubtitle(node), icon = extractIcon(node);
832
887
  const mount = document.createElement('div');
833
- render(html `<button type="button" tabindex="0" value="${tag}">
834
- <h-stack distribution="leading" template="auto spacer">
835
- <label-view data-role="check">
836
- <image-view slot="icon" system-name="check"></image-view>
837
- </label-view>
838
- <h-stack distribution="fill" template="${icon ? 'auto spacer' : null}">
839
- ${icon ? html `<label-view system-image="${icon}"></label-view>` : null}
840
- <v-stack spacing="3" alignment="fill">
841
- <label-view title="${title}"></label-view>
842
- ${subtitle ? html `<label-view foreground="secondary" font="callout" title="${subtitle}"></label-view>` : null}
843
- </v-stack>
844
- </h-stack>
845
- </h-stack>
846
- </button>`, mount);
847
- // const btn = $(
848
- // `<button type="button" tabindex="0"><h-stack distribution="leading" template="auto spacer"><label-view data-role="check"><image-view slot="icon" system-name="check"></image-view></label-view></h-stack></button>`,
849
- // '>1'
850
- // ),
851
- // hStack = btn.querySelector<HTMLElement>(':scope>h-stack')
852
- // // chevron = hStack?.querySelector<HTMLElement>(':scope>label-view')
853
- // btn.setAttribute('value', extractTagFromOption(node))
854
- // // if (selection !== btn.getAttribute('value')) chevron?.style.setProperty('visibility', 'hidden')
855
- // const label = $<LabelView>(`<label-view></label-view>`, '>1')
856
- // renderLabelTitle(label, extractLabel(node)) // label.querySelector('span')!.textContent = extractCurrentValueFromOption(node) //label.setAttribute('title', extractCurrentValueFromOption(node))
857
- // renderLabelIcon(label, extractIcon(node))
858
- // hStack?.appendChild(label)
859
- return mount.firstElementChild; //btn
888
+ switch (this.pickerStyle) {
889
+ case 'radio-group':
890
+ render(_a.#morphRadioGroupBtn({ name: this.#guuid, title, subtitle, icon, tag }), mount);
891
+ return mount.firstElementChild; //btn
892
+ default:
893
+ render(html `<button type="button" tabindex="0" value="${tag}">
894
+ <h-stack distribution="leading" template="auto spacer">
895
+ <label-view data-role="check">
896
+ <image-view slot="icon" system-name="check"></image-view>
897
+ </label-view>
898
+ ${_a.#morphITSLabel({ title, subtitle, icon })}
899
+ </h-stack>
900
+ </button>`, mount);
901
+ return mount.firstElementChild; //btn
902
+ }
903
+ }
904
+ static #morphRadioGroupGroup({ name, title, subtitle, icon }) {
905
+ return html `<label>
906
+ <h-stack distribution="fill" template="auto spacer" spacing="5">
907
+ <input type="radio" name="${name}" style="min-inline-size: 20px; margin: 0" disabled />
908
+ ${_a.#morphITSLabel({ title, subtitle, icon })}
909
+ </h-stack>
910
+ </label>`;
911
+ }
912
+ static #morphRadioGroupBtn({ name, title, subtitle, icon, tag }) {
913
+ return html `<label>
914
+ <h-stack distribution="fill" template="auto spacer" spacing="5">
915
+ <input type="radio" name="${name}" value="${tag}" style="min-inline-size: 20px; margin: 0" />
916
+ ${_a.#morphITSLabel({ title, subtitle, icon })}
917
+ </h-stack>
918
+ </label>`;
860
919
  }
861
- static #wrapOptgroupTag(node) {
862
- if (devFlags.debug)
863
- console.debug(`${_a.name} #wrapOptgroupTag`);
920
+ static #morphITSLabel({ title, subtitle, icon }) {
921
+ return html `<h-stack distribution="fill" template="${icon ? 'auto spacer' : null}">
922
+ ${icon ? html `<label-view system-image="${icon}"></label-view>` : null}
923
+ <v-stack spacing="3" alignment="fill">
924
+ <label-view title="${title}"></label-view>
925
+ ${subtitle ? html `<label-view foreground="secondary" font="callout" title="${subtitle}"></label-view>` : null}
926
+ </v-stack>
927
+ </h-stack>`;
928
+ }
929
+ #wrapOptgroupTag(node) {
930
+ debug(`${_a.name} #wrapOptgroupTag`);
864
931
  const title = extractLabel(node), subtitle = extractSubtitle(node), icon = extractIcon(node);
865
932
  const mount = document.createElement('div');
866
- render(html `<details is="disclosure-group" disclosure-style="marker-trailing">
867
- <summary>
868
- <h-stack distribution="leading" template="auto spacer">
869
- <label-view data-role="check" style="visibility: hidden">
870
- <image-view slot="icon" system-name="check"></image-view>
871
- </label-view>
872
- <h-stack distribution="fill" template="${icon ? 'auto spacer' : null}">
873
- ${icon ? html `<label-view system-image="${icon}"></label-view>` : null}
874
- <v-stack spacing="3" alignment="fill">
875
- <label-view title="${title}"></label-view>
876
- ${subtitle ? html `<label-view foreground="secondary" font="callout" title="${subtitle}"></label-view>` : null}
877
- </v-stack>
933
+ switch (this.pickerStyle) {
934
+ case 'radio-group':
935
+ render(_a.#morphRadioGroupGroup({ name: this.#guuid, title, subtitle, icon }),
936
+ // this.hasAttribute('horizontal-radio-group-layout')
937
+ // ? html`<h-flex-stack style="flex-wrap: wrap">${PickerView.#morphRadioGroupGroup({ name: this.#guuid, title, subtitle, icon })}</h-flex-stack>`
938
+ // : html`<v-stack>${PickerView.#morphRadioGroupGroup({ name: this.#guuid, title, subtitle, icon })}</v-stack>`,
939
+ mount);
940
+ return mount.firstElementChild;
941
+ default:
942
+ render(html `<details is="disclosure-group" disclosure-style="marker-trailing">
943
+ <summary>
944
+ <h-stack distribution="leading" template="auto spacer">
945
+ <label-view data-role="check" style="visibility: hidden">
946
+ <image-view slot="icon" system-name="check"></image-view>
947
+ </label-view>
948
+ ${_a.#morphITSLabel({ title, subtitle, icon })}
949
+ </h-stack>
950
+ </summary>
951
+ </details>`, mount);
952
+ return mount.firstElementChild;
953
+ }
954
+ }
955
+ #wrapDatalistTag(node) {
956
+ const title = extractLabel(node), subtitle = extractSubtitle(node), icon = extractIcon(node);
957
+ const mount = document.createElement('div');
958
+ switch (this.pickerStyle) {
959
+ case 'radio-group':
960
+ render(_a.#morphRadioGroupGroup({ name: this.#guuid, title, subtitle, icon }),
961
+ // this.hasAttribute('horizontal-radio-group-layout')
962
+ // ? html`<h-flex-stack style="flex-wrap: wrap">${PickerView.#morphRadioGroupGroup({ name: this.#guuid, title, subtitle, icon })}</h-flex-stack>`
963
+ // : html`<v-stack>${PickerView.#morphRadioGroupGroup({ name: this.#guuid, title, subtitle, icon })}</v-stack>`,
964
+ mount);
965
+ return mount.firstElementChild;
966
+ default:
967
+ render(html `<menu-view tabindex="0">
968
+ <h-stack slot="label" distribution="leading" template="auto spacer">
969
+ <label-view data-role="check" style="visibility: hidden">
970
+ <image-view slot="icon" system-name="check"></image-view>
971
+ </label-view>
972
+ ${_a.#morphITSLabel({ title, subtitle, icon })}
878
973
  </h-stack>
879
- </h-stack>
880
- </summary>
881
- </details>`, mount);
882
- return mount.firstElementChild;
883
- // const labelT = `<label-view><span></span></label-view>`,
884
- // summaryT = `<summary><h-stack distribution="leading" template="auto spacer"><label-view data-role="check" style="visibility: hidden"><image-view slot="icon" system-name="check"></image-view></label-view>${labelT}</h-stack></summary>`
885
- // const group = $(`<details is="disclosure-group" disclosure-style="marker-trailing">${summaryT}</details>`, '>1'), // NOTE: already applied, here it covers spawned sheets
886
- // hStack = group.querySelector(':scope>summary>h-stack') ?? undefined // ?? group.appendChild($(summaryT, '>1'))
887
- // // summaryLabel = summary.querySelector(':scope>label-view') ?? summary.appendChild($(labelT, '>1'))
888
- // // if (node.hasAttribute('label')) summaryLabel.setAttribute('title', node.getAttribute('label') ?? '')
889
- // // if (node.hasAttribute('data-system-image')) summaryLabel.setAttribute('system-image', node.getAttribute('data-system-image') ?? '')
890
- // renderLabel(':scope>label-view:nth-child(2)', labelT, hStack, extractLabel(node), extractIcon(node))
891
- // return group
974
+ </menu-view>`, mount);
975
+ return mount.firstElementChild;
976
+ }
892
977
  }
893
- // static #reflectButtons(nodes: Element[], container: Element): void
894
- // static #reflectButtons(nodes: Dictionary, container: Element): void
895
- static #reflectButtons(nodes, container) {
896
- if (devFlags.debug)
897
- console.debug(`${_a.name} #reflectButtons`);
978
+ #reflectButtons(nodes, container) {
979
+ debug(`${_a.name} #reflectButtons`);
980
+ const flatten = 'radio-group' === this.pickerStyle;
898
981
  for (const node of nodes)
899
982
  if (node instanceof Element)
900
983
  switch (node.tagName) {
901
984
  case 'DATALIST': {
902
- const title = extractLabel(node), subtitle = extractSubtitle(node), icon = extractIcon(node);
903
- const mount = document.createElement('div');
904
- render(html `<menu-view tabindex="0">
905
- <h-stack slot="label" distribution="leading" template="auto spacer">
906
- <label-view data-role="check" style="visibility: hidden">
907
- <image-view slot="icon" system-name="check"></image-view>
908
- </label-view>
909
- <h-stack distribution="fill" template="${icon ? 'auto spacer' : null}">
910
- ${icon ? html `<label-view system-image="${icon}"></label-view>` : null}
911
- <v-stack spacing="3" alignment="fill">
912
- <label-view title="${title}"></label-view>
913
- ${subtitle ? html `<label-view foreground="secondary" font="callout" title="${subtitle}"></label-view>` : null}
914
- </v-stack>
915
- </h-stack>
916
- </h-stack>
917
- </menu-view>`, mount);
918
- const group = mount.firstElementChild;
919
- // const group = $(
920
- // `<menu-view tabindex="0"><h-stack slot="label" distribution="leading" template="auto spacer"><label-view data-role="check" style="visibility: hidden"><image-view slot="icon" system-name="check"></image-view></label-view><label-view><span></span></label-view></h-stack></menu-view>`,
921
- // '>1'
922
- // ),
923
- // hStack = group.querySelector(':scope>h-stack[slot=label]') ?? undefined
924
- // // label = group.querySelector(':scope>label-view[slot=label]') ?? group.appendChild($(`<label-view slot="label"></label-view>`, '>1'))
925
- // // if (node.hasAttribute('data-label')) label.setAttribute('title', node.getAttribute('data-label') ?? '')
926
- // // if (node.hasAttribute('data-system-image')) label.setAttribute('system-image', node.getAttribute('data-system-image') ?? '')
927
- // renderLabel(':scope>label-view:nth-child(2)', `<label-view><span></span></label-view>`, hStack, extractLabel(node as HTMLDataListElement), extractIcon(node as HTMLDataListElement))
928
- _a.#reflectButtons([...node.children], group);
985
+ if (flatten) {
986
+ this.#reflectButtons([...node.children], container);
987
+ break;
988
+ }
989
+ const group = this.#wrapDatalistTag(node);
990
+ this.#reflectButtons([...node.children], group);
929
991
  container.appendChild(group);
930
992
  break;
931
993
  }
932
994
  case 'OPTGROUP': {
933
- const group = _a.#wrapOptgroupTag(node);
934
- _a.#reflectButtons([...node.children], group);
995
+ if (flatten) {
996
+ this.#reflectButtons([...node.children], container);
997
+ break;
998
+ }
999
+ const group = this.#wrapOptgroupTag(node);
1000
+ this.#reflectButtons([...node.children], group);
935
1001
  container.appendChild(group);
936
1002
  break;
937
1003
  }
938
1004
  case 'OPTION':
939
1005
  default: {
940
- container.appendChild(_a.#wrapOptionTag(node));
1006
+ container.appendChild(this.#wrapOptionTag(node));
941
1007
  break;
942
1008
  }
943
1009
  }
944
1010
  else {
945
1011
  if (node.children.length)
946
- if (allLeaves(node)) {
947
- const group = _a.#wrapOptgroupTag(node);
948
- _a.#reflectButtons(node.children, group);
1012
+ if (flatten)
1013
+ this.#reflectButtons(node.children, container);
1014
+ else if (allLeaves(node)) {
1015
+ const group = this.#wrapOptgroupTag(node);
1016
+ this.#reflectButtons(node.children, group);
949
1017
  container.appendChild(group);
950
1018
  }
951
1019
  else {
952
- const title = extractLabel(node), subtitle = extractSubtitle(node), icon = extractIcon(node);
953
- const mount = document.createElement('div');
954
- render(html `<menu-view tabindex="0">
955
- <h-stack slot="label" distribution="leading" template="auto spacer">
956
- <label-view data-role="check" style="visibility: hidden">
957
- <image-view slot="icon" system-name="check"></image-view>
958
- </label-view>
959
- <h-stack distribution="fill" template="${icon ? 'auto spacer' : null}">
960
- ${icon ? html `<label-view system-image="${icon}"></label-view>` : null}
961
- <v-stack spacing="3" alignment="fill">
962
- <label-view title="${title}"></label-view>
963
- ${subtitle ? html `<label-view foreground="secondary" font="callout" title="${subtitle}"></label-view>` : null}
964
- </v-stack>
965
- </h-stack>
966
- </h-stack>
967
- </menu-view>`, mount);
968
- const group = mount.firstElementChild;
969
- // const group = $(`<menu-view tabindex="0"></menu-view>`, '>1')
970
- // renderLabel(':scope>label-view[slot=label]', `<label-view slot="label"><span></span></label-view>`, group, extractLabel(node), extractIcon(node))
971
- _a.#reflectButtons(node.children, group);
1020
+ const group = this.#wrapDatalistTag(node);
1021
+ this.#reflectButtons(node.children, group);
972
1022
  container.appendChild(group);
973
1023
  }
974
1024
  else
975
- container.appendChild(_a.#wrapOptionTag(node));
1025
+ container.appendChild(this.#wrapOptionTag(node));
976
1026
  }
977
1027
  }
978
1028
  // #reflectPlaceholder(value: string | null) {
979
- // if (devFlags.debug) console.debug(`#reflectPlaceholder`)
1029
+ // debug(`#reflectPlaceholder`)
980
1030
  // const input = this.#shadowRoot.querySelector('input')
981
1031
  // if (input) {
982
- // if (value) input.setAttribute((this.constructor as typeof PickerView).ATTR.PLACEHOLDER, value)
983
- // else input.removeAttribute((this.constructor as typeof PickerView).ATTR.PLACEHOLDER)
1032
+ // if (value) input.setAttribute('prompt', value)
1033
+ // else input.removeAttribute('prompt')
984
1034
  // }
985
1035
  // }
986
1036
  #reflectLabel(value) {
987
- if (devFlags.debug)
988
- console.debug(`${_a.name} #reflectLabel`);
1037
+ debug(`${_a.name} #reflectLabel`);
989
1038
  queryMorph('[slot=label]', html `<label-view slot="label">${value ? html `<span>${value}</span>` : null}</label-view>`, this);
990
1039
  this.#renderSlotted([]);
991
1040
  }
992
1041
  #reflectSelectionOnButtons() {
993
- if (devFlags.debug)
994
- console.debug(`${_a.name} #reflectSelectionOnButtons`);
1042
+ debug(`${_a.name} #reflectSelectionOnButtons`);
995
1043
  self.requestAnimationFrame(() => {
996
1044
  this.ariaCurrent = this.#selection;
997
1045
  const groupMap = indexGroups(this.#lastIndexedRoot);
998
1046
  const groupContainsSelection = (source) => source instanceof Element ? [...source.querySelectorAll('option')].some((opt) => extractTag(opt) === this.#selection) : collectLeafValues(source).includes(this.#selection);
999
1047
  const syncButtons = (root) => {
1000
- // 1. plain value buttons — unchanged
1048
+ // 1. plain value buttons
1001
1049
  for (const el of root.querySelectorAll('button[value]:not([slot])'))
1002
1050
  // $.prop('visibility', el.getAttribute('value') === this.#selection ? 'visible' : 'hidden', el.querySelector<HTMLElement>('label-view[data-role="check"]'))
1003
1051
  el.querySelector('label-view[data-role="check"]')?.style.setProperty('visibility', el.getAttribute('value') === this.#selection ? 'visible' : 'hidden');
1004
- // 2. details/optgroups — unchanged
1052
+ // 2. details/optgroups
1005
1053
  for (const details of root.querySelectorAll('details[is="disclosure-group"]')) {
1006
1054
  const hasSelectedDescendant = [...details.querySelectorAll('button[value]')].some((btn) => btn.getAttribute('value') === this.#selection);
1007
1055
  details.querySelector(':scope>summary label-view[data-role="check"]')?.style.setProperty('visibility', hasSelectedDescendant ? 'visible' : 'hidden');
@@ -1012,6 +1060,9 @@ export class PickerView extends FormAssociatedBase {
1012
1060
  const hasSelectedDescendant = source ? groupContainsSelection(source) : false;
1013
1061
  btn.querySelector('label-view[data-role="check"]')?.style.setProperty('visibility', hasSelectedDescendant ? 'visible' : 'hidden');
1014
1062
  }
1063
+ // 4. radio inputs
1064
+ for (const el of root.querySelectorAll('input[type=radio][value]'))
1065
+ el.checked = el.getAttribute('value') === this.#selection;
1015
1066
  };
1016
1067
  syncButtons(this);
1017
1068
  if (this.#spawn)
@@ -1022,8 +1073,7 @@ export class PickerView extends FormAssociatedBase {
1022
1073
  * Overwrite cvlabel with the label prop of the current(find[value === #selection]) option/dictentry
1023
1074
  */
1024
1075
  #reflectSelectionOnCurrentValueLabel() {
1025
- if (devFlags.debug)
1026
- console.debug(`${_a.name} #reflectSelectionOnCurrentValueLabel`);
1076
+ debug(`${_a.name} #reflectSelectionOnCurrentValueLabel`);
1027
1077
  self.requestAnimationFrame(() => {
1028
1078
  switch (this.pickerStyle) {
1029
1079
  case 'sheet':
@@ -1033,7 +1083,7 @@ export class PickerView extends FormAssociatedBase {
1033
1083
  break;
1034
1084
  // if (!cvl) currentValueLabel.setAttribute('foreground', 'secondary')
1035
1085
  // else currentValueLabel.removeAttribute('foreground')
1036
- const title = this.#currentValueLabel || this.#selection || this.getAttribute(this.constructor.ATTR.PLACEHOLDER), systemImage = this.#currentValueIcon || this.getAttribute(this.constructor.ATTR.PLACEHOLDER_ICON);
1086
+ const title = this.#currentValueLabel || this.#selection || this.getAttribute('prompt'), systemImage = this.#currentValueIcon || this.getAttribute('prompt-icon');
1037
1087
  queryMorph(':not([slot])', html `<span>${title}</span>`, currentValueLabel, { removeIf: !title });
1038
1088
  queryMorph('[slot=icon]', html `<image-view slot="icon" system-name="${systemImage}"></image-view>`, currentValueLabel, { removeIf: !systemImage });
1039
1089
  // morph(
@@ -1048,7 +1098,7 @@ export class PickerView extends FormAssociatedBase {
1048
1098
  break;
1049
1099
  // if (!cvl) currentValueLabel.setAttribute('foreground', 'secondary')
1050
1100
  // else currentValueLabel.removeAttribute('foreground')
1051
- const title = this.#currentValueLabel || this.#selection || this.getAttribute(this.constructor.ATTR.PLACEHOLDER), systemImage = this.#currentValueIcon || this.getAttribute(this.constructor.ATTR.PLACEHOLDER_ICON);
1101
+ const title = this.#currentValueLabel || this.#selection || this.getAttribute('prompt'), systemImage = this.#currentValueIcon || this.getAttribute('prompt-icon');
1052
1102
  queryMorph(':not([slot])', html `<span>${title}</span>`, currentValueLabel, { removeIf: !title });
1053
1103
  queryMorph('[slot=icon]', html `<image-view slot="icon" system-name="${systemImage}"></image-view>`, currentValueLabel, { removeIf: !systemImage });
1054
1104
  // morph(
@@ -1066,8 +1116,7 @@ export class PickerView extends FormAssociatedBase {
1066
1116
  });
1067
1117
  }
1068
1118
  #reflectTriggerHelp() {
1069
- if (devFlags.debug)
1070
- console.debug(`${_a.name} #reflectTriggerHelp`);
1119
+ debug(`${_a.name} #reflectTriggerHelp`);
1071
1120
  let trigger;
1072
1121
  switch (this.pickerStyle) {
1073
1122
  case 'sheet':
@@ -1082,10 +1131,10 @@ export class PickerView extends FormAssociatedBase {
1082
1131
  //udnefined
1083
1132
  }
1084
1133
  }
1085
- if (this.hasAttribute(this.constructor.ATTR.TRIGGER_HELP))
1086
- trigger?.setAttribute(this.constructor.ATTR.TRIGGER_HELP, this.getAttribute(this.constructor.ATTR.TRIGGER_HELP) ?? '');
1134
+ if (this.hasAttribute('help'))
1135
+ trigger?.setAttribute('help', this.getAttribute('help') ?? '');
1087
1136
  else
1088
- trigger?.removeAttribute(this.constructor.ATTR.TRIGGER_HELP);
1137
+ trigger?.removeAttribute('help');
1089
1138
  }
1090
1139
  /**
1091
1140
  * Form participation property
@@ -1122,8 +1171,7 @@ export class PickerView extends FormAssociatedBase {
1122
1171
  message = kebabCase(key);
1123
1172
  break;
1124
1173
  }
1125
- if (devFlags.debug)
1126
- console.debug(`${_a.name} ⚡️ validity-change`);
1174
+ debug(`${_a.name} ⚡️ validity-change`);
1127
1175
  return this.#internals.setValidity(flags, this.#customValidity || message, anchor);
1128
1176
  };
1129
1177
  setCustomValidity = (message) => {