@ixfx/components 0.3.1 → 0.4.0

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 (256) hide show
  1. package/bundle/index.d.ts +1086 -603
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +16527 -14258
  4. package/bundle/index.js.map +1 -1
  5. package/bundle/style.css +14 -4
  6. package/dist/ac-text.d.ts.map +1 -1
  7. package/dist/ac-text.js +11 -6
  8. package/dist/ac-text.js.map +1 -1
  9. package/dist/{button-DMt5XWUK.js → button-C3fLMKUv.js} +4 -4
  10. package/dist/{button-DMt5XWUK.js.map → button-C3fLMKUv.js.map} +1 -1
  11. package/dist/button.d.ts.map +1 -1
  12. package/dist/button.js +1 -1
  13. package/dist/checkbox.d.ts +2 -2
  14. package/dist/checkbox.d.ts.map +1 -1
  15. package/dist/checkbox.js +14 -8
  16. package/dist/checkbox.js.map +1 -1
  17. package/dist/{colour-C3MQIjFJ-BLXg8W3U.js → colour-C3MQIjFJ-vRCdr8W-.js} +146 -552
  18. package/dist/colour-C3MQIjFJ-vRCdr8W-.js.map +1 -0
  19. package/dist/{colour-picker-K6zu82lm.js → colour-picker-0sgAha1T.js} +14 -9
  20. package/dist/colour-picker-0sgAha1T.js.map +1 -0
  21. package/dist/colour-picker.d.ts +1 -1
  22. package/dist/colour-picker.js +1 -1
  23. package/dist/crumbs.d.ts +1 -1
  24. package/dist/crumbs.d.ts.map +1 -1
  25. package/dist/crumbs.js +11 -6
  26. package/dist/crumbs.js.map +1 -1
  27. package/dist/data-display.d.ts +9 -4
  28. package/dist/data-display.d.ts.map +1 -1
  29. package/dist/data-display.js +270 -43
  30. package/dist/data-display.js.map +1 -1
  31. package/dist/data-provider-DgI909FP.js +23 -0
  32. package/dist/data-provider-DgI909FP.js.map +1 -0
  33. package/dist/{decorate-D7rC1gLP.js → decorate-DdjvVHS-.js} +2 -2
  34. package/dist/{decorate-D7rC1gLP.js.map → decorate-DdjvVHS-.js.map} +1 -1
  35. package/dist/{defaults-C7elhuyJ.js → defaults-C3b9OWJD.js} +2 -2
  36. package/dist/{defaults-C7elhuyJ.js.map → defaults-C3b9OWJD.js.map} +1 -1
  37. package/dist/{dist-TAGYwaju.js → dist-CA13FvMn.js} +7 -66
  38. package/dist/dist-CA13FvMn.js.map +1 -0
  39. package/dist/editable-label.d.ts.map +1 -1
  40. package/dist/editable-label.js +3 -2
  41. package/dist/editable-label.js.map +1 -1
  42. package/dist/fallbacks-pNMOMx38.js +168 -0
  43. package/dist/fallbacks-pNMOMx38.js.map +1 -0
  44. package/dist/{hex-editor-DlfoA65y.d.ts → hex-editor-CMIxtNgT.d.ts} +1 -1
  45. package/dist/hex-editor-CMIxtNgT.d.ts.map +1 -0
  46. package/dist/{hex-editor-CsN_ySkH.js → hex-editor-WZrjRtvL.js} +3 -3
  47. package/dist/{hex-editor-CsN_ySkH.js.map → hex-editor-WZrjRtvL.js.map} +1 -1
  48. package/dist/hex.d.ts +1 -1
  49. package/dist/hex.js +1 -1
  50. package/dist/{highlight-TPbSHruI.js → highlight-B-eQrhhb.js} +1 -1
  51. package/dist/{highlight-TPbSHruI.js.map → highlight-B-eQrhhb.js.map} +1 -1
  52. package/dist/{icon-CeTDJhC7.d.ts → icon-Bd5BiU4b.d.ts} +2 -2
  53. package/dist/icon-Bd5BiU4b.d.ts.map +1 -0
  54. package/dist/{icon-9NWTXtE1.js → icon-Ndo40kNO.js} +6 -5
  55. package/dist/icon-Ndo40kNO.js.map +1 -0
  56. package/dist/icons.d.ts +2 -2
  57. package/dist/icons.js +3 -3
  58. package/dist/{incr-search-DSKKsk6w.js → incr-search-CeERfijK.js} +2 -2
  59. package/dist/{incr-search-DSKKsk6w.js.map → incr-search-CeERfijK.js.map} +1 -1
  60. package/dist/incr-search.d.ts +1 -1
  61. package/dist/incr-search.js +2 -2
  62. package/dist/{index-hXFn14tM.d.ts → index-BMjri2-S.d.ts} +2 -2
  63. package/dist/{index-hXFn14tM.d.ts.map → index-BMjri2-S.d.ts.map} +1 -1
  64. package/dist/{index-DSlPeWLK.d.ts → index-CWpNcQKE.d.ts} +5 -5
  65. package/dist/index-CWpNcQKE.d.ts.map +1 -0
  66. package/dist/{index--hrxPBkQ.d.ts → index-CowKi2mo.d.ts} +2 -1
  67. package/dist/index-CowKi2mo.d.ts.map +1 -0
  68. package/dist/{index-B1hNR7Z9.d.ts → index-D87kRcEs.d.ts} +1 -1
  69. package/dist/{index-B1hNR7Z9.d.ts.map → index-D87kRcEs.d.ts.map} +1 -1
  70. package/dist/{index-CnL9krsH.d.ts → index-DgXpCg_G.d.ts} +32 -26
  71. package/dist/index-DgXpCg_G.d.ts.map +1 -0
  72. package/dist/{index-DrQjA8Gs.d.ts → index-s_IhSnwc.d.ts} +2 -2
  73. package/dist/index-s_IhSnwc.d.ts.map +1 -0
  74. package/dist/index.d.ts +432 -121
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +2370 -1707
  77. package/dist/index.js.map +1 -1
  78. package/dist/interaction-D6efrBLo.js +1 -0
  79. package/dist/{keyboard-De_vOHLg.js → keyboard-CimiEskD.js} +1 -1
  80. package/dist/{keyboard-De_vOHLg.js.map → keyboard-CimiEskD.js.map} +1 -1
  81. package/dist/{labelled-input-base-CqPL5rKm.js → labelled-input-base-9K_w3oLj.js} +2 -2
  82. package/dist/{labelled-input-base-CqPL5rKm.js.map → labelled-input-base-9K_w3oLj.js.map} +1 -1
  83. package/dist/{labelled-input-base-D-Y7agky.d.ts → labelled-input-base-ORb1rGq6.d.ts} +1 -1
  84. package/dist/labelled-input-base-ORb1rGq6.d.ts.map +1 -0
  85. package/dist/labelled-radial-input.d.ts +2 -2
  86. package/dist/labelled-radial-input.d.ts.map +1 -1
  87. package/dist/labelled-radial-input.js +7 -6
  88. package/dist/labelled-radial-input.js.map +1 -1
  89. package/dist/labelled-range-input.d.ts +1 -1
  90. package/dist/labelled-range-input.js +2 -2
  91. package/dist/led.d.ts +1 -1
  92. package/dist/led.d.ts.map +1 -1
  93. package/dist/led.js +2 -2
  94. package/dist/led.js.map +1 -1
  95. package/dist/{menu-item-CKRfP0pN.js → menu-item-BrIuORYD.js} +20 -10
  96. package/dist/menu-item-BrIuORYD.js.map +1 -0
  97. package/dist/{menu-item-ClQF2DKN.d.ts → menu-item-COx-Azgj.d.ts} +1 -1
  98. package/dist/menu-item-COx-Azgj.d.ts.map +1 -0
  99. package/dist/{menu-DJJuCm-5.js → menu-vjoiHZ13.js} +30 -17
  100. package/dist/menu-vjoiHZ13.js.map +1 -0
  101. package/dist/menu.d.ts +2 -2
  102. package/dist/menu.js +2 -2
  103. package/dist/miller.d.ts +2 -2
  104. package/dist/miller.d.ts.map +1 -1
  105. package/dist/miller.js +18 -11
  106. package/dist/miller.js.map +1 -1
  107. package/dist/narrowed-text.d.ts.map +1 -1
  108. package/dist/narrowed-text.js +7 -5
  109. package/dist/narrowed-text.js.map +1 -1
  110. package/dist/panel.d.ts +1 -1
  111. package/dist/panel.d.ts.map +1 -1
  112. package/dist/panel.js +5 -4
  113. package/dist/panel.js.map +1 -1
  114. package/dist/plots.d.ts +2 -2
  115. package/dist/plots.js +2 -2
  116. package/dist/polar-pad.d.ts +1 -1
  117. package/dist/polar-pad.d.ts.map +1 -1
  118. package/dist/polar-pad.js +10 -4
  119. package/dist/polar-pad.js.map +1 -1
  120. package/dist/{popup-ImtS9KnS.js → popup-DiWMxsWj.js} +1 -1
  121. package/dist/{popup-ImtS9KnS.js.map → popup-DiWMxsWj.js.map} +1 -1
  122. package/dist/prominence-DlFShic3.js +104 -0
  123. package/dist/prominence-DlFShic3.js.map +1 -0
  124. package/dist/{radial-input-LUSBEycd.d.ts → radial-input-CpQPs1Mp.d.ts} +1 -1
  125. package/dist/radial-input-CpQPs1Mp.d.ts.map +1 -0
  126. package/dist/{radial-input-DZA6WaFu.js → radial-input-DZ7eQCcM.js} +11 -6
  127. package/dist/radial-input-DZ7eQCcM.js.map +1 -0
  128. package/dist/radial-input.d.ts +1 -1
  129. package/dist/radial-input.js +1 -1
  130. package/dist/range-input.d.ts +1 -1
  131. package/dist/range-input.d.ts.map +1 -1
  132. package/dist/range-input.js +9 -4
  133. package/dist/range-input.js.map +1 -1
  134. package/dist/range.d.ts +1 -1
  135. package/dist/range.d.ts.map +1 -1
  136. package/dist/range.js +5 -3
  137. package/dist/range.js.map +1 -1
  138. package/dist/{registry-Q2gYQCHM.js → registry-CkW7q09Q.js} +1 -1
  139. package/dist/{registry-Q2gYQCHM.js.map → registry-CkW7q09Q.js.map} +1 -1
  140. package/dist/selecthorizontal.d.ts +1 -1
  141. package/dist/selecthorizontal.d.ts.map +1 -1
  142. package/dist/selecthorizontal.js +4 -3
  143. package/dist/selecthorizontal.js.map +1 -1
  144. package/dist/snap-container.d.ts.map +1 -1
  145. package/dist/snap-container.js +1 -1
  146. package/dist/split-layout.d.ts +1 -1
  147. package/dist/split-layout.d.ts.map +1 -1
  148. package/dist/split-layout.js +6 -5
  149. package/dist/split-layout.js.map +1 -1
  150. package/dist/style.css +14 -4
  151. package/dist/swipe.d.ts.map +1 -1
  152. package/dist/swipe.js +9 -4
  153. package/dist/swipe.js.map +1 -1
  154. package/dist/{tab-list-BnqISNvO.d.ts → tab-list-DLzb-m-I.d.ts} +2 -2
  155. package/dist/tab-list-DLzb-m-I.d.ts.map +1 -0
  156. package/dist/tabs.d.ts +1 -1
  157. package/dist/tabs.js +10 -4
  158. package/dist/tabs.js.map +1 -1
  159. package/dist/{tickled-controller-Cq1Va0rR.d.ts → tickled-controller-BjYCzGrU.d.ts} +2 -2
  160. package/dist/tickled-controller-BjYCzGrU.d.ts.map +1 -0
  161. package/dist/{tickled-styles-Bg3QbcrD.js → tickled-styles-fNDdqf6l.js} +1 -17
  162. package/dist/{tickled-styles-Bg3QbcrD.js.map → tickled-styles-fNDdqf6l.js.map} +1 -1
  163. package/dist/{timeline-Cv75Th2U.js → timeline-2OFtN4Ta.js} +1437 -36
  164. package/dist/timeline-2OFtN4Ta.js.map +1 -0
  165. package/dist/timeline.d.ts +1 -1
  166. package/dist/timeline.js +1 -1
  167. package/dist/{tooltip-DMxmBNky.js → tooltip-CJt3WLmN.js} +1 -1
  168. package/dist/{tooltip-DMxmBNky.js.map → tooltip-CJt3WLmN.js.map} +1 -1
  169. package/dist/{tooltip-CwGfb4lp.d.ts → tooltip-RGVIwHrZ.d.ts} +1 -1
  170. package/dist/{tooltip-CwGfb4lp.d.ts.map → tooltip-RGVIwHrZ.d.ts.map} +1 -1
  171. package/dist/{tree-CvvKbO-f.js → tree-CJWpMUvD.js} +113 -103
  172. package/dist/tree-CJWpMUvD.js.map +1 -0
  173. package/dist/{tree-component-D8Bg48tt.d.ts → tree-component-BcO26Xvt.d.ts} +65 -3
  174. package/dist/tree-component-BcO26Xvt.d.ts.map +1 -0
  175. package/dist/tree.d.ts +15 -15
  176. package/dist/tree.d.ts.map +1 -1
  177. package/dist/tree.js +1 -1
  178. package/dist/{types-BKaqnpwx.d.ts → types-DSfbtHs3.d.ts} +1 -1
  179. package/dist/types-DSfbtHs3.d.ts.map +1 -0
  180. package/dist/{xy-axis-DL0tfJDr.js → xy-axis-CK64haaK.js} +1831 -359
  181. package/dist/xy-axis-CK64haaK.js.map +1 -0
  182. package/dist/{xy-axis-D9uwpGTT.d.ts → xy-axis-McdUpcYr.d.ts} +102 -3
  183. package/dist/xy-axis-McdUpcYr.d.ts.map +1 -0
  184. package/dist/xy-pad.d.ts +1 -1
  185. package/dist/xy-pad.d.ts.map +1 -1
  186. package/dist/xy-pad.js +11 -6
  187. package/dist/xy-pad.js.map +1 -1
  188. package/docs-user/README.md +45 -0
  189. package/docs-user/ac-text.md +67 -0
  190. package/docs-user/ac-token.md +187 -0
  191. package/docs-user/button.md +355 -0
  192. package/docs-user/checkbox.md +62 -0
  193. package/docs-user/colour-picker.md +237 -0
  194. package/docs-user/crumbs.md +66 -0
  195. package/docs-user/data-display.md +98 -0
  196. package/docs-user/editable-label.md +244 -0
  197. package/docs-user/grouped-item-lister.md +424 -0
  198. package/docs-user/icons.md +191 -0
  199. package/docs-user/incr-search.md +94 -0
  200. package/docs-user/labelled-radial-input.md +204 -0
  201. package/docs-user/labelled-range-input.md +194 -0
  202. package/docs-user/led.md +40 -0
  203. package/docs-user/menu.md +319 -0
  204. package/docs-user/miller.md +453 -0
  205. package/docs-user/narrowed-text.md +72 -0
  206. package/docs-user/panel.md +250 -0
  207. package/docs-user/plots.md +361 -0
  208. package/docs-user/polar-pad.md +228 -0
  209. package/docs-user/radial-input.md +559 -0
  210. package/docs-user/range-input.md +264 -0
  211. package/docs-user/range.md +12 -0
  212. package/docs-user/selecthorizontal.md +32 -0
  213. package/docs-user/snap-container.md +132 -0
  214. package/docs-user/split-layout.md +232 -0
  215. package/docs-user/swipe.md +44 -0
  216. package/docs-user/tabs.md +217 -0
  217. package/docs-user/timeline.md +116 -0
  218. package/docs-user/transitory-label.md +120 -0
  219. package/docs-user/tree.md +592 -0
  220. package/docs-user/user-catalog.md +165 -0
  221. package/docs-user/user-theming.md +379 -0
  222. package/docs-user/util.md +122 -0
  223. package/docs-user/vertical-list.md +351 -0
  224. package/docs-user/xy-pad.md +94 -0
  225. package/package.json +19 -18
  226. package/dist/colour-C3MQIjFJ-BLXg8W3U.js.map +0 -1
  227. package/dist/colour-picker-K6zu82lm.js.map +0 -1
  228. package/dist/dist-BX0OVIm7.js +0 -1290
  229. package/dist/dist-BX0OVIm7.js.map +0 -1
  230. package/dist/dist-TAGYwaju.js.map +0 -1
  231. package/dist/hex-editor-DlfoA65y.d.ts.map +0 -1
  232. package/dist/icon-9NWTXtE1.js.map +0 -1
  233. package/dist/icon-CeTDJhC7.d.ts.map +0 -1
  234. package/dist/index--hrxPBkQ.d.ts.map +0 -1
  235. package/dist/index-CnL9krsH.d.ts.map +0 -1
  236. package/dist/index-DSlPeWLK.d.ts.map +0 -1
  237. package/dist/index-DrQjA8Gs.d.ts.map +0 -1
  238. package/dist/interaction-DG7X1rhI.js +0 -1
  239. package/dist/labelled-input-base-D-Y7agky.d.ts.map +0 -1
  240. package/dist/menu-DJJuCm-5.js.map +0 -1
  241. package/dist/menu-item-CKRfP0pN.js.map +0 -1
  242. package/dist/menu-item-ClQF2DKN.d.ts.map +0 -1
  243. package/dist/prominence--ic9uWBl.js +0 -98
  244. package/dist/prominence--ic9uWBl.js.map +0 -1
  245. package/dist/radial-input-DZA6WaFu.js.map +0 -1
  246. package/dist/radial-input-LUSBEycd.d.ts.map +0 -1
  247. package/dist/tab-list-BnqISNvO.d.ts.map +0 -1
  248. package/dist/tickled-controller-Cq1Va0rR.d.ts.map +0 -1
  249. package/dist/timeline-Cv75Th2U.js.map +0 -1
  250. package/dist/tree-CvvKbO-f.js.map +0 -1
  251. package/dist/tree-component-D8Bg48tt.d.ts.map +0 -1
  252. package/dist/types-BKaqnpwx.d.ts.map +0 -1
  253. package/dist/xy-axis-D9uwpGTT.d.ts.map +0 -1
  254. package/dist/xy-axis-DL0tfJDr.js.map +0 -1
  255. /package/bundle/{chunk-pbuEa-1d.js → chunk-D7D4PA-g.js} +0 -0
  256. /package/dist/{chunk-pbuEa-1d.js → chunk-D7D4PA-g.js} +0 -0
package/dist/index.js CHANGED
@@ -1,37 +1,38 @@
1
- import { n as buildHighlightTargets, r as clearHighlights, t as applyHighlights } from "./highlight-TPbSHruI.js";
2
- import { n as tickledStyles, r as TickledController } from "./tickled-styles-Bg3QbcrD.js";
3
- import { n as safeCustomElement, t as __decorate } from "./decorate-D7rC1gLP.js";
4
- import { a as svgToDataUri, i as registerIcon, n as hasIcon, r as iconBus, t as getIcon } from "./registry-Q2gYQCHM.js";
5
- import { t as IxfxIconElement } from "./icon-9NWTXtE1.js";
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-fNDdqf6l.js";
3
+ import { t as themeFallbacks } from "./fallbacks-pNMOMx38.js";
4
+ import { n as safeCustomElement, t as __decorate } from "./decorate-DdjvVHS-.js";
5
+ import { a as svgToDataUri, i as registerIcon, n as hasIcon, r as iconBus, t as getIcon } from "./registry-CkW7q09Q.js";
6
+ import { t as IxfxIconElement } from "./icon-Ndo40kNO.js";
6
7
  import { AcTextElement } from "./ac-text.js";
7
- import { a as createFuzzySearch, i as createAcCompletionProvider, n as IncrSearchTreeController, r as createIncrSearch, t as createElementIncrSearch } from "./incr-search-DSKKsk6w.js";
8
- import { i as ICON_CLOSE, n as ICON_CHECK, r as ICON_CHEVRON_DOWN, t as ICON_CARET_RIGHT } from "./defaults-C7elhuyJ.js";
8
+ import { a as createFuzzySearch, i as createAcCompletionProvider, n as IncrSearchTreeController, r as createIncrSearch, t as createElementIncrSearch } from "./incr-search-CeERfijK.js";
9
+ import { i as ICON_CLOSE, n as ICON_CHECK, r as ICON_CHEVRON_DOWN, t as ICON_CARET_RIGHT } from "./defaults-C3b9OWJD.js";
9
10
  import "./icons.js";
10
- import { t as prominenceStyles } from "./prominence--ic9uWBl.js";
11
- import { n as buttonStyles, t as ButtonElement } from "./button-DMt5XWUK.js";
12
- import { t as popupSurfaceStyles } from "./popup-ImtS9KnS.js";
13
- import "./menu-item-CKRfP0pN.js";
11
+ import { t as prominenceStyles } from "./prominence-DlFShic3.js";
12
+ import { n as buttonStyles, t as ButtonElement } from "./button-C3fLMKUv.js";
13
+ import { t as popupSurfaceStyles } from "./popup-DiWMxsWj.js";
14
+ import "./menu-item-BrIuORYD.js";
14
15
  import { Checkbox } from "./checkbox.js";
15
- import { C as resultThrow, E as throwIfFailed, d as scaler, h as without, n as clamper, p as containsDuplicateInstances, y as nullUndefTest } from "./dist-TAGYwaju.js";
16
- import { a as computeColour, c as last, i as applyAgeModification, l as QueueMutable, n as PlotSingleAxis, o as parseColourScaleAttr, r as PlotDataSeries, s as readBaseColour, t as PlotXyAxis, u as __exportAll } from "./xy-axis-DL0tfJDr.js";
17
- import { a as toStringAbbreviate, c as isEqualDefault, l as isEqualValueDefault, o as defaultComparer, r as isPrimitive, u as isEqualValueIgnoreOrder } from "./dist-BX0OVIm7.js";
18
- import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-K6zu82lm.js";
16
+ import { _ as isEqualValueDefault, a as PlotDataSeries, c as parseColourScaleAttr, d as QueueMutable, f as isPrimitive, g as isEqualDefault, h as defaultComparer, i as PlotMultiAxis, l as readBaseColour, m as __exportAll, n as PlotSingleAxis, o as applyAgeModification, p as toStringAbbreviate, r as PlotHistogram, s as computeColour, t as PlotXyAxis, u as last, v as isEqualValueIgnoreOrder } from "./xy-axis-CK64haaK.js";
17
+ import { C as resultThrow, T as throwIfFailed, d as scaler, h as without, n as clamper, p as containsDuplicateInstances, y as nullUndefTest } from "./dist-CA13FvMn.js";
18
+ import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-0sgAha1T.js";
19
19
  import { LabelledRangeInput } from "./labelled-range-input.js";
20
- import { i as TreeDataModel, n as TreeController, r as TreeBaseElement, t as TreeListElement } from "./tree-CvvKbO-f.js";
20
+ import { t as collectDataResult } from "./data-provider-DgI909FP.js";
21
+ import { i as TreeDataModel, n as TreeListElement, r as TreeBaseElement, t as TreeController } from "./tree-CJWpMUvD.js";
21
22
  import { NarrowedTextElement } from "./narrowed-text.js";
22
23
  import { CrumbNavigationElement } from "./crumbs.js";
23
24
  import { DataDisplayComponent } from "./data-display.js";
24
25
  import { EditableLabel } from "./editable-label.js";
25
- import { t as resolveStep } from "./keyboard-De_vOHLg.js";
26
- import { t as IxfxHexEditorElement } from "./hex-editor-CsN_ySkH.js";
27
- import { t as RadialInputElement } from "./radial-input-DZA6WaFu.js";
26
+ import { t as resolveStep } from "./keyboard-CimiEskD.js";
27
+ import { PanelElement } from "./panel.js";
28
+ import { t as IxfxHexEditorElement } from "./hex-editor-WZrjRtvL.js";
29
+ import { t as RadialInputElement } from "./radial-input-DZ7eQCcM.js";
28
30
  import { LabelledRadialInput } from "./labelled-radial-input.js";
29
31
  import { LedElement } from "./led.js";
30
- import { t as menu_exports } from "./menu-DJJuCm-5.js";
32
+ import { t as menu_exports } from "./menu-vjoiHZ13.js";
31
33
  import { MillerBaseElement, MillerListElement, MillerTreeController } from "./miller.js";
32
- import { PanelElement } from "./panel.js";
33
34
  import { PolarPad } from "./polar-pad.js";
34
- import { t as tooltipValueStyles } from "./tooltip-DMxmBNky.js";
35
+ import { t as tooltipValueStyles } from "./tooltip-CJt3WLmN.js";
35
36
  import { RangeInput } from "./range-input.js";
36
37
  import { RangeElement } from "./range.js";
37
38
  import { SelectHorizontalElement } from "./selecthorizontal.js";
@@ -39,13 +40,182 @@ import { SnapContainer } from "./snap-container.js";
39
40
  import { SplitLayoutElement } from "./split-layout.js";
40
41
  import { SwipeElement } from "./swipe.js";
41
42
  import { TabListElement } from "./tabs.js";
42
- import { a as resolveCssVars, i as attachTimelineInteractions, n as TimelineTrackTabElement, o as resolveGrid, r as timelineStyles, s as TimelineController, t as IxfxTimelineElement } from "./timeline-Cv75Th2U.js";
43
+ import { a as resolveCssVars, i as attachTimelineInteractions, n as TimelineTrackTabElement, o as resolveGrid, r as timelineStyles, s as TimelineController, t as IxfxTimelineElement } from "./timeline-2OFtN4Ta.js";
43
44
  import { XyPad } from "./xy-pad.js";
44
45
  import { LitElement, css, html, nothing } from "lit";
45
46
  import { eventOptions, property, query, queryAssignedElements, state } from "lit/decorators.js";
46
47
  import { unsafeHTML } from "lit/directives/unsafe-html.js";
47
- import { keyed } from "lit/directives/keyed.js";
48
+ import { repeat } from "lit/directives/repeat.js";
48
49
  import { classMap } from "lit/directives/class-map.js";
50
+ import { keyed } from "lit/directives/keyed.js";
51
+ //#region src/common/data-controller.ts
52
+ function isAsyncIterable(v) {
53
+ return typeof v === `object` && v !== null && Symbol.asyncIterator in v;
54
+ }
55
+ /**
56
+ * Lit ReactiveController that manages one active data provider request at a time.
57
+ *
58
+ * Handles all three provider return modes (sync, async one-shot, streaming),
59
+ * tracks progress, and cancels in-flight requests when a new one starts.
60
+ * Calls host.requestUpdate() on every state change so the component re-renders
61
+ * automatically.
62
+ *
63
+ * @typeParam TQuery - The query/scope type passed to the provider.
64
+ * @typeParam TItem - The item type produced by the provider.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * class MyList extends LitElement {
69
+ * #data = new DataController<string, MyItem>(this, myProvider);
70
+ *
71
+ * protected override render() {
72
+ * return html`
73
+ * ${this.#data.loading ? html`<span>Loading…</span>` : nothing}
74
+ * ${this.#data.items.map(item => html`<div>${item.label}</div>`)}
75
+ * `;
76
+ * }
77
+ * }
78
+ * ```
79
+ */
80
+ var DataController = class {
81
+ #host;
82
+ #opts;
83
+ #provider;
84
+ #abort;
85
+ #items = [];
86
+ #loading = false;
87
+ #loaded = 0;
88
+ #total;
89
+ #error;
90
+ constructor(host, provider, options) {
91
+ this.#host = host;
92
+ this.#provider = provider;
93
+ this.#opts = {
94
+ clearOnRequest: options?.clearOnRequest ?? true,
95
+ onError: options?.onError
96
+ };
97
+ host.addController(this);
98
+ }
99
+ hostConnected() {}
100
+ hostDisconnected() {
101
+ this.cancel();
102
+ }
103
+ get provider() {
104
+ return this.#provider;
105
+ }
106
+ set provider(value) {
107
+ this.#provider = value;
108
+ }
109
+ /** The currently accumulated items. */
110
+ get items() {
111
+ return this.#items;
112
+ }
113
+ /** True while a provider call is pending or a stream is still open. */
114
+ get loading() {
115
+ return this.#loading;
116
+ }
117
+ /** Number of items accumulated so far in the current request. */
118
+ get loaded() {
119
+ return this.#loaded;
120
+ }
121
+ /**
122
+ * Provider's latest estimate of the total number of items expected.
123
+ * Undefined when the provider has not reported a total.
124
+ */
125
+ get total() {
126
+ return this.#total;
127
+ }
128
+ /**
129
+ * Progress as a 0–1 value, or undefined when total is unknown.
130
+ * Derived from loaded / total.
131
+ */
132
+ get progress() {
133
+ if (this.#total === void 0 || this.#total === 0) return void 0;
134
+ return Math.min(this.#loaded / this.#total, 1);
135
+ }
136
+ /** The last error thrown by the provider, or undefined if the last request succeeded. */
137
+ get error() {
138
+ return this.#error;
139
+ }
140
+ /**
141
+ * Cancel any in-flight request and start a new one.
142
+ * Clears items immediately unless clearOnRequest was set to false.
143
+ */
144
+ request(query) {
145
+ this.cancel();
146
+ if (!this.#provider) return;
147
+ if (this.#opts.clearOnRequest) {
148
+ this.#items = [];
149
+ this.#loaded = 0;
150
+ }
151
+ this.#total = void 0;
152
+ this.#error = void 0;
153
+ this.#loading = true;
154
+ this.#host.requestUpdate();
155
+ this.#abort = new AbortController();
156
+ const { signal } = this.#abort;
157
+ this.#consume(this.#provider(query, signal), signal);
158
+ }
159
+ /** Abort any in-flight request without issuing a new one. */
160
+ cancel() {
161
+ this.#abort?.abort();
162
+ this.#abort = void 0;
163
+ if (this.#loading) {
164
+ this.#loading = false;
165
+ this.#host.requestUpdate();
166
+ }
167
+ }
168
+ #consume(result, signal) {
169
+ if (Array.isArray(result)) {
170
+ this.#applyBatch({ items: result }, signal);
171
+ this.#loading = false;
172
+ this.#host.requestUpdate();
173
+ } else if (isAsyncIterable(result)) this.#consumeStream(result, signal);
174
+ else result.then((items) => {
175
+ if (signal.aborted) return;
176
+ this.#applyBatch({ items }, signal);
177
+ this.#loading = false;
178
+ this.#host.requestUpdate();
179
+ }, (err) => {
180
+ if (signal.aborted) return;
181
+ this.#handleError(err);
182
+ });
183
+ }
184
+ async #consumeStream(stream, signal) {
185
+ try {
186
+ for await (const batch of stream) {
187
+ if (signal.aborted) return;
188
+ this.#applyBatch(batch, signal);
189
+ this.#host.requestUpdate();
190
+ }
191
+ } catch (err) {
192
+ if (signal.aborted) return;
193
+ this.#handleError(err);
194
+ return;
195
+ }
196
+ if (!signal.aborted) {
197
+ this.#loading = false;
198
+ this.#host.requestUpdate();
199
+ }
200
+ }
201
+ #applyBatch(batch, _signal) {
202
+ if (batch.replace) {
203
+ this.#items = [...batch.items];
204
+ this.#loaded = batch.items.length;
205
+ } else {
206
+ this.#items = [...this.#items, ...batch.items];
207
+ this.#loaded = this.#items.length;
208
+ }
209
+ if (batch.total !== void 0) this.#total = batch.total;
210
+ }
211
+ #handleError(err) {
212
+ this.#error = err;
213
+ this.#loading = false;
214
+ this.#opts.onError?.(err);
215
+ this.#host.requestUpdate();
216
+ }
217
+ };
218
+ //#endregion
49
219
  //#region src/ac-token/ac-token.ts
50
220
  const DEFAULT_TOKENIZER = (text) => text.split(/[\s,;]+/);
51
221
  function makeLruCache(maxSize) {
@@ -62,26 +232,31 @@ function makeLruCache(maxSize) {
62
232
  };
63
233
  }
64
234
  let AcTokenElement = class AcTokenElement extends LitElement {
235
+ #data;
65
236
  #cache;
66
237
  #debounceTimer;
67
- #abortController;
68
238
  #staticProvider;
239
+ #lastSuggestions;
69
240
  constructor() {
70
241
  super();
71
242
  this.placeholder = ``;
72
243
  this.cacheSize = 20;
73
244
  this.debounceMs = 150;
74
245
  this.strict = false;
246
+ this.allowDuplicates = false;
75
247
  this._tokens = [];
76
248
  this._draft = ``;
77
- this._suggestions = [];
78
249
  this._isOpen = false;
79
- this._isLoading = false;
80
- this._tickled = new TickledController(this, { getItems: () => this._suggestions.map((_, i) => ({
250
+ this._tickled = new TickledController(this, { getItems: () => this.#data.items.map((_, i) => ({
81
251
  id: i,
82
252
  enabled: true
83
253
  })) });
254
+ this.#data = new DataController(this, void 0, {
255
+ clearOnRequest: true,
256
+ onError: (err) => console.error(`[ixfx-ac-token] completionProvider error:`, err)
257
+ });
84
258
  this.#cache = makeLruCache(20);
259
+ this.#lastSuggestions = [];
85
260
  this.#onWrapperClick = (e) => {
86
261
  if (!e.target.closest(`.token-chip`)) this.shadowRoot?.querySelector(`input.draft`)?.focus();
87
262
  };
@@ -196,11 +371,18 @@ let AcTokenElement = class AcTokenElement extends LitElement {
196
371
  }
197
372
  disconnectedCallback() {
198
373
  super.disconnectedCallback();
199
- this.#cancelPending();
374
+ if (this.#debounceTimer !== void 0) {
375
+ clearTimeout(this.#debounceTimer);
376
+ this.#debounceTimer = void 0;
377
+ }
200
378
  }
201
379
  updated(changedProps) {
202
380
  if (changedProps.has(`completionProvider`) || changedProps.has(`cacheSize`)) this.#cache = makeLruCache(this.cacheSize);
203
381
  if (changedProps.has(`completionProvider`)) this.#buildStaticProvider();
382
+ if (this.#data.items !== this.#lastSuggestions) {
383
+ this.#lastSuggestions = this.#data.items;
384
+ this._tickled.clearTickled();
385
+ }
204
386
  }
205
387
  #buildStaticProvider() {
206
388
  const raw = this.getAttribute(`data-tokens`);
@@ -242,9 +424,9 @@ let AcTokenElement = class AcTokenElement extends LitElement {
242
424
  break;
243
425
  case `Enter`: {
244
426
  const tickledIdx = this._tickled.tickledId;
245
- if (this._isOpen && tickledIdx !== void 0 && this._suggestions[tickledIdx]) {
427
+ if (this._isOpen && tickledIdx !== void 0 && this.#data.items[tickledIdx]) {
246
428
  e.preventDefault();
247
- this.#selectSuggestion(this._suggestions[tickledIdx]);
429
+ this.#selectSuggestion(this.#data.items[tickledIdx]);
248
430
  } else if (!this.strict && this._draft.trim()) {
249
431
  e.preventDefault();
250
432
  this.#addToken({ label: this._draft.trim() });
@@ -334,6 +516,11 @@ let AcTokenElement = class AcTokenElement extends LitElement {
334
516
  composed: true
335
517
  }));
336
518
  }
519
+ #filterUsed(items) {
520
+ if (this.allowDuplicates) return items;
521
+ const used = new Set(this._tokens.map((t) => t.label));
522
+ return items.filter((item) => !used.has(item.label));
523
+ }
337
524
  #closePopup() {
338
525
  this._isOpen = false;
339
526
  this._tickled.clearTickled();
@@ -343,50 +530,42 @@ let AcTokenElement = class AcTokenElement extends LitElement {
343
530
  clearTimeout(this.#debounceTimer);
344
531
  this.#debounceTimer = void 0;
345
532
  }
346
- this.#abortController?.abort();
347
- this.#abortController = void 0;
348
- this._isLoading = false;
533
+ this.#data.cancel();
349
534
  }
350
535
  #scheduleSuggestionFetch(query) {
351
- const provider = this.completionProvider ?? this.#staticProvider;
352
- if (!provider) {
536
+ const cachedProvider = this.#buildCachedProvider();
537
+ if (!cachedProvider) {
353
538
  this._isOpen = false;
354
539
  return;
355
540
  }
356
541
  if (this.#debounceTimer !== void 0) clearTimeout(this.#debounceTimer);
357
542
  this._isOpen = true;
358
543
  this.#debounceTimer = setTimeout(() => {
359
- this.#fetchSuggestions(query, provider);
544
+ this.#data.provider = cachedProvider;
545
+ this.#data.request(query);
360
546
  }, this.debounceMs);
361
547
  }
362
- #fetchSuggestions(query, provider) {
363
- const cached = this.#cache.get(query);
364
- if (cached !== void 0) {
365
- this._suggestions = cached;
366
- this._tickled.clearTickled();
367
- this._isLoading = false;
368
- return;
369
- }
370
- this.#abortController?.abort();
371
- this.#abortController = new AbortController();
372
- const { signal } = this.#abortController;
373
- this._isLoading = true;
374
- Promise.resolve(provider(query, signal)).then((results) => {
375
- if (signal.aborted) return;
376
- this.#cache.set(query, results);
377
- this._suggestions = results;
378
- this._tickled.clearTickled();
379
- this._isLoading = false;
380
- }).catch((err) => {
381
- if (signal.aborted) return;
382
- console.error(`[ixfx-ac-token] completionProvider error:`, err);
383
- this._suggestions = [];
384
- this._isLoading = false;
385
- });
548
+ #buildCachedProvider() {
549
+ const raw = this.completionProvider ?? this.#staticProvider;
550
+ if (!raw) return void 0;
551
+ return (query, signal) => {
552
+ const hit = this.#cache.get(query);
553
+ if (hit !== void 0) return this.#filterUsed(hit);
554
+ const result = raw(query, signal);
555
+ if (Symbol.asyncIterator in Object(result)) return result;
556
+ if (Array.isArray(result)) {
557
+ this.#cache.set(query, result);
558
+ return this.#filterUsed(result);
559
+ }
560
+ return result.then((items) => {
561
+ if (!signal.aborted) this.#cache.set(query, items);
562
+ return this.#filterUsed(items);
563
+ });
564
+ };
386
565
  }
387
566
  #scrollSuggestionIntoView() {
388
567
  this.updateComplete.then(() => {
389
- this.shadowRoot?.querySelector(`.suggestion.tickled`)?.scrollIntoView({ block: `nearest` });
568
+ this.shadowRoot?.querySelector(`.item.tickled`)?.scrollIntoView({ block: `nearest` });
390
569
  });
391
570
  }
392
571
  #renderChip(item, index) {
@@ -405,7 +584,7 @@ let AcTokenElement = class AcTokenElement extends LitElement {
405
584
  const isTickled = this._tickled.isTickled(index);
406
585
  return html`
407
586
  <div
408
- class="suggestion ${isTickled ? `tickled` : ``}"
587
+ class="item ${isTickled ? `tickled` : ``}"
409
588
  role="option"
410
589
  id="ac-token-sugg-${index}"
411
590
  aria-selected=${isTickled}
@@ -419,7 +598,7 @@ let AcTokenElement = class AcTokenElement extends LitElement {
419
598
  `;
420
599
  }
421
600
  #renderPopup() {
422
- const showEmpty = !this._isLoading && this._suggestions.length === 0;
601
+ const showEmpty = !this.#data.loading && this.#data.items.length === 0;
423
602
  return html`
424
603
  <div
425
604
  class="popup"
@@ -428,7 +607,7 @@ let AcTokenElement = class AcTokenElement extends LitElement {
428
607
  data-input-mode=${this._tickled.inputMode}
429
608
  @pointerleave=${(e) => this._tickled.handlePointerLeave(e)}
430
609
  >
431
- ${showEmpty ? html`<div class="no-results">No matching results</div>` : this._suggestions.map((item, i) => this.#renderSuggestion(item, i))}
610
+ ${showEmpty ? html`<div class="no-results">No matching results</div>` : this.#data.items.map((item, i) => this.#renderSuggestion(item, i))}
432
611
  </div>
433
612
  `;
434
613
  }
@@ -456,13 +635,17 @@ let AcTokenElement = class AcTokenElement extends LitElement {
456
635
  @blur=${this.#onBlur}
457
636
  @paste=${this.#onPaste}
458
637
  >
459
- ${this._isLoading ? html`<span class="spinner" aria-hidden="true"></span>` : nothing}
638
+ ${this.#data.loading ? html`<span class="spinner" aria-hidden="true"></span>` : nothing}
460
639
  </div>
461
640
  ${this._isOpen ? this.#renderPopup() : nothing}
462
641
  `;
463
642
  }
464
643
  static {
465
- this.styles = [tickledStyles, css`
644
+ this.styles = [
645
+ themeFallbacks,
646
+ tickledStyles,
647
+ tickledItemStyles,
648
+ css`
466
649
  :host {
467
650
  display: block;
468
651
  position: relative;
@@ -594,27 +777,16 @@ let AcTokenElement = class AcTokenElement extends LitElement {
594
777
 
595
778
  /* ---- Suggestion items ---- */
596
779
 
597
- .suggestion {
780
+ .item {
781
+ /* tickledItemStyles provides base; override layout for popup context */
598
782
  display: flex;
599
- align-items: center;
783
+ padding: var(--item-padding, var(--space-xs, 3px) var(--space-l, 12px));
600
784
  gap: var(--space-m, 8px);
601
- padding: var(--space-xs, 3px) var(--space-l, 12px);
602
785
  cursor: pointer;
603
- border-radius: var(--radius-s, 3px);
604
786
  margin: 0 var(--space-xs, 3px);
605
- transition: background var(--transition, 0.1s ease-out);
606
- user-select: none;
607
787
  white-space: nowrap;
608
788
  min-height: 28px;
609
- }
610
-
611
- .suggestion.tickled {
612
- background: var(--_item-focused-bg, var(--accent));
613
- color: var(--accent-text, #fff);
614
- }
615
-
616
- .suggestion.tickled .sugg-sublabel {
617
- color: color-mix(in srgb, var(--accent-text, #fff) 70%, transparent);
789
+ user-select: none;
618
790
  }
619
791
 
620
792
  .sugg-icon {
@@ -643,7 +815,8 @@ let AcTokenElement = class AcTokenElement extends LitElement {
643
815
  color: var(--surface-muted-text);
644
816
  font-style: italic;
645
817
  }
646
- `];
818
+ `
819
+ ];
647
820
  }
648
821
  };
649
822
  __decorate([property({ type: Object })], AcTokenElement.prototype, "completionProvider", void 0);
@@ -658,12 +831,14 @@ __decorate([property({
658
831
  attribute: `debounce-ms`
659
832
  })], AcTokenElement.prototype, "debounceMs", void 0);
660
833
  __decorate([property({ type: Boolean })], AcTokenElement.prototype, "strict", void 0);
834
+ __decorate([property({
835
+ type: Boolean,
836
+ attribute: `allow-duplicates`
837
+ })], AcTokenElement.prototype, "allowDuplicates", void 0);
661
838
  __decorate([state()], AcTokenElement.prototype, "_tokens", void 0);
662
839
  __decorate([state()], AcTokenElement.prototype, "_draft", void 0);
663
840
  __decorate([state()], AcTokenElement.prototype, "_selectedTokenIndex", void 0);
664
- __decorate([state()], AcTokenElement.prototype, "_suggestions", void 0);
665
841
  __decorate([state()], AcTokenElement.prototype, "_isOpen", void 0);
666
- __decorate([state()], AcTokenElement.prototype, "_isLoading", void 0);
667
842
  AcTokenElement = __decorate([safeCustomElement(`ixfx-ac-token`)], AcTokenElement);
668
843
  //#endregion
669
844
  //#region src/button/radio-group.ts
@@ -815,7 +990,10 @@ let RadioGroup = class RadioGroup extends LitElement {
815
990
  `;
816
991
  }
817
992
  static {
818
- this.styles = [prominenceStyles, css`
993
+ this.styles = [
994
+ themeFallbacks,
995
+ prominenceStyles,
996
+ css`
819
997
  :host {
820
998
  display: inline-flex;
821
999
  min-width: min-content;
@@ -964,7 +1142,8 @@ let RadioGroup = class RadioGroup extends LitElement {
964
1142
  .radio-group.compact.horizontal .radio-item {
965
1143
  padding: var(--compact-padding, 0.5rem);
966
1144
  }
967
- `];
1145
+ `
1146
+ ];
968
1147
  }
969
1148
  };
970
1149
  __decorate([property({ type: String })], RadioGroup.prototype, "value", void 0);
@@ -1244,6 +1423,7 @@ let SplitButton = class SplitButton extends ButtonElement {
1244
1423
  }
1245
1424
  static {
1246
1425
  this.styles = [
1426
+ themeFallbacks,
1247
1427
  prominenceStyles,
1248
1428
  buttonStyles,
1249
1429
  css`
@@ -1383,7 +1563,7 @@ __decorate([state()], SplitButton.prototype, "_loadingItems", void 0);
1383
1563
  __decorate([state()], SplitButton.prototype, "_menuHasItems", void 0);
1384
1564
  SplitButton = __decorate([safeCustomElement(`ixfx-split-button`)], SplitButton);
1385
1565
  //#endregion
1386
- //#region node_modules/.pnpm/@ixfx+collections@0.56.12/node_modules/@ixfx/collections/dist/StackMutable-B9Qm32K8.js
1566
+ //#region node_modules/.pnpm/@ixfx+collections@0.56.13/node_modules/@ixfx/collections/dist/StackMutable-B9Qm32K8.js
1387
1567
  const trimStack = (opts, stack, toAdd) => {
1388
1568
  const potentialLength = stack.length + toAdd.length;
1389
1569
  const policy = opts.discardPolicy ?? `additions`;
@@ -1519,7 +1699,7 @@ var StackMutable = class {
1519
1699
  }
1520
1700
  };
1521
1701
  //#endregion
1522
- //#region node_modules/.pnpm/@ixfx+collections@0.56.12/node_modules/@ixfx/collections/dist/tree-C6jGRTgK.js
1702
+ //#region node_modules/.pnpm/@ixfx+collections@0.56.13/node_modules/@ixfx/collections/dist/tree-C6jGRTgK.js
1523
1703
  const compare$1 = (a, b, eq = isEqualValueIgnoreOrder, parent) => {
1524
1704
  const valueEqual = valueOrIdentityEqual(a, b, eq);
1525
1705
  const childrenCompare = compareChildren(a, b, eq);
@@ -4605,12 +4785,18 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
4605
4785
  `;
4606
4786
  }
4607
4787
  static {
4608
- this.styles = [popupSurfaceStyles, css`
4788
+ this.styles = [
4789
+ prominenceStyles,
4790
+ themeFallbacks,
4791
+ popupSurfaceStyles,
4792
+ css`
4609
4793
  :host {
4610
4794
  --text-highlight: var(--accent);
4611
4795
  --separator: var(--surface-muted-text);
4612
4796
  --padding-s: var(--space-xs);
4613
4797
  --padding-m: var(--space-s);
4798
+ --hover-bg: var(--surface-5);
4799
+ --hover-fg: var(--surface-5-text);
4614
4800
 
4615
4801
  display: flex;
4616
4802
  width: 100%;
@@ -4658,11 +4844,11 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
4658
4844
  }
4659
4845
 
4660
4846
  .seg-root {
4661
- opacity: 0.8;
4847
+ opacity: var(--prominence-idle-opacity);
4662
4848
  }
4663
4849
 
4664
4850
  .seg-root:hover {
4665
- opacity: 1;
4851
+ opacity: var(--prominence-tickled-opacity);
4666
4852
  }
4667
4853
 
4668
4854
  .seg-root label {
@@ -4702,7 +4888,7 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
4702
4888
  }
4703
4889
 
4704
4890
  .caret.disabled {
4705
- opacity: 0.4;
4891
+ opacity: var(--prominence-disabled-opacity);
4706
4892
  cursor: not-allowed;
4707
4893
  }
4708
4894
 
@@ -4776,7 +4962,8 @@ let CrumbPathElement = class CrumbPathElement extends LitElement {
4776
4962
  @keyframes crumb-spin {
4777
4963
  to { transform: rotate(360deg); }
4778
4964
  }
4779
- `];
4965
+ `
4966
+ ];
4780
4967
  }
4781
4968
  };
4782
4969
  __decorate([property({ type: String })], CrumbPathElement.prototype, "path", void 0);
@@ -5196,6 +5383,7 @@ let EditableNumber = class EditableNumber extends EditableLabel {
5196
5383
  }
5197
5384
  static {
5198
5385
  this.styles = [
5386
+ themeFallbacks,
5199
5387
  prominenceStyles,
5200
5388
  ...EditableLabel.styles,
5201
5389
  css`
@@ -5375,1843 +5563,2318 @@ __decorate([property({
5375
5563
  __decorate([property({ type: Number })], EditableNumber.prototype, "precision", void 0);
5376
5564
  EditableNumber = __decorate([safeCustomElement(`ixfx-editable-number`)], EditableNumber);
5377
5565
  //#endregion
5378
- //#region src/panel/panel-group.ts
5379
- let PanelGroupElement = class PanelGroupElement extends LitElement {
5566
+ //#region src/grouped-item-lister/grouped-item-lister.ts
5567
+ const UNGROUPED_KEY = `__ungrouped__`;
5568
+ let GroupedItemListerElement = class GroupedItemListerElement extends LitElement {
5380
5569
  constructor(..._args) {
5381
5570
  super(..._args);
5382
- this.orientation = `horizontal`;
5383
- this.variant = `titlebar`;
5384
- this.toggleInteraction = `implicit`;
5385
- this.allowMultiple = false;
5386
- this.gap = `var(--space-m)`;
5571
+ this.grouped = false;
5572
+ this.crossGroupSelection = false;
5573
+ this.#subComponents = /* @__PURE__ */ new Map();
5574
+ this.#clearingSelection = false;
5575
+ this.#data = new DataController(this);
5576
+ this.#onSelect = (event) => {
5577
+ if (this.#clearingSelection) return;
5578
+ const sourceEl = event.target;
5579
+ let sourceKey;
5580
+ for (const [key, subEl] of this.#subComponents) if (subEl === sourceEl) {
5581
+ sourceKey = key;
5582
+ break;
5583
+ }
5584
+ if (sourceKey === void 0) return;
5585
+ if (this.grouped && !this.crossGroupSelection) {
5586
+ this.#clearingSelection = true;
5587
+ for (const [key, subEl] of this.#subComponents) if (key !== sourceKey) subEl.clearSelection();
5588
+ this.#clearingSelection = false;
5589
+ }
5590
+ this.dispatchEvent(new CustomEvent(`grouped-select`, {
5591
+ detail: {
5592
+ selected: this.selectedItems,
5593
+ groupKey: sourceKey === UNGROUPED_KEY ? void 0 : sourceKey
5594
+ },
5595
+ bubbles: true,
5596
+ composed: true
5597
+ }));
5598
+ };
5387
5599
  }
5388
- _onPanelToggle(e) {
5389
- const panel = e.target;
5390
- if (panel.collapsed) return;
5391
- if (this.allowMultiple) return;
5392
- for (const p of this._panels) if (p !== panel) p.collapsed = true;
5600
+ #groupBy;
5601
+ #factory;
5602
+ #subComponents;
5603
+ #renderedGroups;
5604
+ #clearingSelection;
5605
+ #data;
5606
+ get groupBy() {
5607
+ return this.#groupBy;
5608
+ }
5609
+ set groupBy(value) {
5610
+ this.#groupBy = value;
5611
+ this.requestUpdate();
5393
5612
  }
5394
- firstUpdated() {
5395
- this.updateComplete.then(() => {
5396
- this._propagateAll();
5397
- });
5613
+ get factory() {
5614
+ return this.#factory;
5615
+ }
5616
+ set factory(value) {
5617
+ if (value === this.#factory) return;
5618
+ this.#clearSubComponents();
5619
+ this.#factory = value;
5620
+ this.requestUpdate();
5621
+ }
5622
+ get provider() {
5623
+ return this.#data.provider;
5624
+ }
5625
+ set provider(value) {
5626
+ this.#data.provider = value;
5627
+ if (value) this.#data.request(void 0);
5628
+ }
5629
+ /** The union of all selected items across every sub-component. */
5630
+ get selectedItems() {
5631
+ const all = /* @__PURE__ */ new Set();
5632
+ for (const subEl of this.#subComponents.values()) for (const item of subEl.selectedItems) all.add(item);
5633
+ return all;
5634
+ }
5635
+ /**
5636
+ * Forward a command to all live sub-components.
5637
+ * Use this to propagate changes like sort order, filter state, or view mode.
5638
+ */
5639
+ dispatch(commandId, args) {
5640
+ for (const subEl of this.#subComponents.values()) subEl.dispatch(commandId, args);
5641
+ }
5642
+ createRenderRoot() {
5643
+ return this;
5644
+ }
5645
+ connectedCallback() {
5646
+ super.connectedCallback();
5647
+ this.addEventListener(`select`, this.#onSelect);
5648
+ }
5649
+ disconnectedCallback() {
5650
+ super.disconnectedCallback();
5651
+ this.removeEventListener(`select`, this.#onSelect);
5398
5652
  }
5399
5653
  updated(changed) {
5400
5654
  super.updated(changed);
5401
- if (changed.has(`variant`) || changed.has(`toggleInteraction`) || changed.has(`orientation`)) this.updateComplete.then(() => {
5402
- this._propagateAll();
5403
- });
5655
+ if (changed.has(`grouped`)) this.#clearSubComponents();
5656
+ this.#syncSubComponents();
5404
5657
  }
5405
- _propagateAll() {
5406
- const invertedOrientation = this.orientation === `horizontal` ? `vertical` : `horizontal`;
5407
- for (const panel of this._panels) {
5408
- panel.setAttribute(`variant`, this.variant);
5409
- panel.setAttribute(`toggle-interaction`, this.toggleInteraction);
5410
- panel.setAttribute(`orientation`, invertedOrientation);
5658
+ render() {
5659
+ if (!this.#factory) return nothing;
5660
+ if (!this.grouped) return html`<div class="ungrouped-host"></div>`;
5661
+ if (!this.#groupBy) return nothing;
5662
+ this.#renderedGroups = this.#computeGroups();
5663
+ return html`${repeat(this.#renderedGroups.keys(), (key) => key, (key) => html`<ixfx-panel data-group-key=${key} .title=${key}></ixfx-panel>`)}`;
5664
+ }
5665
+ #computeGroups() {
5666
+ const groups = /* @__PURE__ */ new Map();
5667
+ if (!this.#groupBy) return groups;
5668
+ for (const item of this.#data.items) {
5669
+ const key = this.#groupBy(item);
5670
+ let bucket = groups.get(key);
5671
+ if (!bucket) {
5672
+ bucket = [];
5673
+ groups.set(key, bucket);
5674
+ }
5675
+ bucket.push(item);
5411
5676
  }
5677
+ return groups;
5412
5678
  }
5413
- render() {
5414
- return html`
5415
- <slot
5416
- @toggle=${this._onPanelToggle}
5417
- ></slot>
5418
- `;
5679
+ #clearSubComponents() {
5680
+ for (const subEl of this.#subComponents.values()) subEl.remove();
5681
+ this.#subComponents.clear();
5419
5682
  }
5420
- static {
5421
- this.styles = css`
5422
- :host {
5423
- display: flex;
5424
- flex-direction: column;
5425
- gap: var(--group-gap, var(--space-m));
5426
- }
5427
-
5428
- :host([orientation="horizontal"]) {
5429
- flex-direction: row;
5430
- align-items: flex-start;
5431
- flex-wrap: wrap;
5432
- }
5433
-
5434
- :host([orientation="vertical"]) {
5435
- flex-direction: column;
5436
- }
5437
-
5438
- ::slotted(ixfx-panel) {
5439
- flex-shrink: 1;
5440
- }
5441
-
5442
- :host([orientation="horizontal"]) ::slotted(ixfx-panel) {
5443
- flex-basis: content;
5444
- min-width: 0;
5445
- }
5446
- `;
5683
+ #syncSubComponents() {
5684
+ if (!this.#factory) return;
5685
+ if (!this.grouped) {
5686
+ this.#syncUngrouped();
5687
+ return;
5688
+ }
5689
+ if (!this.#groupBy) return;
5690
+ this.#syncGrouped();
5691
+ }
5692
+ #syncUngrouped() {
5693
+ const host = this.querySelector(`.ungrouped-host`);
5694
+ if (!host) return;
5695
+ let subEl = this.#subComponents.get(UNGROUPED_KEY);
5696
+ if (!subEl) {
5697
+ subEl = this.#factory(void 0);
5698
+ host.appendChild(subEl);
5699
+ this.#subComponents.set(UNGROUPED_KEY, subEl);
5700
+ }
5701
+ subEl.setItems(this.#data.items);
5702
+ }
5703
+ #syncGrouped() {
5704
+ const groups = this.#renderedGroups ?? this.#computeGroups();
5705
+ for (const key of [...this.#subComponents.keys()]) if (!groups.has(key)) {
5706
+ this.#subComponents.get(key)?.remove();
5707
+ this.#subComponents.delete(key);
5708
+ }
5709
+ for (const [key, items] of groups) {
5710
+ const panel = [...this.children].find((el) => el instanceof HTMLElement && el.dataset[`groupKey`] === key);
5711
+ if (!panel) continue;
5712
+ let subEl = this.#subComponents.get(key);
5713
+ if (!subEl) {
5714
+ subEl = this.#factory(key);
5715
+ panel.appendChild(subEl);
5716
+ this.#subComponents.set(key, subEl);
5717
+ }
5718
+ subEl.setItems(items);
5719
+ }
5447
5720
  }
5721
+ #onSelect;
5448
5722
  };
5449
5723
  __decorate([property({
5450
- type: String,
5724
+ type: Boolean,
5451
5725
  reflect: true
5452
- })], PanelGroupElement.prototype, "orientation", void 0);
5453
- __decorate([property({ type: String })], PanelGroupElement.prototype, "variant", void 0);
5454
- __decorate([property({
5455
- type: String,
5456
- attribute: `toggle-interaction`
5457
- })], PanelGroupElement.prototype, "toggleInteraction", void 0);
5726
+ })], GroupedItemListerElement.prototype, "grouped", void 0);
5458
5727
  __decorate([property({
5459
5728
  type: Boolean,
5460
- attribute: `allow-multiple`
5461
- })], PanelGroupElement.prototype, "allowMultiple", void 0);
5462
- __decorate([property()], PanelGroupElement.prototype, "gap", void 0);
5463
- __decorate([queryAssignedElements({ slot: `` })], PanelGroupElement.prototype, "_panels", void 0);
5464
- PanelGroupElement = __decorate([safeCustomElement(`ixfx-panel-group`)], PanelGroupElement);
5729
+ attribute: `cross-group-selection`,
5730
+ reflect: true
5731
+ })], GroupedItemListerElement.prototype, "crossGroupSelection", void 0);
5732
+ GroupedItemListerElement = __decorate([safeCustomElement(`ixfx-grouped-item-lister`)], GroupedItemListerElement);
5465
5733
  //#endregion
5466
- //#region src/util/drag.ts
5467
- function getCoordinates(event) {
5468
- return {
5469
- client: {
5470
- x: event.clientX,
5471
- y: event.clientY
5734
+ //#region src/grouped-item-lister/tree-list-adapter.ts
5735
+ /**
5736
+ * Creates an `HTMLElement` that implements `IGroupedSubComponent<T>` by wrapping
5737
+ * an `ixfx-tree-list` internally.
5738
+ *
5739
+ * `toTreeItem` converts each item `T` to display metadata (`key`, `label`, etc).
5740
+ * The adapter stores the original `T` in `TreeItem.data` and uses it to map
5741
+ * tree-node selections back to typed values.
5742
+ *
5743
+ * Unlike `createVerticalListAdapter`, items can be hierarchical: provide
5744
+ * `options.getChildren` to return each item's children and the adapter will
5745
+ * recursively build the `TreeNode` tree. Omit it for a flat list of leaf nodes.
5746
+ *
5747
+ * The four interface events (`select`, `activate`, `item-click`, `tickle`) are
5748
+ * intercepted at the tree level, re-typed from `TreeNode` → `T`, and re-dispatched
5749
+ * on the adapter element so `ixfx-grouped-item-lister` can identify the source.
5750
+ *
5751
+ * @example Flat item list:
5752
+ * ```ts
5753
+ * lister.factory = () =>
5754
+ * createTreeListAdapter<FileItem>(item => ({ key: item.id, label: item.name, isLeaf: true }));
5755
+ * ```
5756
+ *
5757
+ * @example Hierarchical items:
5758
+ * ```ts
5759
+ * lister.factory = () =>
5760
+ * createTreeListAdapter<Category>(
5761
+ * cat => ({ key: cat.id, label: cat.name }),
5762
+ * { getChildren: cat => cat.subCategories },
5763
+ * );
5764
+ * ```
5765
+ */
5766
+ function createTreeListAdapter(toTreeItem, options) {
5767
+ const container = document.createElement(`div`);
5768
+ container.style.cssText = `display:contents;`;
5769
+ let treeEl;
5770
+ function buildNode(item) {
5771
+ const treeItem = {
5772
+ ...toTreeItem(item),
5773
+ data: item
5774
+ };
5775
+ const children = options?.getChildren?.(item);
5776
+ return {
5777
+ item: treeItem,
5778
+ children: children ? children.map(buildNode) : treeItem.isLeaf ? [] : void 0
5779
+ };
5780
+ }
5781
+ function getOrCreateTree() {
5782
+ if (treeEl) return treeEl;
5783
+ treeEl = document.createElement(`ixfx-tree-list`);
5784
+ treeEl.interactionMode = options?.interactionMode ?? `standard`;
5785
+ treeEl.selectionFilter = options?.selectionFilter ?? `all`;
5786
+ treeEl.exclusivity = options?.exclusivity ?? `none`;
5787
+ treeEl.style.cssText = `display:block;width:100%;`;
5788
+ container.appendChild(treeEl);
5789
+ attachBridgeListeners();
5790
+ return treeEl;
5791
+ }
5792
+ function mapNodes(nodes) {
5793
+ const result = /* @__PURE__ */ new Set();
5794
+ for (const node of nodes) if (node.item.data !== void 0) result.add(node.item.data);
5795
+ return result;
5796
+ }
5797
+ function attachBridgeListeners() {
5798
+ treeEl.addEventListener(`select`, (e) => {
5799
+ e.stopPropagation();
5800
+ const detail = {
5801
+ selected: mapNodes(e.detail.selected),
5802
+ previous: mapNodes(e.detail.previous)
5803
+ };
5804
+ container.dispatchEvent(new CustomEvent(`select`, {
5805
+ detail,
5806
+ bubbles: true,
5807
+ composed: true
5808
+ }));
5809
+ });
5810
+ treeEl.addEventListener(`activate`, (e) => {
5811
+ e.stopPropagation();
5812
+ const item = e.detail.node.item.data;
5813
+ if (item === void 0) return;
5814
+ const detail = { item };
5815
+ container.dispatchEvent(new CustomEvent(`activate`, {
5816
+ detail,
5817
+ bubbles: true,
5818
+ composed: true
5819
+ }));
5820
+ });
5821
+ treeEl.addEventListener(`item-click`, (e) => {
5822
+ e.stopPropagation();
5823
+ const item = e.detail.node.item.data;
5824
+ if (item === void 0) return;
5825
+ const detail = { item };
5826
+ container.dispatchEvent(new CustomEvent(`item-click`, {
5827
+ detail,
5828
+ bubbles: true,
5829
+ composed: true
5830
+ }));
5831
+ });
5832
+ treeEl.addEventListener(`tickle`, (e) => {
5833
+ e.stopPropagation();
5834
+ const item = e.detail.node.item.data;
5835
+ if (item === void 0) return;
5836
+ const detail = { item };
5837
+ container.dispatchEvent(new CustomEvent(`tickle`, {
5838
+ detail,
5839
+ bubbles: true,
5840
+ composed: true
5841
+ }));
5842
+ });
5843
+ }
5844
+ let selectionMode = `single`;
5845
+ const adapter = Object.assign(container, {
5846
+ setItems(items) {
5847
+ const tree = getOrCreateTree();
5848
+ tree.root = {
5849
+ item: {
5850
+ key: `__adapter_root__`,
5851
+ label: ``,
5852
+ isLeaf: false
5853
+ },
5854
+ children: items.map(buildNode)
5855
+ };
5472
5856
  },
5473
- offset: {
5474
- x: event.offsetX,
5475
- y: event.offsetY
5857
+ clearSelection() {
5858
+ treeEl?.clearSelection();
5859
+ },
5860
+ dispatch(commandId, args) {
5861
+ options?.onDispatch?.(commandId, args, treeEl);
5476
5862
  }
5477
- };
5478
- }
5479
- function dragLogicStart(downEvent, handler) {
5480
- const start = getCoordinates(downEvent);
5481
- const onMove = (event) => {
5482
- handler.progress(getCoordinates(event), start);
5483
- };
5484
- const onUp = (event) => {
5485
- document.removeEventListener(`pointermove`, onMove);
5486
- document.removeEventListener(`pointerup`, onUp);
5487
- handler.complete(getCoordinates(event), start);
5488
- };
5489
- document.addEventListener(`pointermove`, onMove);
5490
- document.addEventListener(`pointerup`, onUp);
5863
+ });
5864
+ Object.defineProperties(adapter, {
5865
+ selectedItems: {
5866
+ get() {
5867
+ return treeEl ? mapNodes(treeEl.selectedNodes) : /* @__PURE__ */ new Set();
5868
+ },
5869
+ enumerable: true,
5870
+ configurable: true
5871
+ },
5872
+ selectionMode: {
5873
+ get() {
5874
+ return selectionMode;
5875
+ },
5876
+ set(v) {
5877
+ selectionMode = v;
5878
+ if (!treeEl) return;
5879
+ if (v === `none`) treeEl.selectionFilter = `none`;
5880
+ else if (v === `single`) {
5881
+ treeEl.selectionFilter = options?.selectionFilter ?? `all`;
5882
+ treeEl.interactionMode = `implicit`;
5883
+ } else {
5884
+ treeEl.selectionFilter = options?.selectionFilter ?? `all`;
5885
+ treeEl.interactionMode = options?.interactionMode ?? `standard`;
5886
+ }
5887
+ },
5888
+ enumerable: true,
5889
+ configurable: true
5890
+ }
5891
+ });
5892
+ return adapter;
5491
5893
  }
5492
5894
  //#endregion
5493
- //#region src/util/near.ts
5494
- function near(target, range) {
5495
- const min = target - range;
5496
- const max = target + range;
5497
- return (v) => v >= min && v <= max;
5895
+ //#region src/vertical-list/vertical-list.ts
5896
+ const ITEM_SELECTOR = `li, [data-list-item]`;
5897
+ function isMultiMode(mode) {
5898
+ return mode === `checked` || mode === `vscode` || mode === `standard`;
5498
5899
  }
5499
- //#endregion
5500
- //#region src/range/range-multi.ts
5501
- let RangeMultiElement = class RangeMultiElement extends LitElement {
5502
- constructor(..._args) {
5503
- super(..._args);
5504
- this.tooltip = true;
5505
- this.tooltipOrientation = `top`;
5506
- this.crossover = `allow`;
5507
- this.resizeMode = `dual`;
5508
- this.orientation = `horizontal`;
5509
- this.step = 1;
5510
- this.a = 0;
5511
- this.b = 50;
5512
- this.#userMax = 100;
5513
- this.#userMin = 0;
5514
- this.#scaleTo100 = (v) => v;
5515
- this.#scaleFrom100 = (v) => v;
5516
- this.#userClamp = (v) => v;
5517
- this.draggingThumb = `none`;
5518
- }
5519
- #userMax;
5520
- #userMin;
5521
- #scaleTo100;
5522
- #scaleFrom100;
5523
- #userClamp;
5524
- #updateScale() {
5525
- this.#scaleTo100 = scaler(this.#userMin, this.#userMax, 0, 100);
5526
- this.#scaleFrom100 = scaler(0, 100, this.#userMin, this.#userMax);
5527
- this.#userClamp = clamper(this.#userMin, this.#userMax);
5528
- this.a = this.#userClamp(this.a);
5529
- this.b = this.#userClamp(this.b);
5530
- }
5531
- set max(v) {
5532
- this.#userMax = v;
5533
- this.#updateScale();
5534
- }
5535
- get max() {
5536
- return this.#userMax;
5537
- }
5538
- set min(v) {
5539
- this.#userMin = v;
5540
- this.#updateScale();
5541
- }
5542
- get min() {
5543
- return this.#userMin;
5544
- }
5545
- _onInput(event) {
5546
- event.stopPropagation();
5547
- const t = event.target;
5548
- const v = this.#scaleFrom100(t.valueAsNumber);
5549
- const which = t.id;
5550
- let a = this.a;
5551
- let b = this.b;
5552
- if (this.resizeMode === `none`) {
5553
- let panDelta = v - (which === `a` ? this.a : this.b);
5554
- const newA = this.a + panDelta;
5555
- const newB = this.b + panDelta;
5556
- if (newA < this.min) panDelta = this.min - this.a;
5557
- if (newB > this.max) panDelta = this.max - this.b;
5558
- if (panDelta === 0) {
5559
- t.valueAsNumber = this.#scaleTo100(which === `a` ? this.a : this.b);
5900
+ let VerticalListElement = class VerticalListElement extends LitElement {
5901
+ constructor(..._args2) {
5902
+ super(..._args2);
5903
+ this.selectionMode = `single`;
5904
+ this.interactionMode = `standard`;
5905
+ this._selectedItems = /* @__PURE__ */ new Set();
5906
+ this._searchVisible = false;
5907
+ this._searchQuery = ``;
5908
+ this.#customWrappers = /* @__PURE__ */ new Map();
5909
+ this.tickled = new TickledController(this, {
5910
+ getItems: () => this._getVisibleItems().map((el) => ({
5911
+ id: el,
5912
+ enabled: true
5913
+ })),
5914
+ onTickle: (id) => {
5915
+ if (id !== void 0) this._dispatch(`list-tickle`, { item: id });
5916
+ },
5917
+ onStateChange: () => this._syncItemStates()
5918
+ });
5919
+ this._onPointerOver = (e) => {
5920
+ const item = this._findListItem(e.composedPath());
5921
+ if (item) this.tickled.handlePointerEnter(item);
5922
+ };
5923
+ this._onPointerLeave = (e) => {
5924
+ this.tickled.handlePointerLeave(e);
5925
+ };
5926
+ this._onKeyDown = (e) => {
5927
+ if ((e.ctrlKey || e.metaKey) && e.key === `f`) {
5928
+ e.preventDefault();
5929
+ this._openSearch();
5560
5930
  return;
5561
5931
  }
5562
- a = this.a + panDelta;
5563
- b = this.b + panDelta;
5564
- } else if (this.resizeMode === `bipolar`) {
5565
- let newA;
5566
- let newB;
5567
- if (which === `a`) {
5568
- const delta = v - this.a;
5569
- newA = v;
5570
- newB = this.b - delta;
5571
- } else {
5572
- const delta = v - this.b;
5573
- newA = this.a - delta;
5574
- newB = v;
5575
- }
5576
- if (newA < this.min || newB > this.max || newA > this.max || newB < this.min) {
5577
- t.valueAsNumber = this.#scaleTo100(which === `a` ? this.a : this.b);
5932
+ if ((e.ctrlKey || e.metaKey) && e.key === `a`) {
5933
+ if ((this.selectionMode === `multiple` || isMultiMode(this.interactionMode)) && this.selectionMode !== `none`) {
5934
+ e.preventDefault();
5935
+ this._selectAll();
5936
+ }
5578
5937
  return;
5579
5938
  }
5580
- a = newA;
5581
- b = newB;
5582
- } else if (this.resizeMode === `bipolar-flex`) {
5583
- let newA;
5584
- let newB;
5585
- if (which === `a`) {
5586
- newA = v;
5587
- if (this.b <= this.min) newB = this.min;
5588
- else if (this.b >= this.max) newB = this.max;
5589
- else {
5590
- const delta = v - this.a;
5591
- newB = this.b - delta;
5939
+ if (this._searchVisible) return;
5940
+ switch (e.key) {
5941
+ case `ArrowDown`:
5942
+ e.preventDefault();
5943
+ this.tickled.handleKeyboardNavigation(`next`);
5944
+ if (e.shiftKey && this.interactionMode === `vscode`) {
5945
+ const cur = this.tickled.tickledId;
5946
+ if (cur) this._rangeSelectTo(cur);
5947
+ }
5948
+ break;
5949
+ case `ArrowUp`:
5950
+ e.preventDefault();
5951
+ this.tickled.handleKeyboardNavigation(`previous`);
5952
+ if (e.shiftKey && this.interactionMode === `vscode`) {
5953
+ const cur = this.tickled.tickledId;
5954
+ if (cur) this._rangeSelectTo(cur);
5955
+ }
5956
+ break;
5957
+ case `Enter`: {
5958
+ const id = this.tickled.tickledId;
5959
+ if (id) {
5960
+ e.preventDefault();
5961
+ this._dispatch(`list-item-click`, { item: id });
5962
+ this._activateItem(id);
5963
+ }
5964
+ break;
5592
5965
  }
5593
- } else {
5594
- newB = v;
5595
- if (this.a <= this.min) newA = this.min;
5596
- else if (this.a >= this.max) newA = this.max;
5597
- else {
5598
- const delta = v - this.b;
5599
- newA = this.a - delta;
5966
+ case ` `: {
5967
+ const id = this.tickled.tickledId;
5968
+ if (id) {
5969
+ e.preventDefault();
5970
+ this._handleSpaceKey(id);
5971
+ }
5972
+ break;
5600
5973
  }
5974
+ case `Escape`:
5975
+ this._clearSelection();
5976
+ break;
5601
5977
  }
5602
- if (newA < this.min) newA = this.min;
5603
- if (newA > this.max) newA = this.max;
5604
- if (newB < this.min) newB = this.min;
5605
- if (newB > this.max) newB = this.max;
5606
- if (newA > newB) {
5607
- t.valueAsNumber = this.#scaleTo100(which === `a` ? this.a : this.b);
5608
- return;
5609
- }
5610
- a = newA;
5611
- b = newB;
5612
- } else if (which === `a`) if (v > this.b && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.a);
5613
- else a = v;
5614
- else if (which === `b`) if (v < a && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.b);
5615
- else b = v;
5616
- else throw new Error(`Expected 'a' or 'b', got: '${t.id}'`);
5617
- this.setPoles(a, b);
5618
- }
5619
- setPoles(a, b) {
5620
- const aDiff = a !== this.a;
5621
- const bDiff = b !== this.b;
5622
- this.a = this.#userClamp(a);
5623
- this.b = this.#userClamp(b);
5624
- this.dispatchEvent(new CustomEvent(`input`, { detail: {
5625
- a: this.a,
5626
- b: this.b,
5627
- changed: aDiff && bDiff ? `both` : aDiff ? `a` : `b`
5628
- } }));
5629
- }
5630
- _onPointerDown(event) {
5631
- const startA = this.a;
5632
- const startB = this.b;
5633
- this.valuesAtPointerDown = {
5634
- a: startA,
5635
- b: startB
5636
5978
  };
5637
- const rect = event.target.getBoundingClientRect();
5638
- const isVertical = this.orientation === `vertical`;
5639
- const dim = isVertical ? rect.height : rect.width;
5640
- const valuePerPix = dim / (this.max - this.min);
5641
- const pos = isVertical ? event.offsetY : event.offsetX;
5642
- const valueFromPos = (p) => {
5643
- return isVertical ? this.max - p * valuePerPix : p * valuePerPix;
5979
+ this._onClick = (e) => {
5980
+ const item = this._findListItem(e.composedPath());
5981
+ if (!item) return;
5982
+ this._dispatch(`list-item-click`, { item });
5983
+ this._handleClickSelection(item, e);
5644
5984
  };
5645
- const posFromValue = (v) => {
5646
- return isVertical ? dim - v * valuePerPix : v * valuePerPix;
5985
+ this._onDblClick = (e) => {
5986
+ const item = this._findListItem(e.composedPath());
5987
+ if (item) this._activateItem(item);
5647
5988
  };
5648
- const aPosPx = posFromValue(startA);
5649
- const bPosPx = posFromValue(startB);
5650
- if (isVertical ? (this.b < this.a ? pos > bPosPx : pos < bPosPx) || (this.b < this.a ? pos < aPosPx : pos > aPosPx) : this.b < this.a && pos < bPosPx || this.b > this.a && pos > bPosPx || this.a < this.b && pos < aPosPx || this.a > this.b && pos > aPosPx) {
5651
- if (this.resizeMode === `none` || this.resizeMode === `bipolar` || this.resizeMode === `bipolar-flex`) {
5652
- let panDelta = valueFromPos(pos) - this.b;
5653
- if (this.a + panDelta < this.min) panDelta = this.min - this.a;
5654
- if (this.b + panDelta > this.max) panDelta = this.max - this.b;
5655
- const finalA = this.a + panDelta;
5656
- const finalB = this.b + panDelta;
5657
- if (finalA >= this.min && finalB <= this.max) this.setPoles(finalA, finalB);
5658
- } else this.b = valueFromPos(pos);
5659
- return;
5660
- }
5661
- const aPosPxNear = near(aPosPx, 10);
5662
- const bPosPxNear = near(bPosPx, 10);
5663
- const handleDrag = (draggingWhich) => {
5664
- const setPoles = this.setPoles.bind(this);
5665
- const resizeMode = this.resizeMode;
5666
- const min = this.min;
5667
- const max = this.max;
5668
- const startPos = isVertical ? event.offsetY : event.offsetX;
5669
- let polesChanged = false;
5670
- dragLogicStart(event, {
5671
- progress(current, _start) {
5672
- const currentPos = isVertical ? current.offset.y : current.offset.x;
5673
- const amt = (isVertical ? startPos - currentPos : currentPos - startPos) / valuePerPix;
5674
- polesChanged = true;
5675
- if (draggingWhich === `a`) if (resizeMode === `bipolar`) {
5676
- const calcA = startA + amt;
5677
- const calcB = startB - amt;
5678
- if (calcA < min || calcB > max || calcA > max || calcB < min) return;
5679
- setPoles(calcA, calcB);
5680
- } else if (resizeMode === `bipolar-flex`) {
5681
- let calcA = startA + amt;
5682
- let calcB = startB;
5683
- if (startB <= min) calcB = min;
5684
- else if (startB >= max) calcB = max;
5685
- else {
5686
- calcA = startA + amt;
5687
- calcB = startB - amt;
5688
- }
5689
- if (calcA < min) calcA = min;
5690
- if (calcA > max) calcA = max;
5691
- if (calcB < min) calcB = min;
5692
- if (calcB > max) calcB = max;
5693
- if (calcA > calcB) return;
5694
- setPoles(calcA, calcB);
5695
- } else {
5696
- let constrainedAmt = amt;
5697
- if (startA + amt < min) constrainedAmt = min - startA;
5698
- if (startB + constrainedAmt > max) constrainedAmt = max - startB;
5699
- const finalA = startA + constrainedAmt;
5700
- const finalB = startB + constrainedAmt;
5701
- if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
5702
- }
5703
- else if (draggingWhich === `b`) if (resizeMode === `bipolar`) {
5704
- const calcA = startA - amt;
5705
- const calcB = startB + amt;
5706
- if (calcA < min || calcB > max || calcA > max || calcB < min) return;
5707
- setPoles(calcA, calcB);
5708
- } else if (resizeMode === `bipolar-flex`) {
5709
- let calcA = startA;
5710
- let calcB = startB + amt;
5711
- if (startA <= min) calcA = min;
5712
- else if (startA >= max) calcA = max;
5713
- else {
5714
- calcA = startA - amt;
5715
- calcB = startB + amt;
5716
- }
5717
- if (calcA < min) calcA = min;
5718
- if (calcA > max) calcA = max;
5719
- if (calcB < min) calcB = min;
5720
- if (calcB > max) calcB = max;
5721
- if (calcA > calcB) return;
5722
- setPoles(calcA, calcB);
5723
- } else {
5724
- let constrainedAmt = amt;
5725
- if (startA + amt < min) constrainedAmt = min - startA;
5726
- if (startB + constrainedAmt > max) constrainedAmt = max - startB;
5727
- const finalA = startA + constrainedAmt;
5728
- const finalB = startB + constrainedAmt;
5729
- if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
5730
- }
5731
- else if (resizeMode === `bipolar`) {
5732
- const calcA = startA + amt;
5733
- const calcB = startB + amt;
5734
- if (calcA < min || calcB > max) return;
5735
- setPoles(calcA, calcB);
5736
- } else if (resizeMode === `bipolar-flex`) {
5737
- let calcA = startA + amt;
5738
- let calcB = startB + amt;
5739
- if (calcA < min) {
5740
- calcA = min;
5741
- calcB = min + (startB - startA);
5742
- } else if (calcB > max) {
5743
- calcB = max;
5744
- calcA = max - (startB - startA);
5745
- }
5746
- if (calcA < min || calcB > max || calcA > calcB) return;
5747
- setPoles(calcA, calcB);
5748
- } else {
5749
- let constrainedAmt = amt;
5750
- if (startA + amt < min) constrainedAmt = min - startA;
5751
- if (startB + constrainedAmt > max) constrainedAmt = max - startB;
5752
- const finalA = startA + constrainedAmt;
5753
- const finalB = startB + constrainedAmt;
5754
- if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
5755
- }
5756
- },
5757
- complete(_final, _start) {
5758
- if (!polesChanged) {
5759
- const currentPos = isVertical ? event.offsetY : event.offsetX;
5760
- if (Math.abs(currentPos - aPosPx) < Math.abs(currentPos - bPosPx)) setPoles(valueFromPos(currentPos), startB);
5761
- else setPoles(startA, valueFromPos(currentPos));
5762
- }
5989
+ this._onSearchInput = (e) => {
5990
+ const input = e.target;
5991
+ this._searchQuery = input.value;
5992
+ this.#search?.setQuery(this._searchQuery);
5993
+ };
5994
+ this._onSearchKeydown = (e) => {
5995
+ if (e.key === `Escape`) {
5996
+ e.stopPropagation();
5997
+ this._closeSearch();
5998
+ } else if (e.key === `ArrowDown`) {
5999
+ e.preventDefault();
6000
+ this.tickled.handleKeyboardNavigation(`next`);
6001
+ } else if (e.key === `ArrowUp`) {
6002
+ e.preventDefault();
6003
+ this.tickled.handleKeyboardNavigation(`previous`);
6004
+ } else if (e.key === `Enter`) {
6005
+ e.preventDefault();
6006
+ e.stopPropagation();
6007
+ const id = this.tickled.tickledId ?? this._getVisibleItems()[0];
6008
+ if (id) {
6009
+ this._dispatch(`list-item-click`, { item: id });
6010
+ this._activateItem(id);
6011
+ this._closeSearch();
5763
6012
  }
5764
- });
6013
+ }
5765
6014
  };
5766
- if (aPosPxNear(pos)) {
5767
- this.draggingThumb = `a`;
5768
- if (this.resizeMode === `dual`) return false;
5769
- event.preventDefault();
5770
- event.target.setPointerCapture(event.pointerId);
5771
- handleDrag(`a`);
5772
- return;
5773
- } else if (bPosPxNear(pos)) {
5774
- this.draggingThumb = `b`;
5775
- if (this.resizeMode === `dual`) return false;
5776
- event.preventDefault();
5777
- event.target.setPointerCapture(event.pointerId);
5778
- handleDrag(`b`);
5779
- return;
5780
- } else this.draggingThumb = `none`;
5781
- event.preventDefault();
5782
- event.target.setPointerCapture(event.pointerId);
5783
- handleDrag(`none`);
5784
- }
5785
- firstUpdated(_changedProperties) {
5786
- this.#updateScale();
5787
- }
5788
- render() {
5789
- const ttA = this.tooltip ? html`<ixfx-tooltip style="--tooltip-background: var(--surface-5); --tooltip-color: var(--surface-5-text)" anchor="--a-tooltip" .orientation=${this.tooltipOrientation} .value=${this.a}></ixfx-tooltip>` : nothing;
5790
- const ttB = this.tooltip ? html`<ixfx-tooltip style="--tooltip-background: var(--surface-5); --tooltip-color: var(--surface-5-text)" anchor="--b-tooltip" .orientation=${this.tooltipOrientation} .value=${this.b}></ixfx-tooltip>` : nothing;
5791
- const scaledA = this.#scaleTo100(this.a);
5792
- const scaledB = this.#scaleTo100(this.b);
5793
- const verticalStyle = this.orientation === `vertical` ? `writing-mode: vertical-lr; direction: rtl;` : nothing;
5794
- return html`
5795
- <div @pointerdown=${this._onPointerDown} @input=${this._onInput} style="--a: ${scaledA}; --b: ${scaledB}">
5796
- <input class="thumb-round" .value=${scaledA} id="a" step=${this.step} type="range" style="${verticalStyle}" anchor="--a-tooltip" />
5797
- ${ttA}
5798
-
5799
- <input class="thumb-round" .value=${scaledB} id="b" step=${this.step} type="range" style="${verticalStyle}" anchor="--b-tooltip" />
5800
- ${ttB}
5801
- </div>`;
5802
- }
5803
- static {
5804
- this.styles = [
5805
- tooltipValueStyles,
5806
- prominenceStyles,
5807
- css`
5808
- :host {
5809
- display: grid;
5810
- --value-label-color: unset;
5811
-
5812
- --range-background: AccentColor;
5813
- --range-height: 1.5em;
5814
- --range-thickness: 1em;
5815
- --thumb-background: ButtonFace;
5816
- --thumb-radius: 50%;
5817
- --thumb-width: 1em;
5818
- --thumb-height: 1em;
5819
- --js:1;
5820
- }
5821
-
5822
- :host([orientation="vertical"]) {
5823
- display: block;
5824
- width: 1.5em;
5825
- height: 200px;
5826
- }
5827
-
5828
- * {
5829
- margin: 0;
5830
- padding: 0;
5831
- font: inherit;
5832
- }
5833
-
5834
- div {
5835
- --j: var(--js, 0);
5836
- display:inline grid;
5837
- align-content: end;
5838
- grid-gap: 0.25em;
5839
- place-self: center;
5840
- min-width: 8em;
5841
- width: calc(100% - 1.5em);
5842
- height: 1.5rem;
5843
- }
5844
-
5845
- :host([orientation="vertical"]) div {
5846
- width: 1.5rem;
5847
- height: calc(100% - 1.5em);
5848
- min-width: unset;
5849
- min-height: 8em;
5850
- }
5851
-
5852
- div::before, div::after {
5853
- margin: 0.5rem 0.6875rem;
5854
- border-radius: 0.25rem;
5855
- box-shadow: none;
5856
- background: var(--surface-4);
5857
- content: "";
5858
- }
5859
- :host([orientation="vertical"]) div::before,
5860
- :host([orientation="vertical"]) div::after {
5861
- margin: 0.5rem 0;
5862
- }
5863
- div::after {
5864
- --or: calc((100 - Max(var(--a), var(--b)))*1%);
5865
- --ol: calc(Min(var(--a), var(--b))*1%);
5866
- box-shadow: none;
5867
- background: var(--accent);
5868
- clip-path: inset(0 var(--or) 0 var(--ol));
5869
- }
5870
- :host([orientation="vertical"]) div::after {
5871
- clip-path: inset(var(--or) 0 var(--ol) 0);
5872
- }
5873
- div input, div::before, div::after {
5874
- grid-area: calc(1 + var(--j))/1;
5875
- }
5876
- div output, div::after {
5877
- display:'none';
5878
- }
5879
-
5880
- [type=range] {
5881
- width: 100%;
5882
- height: var(--range-height);
5883
- background: transparent;
5884
- pointer-events: none;
5885
- }
5886
-
5887
- :host([orientation="vertical"]) [type=range] {
5888
- writing-mode: vertical-lr;
5889
- direction: rtl;
5890
- width: var(--range-height);
5891
- height: 100%;
5892
- }
5893
-
5894
- [type=range], [type=range]::-webkit-slider-runnable-track, [type=range]::-webkit-slider-thumb {
5895
- -webkit-appearance: none;
5896
- }
5897
- [type=range], [type=range] + ixfx-tooltip {
5898
- --sel: 0;
5899
- z-index: calc(1 + var(--sel));
5900
- }
5901
- [type=range]::-webkit-slider-runnable-track {
5902
- background: transparent;
5903
- }
5904
- [type=range]::-moz-range-track {
5905
- background: transparent;
5906
- }
5907
-
5908
- input.thumb-round::-webkit-slider-thumb {
5909
- width: var(--thumb-width);
5910
- height: var(--thumb-height);
5911
- border-radius: var(--thumb-radius);
5912
- }
5913
-
5914
- [type=range]::-webkit-slider-thumb {
5915
- box-sizing: border-box;
5916
- border: solid calc(0.5rem + -1px) transparent;
5917
-
5918
- /* box-shadow: var(--shadow-m); */
5919
- background: var(--thumb-background);
5920
- pointer-events: auto;
5921
- cursor: ew-resize;
5922
- }
5923
-
5924
- :host([orientation="vertical"]) [type=range]::-webkit-slider-thumb {
5925
- width: var(--thumb-height);
5926
- height: var(--thumb-width);
5927
- cursor: ns-resize;
5928
- }
5929
-
5930
- [type=range]::-moz-range-thumb {
5931
- box-sizing: border-box;
5932
- border: solid calc(0.5rem + -1px) transparent;
5933
- width: 1.375rem;
5934
- height: 1.375rem;
5935
- border-radius: 50%;
5936
- box-shadow: var(--shadow-m);
5937
- background: var(--thumb-background);
5938
- pointer-events: auto;
5939
- cursor: ew-resize;
5940
- }
5941
-
5942
- :host([orientation="vertical"]) [type=range]::-moz-range-thumb {
5943
- cursor: ns-resize;
5944
- }
5945
-
5946
- [type=range]:focus {
5947
- outline: none;
5948
- }
5949
- [type=range]:focus, [type=range]:focus + ixfx-tooltip, [type=range]:hover, [type=range]:hover + ixfx-tooltip {
5950
- --sel: 1 ;
5951
- }
5952
- `
5953
- ];
5954
- }
5955
- };
5956
- __decorate([property({ type: Boolean })], RangeMultiElement.prototype, "tooltip", void 0);
5957
- __decorate([property({
5958
- type: String,
5959
- attribute: `tooltip-orientation`
5960
- })], RangeMultiElement.prototype, "tooltipOrientation", void 0);
5961
- __decorate([property({ type: String })], RangeMultiElement.prototype, "crossover", void 0);
5962
- __decorate([property({
5963
- type: String,
5964
- attribute: `resize-mode`
5965
- })], RangeMultiElement.prototype, "resizeMode", void 0);
5966
- __decorate([property({
5967
- type: String,
5968
- reflect: true
5969
- })], RangeMultiElement.prototype, "orientation", void 0);
5970
- __decorate([property()], RangeMultiElement.prototype, "step", void 0);
5971
- __decorate([property({ type: Number })], RangeMultiElement.prototype, "a", void 0);
5972
- __decorate([property({ type: Number })], RangeMultiElement.prototype, "b", void 0);
5973
- __decorate([property({ type: Number })], RangeMultiElement.prototype, "max", null);
5974
- __decorate([property({ type: Number })], RangeMultiElement.prototype, "min", null);
5975
- __decorate([eventOptions({ capture: true })], RangeMultiElement.prototype, "_onInput", null);
5976
- __decorate([eventOptions({ capture: true })], RangeMultiElement.prototype, "_onPointerDown", null);
5977
- RangeMultiElement = __decorate([safeCustomElement(`ixfx-range-multi`)], RangeMultiElement);
5978
- //#endregion
5979
- //#region src/tabs/tab-list-item.ts
5980
- let TabListItemElement = class TabListItemElement extends LitElement {
5981
- constructor(..._args) {
5982
- super(..._args);
5983
- this.closeable = false;
5984
- this.iconName = void 0;
5985
- this.description = void 0;
5986
- this.commandActive = void 0;
5987
- this.registry = void 0;
5988
- this._compact = false;
5989
6015
  }
6016
+ #search;
6017
+ #selectionAnchor;
6018
+ #customWrappers;
5990
6019
  connectedCallback() {
5991
6020
  super.connectedCallback();
5992
- this._resizeObserver = new ResizeObserver(([entry]) => {
5993
- this._compact = entry.contentRect.width < 64;
5994
- });
5995
- this._resizeObserver.observe(this);
6021
+ if (!this.hasAttribute(`tabindex`)) this.tabIndex = 0;
6022
+ this.addEventListener(`pointerover`, this._onPointerOver);
6023
+ this.addEventListener(`pointerleave`, this._onPointerLeave);
6024
+ this.addEventListener(`keydown`, this._onKeyDown);
6025
+ this.addEventListener(`click`, this._onClick);
6026
+ this.addEventListener(`dblclick`, this._onDblClick);
6027
+ }
6028
+ disconnectedCallback() {
6029
+ super.disconnectedCallback();
6030
+ this.removeEventListener(`pointerover`, this._onPointerOver);
6031
+ this.removeEventListener(`pointerleave`, this._onPointerLeave);
6032
+ this.removeEventListener(`keydown`, this._onKeyDown);
6033
+ this.removeEventListener(`click`, this._onClick);
6034
+ this.removeEventListener(`dblclick`, this._onDblClick);
6035
+ this.#search?.dispose();
6036
+ this.#search = void 0;
5996
6037
  }
5997
- disconnectedCallback() {
5998
- super.disconnectedCallback();
5999
- this._resizeObserver?.disconnect();
6000
- this._resizeObserver = void 0;
6001
- this._commandCleanup?.();
6002
- this._commandCleanup = void 0;
6038
+ firstUpdated() {
6039
+ this.#search = createElementIncrSearch({
6040
+ container: this,
6041
+ itemSelector: ITEM_SELECTOR,
6042
+ getLabel: (el) => el.getAttribute(`data-search-label`) ?? el.textContent?.trim() ?? ``,
6043
+ getKey: (el) => el.getAttribute(`data-key`) ?? el.getAttribute(`data-search-label`) ?? el.textContent?.trim() ?? ``,
6044
+ highlightKey: `vertical-list-search`
6045
+ });
6003
6046
  }
6004
6047
  updated(changed) {
6005
6048
  super.updated(changed);
6006
- this._syncTooltipAttrs();
6007
- if (changed.has(`registry`) || changed.has(`commandActive`)) this._syncCommandListener();
6008
- }
6009
- _syncTooltipAttrs() {
6010
- if (this.description) {
6011
- this.setAttribute(`data-tooltip`, this.description);
6012
- this.setAttribute(`data-tooltip-anchor`, `top`);
6013
- } else {
6014
- this.removeAttribute(`data-tooltip`);
6015
- this.removeAttribute(`data-tooltip-anchor`);
6049
+ if (changed.has(`interactionMode`)) {
6050
+ this.#selectionAnchor = void 0;
6051
+ const previousSelected = this._selectedItems;
6052
+ const savedWrappers = changed.get(`interactionMode`) === `checked` ? new Map(this.#customWrappers) : null;
6053
+ this._syncCheckboxes();
6054
+ if (previousSelected.size > 0) {
6055
+ let remapped;
6056
+ if (savedWrappers && savedWrappers.size > 0) remapped = new Set([...previousSelected].map((el) => savedWrappers.get(el) ?? el));
6057
+ else if (this.#customWrappers.size > 0) {
6058
+ const innerToWrapper = new Map([...this.#customWrappers].map(([w, i]) => [i, w]));
6059
+ remapped = new Set([...previousSelected].map((el) => innerToWrapper.get(el) ?? el));
6060
+ } else remapped = new Set(previousSelected);
6061
+ this._selectedItems = remapped;
6062
+ }
6063
+ this._syncItemStates();
6016
6064
  }
6017
6065
  }
6018
- _syncCommandListener() {
6019
- this._commandCleanup?.();
6020
- this._commandCleanup = void 0;
6021
- if (this.registry && this.commandActive) this._commandCleanup = this.registry.addOnInvokeHandler((id) => {
6022
- if (id === this.commandActive) this.click();
6023
- });
6066
+ /** The most recently selected item, or `undefined` if nothing is selected. */
6067
+ get selectedItem() {
6068
+ return [...this._selectedItems].at(-1);
6024
6069
  }
6025
- render() {
6026
- const showLabel = !this._compact || !this.iconName;
6027
- return html`
6028
- <div>
6029
- ${this.iconName ? html`<ixfx-icon name="${this.iconName}"></ixfx-icon>` : nothing}
6030
- ${showLabel ? html`<span class="label"><slot></slot></span>` : nothing}
6031
- <div class="actions">
6032
- <div class="toolbar"><slot name="toolbar"></slot></div>
6033
- ${this.closeable ? html`
6034
- <button
6035
- class="close-btn"
6036
- type="button"
6037
- aria-label="Close tab"
6038
- @click=${this._onCloseClick}
6039
- >
6040
- <ixfx-icon name="close"></ixfx-icon>
6041
- </button>
6042
- ` : nothing}
6043
- </div>
6044
- </div>
6045
- `;
6070
+ /** The full current selection set (read-only). */
6071
+ get selectedItems() {
6072
+ return this._selectedItems;
6046
6073
  }
6047
- _onCloseClick(e) {
6048
- e.stopPropagation();
6049
- this.dispatchEvent(new CustomEvent(`close`, {
6050
- bubbles: true,
6051
- composed: true
6052
- }));
6053
- this.remove();
6074
+ addItem(item) {
6075
+ if (typeof item === `string`) {
6076
+ const li = document.createElement(`li`);
6077
+ li.textContent = item;
6078
+ this.appendChild(li);
6079
+ } else this.appendChild(item);
6080
+ if (this.interactionMode === `checked`) this._syncCheckboxes();
6054
6081
  }
6055
- static {
6056
- this.styles = [prominenceStyles, css`
6057
- :host {
6058
- --selected-colour: var(--accent);
6059
- --selected-border-width: 1px;
6060
- --padding: var(--space-m);
6061
- display: inline-flex;
6062
- min-width: 0;
6063
- user-select: none;
6064
- box-sizing: border-box;
6065
- }
6066
-
6067
- :host > div {
6068
- display: flex;
6069
- align-items: center;
6070
- gap: var(--space-s, 4px);
6071
- padding: var(--padding) calc(2 * var(--padding));
6072
- min-width: 0;
6073
- width: 100%;
6074
- font-weight: 500;
6075
- border: var(--selected-border-width) solid transparent;
6076
- }
6077
-
6078
- :host([selected]) > div {
6079
- color: var(--selected-colour);
6080
- border-top-color: var(--indicator-color-top, transparent);
6081
- border-bottom-color: var(--indicator-color-bottom, transparent);
6082
- border-left-color: var(--indicator-color-left, transparent);
6083
- border-right-color: var(--indicator-color-right, transparent);
6084
- }
6085
-
6086
- .label {
6087
- overflow: var(--allow-overflow, hidden);
6088
- text-overflow: ellipsis;
6089
- white-space: nowrap;
6090
- min-width: 0;
6091
- flex: 1 1 auto;
6092
- }
6093
-
6094
- ixfx-icon {
6095
- flex-shrink: 0;
6096
- }
6097
-
6098
- .actions {
6099
- display: flex;
6100
- align-items: center;
6101
- gap: var(--space-xs);
6102
- margin-left: auto;
6103
- flex-shrink: 0;
6104
- }
6105
-
6106
- .toolbar {
6107
- display: none;
6108
- align-items: center;
6109
- gap: var(--space-xs);
6110
- }
6111
-
6112
- :host([selected]) .toolbar {
6113
- display: flex;
6114
- }
6115
-
6116
- slot[name="toolbar"] {
6117
- display: contents;
6118
- }
6119
-
6120
- .close-btn {
6121
- display: inline-flex;
6122
- align-items: center;
6123
- justify-content: center;
6124
- background: none;
6125
- border: none;
6126
- padding: var(--space-xs);
6127
- cursor: pointer;
6128
- color: inherit;
6129
- border-radius: var(--radius-s);
6130
- opacity: var(--prominence-idle-opacity);
6131
- transition: opacity var(--transition), background var(--transition);
6132
- }
6133
-
6134
- .close-btn:hover {
6135
- background: var(--surface-5);
6136
- opacity: var(--prominence-tickled-opacity);
6137
- }
6138
-
6139
- .close-btn:focus-visible {
6140
- outline: 2px solid var(--accent);
6141
- outline-offset: 1px;
6142
- }
6143
-
6144
- :host([selected]) .close-btn,
6145
- :host(:hover) .close-btn {
6146
- opacity: var(--prominence-tickled-opacity);
6147
- }
6148
- `];
6082
+ removeItem(item) {
6083
+ item.remove();
6149
6084
  }
6150
- };
6151
- __decorate([property({ type: Boolean })], TabListItemElement.prototype, "closeable", void 0);
6152
- __decorate([property({
6153
- type: String,
6154
- attribute: `icon-name`
6155
- })], TabListItemElement.prototype, "iconName", void 0);
6156
- __decorate([property({ type: String })], TabListItemElement.prototype, "description", void 0);
6157
- __decorate([property({
6158
- type: String,
6159
- attribute: `command-active`
6160
- })], TabListItemElement.prototype, "commandActive", void 0);
6161
- __decorate([property({ attribute: false })], TabListItemElement.prototype, "registry", void 0);
6162
- __decorate([state()], TabListItemElement.prototype, "_compact", void 0);
6163
- TabListItemElement = __decorate([safeCustomElement(`ixfx-tab-list-item`)], TabListItemElement);
6164
- //#endregion
6165
- //#region src/tabs/tab-panel.ts
6166
- let TabPanelElement = class TabPanelElement extends LitElement {
6167
- render() {
6168
- return html`<slot></slot>`;
6085
+ clearItems() {
6086
+ this.#customWrappers.clear();
6087
+ this.replaceChildren();
6088
+ this.#selectionAnchor = void 0;
6089
+ this._selectedItems = /* @__PURE__ */ new Set();
6090
+ this._syncItemStates();
6169
6091
  }
6170
- static {
6171
- this.styles = css`
6172
- :host {
6173
- display:none;
6174
- height:100%;
6175
- width:100%;
6176
- }
6177
-
6178
- :host([selected]) {
6179
- background: var(--surface-3);
6180
- display:block;
6181
- }
6182
- `;
6092
+ /**
6093
+ * Replace the entire item list in one call.
6094
+ * Equivalent to `clearItems()` followed by `addItem()` for each element.
6095
+ * Preserves `interactionMode` checkbox wrapping.
6096
+ */
6097
+ setItems(items) {
6098
+ this.clearItems();
6099
+ for (const item of items) this.appendChild(item);
6100
+ if (this.interactionMode === `checked`) this._syncCheckboxes();
6183
6101
  }
6184
- };
6185
- TabPanelElement = __decorate([safeCustomElement(`ixfx-tab-panel`)], TabPanelElement);
6186
- //#endregion
6187
- //#region src/tabs/tab-panels.ts
6188
- let TabPanelsElement = class TabPanelsElement extends LitElement {
6189
- render() {
6190
- return html`<slot></slot>`;
6102
+ /**
6103
+ * Dispatch a command to this list. No-op by default.
6104
+ * Intended for use with `ixfx-grouped-item-lister`'s `dispatch()` method,
6105
+ * which forwards commands to all sub-components.
6106
+ */
6107
+ dispatch(_commandId, _args) {}
6108
+ select(item) {
6109
+ this._replaceSelection(item);
6191
6110
  }
6192
- getSelectedElement() {
6193
- for (const el of this._listItems) if (this.#isSelected(el)) return el;
6111
+ selectMany(items) {
6112
+ if (this.selectionMode !== `multiple`) throw new Error(`selectMany requires selectionMode="multiple" (current: "${this.selectionMode}")`);
6113
+ const previous = this._selectedItems;
6114
+ const next = new Set(items);
6115
+ if (next.size === 0) return;
6116
+ this._selectedItems = next;
6117
+ this.#selectionAnchor = [...next].at(-1);
6118
+ this._syncItemStates();
6119
+ this._dispatch(`list-select`, {
6120
+ selected: next,
6121
+ previous
6122
+ });
6123
+ }
6124
+ deselect(item) {
6125
+ if (!this._selectedItems.has(item)) return;
6126
+ const previous = this._selectedItems;
6127
+ const next = new Set(this._selectedItems);
6128
+ next.delete(item);
6129
+ this._selectedItems = next;
6130
+ this._syncItemStates();
6131
+ this._dispatch(`list-select`, {
6132
+ selected: next,
6133
+ previous
6134
+ });
6194
6135
  }
6195
- #isSelected(el) {
6196
- return el.hasAttribute(`selected`);
6136
+ clearSelection() {
6137
+ this._clearSelection();
6197
6138
  }
6198
- #unselect(el) {
6199
- el.removeAttribute(`selected`);
6200
- if (this.onUnselectedPanel) this.onUnselectedPanel(el.id, el);
6139
+ selectAll() {
6140
+ if ((this.selectionMode === `multiple` || isMultiMode(this.interactionMode)) && this.selectionMode !== `none`) this._selectAll();
6201
6141
  }
6202
- #select(el) {
6203
- if (this.onSelectingPanel) this.onSelectingPanel(el.id, el);
6204
- el.setAttribute(`selected`, ``);
6205
- if (this.onSelectedPanel) this.onSelectedPanel(el.id, el);
6142
+ _replaceSelection(item) {
6143
+ if (this.selectionMode === `none`) return;
6144
+ const previous = this._selectedItems;
6145
+ const next = new Set([item]);
6146
+ this._selectedItems = next;
6147
+ this.#selectionAnchor = item;
6148
+ this._syncItemStates();
6149
+ this._dispatch(`list-select`, {
6150
+ selected: next,
6151
+ previous
6152
+ });
6206
6153
  }
6207
- syncWithList(el) {
6208
- const apply = (t) => {
6209
- if (!t) return;
6210
- const forEl = t.getAttribute(`for`);
6211
- if (forEl) this.selectPanel(forEl);
6212
- };
6213
- const t = el.getSelectedElement();
6214
- if (!t) {
6215
- el.updateComplete.then(() => apply(el.getSelectedElement()));
6216
- return;
6154
+ _toggleItem(item) {
6155
+ const effectiveMultiple = this.selectionMode === `multiple` || isMultiMode(this.interactionMode);
6156
+ if (this.selectionMode === `none` && this.interactionMode !== `checked`) return;
6157
+ const previous = this._selectedItems;
6158
+ const next = new Set(this._selectedItems);
6159
+ if (next.has(item)) next.delete(item);
6160
+ else {
6161
+ if (!effectiveMultiple) next.clear();
6162
+ next.add(item);
6217
6163
  }
6218
- apply(t);
6164
+ this._selectedItems = next;
6165
+ this._syncItemStates();
6166
+ this._dispatch(`list-select`, {
6167
+ selected: next,
6168
+ previous
6169
+ });
6219
6170
  }
6220
- selectPanel(id) {
6221
- const current = this.getSelectedElement();
6222
- if (current) {
6223
- if (current.id === id) return;
6224
- this.#unselect(current);
6171
+ _rangeSelectTo(item) {
6172
+ if (this.selectionMode === `none`) return;
6173
+ if (!this.#selectionAnchor) {
6174
+ this._replaceSelection(item);
6175
+ return;
6225
6176
  }
6226
- let found = false;
6227
- for (const el of this._listItems) if (el.id === id) {
6228
- this.#select(el);
6229
- found = true;
6177
+ const visible = this._getVisibleItems();
6178
+ const anchorIdx = visible.indexOf(this.#selectionAnchor);
6179
+ const targetIdx = visible.indexOf(item);
6180
+ if (anchorIdx === -1 || targetIdx === -1) {
6181
+ this._replaceSelection(item);
6182
+ return;
6230
6183
  }
6231
- return found;
6232
- }
6233
- static {
6234
- this.styles = css`
6235
- :host {
6236
- display: block;
6237
- }
6238
-
6239
- `;
6184
+ const start = Math.min(anchorIdx, targetIdx);
6185
+ const end = Math.max(anchorIdx, targetIdx);
6186
+ const previous = this._selectedItems;
6187
+ const next = new Set(visible.slice(start, end + 1));
6188
+ this._selectedItems = next;
6189
+ this._syncItemStates();
6190
+ this._dispatch(`list-select`, {
6191
+ selected: next,
6192
+ previous
6193
+ });
6240
6194
  }
6241
- };
6242
- __decorate([queryAssignedElements()], TabPanelsElement.prototype, "_listItems", void 0);
6243
- TabPanelsElement = __decorate([safeCustomElement(`ixfx-tab-panels`)], TabPanelsElement);
6244
- //#endregion
6245
- //#region src/transitory-label/transitory-label.ts
6246
- let TransitoryLabelElement = class TransitoryLabelElement extends LitElement {
6247
- constructor(..._args) {
6248
- super(..._args);
6249
- this.text = ``;
6250
- this.effect = `fade`;
6251
- this.duration = 300;
6252
- this.easing = `ease`;
6253
- this._currentText = ``;
6254
- this._outgoingText = ``;
6255
- this._transitionId = 0;
6256
- this._queue = [];
6257
- this.#onOutgoingEnd = () => {
6258
- this._onTransitionEnd();
6259
- };
6260
- this.#onLastCharOut = () => {
6261
- this._onTransitionEnd();
6262
- };
6195
+ _clearSelection() {
6196
+ if (this._selectedItems.size === 0) return;
6197
+ const previous = this._selectedItems;
6198
+ this._selectedItems = /* @__PURE__ */ new Set();
6199
+ this._syncItemStates();
6200
+ this._dispatch(`list-select`, {
6201
+ selected: /* @__PURE__ */ new Set(),
6202
+ previous
6203
+ });
6263
6204
  }
6264
- setText(msg, effect) {
6265
- this._pendingEffect = effect;
6266
- this.text = msg;
6205
+ _selectAll() {
6206
+ const visible = this._getVisibleItems();
6207
+ if (visible.length === 0) return;
6208
+ const previous = this._selectedItems;
6209
+ const next = new Set(visible);
6210
+ this._selectedItems = next;
6211
+ this._syncItemStates();
6212
+ this._dispatch(`list-select`, {
6213
+ selected: next,
6214
+ previous
6215
+ });
6267
6216
  }
6268
- updated(changed) {
6269
- if (changed.has(`text`) && this.text !== this._currentText) {
6270
- const effect = this._pendingEffect ?? this.effect;
6271
- this._pendingEffect = void 0;
6272
- if (this._activeEffect !== void 0) this._queue.push({
6273
- text: this.text,
6274
- effect
6275
- });
6276
- else this._startTransition(this.text, effect);
6217
+ _handleClickSelection(item, e) {
6218
+ const mode = this.interactionMode;
6219
+ if (mode === `manual`) return;
6220
+ if (this.selectionMode === `none` && mode !== `checked`) return;
6221
+ switch (mode) {
6222
+ case `implicit`:
6223
+ this._replaceSelection(item);
6224
+ break;
6225
+ case `standard`:
6226
+ case `vscode`:
6227
+ if (e.ctrlKey || e.metaKey) {
6228
+ if (this.selectionMode === `multiple` || mode === `vscode`) this._toggleItem(item);
6229
+ } else if (e.shiftKey && (this.selectionMode === `multiple` || mode === `vscode`)) this._rangeSelectTo(item);
6230
+ else this._replaceSelection(item);
6231
+ break;
6232
+ case `checked`: break;
6277
6233
  }
6278
6234
  }
6279
- _startTransition(newText, effect) {
6280
- const prevText = this._currentText;
6281
- this._currentText = newText;
6282
- this._outgoingText = prevText;
6283
- if (prevText !== ``) {
6284
- this._transitionId++;
6285
- this._activeEffect = effect;
6286
- }
6235
+ _handleSpaceKey(item) {
6236
+ const mode = this.interactionMode;
6237
+ if (mode === `manual`) return;
6238
+ if (mode === `implicit`) this._replaceSelection(item);
6239
+ else this._toggleItem(item);
6287
6240
  }
6288
- _onTransitionEnd() {
6289
- this._outgoingText = ``;
6290
- this._activeEffect = void 0;
6291
- if (this._queue.length > 0) {
6292
- const next = this._queue.shift();
6293
- this._startTransition(next.text, next.effect);
6241
+ _getVisibleItems() {
6242
+ return Array.from(this.querySelectorAll(ITEM_SELECTOR)).filter((el) => {
6243
+ if (el.hidden) return false;
6244
+ if (this.filterPredicate && !this.filterPredicate(el)) return false;
6245
+ return true;
6246
+ });
6247
+ }
6248
+ _syncItemStates() {
6249
+ for (const el of this.querySelectorAll(ITEM_SELECTOR)) {
6250
+ el.toggleAttribute(`data-tickled`, this.tickled.isTickled(el));
6251
+ el.toggleAttribute(`data-selected`, this._selectedItems.has(el));
6252
+ if (this.interactionMode === `checked`) el.toggleAttribute(`data-checked`, this._selectedItems.has(el));
6253
+ else el.removeAttribute(`data-checked`);
6294
6254
  }
6255
+ this.dataset.inputMode = this.tickled.inputMode;
6256
+ this._syncCheckboxes();
6295
6257
  }
6296
- #onOutgoingEnd;
6297
- #onLastCharOut;
6298
- #renderCharSwap() {
6299
- const charDuration = Math.round(this.duration * .3);
6300
- const charStagger = Math.round(this.duration * .1);
6301
- const currentChars = this._currentText.split(``);
6302
- const outgoingChars = this._outgoingText.split(``);
6303
- const lastIdx = outgoingChars.length - 1;
6304
- const charStyle = (i) => `animation-duration:${charDuration}ms;animation-delay:${i * charStagger}ms;animation-timing-function:${this.easing}`;
6305
- return html`
6306
- ${keyed(`cc${this._transitionId}`, html`
6307
- <span class="layer current char-swap">
6308
- ${currentChars.map((ch, i) => html`<span class="char in" style=${charStyle(i)}>${ch}</span>`)}
6309
- </span>
6310
- `)}
6311
- ${this._outgoingText ? keyed(this._transitionId, html`
6312
- <span class="layer outgoing char-swap">
6313
- ${outgoingChars.map((ch, i) => html`<span
6314
- class="char out"
6315
- style=${charStyle(i)}
6316
- @animationend=${i === lastIdx ? this.#onLastCharOut : void 0}
6317
- >${ch}</span>`)}
6318
- </span>
6319
- `) : nothing}
6320
- `;
6258
+ _syncCheckboxes() {
6259
+ const inCheckedMode = this.interactionMode === `checked`;
6260
+ if (inCheckedMode) for (const inner of Array.from(this.children)) {
6261
+ if (!inner.hasAttribute(`data-list-item`)) continue;
6262
+ if (inner.parentElement !== this) continue;
6263
+ const wrapper = document.createElement(`li`);
6264
+ wrapper.className = `ixfx-custom-row`;
6265
+ const key = inner.getAttribute(`data-key`);
6266
+ const label = inner.getAttribute(`data-search-label`);
6267
+ if (key !== null) wrapper.setAttribute(`data-key`, key);
6268
+ if (label !== null) wrapper.setAttribute(`data-search-label`, label);
6269
+ inner.removeAttribute(`data-list-item`);
6270
+ this.insertBefore(wrapper, inner);
6271
+ wrapper.appendChild(inner);
6272
+ this.#customWrappers.set(wrapper, inner);
6273
+ }
6274
+ else {
6275
+ for (const [wrapper, inner] of this.#customWrappers) {
6276
+ if (wrapper.parentElement !== this) continue;
6277
+ inner.setAttribute(`data-list-item`, ``);
6278
+ this.insertBefore(inner, wrapper);
6279
+ wrapper.remove();
6280
+ }
6281
+ this.#customWrappers.clear();
6282
+ }
6283
+ for (const el of this.querySelectorAll(`li`)) {
6284
+ let cb = el.querySelector(`input.ixfx-list-checkbox`);
6285
+ if (inCheckedMode) {
6286
+ if (!cb) {
6287
+ cb = document.createElement(`input`);
6288
+ cb.type = `checkbox`;
6289
+ cb.className = `ixfx-list-checkbox`;
6290
+ cb.style.cssText = `flex-shrink:0;margin:0 6px 0 0;cursor:pointer;accent-color:var(--accent,#60a5fa);pointer-events:auto`;
6291
+ cb.tabIndex = -1;
6292
+ cb.addEventListener(`click`, (e) => {
6293
+ e.stopPropagation();
6294
+ this._toggleItem(el);
6295
+ });
6296
+ el.prepend(cb);
6297
+ }
6298
+ cb.checked = this._selectedItems.has(el);
6299
+ } else if (cb) cb.remove();
6300
+ }
6321
6301
  }
6322
- render() {
6323
- if (this._activeEffect === `character-swap`) return html`<span class="container">${this.#renderCharSwap()}</span>`;
6324
- const effect = this._activeEffect ?? ``;
6325
- const durStyle = this._activeEffect ? `animation-duration:${this.duration}ms;animation-timing-function:${this.easing}` : ``;
6326
- return html`
6327
- <span class="container">
6328
- ${this._outgoingText ? keyed(this._transitionId, html`
6329
- <span class="layer outgoing ${effect}" style=${durStyle} @animationend=${this.#onOutgoingEnd}>
6330
- ${this._outgoingText}
6331
- </span>
6332
- `) : nothing}
6333
- ${keyed(`c${this._transitionId}`, html`
6334
- <span class="layer current ${effect}" style=${durStyle}>
6335
- ${this._currentText}
6336
- </span>
6337
- `)}
6338
- </span>
6339
- `;
6302
+ _findListItem(path) {
6303
+ for (const target of path) {
6304
+ if (!(target instanceof Element)) continue;
6305
+ if (target === this) break;
6306
+ if (target.parentElement === this && target.matches(ITEM_SELECTOR)) return target;
6307
+ }
6308
+ }
6309
+ _dispatch(name, detail) {
6310
+ this.dispatchEvent(new CustomEvent(name, {
6311
+ detail,
6312
+ bubbles: true,
6313
+ composed: true
6314
+ }));
6315
+ }
6316
+ _openSearch() {
6317
+ this._searchVisible = true;
6318
+ this.updateComplete.then(() => this._searchInputEl?.focus());
6319
+ }
6320
+ _closeSearch() {
6321
+ this._searchVisible = false;
6322
+ this._searchQuery = ``;
6323
+ this.#search?.clearQuery();
6324
+ this.focus();
6325
+ }
6326
+ _activateItem(item) {
6327
+ if (this.interactionMode !== `manual`) this._replaceSelection(item);
6328
+ this._dispatch(`list-activate`, { item });
6340
6329
  }
6341
6330
  static {
6342
- this.styles = css`
6331
+ this.styles = [themeFallbacks, css`
6343
6332
  :host {
6344
- display: inline-block;
6345
- --transitory-label-easing: ease;
6346
- }
6347
-
6348
- .container {
6349
- display: inline-grid;
6333
+ display: block;
6334
+ position: relative;
6335
+ background: var(--list-bg, var(--surface-3));
6336
+ color: var(--list-text, var(--surface-3-text));
6337
+ border-radius: var(--list-radius, var(--radius-s));
6338
+ border: 1px solid var(--list-border, var(--border));
6339
+ width: 100%;
6340
+ height: 100%;
6350
6341
  overflow: hidden;
6342
+ box-sizing: border-box;
6343
+ outline: none;
6351
6344
  }
6352
6345
 
6353
- .layer {
6354
- grid-area: 1 / 1;
6355
- white-space: nowrap;
6346
+ :host(:focus-visible) {
6347
+ outline: 2px solid var(--accent);
6348
+ outline-offset: 2px;
6356
6349
  }
6357
6350
 
6358
- .layer.outgoing {
6359
- pointer-events: none;
6351
+ .container {
6352
+ position: relative;
6353
+ width: 100%;
6354
+ height: 100%;
6360
6355
  }
6361
6356
 
6362
- /* slide-right */
6363
- .layer.current.slide-right {
6364
- transform: translateX(-100%);
6365
- animation: tl-slide-in-left var(--transitory-label-easing) forwards;
6366
- }
6367
- .layer.outgoing.slide-right {
6368
- animation: tl-slide-out-right var(--transitory-label-easing) forwards;
6357
+ ul {
6358
+ list-style: none;
6359
+ margin: 0;
6360
+ padding: 0;
6361
+ width: 100%;
6362
+ height: 100%;
6363
+ overflow-y: auto;
6364
+ box-sizing: border-box;
6369
6365
  }
6370
6366
 
6371
- @keyframes tl-slide-in-left {
6372
- from { transform: translateX(-100%); }
6373
- to { transform: translateX(0); }
6374
- }
6375
- @keyframes tl-slide-out-right {
6376
- from { transform: translateX(0); }
6377
- to { transform: translateX(100%); }
6367
+ ::slotted([hidden]) {
6368
+ display: none !important;
6378
6369
  }
6379
6370
 
6380
- /* slide-left */
6381
- .layer.current.slide-left {
6382
- transform: translateX(100%);
6383
- animation: tl-slide-in-right var(--transitory-label-easing) forwards;
6384
- }
6385
- .layer.outgoing.slide-left {
6386
- animation: tl-slide-out-left var(--transitory-label-easing) forwards;
6371
+ ::slotted(li) {
6372
+ display: flex;
6373
+ align-items: center;
6374
+ padding: var(--list-item-padding, 4px var(--space-m, 8px));
6375
+ min-height: var(--list-item-height, 28px);
6376
+ cursor: pointer;
6377
+ user-select: none;
6378
+ transition: background var(--transition, 0.1s ease-out),
6379
+ outline-color var(--transition, 0.1s ease-out);
6380
+ box-sizing: border-box;
6381
+ outline: 1px solid transparent;
6387
6382
  }
6388
6383
 
6389
- @keyframes tl-slide-in-right {
6390
- from { transform: translateX(100%); }
6391
- to { transform: translateX(0); }
6392
- }
6393
- @keyframes tl-slide-out-left {
6394
- from { transform: translateX(0); }
6395
- to { transform: translateX(-100%); }
6384
+ /* Custom shadow-DOM components handle their own internal layout/padding */
6385
+ ::slotted([data-list-item]) {
6386
+ display: block;
6387
+ cursor: pointer;
6388
+ user-select: none;
6389
+ transition: background var(--transition, 0.1s ease-out),
6390
+ outline-color var(--transition, 0.1s ease-out);
6391
+ outline: 1px solid transparent;
6396
6392
  }
6397
6393
 
6398
- /* slide-up */
6399
- .layer.current.slide-up {
6400
- transform: translateY(100%);
6401
- animation: tl-slide-in-bottom var(--transitory-label-easing) forwards;
6402
- }
6403
- .layer.outgoing.slide-up {
6404
- animation: tl-slide-out-top var(--transitory-label-easing) forwards;
6394
+ ::slotted([data-tickled]) {
6395
+ background: var(--item-bg-tickled);
6396
+ outline: var(--item-border-tickled);
6405
6397
  }
6406
6398
 
6407
- @keyframes tl-slide-in-bottom {
6408
- from { transform: translateY(100%); }
6409
- to { transform: translateY(0); }
6399
+ ::slotted([data-selected]) {
6400
+ background: var(--item-bg-selected);
6401
+ color: var(--item-text-selected);
6402
+ outline: 1px solid transparent;
6410
6403
  }
6411
- @keyframes tl-slide-out-top {
6412
- from { transform: translateY(0); }
6413
- to { transform: translateY(-100%); }
6404
+
6405
+ ::slotted([data-selected][data-tickled]) {
6406
+ background: var(--item-bg-selected-tickled);
6407
+ outline: 2px dashed var(--surface-3);
6408
+ outline-offset: -2px;
6414
6409
  }
6415
6410
 
6416
- /* slide-down */
6417
- .layer.current.slide-down {
6418
- transform: translateY(-100%);
6419
- animation: tl-slide-in-top var(--transitory-label-easing) forwards;
6411
+ /* checked mode: checkbox (injected into li) communicates selection — suppress bg highlight */
6412
+ :host([interaction-mode="checked"]) ::slotted([data-selected]) {
6413
+ background: transparent;
6414
+ color: inherit;
6415
+ outline: 1px solid transparent;
6420
6416
  }
6421
- .layer.outgoing.slide-down {
6422
- animation: tl-slide-out-bottom var(--transitory-label-easing) forwards;
6417
+
6418
+ :host([interaction-mode="checked"]) ::slotted([data-selected][data-tickled]) {
6419
+ background: var(--item-bg-tickled);
6420
+ color: inherit;
6421
+ outline: var(--item-border-tickled);
6423
6422
  }
6424
6423
 
6425
- @keyframes tl-slide-in-top {
6426
- from { transform: translateY(-100%); }
6427
- to { transform: translateY(0); }
6424
+ .search-overlay {
6425
+ position: absolute;
6426
+ top: 8px;
6427
+ right: 8px;
6428
+ z-index: 10;
6429
+ display: flex;
6430
+ align-items: center;
6431
+ gap: 4px;
6432
+ background: var(--surface-4, #2a2a2a);
6433
+ border: 1px solid var(--border, #444);
6434
+ border-radius: var(--radius-m, 4px);
6435
+ padding: 4px 6px;
6436
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
6428
6437
  }
6429
- @keyframes tl-slide-out-bottom {
6430
- from { transform: translateY(0); }
6431
- to { transform: translateY(100%); }
6438
+
6439
+ .search-overlay[hidden] {
6440
+ display: none;
6432
6441
  }
6433
6442
 
6434
- /* fade */
6435
- .layer.current.fade {
6436
- opacity: 0;
6437
- animation: tl-fade-in var(--transitory-label-easing) forwards;
6443
+ .search-input {
6444
+ background: transparent;
6445
+ border: none;
6446
+ outline: none;
6447
+ color: inherit;
6448
+ font-size: var(--text-m, 0.875em);
6449
+ min-width: 140px;
6438
6450
  }
6439
- .layer.outgoing.fade {
6440
- animation: tl-fade-out var(--transitory-label-easing) forwards;
6451
+
6452
+ .search-close {
6453
+ background: transparent;
6454
+ border: none;
6455
+ color: var(--surface-muted-text, #888);
6456
+ cursor: pointer;
6457
+ font-size: 1.1em;
6458
+ line-height: 1;
6459
+ padding: 0 2px;
6441
6460
  }
6442
6461
 
6443
- @keyframes tl-fade-in {
6444
- from { opacity: 0; }
6445
- to { opacity: 1; }
6462
+ .search-close:hover {
6463
+ color: inherit;
6446
6464
  }
6447
- @keyframes tl-fade-out {
6448
- from { opacity: 1; }
6449
- to { opacity: 0; }
6465
+ `];
6466
+ }
6467
+ render() {
6468
+ return html`
6469
+ <div class="container">
6470
+ <ul part="list">
6471
+ <slot></slot>
6472
+ </ul>
6473
+ <div
6474
+ class="search-overlay"
6475
+ part="search-overlay"
6476
+ ?hidden=${!this._searchVisible}
6477
+ >
6478
+ <input
6479
+ type="text"
6480
+ class="search-input"
6481
+ placeholder="Search…"
6482
+ .value=${this._searchQuery}
6483
+ @input=${this._onSearchInput}
6484
+ @keydown=${this._onSearchKeydown}
6485
+ />
6486
+ <button class="search-close" @click=${this._closeSearch} title="Close search (Esc)">×</button>
6487
+ </div>
6488
+ </div>
6489
+ `;
6490
+ }
6491
+ };
6492
+ __decorate([property({
6493
+ type: String,
6494
+ attribute: `selection-mode`
6495
+ })], VerticalListElement.prototype, "selectionMode", void 0);
6496
+ __decorate([property({
6497
+ type: String,
6498
+ attribute: `interaction-mode`
6499
+ })], VerticalListElement.prototype, "interactionMode", void 0);
6500
+ __decorate([property({ attribute: false })], VerticalListElement.prototype, "filterPredicate", void 0);
6501
+ __decorate([state()], VerticalListElement.prototype, "_selectedItems", void 0);
6502
+ __decorate([state()], VerticalListElement.prototype, "_searchVisible", void 0);
6503
+ __decorate([state()], VerticalListElement.prototype, "_searchQuery", void 0);
6504
+ __decorate([query(`.search-input`)], VerticalListElement.prototype, "_searchInputEl", void 0);
6505
+ VerticalListElement = __decorate([safeCustomElement(`ixfx-vertical-list`)], VerticalListElement);
6506
+ //#endregion
6507
+ //#region src/grouped-item-lister/vertical-list-adapter.ts
6508
+ /**
6509
+ * Creates an `HTMLElement` that implements `IGroupedSubComponent<T>` by wrapping
6510
+ * an `ixfx-vertical-list` internally.
6511
+ *
6512
+ * Items are typed as `T`. The `renderItem` function converts each item to a DOM
6513
+ * element (typically an `<li>`) that `ixfx-vertical-list` renders and handles
6514
+ * pointer/keyboard interaction for.
6515
+ *
6516
+ * The returned element bridges the `list-*` event names fired by
6517
+ * `ixfx-vertical-list` to the `select / activate / item-click / tickle` names
6518
+ * required by `IGroupedSubComponent`, and maps element-based selection sets back
6519
+ * to typed `T` values.
6520
+ *
6521
+ * @example Basic usage with ixfx-grouped-item-lister:
6522
+ * ```ts
6523
+ * lister.factory = () =>
6524
+ * createVerticalListAdapter<MyItem>(item => {
6525
+ * const li = document.createElement('li');
6526
+ * li.textContent = item.label;
6527
+ * return li;
6528
+ * });
6529
+ * ```
6530
+ */
6531
+ function createVerticalListAdapter(renderItem, options) {
6532
+ const container = document.createElement(`div`);
6533
+ container.style.cssText = `display:contents;`;
6534
+ let listEl;
6535
+ let selectionMode = options?.selectionMode ?? `single`;
6536
+ let elToItem = /* @__PURE__ */ new WeakMap();
6537
+ function getOrCreateList() {
6538
+ if (listEl) return listEl;
6539
+ listEl = document.createElement(`ixfx-vertical-list`);
6540
+ listEl.style.cssText = `height:auto;width:100%;`;
6541
+ listEl.selectionMode = selectionMode;
6542
+ if (options?.interactionMode) listEl.interactionMode = options.interactionMode;
6543
+ container.appendChild(listEl);
6544
+ attachBridgeListeners();
6545
+ return listEl;
6546
+ }
6547
+ function attachBridgeListeners() {
6548
+ listEl.addEventListener(`list-select`, (e) => {
6549
+ const detail = {
6550
+ selected: mapEls(e.detail.selected),
6551
+ previous: mapEls(e.detail.previous)
6552
+ };
6553
+ container.dispatchEvent(new CustomEvent(`select`, {
6554
+ detail,
6555
+ bubbles: true,
6556
+ composed: true
6557
+ }));
6558
+ });
6559
+ listEl.addEventListener(`list-activate`, (e) => {
6560
+ const item = elToItem.get(e.detail.item);
6561
+ if (item !== void 0) container.dispatchEvent(new CustomEvent(`activate`, {
6562
+ detail: { item },
6563
+ bubbles: true,
6564
+ composed: true
6565
+ }));
6566
+ });
6567
+ listEl.addEventListener(`list-item-click`, (e) => {
6568
+ const item = elToItem.get(e.detail.item);
6569
+ if (item !== void 0) container.dispatchEvent(new CustomEvent(`item-click`, {
6570
+ detail: { item },
6571
+ bubbles: true,
6572
+ composed: true
6573
+ }));
6574
+ });
6575
+ listEl.addEventListener(`list-tickle`, (e) => {
6576
+ const item = elToItem.get(e.detail.item);
6577
+ if (item !== void 0) container.dispatchEvent(new CustomEvent(`tickle`, {
6578
+ detail: { item },
6579
+ bubbles: true,
6580
+ composed: true
6581
+ }));
6582
+ });
6583
+ }
6584
+ function applyItems(items) {
6585
+ const list = getOrCreateList();
6586
+ list.clearItems();
6587
+ elToItem = /* @__PURE__ */ new WeakMap();
6588
+ for (const item of items) {
6589
+ const el = renderItem(item);
6590
+ elToItem.set(el, item);
6591
+ list.addItem(el);
6592
+ }
6593
+ }
6594
+ function mapEls(els) {
6595
+ const result = /* @__PURE__ */ new Set();
6596
+ for (const el of els) {
6597
+ const item = elToItem.get(el);
6598
+ if (item !== void 0) result.add(item);
6599
+ }
6600
+ return result;
6601
+ }
6602
+ const adapter = Object.assign(container, {
6603
+ setItems(items) {
6604
+ applyItems(items);
6605
+ },
6606
+ clearSelection() {
6607
+ listEl?.clearSelection();
6608
+ },
6609
+ dispatch(commandId, args) {
6610
+ options?.onDispatch?.(commandId, args, listEl);
6611
+ }
6612
+ });
6613
+ Object.defineProperties(adapter, {
6614
+ selectedItems: {
6615
+ get() {
6616
+ return listEl ? mapEls(listEl.selectedItems) : /* @__PURE__ */ new Set();
6617
+ },
6618
+ enumerable: true,
6619
+ configurable: true
6620
+ },
6621
+ selectionMode: {
6622
+ get() {
6623
+ return listEl?.selectionMode ?? selectionMode;
6624
+ },
6625
+ set(v) {
6626
+ selectionMode = v;
6627
+ if (listEl) listEl.selectionMode = v;
6628
+ },
6629
+ enumerable: true,
6630
+ configurable: true
6631
+ }
6632
+ });
6633
+ return adapter;
6634
+ }
6635
+ //#endregion
6636
+ //#region src/panel/panel-group.ts
6637
+ let PanelGroupElement = class PanelGroupElement extends LitElement {
6638
+ constructor(..._args) {
6639
+ super(..._args);
6640
+ this.orientation = `horizontal`;
6641
+ this.variant = `titlebar`;
6642
+ this.toggleInteraction = `implicit`;
6643
+ this.allowMultiple = false;
6644
+ this.gap = `var(--space-m)`;
6645
+ }
6646
+ _onPanelToggle(e) {
6647
+ const panel = e.target;
6648
+ if (panel.collapsed) return;
6649
+ if (this.allowMultiple) return;
6650
+ for (const p of this._panels) if (p !== panel) p.collapsed = true;
6651
+ }
6652
+ firstUpdated() {
6653
+ this.updateComplete.then(() => {
6654
+ this._propagateAll();
6655
+ });
6656
+ }
6657
+ updated(changed) {
6658
+ super.updated(changed);
6659
+ if (changed.has(`variant`) || changed.has(`toggleInteraction`) || changed.has(`orientation`)) this.updateComplete.then(() => {
6660
+ this._propagateAll();
6661
+ });
6662
+ }
6663
+ _propagateAll() {
6664
+ const invertedOrientation = this.orientation === `horizontal` ? `vertical` : `horizontal`;
6665
+ for (const panel of this._panels) {
6666
+ panel.setAttribute(`variant`, this.variant);
6667
+ panel.setAttribute(`toggle-interaction`, this.toggleInteraction);
6668
+ panel.setAttribute(`orientation`, invertedOrientation);
6669
+ }
6670
+ }
6671
+ render() {
6672
+ return html`
6673
+ <slot
6674
+ @toggle=${this._onPanelToggle}
6675
+ ></slot>
6676
+ `;
6677
+ }
6678
+ static {
6679
+ this.styles = css`
6680
+ :host {
6681
+ display: flex;
6682
+ flex-direction: column;
6683
+ gap: var(--group-gap, var(--space-m));
6450
6684
  }
6451
6685
 
6452
- /* character-swap */
6453
- .char {
6454
- display: inline-block;
6686
+ :host([orientation="horizontal"]) {
6687
+ flex-direction: row;
6688
+ align-items: flex-start;
6689
+ flex-wrap: wrap;
6455
6690
  }
6456
6691
 
6457
- .char.in {
6458
- opacity: 0;
6459
- animation: tl-char-in var(--transitory-label-easing) forwards;
6692
+ :host([orientation="vertical"]) {
6693
+ flex-direction: column;
6460
6694
  }
6461
6695
 
6462
- .char.out {
6463
- animation: tl-char-out var(--transitory-label-easing) forwards;
6696
+ ::slotted(ixfx-panel) {
6697
+ flex-shrink: 1;
6464
6698
  }
6465
6699
 
6466
- @keyframes tl-char-in {
6467
- from { opacity: 0; transform: translateY(-0.3em) scale(0.8); }
6468
- to { opacity: 1; transform: translateY(0) scale(1); }
6469
- }
6470
- @keyframes tl-char-out {
6471
- from { opacity: 1; transform: translateY(0) scale(1); }
6472
- to { opacity: 0; transform: translateY(0.3em) scale(0.8); }
6700
+ :host([orientation="horizontal"]) ::slotted(ixfx-panel) {
6701
+ flex-basis: content;
6702
+ min-width: 0;
6473
6703
  }
6474
6704
  `;
6475
6705
  }
6476
6706
  };
6477
- __decorate([property({ type: String })], TransitoryLabelElement.prototype, "text", void 0);
6478
- __decorate([property({ type: String })], TransitoryLabelElement.prototype, "effect", void 0);
6479
- __decorate([property({ type: Number })], TransitoryLabelElement.prototype, "duration", void 0);
6480
- __decorate([property({ type: String })], TransitoryLabelElement.prototype, "easing", void 0);
6481
- __decorate([state()], TransitoryLabelElement.prototype, "_currentText", void 0);
6482
- __decorate([state()], TransitoryLabelElement.prototype, "_outgoingText", void 0);
6483
- __decorate([state()], TransitoryLabelElement.prototype, "_activeEffect", void 0);
6484
- __decorate([state()], TransitoryLabelElement.prototype, "_transitionId", void 0);
6485
- TransitoryLabelElement = __decorate([safeCustomElement(`ixfx-transitory-label`)], TransitoryLabelElement);
6707
+ __decorate([property({
6708
+ type: String,
6709
+ reflect: true
6710
+ })], PanelGroupElement.prototype, "orientation", void 0);
6711
+ __decorate([property({ type: String })], PanelGroupElement.prototype, "variant", void 0);
6712
+ __decorate([property({
6713
+ type: String,
6714
+ attribute: `toggle-interaction`
6715
+ })], PanelGroupElement.prototype, "toggleInteraction", void 0);
6716
+ __decorate([property({
6717
+ type: Boolean,
6718
+ attribute: `allow-multiple`
6719
+ })], PanelGroupElement.prototype, "allowMultiple", void 0);
6720
+ __decorate([property()], PanelGroupElement.prototype, "gap", void 0);
6721
+ __decorate([queryAssignedElements({ slot: `` })], PanelGroupElement.prototype, "_panels", void 0);
6722
+ PanelGroupElement = __decorate([safeCustomElement(`ixfx-panel-group`)], PanelGroupElement);
6486
6723
  //#endregion
6487
- //#region src/util/checkbox.ts
6488
- function isCheckboxLike(el) {
6489
- if (!(el instanceof HTMLElement)) return false;
6490
- return `checked` in el;
6491
- }
6492
- function resolveElement(elOrQuery) {
6493
- if (typeof elOrQuery === `string`) {
6494
- const found = document.querySelector(elOrQuery);
6495
- if (!(found instanceof HTMLElement)) throw new Error(`Element not found or not HTMLElement: ${elOrQuery}`);
6496
- return found;
6497
- }
6498
- return elOrQuery;
6499
- }
6500
- function monitorIndeterminate(targetElOrQuery, watchedElsOrQueries) {
6501
- const target = resolveElement(targetElOrQuery);
6502
- if (!isCheckboxLike(target)) throw new Error(`Target element is not a checkbox-like element`);
6503
- const watched = [];
6504
- for (const elOrQuery of watchedElsOrQueries) {
6505
- const el = resolveElement(elOrQuery);
6506
- if (isCheckboxLike(el)) watched.push(el);
6507
- }
6508
- const updateTarget = () => {
6509
- if (watched.length === 0) {
6510
- target.checked = false;
6511
- target.indeterminate = false;
6512
- return;
6513
- }
6514
- let checkedCount = 0;
6515
- let uncheckedCount = 0;
6516
- for (const el of watched) if (el.checked) checkedCount++;
6517
- else uncheckedCount++;
6518
- if (checkedCount > 0 && uncheckedCount > 0) {
6519
- target.checked = false;
6520
- target.indeterminate = true;
6521
- } else if (checkedCount === watched.length) {
6522
- target.checked = true;
6523
- target.indeterminate = false;
6524
- } else {
6525
- target.checked = false;
6526
- target.indeterminate = false;
6724
+ //#region src/util/drag.ts
6725
+ function getCoordinates(event) {
6726
+ return {
6727
+ client: {
6728
+ x: event.clientX,
6729
+ y: event.clientY
6730
+ },
6731
+ offset: {
6732
+ x: event.offsetX,
6733
+ y: event.offsetY
6527
6734
  }
6528
6735
  };
6529
- const handleChange = () => {
6530
- updateTarget();
6736
+ }
6737
+ function dragLogicStart(downEvent, handler) {
6738
+ const start = getCoordinates(downEvent);
6739
+ const onMove = (event) => {
6740
+ handler.progress(getCoordinates(event), start);
6531
6741
  };
6532
- for (const el of watched) el.addEventListener(`change`, handleChange);
6533
- updateTarget();
6534
- return () => {
6535
- for (const el of watched) el.removeEventListener(`change`, handleChange);
6742
+ const onUp = (event) => {
6743
+ document.removeEventListener(`pointermove`, onMove);
6744
+ document.removeEventListener(`pointerup`, onUp);
6745
+ handler.complete(getCoordinates(event), start);
6536
6746
  };
6747
+ document.addEventListener(`pointermove`, onMove);
6748
+ document.addEventListener(`pointerup`, onUp);
6537
6749
  }
6538
6750
  //#endregion
6539
- //#region src/util/is-numeric.ts
6540
- function isNumeric(str) {
6541
- if (typeof str === `number`) return true;
6542
- if (typeof str !== `string`) return false;
6543
- const trimmed = str.trim();
6544
- return trimmed !== `` && !Number.isNaN(Number(trimmed));
6751
+ //#region src/util/near.ts
6752
+ function near(target, range) {
6753
+ const min = target - range;
6754
+ const max = target + range;
6755
+ return (v) => v >= min && v <= max;
6545
6756
  }
6546
6757
  //#endregion
6547
- //#region src/util/tooltip.ts
6548
- var _TooltipElement;
6549
- let TooltipElement = class TooltipElement extends LitElement {
6550
- static {
6551
- _TooltipElement = this;
6552
- }
6758
+ //#region src/range/range-multi.ts
6759
+ let RangeMultiElement = class RangeMultiElement extends LitElement {
6553
6760
  constructor(..._args) {
6554
6761
  super(..._args);
6555
- this.valueFormatTooltip = _TooltipElement.defaultFormatter;
6556
- this.orientation = `top`;
6557
- this.anchor = `--tooltip`;
6762
+ this.tooltip = true;
6763
+ this.tooltipOrientation = `top`;
6764
+ this.crossover = `allow`;
6765
+ this.resizeMode = `dual`;
6766
+ this.orientation = `horizontal`;
6767
+ this.step = 1;
6768
+ this.a = 0;
6769
+ this.b = 50;
6770
+ this.#userMax = 100;
6771
+ this.#userMin = 0;
6772
+ this.#scaleTo100 = (v) => v;
6773
+ this.#scaleFrom100 = (v) => v;
6774
+ this.#userClamp = (v) => v;
6775
+ this.draggingThumb = `none`;
6558
6776
  }
6559
- static {
6560
- this.numberFormatter = (v) => Math.floor(v).toString();
6777
+ #userMax;
6778
+ #userMin;
6779
+ #scaleTo100;
6780
+ #scaleFrom100;
6781
+ #userClamp;
6782
+ #updateScale() {
6783
+ this.#scaleTo100 = scaler(this.#userMin, this.#userMax, 0, 100);
6784
+ this.#scaleFrom100 = scaler(0, 100, this.#userMin, this.#userMax);
6785
+ this.#userClamp = clamper(this.#userMin, this.#userMax);
6786
+ this.a = this.#userClamp(this.a);
6787
+ this.b = this.#userClamp(this.b);
6561
6788
  }
6562
- static {
6563
- this.defaultFormatter = (v) => {
6564
- if (typeof v === `number`) {
6565
- if (Number.isInteger(v)) return v.toString();
6566
- return v.toFixed(2);
6567
- } else if (typeof v === `string`) return v;
6568
- else return JSON.stringify(v);
6569
- };
6789
+ set max(v) {
6790
+ this.#userMax = v;
6791
+ this.#updateScale();
6570
6792
  }
6571
- #renderIcon() {
6572
- if (!this.icon) return nothing;
6573
- 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>`;
6574
- if (!getIcon(this.icon)) return nothing;
6575
- return html`<ixfx-icon class="tooltip-icon" style="margin-right:0.25em" name="${this.icon}"></ixfx-icon>`;
6793
+ get max() {
6794
+ return this.#userMax;
6576
6795
  }
6577
- render() {
6578
- const classes = {
6579
- "tooltip": true,
6580
- "tooltip-orientation-top": this.orientation === `top`,
6581
- "tooltip-orientation-bottom": this.orientation === `bottom`,
6582
- "tooltip-orientation-right": this.orientation === `right`,
6583
- "tooltip-orientation-left": this.orientation === `left`,
6584
- "tooltip-type-text": true,
6585
- "tooltip-type-number": false,
6586
- "tooltip-style-bubble": true
6587
- };
6588
- let value = ``;
6589
- switch (typeof this.value) {
6590
- case `number`:
6591
- classes[`tooltip-type-number`] = true;
6592
- value = this.valueFormatTooltip(this.value);
6593
- break;
6594
- case `string`:
6595
- if (isNumeric(this.value)) {
6596
- classes[`tooltip-type-number`] = true;
6597
- value = this.valueFormatTooltip(Number.parseFloat(this.value));
6598
- } else value = this.value;
6599
- break;
6600
- default: value = JSON.stringify(this.value);
6601
- }
6602
- return html`<output style="--anchor-id: ${this.anchor}" class=${classMap(classes)}>${this.#renderIcon()}${value}</output>`;
6796
+ set min(v) {
6797
+ this.#userMin = v;
6798
+ this.#updateScale();
6603
6799
  }
6604
- createRenderRoot() {
6605
- return this;
6800
+ get min() {
6801
+ return this.#userMin;
6606
6802
  }
6607
- };
6608
- __decorate([property({ type: String })], TooltipElement.prototype, "orientation", void 0);
6609
- __decorate([property({ type: String })], TooltipElement.prototype, "anchor", void 0);
6610
- __decorate([property()], TooltipElement.prototype, "value", void 0);
6611
- __decorate([property({ type: String })], TooltipElement.prototype, "icon", void 0);
6612
- TooltipElement = _TooltipElement = __decorate([safeCustomElement(`ixfx-tooltip`)], TooltipElement);
6613
- //#endregion
6614
- //#region src/vertical-list/vertical-list.ts
6615
- const ITEM_SELECTOR = `li, [data-list-item]`;
6616
- function isMultiMode(mode) {
6617
- return mode === `checked` || mode === `vscode` || mode === `standard`;
6618
- }
6619
- let VerticalListElement = class VerticalListElement extends LitElement {
6620
- constructor(..._args) {
6621
- super(..._args);
6622
- this.selectionMode = `single`;
6623
- this.interactionMode = `standard`;
6624
- this._selectedItems = /* @__PURE__ */ new Set();
6625
- this._searchVisible = false;
6626
- this._searchQuery = ``;
6627
- this.#customWrappers = /* @__PURE__ */ new Map();
6628
- this.tickled = new TickledController(this, {
6629
- getItems: () => this._getVisibleItems().map((el) => ({
6630
- id: el,
6631
- enabled: true
6632
- })),
6633
- onTickle: (id) => {
6634
- if (id !== void 0) this._dispatch(`list-tickle`, { item: id });
6635
- },
6636
- onStateChange: () => this._syncItemStates()
6637
- });
6638
- this._onPointerOver = (e) => {
6639
- const item = this._findListItem(e.composedPath());
6640
- if (item) this.tickled.handlePointerEnter(item);
6641
- };
6642
- this._onPointerLeave = (e) => {
6643
- this.tickled.handlePointerLeave(e);
6644
- };
6645
- this._onKeyDown = (e) => {
6646
- if ((e.ctrlKey || e.metaKey) && e.key === `f`) {
6647
- e.preventDefault();
6648
- this._openSearch();
6803
+ _onInput(event) {
6804
+ event.stopPropagation();
6805
+ const t = event.target;
6806
+ const v = this.#scaleFrom100(t.valueAsNumber);
6807
+ const which = t.id;
6808
+ let a = this.a;
6809
+ let b = this.b;
6810
+ if (this.resizeMode === `none`) {
6811
+ let panDelta = v - (which === `a` ? this.a : this.b);
6812
+ const newA = this.a + panDelta;
6813
+ const newB = this.b + panDelta;
6814
+ if (newA < this.min) panDelta = this.min - this.a;
6815
+ if (newB > this.max) panDelta = this.max - this.b;
6816
+ if (panDelta === 0) {
6817
+ t.valueAsNumber = this.#scaleTo100(which === `a` ? this.a : this.b);
6649
6818
  return;
6650
6819
  }
6651
- if ((e.ctrlKey || e.metaKey) && e.key === `a`) {
6652
- if ((this.selectionMode === `multiple` || isMultiMode(this.interactionMode)) && this.selectionMode !== `none`) {
6653
- e.preventDefault();
6654
- this._selectAll();
6820
+ a = this.a + panDelta;
6821
+ b = this.b + panDelta;
6822
+ } else if (this.resizeMode === `bipolar`) {
6823
+ let newA;
6824
+ let newB;
6825
+ if (which === `a`) {
6826
+ const delta = v - this.a;
6827
+ newA = v;
6828
+ newB = this.b - delta;
6829
+ } else {
6830
+ const delta = v - this.b;
6831
+ newA = this.a - delta;
6832
+ newB = v;
6833
+ }
6834
+ if (newA < this.min || newB > this.max || newA > this.max || newB < this.min) {
6835
+ t.valueAsNumber = this.#scaleTo100(which === `a` ? this.a : this.b);
6836
+ return;
6837
+ }
6838
+ a = newA;
6839
+ b = newB;
6840
+ } else if (this.resizeMode === `bipolar-flex`) {
6841
+ let newA;
6842
+ let newB;
6843
+ if (which === `a`) {
6844
+ newA = v;
6845
+ if (this.b <= this.min) newB = this.min;
6846
+ else if (this.b >= this.max) newB = this.max;
6847
+ else {
6848
+ const delta = v - this.a;
6849
+ newB = this.b - delta;
6850
+ }
6851
+ } else {
6852
+ newB = v;
6853
+ if (this.a <= this.min) newA = this.min;
6854
+ else if (this.a >= this.max) newA = this.max;
6855
+ else {
6856
+ const delta = v - this.b;
6857
+ newA = this.a - delta;
6655
6858
  }
6859
+ }
6860
+ if (newA < this.min) newA = this.min;
6861
+ if (newA > this.max) newA = this.max;
6862
+ if (newB < this.min) newB = this.min;
6863
+ if (newB > this.max) newB = this.max;
6864
+ if (newA > newB) {
6865
+ t.valueAsNumber = this.#scaleTo100(which === `a` ? this.a : this.b);
6656
6866
  return;
6657
6867
  }
6658
- if (this._searchVisible) return;
6659
- switch (e.key) {
6660
- case `ArrowDown`:
6661
- e.preventDefault();
6662
- this.tickled.handleKeyboardNavigation(`next`);
6663
- if (e.shiftKey && this.interactionMode === `vscode`) {
6664
- const cur = this.tickled.tickledId;
6665
- if (cur) this._rangeSelectTo(cur);
6868
+ a = newA;
6869
+ b = newB;
6870
+ } else if (which === `a`) if (v > this.b && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.a);
6871
+ else a = v;
6872
+ else if (which === `b`) if (v < a && this.crossover === `stop`) t.valueAsNumber = this.#scaleTo100(this.b);
6873
+ else b = v;
6874
+ else throw new Error(`Expected 'a' or 'b', got: '${t.id}'`);
6875
+ this.setPoles(a, b);
6876
+ }
6877
+ setPoles(a, b) {
6878
+ const aDiff = a !== this.a;
6879
+ const bDiff = b !== this.b;
6880
+ this.a = this.#userClamp(a);
6881
+ this.b = this.#userClamp(b);
6882
+ this.dispatchEvent(new CustomEvent(`input`, { detail: {
6883
+ a: this.a,
6884
+ b: this.b,
6885
+ changed: aDiff && bDiff ? `both` : aDiff ? `a` : `b`
6886
+ } }));
6887
+ }
6888
+ _onPointerDown(event) {
6889
+ const startA = this.a;
6890
+ const startB = this.b;
6891
+ this.valuesAtPointerDown = {
6892
+ a: startA,
6893
+ b: startB
6894
+ };
6895
+ const rect = event.target.getBoundingClientRect();
6896
+ const isVertical = this.orientation === `vertical`;
6897
+ const dim = isVertical ? rect.height : rect.width;
6898
+ const valuePerPix = dim / (this.max - this.min);
6899
+ const pos = isVertical ? event.offsetY : event.offsetX;
6900
+ const valueFromPos = (p) => {
6901
+ return isVertical ? this.max - p * valuePerPix : p * valuePerPix;
6902
+ };
6903
+ const posFromValue = (v) => {
6904
+ return isVertical ? dim - v * valuePerPix : v * valuePerPix;
6905
+ };
6906
+ const aPosPx = posFromValue(startA);
6907
+ const bPosPx = posFromValue(startB);
6908
+ if (isVertical ? (this.b < this.a ? pos > bPosPx : pos < bPosPx) || (this.b < this.a ? pos < aPosPx : pos > aPosPx) : this.b < this.a && pos < bPosPx || this.b > this.a && pos > bPosPx || this.a < this.b && pos < aPosPx || this.a > this.b && pos > aPosPx) {
6909
+ if (this.resizeMode === `none` || this.resizeMode === `bipolar` || this.resizeMode === `bipolar-flex`) {
6910
+ let panDelta = valueFromPos(pos) - this.b;
6911
+ if (this.a + panDelta < this.min) panDelta = this.min - this.a;
6912
+ if (this.b + panDelta > this.max) panDelta = this.max - this.b;
6913
+ const finalA = this.a + panDelta;
6914
+ const finalB = this.b + panDelta;
6915
+ if (finalA >= this.min && finalB <= this.max) this.setPoles(finalA, finalB);
6916
+ } else this.b = valueFromPos(pos);
6917
+ return;
6918
+ }
6919
+ const aPosPxNear = near(aPosPx, 10);
6920
+ const bPosPxNear = near(bPosPx, 10);
6921
+ const handleDrag = (draggingWhich) => {
6922
+ const setPoles = this.setPoles.bind(this);
6923
+ const resizeMode = this.resizeMode;
6924
+ const min = this.min;
6925
+ const max = this.max;
6926
+ const startPos = isVertical ? event.offsetY : event.offsetX;
6927
+ let polesChanged = false;
6928
+ dragLogicStart(event, {
6929
+ progress(current, _start) {
6930
+ const currentPos = isVertical ? current.offset.y : current.offset.x;
6931
+ const amt = (isVertical ? startPos - currentPos : currentPos - startPos) / valuePerPix;
6932
+ polesChanged = true;
6933
+ if (draggingWhich === `a`) if (resizeMode === `bipolar`) {
6934
+ const calcA = startA + amt;
6935
+ const calcB = startB - amt;
6936
+ if (calcA < min || calcB > max || calcA > max || calcB < min) return;
6937
+ setPoles(calcA, calcB);
6938
+ } else if (resizeMode === `bipolar-flex`) {
6939
+ let calcA = startA + amt;
6940
+ let calcB = startB;
6941
+ if (startB <= min) calcB = min;
6942
+ else if (startB >= max) calcB = max;
6943
+ else {
6944
+ calcA = startA + amt;
6945
+ calcB = startB - amt;
6946
+ }
6947
+ if (calcA < min) calcA = min;
6948
+ if (calcA > max) calcA = max;
6949
+ if (calcB < min) calcB = min;
6950
+ if (calcB > max) calcB = max;
6951
+ if (calcA > calcB) return;
6952
+ setPoles(calcA, calcB);
6953
+ } else {
6954
+ let constrainedAmt = amt;
6955
+ if (startA + amt < min) constrainedAmt = min - startA;
6956
+ if (startB + constrainedAmt > max) constrainedAmt = max - startB;
6957
+ const finalA = startA + constrainedAmt;
6958
+ const finalB = startB + constrainedAmt;
6959
+ if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
6666
6960
  }
6667
- break;
6668
- case `ArrowUp`:
6669
- e.preventDefault();
6670
- this.tickled.handleKeyboardNavigation(`previous`);
6671
- if (e.shiftKey && this.interactionMode === `vscode`) {
6672
- const cur = this.tickled.tickledId;
6673
- if (cur) this._rangeSelectTo(cur);
6961
+ else if (draggingWhich === `b`) if (resizeMode === `bipolar`) {
6962
+ const calcA = startA - amt;
6963
+ const calcB = startB + amt;
6964
+ if (calcA < min || calcB > max || calcA > max || calcB < min) return;
6965
+ setPoles(calcA, calcB);
6966
+ } else if (resizeMode === `bipolar-flex`) {
6967
+ let calcA = startA;
6968
+ let calcB = startB + amt;
6969
+ if (startA <= min) calcA = min;
6970
+ else if (startA >= max) calcA = max;
6971
+ else {
6972
+ calcA = startA - amt;
6973
+ calcB = startB + amt;
6974
+ }
6975
+ if (calcA < min) calcA = min;
6976
+ if (calcA > max) calcA = max;
6977
+ if (calcB < min) calcB = min;
6978
+ if (calcB > max) calcB = max;
6979
+ if (calcA > calcB) return;
6980
+ setPoles(calcA, calcB);
6981
+ } else {
6982
+ let constrainedAmt = amt;
6983
+ if (startA + amt < min) constrainedAmt = min - startA;
6984
+ if (startB + constrainedAmt > max) constrainedAmt = max - startB;
6985
+ const finalA = startA + constrainedAmt;
6986
+ const finalB = startB + constrainedAmt;
6987
+ if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
6674
6988
  }
6675
- break;
6676
- case `Enter`: {
6677
- const id = this.tickled.tickledId;
6678
- if (id) {
6679
- e.preventDefault();
6680
- this._dispatch(`list-item-click`, { item: id });
6681
- this._activateItem(id);
6989
+ else if (resizeMode === `bipolar`) {
6990
+ const calcA = startA + amt;
6991
+ const calcB = startB + amt;
6992
+ if (calcA < min || calcB > max) return;
6993
+ setPoles(calcA, calcB);
6994
+ } else if (resizeMode === `bipolar-flex`) {
6995
+ let calcA = startA + amt;
6996
+ let calcB = startB + amt;
6997
+ if (calcA < min) {
6998
+ calcA = min;
6999
+ calcB = min + (startB - startA);
7000
+ } else if (calcB > max) {
7001
+ calcB = max;
7002
+ calcA = max - (startB - startA);
7003
+ }
7004
+ if (calcA < min || calcB > max || calcA > calcB) return;
7005
+ setPoles(calcA, calcB);
7006
+ } else {
7007
+ let constrainedAmt = amt;
7008
+ if (startA + amt < min) constrainedAmt = min - startA;
7009
+ if (startB + constrainedAmt > max) constrainedAmt = max - startB;
7010
+ const finalA = startA + constrainedAmt;
7011
+ const finalB = startB + constrainedAmt;
7012
+ if (finalA >= min && finalB <= max) setPoles(finalA, finalB);
6682
7013
  }
6683
- break;
6684
- }
6685
- case ` `: {
6686
- const id = this.tickled.tickledId;
6687
- if (id) {
6688
- e.preventDefault();
6689
- this._handleSpaceKey(id);
7014
+ },
7015
+ complete(_final, _start) {
7016
+ if (!polesChanged) {
7017
+ const currentPos = isVertical ? event.offsetY : event.offsetX;
7018
+ if (Math.abs(currentPos - aPosPx) < Math.abs(currentPos - bPosPx)) setPoles(valueFromPos(currentPos), startB);
7019
+ else setPoles(startA, valueFromPos(currentPos));
6690
7020
  }
6691
- break;
6692
- }
6693
- case `Escape`:
6694
- this._clearSelection();
6695
- break;
6696
- }
6697
- };
6698
- this._onClick = (e) => {
6699
- const item = this._findListItem(e.composedPath());
6700
- if (!item) return;
6701
- this._dispatch(`list-item-click`, { item });
6702
- this._handleClickSelection(item, e);
6703
- };
6704
- this._onDblClick = (e) => {
6705
- const item = this._findListItem(e.composedPath());
6706
- if (item) this._activateItem(item);
6707
- };
6708
- this._onSearchInput = (e) => {
6709
- const input = e.target;
6710
- this._searchQuery = input.value;
6711
- this.#search?.setQuery(this._searchQuery);
6712
- };
6713
- this._onSearchKeydown = (e) => {
6714
- if (e.key === `Escape`) {
6715
- e.stopPropagation();
6716
- this._closeSearch();
6717
- } else if (e.key === `ArrowDown`) {
6718
- e.preventDefault();
6719
- this.tickled.handleKeyboardNavigation(`next`);
6720
- } else if (e.key === `ArrowUp`) {
6721
- e.preventDefault();
6722
- this.tickled.handleKeyboardNavigation(`previous`);
6723
- } else if (e.key === `Enter`) {
6724
- e.preventDefault();
6725
- e.stopPropagation();
6726
- const id = this.tickled.tickledId ?? this._getVisibleItems()[0];
6727
- if (id) {
6728
- this._dispatch(`list-item-click`, { item: id });
6729
- this._activateItem(id);
6730
- this._closeSearch();
6731
7021
  }
6732
- }
7022
+ });
6733
7023
  };
7024
+ if (aPosPxNear(pos)) {
7025
+ this.draggingThumb = `a`;
7026
+ if (this.resizeMode === `dual`) return false;
7027
+ event.preventDefault();
7028
+ event.target.setPointerCapture(event.pointerId);
7029
+ handleDrag(`a`);
7030
+ return;
7031
+ } else if (bPosPxNear(pos)) {
7032
+ this.draggingThumb = `b`;
7033
+ if (this.resizeMode === `dual`) return false;
7034
+ event.preventDefault();
7035
+ event.target.setPointerCapture(event.pointerId);
7036
+ handleDrag(`b`);
7037
+ return;
7038
+ } else this.draggingThumb = `none`;
7039
+ event.preventDefault();
7040
+ event.target.setPointerCapture(event.pointerId);
7041
+ handleDrag(`none`);
7042
+ }
7043
+ firstUpdated(_changedProperties) {
7044
+ this.#updateScale();
7045
+ }
7046
+ render() {
7047
+ const ttA = this.tooltip ? html`<ixfx-tooltip style="--tooltip-background: var(--surface-5); --tooltip-color: var(--surface-5-text)" anchor="--a-tooltip" .orientation=${this.tooltipOrientation} .value=${this.a}></ixfx-tooltip>` : nothing;
7048
+ const ttB = this.tooltip ? html`<ixfx-tooltip style="--tooltip-background: var(--surface-5); --tooltip-color: var(--surface-5-text)" anchor="--b-tooltip" .orientation=${this.tooltipOrientation} .value=${this.b}></ixfx-tooltip>` : nothing;
7049
+ const scaledA = this.#scaleTo100(this.a);
7050
+ const scaledB = this.#scaleTo100(this.b);
7051
+ const verticalStyle = this.orientation === `vertical` ? `writing-mode: vertical-lr; direction: rtl;` : nothing;
7052
+ return html`
7053
+ <div @pointerdown=${this._onPointerDown} @input=${this._onInput} style="--a: ${scaledA}; --b: ${scaledB}">
7054
+ <input class="thumb-round" .value=${scaledA} id="a" step=${this.step} type="range" style="${verticalStyle}" anchor="--a-tooltip" />
7055
+ ${ttA}
7056
+
7057
+ <input class="thumb-round" .value=${scaledB} id="b" step=${this.step} type="range" style="${verticalStyle}" anchor="--b-tooltip" />
7058
+ ${ttB}
7059
+ </div>`;
7060
+ }
7061
+ static {
7062
+ this.styles = [
7063
+ themeFallbacks,
7064
+ tooltipValueStyles,
7065
+ prominenceStyles,
7066
+ css`
7067
+ :host {
7068
+ display: grid;
7069
+ --value-label-color: unset;
7070
+
7071
+ --range-background: AccentColor;
7072
+ --range-height: 1.5em;
7073
+ --range-thickness: 1em;
7074
+ --thumb-background: ButtonFace;
7075
+ --thumb-radius: 50%;
7076
+ --thumb-width: 1em;
7077
+ --thumb-height: 1em;
7078
+ --js:1;
7079
+ }
7080
+
7081
+ :host([orientation="vertical"]) {
7082
+ display: block;
7083
+ width: 1.5em;
7084
+ height: 200px;
7085
+ }
7086
+
7087
+ * {
7088
+ margin: 0;
7089
+ padding: 0;
7090
+ font: inherit;
7091
+ }
7092
+
7093
+ div {
7094
+ --j: var(--js, 0);
7095
+ display:inline grid;
7096
+ align-content: end;
7097
+ grid-gap: 0.25em;
7098
+ place-self: center;
7099
+ min-width: 8em;
7100
+ width: calc(100% - 1.5em);
7101
+ height: 1.5rem;
7102
+ }
7103
+
7104
+ :host([orientation="vertical"]) div {
7105
+ width: 1.5rem;
7106
+ height: calc(100% - 1.5em);
7107
+ min-width: unset;
7108
+ min-height: 8em;
7109
+ }
7110
+
7111
+ div::before, div::after {
7112
+ margin: 0.5rem 0.6875rem;
7113
+ border-radius: 0.25rem;
7114
+ box-shadow: none;
7115
+ background: var(--surface-4);
7116
+ content: "";
7117
+ }
7118
+ :host([orientation="vertical"]) div::before,
7119
+ :host([orientation="vertical"]) div::after {
7120
+ margin: 0.5rem 0;
7121
+ }
7122
+ div::after {
7123
+ --or: calc((100 - Max(var(--a), var(--b)))*1%);
7124
+ --ol: calc(Min(var(--a), var(--b))*1%);
7125
+ box-shadow: none;
7126
+ background: var(--accent);
7127
+ clip-path: inset(0 var(--or) 0 var(--ol));
7128
+ }
7129
+ :host([orientation="vertical"]) div::after {
7130
+ clip-path: inset(var(--or) 0 var(--ol) 0);
7131
+ }
7132
+ div input, div::before, div::after {
7133
+ grid-area: calc(1 + var(--j))/1;
7134
+ }
7135
+ div output, div::after {
7136
+ display:'none';
7137
+ }
7138
+
7139
+ [type=range] {
7140
+ width: 100%;
7141
+ height: var(--range-height);
7142
+ background: transparent;
7143
+ pointer-events: none;
7144
+ }
7145
+
7146
+ :host([orientation="vertical"]) [type=range] {
7147
+ writing-mode: vertical-lr;
7148
+ direction: rtl;
7149
+ width: var(--range-height);
7150
+ height: 100%;
7151
+ }
7152
+
7153
+ [type=range], [type=range]::-webkit-slider-runnable-track, [type=range]::-webkit-slider-thumb {
7154
+ -webkit-appearance: none;
7155
+ }
7156
+ [type=range], [type=range] + ixfx-tooltip {
7157
+ --sel: 0;
7158
+ z-index: calc(1 + var(--sel));
7159
+ }
7160
+ [type=range]::-webkit-slider-runnable-track {
7161
+ background: transparent;
7162
+ }
7163
+ [type=range]::-moz-range-track {
7164
+ background: transparent;
7165
+ }
7166
+
7167
+ input.thumb-round::-webkit-slider-thumb {
7168
+ width: var(--thumb-width);
7169
+ height: var(--thumb-height);
7170
+ border-radius: var(--thumb-radius);
7171
+ }
7172
+
7173
+ [type=range]::-webkit-slider-thumb {
7174
+ box-sizing: border-box;
7175
+ border: solid calc(0.5rem + -1px) transparent;
7176
+
7177
+ /* box-shadow: var(--shadow-m); */
7178
+ background: var(--thumb-background);
7179
+ pointer-events: auto;
7180
+ cursor: ew-resize;
7181
+ }
7182
+
7183
+ :host([orientation="vertical"]) [type=range]::-webkit-slider-thumb {
7184
+ width: var(--thumb-height);
7185
+ height: var(--thumb-width);
7186
+ cursor: ns-resize;
7187
+ }
7188
+
7189
+ [type=range]::-moz-range-thumb {
7190
+ box-sizing: border-box;
7191
+ border: solid calc(0.5rem + -1px) transparent;
7192
+ width: 1.375rem;
7193
+ height: 1.375rem;
7194
+ border-radius: 50%;
7195
+ box-shadow: var(--shadow-m);
7196
+ background: var(--thumb-background);
7197
+ pointer-events: auto;
7198
+ cursor: ew-resize;
7199
+ }
7200
+
7201
+ :host([orientation="vertical"]) [type=range]::-moz-range-thumb {
7202
+ cursor: ns-resize;
7203
+ }
7204
+
7205
+ [type=range]:focus {
7206
+ outline: none;
7207
+ }
7208
+ [type=range]:focus, [type=range]:focus + ixfx-tooltip, [type=range]:hover, [type=range]:hover + ixfx-tooltip {
7209
+ --sel: 1 ;
7210
+ }
7211
+ `
7212
+ ];
7213
+ }
7214
+ };
7215
+ __decorate([property({ type: Boolean })], RangeMultiElement.prototype, "tooltip", void 0);
7216
+ __decorate([property({
7217
+ type: String,
7218
+ attribute: `tooltip-orientation`
7219
+ })], RangeMultiElement.prototype, "tooltipOrientation", void 0);
7220
+ __decorate([property({ type: String })], RangeMultiElement.prototype, "crossover", void 0);
7221
+ __decorate([property({
7222
+ type: String,
7223
+ attribute: `resize-mode`
7224
+ })], RangeMultiElement.prototype, "resizeMode", void 0);
7225
+ __decorate([property({
7226
+ type: String,
7227
+ reflect: true
7228
+ })], RangeMultiElement.prototype, "orientation", void 0);
7229
+ __decorate([property()], RangeMultiElement.prototype, "step", void 0);
7230
+ __decorate([property({ type: Number })], RangeMultiElement.prototype, "a", void 0);
7231
+ __decorate([property({ type: Number })], RangeMultiElement.prototype, "b", void 0);
7232
+ __decorate([property({ type: Number })], RangeMultiElement.prototype, "max", null);
7233
+ __decorate([property({ type: Number })], RangeMultiElement.prototype, "min", null);
7234
+ __decorate([eventOptions({ capture: true })], RangeMultiElement.prototype, "_onInput", null);
7235
+ __decorate([eventOptions({ capture: true })], RangeMultiElement.prototype, "_onPointerDown", null);
7236
+ RangeMultiElement = __decorate([safeCustomElement(`ixfx-range-multi`)], RangeMultiElement);
7237
+ //#endregion
7238
+ //#region src/tabs/tab-list-item.ts
7239
+ let TabListItemElement = class TabListItemElement extends LitElement {
7240
+ constructor(..._args) {
7241
+ super(..._args);
7242
+ this.closeable = false;
7243
+ this.iconName = void 0;
7244
+ this.description = void 0;
7245
+ this.commandActive = void 0;
7246
+ this.registry = void 0;
7247
+ this._compact = false;
6734
7248
  }
6735
- #search;
6736
- #selectionAnchor;
6737
- #customWrappers;
6738
7249
  connectedCallback() {
6739
7250
  super.connectedCallback();
6740
- if (!this.hasAttribute(`tabindex`)) this.tabIndex = 0;
6741
- this.addEventListener(`pointerover`, this._onPointerOver);
6742
- this.addEventListener(`pointerleave`, this._onPointerLeave);
6743
- this.addEventListener(`keydown`, this._onKeyDown);
6744
- this.addEventListener(`click`, this._onClick);
6745
- this.addEventListener(`dblclick`, this._onDblClick);
7251
+ this._resizeObserver = new ResizeObserver(([entry]) => {
7252
+ this._compact = entry.contentRect.width < 64;
7253
+ });
7254
+ this._resizeObserver.observe(this);
6746
7255
  }
6747
7256
  disconnectedCallback() {
6748
7257
  super.disconnectedCallback();
6749
- this.removeEventListener(`pointerover`, this._onPointerOver);
6750
- this.removeEventListener(`pointerleave`, this._onPointerLeave);
6751
- this.removeEventListener(`keydown`, this._onKeyDown);
6752
- this.removeEventListener(`click`, this._onClick);
6753
- this.removeEventListener(`dblclick`, this._onDblClick);
6754
- this.#search?.dispose();
6755
- this.#search = void 0;
6756
- }
6757
- firstUpdated() {
6758
- this.#search = createElementIncrSearch({
6759
- container: this,
6760
- itemSelector: ITEM_SELECTOR,
6761
- getLabel: (el) => el.getAttribute(`data-search-label`) ?? el.textContent?.trim() ?? ``,
6762
- getKey: (el) => el.getAttribute(`data-key`) ?? el.getAttribute(`data-search-label`) ?? el.textContent?.trim() ?? ``,
6763
- highlightKey: `vertical-list-search`
6764
- });
7258
+ this._resizeObserver?.disconnect();
7259
+ this._resizeObserver = void 0;
7260
+ this._commandCleanup?.();
7261
+ this._commandCleanup = void 0;
6765
7262
  }
6766
7263
  updated(changed) {
6767
7264
  super.updated(changed);
6768
- if (changed.has(`interactionMode`)) {
6769
- this.#selectionAnchor = void 0;
6770
- const previousSelected = this._selectedItems;
6771
- const savedWrappers = changed.get(`interactionMode`) === `checked` ? new Map(this.#customWrappers) : null;
6772
- this._syncCheckboxes();
6773
- if (previousSelected.size > 0) {
6774
- let remapped;
6775
- if (savedWrappers && savedWrappers.size > 0) remapped = new Set([...previousSelected].map((el) => savedWrappers.get(el) ?? el));
6776
- else if (this.#customWrappers.size > 0) {
6777
- const innerToWrapper = new Map([...this.#customWrappers].map(([w, i]) => [i, w]));
6778
- remapped = new Set([...previousSelected].map((el) => innerToWrapper.get(el) ?? el));
6779
- } else remapped = new Set(previousSelected);
6780
- this._selectedItems = remapped;
6781
- }
6782
- this._syncItemStates();
7265
+ this._syncTooltipAttrs();
7266
+ if (changed.has(`registry`) || changed.has(`commandActive`)) this._syncCommandListener();
7267
+ }
7268
+ _syncTooltipAttrs() {
7269
+ if (this.description) {
7270
+ this.setAttribute(`data-tooltip`, this.description);
7271
+ this.setAttribute(`data-tooltip-anchor`, `top`);
7272
+ } else {
7273
+ this.removeAttribute(`data-tooltip`);
7274
+ this.removeAttribute(`data-tooltip-anchor`);
6783
7275
  }
6784
7276
  }
6785
- /** The most recently selected item, or `undefined` if nothing is selected. */
6786
- get selectedItem() {
6787
- return [...this._selectedItems].at(-1);
7277
+ _syncCommandListener() {
7278
+ this._commandCleanup?.();
7279
+ this._commandCleanup = void 0;
7280
+ if (this.registry && this.commandActive) this._commandCleanup = this.registry.addOnInvokeHandler((id) => {
7281
+ if (id === this.commandActive) this.click();
7282
+ });
6788
7283
  }
6789
- /** The full current selection set (read-only). */
6790
- get selectedItems() {
6791
- return this._selectedItems;
7284
+ render() {
7285
+ const showLabel = !this._compact || !this.iconName;
7286
+ return html`
7287
+ <div>
7288
+ ${this.iconName ? html`<ixfx-icon name="${this.iconName}"></ixfx-icon>` : nothing}
7289
+ ${showLabel ? html`<span class="label"><slot></slot></span>` : nothing}
7290
+ <div class="actions">
7291
+ <div class="toolbar"><slot name="toolbar"></slot></div>
7292
+ ${this.closeable ? html`
7293
+ <button
7294
+ class="close-btn"
7295
+ type="button"
7296
+ aria-label="Close tab"
7297
+ @click=${this._onCloseClick}
7298
+ >
7299
+ <ixfx-icon name="close"></ixfx-icon>
7300
+ </button>
7301
+ ` : nothing}
7302
+ </div>
7303
+ </div>
7304
+ `;
6792
7305
  }
6793
- addItem(item) {
6794
- if (typeof item === `string`) {
6795
- const li = document.createElement(`li`);
6796
- li.textContent = item;
6797
- this.appendChild(li);
6798
- } else this.appendChild(item);
6799
- if (this.interactionMode === `checked`) this._syncCheckboxes();
7306
+ _onCloseClick(e) {
7307
+ e.stopPropagation();
7308
+ this.dispatchEvent(new CustomEvent(`close`, {
7309
+ bubbles: true,
7310
+ composed: true
7311
+ }));
7312
+ this.remove();
6800
7313
  }
6801
- removeItem(item) {
6802
- item.remove();
7314
+ static {
7315
+ this.styles = [
7316
+ themeFallbacks,
7317
+ prominenceStyles,
7318
+ css`
7319
+ :host {
7320
+ --selected-colour: var(--accent);
7321
+ --selected-border-width: 1px;
7322
+ --padding: var(--space-m);
7323
+ display: inline-flex;
7324
+ min-width: 0;
7325
+ user-select: none;
7326
+ box-sizing: border-box;
7327
+ }
7328
+
7329
+ :host > div {
7330
+ display: flex;
7331
+ align-items: center;
7332
+ gap: var(--space-s, 4px);
7333
+ padding: var(--padding) calc(2 * var(--padding));
7334
+ min-width: 0;
7335
+ width: 100%;
7336
+ font-weight: 500;
7337
+ border: var(--selected-border-width) solid transparent;
7338
+ }
7339
+
7340
+ :host([selected]) > div {
7341
+ color: var(--selected-colour);
7342
+ border-top-color: var(--indicator-color-top, transparent);
7343
+ border-bottom-color: var(--indicator-color-bottom, transparent);
7344
+ border-left-color: var(--indicator-color-left, transparent);
7345
+ border-right-color: var(--indicator-color-right, transparent);
7346
+ }
7347
+
7348
+ .label {
7349
+ overflow: var(--allow-overflow, hidden);
7350
+ text-overflow: ellipsis;
7351
+ white-space: nowrap;
7352
+ min-width: 0;
7353
+ flex: 1 1 auto;
7354
+ }
7355
+
7356
+ ixfx-icon {
7357
+ flex-shrink: 0;
7358
+ }
7359
+
7360
+ .actions {
7361
+ display: flex;
7362
+ align-items: center;
7363
+ gap: var(--space-xs);
7364
+ margin-left: auto;
7365
+ flex-shrink: 0;
7366
+ }
7367
+
7368
+ .toolbar {
7369
+ display: none;
7370
+ align-items: center;
7371
+ gap: var(--space-xs);
7372
+ }
7373
+
7374
+ :host([selected]) .toolbar {
7375
+ display: flex;
7376
+ }
7377
+
7378
+ slot[name="toolbar"] {
7379
+ display: contents;
7380
+ }
7381
+
7382
+ .close-btn {
7383
+ display: inline-flex;
7384
+ align-items: center;
7385
+ justify-content: center;
7386
+ background: none;
7387
+ border: none;
7388
+ padding: var(--space-xs);
7389
+ cursor: pointer;
7390
+ color: inherit;
7391
+ border-radius: var(--radius-s);
7392
+ opacity: var(--prominence-idle-opacity);
7393
+ transition: opacity var(--transition), background var(--transition);
7394
+ }
7395
+
7396
+ .close-btn:hover {
7397
+ background: var(--surface-5);
7398
+ opacity: var(--prominence-tickled-opacity);
7399
+ }
7400
+
7401
+ .close-btn:focus-visible {
7402
+ outline: 2px solid var(--accent);
7403
+ outline-offset: 1px;
7404
+ }
7405
+
7406
+ :host([selected]) .close-btn,
7407
+ :host(:hover) .close-btn {
7408
+ opacity: var(--prominence-tickled-opacity);
7409
+ }
7410
+ `
7411
+ ];
6803
7412
  }
6804
- clearItems() {
6805
- this.#customWrappers.clear();
6806
- this.replaceChildren();
6807
- this.#selectionAnchor = void 0;
6808
- this._selectedItems = /* @__PURE__ */ new Set();
6809
- this._syncItemStates();
7413
+ };
7414
+ __decorate([property({ type: Boolean })], TabListItemElement.prototype, "closeable", void 0);
7415
+ __decorate([property({
7416
+ type: String,
7417
+ attribute: `icon-name`
7418
+ })], TabListItemElement.prototype, "iconName", void 0);
7419
+ __decorate([property({ type: String })], TabListItemElement.prototype, "description", void 0);
7420
+ __decorate([property({
7421
+ type: String,
7422
+ attribute: `command-active`
7423
+ })], TabListItemElement.prototype, "commandActive", void 0);
7424
+ __decorate([property({ attribute: false })], TabListItemElement.prototype, "registry", void 0);
7425
+ __decorate([state()], TabListItemElement.prototype, "_compact", void 0);
7426
+ TabListItemElement = __decorate([safeCustomElement(`ixfx-tab-list-item`)], TabListItemElement);
7427
+ //#endregion
7428
+ //#region src/tabs/tab-panel.ts
7429
+ let TabPanelElement = class TabPanelElement extends LitElement {
7430
+ render() {
7431
+ return html`<slot></slot>`;
6810
7432
  }
6811
- select(item) {
6812
- this._replaceSelection(item);
7433
+ static {
7434
+ this.styles = [themeFallbacks, css`
7435
+ :host {
7436
+ display:none;
7437
+ height:100%;
7438
+ width:100%;
7439
+ }
7440
+
7441
+ :host([selected]) {
7442
+ background: var(--surface-3);
7443
+ display:block;
7444
+ }
7445
+ `];
6813
7446
  }
6814
- selectMany(items) {
6815
- if (this.selectionMode !== `multiple`) throw new Error(`selectMany requires selectionMode="multiple" (current: "${this.selectionMode}")`);
6816
- const previous = this._selectedItems;
6817
- const next = new Set(items);
6818
- if (next.size === 0) return;
6819
- this._selectedItems = next;
6820
- this.#selectionAnchor = [...next].at(-1);
6821
- this._syncItemStates();
6822
- this._dispatch(`list-select`, {
6823
- selected: next,
6824
- previous
6825
- });
7447
+ };
7448
+ TabPanelElement = __decorate([safeCustomElement(`ixfx-tab-panel`)], TabPanelElement);
7449
+ //#endregion
7450
+ //#region src/tabs/tab-panels.ts
7451
+ let TabPanelsElement = class TabPanelsElement extends LitElement {
7452
+ render() {
7453
+ return html`<slot></slot>`;
6826
7454
  }
6827
- deselect(item) {
6828
- if (!this._selectedItems.has(item)) return;
6829
- const previous = this._selectedItems;
6830
- const next = new Set(this._selectedItems);
6831
- next.delete(item);
6832
- this._selectedItems = next;
6833
- this._syncItemStates();
6834
- this._dispatch(`list-select`, {
6835
- selected: next,
6836
- previous
6837
- });
7455
+ getSelectedElement() {
7456
+ for (const el of this._listItems) if (this.#isSelected(el)) return el;
6838
7457
  }
6839
- clearSelection() {
6840
- this._clearSelection();
7458
+ #isSelected(el) {
7459
+ return el.hasAttribute(`selected`);
6841
7460
  }
6842
- selectAll() {
6843
- if ((this.selectionMode === `multiple` || isMultiMode(this.interactionMode)) && this.selectionMode !== `none`) this._selectAll();
7461
+ #unselect(el) {
7462
+ el.removeAttribute(`selected`);
7463
+ if (this.onUnselectedPanel) this.onUnselectedPanel(el.id, el);
6844
7464
  }
6845
- _replaceSelection(item) {
6846
- if (this.selectionMode === `none`) return;
6847
- const previous = this._selectedItems;
6848
- const next = new Set([item]);
6849
- this._selectedItems = next;
6850
- this.#selectionAnchor = item;
6851
- this._syncItemStates();
6852
- this._dispatch(`list-select`, {
6853
- selected: next,
6854
- previous
6855
- });
7465
+ #select(el) {
7466
+ if (this.onSelectingPanel) this.onSelectingPanel(el.id, el);
7467
+ el.setAttribute(`selected`, ``);
7468
+ if (this.onSelectedPanel) this.onSelectedPanel(el.id, el);
6856
7469
  }
6857
- _toggleItem(item) {
6858
- const effectiveMultiple = this.selectionMode === `multiple` || isMultiMode(this.interactionMode);
6859
- if (this.selectionMode === `none` && this.interactionMode !== `checked`) return;
6860
- const previous = this._selectedItems;
6861
- const next = new Set(this._selectedItems);
6862
- if (next.has(item)) next.delete(item);
6863
- else {
6864
- if (!effectiveMultiple) next.clear();
6865
- next.add(item);
6866
- }
6867
- this._selectedItems = next;
6868
- this._syncItemStates();
6869
- this._dispatch(`list-select`, {
6870
- selected: next,
6871
- previous
6872
- });
7470
+ syncWithList(el) {
7471
+ const doSync = () => {
7472
+ const t = el.getSelectedElement();
7473
+ if (!t) return;
7474
+ const forEl = t.getAttribute(`for`);
7475
+ if (forEl) this.selectPanel(forEl);
7476
+ };
7477
+ Promise.all([el.updateComplete, this.updateComplete]).then(doSync);
6873
7478
  }
6874
- _rangeSelectTo(item) {
6875
- if (this.selectionMode === `none`) return;
6876
- if (!this.#selectionAnchor) {
6877
- this._replaceSelection(item);
6878
- return;
7479
+ selectPanel(id) {
7480
+ const current = this.getSelectedElement();
7481
+ if (current) {
7482
+ if (current.id === id) return;
7483
+ this.#unselect(current);
6879
7484
  }
6880
- const visible = this._getVisibleItems();
6881
- const anchorIdx = visible.indexOf(this.#selectionAnchor);
6882
- const targetIdx = visible.indexOf(item);
6883
- if (anchorIdx === -1 || targetIdx === -1) {
6884
- this._replaceSelection(item);
6885
- return;
7485
+ let found = false;
7486
+ for (const el of this._listItems) if (el.id === id) {
7487
+ this.#select(el);
7488
+ found = true;
6886
7489
  }
6887
- const start = Math.min(anchorIdx, targetIdx);
6888
- const end = Math.max(anchorIdx, targetIdx);
6889
- const previous = this._selectedItems;
6890
- const next = new Set(visible.slice(start, end + 1));
6891
- this._selectedItems = next;
6892
- this._syncItemStates();
6893
- this._dispatch(`list-select`, {
6894
- selected: next,
6895
- previous
6896
- });
6897
- }
6898
- _clearSelection() {
6899
- if (this._selectedItems.size === 0) return;
6900
- const previous = this._selectedItems;
6901
- this._selectedItems = /* @__PURE__ */ new Set();
6902
- this._syncItemStates();
6903
- this._dispatch(`list-select`, {
6904
- selected: /* @__PURE__ */ new Set(),
6905
- previous
6906
- });
6907
- }
6908
- _selectAll() {
6909
- const visible = this._getVisibleItems();
6910
- if (visible.length === 0) return;
6911
- const previous = this._selectedItems;
6912
- const next = new Set(visible);
6913
- this._selectedItems = next;
6914
- this._syncItemStates();
6915
- this._dispatch(`list-select`, {
6916
- selected: next,
6917
- previous
6918
- });
7490
+ return found;
6919
7491
  }
6920
- _handleClickSelection(item, e) {
6921
- const mode = this.interactionMode;
6922
- if (mode === `manual`) return;
6923
- if (this.selectionMode === `none` && mode !== `checked`) return;
6924
- switch (mode) {
6925
- case `implicit`:
6926
- this._replaceSelection(item);
6927
- break;
6928
- case `standard`:
6929
- case `vscode`:
6930
- if (e.ctrlKey || e.metaKey) {
6931
- if (this.selectionMode === `multiple` || mode === `vscode`) this._toggleItem(item);
6932
- } else if (e.shiftKey && (this.selectionMode === `multiple` || mode === `vscode`)) this._rangeSelectTo(item);
6933
- else this._replaceSelection(item);
6934
- break;
6935
- case `checked`: break;
6936
- }
7492
+ static {
7493
+ this.styles = css`
7494
+ :host {
7495
+ display: block;
7496
+ }
7497
+
7498
+ `;
6937
7499
  }
6938
- _handleSpaceKey(item) {
6939
- const mode = this.interactionMode;
6940
- if (mode === `manual`) return;
6941
- if (mode === `implicit`) this._replaceSelection(item);
6942
- else this._toggleItem(item);
7500
+ };
7501
+ __decorate([queryAssignedElements()], TabPanelsElement.prototype, "_listItems", void 0);
7502
+ TabPanelsElement = __decorate([safeCustomElement(`ixfx-tab-panels`)], TabPanelsElement);
7503
+ //#endregion
7504
+ //#region src/transitory-label/transitory-label.ts
7505
+ let TransitoryLabelElement = class TransitoryLabelElement extends LitElement {
7506
+ constructor(..._args) {
7507
+ super(..._args);
7508
+ this.text = ``;
7509
+ this.effect = `fade`;
7510
+ this.duration = 300;
7511
+ this.easing = `ease`;
7512
+ this._currentText = ``;
7513
+ this._outgoingText = ``;
7514
+ this._transitionId = 0;
7515
+ this._queue = [];
7516
+ this.#onOutgoingEnd = () => {
7517
+ this._onTransitionEnd();
7518
+ };
7519
+ this.#onLastCharOut = () => {
7520
+ this._onTransitionEnd();
7521
+ };
6943
7522
  }
6944
- _getVisibleItems() {
6945
- return Array.from(this.querySelectorAll(ITEM_SELECTOR)).filter((el) => {
6946
- if (el.hidden) return false;
6947
- if (this.filterPredicate && !this.filterPredicate(el)) return false;
6948
- return true;
6949
- });
7523
+ setText(msg, effect) {
7524
+ this._pendingEffect = effect;
7525
+ this.text = msg;
6950
7526
  }
6951
- _syncItemStates() {
6952
- for (const el of this.querySelectorAll(ITEM_SELECTOR)) {
6953
- el.toggleAttribute(`data-tickled`, this.tickled.isTickled(el));
6954
- el.toggleAttribute(`data-selected`, this._selectedItems.has(el));
6955
- if (this.interactionMode === `checked`) el.toggleAttribute(`data-checked`, this._selectedItems.has(el));
6956
- else el.removeAttribute(`data-checked`);
7527
+ updated(changed) {
7528
+ if (changed.has(`text`) && this.text !== this._currentText) {
7529
+ const effect = this._pendingEffect ?? this.effect;
7530
+ this._pendingEffect = void 0;
7531
+ if (this._activeEffect !== void 0) this._queue.push({
7532
+ text: this.text,
7533
+ effect
7534
+ });
7535
+ else this._startTransition(this.text, effect);
6957
7536
  }
6958
- this.dataset.inputMode = this.tickled.inputMode;
6959
- this._syncCheckboxes();
6960
7537
  }
6961
- _syncCheckboxes() {
6962
- const inCheckedMode = this.interactionMode === `checked`;
6963
- if (inCheckedMode) for (const inner of Array.from(this.children)) {
6964
- if (!inner.hasAttribute(`data-list-item`)) continue;
6965
- if (inner.parentElement !== this) continue;
6966
- const wrapper = document.createElement(`li`);
6967
- wrapper.className = `ixfx-custom-row`;
6968
- const key = inner.getAttribute(`data-key`);
6969
- const label = inner.getAttribute(`data-search-label`);
6970
- if (key !== null) wrapper.setAttribute(`data-key`, key);
6971
- if (label !== null) wrapper.setAttribute(`data-search-label`, label);
6972
- inner.removeAttribute(`data-list-item`);
6973
- this.insertBefore(wrapper, inner);
6974
- wrapper.appendChild(inner);
6975
- this.#customWrappers.set(wrapper, inner);
6976
- }
6977
- else {
6978
- for (const [wrapper, inner] of this.#customWrappers) {
6979
- if (wrapper.parentElement !== this) continue;
6980
- inner.setAttribute(`data-list-item`, ``);
6981
- this.insertBefore(inner, wrapper);
6982
- wrapper.remove();
6983
- }
6984
- this.#customWrappers.clear();
6985
- }
6986
- for (const el of this.querySelectorAll(`li`)) {
6987
- let cb = el.querySelector(`input.ixfx-list-checkbox`);
6988
- if (inCheckedMode) {
6989
- if (!cb) {
6990
- cb = document.createElement(`input`);
6991
- cb.type = `checkbox`;
6992
- cb.className = `ixfx-list-checkbox`;
6993
- cb.style.cssText = `flex-shrink:0;margin:0 6px 0 0;cursor:pointer;accent-color:var(--accent,#60a5fa);pointer-events:auto`;
6994
- cb.tabIndex = -1;
6995
- cb.addEventListener(`click`, (e) => {
6996
- e.stopPropagation();
6997
- this._toggleItem(el);
6998
- });
6999
- el.prepend(cb);
7000
- }
7001
- cb.checked = this._selectedItems.has(el);
7002
- } else if (cb) cb.remove();
7538
+ _startTransition(newText, effect) {
7539
+ const prevText = this._currentText;
7540
+ this._currentText = newText;
7541
+ this._outgoingText = prevText;
7542
+ if (prevText !== ``) {
7543
+ this._transitionId++;
7544
+ this._activeEffect = effect;
7003
7545
  }
7004
7546
  }
7005
- _findListItem(path) {
7006
- for (const target of path) {
7007
- if (!(target instanceof Element)) continue;
7008
- if (target === this) break;
7009
- if (target.parentElement === this && target.matches(ITEM_SELECTOR)) return target;
7547
+ _onTransitionEnd() {
7548
+ this._outgoingText = ``;
7549
+ this._activeEffect = void 0;
7550
+ if (this._queue.length > 0) {
7551
+ const next = this._queue.shift();
7552
+ this._startTransition(next.text, next.effect);
7010
7553
  }
7011
7554
  }
7012
- _dispatch(name, detail) {
7013
- this.dispatchEvent(new CustomEvent(name, {
7014
- detail,
7015
- bubbles: true,
7016
- composed: true
7017
- }));
7018
- }
7019
- _openSearch() {
7020
- this._searchVisible = true;
7021
- this.updateComplete.then(() => this._searchInputEl?.focus());
7022
- }
7023
- _closeSearch() {
7024
- this._searchVisible = false;
7025
- this._searchQuery = ``;
7026
- this.#search?.clearQuery();
7027
- this.focus();
7555
+ #onOutgoingEnd;
7556
+ #onLastCharOut;
7557
+ #renderCharSwap() {
7558
+ const charDuration = Math.round(this.duration * .3);
7559
+ const charStagger = Math.round(this.duration * .1);
7560
+ const currentChars = this._currentText.split(``);
7561
+ const outgoingChars = this._outgoingText.split(``);
7562
+ const lastIdx = outgoingChars.length - 1;
7563
+ const charStyle = (i) => `animation-duration:${charDuration}ms;animation-delay:${i * charStagger}ms;animation-timing-function:${this.easing}`;
7564
+ return html`
7565
+ ${keyed(`cc${this._transitionId}`, html`
7566
+ <span class="layer current char-swap">
7567
+ ${currentChars.map((ch, i) => html`<span class="char in" style=${charStyle(i)}>${ch}</span>`)}
7568
+ </span>
7569
+ `)}
7570
+ ${this._outgoingText ? keyed(this._transitionId, html`
7571
+ <span class="layer outgoing char-swap">
7572
+ ${outgoingChars.map((ch, i) => html`<span
7573
+ class="char out"
7574
+ style=${charStyle(i)}
7575
+ @animationend=${i === lastIdx ? this.#onLastCharOut : void 0}
7576
+ >${ch}</span>`)}
7577
+ </span>
7578
+ `) : nothing}
7579
+ `;
7028
7580
  }
7029
- _activateItem(item) {
7030
- if (this.interactionMode !== `manual`) this._replaceSelection(item);
7031
- this._dispatch(`list-activate`, { item });
7581
+ render() {
7582
+ if (this._activeEffect === `character-swap`) return html`<span class="container">${this.#renderCharSwap()}</span>`;
7583
+ const effect = this._activeEffect ?? ``;
7584
+ const durStyle = this._activeEffect ? `animation-duration:${this.duration}ms;animation-timing-function:${this.easing}` : ``;
7585
+ return html`
7586
+ <span class="container">
7587
+ ${this._outgoingText ? keyed(this._transitionId, html`
7588
+ <span class="layer outgoing ${effect}" style=${durStyle} @animationend=${this.#onOutgoingEnd}>
7589
+ ${this._outgoingText}
7590
+ </span>
7591
+ `) : nothing}
7592
+ ${keyed(`c${this._transitionId}`, html`
7593
+ <span class="layer current ${effect}" style=${durStyle}>
7594
+ ${this._currentText}
7595
+ </span>
7596
+ `)}
7597
+ </span>
7598
+ `;
7032
7599
  }
7033
7600
  static {
7034
7601
  this.styles = css`
7035
7602
  :host {
7036
- display: block;
7037
- position: relative;
7038
- background: var(--list-bg, var(--surface-3));
7039
- color: var(--list-text, var(--surface-3-text));
7040
- border-radius: var(--list-radius, var(--radius-s));
7041
- border: 1px solid var(--list-border, var(--border));
7042
- width: 100%;
7043
- height: 100%;
7603
+ display: inline-block;
7604
+ --transitory-label-easing: ease;
7605
+ }
7606
+
7607
+ .container {
7608
+ display: inline-grid;
7044
7609
  overflow: hidden;
7045
- box-sizing: border-box;
7046
- outline: none;
7047
7610
  }
7048
7611
 
7049
- :host(:focus-visible) {
7050
- outline: 2px solid var(--accent);
7051
- outline-offset: 2px;
7612
+ .layer {
7613
+ grid-area: 1 / 1;
7614
+ white-space: nowrap;
7052
7615
  }
7053
7616
 
7054
- .container {
7055
- position: relative;
7056
- width: 100%;
7057
- height: 100%;
7617
+ .layer.outgoing {
7618
+ pointer-events: none;
7058
7619
  }
7059
7620
 
7060
- ul {
7061
- list-style: none;
7062
- margin: 0;
7063
- padding: 0;
7064
- width: 100%;
7065
- height: 100%;
7066
- overflow-y: auto;
7067
- box-sizing: border-box;
7621
+ /* slide-right */
7622
+ .layer.current.slide-right {
7623
+ transform: translateX(-100%);
7624
+ animation: tl-slide-in-left var(--transitory-label-easing) forwards;
7625
+ }
7626
+ .layer.outgoing.slide-right {
7627
+ animation: tl-slide-out-right var(--transitory-label-easing) forwards;
7068
7628
  }
7069
7629
 
7070
- ::slotted([hidden]) {
7071
- display: none !important;
7630
+ @keyframes tl-slide-in-left {
7631
+ from { transform: translateX(-100%); }
7632
+ to { transform: translateX(0); }
7633
+ }
7634
+ @keyframes tl-slide-out-right {
7635
+ from { transform: translateX(0); }
7636
+ to { transform: translateX(100%); }
7072
7637
  }
7073
7638
 
7074
- ::slotted(li) {
7075
- display: flex;
7076
- align-items: center;
7077
- padding: var(--list-item-padding, 4px var(--space-m, 8px));
7078
- min-height: var(--list-item-height, 28px);
7079
- cursor: pointer;
7080
- user-select: none;
7081
- transition: background var(--transition, 0.1s ease-out),
7082
- outline-color var(--transition, 0.1s ease-out);
7083
- box-sizing: border-box;
7084
- outline: 1px solid transparent;
7639
+ /* slide-left */
7640
+ .layer.current.slide-left {
7641
+ transform: translateX(100%);
7642
+ animation: tl-slide-in-right var(--transitory-label-easing) forwards;
7643
+ }
7644
+ .layer.outgoing.slide-left {
7645
+ animation: tl-slide-out-left var(--transitory-label-easing) forwards;
7085
7646
  }
7086
7647
 
7087
- /* Custom shadow-DOM components handle their own internal layout/padding */
7088
- ::slotted([data-list-item]) {
7089
- display: block;
7090
- cursor: pointer;
7091
- user-select: none;
7092
- transition: background var(--transition, 0.1s ease-out),
7093
- outline-color var(--transition, 0.1s ease-out);
7094
- outline: 1px solid transparent;
7648
+ @keyframes tl-slide-in-right {
7649
+ from { transform: translateX(100%); }
7650
+ to { transform: translateX(0); }
7651
+ }
7652
+ @keyframes tl-slide-out-left {
7653
+ from { transform: translateX(0); }
7654
+ to { transform: translateX(-100%); }
7095
7655
  }
7096
7656
 
7097
- ::slotted([data-tickled]) {
7098
- background: var(--item-bg-tickled, rgba(0, 0, 0, 0.06));
7099
- outline: 1px solid var(--accent, #60a5fa);
7657
+ /* slide-up */
7658
+ .layer.current.slide-up {
7659
+ transform: translateY(100%);
7660
+ animation: tl-slide-in-bottom var(--transitory-label-easing) forwards;
7661
+ }
7662
+ .layer.outgoing.slide-up {
7663
+ animation: tl-slide-out-top var(--transitory-label-easing) forwards;
7664
+ }
7665
+
7666
+ @keyframes tl-slide-in-bottom {
7667
+ from { transform: translateY(100%); }
7668
+ to { transform: translateY(0); }
7669
+ }
7670
+ @keyframes tl-slide-out-top {
7671
+ from { transform: translateY(0); }
7672
+ to { transform: translateY(-100%); }
7100
7673
  }
7101
7674
 
7102
- ::slotted([data-selected]) {
7103
- background: var(--item-bg-selected, rgba(25, 118, 210, 1));
7104
- color: var(--item-text-selected, #fff);
7105
- outline: 1px solid transparent;
7675
+ /* slide-down */
7676
+ .layer.current.slide-down {
7677
+ transform: translateY(-100%);
7678
+ animation: tl-slide-in-top var(--transitory-label-easing) forwards;
7106
7679
  }
7107
-
7108
- ::slotted([data-selected][data-tickled]) {
7109
- background: var(--item-bg-selected-tickled, rgba(21, 101, 192, 1));
7110
- outline: 2px dashed var(--surface-3, #1e1e1e);
7111
- outline-offset: -2px;
7680
+ .layer.outgoing.slide-down {
7681
+ animation: tl-slide-out-bottom var(--transitory-label-easing) forwards;
7112
7682
  }
7113
7683
 
7114
- /* checked mode: checkbox (injected into li) communicates selection — suppress bg highlight */
7115
- :host([interaction-mode="checked"]) ::slotted([data-selected]) {
7116
- background: transparent;
7117
- color: inherit;
7118
- outline: 1px solid transparent;
7684
+ @keyframes tl-slide-in-top {
7685
+ from { transform: translateY(-100%); }
7686
+ to { transform: translateY(0); }
7687
+ }
7688
+ @keyframes tl-slide-out-bottom {
7689
+ from { transform: translateY(0); }
7690
+ to { transform: translateY(100%); }
7119
7691
  }
7120
7692
 
7121
- :host([interaction-mode="checked"]) ::slotted([data-selected][data-tickled]) {
7122
- background: var(--item-bg-tickled, rgba(0, 0, 0, 0.06));
7123
- color: inherit;
7124
- outline: 1px solid var(--accent, #60a5fa);
7693
+ /* fade */
7694
+ .layer.current.fade {
7695
+ opacity: 0;
7696
+ animation: tl-fade-in var(--transitory-label-easing) forwards;
7697
+ }
7698
+ .layer.outgoing.fade {
7699
+ animation: tl-fade-out var(--transitory-label-easing) forwards;
7125
7700
  }
7126
7701
 
7127
- .search-overlay {
7128
- position: absolute;
7129
- top: 8px;
7130
- right: 8px;
7131
- z-index: 10;
7132
- display: flex;
7133
- align-items: center;
7134
- gap: 4px;
7135
- background: var(--surface-4, #2a2a2a);
7136
- border: 1px solid var(--border, #444);
7137
- border-radius: var(--radius-m, 4px);
7138
- padding: 4px 6px;
7139
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
7702
+ @keyframes tl-fade-in {
7703
+ from { opacity: 0; }
7704
+ to { opacity: 1; }
7705
+ }
7706
+ @keyframes tl-fade-out {
7707
+ from { opacity: 1; }
7708
+ to { opacity: 0; }
7140
7709
  }
7141
7710
 
7142
- .search-overlay[hidden] {
7143
- display: none;
7711
+ /* character-swap */
7712
+ .char {
7713
+ display: inline-block;
7144
7714
  }
7145
7715
 
7146
- .search-input {
7147
- background: transparent;
7148
- border: none;
7149
- outline: none;
7150
- color: inherit;
7151
- font-size: var(--text-m, 0.875em);
7152
- min-width: 140px;
7716
+ .char.in {
7717
+ opacity: 0;
7718
+ animation: tl-char-in var(--transitory-label-easing) forwards;
7153
7719
  }
7154
7720
 
7155
- .search-close {
7156
- background: transparent;
7157
- border: none;
7158
- color: var(--surface-muted-text, #888);
7159
- cursor: pointer;
7160
- font-size: 1.1em;
7161
- line-height: 1;
7162
- padding: 0 2px;
7721
+ .char.out {
7722
+ animation: tl-char-out var(--transitory-label-easing) forwards;
7163
7723
  }
7164
7724
 
7165
- .search-close:hover {
7166
- color: inherit;
7725
+ @keyframes tl-char-in {
7726
+ from { opacity: 0; transform: translateY(-0.3em) scale(0.8); }
7727
+ to { opacity: 1; transform: translateY(0) scale(1); }
7728
+ }
7729
+ @keyframes tl-char-out {
7730
+ from { opacity: 1; transform: translateY(0) scale(1); }
7731
+ to { opacity: 0; transform: translateY(0.3em) scale(0.8); }
7167
7732
  }
7168
7733
  `;
7169
7734
  }
7735
+ };
7736
+ __decorate([property({ type: String })], TransitoryLabelElement.prototype, "text", void 0);
7737
+ __decorate([property({ type: String })], TransitoryLabelElement.prototype, "effect", void 0);
7738
+ __decorate([property({ type: Number })], TransitoryLabelElement.prototype, "duration", void 0);
7739
+ __decorate([property({ type: String })], TransitoryLabelElement.prototype, "easing", void 0);
7740
+ __decorate([state()], TransitoryLabelElement.prototype, "_currentText", void 0);
7741
+ __decorate([state()], TransitoryLabelElement.prototype, "_outgoingText", void 0);
7742
+ __decorate([state()], TransitoryLabelElement.prototype, "_activeEffect", void 0);
7743
+ __decorate([state()], TransitoryLabelElement.prototype, "_transitionId", void 0);
7744
+ TransitoryLabelElement = __decorate([safeCustomElement(`ixfx-transitory-label`)], TransitoryLabelElement);
7745
+ //#endregion
7746
+ //#region src/util/checkbox.ts
7747
+ function isCheckboxLike(el) {
7748
+ if (!(el instanceof HTMLElement)) return false;
7749
+ return `checked` in el;
7750
+ }
7751
+ function resolveElement(elOrQuery) {
7752
+ if (typeof elOrQuery === `string`) {
7753
+ const found = document.querySelector(elOrQuery);
7754
+ if (!(found instanceof HTMLElement)) throw new Error(`Element not found or not HTMLElement: ${elOrQuery}`);
7755
+ return found;
7756
+ }
7757
+ return elOrQuery;
7758
+ }
7759
+ function monitorIndeterminate(targetElOrQuery, watchedElsOrQueries) {
7760
+ const target = resolveElement(targetElOrQuery);
7761
+ if (!isCheckboxLike(target)) throw new Error(`Target element is not a checkbox-like element`);
7762
+ const watched = [];
7763
+ for (const elOrQuery of watchedElsOrQueries) {
7764
+ const el = resolveElement(elOrQuery);
7765
+ if (isCheckboxLike(el)) watched.push(el);
7766
+ }
7767
+ const updateTarget = () => {
7768
+ if (watched.length === 0) {
7769
+ target.checked = false;
7770
+ target.indeterminate = false;
7771
+ return;
7772
+ }
7773
+ let checkedCount = 0;
7774
+ let uncheckedCount = 0;
7775
+ for (const el of watched) if (el.checked) checkedCount++;
7776
+ else uncheckedCount++;
7777
+ if (checkedCount > 0 && uncheckedCount > 0) {
7778
+ target.checked = false;
7779
+ target.indeterminate = true;
7780
+ } else if (checkedCount === watched.length) {
7781
+ target.checked = true;
7782
+ target.indeterminate = false;
7783
+ } else {
7784
+ target.checked = false;
7785
+ target.indeterminate = false;
7786
+ }
7787
+ };
7788
+ const handleChange = () => {
7789
+ updateTarget();
7790
+ };
7791
+ for (const el of watched) el.addEventListener(`change`, handleChange);
7792
+ updateTarget();
7793
+ return () => {
7794
+ for (const el of watched) el.removeEventListener(`change`, handleChange);
7795
+ };
7796
+ }
7797
+ //#endregion
7798
+ //#region src/util/is-numeric.ts
7799
+ function isNumeric(str) {
7800
+ if (typeof str === `number`) return true;
7801
+ if (typeof str !== `string`) return false;
7802
+ const trimmed = str.trim();
7803
+ return trimmed !== `` && !Number.isNaN(Number(trimmed));
7804
+ }
7805
+ //#endregion
7806
+ //#region src/util/tooltip.ts
7807
+ var _TooltipElement;
7808
+ let TooltipElement = class TooltipElement extends LitElement {
7809
+ static {
7810
+ _TooltipElement = this;
7811
+ }
7812
+ constructor(..._args) {
7813
+ super(..._args);
7814
+ this.valueFormatTooltip = _TooltipElement.defaultFormatter;
7815
+ this.orientation = `top`;
7816
+ this.anchor = `--tooltip`;
7817
+ }
7818
+ static {
7819
+ this.numberFormatter = (v) => Math.floor(v).toString();
7820
+ }
7821
+ static {
7822
+ this.defaultFormatter = (v) => {
7823
+ if (typeof v === `number`) {
7824
+ if (Number.isInteger(v)) return v.toString();
7825
+ return v.toFixed(2);
7826
+ } else if (typeof v === `string`) return v;
7827
+ else return JSON.stringify(v);
7828
+ };
7829
+ }
7830
+ #renderIcon() {
7831
+ if (!this.icon) return nothing;
7832
+ 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>`;
7833
+ if (!getIcon(this.icon)) return nothing;
7834
+ return html`<ixfx-icon class="tooltip-icon" style="margin-right:0.25em" name="${this.icon}"></ixfx-icon>`;
7835
+ }
7170
7836
  render() {
7171
- return html`
7172
- <div class="container">
7173
- <ul part="list">
7174
- <slot></slot>
7175
- </ul>
7176
- <div
7177
- class="search-overlay"
7178
- part="search-overlay"
7179
- ?hidden=${!this._searchVisible}
7180
- >
7181
- <input
7182
- type="text"
7183
- class="search-input"
7184
- placeholder="Search…"
7185
- .value=${this._searchQuery}
7186
- @input=${this._onSearchInput}
7187
- @keydown=${this._onSearchKeydown}
7188
- />
7189
- <button class="search-close" @click=${this._closeSearch} title="Close search (Esc)">×</button>
7190
- </div>
7191
- </div>
7192
- `;
7837
+ const classes = {
7838
+ "tooltip": true,
7839
+ "tooltip-orientation-top": this.orientation === `top`,
7840
+ "tooltip-orientation-bottom": this.orientation === `bottom`,
7841
+ "tooltip-orientation-right": this.orientation === `right`,
7842
+ "tooltip-orientation-left": this.orientation === `left`,
7843
+ "tooltip-type-text": true,
7844
+ "tooltip-type-number": false,
7845
+ "tooltip-style-bubble": true
7846
+ };
7847
+ let value = ``;
7848
+ switch (typeof this.value) {
7849
+ case `number`:
7850
+ classes[`tooltip-type-number`] = true;
7851
+ value = this.valueFormatTooltip(this.value);
7852
+ break;
7853
+ case `string`:
7854
+ if (isNumeric(this.value)) {
7855
+ classes[`tooltip-type-number`] = true;
7856
+ value = this.valueFormatTooltip(Number.parseFloat(this.value));
7857
+ } else value = this.value;
7858
+ break;
7859
+ default: value = JSON.stringify(this.value);
7860
+ }
7861
+ return html`<output style="--anchor-id: ${this.anchor}" class=${classMap(classes)}>${this.#renderIcon()}${value}</output>`;
7862
+ }
7863
+ createRenderRoot() {
7864
+ return this;
7193
7865
  }
7194
7866
  };
7195
- __decorate([property({
7196
- type: String,
7197
- attribute: `selection-mode`
7198
- })], VerticalListElement.prototype, "selectionMode", void 0);
7199
- __decorate([property({
7200
- type: String,
7201
- attribute: `interaction-mode`
7202
- })], VerticalListElement.prototype, "interactionMode", void 0);
7203
- __decorate([property({ attribute: false })], VerticalListElement.prototype, "filterPredicate", void 0);
7204
- __decorate([state()], VerticalListElement.prototype, "_selectedItems", void 0);
7205
- __decorate([state()], VerticalListElement.prototype, "_searchVisible", void 0);
7206
- __decorate([state()], VerticalListElement.prototype, "_searchQuery", void 0);
7207
- __decorate([query(`.search-input`)], VerticalListElement.prototype, "_searchInputEl", void 0);
7208
- VerticalListElement = __decorate([safeCustomElement(`ixfx-vertical-list`)], VerticalListElement);
7867
+ __decorate([property({ type: String })], TooltipElement.prototype, "orientation", void 0);
7868
+ __decorate([property({ type: String })], TooltipElement.prototype, "anchor", void 0);
7869
+ __decorate([property()], TooltipElement.prototype, "value", void 0);
7870
+ __decorate([property({ type: String })], TooltipElement.prototype, "icon", void 0);
7871
+ TooltipElement = _TooltipElement = __decorate([safeCustomElement(`ixfx-tooltip`)], TooltipElement);
7209
7872
  //#endregion
7210
7873
  //#region src/index.ts
7211
7874
  function init() {
7212
7875
  console.log(`Init`);
7213
7876
  }
7214
7877
  //#endregion
7215
- export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataDisplayComponent, EditableLabel, EditableNumber, 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, PanelElement, PanelGroupElement, PlotDataSeries, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, SelectHorizontalElement, SnapContainer, SplitButton, SplitLayoutElement, SwipeElement, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TimelineController, TimelineTrackTabElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeListElement, VerticalListElement, XyPad, applyAgeModification, applyHighlights, attachTimelineInteractions, buildHighlightTargets, clearHighlights, computeColour, createAcCompletionProvider, createElementIncrSearch, createFuzzySearch, createIncrSearch, getIcon, hasIcon, iconBus, init, monitorIndeterminate, parseColourScaleAttr, readBaseColour, registerIcon, resolveCssVars, resolveGrid, svgToDataUri, timelineStyles };
7878
+ export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, EditableLabel, EditableNumber, 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, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, SelectHorizontalElement, SnapContainer, SplitButton, SplitLayoutElement, SwipeElement, 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, createTreeListAdapter, createVerticalListAdapter, getIcon, hasIcon, iconBus, init, monitorIndeterminate, parseColourScaleAttr, readBaseColour, registerIcon, resolveCssVars, resolveGrid, svgToDataUri, timelineStyles };
7216
7879
 
7217
7880
  //# sourceMappingURL=index.js.map