@swiftwc/ui 0.0.0-dev.4 → 0.0.0-dev.41

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 (314) hide show
  1. package/README.md +15 -0
  2. package/generated/buses/alert-dialog.d.ts +2 -0
  3. package/generated/buses/alert-dialog.js +1 -0
  4. package/generated/buses/confirmation-dialog.d.ts +2 -0
  5. package/generated/buses/confirmation-dialog.js +1 -0
  6. package/generated/buses/index.d.ts +6 -0
  7. package/generated/buses/index.js +6 -0
  8. package/generated/buses/lifecycle-observer.d.ts +2 -0
  9. package/generated/buses/lifecycle-observer.js +1 -0
  10. package/generated/client/index.d.ts +24 -0
  11. package/generated/client/index.js +272 -0
  12. package/generated/components/alert-dialog.d.ts +8 -0
  13. package/generated/components/alert-dialog.js +99 -0
  14. package/generated/components/body-view.d.ts +5 -0
  15. package/generated/components/body-view.js +14 -0
  16. package/generated/components/bordered-button.d.ts +13 -0
  17. package/generated/components/bordered-button.js +45 -0
  18. package/generated/components/bordered-prominent-button.d.ts +13 -0
  19. package/generated/components/bordered-prominent-button.js +45 -0
  20. package/generated/components/borderless-button.d.ts +13 -0
  21. package/generated/components/borderless-button.js +45 -0
  22. package/generated/components/confirmation-dialog.d.ts +9 -0
  23. package/generated/components/confirmation-dialog.js +113 -0
  24. package/generated/components/content-unavailable-view.d.ts +24 -0
  25. package/generated/components/content-unavailable-view.js +81 -0
  26. package/generated/components/date-picker.d.ts +36 -0
  27. package/generated/components/date-picker.js +468 -0
  28. package/generated/components/disclosure-group.d.ts +9 -0
  29. package/generated/components/disclosure-group.js +58 -0
  30. package/generated/components/fine-tooltip.d.ts +7 -0
  31. package/generated/components/fine-tooltip.js +107 -0
  32. package/generated/components/form-view.d.ts +6 -0
  33. package/generated/components/form-view.js +60 -0
  34. package/generated/components/glass-button.d.ts +12 -0
  35. package/generated/components/glass-button.js +42 -0
  36. package/generated/components/glass-prominent-button.d.ts +12 -0
  37. package/generated/components/glass-prominent-button.js +42 -0
  38. package/generated/components/index.d.ts +42 -0
  39. package/generated/components/index.js +42 -0
  40. package/generated/components/label-view.d.ts +9 -0
  41. package/generated/components/label-view.js +59 -0
  42. package/generated/components/list-view.d.ts +5 -0
  43. package/generated/components/list-view.js +29 -0
  44. package/generated/components/menu-view.d.ts +9 -0
  45. package/generated/components/menu-view.js +145 -0
  46. package/generated/components/navigation-large-title.d.ts +6 -0
  47. package/generated/components/navigation-large-title.js +181 -0
  48. package/generated/components/navigation-split-view.d.ts +10 -0
  49. package/generated/components/navigation-split-view.js +25 -0
  50. package/generated/components/navigation-stack.d.ts +10 -0
  51. package/generated/components/navigation-stack.js +31 -0
  52. package/generated/components/navigation-title.d.ts +8 -0
  53. package/generated/components/navigation-title.js +52 -0
  54. package/generated/components/picker-view.d.ts +28 -0
  55. package/generated/components/picker-view.js +697 -0
  56. package/generated/components/plain-button.d.ts +7 -0
  57. package/generated/components/plain-button.js +22 -0
  58. package/generated/components/progress-view.d.ts +13 -0
  59. package/generated/components/progress-view.js +125 -0
  60. package/generated/components/screen-view.d.ts +5 -0
  61. package/generated/components/screen-view.js +11 -0
  62. package/generated/components/scroll-view-proxy.d.ts +8 -0
  63. package/generated/components/scroll-view-proxy.js +17 -0
  64. package/generated/components/scroll-view.d.ts +10 -0
  65. package/generated/components/scroll-view.js +202 -0
  66. package/generated/components/search-view.d.ts +8 -0
  67. package/generated/components/search-view.js +30 -0
  68. package/generated/components/section-view.d.ts +9 -0
  69. package/generated/components/section-view.js +83 -0
  70. package/generated/components/sheet-view.d.ts +8 -0
  71. package/generated/components/sheet-view.js +62 -0
  72. package/generated/components/sidebar-toggle.d.ts +7 -0
  73. package/generated/components/sidebar-toggle.js +85 -0
  74. package/generated/components/sidebar-view.d.ts +7 -0
  75. package/generated/components/sidebar-view.js +34 -0
  76. package/generated/components/sticky-container.d.ts +6 -0
  77. package/generated/components/sticky-container.js +26 -0
  78. package/generated/components/tab-bar.d.ts +10 -0
  79. package/generated/components/tab-bar.js +43 -0
  80. package/generated/components/tab-item.d.ts +7 -0
  81. package/generated/components/tab-item.js +132 -0
  82. package/generated/components/tab-view.d.ts +22 -0
  83. package/generated/components/tab-view.js +264 -0
  84. package/generated/components/table-view.d.ts +7 -0
  85. package/generated/components/table-view.js +174 -0
  86. package/generated/components/text-field.d.ts +29 -0
  87. package/generated/components/text-field.js +503 -0
  88. package/generated/components/tool-bar-item-group.d.ts +5 -0
  89. package/generated/components/tool-bar-item-group.js +28 -0
  90. package/generated/components/tool-bar-item.d.ts +8 -0
  91. package/generated/components/tool-bar-item.js +66 -0
  92. package/generated/components/tool-bar.d.ts +19 -0
  93. package/generated/components/tool-bar.js +93 -0
  94. package/generated/components/v-keyboard.d.ts +15 -0
  95. package/generated/components/v-keyboard.js +89 -0
  96. package/generated/components/v-stack.d.ts +10 -0
  97. package/generated/components/v-stack.js +19 -0
  98. package/generated/css/index.css +8089 -0
  99. package/generated/events/alert-dialog.d.ts +8 -0
  100. package/generated/events/alert-dialog.js +1 -0
  101. package/generated/events/confirmation-dialog.d.ts +9 -0
  102. package/generated/events/confirmation-dialog.js +1 -0
  103. package/generated/events/date-picker.d.ts +8 -0
  104. package/generated/events/date-picker.js +1 -0
  105. package/generated/events/index.d.ts +8 -0
  106. package/generated/events/index.js +8 -0
  107. package/generated/events/lifecycle-observer.d.ts +10 -0
  108. package/generated/events/lifecycle-observer.js +1 -0
  109. package/generated/events/picker-view.d.ts +15 -0
  110. package/generated/events/picker-view.js +1 -0
  111. package/generated/events/scroll-view.d.ts +10 -0
  112. package/generated/events/scroll-view.js +1 -0
  113. package/generated/events/tab-view.d.ts +28 -0
  114. package/generated/events/tab-view.js +1 -0
  115. package/generated/events/text-field.d.ts +8 -0
  116. package/generated/events/text-field.js +1 -0
  117. package/generated/i18n/index.d.ts +34 -0
  118. package/generated/i18n/index.js +167 -0
  119. package/generated/i18n/locales/el.d.ts +16 -0
  120. package/generated/i18n/locales/el.js +16 -0
  121. package/generated/i18n/locales/en.d.ts +16 -0
  122. package/generated/i18n/locales/en.js +16 -0
  123. package/generated/i18n/locales/index.d.ts +4 -0
  124. package/generated/i18n/locales/index.js +4 -0
  125. package/generated/index.d.ts +2 -0
  126. package/generated/index.js +3 -0
  127. package/generated/internal/class/cleanup-registry.d.ts +5 -0
  128. package/generated/internal/class/cleanup-registry.js +38 -0
  129. package/generated/internal/class/css-style-observer.d.ts +8 -0
  130. package/generated/internal/class/css-style-observer.js +26 -0
  131. package/generated/internal/class/form-associated-base.d.ts +16 -0
  132. package/generated/internal/class/form-associated-base.js +78 -0
  133. package/generated/internal/class/mutation-observer-set.d.ts +9 -0
  134. package/generated/internal/class/mutation-observer-set.js +42 -0
  135. package/generated/internal/class/mutation-observer-singleton.d.ts +10 -0
  136. package/generated/internal/class/mutation-observer-singleton.js +64 -0
  137. package/generated/internal/class/navigation-path.d.ts +15 -0
  138. package/generated/internal/class/navigation-path.js +84 -0
  139. package/generated/internal/class/navigation-view.d.ts +8 -0
  140. package/generated/internal/class/navigation-view.js +79 -0
  141. package/generated/internal/class/resize-observer-singleton.d.ts +7 -0
  142. package/generated/internal/class/resize-observer-singleton.js +22 -0
  143. package/generated/internal/decorators/adaptive-slot.d.ts +1 -0
  144. package/generated/internal/decorators/adaptive-slot.js +50 -0
  145. package/generated/internal/decorators/custom-element.d.ts +5 -0
  146. package/generated/internal/decorators/custom-element.js +5 -0
  147. package/generated/internal/decorators/index.d.ts +4 -0
  148. package/generated/internal/decorators/index.js +4 -0
  149. package/generated/internal/privateNamespace.d.ts +14 -0
  150. package/generated/internal/privateNamespace.js +168 -0
  151. package/generated/internal/utils/add.d.ts +1 -0
  152. package/generated/internal/utils/add.js +7 -0
  153. package/generated/internal/utils/cash/ancestors.d.ts +1 -0
  154. package/generated/internal/utils/cash/ancestors.js +27 -0
  155. package/generated/internal/utils/cash/index.d.ts +23 -0
  156. package/generated/internal/utils/cash/index.js +25 -0
  157. package/generated/internal/utils/cash/next-all.d.ts +1 -0
  158. package/generated/internal/utils/cash/next-all.js +10 -0
  159. package/generated/internal/utils/cash/next.d.ts +1 -0
  160. package/generated/internal/utils/cash/next.js +9 -0
  161. package/generated/internal/utils/cash/prev-all.d.ts +1 -0
  162. package/generated/internal/utils/cash/prev-all.js +10 -0
  163. package/generated/internal/utils/cash/prev.d.ts +1 -0
  164. package/generated/internal/utils/cash/prev.js +9 -0
  165. package/generated/internal/utils/cash/prop.d.ts +18 -0
  166. package/generated/internal/utils/cash/prop.js +30 -0
  167. package/generated/internal/utils/cash/siblings.d.ts +1 -0
  168. package/generated/internal/utils/cash/siblings.js +10 -0
  169. package/generated/internal/utils/clamp.d.ts +1 -0
  170. package/generated/internal/utils/clamp.js +4 -0
  171. package/generated/internal/utils/compare-big-decimals.d.ts +1 -0
  172. package/generated/internal/utils/compare-big-decimals.js +90 -0
  173. package/generated/internal/utils/css-time.d.ts +1 -0
  174. package/generated/internal/utils/css-time.js +3 -0
  175. package/generated/internal/utils/debounce.d.ts +1 -0
  176. package/generated/internal/utils/debounce.js +13 -0
  177. package/generated/internal/utils/dev-flags.d.ts +3 -0
  178. package/generated/internal/utils/dev-flags.js +5 -0
  179. package/generated/internal/utils/ensure-placeholder.d.ts +1 -0
  180. package/generated/internal/utils/ensure-placeholder.js +55 -0
  181. package/generated/internal/utils/frame.d.ts +1 -0
  182. package/generated/internal/utils/frame.js +6 -0
  183. package/generated/internal/utils/index.d.ts +19 -0
  184. package/generated/internal/utils/index.js +22 -0
  185. package/generated/internal/utils/is-inside.d.ts +1 -0
  186. package/generated/internal/utils/is-inside.js +4 -0
  187. package/generated/internal/utils/kebab-case.d.ts +1 -0
  188. package/generated/internal/utils/kebab-case.js +11 -0
  189. package/generated/internal/utils/list-active.d.ts +7 -0
  190. package/generated/internal/utils/list-active.js +83 -0
  191. package/generated/internal/utils/microtask.d.ts +1 -0
  192. package/generated/internal/utils/microtask.js +3 -0
  193. package/generated/internal/utils/onoff.d.ts +45 -0
  194. package/generated/internal/utils/onoff.js +31 -0
  195. package/generated/internal/utils/set.d.ts +1 -0
  196. package/generated/internal/utils/set.js +7 -0
  197. package/generated/internal/utils/sleep.d.ts +1 -0
  198. package/generated/internal/utils/sleep.js +3 -0
  199. package/generated/internal/utils/slow-hide-show.d.ts +1 -0
  200. package/generated/internal/utils/slow-hide-show.js +16 -0
  201. package/generated/internal/utils/timeout.d.ts +5 -0
  202. package/generated/internal/utils/timeout.js +16 -0
  203. package/generated/internal/utils/touch-glass.d.ts +7 -0
  204. package/generated/internal/utils/touch-glass.js +19 -0
  205. package/generated/namespace-browser/base.d.ts +45 -0
  206. package/generated/namespace-browser/base.js +115 -0
  207. package/generated/namespace-browser/index.d.ts +7 -0
  208. package/generated/namespace-browser/index.js +1 -0
  209. package/generated/snapshot/index.d.ts +9 -0
  210. package/generated/snapshot/index.js +60 -0
  211. package/package.json +35 -11
  212. package/scss/_components.scss +59 -14
  213. package/scss/_final.scss +1 -0
  214. package/scss/_functions.scss +10 -0
  215. package/scss/_mixins.scss +4 -169
  216. package/scss/_placeholders.scss +3 -0
  217. package/scss/_transitions.scss +22 -1
  218. package/scss/_utils.scss +9 -0
  219. package/scss/_vars.scss +142 -23
  220. package/scss/base/_layout.scss +31 -16
  221. package/scss/base/_reboot.scss +151 -15
  222. package/scss/base/_root.scss +355 -25
  223. package/scss/colors/_index.scss +672 -70
  224. package/scss/components/_alert-dialog.scss +111 -0
  225. package/scss/components/_body-view.scss +12 -3
  226. package/scss/components/_bordered-button.scss +57 -0
  227. package/scss/components/_bordered-prominent-button.scss +63 -0
  228. package/scss/components/_borderless-button.scss +36 -6
  229. package/scss/components/_confirmation-dialog.scss +84 -0
  230. package/scss/components/_content-unavailable-view.scss +45 -0
  231. package/scss/components/_date-picker.scss +30 -0
  232. package/scss/components/_detail-placeholder.scss +153 -0
  233. package/scss/components/_disclosure-group.scss +146 -51
  234. package/scss/components/_fine-tooltip.scss +82 -0
  235. package/scss/components/_form-view.scss +195 -0
  236. package/scss/components/_full-screen.scss +7 -5
  237. package/scss/components/_glass-button.scss +59 -0
  238. package/scss/components/_glass-prominent-button.scss +68 -0
  239. package/scss/components/_h-divider.scss +13 -0
  240. package/scss/components/_h-flex-stack.scss +23 -0
  241. package/scss/components/_h-stack.scss +29 -0
  242. package/scss/components/_index.scss +234 -7
  243. package/scss/components/_label-view copy.scss.txt +420 -0
  244. package/scss/components/_label-view.scss +355 -0
  245. package/scss/components/_label-view.scss.txt +536 -0
  246. package/scss/components/_labeled-content.scss +9 -0
  247. package/scss/components/_list-view.scss +229 -0
  248. package/scss/components/_menu-view.scss +211 -0
  249. package/scss/components/_navigation-large-title.scss +27 -0
  250. package/scss/components/_navigation-split-view.scss +329 -269
  251. package/scss/components/_navigation-stack.scss +6 -6
  252. package/scss/components/_navigation-title.scss +10 -0
  253. package/scss/components/_picker-view.scss +131 -0
  254. package/scss/components/_plain-button.scss +18 -0
  255. package/scss/components/_progress-view.scss +98 -0
  256. package/scss/components/_scroll-view-proxy.scss +79 -0
  257. package/scss/components/_scroll-view-toolbars.scss +126 -0
  258. package/scss/components/_scroll-view.scss +114 -66
  259. package/scss/components/_search-view.scss +18 -0
  260. package/scss/components/_section-view.scss +119 -0
  261. package/scss/components/_sheet-view.scss +78 -35
  262. package/scss/components/_sidebar-toggle.scss +87 -27
  263. package/scss/components/_sidebar-view.scss +30 -40
  264. package/scss/components/_sticky-container.scss +42 -0
  265. package/scss/components/_tab-bar.scss +207 -84
  266. package/scss/components/_tab-item.scss +25 -0
  267. package/scss/components/_tab-view.scss +270 -126
  268. package/scss/components/_table-column.scss +52 -0
  269. package/scss/components/_table-row.scss +172 -0
  270. package/scss/components/_table-view.scss +223 -0
  271. package/scss/components/_text-field.scss +37 -0
  272. package/scss/components/_tool-bar-item-group.scss +30 -19
  273. package/scss/components/_tool-bar-item.scss +81 -71
  274. package/scss/components/_tool-bar.scss +126 -63
  275. package/scss/components/_v-divider.scss +13 -0
  276. package/scss/components/_v-flex-stack.scss +29 -0
  277. package/scss/components/_v-keyboard.scss +6 -4
  278. package/scss/components/_v-stack.scss +15 -9
  279. package/scss/final/_touch-glass.scss +91 -0
  280. package/scss/index.scss +6 -2
  281. package/scss/mixins/_button.scss +44 -0
  282. package/scss/mixins/_color.scss +16 -0
  283. package/scss/mixins/_dialog.scss +89 -0
  284. package/scss/mixins/_index.scss +422 -0
  285. package/scss/placeholders/_buttons.scss +117 -0
  286. package/scss/placeholders/_lists.scss +571 -0
  287. package/scss/transitions/_alert-dialog.scss +18 -0
  288. package/scss/transitions/_bwd.navbar.scss +3 -13
  289. package/scss/transitions/_bwd.scss +4 -20
  290. package/scss/transitions/_confirmation-dialog.scss +22 -0
  291. package/scss/transitions/_disclosure-group.scss +35 -0
  292. package/scss/transitions/_fine-tooltip.scss +21 -0
  293. package/scss/transitions/_fwd.navbar.scss +4 -9
  294. package/scss/transitions/_fwd.scss +4 -34
  295. package/scss/transitions/_glass-button.scss +12 -0
  296. package/scss/transitions/_glass-prominent-button.scss +12 -0
  297. package/scss/transitions/_index.scss +35 -143
  298. package/scss/transitions/_menu-view.scss +26 -0
  299. package/scss/transitions/_navigation-split-view.scss +23 -0
  300. package/scss/transitions/_progress-view.scss +23 -0
  301. package/scss/transitions/_sheet-view.scss +30 -0
  302. package/scss/transitions/_sidebar-view.scss +36 -0
  303. package/scss/transitions/_tab-bar.scss +20 -0
  304. package/scss/utils/_frame.scss +91 -0
  305. package/scss/utils/_index.scss +91 -0
  306. package/scss/utils/_scroll-view.scss +14 -0
  307. package/scss/utils/_spacing.scss +25 -0
  308. package/scss/utils/_stacks.scss +209 -0
  309. package/web-components.html-data/en.json +500 -0
  310. package/generated/styles.css +0 -1305
  311. package/scss/_dev.scss +0 -68
  312. package/scss/components/_tab-bar-stack.scss +0 -101
  313. package/scss/components/_toolbars.scss +0 -100
  314. package/scss/transitions/_dialog.scss +0 -32
@@ -0,0 +1,697 @@
1
+ var _a;
2
+ import { I18n } from '../i18n';
3
+ import { CleanupRegistry } from '../internal/class/cleanup-registry';
4
+ import { FormAssociatedBase, getInternals } from '../internal/class/form-associated-base';
5
+ import { MutationObserverSet } from '../internal/class/mutation-observer-set';
6
+ import { NavigationPath } from '../internal/class/navigation-path';
7
+ import { queryInsertPosition, startViewTransition } from '../internal/privateNamespace';
8
+ import { $, devFlags, kebabCase, onoff } from '../internal/utils';
9
+ const pickerStyles = ['menu', 'inline', 'navigation-link', 'sheet', 'automatic'];
10
+ const update = (path, node, overwrite = true) => {
11
+ if (!(path instanceof NavigationPath))
12
+ throw new Error('invalid view');
13
+ const { component, page } = path;
14
+ if (!component)
15
+ return;
16
+ const position = queryInsertPosition(component); //'afterend'
17
+ // const lookFor = 'beforebegin' === position ? 'previousElementSibling' : 'nextElementSibling'
18
+ if (page)
19
+ page.insertAdjacentElement(position, node);
20
+ };
21
+ const reflectSpawnedElement = (current, source) => {
22
+ const { page: oldSv, toolBarConfig: oldToolbar } = new NavigationPath(current).hydrate(), { page: newSv, toolBarConfig: newToolbar } = new NavigationPath(source).hydrate();
23
+ const oldList = oldSv?.querySelector('list-view'), newList = newSv?.querySelector('list-view'), oldBackBtn = oldToolbar?.at(0)?.querySelector('button'), newBackBtn = newToolbar?.at(0)?.querySelector('button');
24
+ // pre replace list (always exists)
25
+ const oldOpenedDetails = [...(oldList?.querySelectorAll('list-view details[open]>summary') ?? [])].map((item) => item.textContent.trim());
26
+ // replace list (always exists)
27
+ if (oldList && newList)
28
+ oldList.replaceWith(newList);
29
+ // post replace list (always exists)
30
+ for (const label of oldOpenedDetails)
31
+ for (const summary of newList?.querySelectorAll('list-view details>summary') ?? [])
32
+ if (summary.textContent.trim() === label) {
33
+ summary.parentElement?.setAttribute('open', 'open');
34
+ break;
35
+ }
36
+ // replace backbtns (always exists)
37
+ if (oldBackBtn && newBackBtn)
38
+ oldBackBtn.replaceWith(newBackBtn);
39
+ // overwrite navtitle (always exists)
40
+ oldSv?.setAttribute('navigation-inline-title', newSv?.getAttribute('navigation-inline-title') ?? '');
41
+ // replace search (if exists)
42
+ oldList?.style.setProperty('--list--sticky-block-size', newList?.style.getPropertyValue('--list--sticky-block-size') ?? '');
43
+ // replace search (if exists)
44
+ const oldSearch = oldSv?.querySelector('sticky-container'), newSearch = newSv?.querySelector('sticky-container');
45
+ // if already exists, DO NOTHING dont mess up the input element
46
+ if (newSearch) {
47
+ if (!oldSearch)
48
+ oldSv?.insertAdjacentHTML('afterend', `<sticky-container edge="navbar" style="order: -1" padding>
49
+ <v-stack spacing="0" alignment="fill">
50
+ <input is="search-view" placeholder="Search">
51
+ <button type="button">Filters</button>
52
+ </v-stack>
53
+ </sticky-container>`);
54
+ }
55
+ else
56
+ oldSearch?.remove();
57
+ };
58
+ const extractTagFromOption = (node) => {
59
+ return ((node.getAttribute('value') ?? node.textContent?.trim()) || node.getAttribute('label')) ?? '';
60
+ };
61
+ const extractCurrentValueFromOption = (node) => {
62
+ return (node.getAttribute('label') ?? node.getAttribute('value') ?? node.textContent?.trim()) || '';
63
+ };
64
+ export class PickerView extends FormAssociatedBase {
65
+ static get ATTR() {
66
+ return {
67
+ PLACEHOLDER: 'placeholder',
68
+ LABEL: 'label',
69
+ PICKER_STYLE: 'picker-style',
70
+ SELECTION: 'selection',
71
+ SEARCHABLE: 'searchable',
72
+ CURRENT_VALUE_LABEL: 'current-value-label',
73
+ };
74
+ }
75
+ static get observedAttributes() {
76
+ return Object.values(this.ATTR);
77
+ }
78
+ static #templates = new Map();
79
+ #spawn;
80
+ #spawnPage = (tag, searchable = false, title, node) => {
81
+ const body = $(`<${'sheet-view' === tag ? 'dialog is="sheet-view"' : 'body-view'}><scroll-view><v-stack placement="leading fill"><list-view preferred-expanded-style="inset"></list-view></v-stack></scroll-view><tool-bar><tool-bar-item slot="top-bar-leading"><button type="button" tabindex="0"><label-view system-image="caret-left"></label-view></button></tool-bar-item></tool-bar></${'sheet-view' === tag ? 'dialog' : 'body-view'}>`, '>1'), sv = body.querySelector('scroll-view'), list = body.querySelector('list-view'), backBtn = body.querySelector('button');
82
+ if (title)
83
+ sv?.setAttribute('navigation-inline-title', title);
84
+ if (searchable) {
85
+ list?.style.setProperty('--list--sticky-block-size', '70px');
86
+ list?.insertAdjacentHTML('afterend', `<sticky-container edge="navbar" style="order: -1" padding>
87
+ <v-stack spacing="0" alignment="fill">
88
+ <input is="search-view" placeholder="Search">
89
+ <button type="button">Filters</button>
90
+ </v-stack>
91
+ </sticky-container>`);
92
+ const searchInput = sv?.querySelector('input'); // FIXME: compoennt is=search-view??
93
+ searchInput?.addEventListener('focus', (evt) => {
94
+ if (this.#spawn)
95
+ this.dispatchEvent(new CustomEvent('picker:searchfocus', {
96
+ detail: { element: this.#spawn, search: evt.target instanceof HTMLInputElement && evt.target ? evt.target.value : '' },
97
+ bubbles: true,
98
+ composed: true,
99
+ }));
100
+ });
101
+ searchInput?.addEventListener('blur', (evt) => {
102
+ if (this.#spawn)
103
+ this.dispatchEvent(new CustomEvent('picker:searchblur', {
104
+ detail: { element: this.#spawn, search: evt.target instanceof HTMLInputElement && evt.target ? evt.target.value : '' },
105
+ bubbles: true,
106
+ composed: true,
107
+ }));
108
+ });
109
+ searchInput?.addEventListener('input', (evt) => {
110
+ if (this.#spawn)
111
+ this.dispatchEvent(new CustomEvent('picker:searchinput', {
112
+ detail: { element: this.#spawn, search: evt.target instanceof HTMLInputElement && evt.target ? evt.target.value : '' },
113
+ bubbles: true,
114
+ composed: true,
115
+ }));
116
+ });
117
+ }
118
+ backBtn?.setAttribute('help', I18n.t('ButtonRole').Back);
119
+ backBtn?.addEventListener('click', async (evt) => {
120
+ evt.stopImmediatePropagation();
121
+ evt.preventDefault();
122
+ const { target } = evt;
123
+ if (!(target instanceof HTMLElement && target))
124
+ return;
125
+ const { component } = new NavigationPath(target)?.hydrate();
126
+ await startViewTransition(target, 'backwards', async () => {
127
+ component?.remove();
128
+ });
129
+ });
130
+ const elements = node ? Array.from(node.children) : (this.#slots?.get('list')?.assignedElements() ?? []);
131
+ for (const el of elements) {
132
+ if (!(el instanceof HTMLElement))
133
+ continue;
134
+ switch (el.tagName) {
135
+ case 'OPTGROUP': {
136
+ const details = _a.#wrapOptgroupTag(el);
137
+ _a.#reflectButtons([...el.children], details);
138
+ for (const btn of details.querySelectorAll(':scope>button'))
139
+ btn.addEventListener('click', this.#handlePageBtnClick);
140
+ list?.appendChild(details);
141
+ break;
142
+ }
143
+ case 'OPTION': {
144
+ const btn = _a.#wrapOptionTag(el);
145
+ btn.addEventListener('click', this.#handlePageBtnClick);
146
+ list?.appendChild(btn);
147
+ break;
148
+ }
149
+ default: {
150
+ const btn = $(`<button type="button" tabindex="0"><label-view></label-view></button>`, '>1'), label = btn.querySelector(':scope>label-view');
151
+ if (el.dataset.label)
152
+ label?.setAttribute('title', el.dataset.label);
153
+ btn.addEventListener('click', async (evt) => {
154
+ evt.stopImmediatePropagation();
155
+ evt.preventDefault();
156
+ const { target } = evt;
157
+ if (!(target instanceof HTMLElement && target))
158
+ return;
159
+ const newPage = this.#spawnPage('body-view', this.hasAttribute('searchable'), el.dataset.label, el);
160
+ if (!newPage)
161
+ return;
162
+ const path = new NavigationPath(target)?.hydrate();
163
+ await startViewTransition(target, 'forwards', async () => {
164
+ update(path, newPage);
165
+ this.#reflectSelectionOnButtons();
166
+ });
167
+ });
168
+ list?.appendChild(btn);
169
+ break;
170
+ }
171
+ }
172
+ }
173
+ return body;
174
+ };
175
+ #renderSlotted = (entries) => {
176
+ if (devFlags.debug)
177
+ console.debug(`${_a.name} ⚡️ mutation`);
178
+ switch (this.pickerStyle) {
179
+ case 'sheet':
180
+ case 'navigation-link': {
181
+ // current value label only
182
+ const currentValueLabel = this.querySelector(':scope>label-view:not([slot])') ?? this.appendChild($(`<label-view></label-view>`, '>1'));
183
+ // reset state
184
+ currentValueLabel.setAttribute('system-image', 'dots-three'); // overwritten
185
+ currentValueLabel.setAttribute('title', this.#selection); //, this.#currentValueLabel) // overwritten
186
+ // clear all siblings
187
+ for (const el of this.querySelectorAll(':scope>:not([slot])'))
188
+ if (currentValueLabel !== el)
189
+ el.remove();
190
+ CleanupRegistry.unregister(this, 'trigger');
191
+ CleanupRegistry.register(this, onoff('click', this.#handleTriggerClick, currentValueLabel).on(), 'trigger');
192
+ // rebuild snapshot(tree)
193
+ if (!this.#spawn)
194
+ break;
195
+ // rerender level 0
196
+ reflectSpawnedElement(this.#spawn, this.#spawnPage('body-view', this.hasAttribute('searchable'), this.getAttribute('label')));
197
+ for (const el of this.#spawn.querySelectorAll('body-view')) {
198
+ const depth = $.ancestors('body-view,[is=sheet-view]', el).indexOf(this.#spawn);
199
+ if (0 >= depth)
200
+ continue;
201
+ const datalist = this.querySelector(`:scope>${Array.from({ length: depth }, () => 'datalist').join('>')}`);
202
+ if (!datalist) {
203
+ el.remove();
204
+ break;
205
+ }
206
+ reflectSpawnedElement(el, this.#spawnPage('body-view', this.hasAttribute('searchable'), datalist.dataset.label, datalist));
207
+ }
208
+ break;
209
+ }
210
+ case 'menu': {
211
+ const menu = this.querySelector(':scope>menu-view:not([slot])') ?? this.appendChild($(`<menu-view></menu-view>`, '>1'));
212
+ // reset state
213
+ menu.innerHTML = '';
214
+ menu.tabIndex = 0;
215
+ // clear all siblings
216
+ for (const el of this.querySelectorAll(':scope>:not([slot])'))
217
+ if (menu !== el)
218
+ el.remove();
219
+ const currentValueLabel = menu.querySelector(':scope>label-view[slot=label]') ?? menu.appendChild($(`<label-view slot="label"></label-view>`, '>1'));
220
+ currentValueLabel.setAttribute('system-image', 'dots-three'); // overwritten
221
+ currentValueLabel.setAttribute('title', this.#selection); //this.#currentValueLabel) // overwritten
222
+ _a.#reflectButtons([...(this.#slots?.get('list')?.assignedElements() ?? [])], menu);
223
+ break;
224
+ }
225
+ case 'inline':
226
+ default: {
227
+ const sectionTpl = `<section-view></section-view>`;
228
+ const inlineList = this.querySelector(':scope>list-view:not([slot])') ?? this.appendChild($(`<list-view>${sectionTpl}</list-view>`, '>1')), section = inlineList.querySelector(':scope>section-view') ?? inlineList.appendChild($(sectionTpl, '>1'));
229
+ // reset state
230
+ section.innerHTML = '';
231
+ // clear all siblings
232
+ for (const el of this.querySelectorAll(':scope>:not([slot])'))
233
+ if (inlineList !== el)
234
+ el.remove();
235
+ const value = this.getAttribute(this.constructor.ATTR.LABEL);
236
+ if (value) {
237
+ const label = $(`<label-view></label-view>`, '>1');
238
+ label.setAttribute('title', value);
239
+ section.insertAdjacentElement('beforeend', label);
240
+ }
241
+ _a.#reflectButtons([...(this.#slots?.get('list')?.assignedElements({ flatten: true }) ?? [])].filter((el) => el.matches('option')), section);
242
+ break;
243
+ }
244
+ }
245
+ this.#reflectSelectionOnButtons();
246
+ this.#reflectCurrentValueLabel();
247
+ };
248
+ #renderValidityMsgs = (entries) => {
249
+ if (devFlags.debug)
250
+ console.debug(`${_a.name} ⚡️ mutation`);
251
+ this.setValidity(this.validity, this.validationMessage);
252
+ };
253
+ #lastRenderedStyle; //string | null
254
+ #shadowRoot;
255
+ #slots = new Map();
256
+ #validityObservers = new MutationObserverSet(this.#renderValidityMsgs);
257
+ #observers = new MutationObserverSet(this.#renderSlotted);
258
+ #customValidity = '';
259
+ #selection = '';
260
+ get #internals() {
261
+ return getInternals(this);
262
+ }
263
+ get template() {
264
+ if (!_a.#templates.has(this.pickerStyle))
265
+ switch (this.pickerStyle) {
266
+ case 'sheet':
267
+ case 'navigation-link':
268
+ _a.#templates.set(this.pickerStyle, $(String.raw `
269
+ <label part="root picker-stack">
270
+ <div part="root picker-label-stack">
271
+ <slot name="label"></slot>
272
+ </div>
273
+ <div part="root picker-input-stack">
274
+ <slot></slot>
275
+ </div>
276
+ <slot name="list" hidden></slot>
277
+ <slot name="validity-options" hidden></slot>
278
+ </label>
279
+ `));
280
+ break;
281
+ case 'menu':
282
+ _a.#templates.set(this.pickerStyle, $(String.raw `
283
+ <label part="root picker-stack">
284
+ <div part="root picker-label-stack">
285
+ <slot name="label"></slot>
286
+ </div>
287
+ <div part="root picker-input-stack">
288
+ <slot></slot>
289
+ </div>
290
+ <slot name="list" hidden></slot>
291
+ <slot name="validity-options" hidden></slot>
292
+ </label>
293
+ `));
294
+ // break
295
+ // case 'compact':
296
+ // PickerView.#templates.set(
297
+ // style,
298
+ // Object.assign(document.createElement('template'), {
299
+ // innerHTML: String.raw`
300
+ // <label part="compact-picker">
301
+ // <input type="text" part="compact-input">
302
+ // </label>
303
+ // `,
304
+ // })
305
+ // )
306
+ // break
307
+ // case 'fancy':
308
+ // PickerView.#templates.set(
309
+ // style,
310
+ // Object.assign(document.createElement('template'), {
311
+ // innerHTML: String.raw`
312
+ // <div part="fancy-picker">
313
+ // <span>Fancy Picker</span>
314
+ // <input type="text" part="fancy-input">
315
+ // </div>
316
+ // `,
317
+ // })
318
+ // )
319
+ break;
320
+ // case 'gg':
321
+ // PickerView.#templates.set(
322
+ // style,
323
+ // Object.assign(document.createElement('template'), {
324
+ // innerHTML: String.raw`
325
+ // <label part="root text-field-stack">
326
+ // <div part="root text-field-label-stack">
327
+ // <slot name="label"></slot>
328
+ // </div>
329
+ // <div part="root text-field-input-stack">
330
+ // <input type="text" part="root input text-field-form-input" list="tickmarks">
331
+ // <datalist id="tickmarks">
332
+ // <option value="0" label="0%"></option>
333
+ // </datalist>
334
+ // </div>
335
+ // <slot name="list" hidden></slot>
336
+ // </label>`,
337
+ // })
338
+ // )
339
+ // break
340
+ case 'inline':
341
+ default:
342
+ _a.#templates.set(this.pickerStyle, $(String.raw `
343
+ <label part="root picker-stack">
344
+ <div part="root picker-label-stack">
345
+ <slot name="label"></slot>
346
+ </div>
347
+ <div part="root picker-input-stack">
348
+ <slot></slot>
349
+ </div>
350
+ <slot name="list" hidden></slot>
351
+ <slot name="validity-options" hidden></slot>
352
+ </label>`));
353
+ break;
354
+ }
355
+ return _a.#templates.get(this.pickerStyle);
356
+ }
357
+ constructor() {
358
+ super();
359
+ this.#shadowRoot = this.attachShadow({ mode: 'closed' });
360
+ }
361
+ connectedCallback() {
362
+ if (devFlags.debug)
363
+ console.debug(`${_a.name} ⚡️ connect`);
364
+ CleanupRegistry.register(this, onoff('localechange', () => {
365
+ this.#renderSlotted([]);
366
+ }, I18n.on).on());
367
+ CleanupRegistry.register(this, onoff('click', this.#handleClick, this).on());
368
+ if (!this.hasAttribute(this.constructor.ATTR.PICKER_STYLE))
369
+ this.#render(); // will be picked up by attr-change!
370
+ // finally
371
+ if (!this.hasAttribute('selection'))
372
+ return;
373
+ this.#selection = this.getAttribute('selection') ?? '';
374
+ this.#sendValueToForm(false);
375
+ }
376
+ disconnectedCallback() {
377
+ if (devFlags.debug)
378
+ console.debug(`${_a.name} ⚡️ disconnect`);
379
+ CleanupRegistry.unregister(this);
380
+ this.#validityObservers.unobserveAll();
381
+ this.#observers.unobserveAll();
382
+ }
383
+ attributeChangedCallback(name, oldValue, newValue) {
384
+ if (devFlags.debug)
385
+ console.debug(`${_a.name} ⚡️ attr-change [${name}] ("${oldValue}" → "${newValue}")`);
386
+ switch (name) {
387
+ case this.constructor.ATTR.PLACEHOLDER:
388
+ this.#reflectPlaceholder(newValue);
389
+ break;
390
+ case this.constructor.ATTR.LABEL:
391
+ this.#reflectLabel(newValue);
392
+ // this.#sendValueToForm()
393
+ break;
394
+ case this.constructor.ATTR.PICKER_STYLE:
395
+ if (oldValue === newValue)
396
+ break;
397
+ this.#render();
398
+ break;
399
+ case this.constructor.ATTR.SEARCHABLE:
400
+ if (oldValue === newValue)
401
+ break;
402
+ this.#renderSlotted([]);
403
+ break;
404
+ case this.constructor.ATTR.CURRENT_VALUE_LABEL:
405
+ // if (oldValue === newValue) break
406
+ this.#reflectCurrentValueLabel();
407
+ break;
408
+ case this.constructor.ATTR.SELECTION:
409
+ // nothing happens
410
+ break;
411
+ }
412
+ }
413
+ get pickerStyle() {
414
+ const attr = this.constructor.ATTR.PICKER_STYLE;
415
+ return pickerStyles.includes(this.getAttribute(attr) ?? '') ? this.getAttribute(attr) : 'automatic';
416
+ }
417
+ #render() {
418
+ if (devFlags.debug)
419
+ console.debug(`${_a.name} ⚡️ render (${this.pickerStyle})`);
420
+ // const style = this.getAttribute((this.constructor as typeof PickerView).ATTR.PICKER_STYLE)
421
+ if (this.#lastRenderedStyle === this.pickerStyle)
422
+ return; // skip if already applied
423
+ this.#lastRenderedStyle = this.pickerStyle;
424
+ // clear shadow DOM
425
+ this.#shadowRoot.replaceChildren(document.importNode(this.template, true));
426
+ CleanupRegistry.unregister(this, 'slots');
427
+ for (const slot of this.#shadowRoot.querySelectorAll('slot'))
428
+ this.#slots?.set(slot.name, slot);
429
+ CleanupRegistry.register(this, () => {
430
+ this.#slots = new Map();
431
+ }, 'slots');
432
+ CleanupRegistry.unregister(this, 'validities');
433
+ CleanupRegistry.register(this, onoff('slotchange', this.#handleValiditiesSlotchange, this.#slots?.get('validity-options')).on(), 'validities');
434
+ CleanupRegistry.unregister(this, 'datalist'); //off1()
435
+ CleanupRegistry.register(this, onoff('slotchange', this.#handleListSlotchange, this.#slots?.get('list')).on(), 'datalist');
436
+ // #renderSlotted should run automatically now by slotchange initial event
437
+ // switch (this.pickerStyle) {
438
+ // }
439
+ }
440
+ #sendValueToForm = (dispatchEvent = true) => {
441
+ // input.value has already been updated/synced !!
442
+ if (this.matches(':disabled'))
443
+ return this.setValidity({});
444
+ if (this.hasAttribute('required')) {
445
+ if (!this.#selection) {
446
+ this.setValidity({ badInput: true }, 'invalid-selection');
447
+ }
448
+ else
449
+ this.setValidity({});
450
+ }
451
+ else
452
+ this.setValidity({});
453
+ const entries = new FormData();
454
+ entries.append(this.name, this.#selection);
455
+ this.#internals.setFormValue(entries);
456
+ if (dispatchEvent)
457
+ this.dispatchEvent(new CustomEvent('selection', { detail: { selection: this.#selection }, bubbles: true, composed: true }));
458
+ };
459
+ #handleTriggerClick = async ({ type, target }) => {
460
+ if (devFlags.debug)
461
+ console.debug(`${_a.name} ⚡️ ${type}`);
462
+ if (!(target instanceof HTMLElement && target))
463
+ return;
464
+ this.#spawn?.remove?.();
465
+ const level0 = this.#spawnPage('sheet' === this.pickerStyle ? 'sheet-view' : 'body-view', this.hasAttribute('searchable'), this.getAttribute('label'));
466
+ if (!level0)
467
+ return;
468
+ const path = new NavigationPath(target)?.hydrate();
469
+ await startViewTransition(target, 'forwards', async () => {
470
+ this.#spawn = level0;
471
+ update(path, level0);
472
+ this.#reflectSelectionOnButtons();
473
+ });
474
+ };
475
+ #handlePageBtnClick = async (evt) => {
476
+ if (devFlags.debug)
477
+ console.debug(`${_a.name} ⚡️ ${evt?.type}`);
478
+ evt.stopImmediatePropagation();
479
+ evt.preventDefault();
480
+ const { currentTarget: btn } = evt;
481
+ if (!(btn instanceof HTMLElement && btn))
482
+ return;
483
+ // const btn = target.closest('button')
484
+ // if (!btn) return
485
+ const proceed = () => {
486
+ this.#spawn?.remove();
487
+ this.#selection = btn.getAttribute('value') ?? '';
488
+ this.#reflectSelectionOnButtons();
489
+ this.#reflectCurrentValueLabel();
490
+ this.#sendValueToForm();
491
+ };
492
+ const { body } = new NavigationPath(this.#spawn)?.hydrate();
493
+ if (!body)
494
+ return proceed();
495
+ await startViewTransition(body, 'backwards', async () => {
496
+ proceed();
497
+ });
498
+ };
499
+ #handleClick({ type, target }) {
500
+ if (devFlags.debug)
501
+ console.debug(`${_a.name} ⚡️ ${type}`);
502
+ if (!(target instanceof HTMLElement && target))
503
+ return;
504
+ const btn = target.closest('button');
505
+ if (!btn)
506
+ return;
507
+ this.#selection = btn.getAttribute('value') ?? '';
508
+ this.#reflectSelectionOnButtons();
509
+ this.#reflectCurrentValueLabel();
510
+ this.#sendValueToForm();
511
+ }
512
+ #handleValiditiesSlotchange = ({ type, target: slot }) => {
513
+ if (devFlags.debug)
514
+ console.debug(`${_a.name} ⚡️ ${type}`);
515
+ if (!(slot instanceof HTMLSlotElement && slot))
516
+ return;
517
+ const assigned = slot.assignedElements();
518
+ this.#validityObservers.syncObservations(assigned, ['value', 'label']);
519
+ // if (0 < assigned.length)
520
+ this.#renderValidityMsgs([]);
521
+ };
522
+ #handleListSlotchange = ({ type, target: slot }) => {
523
+ if (devFlags.debug)
524
+ console.debug(`${_a.name} ⚡️ ${type}`);
525
+ if (!(slot instanceof HTMLSlotElement && slot))
526
+ return;
527
+ const assigned = slot.assignedElements();
528
+ this.#observers.syncObservations(assigned);
529
+ // if (0 < assigned.length)
530
+ this.#renderSlotted([]);
531
+ };
532
+ static #wrapOptionTag(node) {
533
+ const btn = $(`<button type="button" tabindex="0"><h-stack template="auto spacer"><label-view system-image="check"></label-view></h-stack></button>`, '>1'), hStack = btn.querySelector(':scope>h-stack');
534
+ // chevron = hStack?.querySelector<HTMLElement>(':scope>label-view')
535
+ btn.setAttribute('value', extractTagFromOption(node));
536
+ // if (selection !== btn.getAttribute('value')) chevron?.style.setProperty('visibility', 'hidden')
537
+ const label = $(`<label-view></label-view>`, '>1');
538
+ label.setAttribute('title', extractCurrentValueFromOption(node));
539
+ hStack?.appendChild(label);
540
+ return btn;
541
+ }
542
+ static #wrapOptgroupTag(node) {
543
+ const labelT = `<label-view></label-view>`, summaryT = `<summary>${labelT}</summary>`;
544
+ const group = $(`<details is="disclosure-group">${summaryT}</details>`, '>1'), summary = group.querySelector(':scope>summary') ?? group.appendChild($(summaryT, '>1')), summaryLabel = summary.querySelector(':scope>label-view') ?? summary.appendChild($(labelT, '>1'));
545
+ if (node.hasAttribute('label'))
546
+ summaryLabel.setAttribute('title', node.getAttribute('label') ?? '');
547
+ if (node.hasAttribute('data-system-image'))
548
+ summaryLabel.setAttribute('system-image', node.getAttribute('data-system-image') ?? '');
549
+ return group;
550
+ }
551
+ static #reflectButtons(nodes, container) {
552
+ for (const node of nodes)
553
+ switch (node.tagName) {
554
+ case 'DATALIST': {
555
+ const group = $(`<menu-view tabindex="0"></menu-view>`, '>1'), label = group.querySelector(':scope>label-view[slot=label]') ?? group.appendChild($(`<label-view slot="label"></label-view>`, '>1'));
556
+ if (node.hasAttribute('data-label'))
557
+ label.setAttribute('title', node.getAttribute('data-label') ?? '');
558
+ if (node.hasAttribute('data-system-image'))
559
+ label.setAttribute('system-image', node.getAttribute('data-system-image') ?? '');
560
+ _a.#reflectButtons([...node.children], group);
561
+ container.appendChild(group);
562
+ break;
563
+ }
564
+ case 'OPTGROUP': {
565
+ const group = _a.#wrapOptgroupTag(node);
566
+ _a.#reflectButtons([...node.children], group);
567
+ container.appendChild(group);
568
+ break;
569
+ }
570
+ case 'OPTION':
571
+ default: {
572
+ container.appendChild(_a.#wrapOptionTag(node));
573
+ break;
574
+ }
575
+ }
576
+ }
577
+ #reflectPlaceholder(value) {
578
+ const input = this.#shadowRoot.querySelector('input');
579
+ if (input) {
580
+ if (value)
581
+ input.setAttribute('placeholder', value);
582
+ else
583
+ input.removeAttribute('placeholder');
584
+ }
585
+ }
586
+ #reflectLabel(value) {
587
+ let label = this.querySelector(':scope>label-view[slot=label]');
588
+ if (value) {
589
+ label ??= this.appendChild($(`<label-view slot="label"></label-view>`, '>1'));
590
+ label.setAttribute('foreground', 'secondary');
591
+ label.setAttribute('title', value);
592
+ }
593
+ else
594
+ label?.remove();
595
+ this.#renderSlotted([]);
596
+ }
597
+ #reflectSelectionOnButtons() {
598
+ // walk all rendered buttons (inline has buttons in list, menu has buttons in menu-view)
599
+ for (const el of this.querySelectorAll('button[value]:not([slot])'))
600
+ el.querySelector('label-view[system-image="check"]')?.style.setProperty('visibility', el.getAttribute('value') === this.#selection ? 'visible' : 'hidden');
601
+ // also sync the spawn (sheet/navigation) if open
602
+ if (this.#spawn)
603
+ for (const el of this.#spawn.querySelectorAll('list-view button[value]:not([slot])'))
604
+ el.querySelector('label-view[system-image="check"]')?.style.setProperty('visibility', el.getAttribute('value') === this.#selection ? 'visible' : 'hidden');
605
+ }
606
+ get #currentTag() {
607
+ return this.#slots
608
+ ?.get('list')
609
+ ?.assignedElements({ flatten: true })
610
+ .flatMap((el) => [...(el.matches('option') ? [el] : []), ...el.querySelectorAll('option')])
611
+ .find((el) => this.#selection === extractTagFromOption(el));
612
+ }
613
+ get #currentValueLabel() {
614
+ const cvl = this.#currentTag ? extractCurrentValueFromOption(this.#currentTag) : '';
615
+ return (this.getAttribute('current-value-label') ?? '').replaceAll('{{selection}}', this.#selection).replaceAll('{{currentValueLabel}}', this.#selection) || cvl || this.#selection;
616
+ }
617
+ #reflectCurrentValueLabel() {
618
+ switch (this.pickerStyle) {
619
+ case 'sheet':
620
+ case 'navigation-link': {
621
+ const currentValueLabel = this.querySelector(':scope>label-view:not([slot])');
622
+ currentValueLabel?.setAttribute('system-image', 'dots-three');
623
+ currentValueLabel?.setAttribute('title', this.#currentValueLabel);
624
+ break;
625
+ }
626
+ case 'menu': {
627
+ const currentValueLabel = this.querySelector(':scope>menu-view:not([slot])>label-view[slot=label]');
628
+ currentValueLabel?.setAttribute('system-image', 'dots-three');
629
+ currentValueLabel?.setAttribute('title', this.#currentValueLabel);
630
+ break;
631
+ }
632
+ case 'inline':
633
+ default: {
634
+ //
635
+ break;
636
+ }
637
+ }
638
+ }
639
+ // Optional: form participation properties
640
+ get name() {
641
+ return this.getAttribute('name') ?? this.getAttribute('label') ?? this.querySelector(':scope>[slot=label]')?.textContent ?? '';
642
+ }
643
+ setValidity = (flags, message, anchor) => {
644
+ // let msg
645
+ // if (message)
646
+ for (const k in flags) {
647
+ const key = k; // ✅ type-safe cast
648
+ if (true !== flags[key])
649
+ continue;
650
+ for (const el of this.#slots?.get('validity-options')?.assignedElements({ flatten: true }) ?? []) {
651
+ if (!el.matches('option'))
652
+ continue;
653
+ const option = el;
654
+ if (`${kebabCase(key)}` === option.value) {
655
+ message = option.label;
656
+ break;
657
+ }
658
+ else if (`${kebabCase(key)}:${message}` === option.value) {
659
+ message = option.label;
660
+ break;
661
+ }
662
+ }
663
+ }
664
+ if (!message)
665
+ for (const k in flags) {
666
+ const key = k; // ✅ type-safe cast
667
+ if (true !== flags[key])
668
+ continue;
669
+ message = kebabCase(key);
670
+ break;
671
+ }
672
+ if (devFlags.debug)
673
+ console.debug(`${_a.name} ⚡️ validity-change`);
674
+ return this.#internals.setValidity(flags, this.#customValidity || message, anchor);
675
+ };
676
+ setCustomValidity = (message) => {
677
+ this.#customValidity = message;
678
+ if (this.#customValidity)
679
+ this.#internals.setValidity({ ...this.#internals.validity, customError: true }, message);
680
+ else
681
+ this.#sendValueToForm(false);
682
+ };
683
+ formAssociatedCallback = (form) => {
684
+ this.#sendValueToForm();
685
+ };
686
+ formDisabledCallback = (disabled) => {
687
+ for (const btn of this.#shadowRoot.querySelectorAll('button'))
688
+ btn.toggleAttribute('disabled', !disabled);
689
+ };
690
+ formResetCallback = () => {
691
+ this.#selection = '';
692
+ this.#reflectSelectionOnButtons();
693
+ this.#reflectCurrentValueLabel();
694
+ this.#sendValueToForm();
695
+ };
696
+ }
697
+ _a = PickerView;