@ixfx/components 0.5.20 → 0.6.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 (285) hide show
  1. package/bundle/index.d.ts +586 -261
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +8306 -6624
  4. package/bundle/index.js.map +1 -1
  5. package/dist/ac-text.d.ts +12 -7
  6. package/dist/ac-text.d.ts.map +1 -1
  7. package/dist/ac-text.js +3 -4
  8. package/dist/ac-text.js.map +1 -1
  9. package/dist/ac-token-DVbmHmky.d.ts +107 -0
  10. package/dist/ac-token-DVbmHmky.d.ts.map +1 -0
  11. package/dist/ac-token.d.ts +2 -0
  12. package/dist/ac-token.js +646 -0
  13. package/dist/ac-token.js.map +1 -0
  14. package/dist/{button-pcDaCemT.js → button-Bn0BuLpO.js} +3 -4
  15. package/dist/{button-pcDaCemT.js.map → button-Bn0BuLpO.js.map} +1 -1
  16. package/dist/button.d.ts +2 -3
  17. package/dist/button.d.ts.map +1 -1
  18. package/dist/button.js +1 -1
  19. package/dist/checkbox.d.ts +0 -1
  20. package/dist/checkbox.d.ts.map +1 -1
  21. package/dist/checkbox.js +1 -1
  22. package/dist/checkbox.js.map +1 -1
  23. package/dist/{colour-picker-D43Q96r0.js → colour-picker-0stHB90J.js} +11 -14
  24. package/dist/{colour-picker-D43Q96r0.js.map → colour-picker-0stHB90J.js.map} +1 -1
  25. package/dist/colour-picker.d.ts +1 -1
  26. package/dist/colour-picker.js +1 -1
  27. package/dist/crumbs.d.ts +4 -2
  28. package/dist/crumbs.d.ts.map +1 -1
  29. package/dist/crumbs.js +1152 -1
  30. package/dist/crumbs.js.map +1 -0
  31. package/dist/data-controller-DOlmqNKb.js +171 -0
  32. package/dist/data-controller-DOlmqNKb.js.map +1 -0
  33. package/dist/data-display.d.ts +1 -2
  34. package/dist/data-display.d.ts.map +1 -1
  35. package/dist/data-display.js +24 -22
  36. package/dist/data-display.js.map +1 -1
  37. package/dist/data-grid-BeAkORz2.d.ts +215 -0
  38. package/dist/data-grid-BeAkORz2.d.ts.map +1 -0
  39. package/dist/data-grid.d.ts +2 -0
  40. package/dist/data-grid.js +1225 -0
  41. package/dist/data-grid.js.map +1 -0
  42. package/dist/data-provider-BAn_-oR1.d.ts +61 -0
  43. package/dist/data-provider-BAn_-oR1.d.ts.map +1 -0
  44. package/dist/{decorate-DdjvVHS-.js → decorate-VRK8rslU.js} +2 -2
  45. package/dist/{decorate-DdjvVHS-.js.map → decorate-VRK8rslU.js.map} +1 -1
  46. package/dist/{defaults-BkWCPJFL.js → defaults-BCiDhZbF.js} +20 -3
  47. package/dist/defaults-BCiDhZbF.js.map +1 -0
  48. package/dist/drag-ghost-DtSDvjri.js +85 -0
  49. package/dist/drag-ghost-DtSDvjri.js.map +1 -0
  50. package/dist/editable-label.d.ts +1 -2
  51. package/dist/editable-label.d.ts.map +1 -1
  52. package/dist/editable-label.js +1 -1
  53. package/dist/editable-label.js.map +1 -1
  54. package/dist/{incr-search-CeERfijK.js → element-search-Y8SRfPGM.js} +7 -135
  55. package/dist/element-search-Y8SRfPGM.js.map +1 -0
  56. package/dist/form-CsXJX15p.js +64 -0
  57. package/dist/form-CsXJX15p.js.map +1 -0
  58. package/dist/form.d.ts +15 -0
  59. package/dist/form.d.ts.map +1 -0
  60. package/dist/form.js +2 -0
  61. package/dist/grouped-item-lister-CNLMgdIr.d.ts +121 -0
  62. package/dist/grouped-item-lister-CNLMgdIr.d.ts.map +1 -0
  63. package/dist/grouped-item-lister.d.ts +2 -0
  64. package/dist/grouped-item-lister.js +177 -0
  65. package/dist/grouped-item-lister.js.map +1 -0
  66. package/dist/{hex-editor-B-UI4OZu.js → hex-editor-Bk6rxhfg.js} +6 -8
  67. package/dist/{hex-editor-B-UI4OZu.js.map → hex-editor-Bk6rxhfg.js.map} +1 -1
  68. package/dist/{hex-editor-CMIxtNgT.d.ts → hex-editor-Caq8vNQk.d.ts} +2 -3
  69. package/dist/hex-editor-Caq8vNQk.d.ts.map +1 -0
  70. package/dist/hex.d.ts +1 -1
  71. package/dist/hex.js +1 -1
  72. package/dist/highlight-B-eQrhhb.js.map +1 -1
  73. package/dist/{icon-Bd5BiU4b.d.ts → icon-BUwP1CZ1.d.ts} +3 -4
  74. package/dist/icon-BUwP1CZ1.d.ts.map +1 -0
  75. package/dist/{icon-CK14NUcE.js → icons-Bm2ByQ3s.js} +10 -5
  76. package/dist/icons-Bm2ByQ3s.js.map +1 -0
  77. package/dist/icons.d.ts +2 -2
  78. package/dist/icons.js +2 -8
  79. package/dist/incr-search-vCzuao-2.js +137 -0
  80. package/dist/incr-search-vCzuao-2.js.map +1 -0
  81. package/dist/incr-search.d.ts +1 -1
  82. package/dist/incr-search.js +2 -1
  83. package/dist/{index-DrKRD8_a.d.ts → index-BOUaDIW-.d.ts} +4 -4
  84. package/dist/index-BOUaDIW-.d.ts.map +1 -0
  85. package/dist/{index-CkMIKEWp.d.ts → index-BUB5SICW.d.ts} +3 -4
  86. package/dist/index-BUB5SICW.d.ts.map +1 -0
  87. package/dist/{index-tX6fKF8m.d.ts → index-BeuCXtiO.d.ts} +3 -3
  88. package/dist/index-BeuCXtiO.d.ts.map +1 -0
  89. package/dist/{index-BslNaMLo.d.ts → index-Cu5i8zZY.d.ts} +3 -3
  90. package/dist/index-Cu5i8zZY.d.ts.map +1 -0
  91. package/dist/{index-D87kRcEs.d.ts → index-RqMh1i-O.d.ts} +2 -1
  92. package/dist/index-RqMh1i-O.d.ts.map +1 -0
  93. package/dist/{index-Cdmrn0SZ.d.ts → index-ovq_GTdl.d.ts} +11 -11
  94. package/dist/index-ovq_GTdl.d.ts.map +1 -0
  95. package/dist/index.d.ts +139 -599
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +789 -2845
  98. package/dist/index.js.map +1 -1
  99. package/dist/{labelled-input-base-ORb1rGq6.d.ts → labelled-input-base-Dp_9KP0G.d.ts} +2 -3
  100. package/dist/labelled-input-base-Dp_9KP0G.d.ts.map +1 -0
  101. package/dist/{labelled-input-base-9K_w3oLj.js → labelled-input-base-hoKGwyKT.js} +2 -2
  102. package/dist/{labelled-input-base-9K_w3oLj.js.map → labelled-input-base-hoKGwyKT.js.map} +1 -1
  103. package/dist/labelled-radial-input.d.ts +4 -5
  104. package/dist/labelled-radial-input.d.ts.map +1 -1
  105. package/dist/labelled-radial-input.js +2 -3
  106. package/dist/labelled-radial-input.js.map +1 -1
  107. package/dist/labelled-range-input.d.ts +1 -1
  108. package/dist/labelled-range-input.js +2 -2
  109. package/dist/labelled-range-input.js.map +1 -1
  110. package/dist/led.d.ts +1 -2
  111. package/dist/led.d.ts.map +1 -1
  112. package/dist/led.js +1 -1
  113. package/dist/led.js.map +1 -1
  114. package/dist/menu-DIfU70AA.js +1609 -0
  115. package/dist/menu-DIfU70AA.js.map +1 -0
  116. package/dist/{menu-item-AtoP6bD4.d.ts → menu-item-BG5w7fi4.d.ts} +4 -4
  117. package/dist/menu-item-BG5w7fi4.d.ts.map +1 -0
  118. package/dist/menu.d.ts +2 -2
  119. package/dist/menu.js +1 -2
  120. package/dist/miller.d.ts +7 -5
  121. package/dist/miller.d.ts.map +1 -1
  122. package/dist/miller.js +23 -25
  123. package/dist/miller.js.map +1 -1
  124. package/dist/narrowed-text.d.ts +1 -2
  125. package/dist/narrowed-text.d.ts.map +1 -1
  126. package/dist/narrowed-text.js +14 -13
  127. package/dist/narrowed-text.js.map +1 -1
  128. package/dist/notification-pill-DyZydXoZ.d.ts +68 -0
  129. package/dist/notification-pill-DyZydXoZ.d.ts.map +1 -0
  130. package/dist/notifier.d.ts +2 -0
  131. package/dist/notifier.js +146 -0
  132. package/dist/notifier.js.map +1 -0
  133. package/dist/panel.d.ts +1 -1
  134. package/dist/panel.d.ts.map +1 -1
  135. package/dist/panel.js +1 -2
  136. package/dist/panel.js.map +1 -1
  137. package/dist/plots.d.ts +1 -1
  138. package/dist/plots.js +1 -1
  139. package/dist/polar-pad.d.ts +1 -2
  140. package/dist/polar-pad.d.ts.map +1 -1
  141. package/dist/polar-pad.js +2 -2
  142. package/dist/polar-pad.js.map +1 -1
  143. package/dist/{radial-input-Dhu5ZGP5.d.ts → radial-input-BhZeyyP-.d.ts} +2 -3
  144. package/dist/radial-input-BhZeyyP-.d.ts.map +1 -0
  145. package/dist/{radial-input-C4f-2Bya.js → radial-input-Dk8Wydp5.js} +26 -16
  146. package/dist/radial-input-Dk8Wydp5.js.map +1 -0
  147. package/dist/radial-input.d.ts +1 -1
  148. package/dist/radial-input.js +1 -1
  149. package/dist/range-input.d.ts +2 -3
  150. package/dist/range-input.d.ts.map +1 -1
  151. package/dist/range-input.js +2 -2
  152. package/dist/range-input.js.map +1 -1
  153. package/dist/range.d.ts +2 -3
  154. package/dist/range.d.ts.map +1 -1
  155. package/dist/range.js +2 -2
  156. package/dist/range.js.map +1 -1
  157. package/dist/scroll-fade-CAs1EabA.js +70 -0
  158. package/dist/scroll-fade-CAs1EabA.js.map +1 -0
  159. package/dist/select-horiz.d.ts +50 -0
  160. package/dist/select-horiz.d.ts.map +1 -0
  161. package/dist/select-horiz.js +263 -0
  162. package/dist/select-horiz.js.map +1 -0
  163. package/dist/{slider-input-SW7e2Ac2.js → slider-input-CT4gcF-o.js} +30 -27
  164. package/dist/{slider-input-SW7e2Ac2.js.map → slider-input-CT4gcF-o.js.map} +1 -1
  165. package/dist/{slider-input-BEaztT-g.d.ts → slider-input-TidGhvXt.d.ts} +2 -3
  166. package/dist/slider-input-TidGhvXt.d.ts.map +1 -0
  167. package/dist/slider-input.d.ts +1 -1
  168. package/dist/slider-input.js +1 -1
  169. package/dist/snackbar.d.ts +58 -0
  170. package/dist/snackbar.d.ts.map +1 -0
  171. package/dist/snackbar.js +265 -0
  172. package/dist/snackbar.js.map +1 -0
  173. package/dist/snap-container.d.ts +1 -2
  174. package/dist/snap-container.d.ts.map +1 -1
  175. package/dist/snap-container.js +6 -5
  176. package/dist/snap-container.js.map +1 -1
  177. package/dist/split-layout.d.ts +1 -2
  178. package/dist/split-layout.d.ts.map +1 -1
  179. package/dist/split-layout.js +5 -3
  180. package/dist/split-layout.js.map +1 -1
  181. package/dist/swipe.d.ts +1 -2
  182. package/dist/swipe.d.ts.map +1 -1
  183. package/dist/swipe.js +4 -3
  184. package/dist/swipe.js.map +1 -1
  185. package/dist/{tab-list-B8v9KntS.d.ts → tab-list-Beuh2nom.d.ts} +4 -4
  186. package/dist/tab-list-Beuh2nom.d.ts.map +1 -0
  187. package/dist/tabs.d.ts +1 -1
  188. package/dist/tabs.js +533 -1
  189. package/dist/tabs.js.map +1 -0
  190. package/dist/{tickled-controller-JDOR9B8V.d.ts → tickled-controller-BtevrRLV.d.ts} +1 -2
  191. package/dist/tickled-controller-BtevrRLV.d.ts.map +1 -0
  192. package/dist/{tickled-styles-Bgo_Lpw-.js → tickled-controller-DkAU-0qL.js} +2 -88
  193. package/dist/tickled-controller-DkAU-0qL.js.map +1 -0
  194. package/dist/tickled-styles-BrAHEj1q.js +89 -0
  195. package/dist/tickled-styles-BrAHEj1q.js.map +1 -0
  196. package/dist/{timeline-CdSI003L.js → timeline-B2fgDL4U.js} +3 -3
  197. package/dist/{timeline-CdSI003L.js.map → timeline-B2fgDL4U.js.map} +1 -1
  198. package/dist/timeline.d.ts +1 -1
  199. package/dist/timeline.js +1 -1
  200. package/dist/{tooltip-BMTSUPBU.d.ts → tooltip-BlvBUQxx.d.ts} +2 -3
  201. package/dist/tooltip-BlvBUQxx.d.ts.map +1 -0
  202. package/dist/transitory-label.d.ts +30 -0
  203. package/dist/transitory-label.d.ts.map +1 -0
  204. package/dist/transitory-label.js +249 -0
  205. package/dist/transitory-label.js.map +1 -0
  206. package/dist/{tree-CqPhQRHo.js → tree-BO6BXI2b.js} +9 -10
  207. package/dist/{tree-CqPhQRHo.js.map → tree-BO6BXI2b.js.map} +1 -1
  208. package/dist/{tree-component-CDLO1ITF.d.ts → tree-component-BvV4muxx.d.ts} +8 -124
  209. package/dist/tree-component-BvV4muxx.d.ts.map +1 -0
  210. package/dist/tree.d.ts +9 -4
  211. package/dist/tree.d.ts.map +1 -1
  212. package/dist/tree.js +1 -1
  213. package/dist/types-Bc23SI94.d.ts +72 -0
  214. package/dist/types-Bc23SI94.d.ts.map +1 -0
  215. package/dist/types-DlVNJez_.d.ts +41 -0
  216. package/dist/types-DlVNJez_.d.ts.map +1 -0
  217. package/dist/vertical-list.d.ts +122 -0
  218. package/dist/vertical-list.d.ts.map +1 -0
  219. package/dist/vertical-list.js +737 -0
  220. package/dist/vertical-list.js.map +1 -0
  221. package/dist/{wheel-nudge-Dhzi5nHc.js → wheel-nudge-BlSCe_hD.js} +2 -2
  222. package/dist/{wheel-nudge-Dhzi5nHc.js.map → wheel-nudge-BlSCe_hD.js.map} +1 -1
  223. package/dist/{wheel-nudge-C-ra_1os.d.ts → wheel-nudge-DgMTRYlh.d.ts} +1 -2
  224. package/dist/wheel-nudge-DgMTRYlh.d.ts.map +1 -0
  225. package/dist/{xy-axis-CtDDQzGZ.d.ts → xy-axis-5KhVTNoX.d.ts} +8 -6
  226. package/dist/xy-axis-5KhVTNoX.d.ts.map +1 -0
  227. package/dist/{xy-axis-BpA2eJq6.js → xy-axis-B6yMjckW.js} +8 -112
  228. package/dist/xy-axis-B6yMjckW.js.map +1 -0
  229. package/dist/xy-pad.d.ts +1 -2
  230. package/dist/xy-pad.d.ts.map +1 -1
  231. package/dist/xy-pad.js +2 -2
  232. package/dist/xy-pad.js.map +1 -1
  233. package/docs-user/README.md +4 -2
  234. package/docs-user/data-grid.md +248 -0
  235. package/docs-user/index.json +222 -0
  236. package/docs-user/llms.txt +58 -0
  237. package/docs-user/rating.md +102 -0
  238. package/docs-user/toolbar.md +135 -0
  239. package/llms.txt +58 -0
  240. package/package.json +21 -11
  241. package/dist/crumb-navigation-Pif-kupA.js +0 -1221
  242. package/dist/crumb-navigation-Pif-kupA.js.map +0 -1
  243. package/dist/defaults-BkWCPJFL.js.map +0 -1
  244. package/dist/hex-editor-CMIxtNgT.d.ts.map +0 -1
  245. package/dist/icon-Bd5BiU4b.d.ts.map +0 -1
  246. package/dist/icon-CK14NUcE.js.map +0 -1
  247. package/dist/icons.js.map +0 -1
  248. package/dist/incr-search-CeERfijK.js.map +0 -1
  249. package/dist/index-BslNaMLo.d.ts.map +0 -1
  250. package/dist/index-Cdmrn0SZ.d.ts.map +0 -1
  251. package/dist/index-CkMIKEWp.d.ts.map +0 -1
  252. package/dist/index-D87kRcEs.d.ts.map +0 -1
  253. package/dist/index-DrKRD8_a.d.ts.map +0 -1
  254. package/dist/index-tX6fKF8m.d.ts.map +0 -1
  255. package/dist/interaction-_Y2qO3QI.js +0 -1
  256. package/dist/labelled-input-base-ORb1rGq6.d.ts.map +0 -1
  257. package/dist/menu-BiFarLUA.js +0 -826
  258. package/dist/menu-BiFarLUA.js.map +0 -1
  259. package/dist/menu-item-AtoP6bD4.d.ts.map +0 -1
  260. package/dist/menu-item-yHSPV8nS.js +0 -783
  261. package/dist/menu-item-yHSPV8nS.js.map +0 -1
  262. package/dist/radial-input-C4f-2Bya.js.map +0 -1
  263. package/dist/radial-input-Dhu5ZGP5.d.ts.map +0 -1
  264. package/dist/registry-CkW7q09Q.js +0 -21
  265. package/dist/registry-CkW7q09Q.js.map +0 -1
  266. package/dist/selecthorizontal.d.ts +0 -16
  267. package/dist/selecthorizontal.d.ts.map +0 -1
  268. package/dist/selecthorizontal.js +0 -43
  269. package/dist/selecthorizontal.js.map +0 -1
  270. package/dist/slider-input-BEaztT-g.d.ts.map +0 -1
  271. package/dist/tab-list-B8v9KntS.d.ts.map +0 -1
  272. package/dist/tab-list-CR0v53KJ.js +0 -615
  273. package/dist/tab-list-CR0v53KJ.js.map +0 -1
  274. package/dist/tickled-controller-JDOR9B8V.d.ts.map +0 -1
  275. package/dist/tickled-styles-Bgo_Lpw-.js.map +0 -1
  276. package/dist/tooltip-BMTSUPBU.d.ts.map +0 -1
  277. package/dist/tree-component-CDLO1ITF.d.ts.map +0 -1
  278. package/dist/types-DSfbtHs3.d.ts +0 -8
  279. package/dist/types-DSfbtHs3.d.ts.map +0 -1
  280. package/dist/wheel-nudge-C-ra_1os.d.ts.map +0 -1
  281. package/dist/xy-axis-BpA2eJq6.js.map +0 -1
  282. package/dist/xy-axis-CtDDQzGZ.d.ts.map +0 -1
  283. package/docs-user/selecthorizontal.md +0 -32
  284. /package/bundle/{chunk-D7D4PA-g.js → rolldown-runtime-D7D4PA-g.js} +0 -0
  285. /package/dist/{chunk-D7D4PA-g.js → rolldown-runtime-D7D4PA-g.js} +0 -0
package/dist/index.js CHANGED
@@ -1,981 +1,183 @@
1
1
  import { n as buildHighlightTargets, r as clearHighlights, t as applyHighlights } from "./highlight-B-eQrhhb.js";
2
- import { n as tickledStyles, r as TickledController, t as tickledItemStyles } from "./tickled-styles-Bgo_Lpw-.js";
3
2
  import { t as themeFallbacks } from "./fallbacks-DEE1nCTt.js";
4
3
  import { t as popupSurfaceStyles } from "./popup-D80sj2QC.js";
5
- import { n as safeCustomElement, t as __decorate } from "./decorate-DdjvVHS-.js";
6
- import { a as svgToDataUri, i as registerIcon, n as hasIcon, r as iconBus, t as getIcon } from "./registry-CkW7q09Q.js";
7
- import { t as IxfxIconElement } from "./icon-CK14NUcE.js";
4
+ import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
5
+ import { c as iconBus, i as ICON_CLOSE, l as registerIcon, n as ICON_CHECK, o as getIcon, r as ICON_CHEVRON_DOWN, s as hasIcon, t as ICON_CARET_RIGHT, u as svgToDataUri } from "./defaults-BCiDhZbF.js";
6
+ import { t as IxfxIconElement } from "./icons-Bm2ByQ3s.js";
8
7
  import { AcTextElement } from "./ac-text.js";
9
- import { a as createFuzzySearch, i as createAcCompletionProvider, n as IncrSearchTreeController, r as createIncrSearch, t as createElementIncrSearch } from "./incr-search-CeERfijK.js";
10
- import { i as ICON_CLOSE, n as ICON_CHECK, r as ICON_CHEVRON_DOWN, t as ICON_CARET_RIGHT } from "./defaults-BkWCPJFL.js";
11
- import "./icons.js";
8
+ import { t as DataController } from "./data-controller-DOlmqNKb.js";
9
+ import { n as createIncrSearch, r as createFuzzySearch, t as createElementIncrSearch } from "./element-search-Y8SRfPGM.js";
10
+ import { n as createAcCompletionProvider, t as IncrSearchTreeController } from "./incr-search-vCzuao-2.js";
11
+ import { AcTokenElement } from "./ac-token.js";
12
12
  import { t as prominenceStyles } from "./prominence-DlFShic3.js";
13
- import { n as buttonStyles, t as ButtonElement } from "./button-pcDaCemT.js";
14
- import "./interaction-_Y2qO3QI.js";
15
- import "./menu-item-yHSPV8nS.js";
13
+ import { n as buttonStyles, t as ButtonElement } from "./button-Bn0BuLpO.js";
14
+ import { t as menu_exports } from "./menu-DIfU70AA.js";
16
15
  import { Checkbox } from "./checkbox.js";
17
- import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-D43Q96r0.js";
16
+ import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-0stHB90J.js";
18
17
  import { LabelledRangeInput } from "./labelled-range-input.js";
19
18
  import { t as collectDataResult } from "./data-provider-35TyWclX.js";
20
- import { i as TreeDataModel, n as TreeListElement, r as TreeBaseElement, t as TreeController } from "./tree-CqPhQRHo.js";
21
- import { n as scrollFadeStyles, t as CrumbNavigationElement } from "./crumb-navigation-Pif-kupA.js";
19
+ import { i as TreeDataModel, n as TreeListElement, r as TreeBaseElement, t as TreeController } from "./tree-BO6BXI2b.js";
20
+ import { t as scrollFadeStyles } from "./scroll-fade-CAs1EabA.js";
22
21
  import { NarrowedTextElement } from "./narrowed-text.js";
22
+ import { CrumbNavigationElement } from "./crumbs.js";
23
23
  import { DataDisplayComponent } from "./data-display.js";
24
+ import { DataGridElement } from "./data-grid.js";
24
25
  import { EditableLabel } from "./editable-label.js";
25
26
  import { t as resolveAxisStep } from "./keyboard-B5xD7Fz-.js";
26
- import { t as WheelNudgeMixin } from "./wheel-nudge-Dhzi5nHc.js";
27
+ import { t as WheelNudgeMixin } from "./wheel-nudge-BlSCe_hD.js";
28
+ import { t as FormElement } from "./form-CsXJX15p.js";
27
29
  import { PanelElement } from "./panel.js";
28
- import { t as IxfxHexEditorElement } from "./hex-editor-B-UI4OZu.js";
29
- import { t as RadialInputElement } from "./radial-input-C4f-2Bya.js";
30
+ import { GroupedItemListerElement } from "./grouped-item-lister.js";
31
+ import { VerticalListElement } from "./vertical-list.js";
32
+ import { t as IxfxHexEditorElement } from "./hex-editor-Bk6rxhfg.js";
33
+ import { t as RadialInputElement } from "./radial-input-Dk8Wydp5.js";
30
34
  import { LabelledRadialInput } from "./labelled-radial-input.js";
31
35
  import { LedElement } from "./led.js";
32
- import { t as menu_exports } from "./menu-BiFarLUA.js";
33
36
  import { MillerBaseElement, MillerListElement, MillerTreeController } from "./miller.js";
34
- import { a as TooltipElement, c as computeColour, i as PlotMultiAxis, l as parseColourScaleAttr, n as PlotSingleAxis, o as PlotDataSeries, r as PlotHistogram, s as applyAgeModification, t as PlotXyAxis, u as readBaseColour } from "./xy-axis-BpA2eJq6.js";
37
+ import { NotificationPillElement } from "./notifier.js";
38
+ import { a as PlotDataSeries, c as parseColourScaleAttr, i as PlotMultiAxis, l as readBaseColour, n as PlotSingleAxis, o as applyAgeModification, r as PlotHistogram, s as computeColour, t as PlotXyAxis } from "./xy-axis-B6yMjckW.js";
35
39
  import { PolarPad } from "./polar-pad.js";
36
40
  import { t as tooltipValueStyles } from "./tooltip-CJt3WLmN.js";
37
41
  import { RangeInput } from "./range-input.js";
38
42
  import { RangeElement } from "./range.js";
39
- import { SelectHorizontalElement } from "./selecthorizontal.js";
40
- import { t as SliderInputElement } from "./slider-input-SW7e2Ac2.js";
43
+ import { SelectHorizElement } from "./select-horiz.js";
44
+ import { t as SliderInputElement } from "./slider-input-CT4gcF-o.js";
45
+ import { SnackbarElement } from "./snackbar.js";
41
46
  import { SnapContainer } from "./snap-container.js";
42
47
  import { SplitLayoutElement } from "./split-layout.js";
43
48
  import { SwipeElement } from "./swipe.js";
44
- import { t as TabListElement } from "./tab-list-CR0v53KJ.js";
45
- import { a as resolveCssVars, i as attachTimelineInteractions, n as TimelineTrackTabElement, o as resolveGrid, r as timelineStyles, s as TimelineController, t as IxfxTimelineElement } from "./timeline-CdSI003L.js";
49
+ import { TabListElement } from "./tabs.js";
50
+ import { a as resolveCssVars, i as attachTimelineInteractions, n as TimelineTrackTabElement, o as resolveGrid, r as timelineStyles, s as TimelineController, t as IxfxTimelineElement } from "./timeline-B2fgDL4U.js";
51
+ import { TransitoryLabelElement } from "./transitory-label.js";
46
52
  import { XyPad } from "./xy-pad.js";
47
- import { LitElement, css, html, nothing, render } from "lit";
48
- import { eventOptions, property, query, queryAssignedElements, state } from "lit/decorators.js";
53
+ import { LitElement, css, html, nothing } from "lit";
54
+ import { customElement, eventOptions, property, query, queryAssignedElements, state } from "lit/decorators.js";
49
55
  import { unsafeHTML } from "lit/directives/unsafe-html.js";
50
56
  import { Trees } from "@ixfx/collections";
51
57
  import { clamper, scaler } from "@ixfx/numbers";
52
- import { repeat } from "lit/directives/repeat.js";
53
- import { keyed } from "lit/directives/keyed.js";
54
- //#region src/common/data-controller.ts
55
- function isAsyncIterable(v) {
56
- return typeof v === `object` && v !== null && Symbol.asyncIterator in v;
57
- }
58
- /**
59
- * Lit ReactiveController that manages one active data provider request at a time.
60
- *
61
- * Handles all three provider return modes (sync, async one-shot, streaming),
62
- * tracks progress, and cancels in-flight requests when a new one starts.
63
- * Calls host.requestUpdate() on every state change so the component re-renders
64
- * automatically.
65
- *
66
- * @typeParam TQuery - The query/scope type passed to the provider.
67
- * @typeParam TItem - The item type produced by the provider.
68
- *
69
- * @example
70
- * ```ts
71
- * class MyList extends LitElement {
72
- * #data = new DataController<string, MyItem>(this, myProvider);
73
- *
74
- * protected override render() {
75
- * return html`
76
- * ${this.#data.loading ? html`<span>Loading…</span>` : nothing}
77
- * ${this.#data.items.map(item => html`<div>${item.label}</div>`)}
78
- * `;
79
- * }
80
- * }
81
- * ```
82
- */
83
- var DataController = class {
84
- #host;
85
- #opts;
86
- #provider;
87
- #abort;
88
- #items = [];
89
- #loading = false;
90
- #loaded = 0;
91
- #total;
92
- #error;
93
- constructor(host, provider, options) {
94
- this.#host = host;
95
- this.#provider = provider;
96
- this.#opts = {
97
- clearOnRequest: options?.clearOnRequest ?? true,
98
- onError: options?.onError
99
- };
100
- host.addController(this);
101
- }
102
- hostConnected() {}
103
- hostDisconnected() {
104
- this.cancel();
105
- }
106
- get provider() {
107
- return this.#provider;
108
- }
109
- set provider(value) {
110
- this.#provider = value;
111
- }
112
- /** The currently accumulated items. */
113
- get items() {
114
- return this.#items;
115
- }
116
- /** True while a provider call is pending or a stream is still open. */
117
- get loading() {
118
- return this.#loading;
119
- }
120
- /** Number of items accumulated so far in the current request. */
121
- get loaded() {
122
- return this.#loaded;
123
- }
124
- /**
125
- * Provider's latest estimate of the total number of items expected.
126
- * Undefined when the provider has not reported a total.
127
- */
128
- get total() {
129
- return this.#total;
130
- }
131
- /**
132
- * Progress as a 0–1 value, or undefined when total is unknown.
133
- * Derived from loaded / total.
134
- */
135
- get progress() {
136
- if (this.#total === void 0 || this.#total === 0) return void 0;
137
- return Math.min(this.#loaded / this.#total, 1);
138
- }
139
- /** The last error thrown by the provider, or undefined if the last request succeeded. */
140
- get error() {
141
- return this.#error;
142
- }
143
- /**
144
- * Cancel any in-flight request and start a new one.
145
- * Clears items immediately unless clearOnRequest was set to false.
146
- */
147
- request(query) {
148
- this.cancel();
149
- if (!this.#provider) return;
150
- if (this.#opts.clearOnRequest) {
151
- this.#items = [];
152
- this.#loaded = 0;
153
- }
154
- this.#total = void 0;
155
- this.#error = void 0;
156
- this.#loading = true;
157
- this.#host.requestUpdate();
158
- this.#abort = new AbortController();
159
- const { signal } = this.#abort;
160
- this.#consume(this.#provider(query, signal), signal);
161
- }
162
- /** Abort any in-flight request without issuing a new one. */
163
- cancel() {
164
- this.#abort?.abort();
165
- this.#abort = void 0;
166
- if (this.#loading) {
167
- this.#loading = false;
168
- this.#host.requestUpdate();
169
- }
170
- }
171
- #consume(result, signal) {
172
- if (Array.isArray(result)) {
173
- this.#applyBatch({ items: result }, signal);
174
- this.#loading = false;
175
- this.#host.requestUpdate();
176
- } else if (isAsyncIterable(result)) this.#consumeStream(result, signal);
177
- else result.then((items) => {
178
- if (signal.aborted) return;
179
- this.#applyBatch({ items }, signal);
180
- this.#loading = false;
181
- this.#host.requestUpdate();
182
- }, (err) => {
183
- if (signal.aborted) return;
184
- this.#handleError(err);
185
- });
58
+ import { classMap } from "lit/directives/class-map.js";
59
+ //#region src/button/radio-group.ts
60
+ let RadioGroup = class RadioGroup extends LitElement {
61
+ constructor(..._args) {
62
+ super(..._args);
63
+ this.value = ``;
64
+ this.orientation = `horizontal`;
65
+ this.items = [];
66
+ this.name = ``;
67
+ this.mode = `compact`;
68
+ this.checked = false;
69
+ this.valueOff = ``;
70
+ this.iconName = ``;
71
+ this.iconNameOff = ``;
72
+ this.hideLabels = false;
73
+ this._computedItems = [];
74
+ this._icons = /* @__PURE__ */ new Map();
186
75
  }
187
- async #consumeStream(stream, signal) {
188
- try {
189
- for await (const batch of stream) {
190
- if (signal.aborted) return;
191
- this.#applyBatch(batch, signal);
192
- this.#host.requestUpdate();
193
- }
194
- } catch (err) {
195
- if (signal.aborted) return;
196
- this.#handleError(err);
197
- return;
198
- }
199
- if (!signal.aborted) {
200
- this.#loading = false;
201
- this.#host.requestUpdate();
202
- }
76
+ get _isSingleToggle() {
77
+ return this._computedItems.length === 0 && Boolean(this.textContent?.trim());
203
78
  }
204
- #applyBatch(batch, _signal) {
205
- if (batch.replace) {
206
- this.#items = [...batch.items];
207
- this.#loaded = batch.items.length;
208
- } else {
209
- this.#items = [...this.#items, ...batch.items];
210
- this.#loaded = this.#items.length;
211
- }
212
- if (batch.total !== void 0) this.#total = batch.total;
79
+ get _singleToggleIconName() {
80
+ if (!this.iconName && !this.iconNameOff) return null;
81
+ return this.checked ? this.iconName : this.iconNameOff || this.iconName;
213
82
  }
214
- #handleError(err) {
215
- this.#error = err;
216
- this.#loading = false;
217
- this.#opts.onError?.(err);
218
- this.#host.requestUpdate();
83
+ firstUpdated() {
84
+ this.#updateComputedItems();
219
85
  }
220
- };
221
- //#endregion
222
- //#region src/ac-token/ac-token.ts
223
- const DEFAULT_TOKENIZER = (text) => text.split(/[\s,;]+/);
224
- function makeLruCache(maxSize) {
225
- const map = /* @__PURE__ */ new Map();
226
- return {
227
- get: (k) => map.get(k),
228
- set: (k, v) => {
229
- if (map.has(k)) map.delete(k);
230
- map.set(k, v);
231
- if (map.size > maxSize) map.delete(map.keys().next().value);
232
- },
233
- has: (k) => map.has(k),
234
- clear: () => map.clear()
235
- };
236
- }
237
- let AcTokenElement = class AcTokenElement extends LitElement {
238
- #data;
239
- #cache;
240
- #debounceTimer;
241
- #staticProvider;
242
- #lastSuggestions;
243
- constructor() {
244
- super();
245
- this.placeholder = ``;
246
- this.cacheSize = 20;
247
- this.debounceMs = 150;
248
- this.strict = false;
249
- this.allowDuplicates = false;
250
- this._tokens = [];
251
- this._draft = ``;
252
- this._isOpen = false;
253
- this._tickled = new TickledController(this, { getItems: () => this.#data.items.map((_, i) => ({
254
- id: i,
255
- enabled: true
256
- })) });
257
- this.#data = new DataController(this, void 0, {
258
- clearOnRequest: true,
259
- onError: (err) => console.error(`[ixfx-ac-token] completionProvider error:`, err)
260
- });
261
- this.#cache = makeLruCache(20);
262
- this.#lastSuggestions = [];
263
- this.#onWrapperClick = (e) => {
264
- if (!e.target.closest(`.token-chip`)) this.shadowRoot?.querySelector(`input.draft`)?.focus();
265
- };
266
- this.#onFocus = () => {
267
- this._selectedTokenIndex = void 0;
268
- this.#scheduleSuggestionFetch(this._draft);
269
- };
270
- this.#onBlur = () => {
271
- setTimeout(() => {
272
- this._isOpen = false;
273
- this._tickled.clearTickled();
274
- this._selectedTokenIndex = void 0;
275
- }, 120);
276
- };
277
- this.#onInput = (e) => {
278
- const value = e.target.value;
279
- this._selectedTokenIndex = void 0;
280
- const parts = (this.tokenizer ?? DEFAULT_TOKENIZER)(value);
281
- if (parts.length > 1) {
282
- for (let i = 0; i < parts.length - 1; i++) {
283
- const label = parts[i].trim();
284
- if (label) this.#addToken({ label });
285
- }
286
- this._draft = parts[parts.length - 1] ?? ``;
287
- } else this._draft = value;
288
- this.#scheduleSuggestionFetch(this._draft);
289
- };
290
- this.#onKeyDown = (e) => {
291
- const input = e.target;
292
- if ((e.metaKey || e.ctrlKey) && e.key === `a`) {
293
- e.preventDefault();
294
- const parts = [...this._tokens.map((t) => t.label), this._draft.trim()].filter(Boolean);
295
- navigator.clipboard.writeText(parts.join(` `)).catch(() => {});
296
- return;
297
- }
298
- if (this._selectedTokenIndex !== void 0 && e.key.length === 1 && !e.metaKey && !e.ctrlKey && !e.altKey) {
299
- e.preventDefault();
300
- this.#startEditingSelectedToken(e.key);
301
- return;
302
- }
303
- this.#handleNavigationKey(e, input);
304
- };
305
- this.#onPaste = (e) => {
306
- e.preventDefault();
307
- const text = e.clipboardData?.getData(`text/plain`) ?? ``;
308
- if (!text) return;
309
- const parts = (this.tokenizer ?? DEFAULT_TOKENIZER)(this._draft + text).filter(Boolean);
310
- if (parts.length === 0) return;
311
- if (parts.length === 1) this._draft = parts[0];
312
- else {
313
- for (let i = 0; i < parts.length - 1; i++) {
314
- const label = parts[i].trim();
315
- if (label) this.#addToken({ label });
316
- }
317
- this._draft = parts[parts.length - 1] ?? ``;
86
+ updated(changedProperties) {
87
+ if (changedProperties.has(`checked`)) {
88
+ const input = this.shadowRoot?.querySelector(`.radio-toggle-input`);
89
+ if (input && input.checked !== this.checked) {
90
+ input.checked = this.checked;
91
+ const newValue = this.checked ? this.value || `on` : this.valueOff || void 0;
92
+ this.dispatchEvent(new CustomEvent(`change`, {
93
+ detail: {
94
+ checked: this.checked,
95
+ value: newValue
96
+ },
97
+ bubbles: true,
98
+ composed: true
99
+ }));
318
100
  }
319
- this.updateComplete.then(() => {
320
- this.shadowRoot?.querySelector(`input.draft`)?.setSelectionRange(this._draft.length, this._draft.length);
321
- });
322
- this.#scheduleSuggestionFetch(this._draft);
323
- };
324
- this.#onSuggestionPointerDown = (e, item) => {
325
- e.preventDefault();
326
- this.#selectSuggestion(item);
327
- };
328
- this.#onChipPointerDown = (e, index) => {
329
- if (e.button !== 0) return;
330
- e.preventDefault();
331
- const el = e.currentTarget;
332
- const startY = e.clientY;
333
- let dragged = false;
334
- el.setPointerCapture(e.pointerId);
335
- const cleanup = () => {
336
- el.removeEventListener(`pointermove`, onMove);
337
- el.removeEventListener(`pointerup`, onUp);
338
- };
339
- const onMove = (me) => {
340
- if (Math.abs(me.clientY - startY) > 28) {
341
- dragged = true;
342
- el.releasePointerCapture(me.pointerId);
343
- cleanup();
344
- this.#removeToken(index);
345
- this.shadowRoot?.querySelector(`input.draft`)?.focus();
346
- }
347
- };
348
- const onUp = () => {
349
- cleanup();
350
- if (!dragged) {
351
- this._selectedTokenIndex = this._selectedTokenIndex === index ? void 0 : index;
352
- this.shadowRoot?.querySelector(`input.draft`)?.focus();
353
- }
354
- };
355
- el.addEventListener(`pointermove`, onMove);
356
- el.addEventListener(`pointerup`, onUp);
357
- };
358
- this.#cache = makeLruCache(this.cacheSize);
359
- }
360
- get tokens() {
361
- return this._tokens;
362
- }
363
- set tokens(value) {
364
- this._tokens = [...value];
365
- this.#emitChange();
366
- }
367
- /**
368
- * Set the token list programmatically. Unlike the `tokens` property setter,
369
- * this does not dispatch `ac-token-change` — use it for initialisation or any
370
- * other programmatic update that should not re-enter a parent's own
371
- * `ac-token-change` handler.
372
- */
373
- setTokens(value) {
374
- this._tokens = [...value];
375
- }
376
- /** All committed token labels joined with commas. */
377
- get value() {
378
- return this._tokens.map((t) => t.label).join(`, `);
379
- }
380
- connectedCallback() {
381
- super.connectedCallback();
382
- this.#buildStaticProvider();
383
- }
384
- disconnectedCallback() {
385
- super.disconnectedCallback();
386
- if (this.#debounceTimer !== void 0) {
387
- clearTimeout(this.#debounceTimer);
388
- this.#debounceTimer = void 0;
389
- }
390
- }
391
- updated(changedProps) {
392
- if (changedProps.has(`completionProvider`) || changedProps.has(`cacheSize`)) this.#cache = makeLruCache(this.cacheSize);
393
- if (changedProps.has(`completionProvider`)) this.#buildStaticProvider();
394
- if (this.#data.items !== this.#lastSuggestions) {
395
- this.#lastSuggestions = this.#data.items;
396
- if (this.#data.items.length > 0) this._tickled.setTickled(0);
397
- else this._tickled.clearTickled();
398
- }
399
- }
400
- #buildStaticProvider() {
401
- const raw = this.getAttribute(`data-tokens`);
402
- if (!raw || this.completionProvider) {
403
- this.#staticProvider = void 0;
404
- return;
405
101
  }
406
- const items = raw.trim().split(/[\s,;]+/).filter(Boolean).map((label) => ({ label }));
407
- this.#staticProvider = createAcCompletionProvider(items);
408
- }
409
- #onWrapperClick;
410
- #onFocus;
411
- #onBlur;
412
- #onInput;
413
- #onKeyDown;
414
- #handleNavigationKey(e, input) {
415
- switch (e.key) {
416
- case `ArrowLeft`:
417
- if (input.selectionStart === 0 && input.selectionEnd === 0) {
418
- e.preventDefault();
419
- if (this._selectedTokenIndex === void 0) {
420
- if (this._tokens.length > 0) this._selectedTokenIndex = this._tokens.length - 1;
421
- } else if (this._selectedTokenIndex > 0) this._selectedTokenIndex--;
422
- }
423
- break;
424
- case `ArrowRight`:
425
- if (this._selectedTokenIndex !== void 0) {
426
- e.preventDefault();
427
- if (this._selectedTokenIndex < this._tokens.length - 1) this._selectedTokenIndex++;
428
- else this._selectedTokenIndex = void 0;
429
- }
430
- break;
431
- case `Backspace`:
432
- if (input.selectionStart === 0 && input.selectionEnd === 0) {
433
- e.preventDefault();
434
- if (this._selectedTokenIndex !== void 0) this.#removeToken(this._selectedTokenIndex);
435
- else if (this._tokens.length > 0) this.#removeToken(this._tokens.length - 1);
436
- }
437
- break;
438
- case `Enter`: {
439
- const tickledIdx = this._tickled.tickledId;
440
- if (this._isOpen && tickledIdx !== void 0 && this.#data.items[tickledIdx]) {
441
- e.preventDefault();
442
- this.#selectSuggestion(this.#data.items[tickledIdx]);
443
- } else if (!this.strict && this._draft.trim()) {
444
- e.preventDefault();
445
- this.#addToken({ label: this._draft.trim() });
446
- this._draft = ``;
447
- this.#closePopup();
448
- }
449
- break;
102
+ if (changedProperties.has(`value`) && !this._isSingleToggle) {
103
+ const inputs = this.shadowRoot?.querySelectorAll(`.radio-input`);
104
+ if (inputs) {
105
+ for (const input of inputs) if (input.checked !== (input.value === this.value)) input.checked = input.value === this.value;
450
106
  }
451
- case `ArrowDown`:
452
- if (!this._isOpen) return;
453
- e.preventDefault();
454
- this._tickled.handleKeyboardNavigation(`next`);
455
- this.#scrollSuggestionIntoView();
456
- break;
457
- case `ArrowUp`:
458
- if (!this._isOpen) return;
459
- e.preventDefault();
460
- this._tickled.handleKeyboardNavigation(`previous`);
461
- this.#scrollSuggestionIntoView();
462
- break;
463
- case `Escape`:
464
- e.preventDefault();
465
- this.#closePopup();
466
- this._selectedTokenIndex = void 0;
467
- break;
468
107
  }
469
108
  }
470
- #onPaste;
471
- #onSuggestionPointerDown;
472
- #onChipPointerDown;
473
- #startEditingSelectedToken(key) {
474
- const idx = this._selectedTokenIndex;
475
- if (idx === void 0) return;
476
- const token = this._tokens[idx];
477
- if (!token) return;
478
- const newDraft = token.label + key;
479
- this.#removeToken(idx);
480
- this._selectedTokenIndex = void 0;
481
- this._draft = newDraft;
482
- this.updateComplete.then(() => {
483
- const inp = this.shadowRoot?.querySelector(`input.draft`);
484
- if (!inp) return;
485
- inp.setSelectionRange(inp.value.length, inp.value.length);
486
- });
487
- this.#scheduleSuggestionFetch(newDraft);
109
+ #updateComputedItems() {
110
+ const options = this.querySelectorAll(`option`);
111
+ const icons = /* @__PURE__ */ new Map();
112
+ if (options.length > 0) {
113
+ this._computedItems = Array.from(options, (el) => {
114
+ const tempDiv = document.createElement(`div`);
115
+ tempDiv.innerHTML = el.innerHTML;
116
+ const iconEl = tempDiv.querySelector(`svg`);
117
+ if (iconEl) icons.set(el.getAttribute(`value`) || ``, iconEl.outerHTML);
118
+ return {
119
+ value: el.getAttribute(`value`) || ``,
120
+ label: el.textContent?.trim() || ``,
121
+ disabled: el.hasAttribute(`disabled`),
122
+ iconName: el.getAttribute(`icon-name`) || void 0,
123
+ iconNameOff: el.getAttribute(`icon-name-off`) || void 0
124
+ };
125
+ });
126
+ this._icons = icons;
127
+ } else this._computedItems = [...this.items];
488
128
  }
489
- #addToken(item) {
490
- const index = this._tokens.length;
491
- this._tokens = [...this._tokens, item];
492
- this.dispatchEvent(new CustomEvent(`ac-token-add`, {
129
+ #handleRadioChange(e) {
130
+ e.stopImmediatePropagation();
131
+ const input = e.target;
132
+ this.value = input.value;
133
+ this.dispatchEvent(new CustomEvent(`change`, {
493
134
  detail: {
494
- item,
495
- index
135
+ checked: true,
136
+ value: input.value
496
137
  },
497
138
  bubbles: true,
498
139
  composed: true
499
140
  }));
500
- this.#emitChange();
501
- }
502
- #removeToken(index) {
503
- const item = this._tokens[index];
504
- if (!item) return;
505
- this._tokens = this._tokens.filter((_, i) => i !== index);
506
- if (this._selectedTokenIndex !== void 0) {
507
- if (this._selectedTokenIndex === index) this._selectedTokenIndex = void 0;
508
- else if (this._selectedTokenIndex > index) this._selectedTokenIndex--;
509
- }
510
- this.dispatchEvent(new CustomEvent(`ac-token-remove`, {
141
+ }
142
+ #handleToggleChange(e) {
143
+ e.stopImmediatePropagation();
144
+ const input = e.target;
145
+ this.checked = input.checked;
146
+ const newValue = this.checked ? this.value || `on` : this.valueOff || void 0;
147
+ this.dispatchEvent(new CustomEvent(`change`, {
511
148
  detail: {
512
- item,
513
- index
149
+ checked: this.checked,
150
+ value: newValue
514
151
  },
515
152
  bubbles: true,
516
153
  composed: true
517
154
  }));
518
- this.#emitChange();
519
- }
520
- #selectSuggestion(item) {
521
- this.#addToken(item);
522
- this._draft = ``;
523
- this.#closePopup();
524
- }
525
- #emitChange() {
526
- this.dispatchEvent(new CustomEvent(`ac-token-change`, {
527
- detail: { tokens: this._tokens },
528
- bubbles: true,
529
- composed: true
530
- }));
531
- }
532
- #filterUsed(items) {
533
- if (this.allowDuplicates) return items;
534
- const used = new Set(this._tokens.map((t) => t.label));
535
- return items.filter((item) => !used.has(item.label));
536
- }
537
- #closePopup() {
538
- this._isOpen = false;
539
- this._tickled.clearTickled();
540
- }
541
- #cancelPending() {
542
- if (this.#debounceTimer !== void 0) {
543
- clearTimeout(this.#debounceTimer);
544
- this.#debounceTimer = void 0;
545
- }
546
- this.#data.cancel();
547
- }
548
- #scheduleSuggestionFetch(query) {
549
- const cachedProvider = this.#buildCachedProvider();
550
- if (!cachedProvider) {
551
- this._isOpen = false;
552
- return;
553
- }
554
- if (this.#debounceTimer !== void 0) clearTimeout(this.#debounceTimer);
555
- this._isOpen = true;
556
- this.#debounceTimer = setTimeout(() => {
557
- this.#data.provider = cachedProvider;
558
- this.#data.request(query);
559
- }, this.debounceMs);
560
- }
561
- #buildCachedProvider() {
562
- const raw = this.completionProvider ?? this.#staticProvider;
563
- if (!raw) return void 0;
564
- return (query, signal) => {
565
- const hit = this.#cache.get(query);
566
- if (hit !== void 0) return this.#filterUsed(hit);
567
- const result = raw(query, signal);
568
- if (Symbol.asyncIterator in new Object(result)) return result;
569
- if (Array.isArray(result)) {
570
- this.#cache.set(query, result);
571
- return this.#filterUsed(result);
572
- }
573
- return result.then((items) => {
574
- if (!signal.aborted) this.#cache.set(query, items);
575
- return this.#filterUsed(items);
576
- });
577
- };
578
- }
579
- #scrollSuggestionIntoView() {
580
- this.updateComplete.then(() => {
581
- this.shadowRoot?.querySelector(`.item.tickled`)?.scrollIntoView({ block: `nearest` });
582
- });
583
- }
584
- #renderChip(item, index) {
585
- return html`
586
- <span
587
- class="token-chip ${this._selectedTokenIndex === index ? `selected` : ``}"
588
- title=${item.subLabel ?? nothing}
589
- @pointerdown=${(e) => this.#onChipPointerDown(e, index)}
590
- >
591
- ${item.icon ? html`<ixfx-icon class="chip-icon" name=${item.icon}></ixfx-icon>` : nothing}
592
- <span class="chip-label">${item.label}</span>
593
- </span>
594
- `;
595
- }
596
- #renderSuggestion(item, index) {
597
- const isTickled = this._tickled.isTickled(index);
598
- return html`
599
- <div
600
- class="item ${isTickled ? `tickled` : ``}"
601
- role="option"
602
- id="ac-token-sugg-${index}"
603
- aria-selected=${isTickled}
604
- @pointerenter=${() => this._tickled.handlePointerEnter(index)}
605
- @pointerdown=${(e) => this.#onSuggestionPointerDown(e, item)}
606
- >
607
- ${item.icon ? html`<ixfx-icon class="sugg-icon" name=${item.icon}></ixfx-icon>` : nothing}
608
- <span class="sugg-label">${item.label}</span>
609
- ${item.subLabel ? html`<span class="sugg-sublabel">${item.subLabel}</span>` : nothing}
610
- </div>
611
- `;
612
155
  }
613
- #renderPopup() {
614
- const showEmpty = !this.#data.loading && this.#data.items.length === 0;
615
- return html`
616
- <div
617
- class="popup"
618
- role="listbox"
619
- aria-label="Suggestions"
620
- data-input-mode=${this._tickled.inputMode}
621
- @pointerleave=${(e) => this._tickled.handlePointerLeave(e)}
622
- >
623
- ${showEmpty ? html`<div class="no-results">No matching results</div>` : this.#data.items.map((item, i) => this.#renderSuggestion(item, i))}
624
- </div>
625
- `;
156
+ #renderIcon(item) {
157
+ const iconName = item.value === this.value ? item.iconName || null : item.iconNameOff || item.iconName || null;
158
+ if (iconName) return html`<ixfx-icon class="radio-icon" name="${iconName}"></ixfx-icon>`;
159
+ const iconHtml = this._icons.get(item.value);
160
+ if (!iconHtml) return null;
161
+ return html`<span class="radio-icon">${unsafeHTML(iconHtml)}</span>`;
626
162
  }
627
163
  render() {
628
- const tickledIdx = this._tickled.tickledId ?? -1;
629
- const activeDescendant = tickledIdx >= 0 ? `ac-token-sugg-${tickledIdx}` : void 0;
630
- const showPlaceholder = this._tokens.length === 0 ? this.placeholder || nothing : nothing;
631
- return html`
632
- <div class="wrapper" @click=${this.#onWrapperClick}>
633
- ${this._tokens.map((t, i) => this.#renderChip(t, i))}
634
- <input
635
- type="text"
636
- class="draft"
637
- .value=${this._draft}
638
- placeholder=${showPlaceholder}
639
- autocomplete="off"
640
- spellcheck="false"
641
- role="combobox"
642
- aria-autocomplete="list"
643
- aria-expanded=${this._isOpen}
644
- aria-activedescendant=${activeDescendant ?? nothing}
645
- @input=${this.#onInput}
646
- @keydown=${this.#onKeyDown}
647
- @focus=${this.#onFocus}
648
- @blur=${this.#onBlur}
649
- @paste=${this.#onPaste}
650
- >
651
- ${this.#data.loading ? html`<span class="spinner" aria-hidden="true"></span>` : nothing}
652
- </div>
653
- ${this._isOpen ? this.#renderPopup() : nothing}
654
- `;
655
- }
656
- static {
657
- this.styles = [
658
- themeFallbacks,
659
- tickledStyles,
660
- tickledItemStyles,
661
- css`
662
- :host {
663
- display: block;
664
- position: relative;
665
- font-family: var(--font-family, system-ui, sans-serif);
666
- font-size: var(--text-m, 12px);
667
- color: var(--surface-2-text);
668
- }
669
-
670
- /* ---- Wrapper (looks like a text input) ---- */
671
-
672
- .wrapper {
673
- display: flex;
674
- flex-wrap: wrap;
675
- align-items: center;
676
- gap: var(--ac-token-chip-gap, var(--space-xs, 3px));
677
- padding: var(--ac-token-input-padding, var(--space-xs, 3px) var(--space-m, 8px));
678
- background: var(--ac-token-input-background, var(--surface-3, var(--surface-2)));
679
- color: var(--surface-2-text);
680
- border: var(--ac-token-input-border, var(--border));
681
- border-radius: var(--ac-token-input-border-radius, var(--radius-m, 4px));
682
- cursor: text;
683
- min-height: 32px;
684
- box-sizing: border-box;
685
- transition: border-color var(--transition, 0.15s ease-out);
686
- }
687
-
688
- .wrapper:focus-within {
689
- border-color: var(--accent);
690
- }
691
-
692
- /* ---- Token chips ---- */
693
-
694
- .token-chip {
695
- display: inline-flex;
696
- align-items: center;
697
- gap: var(--space-xs, 3px);
698
- padding: 1px var(--space-m, 8px);
699
- background: var(--ac-token-chip-background, var(--surface-4));
700
- border: var(--ac-token-chip-border, var(--border));
701
- border-radius: var(--ac-token-chip-border-radius, var(--radius-s, 3px));
702
- user-select: none;
703
- cursor: default;
704
- font-size: var(--text-s, 11px);
705
- white-space: nowrap;
706
- touch-action: none;
707
- transition:
708
- background var(--transition, 0.1s ease-out),
709
- border-color var(--transition, 0.1s ease-out),
710
- color var(--transition, 0.1s ease-out);
711
- }
712
-
713
- .token-chip.selected {
714
- background: var(--ac-token-chip-selected-background, var(--accent));
715
- color: var(--ac-token-chip-selected-color, var(--accent-text, #fff));
716
- border-color: var(--accent);
717
- }
718
-
719
- .chip-icon {
720
- flex-shrink: 0;
721
- width: 1em;
722
- height: 1em;
723
- }
724
-
725
- /* ---- Draft input ---- */
726
-
727
- input.draft {
728
- flex: 1;
729
- min-width: 60px;
730
- border: none;
731
- background: transparent;
732
- color: inherit;
733
- font: inherit;
734
- outline: none;
735
- caret-color: var(--accent);
736
- padding: 1px 0;
737
- anchor-name: --ac-token-draft;
738
- }
739
-
740
- input.draft::placeholder {
741
- color: var(--surface-muted-text);
742
- }
743
-
744
- /* ---- Spinner ---- */
745
-
746
- .spinner {
747
- width: 12px;
748
- height: 12px;
749
- border: 2px solid var(--surface-5);
750
- border-top-color: var(--accent);
751
- border-radius: 50%;
752
- animation: ac-token-spin 0.7s linear infinite;
753
- flex-shrink: 0;
754
- pointer-events: none;
755
- margin-left: var(--space-xs, 3px);
756
- }
757
-
758
- @keyframes ac-token-spin {
759
- to { transform: rotate(360deg); }
760
- }
761
-
762
- /* ---- Popup ---- */
763
-
764
- .popup {
765
- position: fixed;
766
- position-anchor: --ac-token-draft;
767
- top: anchor(bottom);
768
- left: anchor(left);
769
- margin-top: 2px;
770
- position-try-fallbacks: --ac-token-popup-above;
771
- z-index: 200;
772
- background: var(--surface-3, var(--surface-2));
773
- border: var(--border);
774
- border-radius: var(--radius-m, 4px);
775
- box-shadow: var(--shadow-l, 0 4px 24px rgba(0, 0, 0, 0.5));
776
- padding: var(--space-xs, 3px) 0;
777
- max-height: 260px;
778
- min-width: 160px;
779
- overflow-y: auto;
780
- font-size: var(--ac-token-popup-font-size, var(--text-s, 11px));
781
- }
782
-
783
- @position-try --ac-token-popup-above {
784
- top: auto;
785
- bottom: anchor(top);
786
- left: anchor(left);
787
- margin-top: 0;
788
- margin-bottom: 2px;
789
- }
790
-
791
- /* ---- Suggestion items ---- */
792
-
793
- .item {
794
- /* tickledItemStyles provides base; override layout for popup context */
795
- display: flex;
796
- padding: var(--item-padding, var(--space-xs, 3px) var(--space-l, 12px));
797
- gap: var(--space-m, 8px);
798
- cursor: pointer;
799
- margin: 0 var(--space-xs, 3px);
800
- white-space: nowrap;
801
- min-height: 28px;
802
- user-select: none;
803
- }
804
-
805
- .sugg-icon {
806
- flex-shrink: 0;
807
- width: 1em;
808
- height: 1em;
809
- }
810
-
811
- .sugg-label {
812
- flex: 1;
813
- overflow: hidden;
814
- text-overflow: ellipsis;
815
- }
816
-
817
- .sugg-sublabel {
818
- flex-shrink: 0;
819
- margin-left: auto;
820
- color: var(--surface-muted-text);
821
- font-size: var(--text-s, 11px);
822
- }
823
-
824
- /* ---- Empty state ---- */
825
-
826
- .no-results {
827
- padding: var(--space-m, 8px) var(--space-l, 12px);
828
- color: var(--surface-muted-text);
829
- font-style: italic;
830
- }
831
- `
832
- ];
833
- }
834
- };
835
- __decorate([property({ type: Object })], AcTokenElement.prototype, "completionProvider", void 0);
836
- __decorate([property({ type: Object })], AcTokenElement.prototype, "tokenizer", void 0);
837
- __decorate([property({ type: String })], AcTokenElement.prototype, "placeholder", void 0);
838
- __decorate([property({
839
- type: Number,
840
- attribute: `cache-size`
841
- })], AcTokenElement.prototype, "cacheSize", void 0);
842
- __decorate([property({
843
- type: Number,
844
- attribute: `debounce-ms`
845
- })], AcTokenElement.prototype, "debounceMs", void 0);
846
- __decorate([property({ type: Boolean })], AcTokenElement.prototype, "strict", void 0);
847
- __decorate([property({
848
- type: Boolean,
849
- attribute: `allow-duplicates`
850
- })], AcTokenElement.prototype, "allowDuplicates", void 0);
851
- __decorate([state()], AcTokenElement.prototype, "_tokens", void 0);
852
- __decorate([state()], AcTokenElement.prototype, "_draft", void 0);
853
- __decorate([state()], AcTokenElement.prototype, "_selectedTokenIndex", void 0);
854
- __decorate([state()], AcTokenElement.prototype, "_isOpen", void 0);
855
- AcTokenElement = __decorate([safeCustomElement(`ixfx-ac-token`)], AcTokenElement);
856
- //#endregion
857
- //#region src/button/radio-group.ts
858
- let RadioGroup = class RadioGroup extends LitElement {
859
- constructor(..._args) {
860
- super(..._args);
861
- this.value = ``;
862
- this.orientation = `horizontal`;
863
- this.items = [];
864
- this.name = ``;
865
- this.mode = `compact`;
866
- this.checked = false;
867
- this.valueOff = ``;
868
- this.iconName = ``;
869
- this.iconNameOff = ``;
870
- this.hideLabels = false;
871
- this._computedItems = [];
872
- this._icons = /* @__PURE__ */ new Map();
873
- }
874
- get _isSingleToggle() {
875
- return this._computedItems.length === 0 && Boolean(this.textContent?.trim());
876
- }
877
- get _singleToggleIconName() {
878
- if (!this.iconName && !this.iconNameOff) return null;
879
- return this.checked ? this.iconName : this.iconNameOff || this.iconName;
880
- }
881
- firstUpdated() {
882
- this.#updateComputedItems();
883
- }
884
- updated(changedProperties) {
885
- if (changedProperties.has(`checked`)) {
886
- const input = this.shadowRoot?.querySelector(`.radio-toggle-input`);
887
- if (input && input.checked !== this.checked) {
888
- input.checked = this.checked;
889
- const newValue = this.checked ? this.value || `on` : this.valueOff || void 0;
890
- this.dispatchEvent(new CustomEvent(`change`, {
891
- detail: {
892
- checked: this.checked,
893
- value: newValue
894
- },
895
- bubbles: true,
896
- composed: true
897
- }));
898
- }
899
- }
900
- if (changedProperties.has(`value`) && !this._isSingleToggle) {
901
- const inputs = this.shadowRoot?.querySelectorAll(`.radio-input`);
902
- if (inputs) {
903
- for (const input of inputs) if (input.checked !== (input.value === this.value)) input.checked = input.value === this.value;
904
- }
905
- }
906
- }
907
- #updateComputedItems() {
908
- const options = this.querySelectorAll(`option`);
909
- const icons = /* @__PURE__ */ new Map();
910
- if (options.length > 0) {
911
- this._computedItems = Array.from(options, (el) => {
912
- const tempDiv = document.createElement(`div`);
913
- tempDiv.innerHTML = el.innerHTML;
914
- const iconEl = tempDiv.querySelector(`svg`);
915
- if (iconEl) icons.set(el.getAttribute(`value`) || ``, iconEl.outerHTML);
916
- return {
917
- value: el.getAttribute(`value`) || ``,
918
- label: el.textContent?.trim() || ``,
919
- disabled: el.hasAttribute(`disabled`),
920
- iconName: el.getAttribute(`icon-name`) || void 0,
921
- iconNameOff: el.getAttribute(`icon-name-off`) || void 0
922
- };
923
- });
924
- this._icons = icons;
925
- } else this._computedItems = [...this.items];
926
- }
927
- #handleRadioChange(e) {
928
- e.stopImmediatePropagation();
929
- const input = e.target;
930
- this.value = input.value;
931
- this.dispatchEvent(new CustomEvent(`change`, {
932
- detail: {
933
- checked: true,
934
- value: input.value
935
- },
936
- bubbles: true,
937
- composed: true
938
- }));
939
- }
940
- #handleToggleChange(e) {
941
- e.stopImmediatePropagation();
942
- const input = e.target;
943
- this.checked = input.checked;
944
- const newValue = this.checked ? this.value || `on` : this.valueOff || void 0;
945
- this.dispatchEvent(new CustomEvent(`change`, {
946
- detail: {
947
- checked: this.checked,
948
- value: newValue
949
- },
950
- bubbles: true,
951
- composed: true
952
- }));
953
- }
954
- #renderIcon(item) {
955
- const iconName = item.value === this.value ? item.iconName || null : item.iconNameOff || item.iconName || null;
956
- if (iconName) return html`<ixfx-icon class="radio-icon" name="${iconName}"></ixfx-icon>`;
957
- const iconHtml = this._icons.get(item.value);
958
- if (!iconHtml) return null;
959
- return html`<span class="radio-icon">${unsafeHTML(iconHtml)}</span>`;
960
- }
961
- render() {
962
- if (this._isSingleToggle) {
963
- const iconName = this._singleToggleIconName;
964
- const iconPart = iconName || this.hideLabels ? html`<ixfx-icon class="radio-icon" name="${iconName || `check`}"></ixfx-icon>` : null;
965
- const labelPart = !this.hideLabels ? html`<span class="radio-label" data-text="${this.textContent?.trim()}">${this.textContent?.trim()}</span>` : null;
966
- return html`
967
- <label class="radio-item ${this.checked ? `selected` : ``}">
968
- <input
969
- type="checkbox"
970
- class="radio-toggle-input"
971
- ?checked=${this.checked}
972
- @change=${this.#handleToggleChange}
973
- />
974
- ${iconPart}
975
- ${labelPart}
976
- </label>
977
- `;
978
- }
164
+ if (this._isSingleToggle) {
165
+ const iconName = this._singleToggleIconName;
166
+ const iconPart = iconName || this.hideLabels ? html`<ixfx-icon class="radio-icon" name="${iconName || `check`}"></ixfx-icon>` : null;
167
+ const labelPart = !this.hideLabels ? html`<span class="radio-label" data-text="${this.textContent?.trim()}">${this.textContent?.trim()}</span>` : null;
168
+ return html`
169
+ <label class="radio-item ${this.checked ? `selected` : ``}">
170
+ <input
171
+ type="checkbox"
172
+ class="radio-toggle-input"
173
+ ?checked=${this.checked}
174
+ @change=${this.#handleToggleChange}
175
+ />
176
+ ${iconPart}
177
+ ${labelPart}
178
+ </label>
179
+ `;
180
+ }
979
181
  return html`
980
182
  <slot @slotchange=${this.#updateComputedItems} style="display: none;"></slot>
981
183
  <div class="radio-group ${this.orientation} ${this.mode}" role="radiogroup" aria-label=${this.name}>
@@ -1605,9 +807,11 @@ var CrumbPathController = class {
1605
807
  #pathed;
1606
808
  #separator;
1607
809
  #onQuery;
810
+ #sortCompare;
1608
811
  constructor(options = {}) {
1609
812
  this.#separator = options.separator ?? `/`;
1610
813
  this.#onQuery = options.onQuery;
814
+ this.#sortCompare = options.sortCompare;
1611
815
  this.#pathed = new Trees.Pathed.Pathed({ separator: this.#separator });
1612
816
  if (options.paths) this.addPaths(options.paths);
1613
817
  }
@@ -1645,18 +849,22 @@ var CrumbPathController = class {
1645
849
  async #siblingLookup(pathSegments, _index, signal) {
1646
850
  const currentPath = pathSegments.join(this.#separator);
1647
851
  const children = [...this.#pathed.children(currentPath)];
1648
- if (children.length > 0) return children.map((node) => node.value).filter((v) => v !== void 0).map((v) => {
1649
- if (`value` in v) return v.value ?? { label: v.label };
1650
- return { label: v.label };
1651
- });
852
+ if (children.length > 0) {
853
+ const mapped = children.map((node) => node.value).filter((v) => v !== void 0).map((v) => {
854
+ if (`value` in v) return v.value ?? { label: v.label };
855
+ return { label: v.label };
856
+ });
857
+ return this.#sortCompare ? [...mapped].sort(this.#sortCompare) : mapped;
858
+ }
1652
859
  if (this.#onQuery) {
1653
860
  const newChildren = await this.#onQuery(pathSegments);
1654
- for (const child of newChildren) {
861
+ const sorted = this.#sortCompare ? [...newChildren].sort(this.#sortCompare) : newChildren;
862
+ for (const child of sorted) {
1655
863
  const childPath = currentPath.length > 0 ? `${currentPath}${this.#separator}${child.label}` : child.label;
1656
864
  this.#pathed.add(child, childPath);
1657
865
  }
1658
866
  if (signal.aborted) return [];
1659
- return newChildren;
867
+ return sorted;
1660
868
  }
1661
869
  return [];
1662
870
  }
@@ -1717,7 +925,6 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
1717
925
  case `Escape`:
1718
926
  e.preventDefault();
1719
927
  this.#closeDropdown();
1720
- break;
1721
928
  }
1722
929
  };
1723
930
  this.#onHostKeyDown = (e) => {
@@ -2056,9 +1263,11 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
2056
1263
  #onHostKeyDown;
2057
1264
  render() {
2058
1265
  const segments = this.#getSegments();
2059
- if (this._editing) return html`
1266
+ if (this._editing) {
1267
+ const editValue = this.path;
1268
+ return html`
2060
1269
  <ixfx-ac-text
2061
- .value=${this.path}
1270
+ .value=${editValue}
2062
1271
  .tabSuffix=${this.separator}
2063
1272
  .completionProvider=${this.#makeCompletionProvider()}
2064
1273
  @change=${this.#onAcChange}
@@ -2066,6 +1275,7 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
2066
1275
  @keydown=${this.#onAcKeyDown}
2067
1276
  ></ixfx-ac-text>
2068
1277
  `;
1278
+ }
2069
1279
  const rootSegments = this.#getRootSegments();
2070
1280
  const leadingCaret = this.siblingLookup && rootSegments.length === 0 ? html`
2071
1281
  <div class="caret ${this._openIdx === -1 ? `open` : ``} ${this._confirmedLeafIndices.has(``) ? `disabled` : ``}"
@@ -2547,14 +1757,15 @@ let EditableNumber = class EditableNumber extends WheelNudgeMixin(EditableLabel)
2547
1757
  this.style.setProperty(`--value`, String(normalized));
2548
1758
  let valueStart = 0;
2549
1759
  let valueEnd = normalized;
2550
- if (this.linearStyle === `bipolar`) if (normalized <= .5) {
2551
- valueStart = normalized;
2552
- valueEnd = .5;
2553
- } else {
2554
- valueStart = .5;
2555
- valueEnd = normalized;
2556
- }
2557
- else if (this.linearStyle === `unipolar`) {
1760
+ if (this.linearStyle === `bipolar`) {
1761
+ if (normalized <= .5) {
1762
+ valueStart = normalized;
1763
+ valueEnd = .5;
1764
+ } else {
1765
+ valueStart = .5;
1766
+ valueEnd = normalized;
1767
+ }
1768
+ } else if (this.linearStyle === `unipolar`) {
2558
1769
  valueStart = .5 - normalized * .5;
2559
1770
  valueEnd = .5 + normalized * .5;
2560
1771
  }
@@ -2617,7 +1828,6 @@ let EditableNumber = class EditableNumber extends WheelNudgeMixin(EditableLabel)
2617
1828
  case `End`:
2618
1829
  delta = (this.max ?? 0) - this._parseValue();
2619
1830
  handled = true;
2620
- break;
2621
1831
  }
2622
1832
  if (handled) {
2623
1833
  e.preventDefault();
@@ -2960,231 +2170,6 @@ let FormPartElement = class FormPartElement extends LitElement {
2960
2170
  __decorate([property({ type: String })], FormPartElement.prototype, "label", void 0);
2961
2171
  FormPartElement = __decorate([safeCustomElement(`ixfx-form-part`)], FormPartElement);
2962
2172
  //#endregion
2963
- //#region src/form/form-values.ts
2964
- function collectFormValues(root) {
2965
- const values = {};
2966
- root.querySelectorAll(`[name]`).forEach((el) => {
2967
- const name = el.getAttribute(`name`);
2968
- if (!name) return;
2969
- if (el instanceof HTMLInputElement) if (el.type === `radio`) {
2970
- if (el.checked) values[name] = el.value;
2971
- } else if (el.type === `checkbox`) values[name] = el.checked;
2972
- else values[name] = el.value;
2973
- else if (el instanceof HTMLSelectElement) if (el.multiple) values[name] = Array.from(el.selectedOptions).map((opt) => opt.value);
2974
- else values[name] = el.value;
2975
- else if (el instanceof HTMLTextAreaElement) values[name] = el.value;
2976
- else if (`value` in el) values[name] = el.value;
2977
- });
2978
- return values;
2979
- }
2980
- function applyFormValues(root, data) {
2981
- root.querySelectorAll(`[name]`).forEach((el) => {
2982
- const name = el.getAttribute(`name`);
2983
- if (!name || !(name in data)) return;
2984
- const value = data[name];
2985
- if (el instanceof HTMLInputElement) {
2986
- if (el.type === `radio`) el.checked = el.value === value;
2987
- else if (el.type === `checkbox`) el.checked = Boolean(value);
2988
- else el.value = String(value ?? ``);
2989
- el.dispatchEvent(new Event(`input`, { bubbles: true }));
2990
- el.dispatchEvent(new Event(`change`, { bubbles: true }));
2991
- } else if (el instanceof HTMLSelectElement) {
2992
- if (el.multiple && Array.isArray(value)) Array.from(el.options).forEach((opt) => {
2993
- opt.selected = value.includes(opt.value);
2994
- });
2995
- else el.value = String(value ?? ``);
2996
- el.dispatchEvent(new Event(`input`, { bubbles: true }));
2997
- el.dispatchEvent(new Event(`change`, { bubbles: true }));
2998
- } else if (el instanceof HTMLTextAreaElement) {
2999
- el.value = String(value ?? ``);
3000
- el.dispatchEvent(new Event(`input`, { bubbles: true }));
3001
- el.dispatchEvent(new Event(`change`, { bubbles: true }));
3002
- } else if (`value` in el) el.value = value;
3003
- });
3004
- }
3005
- //#endregion
3006
- //#region src/form/form.ts
3007
- let FormElement = class FormElement extends LitElement {
3008
- createRenderRoot() {
3009
- return this;
3010
- }
3011
- getValues() {
3012
- return collectFormValues(this);
3013
- }
3014
- setValues(data) {
3015
- applyFormValues(this, data);
3016
- }
3017
- };
3018
- FormElement = __decorate([safeCustomElement(`ixfx-form`)], FormElement);
3019
- //#endregion
3020
- //#region src/grouped-item-lister/grouped-item-lister.ts
3021
- const UNGROUPED_KEY = `__ungrouped__`;
3022
- let GroupedItemListerElement = class GroupedItemListerElement extends LitElement {
3023
- constructor(..._args) {
3024
- super(..._args);
3025
- this.grouped = false;
3026
- this.crossGroupSelection = false;
3027
- this.#subComponents = /* @__PURE__ */ new Map();
3028
- this.#clearingSelection = false;
3029
- this.#data = new DataController(this);
3030
- this.#onSelect = (event) => {
3031
- if (this.#clearingSelection) return;
3032
- const sourceEl = event.target;
3033
- let sourceKey;
3034
- for (const [key, subEl] of this.#subComponents) if (subEl === sourceEl) {
3035
- sourceKey = key;
3036
- break;
3037
- }
3038
- if (sourceKey === void 0) return;
3039
- if (this.grouped && !this.crossGroupSelection) {
3040
- this.#clearingSelection = true;
3041
- for (const [key, subEl] of this.#subComponents) if (key !== sourceKey) subEl.clearSelection();
3042
- this.#clearingSelection = false;
3043
- }
3044
- this.dispatchEvent(new CustomEvent(`grouped-select`, {
3045
- detail: {
3046
- selected: this.selectedItems,
3047
- groupKey: sourceKey === UNGROUPED_KEY ? void 0 : sourceKey
3048
- },
3049
- bubbles: true,
3050
- composed: true
3051
- }));
3052
- };
3053
- }
3054
- #groupBy;
3055
- #factory;
3056
- #subComponents;
3057
- #renderedGroups;
3058
- #clearingSelection;
3059
- #data;
3060
- get groupBy() {
3061
- return this.#groupBy;
3062
- }
3063
- set groupBy(value) {
3064
- this.#groupBy = value;
3065
- this.requestUpdate();
3066
- }
3067
- get factory() {
3068
- return this.#factory;
3069
- }
3070
- set factory(value) {
3071
- if (value === this.#factory) return;
3072
- this.#clearSubComponents();
3073
- this.#factory = value;
3074
- this.requestUpdate();
3075
- }
3076
- get provider() {
3077
- return this.#data.provider;
3078
- }
3079
- set provider(value) {
3080
- this.#data.provider = value;
3081
- if (value) this.#data.request(void 0);
3082
- }
3083
- /** The union of all selected items across every sub-component. */
3084
- get selectedItems() {
3085
- const all = /* @__PURE__ */ new Set();
3086
- for (const subEl of this.#subComponents.values()) for (const item of subEl.selectedItems) all.add(item);
3087
- return all;
3088
- }
3089
- /**
3090
- * Forward a command to all live sub-components.
3091
- * Use this to propagate changes like sort order, filter state, or view mode.
3092
- */
3093
- dispatch(commandId, args) {
3094
- for (const subEl of this.#subComponents.values()) subEl.dispatch(commandId, args);
3095
- }
3096
- createRenderRoot() {
3097
- return this;
3098
- }
3099
- connectedCallback() {
3100
- super.connectedCallback();
3101
- this.addEventListener(`select`, this.#onSelect);
3102
- }
3103
- disconnectedCallback() {
3104
- super.disconnectedCallback();
3105
- this.removeEventListener(`select`, this.#onSelect);
3106
- }
3107
- updated(changed) {
3108
- super.updated(changed);
3109
- if (changed.has(`grouped`)) this.#clearSubComponents();
3110
- this.#syncSubComponents();
3111
- }
3112
- render() {
3113
- if (!this.#factory) return nothing;
3114
- if (!this.grouped) return html`<div class="ungrouped-host"></div>`;
3115
- if (!this.#groupBy) return nothing;
3116
- this.#renderedGroups = this.#computeGroups();
3117
- return html`${repeat(this.#renderedGroups.keys(), (key) => key, (key) => html`<ixfx-panel data-group-key=${key} .title=${key}></ixfx-panel>`)}`;
3118
- }
3119
- #computeGroups() {
3120
- const groups = /* @__PURE__ */ new Map();
3121
- if (!this.#groupBy) return groups;
3122
- for (const item of this.#data.items) {
3123
- const key = this.#groupBy(item);
3124
- let bucket = groups.get(key);
3125
- if (!bucket) {
3126
- bucket = [];
3127
- groups.set(key, bucket);
3128
- }
3129
- bucket.push(item);
3130
- }
3131
- return groups;
3132
- }
3133
- #clearSubComponents() {
3134
- for (const subEl of this.#subComponents.values()) subEl.remove();
3135
- this.#subComponents.clear();
3136
- }
3137
- #syncSubComponents() {
3138
- if (!this.#factory) return;
3139
- if (!this.grouped) {
3140
- this.#syncUngrouped();
3141
- return;
3142
- }
3143
- if (!this.#groupBy) return;
3144
- this.#syncGrouped();
3145
- }
3146
- #syncUngrouped() {
3147
- const host = this.querySelector(`.ungrouped-host`);
3148
- if (!host) return;
3149
- let subEl = this.#subComponents.get(UNGROUPED_KEY);
3150
- if (!subEl) {
3151
- subEl = this.#factory(void 0);
3152
- host.appendChild(subEl);
3153
- this.#subComponents.set(UNGROUPED_KEY, subEl);
3154
- }
3155
- subEl.setItems(this.#data.items);
3156
- }
3157
- #syncGrouped() {
3158
- const groups = this.#renderedGroups ?? this.#computeGroups();
3159
- for (const key of [...this.#subComponents.keys()]) if (!groups.has(key)) {
3160
- this.#subComponents.get(key)?.remove();
3161
- this.#subComponents.delete(key);
3162
- }
3163
- for (const [key, items] of groups) {
3164
- const panel = [...this.children].find((el) => el instanceof HTMLElement && el.dataset.groupKey === key);
3165
- if (!panel) continue;
3166
- let subEl = this.#subComponents.get(key);
3167
- if (!subEl) {
3168
- subEl = this.#factory(key);
3169
- panel.appendChild(subEl);
3170
- this.#subComponents.set(key, subEl);
3171
- }
3172
- subEl.setItems(items);
3173
- }
3174
- }
3175
- #onSelect;
3176
- };
3177
- __decorate([property({
3178
- type: Boolean,
3179
- reflect: true
3180
- })], GroupedItemListerElement.prototype, "grouped", void 0);
3181
- __decorate([property({
3182
- type: Boolean,
3183
- attribute: `cross-group-selection`,
3184
- reflect: true
3185
- })], GroupedItemListerElement.prototype, "crossGroupSelection", void 0);
3186
- GroupedItemListerElement = __decorate([safeCustomElement(`ixfx-grouped-item-lister`)], GroupedItemListerElement);
3187
- //#endregion
3188
2173
  //#region src/grouped-item-lister/tree-list-adapter.ts
3189
2174
  /**
3190
2175
  * Creates an `HTMLElement` that implements `IGroupedSubComponent<T>` by wrapping
@@ -3301,779 +2286,50 @@ function createTreeListAdapter(toTreeItem, options) {
3301
2286
  const tree = getOrCreateTree();
3302
2287
  tree.root = {
3303
2288
  item: {
3304
- key: `__adapter_root__`,
3305
- label: ``,
3306
- isLeaf: false
3307
- },
3308
- children: items.map(buildNode)
3309
- };
3310
- },
3311
- clearSelection() {
3312
- treeEl?.clearSelection();
3313
- },
3314
- dispatch(commandId, args) {
3315
- options?.onDispatch?.(commandId, args, treeEl);
3316
- }
3317
- });
3318
- Object.defineProperties(adapter, {
3319
- selectedItems: {
3320
- get() {
3321
- return treeEl ? mapNodes(treeEl.selectedNodes) : /* @__PURE__ */ new Set();
3322
- },
3323
- enumerable: true,
3324
- configurable: true
3325
- },
3326
- selectionMode: {
3327
- get() {
3328
- return selectionMode;
3329
- },
3330
- set(v) {
3331
- selectionMode = v;
3332
- if (!treeEl) return;
3333
- if (v === `none`) treeEl.selectionFilter = `none`;
3334
- else if (v === `single`) {
3335
- treeEl.selectionFilter = options?.selectionFilter ?? `all`;
3336
- treeEl.interactionMode = `implicit`;
3337
- } else {
3338
- treeEl.selectionFilter = options?.selectionFilter ?? `all`;
3339
- treeEl.interactionMode = options?.interactionMode ?? `standard`;
3340
- }
3341
- },
3342
- enumerable: true,
3343
- configurable: true
3344
- }
3345
- });
3346
- return adapter;
3347
- }
3348
- //#endregion
3349
- //#region src/vertical-list/vertical-list.ts
3350
- const ITEM_SELECTOR = `li, [data-list-item]`;
3351
- function isMultiMode(mode) {
3352
- return mode === `checked` || mode === `sticky` || mode === `vscode` || mode === `standard`;
3353
- }
3354
- let VerticalListElement = class VerticalListElement extends LitElement {
3355
- constructor(..._args2) {
3356
- super(..._args2);
3357
- this.selectionMode = `single`;
3358
- this.interactionMode = `standard`;
3359
- this._selectedItems = /* @__PURE__ */ new Set();
3360
- this._searchVisible = false;
3361
- this._searchQuery = ``;
3362
- this.#customWrappers = /* @__PURE__ */ new Map();
3363
- this.#wrappedElements = /* @__PURE__ */ new Set();
3364
- this.tickled = new TickledController(this, {
3365
- getItems: () => this._getVisibleItems().map((el) => ({
3366
- id: el,
3367
- enabled: true
3368
- })),
3369
- onTickle: (id) => {
3370
- if (id !== void 0) this._dispatch(`list-tickle`, { item: id });
3371
- },
3372
- onStateChange: () => this._syncItemStates()
3373
- });
3374
- this._onPointerOver = (e) => {
3375
- const item = this._findListItem(e.composedPath());
3376
- if (item) this.tickled.handlePointerEnter(item);
3377
- };
3378
- this._onPointerLeave = (e) => {
3379
- this.tickled.handlePointerLeave(e);
3380
- };
3381
- this._onKeyDown = (e) => {
3382
- if ((e.ctrlKey || e.metaKey) && e.key === `f`) {
3383
- e.preventDefault();
3384
- this._openSearch();
3385
- return;
3386
- }
3387
- if ((e.ctrlKey || e.metaKey) && e.key === `a`) {
3388
- if ((this.selectionMode === `multiple` || isMultiMode(this.interactionMode)) && this.selectionMode !== `none`) {
3389
- e.preventDefault();
3390
- this._selectAll();
3391
- }
3392
- return;
3393
- }
3394
- if (this._searchVisible) return;
3395
- switch (e.key) {
3396
- case `ArrowDown`:
3397
- e.preventDefault();
3398
- this.tickled.handleKeyboardNavigation(`next`);
3399
- if (e.shiftKey && this.interactionMode === `vscode`) {
3400
- const cur = this.tickled.tickledId;
3401
- if (cur) this._rangeSelectTo(cur);
3402
- }
3403
- break;
3404
- case `ArrowUp`:
3405
- e.preventDefault();
3406
- this.tickled.handleKeyboardNavigation(`previous`);
3407
- if (e.shiftKey && this.interactionMode === `vscode`) {
3408
- const cur = this.tickled.tickledId;
3409
- if (cur) this._rangeSelectTo(cur);
3410
- }
3411
- break;
3412
- case `Enter`: {
3413
- const id = this.tickled.tickledId;
3414
- if (id) {
3415
- e.preventDefault();
3416
- this._dispatch(`list-item-click`, { item: id });
3417
- this._activateItem(id);
3418
- }
3419
- break;
3420
- }
3421
- case ` `: {
3422
- const id = this.tickled.tickledId;
3423
- if (id) {
3424
- e.preventDefault();
3425
- this._handleSpaceKey(id);
3426
- }
3427
- break;
3428
- }
3429
- case `Escape`:
3430
- this._clearSelection();
3431
- break;
3432
- }
3433
- };
3434
- this._onClick = (e) => {
3435
- const item = this._findListItem(e.composedPath());
3436
- if (!item) return;
3437
- this._dispatch(`list-item-click`, { item });
3438
- this._handleClickSelection(item, e);
3439
- };
3440
- this._onDblClick = (e) => {
3441
- const item = this._findListItem(e.composedPath());
3442
- if (item) this._activateItem(item);
3443
- };
3444
- this._onSearchInput = (e) => {
3445
- const input = e.target;
3446
- this._searchQuery = input.value;
3447
- this.#search?.setQuery(this._searchQuery);
3448
- };
3449
- this._onSearchKeydown = (e) => {
3450
- if (e.key === `Escape`) {
3451
- e.stopPropagation();
3452
- this._closeSearch();
3453
- } else if (e.key === `ArrowDown`) {
3454
- e.preventDefault();
3455
- this.tickled.handleKeyboardNavigation(`next`);
3456
- } else if (e.key === `ArrowUp`) {
3457
- e.preventDefault();
3458
- this.tickled.handleKeyboardNavigation(`previous`);
3459
- } else if (e.key === `Enter`) {
3460
- e.preventDefault();
3461
- e.stopPropagation();
3462
- const id = this.tickled.tickledId ?? this._getVisibleItems()[0];
3463
- if (id) {
3464
- this._dispatch(`list-item-click`, { item: id });
3465
- this._activateItem(id);
3466
- this._closeSearch();
3467
- }
3468
- }
3469
- };
3470
- }
3471
- #search;
3472
- #selectionAnchor;
3473
- #customWrappers;
3474
- #wrappedElements;
3475
- connectedCallback() {
3476
- super.connectedCallback();
3477
- if (!this.hasAttribute(`tabindex`)) this.tabIndex = 0;
3478
- this.addEventListener(`pointerover`, this._onPointerOver);
3479
- this.addEventListener(`pointerleave`, this._onPointerLeave);
3480
- this.addEventListener(`keydown`, this._onKeyDown);
3481
- this.addEventListener(`click`, this._onClick);
3482
- this.addEventListener(`dblclick`, this._onDblClick);
3483
- }
3484
- disconnectedCallback() {
3485
- super.disconnectedCallback();
3486
- this.removeEventListener(`pointerover`, this._onPointerOver);
3487
- this.removeEventListener(`pointerleave`, this._onPointerLeave);
3488
- this.removeEventListener(`keydown`, this._onKeyDown);
3489
- this.removeEventListener(`click`, this._onClick);
3490
- this.removeEventListener(`dblclick`, this._onDblClick);
3491
- this.#search?.dispose();
3492
- this.#search = void 0;
3493
- }
3494
- firstUpdated() {
3495
- this.#search = createElementIncrSearch({
3496
- container: this,
3497
- itemSelector: ITEM_SELECTOR,
3498
- getLabel: (el) => el.getAttribute(`data-search-label`) ?? el.textContent?.trim() ?? ``,
3499
- getKey: (el) => el.getAttribute(`data-key`) ?? el.getAttribute(`data-search-label`) ?? el.textContent?.trim() ?? ``,
3500
- highlightKey: `vertical-list-search`
3501
- });
3502
- }
3503
- updated(changed) {
3504
- super.updated(changed);
3505
- if (changed.has(`interactionMode`)) {
3506
- this.#selectionAnchor = void 0;
3507
- const previousSelected = this._selectedItems;
3508
- const savedWrappers = changed.get(`interactionMode`) === `checked` ? new Map(this.#customWrappers) : null;
3509
- this._syncCheckboxes();
3510
- if (previousSelected.size > 0) {
3511
- let remapped;
3512
- if (savedWrappers && savedWrappers.size > 0) remapped = new Set([...previousSelected].map((el) => savedWrappers.get(el) ?? el));
3513
- else if (this.#customWrappers.size > 0) {
3514
- const innerToWrapper = new Map([...this.#customWrappers].map(([w, i]) => [i, w]));
3515
- remapped = new Set([...previousSelected].map((el) => innerToWrapper.get(el) ?? el));
3516
- } else remapped = new Set(previousSelected);
3517
- this._selectedItems = remapped;
3518
- }
3519
- this._syncItemStates();
3520
- } else if (changed.has(`checkboxRenderer`) && this.interactionMode === `checked`) this._syncCheckboxes();
3521
- }
3522
- /** The most recently selected item, or `undefined` if nothing is selected. */
3523
- get selectedItem() {
3524
- return [...this._selectedItems].at(-1);
3525
- }
3526
- /** The full current selection set (read-only). */
3527
- get selectedItems() {
3528
- return this._selectedItems;
3529
- }
3530
- addItem(item, options) {
3531
- let el;
3532
- if (typeof item === `string`) {
3533
- const li = document.createElement(`li`);
3534
- li.textContent = item;
3535
- el = li;
3536
- } else el = item;
3537
- if (options?.notChecked) el.setAttribute(`not-checked`, ``);
3538
- this.appendChild(el);
3539
- if (this.interactionMode === `checked`) this._syncCheckboxes();
3540
- }
3541
- removeItem(item) {
3542
- item.remove();
3543
- }
3544
- clearItems() {
3545
- this.#customWrappers.clear();
3546
- this.replaceChildren();
3547
- this.#selectionAnchor = void 0;
3548
- this._selectedItems = /* @__PURE__ */ new Set();
3549
- this._syncItemStates();
3550
- }
3551
- /**
3552
- * Replace the entire item list in one call.
3553
- * Equivalent to `clearItems()` followed by `addItem()` for each element.
3554
- * Preserves `interactionMode` checkbox wrapping.
3555
- */
3556
- setItems(items) {
3557
- this.clearItems();
3558
- for (const item of items) this.appendChild(item);
3559
- if (this.interactionMode === `checked`) this._syncCheckboxes();
3560
- }
3561
- /**
3562
- * Dispatch a command to this list. No-op by default.
3563
- * Intended for use with `ixfx-grouped-item-lister`'s `dispatch()` method,
3564
- * which forwards commands to all sub-components.
3565
- */
3566
- dispatch(_commandId, _args) {}
3567
- select(item) {
3568
- this._replaceSelection(item);
3569
- }
3570
- selectMany(items) {
3571
- if (this.selectionMode !== `multiple`) throw new Error(`selectMany requires selectionMode="multiple" (current: "${this.selectionMode}")`);
3572
- const previous = this._selectedItems;
3573
- const next = new Set([...items].filter((el) => this._isCheckable(el)));
3574
- if (next.size === 0) return;
3575
- this._selectedItems = next;
3576
- this.#selectionAnchor = [...next].at(-1);
3577
- this._syncItemStates();
3578
- this._dispatch(`list-select`, {
3579
- selected: next,
3580
- previous
3581
- });
3582
- }
3583
- deselect(item) {
3584
- if (!this._selectedItems.has(item)) return;
3585
- const previous = this._selectedItems;
3586
- const next = new Set(this._selectedItems);
3587
- next.delete(item);
3588
- this._selectedItems = next;
3589
- this._syncItemStates();
3590
- this._dispatch(`list-select`, {
3591
- selected: next,
3592
- previous
3593
- });
3594
- }
3595
- clearSelection() {
3596
- this._clearSelection();
3597
- }
3598
- selectAll() {
3599
- if ((this.selectionMode === `multiple` || isMultiMode(this.interactionMode)) && this.selectionMode !== `none`) this._selectAll();
3600
- }
3601
- *selectedFilter(kind) {
3602
- const wanted = (el) => {
3603
- switch (kind) {
3604
- case `selected`: return el.hasAttribute(`data-selected`);
3605
- case `checked`: return el.hasAttribute(`data-checked`);
3606
- case `either`: return el.hasAttribute(`data-selected`) || el.hasAttribute(`data-checked`);
3607
- }
3608
- };
3609
- for (const el of this.querySelectorAll(ITEM_SELECTOR)) {
3610
- if (this.#wrappedElements.has(el)) continue;
3611
- if (el.hidden) continue;
3612
- if (wanted(el)) yield el;
3613
- }
3614
- }
3615
- _replaceSelection(item) {
3616
- if (this.selectionMode === `none`) return;
3617
- if (!this._isCheckable(item)) return;
3618
- const previous = this._selectedItems;
3619
- const next = new Set([item]);
3620
- this._selectedItems = next;
3621
- this.#selectionAnchor = item;
3622
- this._syncItemStates();
3623
- this._dispatch(`list-select`, {
3624
- selected: next,
3625
- previous
3626
- });
3627
- }
3628
- _toggleItem(item) {
3629
- if (!this._isCheckable(item)) return;
3630
- const effectiveMultiple = this.selectionMode === `multiple` || isMultiMode(this.interactionMode);
3631
- if (this.selectionMode === `none` && this.interactionMode !== `checked` && this.interactionMode !== `sticky`) return;
3632
- const previous = this._selectedItems;
3633
- const next = new Set(this._selectedItems);
3634
- if (next.has(item)) next.delete(item);
3635
- else {
3636
- if (!effectiveMultiple) next.clear();
3637
- next.add(item);
3638
- }
3639
- this._selectedItems = next;
3640
- this._syncItemStates();
3641
- this._dispatch(`list-select`, {
3642
- selected: next,
3643
- previous
3644
- });
3645
- }
3646
- _rangeSelectTo(item) {
3647
- if (this.selectionMode === `none`) return;
3648
- if (!this.#selectionAnchor) {
3649
- this._replaceSelection(item);
3650
- return;
3651
- }
3652
- const visible = this._getVisibleItems();
3653
- const anchorIdx = visible.indexOf(this.#selectionAnchor);
3654
- const targetIdx = visible.indexOf(item);
3655
- if (anchorIdx === -1 || targetIdx === -1) {
3656
- this._replaceSelection(item);
3657
- return;
3658
- }
3659
- const start = Math.min(anchorIdx, targetIdx);
3660
- const end = Math.max(anchorIdx, targetIdx);
3661
- const previous = this._selectedItems;
3662
- const next = new Set(visible.slice(start, end + 1).filter((el) => this._isCheckable(el)));
3663
- this._selectedItems = next;
3664
- this._syncItemStates();
3665
- this._dispatch(`list-select`, {
3666
- selected: next,
3667
- previous
3668
- });
3669
- }
3670
- _clearSelection() {
3671
- if (this._selectedItems.size === 0) return;
3672
- const previous = this._selectedItems;
3673
- this._selectedItems = /* @__PURE__ */ new Set();
3674
- this._syncItemStates();
3675
- this._dispatch(`list-select`, {
3676
- selected: /* @__PURE__ */ new Set(),
3677
- previous
3678
- });
3679
- }
3680
- _selectAll() {
3681
- const visible = this._getVisibleItems();
3682
- if (visible.length === 0) return;
3683
- const previous = this._selectedItems;
3684
- const next = new Set(visible.filter((el) => this._isCheckable(el)));
3685
- if (next.size === 0) return;
3686
- this._selectedItems = next;
3687
- this._syncItemStates();
3688
- this._dispatch(`list-select`, {
3689
- selected: next,
3690
- previous
3691
- });
3692
- }
3693
- _handleClickSelection(item, e) {
3694
- const mode = this.interactionMode;
3695
- if (mode === `manual`) return;
3696
- if (this.selectionMode === `none` && mode !== `checked` && mode !== `sticky`) return;
3697
- switch (mode) {
3698
- case `implicit`:
3699
- this._replaceSelection(item);
3700
- break;
3701
- case `standard`:
3702
- case `vscode`:
3703
- if (e.ctrlKey || e.metaKey) {
3704
- if (this.selectionMode === `multiple` || mode === `vscode`) this._toggleItem(item);
3705
- } else if (e.shiftKey && (this.selectionMode === `multiple` || mode === `vscode`)) this._rangeSelectTo(item);
3706
- else this._replaceSelection(item);
3707
- break;
3708
- case `checked`: break;
3709
- case `sticky`:
3710
- this._toggleItem(item);
3711
- break;
3712
- }
3713
- }
3714
- _handleSpaceKey(item) {
3715
- const mode = this.interactionMode;
3716
- if (mode === `manual`) return;
3717
- if (mode === `implicit`) this._replaceSelection(item);
3718
- else this._toggleItem(item);
3719
- }
3720
- _getVisibleItems() {
3721
- return Array.from(this.querySelectorAll(ITEM_SELECTOR)).filter((el) => {
3722
- if (this.#wrappedElements.has(el)) return false;
3723
- if (el.hidden) return false;
3724
- if (this.filterPredicate && !this.filterPredicate(el)) return false;
3725
- return true;
3726
- });
3727
- }
3728
- _isCheckable(item) {
3729
- if (this.interactionMode !== `checked`) return true;
3730
- return !(this.#customWrappers.get(item) ?? item).hasAttribute(`not-checked`);
3731
- }
3732
- _syncItemStates() {
3733
- for (const el of this.querySelectorAll(ITEM_SELECTOR)) {
3734
- if (this.#wrappedElements.has(el)) continue;
3735
- const item = this.#customWrappers.get(el) ?? el;
3736
- el.toggleAttribute(`data-tickled`, this.tickled.isTickled(el));
3737
- el.toggleAttribute(`data-selected`, this._selectedItems.has(el));
3738
- if (this.interactionMode === `checked`) el.toggleAttribute(`data-checked`, !item.hasAttribute(`not-checked`) && this._selectedItems.has(el));
3739
- else el.removeAttribute(`data-checked`);
3740
- }
3741
- this.dataset.inputMode = this.tickled.inputMode;
3742
- this._syncCheckboxes();
3743
- }
3744
- _syncCheckboxes() {
3745
- const inCheckedMode = this.interactionMode === `checked`;
3746
- const wantsCustom = typeof this.checkboxRenderer === `function`;
3747
- if (inCheckedMode) for (const inner of Array.from(this.children)) {
3748
- if (!inner.hasAttribute(`data-list-item`)) continue;
3749
- if (inner.parentElement !== this) continue;
3750
- const wrapper = document.createElement(`li`);
3751
- wrapper.className = `ixfx-custom-row`;
3752
- const key = inner.getAttribute(`data-key`);
3753
- const label = inner.getAttribute(`data-search-label`);
3754
- if (key !== null) wrapper.setAttribute(`data-key`, key);
3755
- if (label !== null) wrapper.setAttribute(`data-search-label`, label);
3756
- inner.removeAttribute(`data-list-item`);
3757
- this.insertBefore(wrapper, inner);
3758
- wrapper.appendChild(inner);
3759
- this.#customWrappers.set(wrapper, inner);
3760
- this.#wrappedElements.add(inner);
3761
- }
3762
- else {
3763
- for (const [wrapper, inner] of this.#customWrappers) {
3764
- if (wrapper.parentElement !== this) continue;
3765
- inner.setAttribute(`data-list-item`, ``);
3766
- this.insertBefore(inner, wrapper);
3767
- wrapper.remove();
3768
- }
3769
- this.#customWrappers.clear();
3770
- this.#wrappedElements.clear();
3771
- }
3772
- for (const el of this.querySelectorAll(`li`)) {
3773
- const existing = el.querySelector(`.ixfx-list-checkbox`);
3774
- if (!inCheckedMode) {
3775
- if (existing) existing.remove();
3776
- continue;
3777
- }
3778
- if ((this.#customWrappers.get(el) ?? el).hasAttribute(`not-checked`)) {
3779
- if (existing) existing.remove();
3780
- continue;
3781
- }
3782
- const existingIsCustom = existing?.classList.contains(`ixfx-list-checkbox-custom`) ?? false;
3783
- if (existing && existingIsCustom !== wantsCustom) existing.remove();
3784
- let cb = el.querySelector(`.ixfx-list-checkbox`);
3785
- if (!cb) {
3786
- if (wantsCustom) {
3787
- const opts = this.checkboxRenderer;
3788
- const margin = opts.margin ?? `0`;
3789
- const width = opts.width ?? `24px`;
3790
- cb = this._createCustomCheckbox(el, margin, width);
3791
- } else cb = this._createNativeCheckboxCell(el);
3792
- el.prepend(cb);
3793
- }
3794
- const checked = this._selectedItems.has(el);
3795
- if (wantsCustom) {
3796
- cb.setAttribute(`aria-checked`, String(checked));
3797
- cb.toggleAttribute(`data-checked`, checked);
3798
- if (this.checkboxRenderer) render((typeof this.checkboxRenderer === `function` ? this.checkboxRenderer : this.checkboxRenderer.renderer)(checked), cb);
3799
- } else {
3800
- const input = cb.querySelector(`input.ixfx-list-checkbox`);
3801
- if (input) input.checked = checked;
3802
- }
3803
- }
3804
- }
3805
- /**
3806
- * Native checkbox cell: a span that stretches to the row's full cross-axis
3807
- * (so the entire column height is a click target) with a real `<input>`
3808
- * centred inside. The span owns the click; the input is purely visual and
3809
- * has `pointer-events:none` so a single click produces one toggle.
3810
- */
3811
- _createNativeCheckboxCell(el) {
3812
- const cell = document.createElement(`span`);
3813
- cell.className = `ixfx-list-checkbox ixfx-list-checkbox-native`;
3814
- cell.style.cssText = `display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;align-self:stretch;width:18px;margin:0 6px 0 0;cursor:pointer;pointer-events:auto`;
3815
- cell.tabIndex = -1;
3816
- cell.setAttribute(`role`, `checkbox`);
3817
- cell.setAttribute(`part`, `checkbox`);
3818
- cell.addEventListener(`click`, (e) => {
3819
- e.stopPropagation();
3820
- this._toggleItem(el);
3821
- });
3822
- const input = document.createElement(`input`);
3823
- input.type = `checkbox`;
3824
- input.className = `ixfx-list-checkbox`;
3825
- input.style.cssText = `pointer-events:none;cursor:pointer;margin:0`;
3826
- cell.appendChild(input);
3827
- return cell;
3828
- }
3829
- /**
3830
- * Custom checkbox cell: same shape as the native cell (a stretching span)
3831
- * so behaviour is identical. The renderer's content goes inside.
3832
- */
3833
- _createCustomCheckbox(el, margin, width) {
3834
- const span = document.createElement(`span`);
3835
- span.className = `ixfx-list-checkbox ixfx-list-checkbox-custom`;
3836
- span.style.cssText = `display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;align-self:stretch;width:${width};margin:${margin};cursor:pointer;pointer-events:auto`;
3837
- span.tabIndex = -1;
3838
- span.setAttribute(`role`, `checkbox`);
3839
- span.setAttribute(`part`, `checkbox`);
3840
- span.addEventListener(`click`, (e) => {
3841
- e.stopPropagation();
3842
- this._toggleItem(el);
3843
- });
3844
- return span;
3845
- }
3846
- _findListItem(path) {
3847
- for (const target of path) {
3848
- if (!(target instanceof Element)) continue;
3849
- if (target === this) break;
3850
- if (target.parentElement === this && target.matches(ITEM_SELECTOR)) return target;
3851
- }
3852
- }
3853
- _dispatch(name, detail) {
3854
- this.dispatchEvent(new CustomEvent(name, {
3855
- detail,
3856
- bubbles: true,
3857
- composed: true
3858
- }));
3859
- }
3860
- _openSearch() {
3861
- this._searchVisible = true;
3862
- this.updateComplete.then(() => this._searchInputEl?.focus());
3863
- }
3864
- _closeSearch() {
3865
- this._searchVisible = false;
3866
- this._searchQuery = ``;
3867
- this.#search?.clearQuery();
3868
- this.focus();
3869
- }
3870
- _activateItem(item) {
3871
- if (this.interactionMode !== `manual`) this._replaceSelection(item);
3872
- this._dispatch(`list-activate`, { item });
3873
- }
3874
- static {
3875
- this.styles = [themeFallbacks, css`
3876
- :host {
3877
- display: block;
3878
- position: relative;
3879
- background: var(--list-bg, var(--surface-3));
3880
- color: var(--list-text, var(--surface-3-text));
3881
- border-radius: var(--list-radius, var(--radius-s));
3882
- border: 1px solid var(--list-border, var(--border));
3883
- width: 100%;
3884
- height: 100%;
3885
- overflow: hidden;
3886
- box-sizing: border-box;
3887
- outline: none;
3888
- --ixfx-list-item-padding: var(--ixfx-list-item-padding, var(--list-item-padding, 4px var(--space-m, 8px)));
3889
- }
3890
-
3891
- :host(:focus-visible) {
3892
- outline: 2px solid var(--accent);
3893
- outline-offset: 2px;
3894
- }
3895
-
3896
- .container {
3897
- position: relative;
3898
- width: 100%;
3899
- height: 100%;
3900
- }
3901
-
3902
- ul {
3903
- list-style: none;
3904
- margin: 0;
3905
- padding: 0;
3906
- width: 100%;
3907
- height: 100%;
3908
- overflow-x: hidden;
3909
- overflow-y: auto;
3910
- box-sizing: border-box;
3911
- /* Scrollbar theming: end users override these CSS variables to control
3912
- the native scrollbar (scrollbar-width, scrollbar-gutter, scrollbar-color). */
3913
- scrollbar-width: var(--list-scrollbar-width, auto);
3914
- scrollbar-gutter: var(--list-scrollbar-gutter, auto);
3915
- scrollbar-color: var(--list-scrollbar-color, auto);
3916
- }
3917
-
3918
- ::slotted([hidden]) {
3919
- display: none !important;
3920
- }
3921
-
3922
- ::slotted(li) {
3923
- display: flex;
3924
- align-items: center;
3925
- padding: var(--ixfx-list-item-padding);
3926
- min-height: var(--list-item-height, 28px);
3927
- cursor: pointer;
3928
- user-select: none;
3929
- transition: background var(--transition, 0.1s ease-out),
3930
- outline-color var(--transition, 0.1s ease-out);
3931
- box-sizing: border-box;
3932
- outline: 1px solid transparent;
3933
- }
3934
-
3935
- /* Custom shadow-DOM components handle their own internal layout/padding */
3936
- ::slotted([data-list-item]) {
3937
- display: block;
3938
- cursor: pointer;
3939
- user-select: none;
3940
- transition: background var(--transition, 0.1s ease-out),
3941
- outline-color var(--transition, 0.1s ease-out);
3942
- outline: 1px solid transparent;
3943
- }
3944
-
3945
- /* In checked mode, only the checkbox column is clickable; the row body
3946
- gets a default cursor so it doesn't suggest otherwise. */
3947
- :host([interaction-mode="checked"]) ::slotted(li),
3948
- :host([interaction-mode="checked"]) ::slotted([data-list-item]) {
3949
- cursor: default;
3950
- }
3951
-
3952
- /* Wrapper inserted around custom [data-list-item] elements in checked mode.
3953
- Provides the flex layout so the injected checkbox can stretch to the
3954
- row's full height via align-self:stretch. */
3955
- .ixfx-custom-row {
3956
- display: flex;
3957
- align-items: center;
3958
- min-height: var(--list-item-height, 28px);
3959
- box-sizing: border-box;
3960
- cursor: default;
3961
- user-select: none;
3962
- }
3963
-
3964
- ::slotted([data-tickled]) {
3965
- background: var(--item-bg-tickled);
3966
- outline: var(--item-border-tickled);
3967
- }
3968
-
3969
- ::slotted([data-selected]) {
3970
- background: var(--item-bg-selected);
3971
- color: var(--item-text-selected);
3972
- outline: 1px solid transparent;
3973
- }
3974
-
3975
- ::slotted([data-selected][data-tickled]) {
3976
- background: var(--item-bg-selected-tickled);
3977
- outline: 2px dashed var(--surface-3);
3978
- outline-offset: -2px;
3979
- }
3980
-
3981
- /* checked mode: checkbox (injected into li) communicates selection — suppress bg highlight */
3982
- :host([interaction-mode="checked"]) ::slotted([data-selected]) {
3983
- background: transparent;
3984
- color: inherit;
3985
- outline: 1px solid transparent;
3986
- }
3987
-
3988
- :host([interaction-mode="checked"]) ::slotted([data-selected][data-tickled]) {
3989
- background: var(--item-bg-tickled);
3990
- color: inherit;
3991
- outline: var(--item-border-tickled);
3992
- }
3993
-
3994
- .search-overlay {
3995
- position: absolute;
3996
- top: 8px;
3997
- right: 8px;
3998
- z-index: 10;
3999
- display: flex;
4000
- align-items: center;
4001
- gap: 4px;
4002
- background: var(--surface-4, #2a2a2a);
4003
- border: 1px solid var(--border, #444);
4004
- border-radius: var(--radius-m, 4px);
4005
- padding: 4px 6px;
4006
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
4007
- }
4008
-
4009
- .search-overlay[hidden] {
4010
- display: none;
4011
- }
4012
-
4013
- .search-input {
4014
- background: transparent;
4015
- border: none;
4016
- outline: none;
4017
- color: inherit;
4018
- font-size: var(--text-m, 0.875em);
4019
- min-width: 140px;
4020
- }
4021
-
4022
- .search-close {
4023
- background: transparent;
4024
- border: none;
4025
- color: var(--surface-muted-text, #888);
4026
- cursor: pointer;
4027
- font-size: 1.1em;
4028
- line-height: 1;
4029
- padding: 0 2px;
4030
- }
4031
-
4032
- .search-close:hover {
4033
- color: inherit;
4034
- }
4035
- `];
4036
- }
4037
- render() {
4038
- return html`
4039
- <div class="container">
4040
- <ul part="list">
4041
- <slot></slot>
4042
- </ul>
4043
- <div
4044
- class="search-overlay"
4045
- part="search-overlay"
4046
- ?hidden=${!this._searchVisible}
4047
- >
4048
- <input
4049
- type="text"
4050
- class="search-input"
4051
- placeholder="Search…"
4052
- .value=${this._searchQuery}
4053
- @input=${this._onSearchInput}
4054
- @keydown=${this._onSearchKeydown}
4055
- />
4056
- <button class="search-close" @click=${this._closeSearch} title="Close search (Esc)">×</button>
4057
- </div>
4058
- </div>
4059
- `;
4060
- }
4061
- };
4062
- __decorate([property({
4063
- type: String,
4064
- attribute: `selection-mode`
4065
- })], VerticalListElement.prototype, "selectionMode", void 0);
4066
- __decorate([property({
4067
- type: String,
4068
- attribute: `interaction-mode`
4069
- })], VerticalListElement.prototype, "interactionMode", void 0);
4070
- __decorate([property({ attribute: false })], VerticalListElement.prototype, "filterPredicate", void 0);
4071
- __decorate([property({ attribute: false })], VerticalListElement.prototype, "checkboxRenderer", void 0);
4072
- __decorate([state()], VerticalListElement.prototype, "_selectedItems", void 0);
4073
- __decorate([state()], VerticalListElement.prototype, "_searchVisible", void 0);
4074
- __decorate([state()], VerticalListElement.prototype, "_searchQuery", void 0);
4075
- __decorate([query(`.search-input`)], VerticalListElement.prototype, "_searchInputEl", void 0);
4076
- VerticalListElement = __decorate([safeCustomElement(`ixfx-vertical-list`)], VerticalListElement);
2289
+ key: `__adapter_root__`,
2290
+ label: ``,
2291
+ isLeaf: false
2292
+ },
2293
+ children: items.map(buildNode)
2294
+ };
2295
+ },
2296
+ clearSelection() {
2297
+ treeEl?.clearSelection();
2298
+ },
2299
+ dispatch(commandId, args) {
2300
+ options?.onDispatch?.(commandId, args, treeEl);
2301
+ }
2302
+ });
2303
+ Object.defineProperties(adapter, {
2304
+ selectedItems: {
2305
+ get() {
2306
+ return treeEl ? mapNodes(treeEl.selectedNodes) : /* @__PURE__ */ new Set();
2307
+ },
2308
+ enumerable: true,
2309
+ configurable: true
2310
+ },
2311
+ selectionMode: {
2312
+ get() {
2313
+ return selectionMode;
2314
+ },
2315
+ set(v) {
2316
+ selectionMode = v;
2317
+ if (!treeEl) return;
2318
+ if (v === `none`) treeEl.selectionFilter = `none`;
2319
+ else if (v === `single`) {
2320
+ treeEl.selectionFilter = options?.selectionFilter ?? `all`;
2321
+ treeEl.interactionMode = `implicit`;
2322
+ } else {
2323
+ treeEl.selectionFilter = options?.selectionFilter ?? `all`;
2324
+ treeEl.interactionMode = options?.interactionMode ?? `standard`;
2325
+ }
2326
+ },
2327
+ enumerable: true,
2328
+ configurable: true
2329
+ }
2330
+ });
2331
+ return adapter;
2332
+ }
4077
2333
  //#endregion
4078
2334
  //#region src/grouped-item-lister/vertical-list-adapter.ts
4079
2335
  /**
@@ -4204,143 +2460,6 @@ function createVerticalListAdapter(renderItem, options) {
4204
2460
  return adapter;
4205
2461
  }
4206
2462
  //#endregion
4207
- //#region src/notifier/notification-pill.ts
4208
- let NotificationPillElement = class NotificationPillElement extends LitElement {
4209
- constructor(..._args) {
4210
- super(..._args);
4211
- this.notificationType = `info`;
4212
- this.message = ``;
4213
- this.dismissing = false;
4214
- this.notificationId = ``;
4215
- }
4216
- #handleClick() {
4217
- this.#emitTap();
4218
- }
4219
- #handleKeyDown(e) {
4220
- if (e.key === `Enter` || e.key === ` `) {
4221
- e.preventDefault();
4222
- this.#emitTap();
4223
- }
4224
- }
4225
- #emitTap() {
4226
- this.dispatchEvent(new CustomEvent(`pill-tap`, {
4227
- detail: { id: this.notificationId },
4228
- bubbles: true,
4229
- composed: true
4230
- }));
4231
- }
4232
- #renderIcon() {
4233
- if (!this.icon) return nothing;
4234
- if (this.icon.startsWith(`<svg`)) return html`<span class="pill-icon">${unsafeHTML(this.icon)}</span>`;
4235
- if (!getIcon(this.icon)) return nothing;
4236
- return html`<ixfx-icon class="pill-icon" name="${this.icon}"></ixfx-icon>`;
4237
- }
4238
- render() {
4239
- return html`
4240
- <button
4241
- type="button"
4242
- class="pill"
4243
- notification-type="${this.notificationType}"
4244
- @click=${this.#handleClick}
4245
- @keydown=${this.#handleKeyDown}
4246
- aria-label="${this.message}"
4247
- >
4248
- ${this.#renderIcon()}
4249
- <span class="pill-message">${this.message}</span>
4250
- </button>
4251
- `;
4252
- }
4253
- static {
4254
- this.styles = [themeFallbacks, css`
4255
- :host {
4256
- display: block;
4257
- }
4258
-
4259
- .pill {
4260
- appearance: none;
4261
- cursor: pointer;
4262
- font-family: var(--font-family, inherit);
4263
- font-size: var(--text-m, 12px);
4264
- padding: var(--space-s, 4px) var(--space-m, 8px);
4265
- border-radius: var(--radius-l, 6px);
4266
- border: 1px solid var(--surface-6, #666);
4267
- display: inline-flex;
4268
- align-items: center;
4269
- gap: var(--space-s, 4px);
4270
- max-width: 300px;
4271
- box-shadow: var(--shadow-m);
4272
- transition: opacity 0.2s ease-out, transform 0.2s ease-out;
4273
- pointer-events: auto;
4274
- }
4275
-
4276
- :host([dismissing]) .pill {
4277
- opacity: 0;
4278
- transform: translateX(20px);
4279
- }
4280
-
4281
- .pill[notification-type="info"] {
4282
- background: var(--surface-5, #555);
4283
- color: var(--surface-5-text, #fff);
4284
- }
4285
-
4286
- .pill[notification-type="warning"] {
4287
- background: color-mix(in oklch, oklch(65% 0.18 70) 30%, var(--surface-5));
4288
- border-color: oklch(65% 0.18 70);
4289
- color: var(--surface-5-text, #fff);
4290
- }
4291
-
4292
- .pill[notification-type="error"] {
4293
- background: var(--error, #c00);
4294
- border-color: var(--error, #c00);
4295
- color: var(--error-text, #fff);
4296
- }
4297
-
4298
- .pill-icon {
4299
- display: inline-flex;
4300
- align-items: center;
4301
- flex-shrink: 0;
4302
- }
4303
-
4304
- .pill-icon ixfx-icon {
4305
- font-size: var(--text-m, 12px);
4306
- }
4307
-
4308
- .pill-message {
4309
- white-space: nowrap;
4310
- overflow: hidden;
4311
- text-overflow: ellipsis;
4312
- }
4313
-
4314
- .pill:focus-visible {
4315
- outline: 2px solid var(--accent, #4a9);
4316
- outline-offset: 2px;
4317
- }
4318
-
4319
- @media (prefers-reduced-motion: reduce) {
4320
- .pill {
4321
- transition: opacity 0.1s ease-out;
4322
- transform: none !important;
4323
- }
4324
- }
4325
- `];
4326
- }
4327
- };
4328
- __decorate([property({
4329
- type: String,
4330
- attribute: `notification-type`
4331
- })], NotificationPillElement.prototype, "notificationType", void 0);
4332
- __decorate([property({ type: String })], NotificationPillElement.prototype, "message", void 0);
4333
- __decorate([property({ type: String })], NotificationPillElement.prototype, "icon", void 0);
4334
- __decorate([property({
4335
- type: Boolean,
4336
- reflect: true
4337
- })], NotificationPillElement.prototype, "dismissing", void 0);
4338
- __decorate([property({
4339
- type: String,
4340
- attribute: `notification-id`
4341
- })], NotificationPillElement.prototype, "notificationId", void 0);
4342
- NotificationPillElement = __decorate([safeCustomElement(`ixfx-notification-pill`)], NotificationPillElement);
4343
- //#endregion
4344
2463
  //#region src/notifier/pill-renderer.ts
4345
2464
  const ROW_SPACING = 8;
4346
2465
  const DEFAULT_ROW_HEIGHT = 40;
@@ -4554,7 +2673,7 @@ function clearTimer(managed) {
4554
2673
  function startTimer(managed) {
4555
2674
  const base = managed.type === `error` ? options.timeoutError : options.timeout;
4556
2675
  const duration = managed.wasQueued ? base / options.queueSize : base;
4557
- managed.timer = window.setTimeout(() => dismiss(managed.id), duration);
2676
+ managed.timer = window.setTimeout(dismiss, duration, managed.id);
4558
2677
  }
4559
2678
  function ensureFrontTimer() {
4560
2679
  const front = visible[0];
@@ -4727,6 +2846,108 @@ __decorate([property()], PanelGroupElement.prototype, "gap", void 0);
4727
2846
  __decorate([queryAssignedElements({ slot: `` })], PanelGroupElement.prototype, "_panels", void 0);
4728
2847
  PanelGroupElement = __decorate([safeCustomElement(`ixfx-panel-group`)], PanelGroupElement);
4729
2848
  //#endregion
2849
+ //#region src/util/is-numeric.ts
2850
+ function isNumeric(str) {
2851
+ if (typeof str === `number`) return true;
2852
+ if (typeof str !== `string`) return false;
2853
+ const trimmed = str.trim();
2854
+ return trimmed !== `` && !Number.isNaN(Number(trimmed));
2855
+ }
2856
+ //#endregion
2857
+ //#region src/util/tooltip.ts
2858
+ var _TooltipElement;
2859
+ let _baseStylesInjected = false;
2860
+ function ensureBaseTooltipStyles() {
2861
+ if (_baseStylesInjected) return;
2862
+ _baseStylesInjected = true;
2863
+ const style = document.createElement(`style`);
2864
+ style.textContent = `
2865
+ ixfx-tooltip {
2866
+ display: inline-block;
2867
+ background: var(--surface-5);
2868
+ color: var(--surface-5-text);
2869
+ border: var(--border);
2870
+ border-radius: var(--radius-l, 6px);
2871
+ box-shadow: var(--shadow-m);
2872
+ padding: var(--space-s, 4px);
2873
+ font-size: 10px;
2874
+ font-family: var(--font-family, inherit);
2875
+ }
2876
+ ixfx-tooltip .tooltip-type-number {
2877
+ font-family: var(--font-mono, ui-monospace, monospace);
2878
+ }
2879
+ `;
2880
+ document.head.appendChild(style);
2881
+ }
2882
+ let TooltipElement = class TooltipElement extends LitElement {
2883
+ static {
2884
+ _TooltipElement = this;
2885
+ }
2886
+ constructor(..._args) {
2887
+ super(..._args);
2888
+ this.valueFormatTooltip = _TooltipElement.defaultFormatter;
2889
+ this.orientation = `top`;
2890
+ this.anchor = `--tooltip`;
2891
+ }
2892
+ connectedCallback() {
2893
+ super.connectedCallback();
2894
+ ensureBaseTooltipStyles();
2895
+ }
2896
+ static {
2897
+ this.numberFormatter = (v) => Math.floor(v).toString();
2898
+ }
2899
+ static {
2900
+ this.defaultFormatter = (v) => {
2901
+ if (typeof v === `number`) {
2902
+ if (Number.isInteger(v)) return v.toString();
2903
+ return v.toFixed(2);
2904
+ } else if (typeof v === `string`) return v;
2905
+ else return JSON.stringify(v);
2906
+ };
2907
+ }
2908
+ #renderIcon() {
2909
+ if (!this.icon) return nothing;
2910
+ if (this.icon.startsWith(`<svg`)) return html`<span class="tooltip-icon" style="display:inline-flex;align-items:center;margin-right:0.25em">${unsafeHTML(this.icon)}</span>`;
2911
+ if (!getIcon(this.icon)) return nothing;
2912
+ return html`<ixfx-icon class="tooltip-icon" style="margin-right:0.25em" name="${this.icon}"></ixfx-icon>`;
2913
+ }
2914
+ render() {
2915
+ const classes = {
2916
+ "tooltip": true,
2917
+ "tooltip-orientation-top": this.orientation === `top`,
2918
+ "tooltip-orientation-bottom": this.orientation === `bottom`,
2919
+ "tooltip-orientation-right": this.orientation === `right`,
2920
+ "tooltip-orientation-left": this.orientation === `left`,
2921
+ "tooltip-type-text": true,
2922
+ "tooltip-type-number": false,
2923
+ "tooltip-style-bubble": true
2924
+ };
2925
+ let value = ``;
2926
+ switch (typeof this.value) {
2927
+ case `number`:
2928
+ classes[`tooltip-type-number`] = true;
2929
+ value = this.valueFormatTooltip(this.value);
2930
+ break;
2931
+ case `string`:
2932
+ if (isNumeric(this.value)) {
2933
+ classes[`tooltip-type-number`] = true;
2934
+ value = this.valueFormatTooltip(Number.parseFloat(this.value));
2935
+ } else value = this.value;
2936
+ break;
2937
+ default: value = JSON.stringify(this.value);
2938
+ }
2939
+ return html`<output style="--anchor-id: ${this.anchor}" class=${classMap(classes)}>${this.#renderIcon()}${value}</output>`;
2940
+ }
2941
+ createRenderRoot() {
2942
+ return this;
2943
+ }
2944
+ };
2945
+ __decorate([property({ type: String })], TooltipElement.prototype, "orientation", void 0);
2946
+ __decorate([property({ type: String })], TooltipElement.prototype, "anchor", void 0);
2947
+ __decorate([property()], TooltipElement.prototype, "value", void 0);
2948
+ __decorate([property({ type: String })], TooltipElement.prototype, "icon", void 0);
2949
+ TooltipElement = _TooltipElement = __decorate([safeCustomElement(`ixfx-tooltip`)], TooltipElement);
2950
+ //#endregion
4730
2951
  //#region src/util/drag.ts
4731
2952
  function getCoordinates(event) {
4732
2953
  return {
@@ -4873,11 +3094,13 @@ let RangeMultiElement = class RangeMultiElement extends LitElement {
4873
3094
  }
4874
3095
  a = newA;
4875
3096
  b = newB;
4876
- } else if (which === `a`) if (v > this.b && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.a);
4877
- else a = v;
4878
- else if (which === `b`) if (v < a && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.b);
4879
- else b = v;
4880
- else throw new Error(`Expected 'a' or 'b', got: '${t.id}'`);
3097
+ } else if (which === `a`) {
3098
+ if (v > this.b && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.a);
3099
+ else a = v;
3100
+ } else if (which === `b`) {
3101
+ if (v < a && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.b);
3102
+ else b = v;
3103
+ } else throw new Error(`Expected 'a' or 'b', got: '${t.id}'`);
4881
3104
  this.setPoles(a, b);
4882
3105
  }
4883
3106
  setPoles(a, b) {
@@ -4936,63 +3159,65 @@ let RangeMultiElement = class RangeMultiElement extends LitElement {
4936
3159
  const currentPos = isVertical ? current.offset.y : current.offset.x;
4937
3160
  const amt = (isVertical ? startPos - currentPos : currentPos - startPos) / valuePerPix;
4938
3161
  polesChanged = true;
4939
- if (draggingWhich === `a`) if (resizeMode === `bipolar`) {
4940
- const calcA = startA + amt;
4941
- const calcB = startB - amt;
4942
- if (calcA < min || calcB > max || calcA > max || calcB < min) return;
4943
- setPoles(calcA, calcB);
4944
- } else if (resizeMode === `bipolar-flex`) {
4945
- let calcA = startA + amt;
4946
- let calcB = startB;
4947
- if (startB <= min) calcB = min;
4948
- else if (startB >= max) calcB = max;
4949
- else {
4950
- calcA = startA + amt;
4951
- calcB = startB - amt;
3162
+ if (draggingWhich === `a`) {
3163
+ if (resizeMode === `bipolar`) {
3164
+ const calcA = startA + amt;
3165
+ const calcB = startB - amt;
3166
+ if (calcA < min || calcB > max || calcA > max || calcB < min) return;
3167
+ setPoles(calcA, calcB);
3168
+ } else if (resizeMode === `bipolar-flex`) {
3169
+ let calcA = startA + amt;
3170
+ let calcB = startB;
3171
+ if (startB <= min) calcB = min;
3172
+ else if (startB >= max) calcB = max;
3173
+ else {
3174
+ calcA = startA + amt;
3175
+ calcB = startB - amt;
3176
+ }
3177
+ if (calcA < min) calcA = min;
3178
+ if (calcA > max) calcA = max;
3179
+ if (calcB < min) calcB = min;
3180
+ if (calcB > max) calcB = max;
3181
+ if (calcA > calcB) return;
3182
+ setPoles(calcA, calcB);
3183
+ } else {
3184
+ let constrainedAmt = amt;
3185
+ if (startA + amt < min) constrainedAmt = min - startA;
3186
+ if (startB + constrainedAmt > max) constrainedAmt = max - startB;
3187
+ const finalA = startA + constrainedAmt;
3188
+ const finalB = startB + constrainedAmt;
3189
+ if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
4952
3190
  }
4953
- if (calcA < min) calcA = min;
4954
- if (calcA > max) calcA = max;
4955
- if (calcB < min) calcB = min;
4956
- if (calcB > max) calcB = max;
4957
- if (calcA > calcB) return;
4958
- setPoles(calcA, calcB);
4959
- } else {
4960
- let constrainedAmt = amt;
4961
- if (startA + amt < min) constrainedAmt = min - startA;
4962
- if (startB + constrainedAmt > max) constrainedAmt = max - startB;
4963
- const finalA = startA + constrainedAmt;
4964
- const finalB = startB + constrainedAmt;
4965
- if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
4966
- }
4967
- else if (draggingWhich === `b`) if (resizeMode === `bipolar`) {
4968
- const calcA = startA - amt;
4969
- const calcB = startB + amt;
4970
- if (calcA < min || calcB > max || calcA > max || calcB < min) return;
4971
- setPoles(calcA, calcB);
4972
- } else if (resizeMode === `bipolar-flex`) {
4973
- let calcA = startA;
4974
- let calcB = startB + amt;
4975
- if (startA <= min) calcA = min;
4976
- else if (startA >= max) calcA = max;
4977
- else {
4978
- calcA = startA - amt;
4979
- calcB = startB + amt;
3191
+ } else if (draggingWhich === `b`) {
3192
+ if (resizeMode === `bipolar`) {
3193
+ const calcA = startA - amt;
3194
+ const calcB = startB + amt;
3195
+ if (calcA < min || calcB > max || calcA > max || calcB < min) return;
3196
+ setPoles(calcA, calcB);
3197
+ } else if (resizeMode === `bipolar-flex`) {
3198
+ let calcA = startA;
3199
+ let calcB = startB + amt;
3200
+ if (startA <= min) calcA = min;
3201
+ else if (startA >= max) calcA = max;
3202
+ else {
3203
+ calcA = startA - amt;
3204
+ calcB = startB + amt;
3205
+ }
3206
+ if (calcA < min) calcA = min;
3207
+ if (calcA > max) calcA = max;
3208
+ if (calcB < min) calcB = min;
3209
+ if (calcB > max) calcB = max;
3210
+ if (calcA > calcB) return;
3211
+ setPoles(calcA, calcB);
3212
+ } else {
3213
+ let constrainedAmt = amt;
3214
+ if (startA + amt < min) constrainedAmt = min - startA;
3215
+ if (startB + constrainedAmt > max) constrainedAmt = max - startB;
3216
+ const finalA = startA + constrainedAmt;
3217
+ const finalB = startB + constrainedAmt;
3218
+ if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
4980
3219
  }
4981
- if (calcA < min) calcA = min;
4982
- if (calcA > max) calcA = max;
4983
- if (calcB < min) calcB = min;
4984
- if (calcB > max) calcB = max;
4985
- if (calcA > calcB) return;
4986
- setPoles(calcA, calcB);
4987
- } else {
4988
- let constrainedAmt = amt;
4989
- if (startA + amt < min) constrainedAmt = min - startA;
4990
- if (startB + constrainedAmt > max) constrainedAmt = max - startB;
4991
- const finalA = startA + constrainedAmt;
4992
- const finalB = startB + constrainedAmt;
4993
- if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
4994
- }
4995
- else if (resizeMode === `bipolar`) {
3220
+ } else if (resizeMode === `bipolar`) {
4996
3221
  const calcA = startA + amt;
4997
3222
  const calcB = startB + amt;
4998
3223
  if (calcA < min || calcB > max) return;
@@ -5241,514 +3466,475 @@ __decorate([eventOptions({ capture: true })], RangeMultiElement.prototype, "_onI
5241
3466
  __decorate([eventOptions({ capture: true })], RangeMultiElement.prototype, "_onPointerDown", null);
5242
3467
  RangeMultiElement = __decorate([safeCustomElement(`ixfx-range-multi`)], RangeMultiElement);
5243
3468
  //#endregion
5244
- //#region src/select-horiz/select-horiz.ts
5245
- let SelectHorizElement = class SelectHorizElement extends WheelNudgeMixin(LitElement) {
3469
+ //#region src/rating/rating.ts
3470
+ let RatingElement = class RatingElement extends LitElement {
5246
3471
  constructor(..._args) {
5247
3472
  super(..._args);
5248
- this._selectedIndex = -1;
5249
- this._slottedItems = [];
5250
- this.tickled = new TickledController(this, {
5251
- getItems: () => this._slottedItems.map((_, i) => ({
5252
- id: i,
5253
- enabled: true
5254
- })),
5255
- onStateChange: () => this._syncTickled()
5256
- });
5257
- this._onSlotChange = () => {
5258
- this._slottedItems = Array.from(this.shadowRoot?.querySelector(`slot`)?.assignedElements() ?? []);
5259
- const declaredIndex = this._slottedItems.findIndex((item) => item.hasAttribute(`selected`));
5260
- let resolvedIndex = declaredIndex >= 0 ? declaredIndex : this._selectedIndex;
5261
- if (resolvedIndex >= this._slottedItems.length) resolvedIndex = this._slottedItems.length - 1;
5262
- if (resolvedIndex < 0 && this._slottedItems.length > 0) resolvedIndex = 0;
5263
- this.selectedIndex = resolvedIndex;
5264
- };
5265
- this._syncTickled = () => {
5266
- this._slottedItems.forEach((item, i) => {
5267
- const isTickled = this.tickled.isTickled(i);
5268
- item.classList.toggle(`tickled`, isTickled);
5269
- item.tabIndex = isTickled && this.tickled.inputMode === `keyboard` ? 0 : -1;
5270
- });
5271
- };
5272
- this._findSlottedItem = (target) => {
5273
- let el = target instanceof Element ? target : null;
5274
- while (el) {
5275
- if (this._slottedItems.includes(el)) return el;
5276
- el = el.parentElement;
5277
- }
5278
- };
5279
- this._handlePointerOver = (e) => {
5280
- const item = this._findSlottedItem(e.target);
5281
- if (item) this.tickled.handlePointerEnter(this._slottedItems.indexOf(item));
5282
- };
5283
- this._handleKeyDown = (e) => {
5284
- if (e.key === `ArrowLeft`) {
5285
- e.preventDefault();
5286
- this.tickled.handleKeyboardNavigation(`previous`);
5287
- this._applyTickledSelection();
5288
- } else if (e.key === `ArrowRight`) {
5289
- e.preventDefault();
5290
- this.tickled.handleKeyboardNavigation(`next`);
5291
- this._applyTickledSelection();
5292
- } else if (e.key === `Home`) {
5293
- e.preventDefault();
5294
- this.tickled.handleKeyboardNavigation(`first`);
5295
- this._applyTickledSelection();
5296
- } else if (e.key === `End`) {
5297
- e.preventDefault();
5298
- this.tickled.handleKeyboardNavigation(`last`);
5299
- this._applyTickledSelection();
5300
- }
5301
- };
5302
- this._applyTickledSelection = () => {
5303
- const id = this.tickled.tickledId;
5304
- if (id !== void 0 && id !== this._selectedIndex) this.selectedIndex = id;
5305
- };
5306
- this._wheelCooldown = false;
5307
- this._handleClick = (e) => {
5308
- e.currentTarget.focus();
5309
- const item = this._findSlottedItem(e.target);
5310
- const index = item ? this._slottedItems.indexOf(item) : -1;
5311
- if (index >= 0 && index !== this._selectedIndex) this.selectedIndex = index;
5312
- };
5313
- this._updateSelectedAttribute = () => {
5314
- this._slottedItems.forEach((item, i) => {
5315
- if (i === this._selectedIndex) item.setAttribute(`selected`, ``);
5316
- else item.removeAttribute(`selected`);
5317
- });
5318
- };
5319
- this._scrollSelectedIntoView = () => {
5320
- const item = this._slottedItems[this._selectedIndex];
5321
- if (item) item.scrollIntoView({
5322
- inline: `center`,
5323
- behavior: `smooth`
5324
- });
5325
- };
5326
- this._emitChange = () => {
5327
- this.dispatchEvent(new CustomEvent(`change`, {
5328
- detail: {
5329
- selectedIndex: this._selectedIndex,
5330
- selectedItem: this.selectedItem,
5331
- selectedValue: this.selectedValue
5332
- },
5333
- bubbles: true,
5334
- composed: true
5335
- }));
5336
- };
3473
+ this.value = 0;
3474
+ this.max = 5;
3475
+ this.allowHalf = false;
3476
+ this.disabled = false;
3477
+ this.readonly = false;
3478
+ this.variant = `star`;
3479
+ this._preview = null;
5337
3480
  }
5338
3481
  static {
5339
- this.styles = [
5340
- themeFallbacks,
5341
- tickledStyles,
5342
- tickledItemStyles,
5343
- scrollFadeStyles(`x`),
5344
- css`
5345
- :host {
5346
- --select-horiz-item-width: 80%;
5347
- --select-horiz-gap: var(--space-s);
5348
- --select-horiz-bg: var(--surface-3);
5349
- --select-horiz-border: var(--border);
5350
- --select-horiz-radius: var(--radius-l);
5351
- display: flex;
5352
- width: 100%;
5353
- background: var(--select-horiz-bg);
5354
- border: var(--select-horiz-border);
5355
- border-radius: var(--select-horiz-radius);
5356
- }
5357
-
5358
- /* Edge fade (the scroll-fade-x class, see ../styles/scroll-fade.ts) must sit on
5359
- * the element that actually scrolls - its mask is sized to this element's own
5360
- * box, and content overflowing a *different*, non-scrolling ancestor gets the
5361
- * mask tiled across it instead of fading correctly. */
5362
- .items {
5363
- display: flex;
5364
- align-items: center;
5365
- gap: var(--select-horiz-gap);
5366
- padding: var(--space-xs) var(--scroll-fade-width, 30px);
5367
- width: 100%;
5368
- min-height: 48px;
5369
- overflow-x: scroll;
5370
- overflow-y: hidden;
5371
- scrollbar-width: none;
5372
- scroll-snap-type: x mandatory;
5373
- -webkit-overflow-scrolling: touch;
5374
- cursor: grab;
5375
-
5376
- box-sizing: border-box;
5377
- }
5378
-
5379
- .items:focus-within {
5380
- cursor: default;
5381
- }
5382
-
5383
- .spacer {
5384
- flex: 0 0 var(--select-horiz-spacer-width, 10%);
5385
- pointer-events: none;
5386
- user-select: none;
5387
- }
5388
-
5389
- ::slotted(*) {
5390
- flex: 0 0 var(--select-horiz-item-width);
5391
- scroll-snap-align: center;
5392
- user-select: none;
5393
- min-height: 100%;
5394
- box-sizing: border-box;
5395
- transition: opacity var(--transition), background var(--transition), border-color var(--transition), color var(--transition);
5396
- background: var(--item-bg);
5397
- border: var(--item-border);
5398
- border-radius: var(--item-border-radius);
5399
- padding: var(--item-padding);
5400
- display: grid;
5401
- align-content: center;
5402
- justify-content: center;
5403
- }
5404
-
5405
- ::slotted(.tickled) {
5406
- background: var(--item-bg-tickled);
5407
- border: var(--item-border-tickled);
5408
- color: var(--item-text-tickled);
5409
- }
5410
-
5411
- ::slotted([selected]) {
5412
- background: var(--item-bg-selected);
5413
- border: var(--item-border-selected);
5414
- color: var(--item-text-selected);
5415
- }
5416
-
5417
- ::slotted([selected].tickled) {
5418
- background: var(--item-bg-selected-tickled);
5419
- outline: 2px dashed var(--surface-3);
5420
- outline-offset: -2px;
5421
- }
5422
-
5423
- ::-webkit-scrollbar {
5424
- display: none;
5425
- }
5426
- `
5427
- ];
5428
- }
5429
- get selectedIndex() {
5430
- return this._selectedIndex;
5431
- }
5432
- set selectedIndex(value) {
5433
- const oldValue = this._selectedIndex;
5434
- if (value < -1 || this._slottedItems.length > 0 && value >= this._slottedItems.length) return;
5435
- this._selectedIndex = value;
5436
- this._updateSelectedAttribute();
5437
- this._scrollSelectedIntoView();
5438
- this.tickled.setTickled(value === -1 ? void 0 : value);
5439
- if (oldValue !== value) this._emitChange();
5440
- }
5441
- get selectedValue() {
5442
- return this._slottedItems[this._selectedIndex]?.getAttribute(`value`) ?? null;
3482
+ this.styles = [prominenceStyles, css`
3483
+ :host {
3484
+ --ixfx-rating-size: 1.5rem;
3485
+ --ixfx-rating-gap: 0.2rem;
3486
+ --ixfx-rating-color: var(--surface-4);
3487
+ --ixfx-rating-color-active: var(--accent);
3488
+ --ixfx-rating-color-hover: var(--accent);
3489
+ display: inline-flex;
3490
+ gap: var(--ixfx-rating-gap);
3491
+ align-items: center;
3492
+ user-select: none;
3493
+ --transition: 0.15s ease;
3494
+ }
3495
+ :host([readonly]) { pointer-events: none; filter: none; }
3496
+ :host(:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
3497
+ .glyph {
3498
+ width: var(--ixfx-rating-size);
3499
+ height: var(--ixfx-rating-size);
3500
+ position: relative;
3501
+ cursor: pointer;
3502
+ flex-shrink: 0;
3503
+ color: var(--ixfx-rating-glyph-color, var(--ixfx-rating-color));
3504
+ transition: color var(--transition), transform var(--transition);
3505
+ }
3506
+ .glyph.filled { color: var(--ixfx-rating-glyph-color-active, var(--ixfx-rating-color-active)); }
3507
+ .glyph.preview { color: var(--ixfx-rating-glyph-color-hover, var(--ixfx-rating-color-hover)); }
3508
+ .glyph.half .fill { clip-path: inset(0 50% 0 0); }
3509
+ .glyph svg { width: 100%; height: 100%; display: block; }
3510
+ .glyph .fill { position: absolute; inset: 0; color: var(--ixfx-rating-glyph-color-active, var(--ixfx-rating-color-active)); }
3511
+ .glyph.preview .fill { color: var(--ixfx-rating-glyph-color-hover, var(--ixfx-rating-color-hover)); }
3512
+ .glyph .bg { color: var(--ixfx-rating-glyph-color, var(--ixfx-rating-color)); }
3513
+ /* per-rank vars: consumer sets --ixfx-rating-1-color etc outside shadow, we map via inline style fallback */
3514
+ `];
5443
3515
  }
5444
- set selectedValue(value) {
5445
- if (value === null) return;
5446
- const index = this._slottedItems.findIndex((item) => item.getAttribute(`value`) === value);
5447
- if (index >= 0) this.selectedIndex = index;
3516
+ connectedCallback() {
3517
+ super.connectedCallback();
3518
+ this.setAttribute(`role`, `slider`);
3519
+ this.tabIndex = this.disabled || this.readonly ? -1 : 0;
5448
3520
  }
5449
- get selectedItem() {
5450
- return this._slottedItems[this._selectedIndex] ?? null;
3521
+ updated(changed) {
3522
+ if (changed.has(`disabled`) || changed.has(`readonly`)) {
3523
+ this.tabIndex = this.disabled || this.readonly ? -1 : 0;
3524
+ this.setAttribute(`aria-disabled`, String(this.disabled));
3525
+ }
3526
+ this.setAttribute(`aria-valuenow`, String(this.value));
3527
+ this.setAttribute(`aria-valuemin`, `0`);
3528
+ this.setAttribute(`aria-valuemax`, String(this.max));
3529
+ this.setAttribute(`aria-readonly`, String(this.readonly));
3530
+ }
3531
+ _path(v) {
3532
+ if (v === `heart`) return `M12 21s-6.5-4.2-8.5-8.2A4.5 4.5 0 0 1 12 5a4.5 4.5 0 0 1 8.5 7.8C18.5 16.8 12 21 12 21z`;
3533
+ if (v === `square`) return `M3 3h18v18H3z`;
3534
+ return `M12 2l2.4 7.4H22l-6.2 4.5 2.4 7.4L12 17 5.8 21.3l2.4-7.4L2 9.4h7.6z`;
3535
+ }
3536
+ _effective() {
3537
+ return this._preview ?? this.value;
3538
+ }
3539
+ _commit(newVal) {
3540
+ if (this.disabled || this.readonly) return;
3541
+ const oldValue = this.value;
3542
+ if (newVal === oldValue) newVal = 0;
3543
+ if (newVal === oldValue) return;
3544
+ this.value = newVal;
3545
+ this.dispatchEvent(new CustomEvent(`input`, {
3546
+ detail: {
3547
+ value: newVal,
3548
+ oldValue
3549
+ },
3550
+ bubbles: true,
3551
+ composed: true
3552
+ }));
3553
+ this.dispatchEvent(new CustomEvent(`change`, {
3554
+ detail: {
3555
+ value: newVal,
3556
+ oldValue
3557
+ },
3558
+ bubbles: true,
3559
+ composed: true
3560
+ }));
5451
3561
  }
5452
- get items() {
5453
- return this._slottedItems;
3562
+ _calc(e, index) {
3563
+ if (!this.allowHalf) return index + 1;
3564
+ const rect = e.currentTarget.getBoundingClientRect();
3565
+ return e.clientX - rect.left < rect.width / 2 ? index + .5 : index + 1;
5454
3566
  }
5455
3567
  render() {
5456
- return html`
5457
- <div
5458
- class="items scroll-fade-x"
5459
- tabindex="0"
5460
- data-input-mode=${this.tickled.inputMode}
5461
- @pointerover=${this._handlePointerOver}
5462
- @pointerleave=${(e) => this.tickled.handlePointerLeave(e)}
5463
- @keydown=${this._handleKeyDown}
5464
- @click=${this._handleClick}
5465
- >
5466
- <div class="spacer"></div>
5467
- <slot @slotchange=${this._onSlotChange}></slot>
5468
- <div class="spacer"></div>
5469
- </div>
5470
- `;
3568
+ const eff = this._effective();
3569
+ const hovering = this._preview !== null;
3570
+ return html`${Array.from({ length: this.max }, (_, i) => {
3571
+ const rank = i + 1;
3572
+ const filled = eff >= rank;
3573
+ const half = !filled && eff >= rank - .5;
3574
+ const cls = `glyph ${filled ? `filled` : ``} ${half ? `half` : ``} ${hovering && (filled || half) ? `preview` : ``}`;
3575
+ const style = `--ixfx-rating-glyph-color:var(--ixfx-rating-${rank}-color, var(--ixfx-rating-color));--ixfx-rating-glyph-color-active:var(--ixfx-rating-${rank}-color-active, var(--ixfx-rating-color-active));--ixfx-rating-glyph-color-hover:var(--ixfx-rating-${rank}-color-hover, var(--ixfx-rating-color-hover));${half || filled ? `` : ``}`;
3576
+ const d = this._path(this.variant);
3577
+ return html`<span class=${cls} style=${style}
3578
+ @pointermove=${(e) => {
3579
+ if (this.disabled || this.readonly) return;
3580
+ this._preview = this._calc(e, i);
3581
+ }}
3582
+ @pointerleave=${() => this._preview = null}
3583
+ @click=${(e) => this._commit(this._calc(e, i))}>
3584
+ <svg viewBox="0 0 24 24" class="bg" fill="currentColor"><path d=${d}></path></svg>
3585
+ ${filled || half ? html`<svg viewBox="0 0 24 24" class="fill" fill="currentColor"><path d=${d}></path></svg>` : ``}
3586
+ </span>`;
3587
+ })}`;
5471
3588
  }
5472
- willUpdate(changed) {
5473
- super.willUpdate(changed);
5474
- this.setAttribute(`data-input-mode`, this.tickled.inputMode);
5475
- }
5476
- _applyWheelDelta(direction, _event) {
5477
- if (this._wheelCooldown) return;
5478
- this._wheelCooldown = true;
5479
- this.tickled.handleKeyboardNavigation(direction === 1 ? `next` : `previous`);
5480
- this._applyTickledSelection();
5481
- setTimeout(() => {
5482
- this._wheelCooldown = false;
5483
- }, 250);
3589
+ firstUpdated() {
3590
+ this.addEventListener(`pointerleave`, () => this._preview = null);
3591
+ this.addEventListener(`keydown`, (e) => {
3592
+ if (this.disabled || this.readonly) return;
3593
+ const step = this.allowHalf ? .5 : 1;
3594
+ if (e.key === `ArrowRight` || e.key === `ArrowUp`) {
3595
+ e.preventDefault();
3596
+ this._commit(Math.min(this.max, this.value + step));
3597
+ } else if (e.key === `ArrowLeft` || e.key === `ArrowDown`) {
3598
+ e.preventDefault();
3599
+ this._commit(Math.max(0, this.value - step));
3600
+ } else if (e.key === `Home`) {
3601
+ e.preventDefault();
3602
+ this._commit(0);
3603
+ } else if (e.key === `End`) {
3604
+ e.preventDefault();
3605
+ this._commit(this.max);
3606
+ } else if (/^\d$/.test(e.key)) {
3607
+ e.preventDefault();
3608
+ const n = parseInt(e.key, 10);
3609
+ this._commit(Math.min(n, this.max));
3610
+ }
3611
+ });
5484
3612
  }
5485
3613
  };
5486
- __decorate([state()], SelectHorizElement.prototype, "_selectedIndex", void 0);
5487
- __decorate([state()], SelectHorizElement.prototype, "_slottedItems", void 0);
3614
+ __decorate([property({ type: Number })], RatingElement.prototype, "value", void 0);
3615
+ __decorate([property({ type: Number })], RatingElement.prototype, "max", void 0);
5488
3616
  __decorate([property({
5489
- type: Number,
5490
- reflect: true,
5491
- attribute: `selected-index`
5492
- })], SelectHorizElement.prototype, "selectedIndex", null);
5493
- __decorate([property({ type: String })], SelectHorizElement.prototype, "selectedValue", null);
5494
- SelectHorizElement = __decorate([safeCustomElement(`ixfx-select-horiz`)], SelectHorizElement);
3617
+ type: Boolean,
3618
+ attribute: `allow-half`
3619
+ })], RatingElement.prototype, "allowHalf", void 0);
3620
+ __decorate([property({
3621
+ type: Boolean,
3622
+ reflect: true
3623
+ })], RatingElement.prototype, "disabled", void 0);
3624
+ __decorate([property({
3625
+ type: Boolean,
3626
+ reflect: true
3627
+ })], RatingElement.prototype, "readonly", void 0);
3628
+ __decorate([property({ type: String })], RatingElement.prototype, "variant", void 0);
3629
+ __decorate([state()], RatingElement.prototype, "_preview", void 0);
3630
+ RatingElement = __decorate([customElement(`ixfx-rating`)], RatingElement);
5495
3631
  //#endregion
5496
- //#region src/snackbar/snackbar.ts
5497
- let _instanceCounter = 0;
5498
- let SnackbarElement = class SnackbarElement extends LitElement {
3632
+ //#region src/toolbar/toolbar.ts
3633
+ var _ToolbarElement;
3634
+ let ToolbarElement = class ToolbarElement extends LitElement {
3635
+ static {
3636
+ _ToolbarElement = this;
3637
+ }
5499
3638
  constructor(..._args) {
5500
3639
  super(..._args);
5501
- this.for = ``;
5502
- this.mode = `explicit`;
5503
- this.placement = `top`;
5504
- this.dismiss = `auto`;
5505
- this.showDelay = 150;
5506
- this.hideDelay = 500;
5507
- this._isOpen = false;
5508
- this._anchorName = `--ixfx-snackbar-anchor-${++_instanceCounter}`;
5509
- this._addedTabindex = false;
5510
- this._addedRole = false;
5511
- this._onTargetClick = () => this.toggle();
5512
- this._onTargetKeydown = (e) => {
5513
- if (e.key !== `Enter` && e.key !== ` `) return;
5514
- e.preventDefault();
5515
- this.toggle();
5516
- };
5517
- this._onTickleIn = () => this._scheduleShow();
5518
- this._onTickleOut = () => this._scheduleHide();
5519
- this._onPanelClick = () => {
5520
- if (this.dismiss === `auto`) this.hide();
5521
- };
5522
- this._onToggle = (e) => {
5523
- const { newState } = e;
5524
- this._isOpen = newState === `open`;
5525
- if (newState === `closed` && this.contains(document.activeElement)) this._target?.focus();
5526
- };
5527
- this._onBeforeToggle = (e) => {
5528
- const { newState } = e;
5529
- this._recentCloseAt = newState === `closed` ? performance.now() : void 0;
5530
- };
5531
- }
5532
- get isOpen() {
5533
- return this._isOpen;
5534
- }
5535
- show() {
5536
- if (!this.popover) return;
5537
- try {
5538
- this.showPopover();
5539
- } catch {}
3640
+ this.orientation = `horizontal`;
3641
+ this.layout = `one-line`;
3642
+ this.verticalWriting = `auto`;
3643
+ this.showGroupLabels = false;
3644
+ this.invisibleGroups = false;
3645
+ this._overflowCount = 0;
3646
+ this._ro = null;
3647
+ this._anchor = `--toolbar-${_ToolbarElement._cnt++}`;
3648
+ this._sizes = /* @__PURE__ */ new WeakMap();
3649
+ this._measureQueued = false;
5540
3650
  }
5541
- hide() {
5542
- if (!this.popover) return;
5543
- try {
5544
- this.hidePopover();
5545
- } catch {}
3651
+ static {
3652
+ this._cnt = 0;
5546
3653
  }
5547
- toggle() {
5548
- if (!this.popover) return;
5549
- if (this._recentCloseAt !== void 0 && performance.now() - this._recentCloseAt < 50) {
5550
- this._recentCloseAt = void 0;
5551
- return;
5552
- }
5553
- try {
5554
- this.togglePopover();
5555
- } catch {}
3654
+ static {
3655
+ this.styles = [
3656
+ themeFallbacks,
3657
+ popupSurfaceStyles,
3658
+ css`
3659
+ :host {
3660
+ --toolbar-gap: var(--space-s);
3661
+ --toolbar-group-gap: var(--space-m);
3662
+ display: block;
3663
+ container-type: inline-size;
3664
+ }
3665
+ :host([orientation="vertical-left"]),
3666
+ :host([orientation="vertical-right"]) {
3667
+ container-type: normal;
3668
+ width: max-content;
3669
+ }
3670
+ :host([orientation="vertical-left"]),
3671
+ :host([orientation="vertical-right"]) { height: 100%; }
3672
+ :host([orientation="vertical-left"]) .inner,
3673
+ :host([orientation="vertical-right"]) .inner { height: 100%; box-sizing: border-box; width: max-content; }
3674
+ .inner {
3675
+ display: flex;
3676
+ gap: var(--toolbar-gap);
3677
+ background: var(--toolbar-bg, var(--surface-2));
3678
+ padding: var(--toolbar-padding, var(--space-s));
3679
+ border: var(--toolbar-border, var(--border-subtle));
3680
+ border-radius: var(--radius-s);
3681
+ align-items: center;
3682
+ }
3683
+ :host([orientation="horizontal"]) .inner { flex-direction: row; justify-content: flex-start; }
3684
+ :host([orientation="vertical-left"]) .inner { flex-direction: column-reverse; align-items: stretch; }
3685
+ :host([orientation="vertical-right"]) .inner { flex-direction: column; align-items: stretch; }
3686
+ :host([layout="wrap"]) .inner { flex-wrap: wrap; }
3687
+ :host([layout="one-line"]) .inner { flex-wrap: nowrap; overflow: hidden; }
3688
+ :host([orientation="vertical-left"][vertical-writing="auto"]) ::slotted(*) { writing-mode: sideways-lr; }
3689
+ :host([orientation="vertical-right"][vertical-writing="auto"]) ::slotted(*) { writing-mode: vertical-lr; }
3690
+ :host([vertical-writing="up"]) ::slotted(*) { writing-mode: vertical-rl; text-orientation: upright; }
3691
+ :host([vertical-writing="down"]) ::slotted(*) { writing-mode: vertical-lr; }
3692
+ :host([vertical-writing="none"]) ::slotted(*) { writing-mode: horizontal-tb; }
3693
+ ::slotted(*) { flex: 0 0 auto; }
3694
+ ::slotted([grow]), ::slotted(ixfx-toolbar-group[grow]) { flex: 1 1 auto; }
3695
+ ::slotted([hidden]) { display: none !important; }
3696
+ :host([invisible-groups]) ::slotted(ixfx-toolbar-group) { --toolbar-group-border: none; }
3697
+ .overflow-btn {
3698
+ anchor-name: var(--anchor-name);
3699
+ flex-shrink: 0;
3700
+ background: var(--surface-3);
3701
+ border: var(--border);
3702
+ border-radius: var(--radius-s);
3703
+ padding: var(--space-xs) var(--space-s);
3704
+ cursor: pointer;
3705
+ display: none;
3706
+ }
3707
+ .overflow-btn[visible] { display: inline-flex; }
3708
+ .overflow-popover {
3709
+ position: fixed;
3710
+ top: anchor(bottom);
3711
+ left: anchor(right);
3712
+ position-anchor: var(--anchor-name);
3713
+ position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
3714
+ margin: 8px;
3715
+ max-height: min(60vh, 400px);
3716
+ max-width: min(90vw, 320px);
3717
+ overflow: auto;
3718
+ overscroll-behavior: contain;
3719
+ z-index: 100;
3720
+ padding: var(--space-s);
3721
+ flex-direction: column;
3722
+ gap: var(--space-s);
3723
+ }
3724
+ .overflow-popover:popover-open { display: flex; }
3725
+ .overflow-popover ::slotted(*) { writing-mode: horizontal-tb; text-orientation: mixed; }
3726
+ `
3727
+ ];
5556
3728
  }
5557
3729
  connectedCallback() {
5558
3730
  super.connectedCallback();
5559
- if (!this.hasAttribute(`popover`)) this.popover = `auto`;
5560
- this.classList.add(`popup-surface`);
5561
- this.addEventListener(`toggle`, this._onToggle);
5562
- this.addEventListener(`beforetoggle`, this._onBeforeToggle);
5563
- this.addEventListener(`click`, this._onPanelClick);
5564
- this.style.setProperty(`position-anchor`, this._anchorName);
5565
- this._attachToTarget();
3731
+ this.style.setProperty(`--anchor-name`, this._anchor);
5566
3732
  }
5567
- disconnectedCallback() {
5568
- super.disconnectedCallback();
5569
- this.removeEventListener(`toggle`, this._onToggle);
5570
- this.removeEventListener(`beforetoggle`, this._onBeforeToggle);
5571
- this.removeEventListener(`click`, this._onPanelClick);
5572
- this._detachFromTarget();
5573
- this._cancelShow();
5574
- this._cancelHide();
3733
+ firstUpdated() {
3734
+ this._slot.addEventListener(`slotchange`, () => this._scheduleMeasure());
3735
+ this._ro = new ResizeObserver(() => this._scheduleMeasure());
3736
+ this._ro.observe(this._inner);
3737
+ this._scheduleMeasure();
3738
+ this._updateGroupLabels();
5575
3739
  }
5576
3740
  updated(changed) {
5577
- super.updated(changed);
5578
- if (changed.has(`for`) || changed.has(`mode`)) this._attachToTarget();
3741
+ if (changed.has(`showGroupLabels`)) this._updateGroupLabels();
5579
3742
  }
5580
- _resolveTarget() {
5581
- if (!this.for) return void 0;
5582
- return this.getRootNode().getElementById(this.for) ?? void 0;
5583
- }
5584
- _attachToTarget() {
5585
- this._detachFromTarget();
5586
- const target = this._resolveTarget();
5587
- if (!target) {
5588
- if (this.for) console.warn(`ixfx-snackbar: no element found with id "${this.for}"`);
5589
- return;
3743
+ _updateGroupLabels() {
3744
+ for (const child of Array.from(this.children)) if (child.tagName === `IXFX-TOOLBAR-GROUP`) {
3745
+ if (this.showGroupLabels) child.setAttribute(`show-label`, ``);
3746
+ else child.removeAttribute(`show-label`);
5590
3747
  }
5591
- this._target = target;
5592
- target.style.setProperty(`anchor-name`, this._anchorName);
5593
- if (this.mode === `explicit`) {
5594
- const alreadyFocusable = target.tabIndex >= 0;
5595
- if (!alreadyFocusable) {
5596
- target.setAttribute(`tabindex`, `0`);
5597
- this._addedTabindex = true;
3748
+ }
3749
+ disconnectedCallback() {
3750
+ super.disconnectedCallback();
3751
+ this._ro?.disconnect();
3752
+ }
3753
+ /** Coalesce measure passes into one per frame; prevents slotchange feedback loops. */
3754
+ _scheduleMeasure() {
3755
+ if (this._measureQueued) return;
3756
+ this._measureQueued = true;
3757
+ requestAnimationFrame(() => {
3758
+ this._measureQueued = false;
3759
+ this._measure();
3760
+ });
3761
+ }
3762
+ _measure() {
3763
+ const children = Array.from(this.children);
3764
+ const isGrow = (el) => el.hasAttribute(`grow`) || el.matches(`[grow]`);
3765
+ const overflowable = children.filter((el) => !isGrow(el));
3766
+ const isHoriz = this.orientation === `horizontal`;
3767
+ if (this.layout !== `one-line`) {
3768
+ let mutated = false;
3769
+ for (const el of children) {
3770
+ if (el.getAttribute(`slot`) === `overflow`) {
3771
+ el.removeAttribute(`slot`);
3772
+ mutated = true;
3773
+ }
3774
+ if (el.hasAttribute(`hidden`)) {
3775
+ el.removeAttribute(`hidden`);
3776
+ mutated = true;
3777
+ }
5598
3778
  }
5599
- if (!target.hasAttribute(`role`) && !alreadyFocusable) {
5600
- target.setAttribute(`role`, `button`);
5601
- this._addedRole = true;
3779
+ if (this._overflowCount !== 0) {
3780
+ this._overflowCount = 0;
3781
+ mutated = true;
5602
3782
  }
5603
- target.setAttribute(`aria-haspopup`, `true`);
5604
- target.addEventListener(`click`, this._onTargetClick);
5605
- if (!alreadyFocusable) target.addEventListener(`keydown`, this._onTargetKeydown);
5606
- } else if (this.mode === `implicit`) {
5607
- target.addEventListener(`pointerenter`, this._onTickleIn);
5608
- target.addEventListener(`focus`, this._onTickleIn);
5609
- target.addEventListener(`pointerleave`, this._onTickleOut);
5610
- target.addEventListener(`blur`, this._onTickleOut);
5611
- this.addEventListener(`pointerenter`, this._onTickleIn);
5612
- this.addEventListener(`focusin`, this._onTickleIn);
5613
- this.addEventListener(`pointerleave`, this._onTickleOut);
5614
- this.addEventListener(`focusout`, this._onTickleOut);
3783
+ if (mutated) this.requestUpdate();
3784
+ return;
5615
3785
  }
5616
- }
5617
- _detachFromTarget() {
5618
- const target = this._target;
5619
- if (!target) return;
5620
- target.style.removeProperty(`anchor-name`);
5621
- if (this._addedTabindex) {
5622
- target.removeAttribute(`tabindex`);
5623
- this._addedTabindex = false;
3786
+ if (!this._inner) return;
3787
+ const cs = getComputedStyle(this._inner);
3788
+ const gap = (isHoriz ? Number.parseFloat(cs.columnGap) : Number.parseFloat(cs.rowGap)) || 0;
3789
+ const available = isHoriz ? this._inner.clientWidth : this._inner.clientHeight;
3790
+ const btnSize = 36;
3791
+ const inMain = overflowable.filter((el) => el.getAttribute(`slot`) !== `overflow`);
3792
+ const inOverflow = overflowable.filter((el) => el.getAttribute(`slot`) === `overflow`);
3793
+ let cum = 0;
3794
+ inMain.forEach((el, i) => {
3795
+ const s = isHoriz ? el.offsetWidth : el.offsetHeight;
3796
+ if (s > 0) this._sizes.set(el, s);
3797
+ cum += (i ? gap : 0) + (this._sizes.get(el) ?? s);
3798
+ });
3799
+ const btnAllowance = inOverflow.length > 0 ? gap + btnSize : 0;
3800
+ let mutated = false;
3801
+ while (inMain.length > 0 && cum + btnAllowance > available) {
3802
+ const last = inMain[inMain.length - 1];
3803
+ const s = this._sizes.get(last) ?? 0;
3804
+ last.setAttribute(`slot`, `overflow`);
3805
+ inMain.pop();
3806
+ inOverflow.unshift(last);
3807
+ cum -= (inMain.length ? gap : 0) + s;
3808
+ mutated = true;
5624
3809
  }
5625
- if (this._addedRole) {
5626
- target.removeAttribute(`role`);
5627
- this._addedRole = false;
3810
+ while (inOverflow.length > 0) {
3811
+ const first = inOverflow[0];
3812
+ const s = this._sizes.get(first);
3813
+ if (s === void 0) break;
3814
+ const addGap = inMain.length ? gap : 0;
3815
+ const nextBtnAllowance = inOverflow.length > 1 ? gap + btnSize : 0;
3816
+ if (cum + addGap + s + nextBtnAllowance > available) break;
3817
+ first.removeAttribute(`slot`);
3818
+ inOverflow.shift();
3819
+ inMain.push(first);
3820
+ cum += addGap + s;
3821
+ mutated = true;
5628
3822
  }
5629
- target.removeAttribute(`aria-haspopup`);
5630
- target.removeEventListener(`click`, this._onTargetClick);
5631
- target.removeEventListener(`keydown`, this._onTargetKeydown);
5632
- target.removeEventListener(`pointerenter`, this._onTickleIn);
5633
- target.removeEventListener(`focus`, this._onTickleIn);
5634
- target.removeEventListener(`pointerleave`, this._onTickleOut);
5635
- target.removeEventListener(`blur`, this._onTickleOut);
5636
- this.removeEventListener(`pointerenter`, this._onTickleIn);
5637
- this.removeEventListener(`focusin`, this._onTickleIn);
5638
- this.removeEventListener(`pointerleave`, this._onTickleOut);
5639
- this.removeEventListener(`focusout`, this._onTickleOut);
5640
- this._target = void 0;
5641
- }
5642
- _scheduleShow() {
5643
- this._cancelHide();
5644
- this._cancelShow();
5645
- if (this.showDelay <= 0) {
5646
- this.show();
5647
- return;
3823
+ const newCount = inOverflow.length;
3824
+ if (newCount !== this._overflowCount) {
3825
+ this._overflowCount = newCount;
3826
+ mutated = true;
5648
3827
  }
5649
- this._showTimeout = window.setTimeout(() => this.show(), this.showDelay);
3828
+ if (mutated) this.requestUpdate();
5650
3829
  }
5651
- _scheduleHide() {
5652
- this._cancelShow();
5653
- this._cancelHide();
5654
- if (this.hideDelay <= 0) {
5655
- this.hide();
5656
- return;
3830
+ _toggleOverflow() {
3831
+ try {
3832
+ this._popover.togglePopover();
3833
+ } catch {
3834
+ this._popover.showPopover();
5657
3835
  }
5658
- this._hideTimeout = window.setTimeout(() => this.hide(), this.hideDelay);
5659
3836
  }
5660
- _cancelShow() {
5661
- if (this._showTimeout !== void 0) {
5662
- window.clearTimeout(this._showTimeout);
5663
- this._showTimeout = void 0;
5664
- }
3837
+ render() {
3838
+ const hasOverflow = this._overflowCount > 0;
3839
+ return html`
3840
+ <div class="inner" role="toolbar" aria-orientation=${this.orientation}>
3841
+ <slot></slot>
3842
+ <button class="overflow-btn" ?visible=${hasOverflow} @click=${this._toggleOverflow} aria-label="More" aria-haspopup="true" aria-expanded=${this._popover?.matches(`:popover-open`) ?? false}>⋯</button>
3843
+ </div>
3844
+ <div class="overflow-popover popup-surface" popover="auto" @click=${(e) => e.stopPropagation()}>
3845
+ <slot name="overflow"></slot>
3846
+ </div>
3847
+ `;
5665
3848
  }
5666
- _cancelHide() {
5667
- if (this._hideTimeout !== void 0) {
5668
- window.clearTimeout(this._hideTimeout);
5669
- this._hideTimeout = void 0;
5670
- }
3849
+ };
3850
+ __decorate([property({
3851
+ type: String,
3852
+ reflect: true
3853
+ })], ToolbarElement.prototype, "orientation", void 0);
3854
+ __decorate([property({
3855
+ type: String,
3856
+ reflect: true
3857
+ })], ToolbarElement.prototype, "layout", void 0);
3858
+ __decorate([property({
3859
+ type: String,
3860
+ attribute: `vertical-writing`,
3861
+ reflect: true
3862
+ })], ToolbarElement.prototype, "verticalWriting", void 0);
3863
+ __decorate([property({
3864
+ type: Boolean,
3865
+ attribute: `show-group-labels`,
3866
+ reflect: true
3867
+ })], ToolbarElement.prototype, "showGroupLabels", void 0);
3868
+ __decorate([property({
3869
+ type: Boolean,
3870
+ attribute: `invisible-groups`,
3871
+ reflect: true
3872
+ })], ToolbarElement.prototype, "invisibleGroups", void 0);
3873
+ __decorate([state()], ToolbarElement.prototype, "_overflowCount", void 0);
3874
+ __decorate([query(`.inner`)], ToolbarElement.prototype, "_inner", void 0);
3875
+ __decorate([query(`.overflow-popover`)], ToolbarElement.prototype, "_popover", void 0);
3876
+ __decorate([query(`slot`)], ToolbarElement.prototype, "_slot", void 0);
3877
+ ToolbarElement = _ToolbarElement = __decorate([safeCustomElement(`ixfx-toolbar`)], ToolbarElement);
3878
+ //#endregion
3879
+ //#region src/toolbar/toolbar-group.ts
3880
+ let ToolbarGroupElement = class ToolbarGroupElement extends LitElement {
3881
+ constructor(..._args) {
3882
+ super(..._args);
3883
+ this.label = ``;
3884
+ this.grow = false;
5671
3885
  }
5672
3886
  static {
5673
- this.styles = [
5674
- themeFallbacks,
5675
- popupSurfaceStyles,
5676
- css`
3887
+ this.styles = [themeFallbacks, css`
5677
3888
  :host {
5678
3889
  display: flex;
5679
- align-items: center;
5680
- gap: var(--space-s);
5681
- padding: var(--space-s);
5682
-
5683
- position: fixed;
5684
- inset: unset;
5685
- margin: 0;
5686
- z-index: 100;
5687
- position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
5688
-
5689
- opacity: 0;
5690
- scale: 0.97;
5691
- pointer-events: none;
5692
- transition: opacity 0.12s ease-out, scale 0.12s ease-out,
5693
- display 0.12s allow-discrete, overlay 0.12s allow-discrete;
5694
- }
5695
-
5696
- :host(:popover-open) {
5697
- opacity: 1;
5698
- scale: 1;
5699
- pointer-events: auto;
5700
- }
5701
-
5702
- @starting-style {
5703
- :host(:popover-open) {
5704
- opacity: 0;
5705
- scale: 0.97;
5706
- }
5707
- }
5708
-
5709
- :host([placement="top"]) {
5710
- position-area: block-start;
5711
- margin-block-end: var(--space-s);
5712
- }
5713
-
5714
- :host([placement="bottom"]) {
5715
- position-area: block-end;
5716
- margin-block-start: var(--space-s);
5717
- }
5718
-
5719
- :host([placement="left"]) {
5720
- position-area: inline-start;
5721
- margin-inline-end: var(--space-s);
3890
+ flex-direction: column;
3891
+ align-items: var(--toolbar-group-align-items, center);
3892
+ justify-content: var(--toolbar-group-justify-content, flex-start);
3893
+ gap: var(--toolbar-gap, var(--space-s));
3894
+ padding: var(--space-xs);
3895
+ border: 1px solid var(--border-subtle, var(--border));
3896
+ border-radius: var(--radius-s);
3897
+ background: var(--surface-3);
3898
+ min-width: 0;
5722
3899
  }
5723
-
5724
- :host([placement="right"]) {
5725
- position-area: inline-end;
5726
- margin-inline-start: var(--space-s);
3900
+ :host(:not([label])) {
3901
+ border: none;
3902
+ background: transparent;
3903
+ padding: 0;
5727
3904
  }
5728
- `
5729
- ];
3905
+ .label-row {
3906
+ display: none;
3907
+ font-size: var(--text-s, 12px);
3908
+ color: var(--surface-muted-text);
3909
+ padding-inline: var(--space-xs);
3910
+ white-space: nowrap;
3911
+ border-bottom: 1px solid var(--border-subtle);
3912
+ margin-bottom: var(--space-xs);
3913
+ }
3914
+ :host([label][show-label]) .label-row { display: block; }
3915
+ :host(:not([label])) .label-row { display: none; }
3916
+ :host([grow]) { flex: 1 1 auto; min-width: 0; }
3917
+ :host([hidden]) { display: none !important; }
3918
+ .components { display: flex; }
3919
+ ::slotted(*) { flex: 0 0 auto; }
3920
+ ::slotted([grow]) { flex: 1 1 auto; }
3921
+ `];
5730
3922
  }
5731
3923
  render() {
5732
- return html`<slot></slot>`;
3924
+ return html`
3925
+ <div class="label-row">${this.label}</div>
3926
+ <div class="components">
3927
+ <slot></slot>
3928
+ </div>
3929
+ `;
5733
3930
  }
5734
3931
  };
5735
- __decorate([property({ type: String })], SnackbarElement.prototype, "for", void 0);
5736
- __decorate([property({ type: String })], SnackbarElement.prototype, "mode", void 0);
3932
+ __decorate([property({ type: String })], ToolbarGroupElement.prototype, "label", void 0);
5737
3933
  __decorate([property({
5738
- type: String,
3934
+ type: Boolean,
5739
3935
  reflect: true
5740
- })], SnackbarElement.prototype, "placement", void 0);
5741
- __decorate([property({ type: String })], SnackbarElement.prototype, "dismiss", void 0);
5742
- __decorate([property({
5743
- type: Number,
5744
- attribute: `show-delay`
5745
- })], SnackbarElement.prototype, "showDelay", void 0);
5746
- __decorate([property({
5747
- type: Number,
5748
- attribute: `hide-delay`
5749
- })], SnackbarElement.prototype, "hideDelay", void 0);
5750
- __decorate([state()], SnackbarElement.prototype, "_isOpen", void 0);
5751
- SnackbarElement = __decorate([safeCustomElement(`ixfx-snackbar`)], SnackbarElement);
3936
+ })], ToolbarGroupElement.prototype, "grow", void 0);
3937
+ ToolbarGroupElement = __decorate([safeCustomElement(`ixfx-toolbar-group`)], ToolbarGroupElement);
5752
3938
  //#endregion
5753
3939
  //#region src/tabs/tab-list-item.ts
5754
3940
  let TabListItemElement = class TabListItemElement extends LitElement {
@@ -6396,248 +4582,6 @@ let TabPanelsElement = class TabPanelsElement extends LitElement {
6396
4582
  __decorate([queryAssignedElements()], TabPanelsElement.prototype, "_listItems", void 0);
6397
4583
  TabPanelsElement = __decorate([safeCustomElement(`ixfx-tab-panels`)], TabPanelsElement);
6398
4584
  //#endregion
6399
- //#region src/transitory-label/transitory-label.ts
6400
- let TransitoryLabelElement = class TransitoryLabelElement extends LitElement {
6401
- constructor(..._args) {
6402
- super(..._args);
6403
- this.text = ``;
6404
- this.effect = `fade`;
6405
- this.duration = 300;
6406
- this.easing = `ease`;
6407
- this._currentText = ``;
6408
- this._outgoingText = ``;
6409
- this._transitionId = 0;
6410
- this._queue = [];
6411
- this.#onOutgoingEnd = () => {
6412
- this._onTransitionEnd();
6413
- };
6414
- this.#onLastCharOut = () => {
6415
- this._onTransitionEnd();
6416
- };
6417
- }
6418
- setText(msg, effect) {
6419
- this._pendingEffect = effect;
6420
- this.text = msg;
6421
- }
6422
- updated(changed) {
6423
- if (changed.has(`text`) && this.text !== this._currentText) {
6424
- const effect = this._pendingEffect ?? this.effect;
6425
- this._pendingEffect = void 0;
6426
- if (this._activeEffect !== void 0) this._queue.push({
6427
- text: this.text,
6428
- effect
6429
- });
6430
- else this._startTransition(this.text, effect);
6431
- }
6432
- }
6433
- _startTransition(newText, effect) {
6434
- const prevText = this._currentText;
6435
- this._currentText = newText;
6436
- this._outgoingText = prevText;
6437
- if (prevText !== ``) {
6438
- this._transitionId++;
6439
- this._activeEffect = effect;
6440
- }
6441
- }
6442
- _onTransitionEnd() {
6443
- this._outgoingText = ``;
6444
- this._activeEffect = void 0;
6445
- if (this._queue.length > 0) {
6446
- const next = this._queue.shift();
6447
- this._startTransition(next.text, next.effect);
6448
- }
6449
- }
6450
- #onOutgoingEnd;
6451
- #onLastCharOut;
6452
- #renderCharSwap() {
6453
- const charDuration = Math.round(this.duration * .3);
6454
- const charStagger = Math.round(this.duration * .1);
6455
- const currentChars = this._currentText.split(``);
6456
- const outgoingChars = this._outgoingText.split(``);
6457
- const lastIdx = outgoingChars.length - 1;
6458
- const charStyle = (i) => `animation-duration:${charDuration}ms;animation-delay:${i * charStagger}ms;animation-timing-function:${this.easing}`;
6459
- return html`
6460
- ${keyed(`cc${this._transitionId}`, html`
6461
- <span class="layer current char-swap">
6462
- ${currentChars.map((ch, i) => html`<span class="char in" style=${charStyle(i)}>${ch}</span>`)}
6463
- </span>
6464
- `)}
6465
- ${this._outgoingText ? keyed(this._transitionId, html`
6466
- <span class="layer outgoing char-swap">
6467
- ${outgoingChars.map((ch, i) => html`<span
6468
- class="char out"
6469
- style=${charStyle(i)}
6470
- @animationend=${i === lastIdx ? this.#onLastCharOut : void 0}
6471
- >${ch}</span>`)}
6472
- </span>
6473
- `) : nothing}
6474
- `;
6475
- }
6476
- render() {
6477
- if (this._activeEffect === `character-swap`) return html`<span class="container">${this.#renderCharSwap()}</span>`;
6478
- const effect = this._activeEffect ?? ``;
6479
- const durStyle = this._activeEffect ? `animation-duration:${this.duration}ms;animation-timing-function:${this.easing}` : ``;
6480
- return html`
6481
- <span class="container">
6482
- ${this._outgoingText ? keyed(this._transitionId, html`
6483
- <span class="layer outgoing ${effect}" style=${durStyle} @animationend=${this.#onOutgoingEnd}>
6484
- ${this._outgoingText}
6485
- </span>
6486
- `) : nothing}
6487
- ${keyed(`c${this._transitionId}`, html`
6488
- <span class="layer current ${effect}" style=${durStyle}>
6489
- ${this._currentText}
6490
- </span>
6491
- `)}
6492
- </span>
6493
- `;
6494
- }
6495
- static {
6496
- this.styles = css`
6497
- :host {
6498
- display: inline-block;
6499
- --transitory-label-easing: ease;
6500
- }
6501
-
6502
- .container {
6503
- display: inline-grid;
6504
- overflow: hidden;
6505
- }
6506
-
6507
- .layer {
6508
- grid-area: 1 / 1;
6509
- white-space: nowrap;
6510
- }
6511
-
6512
- .layer.outgoing {
6513
- pointer-events: none;
6514
- }
6515
-
6516
- /* slide-right */
6517
- .layer.current.slide-right {
6518
- transform: translateX(-100%);
6519
- animation: tl-slide-in-left var(--transitory-label-easing) forwards;
6520
- }
6521
- .layer.outgoing.slide-right {
6522
- animation: tl-slide-out-right var(--transitory-label-easing) forwards;
6523
- }
6524
-
6525
- @keyframes tl-slide-in-left {
6526
- from { transform: translateX(-100%); }
6527
- to { transform: translateX(0); }
6528
- }
6529
- @keyframes tl-slide-out-right {
6530
- from { transform: translateX(0); }
6531
- to { transform: translateX(100%); }
6532
- }
6533
-
6534
- /* slide-left */
6535
- .layer.current.slide-left {
6536
- transform: translateX(100%);
6537
- animation: tl-slide-in-right var(--transitory-label-easing) forwards;
6538
- }
6539
- .layer.outgoing.slide-left {
6540
- animation: tl-slide-out-left var(--transitory-label-easing) forwards;
6541
- }
6542
-
6543
- @keyframes tl-slide-in-right {
6544
- from { transform: translateX(100%); }
6545
- to { transform: translateX(0); }
6546
- }
6547
- @keyframes tl-slide-out-left {
6548
- from { transform: translateX(0); }
6549
- to { transform: translateX(-100%); }
6550
- }
6551
-
6552
- /* slide-up */
6553
- .layer.current.slide-up {
6554
- transform: translateY(100%);
6555
- animation: tl-slide-in-bottom var(--transitory-label-easing) forwards;
6556
- }
6557
- .layer.outgoing.slide-up {
6558
- animation: tl-slide-out-top var(--transitory-label-easing) forwards;
6559
- }
6560
-
6561
- @keyframes tl-slide-in-bottom {
6562
- from { transform: translateY(100%); }
6563
- to { transform: translateY(0); }
6564
- }
6565
- @keyframes tl-slide-out-top {
6566
- from { transform: translateY(0); }
6567
- to { transform: translateY(-100%); }
6568
- }
6569
-
6570
- /* slide-down */
6571
- .layer.current.slide-down {
6572
- transform: translateY(-100%);
6573
- animation: tl-slide-in-top var(--transitory-label-easing) forwards;
6574
- }
6575
- .layer.outgoing.slide-down {
6576
- animation: tl-slide-out-bottom var(--transitory-label-easing) forwards;
6577
- }
6578
-
6579
- @keyframes tl-slide-in-top {
6580
- from { transform: translateY(-100%); }
6581
- to { transform: translateY(0); }
6582
- }
6583
- @keyframes tl-slide-out-bottom {
6584
- from { transform: translateY(0); }
6585
- to { transform: translateY(100%); }
6586
- }
6587
-
6588
- /* fade */
6589
- .layer.current.fade {
6590
- opacity: 0;
6591
- animation: tl-fade-in var(--transitory-label-easing) forwards;
6592
- }
6593
- .layer.outgoing.fade {
6594
- animation: tl-fade-out var(--transitory-label-easing) forwards;
6595
- }
6596
-
6597
- @keyframes tl-fade-in {
6598
- from { opacity: 0; }
6599
- to { opacity: 1; }
6600
- }
6601
- @keyframes tl-fade-out {
6602
- from { opacity: 1; }
6603
- to { opacity: 0; }
6604
- }
6605
-
6606
- /* character-swap */
6607
- .char {
6608
- display: inline-block;
6609
- }
6610
-
6611
- .char.in {
6612
- opacity: 0;
6613
- animation: tl-char-in var(--transitory-label-easing) forwards;
6614
- }
6615
-
6616
- .char.out {
6617
- animation: tl-char-out var(--transitory-label-easing) forwards;
6618
- }
6619
-
6620
- @keyframes tl-char-in {
6621
- from { opacity: 0; transform: translateY(-0.3em) scale(0.8); }
6622
- to { opacity: 1; transform: translateY(0) scale(1); }
6623
- }
6624
- @keyframes tl-char-out {
6625
- from { opacity: 1; transform: translateY(0) scale(1); }
6626
- to { opacity: 0; transform: translateY(0.3em) scale(0.8); }
6627
- }
6628
- `;
6629
- }
6630
- };
6631
- __decorate([property({ type: String })], TransitoryLabelElement.prototype, "text", void 0);
6632
- __decorate([property({ type: String })], TransitoryLabelElement.prototype, "effect", void 0);
6633
- __decorate([property({ type: Number })], TransitoryLabelElement.prototype, "duration", void 0);
6634
- __decorate([property({ type: String })], TransitoryLabelElement.prototype, "easing", void 0);
6635
- __decorate([state()], TransitoryLabelElement.prototype, "_currentText", void 0);
6636
- __decorate([state()], TransitoryLabelElement.prototype, "_outgoingText", void 0);
6637
- __decorate([state()], TransitoryLabelElement.prototype, "_activeEffect", void 0);
6638
- __decorate([state()], TransitoryLabelElement.prototype, "_transitionId", void 0);
6639
- TransitoryLabelElement = __decorate([safeCustomElement(`ixfx-transitory-label`)], TransitoryLabelElement);
6640
- //#endregion
6641
4585
  //#region src/util/checkbox.ts
6642
4586
  function isCheckboxLike(el) {
6643
4587
  if (!(el instanceof HTMLElement)) return false;
@@ -6695,6 +4639,6 @@ function init() {
6695
4639
  console.log(`Init`);
6696
4640
  }
6697
4641
  //#endregion
6698
- export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, LabelledRadialInput, LabelledRangeInput, LedElement, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, SelectHorizElement, SelectHorizontalElement, SliderInputElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TimelineController, TimelineTrackTabElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeListElement, VerticalListElement, XyPad, applyAgeModification, applyHighlights, attachTimelineInteractions, buildHighlightTargets, clearHighlights, collectDataResult, computeColour, createAcCompletionProvider, createElementIncrSearch, createFuzzySearch, createIncrSearch, createPillRenderer, createTreeListAdapter, createVerticalListAdapter, getIcon, hasIcon, iconBus, init, monitorIndeterminate, parseColourScaleAttr, readBaseColour, registerIcon, resolveCssVars, resolveGrid, svgToDataUri, timelineStyles };
4642
+ export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, DataGridElement, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, LabelledRadialInput, LabelledRangeInput, LedElement, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, SliderInputElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TimelineController, TimelineTrackTabElement, ToolbarElement, ToolbarGroupElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeListElement, VerticalListElement, XyPad, applyAgeModification, applyHighlights, attachTimelineInteractions, buildHighlightTargets, clearHighlights, collectDataResult, computeColour, createAcCompletionProvider, createElementIncrSearch, createFuzzySearch, createIncrSearch, createPillRenderer, createTreeListAdapter, createVerticalListAdapter, getIcon, hasIcon, iconBus, init, monitorIndeterminate, parseColourScaleAttr, readBaseColour, registerIcon, resolveCssVars, resolveGrid, svgToDataUri, timelineStyles };
6699
4643
 
6700
4644
  //# sourceMappingURL=index.js.map