@ixfx/components 0.4.3 → 0.5.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 (239) hide show
  1. package/bundle/index.d.ts +518 -1176
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +4861 -17274
  4. package/bundle/index.js.map +1 -1
  5. package/bundle/style.css +1 -1
  6. package/dist/ac-text.d.ts +12 -7
  7. package/dist/ac-text.d.ts.map +1 -1
  8. package/dist/ac-text.js +2 -3
  9. package/dist/ac-text.js.map +1 -1
  10. package/dist/{button-C3fLMKUv.js → button-DxYee1ZH.js} +2 -2
  11. package/dist/{button-C3fLMKUv.js.map → button-DxYee1ZH.js.map} +1 -1
  12. package/dist/button.d.ts +1 -2
  13. package/dist/button.d.ts.map +1 -1
  14. package/dist/button.js +1 -2
  15. package/dist/checkbox.d.ts +0 -1
  16. package/dist/checkbox.d.ts.map +1 -1
  17. package/dist/checkbox.js +1 -1
  18. package/dist/checkbox.js.map +1 -1
  19. package/dist/{colour-picker-0sgAha1T.js → colour-picker-C3Ag4uh-.js} +15 -17
  20. package/dist/colour-picker-C3Ag4uh-.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 +5 -2
  24. package/dist/crumbs.d.ts.map +1 -1
  25. package/dist/crumbs.js +45 -20
  26. package/dist/crumbs.js.map +1 -1
  27. package/dist/data-display.d.ts +1 -2
  28. package/dist/data-display.d.ts.map +1 -1
  29. package/dist/data-display.js +25 -23
  30. package/dist/data-display.js.map +1 -1
  31. package/dist/{data-provider-DgI909FP.js → data-provider-35TyWclX.js} +2 -2
  32. package/dist/data-provider-35TyWclX.js.map +1 -0
  33. package/dist/{decorate-DdjvVHS-.js → decorate-VRK8rslU.js} +2 -2
  34. package/dist/{decorate-DdjvVHS-.js.map → decorate-VRK8rslU.js.map} +1 -1
  35. package/dist/{defaults-C3b9OWJD.js → defaults-DcE8RQJc.js} +19 -1
  36. package/dist/defaults-DcE8RQJc.js.map +1 -0
  37. package/dist/editable-label.d.ts +1 -2
  38. package/dist/editable-label.d.ts.map +1 -1
  39. package/dist/editable-label.js +1 -1
  40. package/dist/editable-label.js.map +1 -1
  41. package/dist/{hex-editor-WZrjRtvL.js → hex-editor-Bk6rxhfg.js} +9 -11
  42. package/dist/hex-editor-Bk6rxhfg.js.map +1 -0
  43. package/dist/{hex-editor-CMIxtNgT.d.ts → hex-editor-Caq8vNQk.d.ts} +2 -3
  44. package/dist/hex-editor-Caq8vNQk.d.ts.map +1 -0
  45. package/dist/hex.d.ts +1 -1
  46. package/dist/hex.js +1 -1
  47. package/dist/highlight-B-eQrhhb.js.map +1 -1
  48. package/dist/{icon-Ndo40kNO.js → icon-B22XVlCt.js} +6 -4
  49. package/dist/{icon-Ndo40kNO.js.map → icon-B22XVlCt.js.map} +1 -1
  50. package/dist/{icon-Bd5BiU4b.d.ts → icon-DpA9x2Ve.d.ts} +2 -3
  51. package/dist/icon-DpA9x2Ve.d.ts.map +1 -0
  52. package/dist/icons.d.ts +2 -2
  53. package/dist/icons.js +2 -2
  54. package/dist/{incr-search-CeERfijK.js → incr-search-2pz21xtR.js} +9 -6
  55. package/dist/incr-search-2pz21xtR.js.map +1 -0
  56. package/dist/incr-search.d.ts +1 -1
  57. package/dist/incr-search.js +1 -1
  58. package/dist/{index-CowKi2mo.d.ts → index-BeuCXtiO.d.ts} +3 -4
  59. package/dist/index-BeuCXtiO.d.ts.map +1 -0
  60. package/dist/{index-D87kRcEs.d.ts → index-BtGFYfaK.d.ts} +2 -1
  61. package/dist/index-BtGFYfaK.d.ts.map +1 -0
  62. package/dist/{index-s_IhSnwc.d.ts → index-CoqtMSd9.d.ts} +6 -4
  63. package/dist/index-CoqtMSd9.d.ts.map +1 -0
  64. package/dist/{index-9fGVAg1d.d.ts → index-Cxwxtj6g.d.ts} +3 -3
  65. package/dist/index-Cxwxtj6g.d.ts.map +1 -0
  66. package/dist/index-D_ftz_IT.d.ts +184 -0
  67. package/dist/index-D_ftz_IT.d.ts.map +1 -0
  68. package/dist/{index-_RTQSKHi.d.ts → index-DfEkTGvT.d.ts} +11 -11
  69. package/dist/index-DfEkTGvT.d.ts.map +1 -0
  70. package/dist/index.d.ts +167 -29
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +712 -2970
  73. package/dist/index.js.map +1 -1
  74. package/dist/keyboard-B5xD7Fz-.js +36 -0
  75. package/dist/keyboard-B5xD7Fz-.js.map +1 -0
  76. package/dist/{labelled-input-base-ORb1rGq6.d.ts → labelled-input-base-DiTme1JO.d.ts} +1 -2
  77. package/dist/labelled-input-base-DiTme1JO.d.ts.map +1 -0
  78. package/dist/{labelled-input-base-9K_w3oLj.js → labelled-input-base-hoKGwyKT.js} +2 -2
  79. package/dist/{labelled-input-base-9K_w3oLj.js.map → labelled-input-base-hoKGwyKT.js.map} +1 -1
  80. package/dist/labelled-radial-input.d.ts +5 -4
  81. package/dist/labelled-radial-input.d.ts.map +1 -1
  82. package/dist/labelled-radial-input.js +7 -3
  83. package/dist/labelled-radial-input.js.map +1 -1
  84. package/dist/labelled-range-input.d.ts +1 -1
  85. package/dist/labelled-range-input.js +27 -3
  86. package/dist/labelled-range-input.js.map +1 -1
  87. package/dist/led.d.ts +1 -2
  88. package/dist/led.d.ts.map +1 -1
  89. package/dist/led.js +1 -1
  90. package/dist/led.js.map +1 -1
  91. package/dist/{menu-vjoiHZ13.js → menu-g6yd7ddN.js} +8 -9
  92. package/dist/menu-g6yd7ddN.js.map +1 -0
  93. package/dist/{menu-item-COx-Azgj.d.ts → menu-item-DSyf9f_L.d.ts} +4 -4
  94. package/dist/menu-item-DSyf9f_L.d.ts.map +1 -0
  95. package/dist/{menu-item-BrIuORYD.js → menu-item-NUKwJ4s5.js} +3 -4
  96. package/dist/{menu-item-BrIuORYD.js.map → menu-item-NUKwJ4s5.js.map} +1 -1
  97. package/dist/menu.d.ts +2 -2
  98. package/dist/menu.js +2 -2
  99. package/dist/miller.d.ts +8 -5
  100. package/dist/miller.d.ts.map +1 -1
  101. package/dist/miller.js +22 -24
  102. package/dist/miller.js.map +1 -1
  103. package/dist/narrowed-text.d.ts +7 -3
  104. package/dist/narrowed-text.d.ts.map +1 -1
  105. package/dist/narrowed-text.js +73 -47
  106. package/dist/narrowed-text.js.map +1 -1
  107. package/dist/panel.d.ts +1 -1
  108. package/dist/panel.d.ts.map +1 -1
  109. package/dist/panel.js +2 -2
  110. package/dist/panel.js.map +1 -1
  111. package/dist/plots.d.ts +2 -2
  112. package/dist/plots.js +1 -1
  113. package/dist/polar-pad.d.ts +15 -3
  114. package/dist/polar-pad.d.ts.map +1 -1
  115. package/dist/polar-pad.js +64 -11
  116. package/dist/polar-pad.js.map +1 -1
  117. package/dist/{radial-input-CpQPs1Mp.d.ts → radial-input-BhZeyyP-.d.ts} +6 -4
  118. package/dist/radial-input-BhZeyyP-.d.ts.map +1 -0
  119. package/dist/{radial-input-DZ7eQCcM.js → radial-input-DxCrt_NE.js} +41 -19
  120. package/dist/radial-input-DxCrt_NE.js.map +1 -0
  121. package/dist/radial-input.d.ts +1 -1
  122. package/dist/radial-input.js +1 -1
  123. package/dist/range-input.d.ts +15 -4
  124. package/dist/range-input.d.ts.map +1 -1
  125. package/dist/range-input.js +23 -2
  126. package/dist/range-input.js.map +1 -1
  127. package/dist/range.d.ts +15 -4
  128. package/dist/range.d.ts.map +1 -1
  129. package/dist/range.js +23 -2
  130. package/dist/range.js.map +1 -1
  131. package/dist/selecthorizontal.d.ts +1 -2
  132. package/dist/selecthorizontal.d.ts.map +1 -1
  133. package/dist/selecthorizontal.js +1 -1
  134. package/dist/selecthorizontal.js.map +1 -1
  135. package/dist/slider-input-DFpG23bS.js +1592 -0
  136. package/dist/slider-input-DFpG23bS.js.map +1 -0
  137. package/dist/slider-input-TidGhvXt.d.ts +160 -0
  138. package/dist/slider-input-TidGhvXt.d.ts.map +1 -0
  139. package/dist/slider-input.d.ts +2 -0
  140. package/dist/slider-input.js +2 -0
  141. package/dist/snap-container.d.ts +1 -2
  142. package/dist/snap-container.d.ts.map +1 -1
  143. package/dist/snap-container.js +6 -5
  144. package/dist/snap-container.js.map +1 -1
  145. package/dist/split-layout.d.ts +1 -2
  146. package/dist/split-layout.d.ts.map +1 -1
  147. package/dist/split-layout.js +6 -4
  148. package/dist/split-layout.js.map +1 -1
  149. package/dist/style.css +1 -1
  150. package/dist/swipe.d.ts +12 -2
  151. package/dist/swipe.d.ts.map +1 -1
  152. package/dist/swipe.js +22 -3
  153. package/dist/swipe.js.map +1 -1
  154. package/dist/{tab-list-DLzb-m-I.d.ts → tab-list-BohmbvqF.d.ts} +14 -5
  155. package/dist/tab-list-BohmbvqF.d.ts.map +1 -0
  156. package/dist/tab-list-DhkVhRQc.js +597 -0
  157. package/dist/tab-list-DhkVhRQc.js.map +1 -0
  158. package/dist/tabs.d.ts +2 -2
  159. package/dist/tabs.js +1 -208
  160. package/dist/{tickled-controller-BjYCzGrU.d.ts → tickled-controller-BF2Ea0DE.d.ts} +2 -31
  161. package/dist/tickled-controller-BF2Ea0DE.d.ts.map +1 -0
  162. package/dist/tickled-styles-fNDdqf6l.js.map +1 -1
  163. package/dist/{timeline-2OFtN4Ta.js → timeline-B2fgDL4U.js} +37 -1438
  164. package/dist/timeline-B2fgDL4U.js.map +1 -0
  165. package/dist/timeline.d.ts +1 -1
  166. package/dist/timeline.js +1 -1
  167. package/dist/{tooltip-RGVIwHrZ.d.ts → tooltip-BlvBUQxx.d.ts} +3 -3
  168. package/dist/tooltip-BlvBUQxx.d.ts.map +1 -0
  169. package/dist/{tree-D84RUgFC.js → tree-BnvzhsAw.js} +8 -9
  170. package/dist/tree-BnvzhsAw.js.map +1 -0
  171. package/dist/{tree-component-BaCSPWg1.d.ts → tree-component-DCmmKZ4j.d.ts} +8 -124
  172. package/dist/tree-component-DCmmKZ4j.d.ts.map +1 -0
  173. package/dist/tree.d.ts +10 -4
  174. package/dist/tree.d.ts.map +1 -1
  175. package/dist/tree.js +1 -1
  176. package/dist/types-DO3gt5vg.d.ts +130 -0
  177. package/dist/types-DO3gt5vg.d.ts.map +1 -0
  178. package/dist/wheel-nudge-BlSCe_hD.js +86 -0
  179. package/dist/wheel-nudge-BlSCe_hD.js.map +1 -0
  180. package/dist/wheel-nudge-DgMTRYlh.d.ts +29 -0
  181. package/dist/wheel-nudge-DgMTRYlh.d.ts.map +1 -0
  182. package/dist/{xy-axis-BeWRMmbo.d.ts → xy-axis-5KhVTNoX.d.ts} +30 -7
  183. package/dist/xy-axis-5KhVTNoX.d.ts.map +1 -0
  184. package/dist/xy-axis-CxHC8z5E.js +1849 -0
  185. package/dist/xy-axis-CxHC8z5E.js.map +1 -0
  186. package/dist/xy-pad.d.ts +13 -2
  187. package/dist/xy-pad.d.ts.map +1 -1
  188. package/dist/xy-pad.js +47 -6
  189. package/dist/xy-pad.js.map +1 -1
  190. package/docs-user/README.md +2 -0
  191. package/docs-user/button.md +48 -0
  192. package/docs-user/narrowed-text.md +33 -1
  193. package/docs-user/notifier.md +131 -0
  194. package/docs-user/plots.md +61 -1
  195. package/docs-user/radial-input.md +2 -2
  196. package/docs-user/slider-input.md +673 -0
  197. package/docs-user/tabs.md +12 -14
  198. package/docs-user/user-catalog.md +69 -4
  199. package/docs-user/vertical-list.md +75 -7
  200. package/package.json +23 -20
  201. package/dist/colour-C3MQIjFJ-vRCdr8W-.js +0 -3732
  202. package/dist/colour-C3MQIjFJ-vRCdr8W-.js.map +0 -1
  203. package/dist/colour-picker-0sgAha1T.js.map +0 -1
  204. package/dist/data-provider-DgI909FP.js.map +0 -1
  205. package/dist/defaults-C3b9OWJD.js.map +0 -1
  206. package/dist/dist-CA13FvMn.js +0 -980
  207. package/dist/dist-CA13FvMn.js.map +0 -1
  208. package/dist/hex-editor-CMIxtNgT.d.ts.map +0 -1
  209. package/dist/hex-editor-WZrjRtvL.js.map +0 -1
  210. package/dist/icon-Bd5BiU4b.d.ts.map +0 -1
  211. package/dist/incr-search-CeERfijK.js.map +0 -1
  212. package/dist/index-9fGVAg1d.d.ts.map +0 -1
  213. package/dist/index-CowKi2mo.d.ts.map +0 -1
  214. package/dist/index-D87kRcEs.d.ts.map +0 -1
  215. package/dist/index-DgXpCg_G.d.ts +0 -1244
  216. package/dist/index-DgXpCg_G.d.ts.map +0 -1
  217. package/dist/index-_RTQSKHi.d.ts.map +0 -1
  218. package/dist/index-s_IhSnwc.d.ts.map +0 -1
  219. package/dist/keyboard-CimiEskD.js +0 -20
  220. package/dist/keyboard-CimiEskD.js.map +0 -1
  221. package/dist/labelled-input-base-ORb1rGq6.d.ts.map +0 -1
  222. package/dist/menu-item-COx-Azgj.d.ts.map +0 -1
  223. package/dist/menu-vjoiHZ13.js.map +0 -1
  224. package/dist/radial-input-CpQPs1Mp.d.ts.map +0 -1
  225. package/dist/radial-input-DZ7eQCcM.js.map +0 -1
  226. package/dist/tab-list-DLzb-m-I.d.ts.map +0 -1
  227. package/dist/tabs.js.map +0 -1
  228. package/dist/tickled-controller-BjYCzGrU.d.ts.map +0 -1
  229. package/dist/timeline-2OFtN4Ta.js.map +0 -1
  230. package/dist/tooltip-RGVIwHrZ.d.ts.map +0 -1
  231. package/dist/tree-D84RUgFC.js.map +0 -1
  232. package/dist/tree-component-BaCSPWg1.d.ts.map +0 -1
  233. package/dist/types-DSfbtHs3.d.ts +0 -8
  234. package/dist/types-DSfbtHs3.d.ts.map +0 -1
  235. package/dist/xy-axis-BeWRMmbo.d.ts.map +0 -1
  236. package/dist/xy-axis-no0OL_O1.js +0 -7893
  237. package/dist/xy-axis-no0OL_O1.js.map +0 -1
  238. /package/bundle/{chunk-D7D4PA-g.js → rolldown-runtime-D7D4PA-g.js} +0 -0
  239. /package/dist/{chunk-D7D4PA-g.js → rolldown-runtime-D7D4PA-g.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"crumbs.d.ts","names":[],"sources":["../src/crumbs/crumb-navigation.ts"],"mappings":";;;;;KAmCY,2BAAA;EAAA,SACD,QAAA,EAAU,QAAA;EAAA,SACV,QAAA,EAAU,QAAQ;AAAA;AAAA,KAGjB,0BAAA,GAA6B,WAAW,CAAC,2BAAA;AAAA,KAEzC,8BAAA;EAAmC,IAAA,EAAM,QAAQ;EAAE,KAAA;AAAA;AAAA,KACnD,6BAAA,GAAgC,WAAW,CAAC,8BAAA;AAAA,KAE5C,2BAAA;EAAgC,IAAA,EAAM,QAAQ;EAAE,KAAA;AAAA;AAAA,KAChD,0BAAA,GAA6B,WAAW,CAAC,2BAAA;;;;AAJe;AACpE;;;;AAAsF;AAEtF;;;;;;;;AAAiE;cAsBpD,sBAAA,SAA+B,UAAA,YAAsB,aAAA;EAAA;EAEhE,IAAA,EAAM,QAAA;EAGN,KAAA,EAAO,aAAA;EAGP,YAAA,EAAc,QAAA;EAAA,QAGN,cAAA;EAAA,IAEJ,aAAA,IAAiB,WAAA,CAAY,QAAA;;EAMjC,YAAA,EAAc,oBAAA;EAGd,eAAA,EAAiB,mBAAA;EAGjB,WAAA,EAAa,eAAA;EAGb,eAAA,EAAiB,mBAAA;EAAA,QAGT,QAAA;EAAA,QAGA,UAAA;EAAA,QAGA,SAAA;EAAA,QAGA,oBAAA;EAGR,SAAA;EAAA,QAUQ,OAAA;EAsSR,MAAA,CAAO,IAAA,EAAM,QAAA;EAIb,QAAA,CAAS,KAAA,EAAO,QAAA;EAIhB,cAAA;EAKA,QAAA,IAAY,aAAA;IAAgB,IAAA,EAAM,QAAA;IAAU,KAAA;EAAA;EAgBnC,OAAA,CAAQ,YAAA,EAAc,cAAA;EAkBtB,oBAAA;EA1YiC;EA4jB1C,UAAA,CAAW,IAAA;;EAiBX,cAAA,CAAe,SAAA,GAAY,IAAA,EAAM,QAAA;EAwCjC,MAAA,kBAAM,cAAA;EAAA,OA6JC,MAAA,gBAAM,SAAA;AAAA;AAAA,QA0JP,MAAA;EAAA,UACI,qBAAA;IACR,uBAAA,EAAyB,sBAAsB;EAAA;AAAA;AAAA,UAIlC,8BAAA,SAAuC,qBAAA;EACtD,YAAA,EAAc,kBAAA;EACd,QAAA,EAAU,eAAA;EACV,QAAA,EAAU,eAAA;EACV,QAAA,EAAU,eAAA;EACV,UAAA,EAAY,iBAAA;AAAA;AAAA,UAGG,sBAAA;EACf,gBAAA,oBAAoC,8BAAA,EAClC,IAAA,EAAM,CAAA,EACN,QAAA,GAAW,IAAA,EAAM,sBAAA,EAAwB,KAAA,EAAO,8BAAA,CAA+B,CAAA,YAC/E,OAAA,aAAoB,uBAAA,eAEpB,IAAA,UACA,QAAA,EAAU,kCAAA,EACV,OAAA,aAAoB,uBAAA;AAAA"}
1
+ {"version":3,"file":"crumbs.d.ts","names":[],"sources":["../src/crumbs/crumb-navigation.ts"],"mappings":";;;;;;;KAmCY;WACD,UAAU;WACV,UAAU;;KAGT,6BAA6B,YAAY;KAEzC;EAAmC,MAAM;EAAU;;KACnD,gCAAgC,YAAY;KAE5C;EAAgC,MAAM;EAAU;;KAChD,6BAA6B,YAAY;;;;;;;;;;;;;;;;;;;cAqBxC,+BAA+B,sBAAsB;;EAEhE,MAAM;EAGN,OAAO;EAGP,cAAc;UAGN;MAEJ,iBAAiB,YAAY;;EAMjC,cAAc;EAGd,iBAAiB;EAGjB,aAAa;EAGb,iBAAiB;UAGT;UAGA;UAGA;UAGA;EAGR;UAUQ;EA4TR,OAAO,MAAM;EAIb,SAAS,OAAO;EAIhB;EAKA,YAAY;IAAgB,MAAM;IAAU;;EAgBnC,QAAQ,cAAc;EAkBtB;EAKA;;EAmLT,WAAW;;EAiBX,eAAe,YAAY,MAAM;EAwCjC,wBAAM;SA8JC,sBAAM;;QAgKP;YACI;IACR,yBAAyB;;;UAIZ,uCAAuC;EACtD,cAAc;EACd,UAAU;EACV,UAAU;EACV,UAAU;EACV,YAAY;;UAGG;EACf,oBAAoB,gBAAgB,gCAClC,MAAM,GACN,WAAW,MAAM,wBAAwB,OAAO,+BAA+B,aAC/E,oBAAoB,sCAEpB,cACA,UAAU,oCACV,oBAAoB"}
package/dist/crumbs.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { n as tickledStyles, r as TickledController, t as tickledItemStyles } from "./tickled-styles-fNDdqf6l.js";
2
2
  import { t as themeFallbacks } from "./fallbacks-pNMOMx38.js";
3
- import { n as safeCustomElement, t as __decorate } from "./decorate-DdjvVHS-.js";
3
+ import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
4
4
  import "./interaction-D6efrBLo.js";
5
- import "./menu-item-BrIuORYD.js";
6
- import { t as collectDataResult } from "./data-provider-DgI909FP.js";
5
+ import "./menu-item-NUKwJ4s5.js";
6
+ import { t as collectDataResult } from "./data-provider-35TyWclX.js";
7
7
  import "./narrowed-text.js";
8
8
  import { LitElement, css, html, nothing } from "lit";
9
9
  import { property, state } from "lit/decorators.js";
@@ -104,18 +104,16 @@ let CrumbNavigationElement = class CrumbNavigationElement extends LitElement {
104
104
  this.tickled.clearTickled();
105
105
  this.blur();
106
106
  break;
107
- case `Tab`:
108
- if (e.shiftKey) {
109
- e.preventDefault();
110
- this.#shiftFocusToPath();
111
- } else if (currentTickled === totalItems - 1) {
112
- e.preventDefault();
113
- this._menuOpen = false;
114
- this._focusOnNarrowedText = true;
115
- const narrowedText = this.shadowRoot?.querySelector(`ixfx-narrowed-text`);
116
- if (narrowedText) narrowedText.focus();
117
- }
118
- break;
107
+ case `Tab`: if (e.shiftKey) {
108
+ e.preventDefault();
109
+ this.#shiftFocusToPath();
110
+ } else if (currentTickled === totalItems - 1) {
111
+ e.preventDefault();
112
+ this._menuOpen = false;
113
+ this._focusOnNarrowedText = true;
114
+ const narrowedText = this.shadowRoot?.querySelector(`ixfx-narrowed-text`);
115
+ if (narrowedText) narrowedText.focus();
116
+ }
119
117
  }
120
118
  };
121
119
  this.#onNarrowedTextBlur = () => {
@@ -162,6 +160,21 @@ let CrumbNavigationElement = class CrumbNavigationElement extends LitElement {
162
160
  const hasChildOptions = this.#hasChildOptions();
163
161
  if (index < pathNodes.length) this._openIdx = index;
164
162
  else if (hasChildOptions && index === pathNodes.length) this._openIdx = pathNodes.length - 1;
163
+ if (this.tickled.inputMode === `keyboard`) this.#scrollTickledIntoView(index);
164
+ }
165
+ #scrollTickledIntoView(index) {
166
+ const r = this.root;
167
+ const sel = this.selectedNode;
168
+ if (!r || !sel) return;
169
+ const pathNodes = this.#findPath(r, sel) ?? [r];
170
+ let el = null;
171
+ if (index < pathNodes.length) el = this.shadowRoot?.querySelectorAll(`.crumb-segment`)[index] ?? null;
172
+ else if (index === pathNodes.length) el = this.shadowRoot?.querySelector(`#child-options-trigger`) ?? null;
173
+ el?.scrollIntoView({
174
+ inline: `nearest`,
175
+ block: `nearest`,
176
+ behavior: `smooth`
177
+ });
165
178
  }
166
179
  #hasChildOptions() {
167
180
  const s = this.selectedNode;
@@ -292,8 +305,13 @@ let CrumbNavigationElement = class CrumbNavigationElement extends LitElement {
292
305
  }
293
306
  this.#runLayoutUpdate(changedProps);
294
307
  }
308
+ connectedCallback() {
309
+ super.connectedCallback();
310
+ this.addEventListener(`click`, this.#onHostClick);
311
+ }
295
312
  disconnectedCallback() {
296
313
  super.disconnectedCallback();
314
+ this.removeEventListener(`click`, this.#onHostClick);
297
315
  this.#modelUnsubscribe?.();
298
316
  this.#modelUnsubscribe = void 0;
299
317
  document.removeEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });
@@ -350,12 +368,12 @@ let CrumbNavigationElement = class CrumbNavigationElement extends LitElement {
350
368
  const previous = this.selectedNode;
351
369
  if (previous) this.#previousSelectionKey = previous.item?.key ?? ``;
352
370
  else this.#previousSelectionKey = ``;
353
- const previousSet = previous ? new Set([previous]) : /* @__PURE__ */ new Set();
371
+ const previousSet = previous ? /* @__PURE__ */ new Set([previous]) : /* @__PURE__ */ new Set();
354
372
  this.selectedNode = node;
355
- this._selectedNodes = new Set([node]);
373
+ this._selectedNodes = /* @__PURE__ */ new Set([node]);
356
374
  this.dispatchEvent(new CustomEvent(`select`, {
357
375
  detail: {
358
- selected: new Set([node]),
376
+ selected: /* @__PURE__ */ new Set([node]),
359
377
  previous: previousSet
360
378
  },
361
379
  bubbles: true,
@@ -537,7 +555,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends LitElement {
537
555
  @menu-trigger-close=${this.#onMenuTriggerClose}
538
556
  @pointerleave=${(e) => this.tickled.handlePointerLeave(e)}
539
557
  >
540
- <div class="parts">${parts}</div>
558
+ <div class="parts">${parts}<div class="trailing"></div></div>
541
559
  ${childOptions ? html`
542
560
  <ixfx-menu-trigger
543
561
  id="child-options-trigger"
@@ -593,6 +611,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends LitElement {
593
611
  `;
594
612
  }
595
613
  #onNarrowedTextChange(e) {
614
+ e.stopPropagation();
596
615
  const detail = e.detail;
597
616
  const node = this.selectedNode;
598
617
  if (!node?.children) return;
@@ -629,7 +648,7 @@ let CrumbNavigationElement = class CrumbNavigationElement extends LitElement {
629
648
  outline: none;
630
649
  }
631
650
 
632
- :host([input-mode="keyboard"]) .host-container {
651
+ :host(:focus-within) .host-container {
633
652
  outline: 2px solid var(--accent);
634
653
  outline-offset: 2px;
635
654
  }
@@ -644,6 +663,12 @@ let CrumbNavigationElement = class CrumbNavigationElement extends LitElement {
644
663
  display: flex;
645
664
  }
646
665
 
666
+ .trailing {
667
+ flex: 1;
668
+ min-width: 1em;
669
+ cursor: pointer;
670
+ }
671
+
647
672
  .crumb-segment {
648
673
  display: flex;
649
674
  align-items: center;
@@ -1 +1 @@
1
- {"version":3,"file":"crumbs.js","names":["#getTickledItems","#onTickled","#onMenuKeyNav","#currentOpenTrigger","#menuOpenedByKeyboard","#findPath","#hasChildOptions","#shiftFocusToNarrowedText","#handleOpenCaretMenu","#handleEnter","#shiftFocusToPath","#pendingNode","#propagateInputModeToMenu","#setSelected","#modelUnsubscribe","#runLayoutUpdate","#previousSelectionKey","#scrollToValue","#pendingController","#abortPending","#invokeLoadChildren","#onChildClick","#findNodePath","#onLabelClick","#onSegmentMenuCommand","#renderChildOptions","#onFocus","#onBlur","#onKeyDown","#onHostClick","#onMenuTriggerClose","#onMenuCommand","#getChildOptionsWidth","#onNarrowedTextChange","#onNarrowedTextBlur","#onNarrowedTextShiftTab","customElement"],"sources":["../src/crumbs/crumb-navigation.ts"],"sourcesContent":["/* eslint-disable ts/no-unsafe-declaration-merging */\nimport type { PropertyValues } from 'lit';\nimport type {\n TreeActivateEvent,\n TreeComponent,\n TreeComponentEventMap,\n TreeExpandEvent,\n TreeItemClickEvent,\n TreeSelectDetail,\n TreeSelectEvent,\n TreeTickleDetail,\n TreeTickleEvent,\n} from '../common/tree-component.js';\nimport type { TreeDataModel } from '../common/tree-data-model.js';\nimport type {\n TreeExclusivity,\n TreeFilterPredicate,\n TreeSelectionFilter,\n} from '../common/types.js';\nimport type { MenuTrigger } from '../menu/menu-trigger.js';\nimport type { LoadChildrenCallback, TreeNode } from '../tree/types.js';\nimport { css, html, LitElement, nothing } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { collectDataResult } from '../common/data-provider.js';\n\nimport { TickledController, tickledItemStyles, tickledStyles } from '../interaction/index.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\nimport '../menu/menu-trigger.js';\nimport '../menu/menu-container.js';\nimport '../menu/menu-item.js';\n\nimport '../narrowed-text/index.js';\n\n/** @deprecated Use TreeSelectDetail from src/common/tree-component.ts */\nexport type CrumbNavigationChangeDetail = {\n readonly selected: TreeNode;\n readonly previous: TreeNode | undefined;\n};\n\nexport type CrumbNavigationChangeEvent = CustomEvent<CrumbNavigationChangeDetail>;\n\nexport type CrumbNavigationItemClickDetail = { node: TreeNode; depth: number };\nexport type CrumbNavigationItemClickEvent = CustomEvent<CrumbNavigationItemClickDetail>;\n\nexport type CrumbNavigationExpandDetail = { node: TreeNode; depth: number };\nexport type CrumbNavigationExpandEvent = CustomEvent<CrumbNavigationExpandDetail>;\n\n/**\n * Breadcrumb navigation with lazy-loading support.\n *\n * Uses the same `TreeNode` / `TreeItem` data model as `ixfx-tree-list`,\n * so the two components can be swapped with minimal code changes.\n *\n * Events\n * - `navigate`: fired when user clicks a breadcrumb label. detail: `{ node: TreeNode }`\n * - `change`: fired when selected node changes. detail: `{ selected: TreeNode, previous: TreeNode | undefined }`\n * - `expand`: fired when user clicks a caret whose node has no children yet.\n * detail: `{ node: TreeNode, depth: number, signal: AbortSignal }`\n * Populate `node.children` then call `requestUpdate()` on the element.\n *\n * CSS variables\n * --text-highlight: var(--accent); // highlight on mouse hover\n * --separator: var(--surface-muted-text); // text colour of separator character\n * --padding-s: var(--space-xs); // padding between items\n */\n@customElement(`ixfx-crumb-navigation`)\nexport class CrumbNavigationElement extends LitElement implements TreeComponent {\n @property({ type: Object })\n root: TreeNode | undefined;\n\n @property({ attribute: false })\n model: TreeDataModel | undefined;\n\n @property({ type: Object })\n selectedNode: TreeNode | undefined;\n\n @state()\n private _selectedNodes = new Set<TreeNode>();\n\n get selectedNodes(): ReadonlySet<TreeNode> {\n return this._selectedNodes;\n }\n\n /** Callback to lazily load children for a node. When set, replaces event-based lazy loading. */\n @property({ attribute: false })\n loadChildren: LoadChildrenCallback | undefined;\n\n @property({ attribute: false })\n filterPredicate: TreeFilterPredicate | undefined;\n\n @property({ reflect: true, attribute: `exclusivity` })\n exclusivity: TreeExclusivity = `none`;\n\n @property({ reflect: true, attribute: `selection-filter` })\n selectionFilter: TreeSelectionFilter = `leaf`;\n\n @state()\n private _openIdx = -1;\n\n @state()\n private _isFocused = false;\n\n @state()\n private _menuOpen = false;\n\n @state()\n private _focusOnNarrowedText = false;\n\n @property({ reflect: true, attribute: `input-mode` })\n inputMode: string = ``;\n\n #pendingNode: TreeNode | undefined;\n #pendingController: AbortController | undefined;\n #modelUnsubscribe: (() => void) | undefined;\n\n #previousSelectionKey = ``;\n #menuOpenedByKeyboard = false;\n #currentOpenTrigger: MenuTrigger | null = null;\n\n private tickled = new TickledController<number>(this, {\n getItems: () => this.#getTickledItems(),\n onTickle: (index) => {\n if (index !== undefined) {\n this.#onTickled(index);\n }\n },\n });\n\n #getTickledItems() {\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return [];\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n const items: Array<{ id: number; enabled: boolean }> = [];\n\n pathNodes.forEach((_node, i) => {\n items.push({ id: i, enabled: true });\n });\n\n if (this.#hasChildOptions()) {\n items.push({ id: pathNodes.length, enabled: true });\n }\n\n return items;\n }\n\n #onTickled(index: number) {\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n const hasChildOptions = this.#hasChildOptions();\n\n if (index < pathNodes.length) {\n this._openIdx = index;\n } else if (hasChildOptions && index === pathNodes.length) {\n this._openIdx = pathNodes.length - 1;\n }\n }\n\n #hasChildOptions(): boolean {\n const s = this.selectedNode;\n if (s === undefined)\n return false;\n\n const isPending = this.#pendingNode === s;\n const children = s.children ?? [];\n\n return children.length > 0 || isPending;\n }\n\n #onFocus = (): void => {\n this._isFocused = true;\n };\n\n #onBlur = (): void => {\n this._isFocused = false;\n };\n\n #onHostClick = (): void => {\n this.shadowRoot?.querySelector<HTMLElement>(`.host-container`)?.focus();\n };\n\n #handleOpenCaretMenu() {\n const currentTickled = this.tickled.tickledId;\n if (currentTickled === undefined)\n return;\n\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n\n // For non-last segments: open the inline caret menu for that segment\n if (currentTickled < pathNodes.length - 1) {\n const segments = this.shadowRoot?.querySelectorAll<HTMLElement>(`.crumb-segment`);\n const trigger = segments?.[currentTickled]?.querySelector<MenuTrigger>(`.caret ixfx-menu-trigger`);\n if (trigger) {\n this.#menuOpenedByKeyboard = true;\n this.#currentOpenTrigger = trigger;\n document.addEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });\n trigger.openMenu();\n this.#propagateInputModeToMenu();\n return;\n }\n }\n\n // Last segment or the child-options separator: open the child-options menu\n if (this.#hasChildOptions()) {\n const trigger = this.shadowRoot?.querySelector<MenuTrigger>(`#child-options-trigger`);\n if (trigger) {\n this.#menuOpenedByKeyboard = true;\n this.#currentOpenTrigger = trigger;\n document.addEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });\n trigger.openMenu();\n this.#propagateInputModeToMenu();\n }\n }\n }\n\n #propagateInputModeToMenu(): void {\n const inputMode = this.tickled.inputMode;\n requestAnimationFrame(() => {\n const container = this.#currentOpenTrigger?.querySelector(`ixfx-menu-container`);\n if (container) {\n container.setAttribute(`data-input-mode`, inputMode);\n }\n });\n }\n\n #onMenuTriggerClose = (): void => {\n document.removeEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });\n this.#currentOpenTrigger = null;\n this.#menuOpenedByKeyboard = false;\n requestAnimationFrame(() => {\n this.shadowRoot?.querySelector<HTMLElement>(`.host-container`)?.focus();\n });\n };\n\n #onMenuKeyNav = (e: KeyboardEvent): void => {\n // Only handle ArrowLeft/ArrowRight - close menu and navigate to previous/next breadcrumb segment\n // ArrowDown/ArrowUp should pass through to let the menu handle them\n const container = this.#currentOpenTrigger?.querySelector(`ixfx-menu-container`);\n if (!container || !this.#currentOpenTrigger?.isOpen)\n return;\n\n switch (e.key) {\n case `ArrowLeft`:\n case `ArrowRight`: {\n e.preventDefault();\n e.stopPropagation();\n this.#currentOpenTrigger.closeMenu();\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n break;\n const pathNodes = this.#findPath(r, sel) ?? [r];\n const totalItems = pathNodes.length + (this.#hasChildOptions() ? 1 : 0);\n const currentTickled = this.tickled.tickledId ?? -1;\n if (e.key === `ArrowLeft`) {\n if (currentTickled > 0) {\n this.tickled.handleKeyboardNavigation(`previous`);\n }\n } else {\n if (currentTickled < totalItems - 1) {\n this.tickled.handleKeyboardNavigation(`next`);\n }\n }\n break;\n }\n }\n };\n\n #onKeyDown = (e: KeyboardEvent): void => {\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n const totalItems = pathNodes.length + (this.#hasChildOptions() ? 1 : 0);\n const currentTickled = this.tickled.tickledId ?? -1;\n\n switch (e.key) {\n case `ArrowRight`: {\n e.preventDefault();\n if (currentTickled < totalItems - 1) {\n this.tickled.handleKeyboardNavigation(`next`);\n } else if (currentTickled === totalItems - 1) {\n this.#shiftFocusToNarrowedText();\n }\n break;\n }\n case `ArrowLeft`: {\n e.preventDefault();\n if (currentTickled > 0) {\n this.tickled.handleKeyboardNavigation(`previous`);\n }\n break;\n }\n case `ArrowDown`:\n case `ArrowUp`: {\n if (this.tickled.tickledId !== undefined) {\n e.preventDefault();\n if (this.#currentOpenTrigger?.isOpen) {\n // Menu is already open - dispatch ArrowDown to the popover element for it to handle\n const container = this.#currentOpenTrigger.querySelector(`ixfx-menu-container`);\n const popover = container?.shadowRoot?.querySelector(`.popover`);\n if (popover) {\n popover.dispatchEvent(new KeyboardEvent(`keydown`, { key: e.key, bubbles: true }));\n }\n } else {\n this.#handleOpenCaretMenu();\n }\n }\n break;\n }\n case `Enter`: {\n e.preventDefault();\n this.#handleEnter();\n break;\n }\n case `Escape`: {\n e.preventDefault();\n this._menuOpen = false;\n this.tickled.clearTickled();\n this.blur();\n break;\n }\n case `Tab`: {\n if (e.shiftKey) {\n e.preventDefault();\n this.#shiftFocusToPath();\n } else if (currentTickled === totalItems - 1) {\n e.preventDefault();\n this._menuOpen = false;\n this._focusOnNarrowedText = true;\n const narrowedText = this.shadowRoot?.querySelector(`ixfx-narrowed-text`);\n if (narrowedText) {\n narrowedText.focus();\n }\n }\n break;\n }\n }\n };\n\n #handleEnter() {\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n const hasChildOptions = this.#hasChildOptions();\n const currentTickled = this.tickled.tickledId ?? -1;\n\n if (currentTickled < pathNodes.length) {\n const node = pathNodes[currentTickled];\n this.#setSelected(node);\n this._menuOpen = false;\n this.dispatchEvent(new CustomEvent<CrumbNavigationItemClickDetail>(`item-click`, {\n detail: { node, depth: currentTickled },\n bubbles: true,\n composed: true,\n }));\n } else if (hasChildOptions && currentTickled === pathNodes.length) {\n this._menuOpen = true;\n this.#menuOpenedByKeyboard = true;\n const trigger = this.shadowRoot?.querySelector<MenuTrigger>(`#child-options-trigger`);\n if (trigger) {\n this.#currentOpenTrigger = trigger;\n document.addEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });\n trigger.openMenu();\n this.#propagateInputModeToMenu();\n }\n }\n }\n\n #shiftFocusToNarrowedText() {\n const narrowedText = this.shadowRoot?.querySelector(`ixfx-narrowed-text`);\n if (narrowedText) {\n this._focusOnNarrowedText = true;\n narrowedText.focus();\n }\n }\n\n #shiftFocusToPath() {\n this._focusOnNarrowedText = false;\n const hostContainer = this.shadowRoot?.querySelector<HTMLElement>(`.host-container`);\n if (hostContainer) {\n hostContainer.focus();\n }\n }\n\n #onNarrowedTextBlur = (): void => {\n this._focusOnNarrowedText = false;\n this.#shiftFocusToPath();\n };\n\n #onNarrowedTextShiftTab = (): void => {\n this._focusOnNarrowedText = false;\n this.#shiftFocusToPath();\n };\n\n // --- TreeComponent methods ---\n\n select(node: TreeNode): void {\n this.#setSelected(node);\n }\n\n deselect(_node: TreeNode): void {\n // Crumb navigation is single-selection; deselect navigates to parent or root\n }\n\n clearSelection(): void {\n if (this.root)\n this.#setSelected(this.root);\n }\n\n getNodes(): ReadonlyArray<{ node: TreeNode; depth: number }> {\n if (!this.root)\n return [];\n const result: Array<{ node: TreeNode; depth: number }> = [];\n const visit = (node: TreeNode, depth: number) => {\n result.push({ node, depth });\n if (node.children) {\n for (const child of node.children) visit(child, depth + 1);\n }\n };\n for (const child of this.root.children ?? []) visit(child, 0);\n return result;\n }\n\n // --- Lifecycle ---\n\n override updated(changedProps: PropertyValues): void {\n if (changedProps.has(`model`)) {\n this.#modelUnsubscribe?.();\n this.#modelUnsubscribe = undefined;\n const model = this.model;\n if (model) {\n this.root = model.root;\n this.#modelUnsubscribe = model._subscribe((event) => {\n if (event.type === `root`) {\n this.root = event.root;\n this.requestUpdate();\n }\n });\n }\n }\n this.#runLayoutUpdate(changedProps);\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.#modelUnsubscribe?.();\n this.#modelUnsubscribe = undefined;\n document.removeEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });\n this.#currentOpenTrigger = null;\n }\n\n #runLayoutUpdate(_changedProperties: PropertyValues): void {\n if (!this.shadowRoot)\n return;\n\n const hsiElement: HTMLElement | null = this.shadowRoot.querySelector(`.horiz-select-items`);\n if (!hsiElement)\n return;\n\n const ulElement: HTMLElement | null = hsiElement.querySelector(`ul`);\n if (!ulElement)\n return;\n\n const menuTrigger: HTMLElement | null = this.shadowRoot.querySelector(`ixfx-menu-trigger`);\n if (!menuTrigger)\n return;\n\n if (ulElement.getBoundingClientRect().width > hsiElement.getBoundingClientRect().width) {\n menuTrigger.style.display = `inline-flex`;\n } else {\n menuTrigger.style.display = `none`;\n }\n\n for (const li of ulElement.querySelectorAll(`li`)) {\n const key = li.getAttribute(`data-key`) ?? ``;\n if (key === this.#previousSelectionKey) {\n this.#scrollToValue(li);\n break;\n }\n }\n }\n\n #scrollToValue(li: HTMLLIElement) {\n let l = li.offsetLeft;\n\n const ul = li.parentElement;\n if (!ul)\n return;\n l -= ul.offsetLeft;\n\n const horizSelectItems = ul.parentElement;\n if (!horizSelectItems)\n return;\n horizSelectItems.scroll({ left: l, top: 0, behavior: `smooth` });\n\n const horizSelect = horizSelectItems.parentElement;\n if (!horizSelect)\n return;\n horizSelect.style.minWidth = `${li.getBoundingClientRect().width}px`;\n }\n\n #abortPending() {\n if (this.#pendingController) {\n this.#pendingController.abort();\n this.#pendingController = undefined;\n this.#pendingNode = undefined;\n }\n }\n\n #findPath(node: TreeNode, target: TreeNode, acc: TreeNode[] = []): TreeNode[] | undefined {\n const path = [...acc, node];\n if (node === target)\n return path;\n if (!node.children)\n return undefined;\n for (const child of node.children) {\n const result = this.#findPath(child, target, path);\n if (result)\n return result;\n }\n return undefined;\n }\n\n #setSelected(node: TreeNode) {\n const previous = this.selectedNode;\n if (previous) {\n this.#previousSelectionKey = previous.item?.key ?? ``;\n } else {\n this.#previousSelectionKey = ``;\n }\n const previousSet: ReadonlySet<TreeNode> = previous ? new Set([previous]) : new Set();\n this.selectedNode = node;\n this._selectedNodes = new Set([node]);\n\n this.dispatchEvent(new CustomEvent<TreeSelectDetail>(`select`, {\n detail: { selected: new Set([node]), previous: previousSet },\n bubbles: true,\n composed: true,\n }));\n }\n\n #onLabelClick(node: TreeNode, depth: number) {\n this._openIdx = -1;\n this.#setSelected(node);\n this.dispatchEvent(new CustomEvent<CrumbNavigationItemClickDetail>(`item-click`, {\n detail: { node, depth },\n bubbles: true,\n composed: true,\n }));\n }\n\n #onCaretClick(node: TreeNode, depth: number, e: MouseEvent) {\n e.preventDefault();\n e.stopPropagation();\n\n if (this._openIdx === depth) {\n this._openIdx = -1;\n return;\n }\n this._openIdx = depth;\n\n if (node.children === undefined && this.#pendingNode !== node) {\n this.#abortPending();\n this.#pendingNode = node;\n const controller = new AbortController();\n this.#pendingController = controller;\n\n if (this.loadChildren) {\n this.#invokeLoadChildren(node, depth, controller).catch(() => {});\n }\n }\n\n this.requestUpdate();\n }\n\n async #invokeLoadChildren(node: TreeNode, depth: number, controller: AbortController): Promise<void> {\n try {\n const children = [...await collectDataResult(\n this.loadChildren!({ node, depth }, controller.signal),\n controller.signal,\n )];\n if (controller.signal.aborted)\n return;\n node.children = children;\n this.#pendingNode = undefined;\n this.#pendingController = undefined;\n this.dispatchEvent(new CustomEvent<CrumbNavigationExpandDetail>(`expand`, {\n detail: { node, depth },\n bubbles: true,\n composed: true,\n }));\n this.requestUpdate();\n } catch {\n if (controller.signal.aborted)\n return;\n node.children = [];\n this.#pendingNode = undefined;\n this.#pendingController = undefined;\n this.requestUpdate();\n }\n }\n\n #onSegmentMenuCommand(e: CustomEvent, node: TreeNode, depth: number) {\n const key = e.detail.command;\n const child = node.children?.find(c => c.item.key === key);\n if (child) {\n this.#onChildClick(child, depth + 1);\n }\n }\n\n #onChildClick(node: TreeNode, depth: number) {\n this._openIdx = -1;\n this.#setSelected(node);\n this.dispatchEvent(new CustomEvent<CrumbNavigationItemClickDetail>(`item-click`, {\n detail: { node, depth },\n bubbles: true,\n composed: true,\n }));\n }\n\n /** Navigate to a node by key path. Returns false if any key is not found in already-loaded children. */\n navigateTo(keys: readonly string[]): boolean {\n if (!this.root?.children)\n return false;\n let current: TreeNode | undefined = this.root;\n for (const key of keys) {\n const found: TreeNode | undefined = current?.children?.find(n => n.item.key === key);\n if (!found)\n return false;\n current = found;\n }\n if (current && current !== this.root) {\n this.#setSelected(current);\n }\n return true;\n }\n\n /** Navigate to the first node matching the predicate. Returns false if not found. */\n navigateToNode(predicate: (node: TreeNode) => boolean): boolean {\n if (!this.root)\n return false;\n const keyPath = this.#findNodePath(this.root.children ?? [], predicate);\n if (!keyPath)\n return false;\n return this.navigateTo(keyPath);\n }\n\n #findNodePath(\n nodes: TreeNode[],\n predicate: (node: TreeNode) => boolean,\n prefix: string[] = [],\n ): string[] | undefined {\n for (const node of nodes) {\n const path = [...prefix, node.item.key];\n if (predicate(node))\n return path;\n if (node.children?.length) {\n const result = this.#findNodePath(node.children, predicate, path);\n if (result)\n return result;\n }\n }\n return undefined;\n }\n\n #onMenuCommand(e: CustomEvent) {\n const node = this.selectedNode;\n if (!node?.children)\n return;\n\n const key = e.detail.command;\n const child = node.children.find(c => c.item.key === key);\n if (child) {\n const depth = this.root ? (this.#findPath(this.root, node)?.length ?? 1) : 1;\n this.#onChildClick(child, depth);\n }\n }\n\n render() {\n const r = this.root;\n const sel = this.selectedNode;\n\n if (!r || !sel) {\n return html``;\n }\n\n this.inputMode = this.tickled.inputMode;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n const _hasChildOptions = this.#hasChildOptions();\n\n const parts = pathNodes.map((node, i) => {\n const isLast = i === pathNodes.length - 1;\n const isPending = this.#pendingNode === node;\n const isOpen = this._openIdx === i;\n const hasChildren = node.item.isLeaf !== true && (node.children === undefined || node.children.length > 0);\n const showCaret = !isLast && hasChildren;\n const isTickled = this.tickled.isTickled(i);\n\n const menuItems = (node.children ?? []).map(c => html`\n <ixfx-menu-item \n label=\"${c.item.label}\" \n command=\"${c.item.key}\"\n icon-name=\"${c.item.icon ?? nothing}\"\n ></ixfx-menu-item>\n `);\n\n return html`\n <div class=\"item crumb-segment ${isTickled ? `tickled` : ``}\"\n @pointerenter=${() => {\n this.tickled.handlePointerEnter(i);\n this.dispatchEvent(new CustomEvent<TreeTickleDetail>(`tickle`, { detail: { node, depth: i }, bubbles: true, composed: true }));\n }}\n >\n <span class=\"label\" @click=${() => this.#onLabelClick(node, i)}>${node.item.label}</span>\n ${showCaret\n ? html`\n <span class=\"caret ${isOpen ? `open` : ``} ${isPending ? `pending` : ``}\">\n ${isPending\n ? html`<span class=\"loading-spinner\"></span>`\n : html`\n <ixfx-menu-trigger mode=\"trigger\" label=\"›\" @menu-command=${(e: CustomEvent) => this.#onSegmentMenuCommand(e, node, i)}>\n <ixfx-menu-container slot=\"menu\">\n ${menuItems}\n </ixfx-menu-container>\n </ixfx-menu-trigger>\n `\n }\n </span>\n `\n : nothing\n }\n </div>\n `;\n });\n\n const childOptions = this.#renderChildOptions();\n const isLastItemTickled = this.tickled.isTickled(pathNodes.length);\n return html`\n <div\n class=\"host-container\"\n tabindex=\"0\"\n @focus=${this.#onFocus}\n @blur=${this.#onBlur}\n @keydown=${this.#onKeyDown}\n @click=${this.#onHostClick}\n @menu-trigger-close=${this.#onMenuTriggerClose}\n @pointerleave=${(e: PointerEvent) => this.tickled.handlePointerLeave(e)}\n >\n <div class=\"parts\">${parts}</div>\n ${childOptions\n ? html`\n <ixfx-menu-trigger\n id=\"child-options-trigger\"\n class=\"item separator-trigger ${isLastItemTickled ? `tickled` : ``}\"\n mode=\"trigger\"\n label=\"›\"\n @menu-command=${this.#onMenuCommand}\n @pointerenter=${() => this.tickled.handlePointerEnter(pathNodes.length)}\n >\n <ixfx-menu-container slot=\"menu\">\n ${(this.selectedNode?.children ?? []).map(c => html`\n <ixfx-menu-item \n label=\"${c.item.label}\" \n command=\"${c.item.key}\"\n icon-name=\"${c.item.icon ?? nothing}\"\n ></ixfx-menu-item>\n `)}\n </ixfx-menu-container>\n </ixfx-menu-trigger>\n `\n : nothing}\n ${childOptions}\n </div>\n `;\n }\n\n #renderChildOptions() {\n const s = this.selectedNode;\n if (s === undefined) {\n return nothing;\n }\n\n const isPending = this.#pendingNode === s;\n const children = s.children ?? [];\n\n if (children.length === 0 && !isPending) {\n return nothing;\n }\n\n if (isPending) {\n return html`\n <div class=\"horiz-select\">\n <div class=\"horiz-select-items\">\n <span class=\"loading-spinner\"></span>\n </div>\n </div>\n `;\n }\n\n return html`\n <ixfx-narrowed-text\n class=\"horiz-select\"\n selection-mode=\"single\"\n orientation=\"horizontal\"\n nowrap\n width=${this.#getChildOptionsWidth()}\n @change=${this.#onNarrowedTextChange}\n @narrowed-text-blur=${this.#onNarrowedTextBlur}\n @narrowed-text-shift-tab=${this.#onNarrowedTextShiftTab}\n >\n ${children.map(c => html`\n <span data-value=\"${c.item.key}\" data-label=\"${c.item.label}\"></span>\n `)}\n </ixfx-narrowed-text>\n `;\n }\n\n #onNarrowedTextChange(e: CustomEvent) {\n const detail = e.detail as { item: { value: string } };\n const node = this.selectedNode;\n if (!node?.children)\n return;\n\n const child = node.children.find(c => c.item.key === detail.item.value);\n if (child) {\n const depth = this.root ? (this.#findPath(this.root, node)?.length ?? 1) : 1;\n this.#onChildClick(child, depth);\n }\n }\n\n #getChildOptionsWidth(): string {\n return `var(--child-options-width, 50ch)`;\n }\n\n static styles = [themeFallbacks, tickledStyles, tickledItemStyles, css`\n :host {\n --text-highlight: var(--accent);\n --separator: var(--surface-muted-text);\n --padding-s: var(--space-xs);\n display: flex;\n overflow: scroll;\n width: 100%;\n scroll-snap-type: x mandatory;\n scrollbar-width: none;\n\n /* Breadcrumb tickled overrides — no layout shift: keep transparent border at rest */\n --item-padding: 0;\n }\n\n :host(.focused) {\n outline: none;\n }\n\n :host([input-mode=\"keyboard\"]) .host-container {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n }\n\n .host-container {\n display: flex;\n width: 100%;\n outline: none;\n }\n\n .parts {\n display: flex;\n }\n\n .crumb-segment {\n display: flex;\n align-items: center;\n }\n\n .label {\n cursor: pointer;\n margin-right: var(--padding-s);\n white-space: nowrap;\n }\n\n .caret {\n position: relative;\n cursor: pointer;\n padding: var(--padding-m);\n margin-left: var(--padding-s);\n margin-right: var(--padding-s);\n color: var(--separator);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease-in-out;\n }\n\n .caret.open {\n background: color-mix(in srgb, var(--surface-5) 40%, transparent);\n }\n\n .caret.pending {\n display: inline-flex;\n }\n\n .caret > ixfx-menu-trigger {\n display: inline-flex;\n margin: 0;\n --_trigger-hover-bg: transparent;\n --_trigger-hover-opacity: 0.6;\n }\n\n .caret > ixfx-menu-trigger::part(base) {\n background: none;\n border: none;\n color: inherit;\n padding: 0;\n cursor: pointer;\n font-size: inherit;\n line-height: 1;\n }\n\n .caret > ixfx-menu-trigger::part(base):hover {\n background: none;\n opacity: 0.6;\n }\n\n .separator {\n margin-left: var(--padding-s);\n margin-right: var(--padding-s);\n color: var(--separator);\n }\n\n .separator-trigger {\n display: inline-flex;\n margin-left: var(--padding-s);\n margin-right: var(--padding-s);\n --_trigger-hover-bg: transparent;\n --_trigger-hover-opacity: 0.6;\n }\n\n .separator-trigger::part(base) {\n background: none;\n border: none;\n color: var(--separator);\n padding: 0;\n cursor: pointer;\n font-size: inherit;\n line-height: 1;\n }\n\n .separator-trigger::part(base):hover {\n background: none;\n opacity: 0.6;\n }\n\n .separator-trigger.tickled::part(base) {\n }\n\n ixfx-menu-trigger {\n display: none;\n }\n\n .horiz-select > ixfx-menu-trigger {\n display: inline-flex;\n }\n\n .horiz-select {\n display: flex;\n min-width: 5ch;\n }\n\n .loading-spinner {\n display: inline-block;\n width: 12px;\n height: 12px;\n border: 2px solid var(--surface-5);\n border-top-color: var(--accent);\n border-radius: 50%;\n animation: crumb-spin 0.7s linear infinite;\n }\n\n @keyframes crumb-spin {\n to { transform: rotate(360deg); }\n }\n\n ::slotted(*), option {\n user-select: none;\n scroll-snap-align: start;\n }\n `];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ixfx-crumb-navigation\": CrumbNavigationElement;\n }\n}\n\nexport interface CrumbNavigationElementEventMap extends TreeComponentEventMap {\n 'item-click': TreeItemClickEvent;\n 'expand': TreeExpandEvent;\n 'select': TreeSelectEvent;\n 'tickle': TreeTickleEvent;\n 'activate': TreeActivateEvent;\n}\n\nexport interface CrumbNavigationElement {\n addEventListener: (<K extends keyof CrumbNavigationElementEventMap>(\n type: K,\n listener: (this: CrumbNavigationElement, event: CrumbNavigationElementEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ) => void) & ((\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ) => void);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"crumbs.js","names":["#getTickledItems","#onTickled","#onMenuKeyNav","#currentOpenTrigger","#menuOpenedByKeyboard","#findPath","#hasChildOptions","#shiftFocusToNarrowedText","#handleOpenCaretMenu","#handleEnter","#shiftFocusToPath","#scrollTickledIntoView","#pendingNode","#propagateInputModeToMenu","#setSelected","#modelUnsubscribe","#runLayoutUpdate","#onHostClick","#previousSelectionKey","#scrollToValue","#pendingController","#abortPending","#invokeLoadChildren","#onChildClick","#findNodePath","#onLabelClick","#onSegmentMenuCommand","#renderChildOptions","#onFocus","#onBlur","#onKeyDown","#onMenuTriggerClose","#onMenuCommand","#getChildOptionsWidth","#onNarrowedTextChange","#onNarrowedTextBlur","#onNarrowedTextShiftTab","customElement"],"sources":["../src/crumbs/crumb-navigation.ts"],"sourcesContent":["/* eslint-disable ts/no-unsafe-declaration-merging */\nimport type { PropertyValues } from 'lit';\nimport type {\n TreeActivateEvent,\n TreeComponent,\n TreeComponentEventMap,\n TreeExpandEvent,\n TreeItemClickEvent,\n TreeSelectDetail,\n TreeSelectEvent,\n TreeTickleDetail,\n TreeTickleEvent,\n} from '../common/tree-component.js';\nimport type { TreeDataModel } from '../common/tree-data-model.js';\nimport type {\n TreeExclusivity,\n TreeFilterPredicate,\n TreeSelectionFilter,\n} from '../common/types.js';\nimport type { MenuTrigger } from '../menu/menu-trigger.js';\nimport type { LoadChildrenCallback, TreeNode } from '../tree/types.js';\nimport { css, html, LitElement, nothing } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { collectDataResult } from '../common/data-provider.js';\n\nimport { TickledController, tickledItemStyles, tickledStyles } from '../interaction/index.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\nimport '../menu/menu-trigger.js';\nimport '../menu/menu-container.js';\nimport '../menu/menu-item.js';\n\nimport '../narrowed-text/index.js';\n\n/** @deprecated Use TreeSelectDetail from src/common/tree-component.ts */\nexport type CrumbNavigationChangeDetail = {\n readonly selected: TreeNode;\n readonly previous: TreeNode | undefined;\n};\n\nexport type CrumbNavigationChangeEvent = CustomEvent<CrumbNavigationChangeDetail>;\n\nexport type CrumbNavigationItemClickDetail = { node: TreeNode; depth: number };\nexport type CrumbNavigationItemClickEvent = CustomEvent<CrumbNavigationItemClickDetail>;\n\nexport type CrumbNavigationExpandDetail = { node: TreeNode; depth: number };\nexport type CrumbNavigationExpandEvent = CustomEvent<CrumbNavigationExpandDetail>;\n\n/**\n * Breadcrumb navigation with lazy-loading support.\n *\n * Uses the same `TreeNode` / `TreeItem` data model as `ixfx-tree-list`,\n * so the two components can be swapped with minimal code changes.\n *\n * Events\n * - `navigate`: fired when user clicks a breadcrumb label. detail: `{ node: TreeNode }`\n * - `change`: fired when selected node changes. detail: `{ selected: TreeNode, previous: TreeNode | undefined }`\n * - `expand`: fired when user clicks a caret whose node has no children yet.\n * detail: `{ node: TreeNode, depth: number, signal: AbortSignal }`\n * Populate `node.children` then call `requestUpdate()` on the element.\n *\n * CSS variables\n * --text-highlight: var(--accent); // highlight on mouse hover\n * --separator: var(--surface-muted-text); // text colour of separator character\n * --padding-s: var(--space-xs); // padding between items\n */\n@customElement(`ixfx-crumb-navigation`)\nexport class CrumbNavigationElement extends LitElement implements TreeComponent {\n @property({ type: Object })\n root: TreeNode | undefined;\n\n @property({ attribute: false })\n model: TreeDataModel | undefined;\n\n @property({ type: Object })\n selectedNode: TreeNode | undefined;\n\n @state()\n private _selectedNodes = new Set<TreeNode>();\n\n get selectedNodes(): ReadonlySet<TreeNode> {\n return this._selectedNodes;\n }\n\n /** Callback to lazily load children for a node. When set, replaces event-based lazy loading. */\n @property({ attribute: false })\n loadChildren: LoadChildrenCallback | undefined;\n\n @property({ attribute: false })\n filterPredicate: TreeFilterPredicate | undefined;\n\n @property({ reflect: true, attribute: `exclusivity` })\n exclusivity: TreeExclusivity = `none`;\n\n @property({ reflect: true, attribute: `selection-filter` })\n selectionFilter: TreeSelectionFilter = `leaf`;\n\n @state()\n private _openIdx = -1;\n\n @state()\n private _isFocused = false;\n\n @state()\n private _menuOpen = false;\n\n @state()\n private _focusOnNarrowedText = false;\n\n @property({ reflect: true, attribute: `input-mode` })\n inputMode: string = ``;\n\n #pendingNode: TreeNode | undefined;\n #pendingController: AbortController | undefined;\n #modelUnsubscribe: (() => void) | undefined;\n\n #previousSelectionKey = ``;\n #menuOpenedByKeyboard = false;\n #currentOpenTrigger: MenuTrigger | null = null;\n\n private tickled = new TickledController<number>(this, {\n getItems: () => this.#getTickledItems(),\n onTickle: (index) => {\n if (index !== undefined) {\n this.#onTickled(index);\n }\n },\n });\n\n #getTickledItems() {\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return [];\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n const items: Array<{ id: number; enabled: boolean }> = [];\n\n pathNodes.forEach((_node, i) => {\n items.push({ id: i, enabled: true });\n });\n\n if (this.#hasChildOptions()) {\n items.push({ id: pathNodes.length, enabled: true });\n }\n\n return items;\n }\n\n #onTickled(index: number) {\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n const hasChildOptions = this.#hasChildOptions();\n\n if (index < pathNodes.length) {\n this._openIdx = index;\n } else if (hasChildOptions && index === pathNodes.length) {\n this._openIdx = pathNodes.length - 1;\n }\n\n if (this.tickled.inputMode === `keyboard`) {\n this.#scrollTickledIntoView(index);\n }\n }\n\n #scrollTickledIntoView(index: number): void {\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n let el: HTMLElement | null = null;\n\n if (index < pathNodes.length) {\n el = this.shadowRoot?.querySelectorAll<HTMLElement>(`.crumb-segment`)[index] ?? null;\n } else if (index === pathNodes.length) {\n el = this.shadowRoot?.querySelector<HTMLElement>(`#child-options-trigger`) ?? null;\n }\n\n el?.scrollIntoView({ inline: `nearest`, block: `nearest`, behavior: `smooth` });\n }\n\n #hasChildOptions(): boolean {\n const s = this.selectedNode;\n if (s === undefined)\n return false;\n\n const isPending = this.#pendingNode === s;\n const children = s.children ?? [];\n\n return children.length > 0 || isPending;\n }\n\n #onFocus = (): void => {\n this._isFocused = true;\n };\n\n #onBlur = (): void => {\n this._isFocused = false;\n };\n\n #onHostClick = (): void => {\n this.shadowRoot?.querySelector<HTMLElement>(`.host-container`)?.focus();\n };\n\n #handleOpenCaretMenu() {\n const currentTickled = this.tickled.tickledId;\n if (currentTickled === undefined)\n return;\n\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n\n // For non-last segments: open the inline caret menu for that segment\n if (currentTickled < pathNodes.length - 1) {\n const segments = this.shadowRoot?.querySelectorAll<HTMLElement>(`.crumb-segment`);\n const trigger = segments?.[currentTickled]?.querySelector<MenuTrigger>(`.caret ixfx-menu-trigger`);\n if (trigger) {\n this.#menuOpenedByKeyboard = true;\n this.#currentOpenTrigger = trigger;\n document.addEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });\n trigger.openMenu();\n this.#propagateInputModeToMenu();\n return;\n }\n }\n\n // Last segment or the child-options separator: open the child-options menu\n if (this.#hasChildOptions()) {\n const trigger = this.shadowRoot?.querySelector<MenuTrigger>(`#child-options-trigger`);\n if (trigger) {\n this.#menuOpenedByKeyboard = true;\n this.#currentOpenTrigger = trigger;\n document.addEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });\n trigger.openMenu();\n this.#propagateInputModeToMenu();\n }\n }\n }\n\n #propagateInputModeToMenu(): void {\n const inputMode = this.tickled.inputMode;\n requestAnimationFrame(() => {\n const container = this.#currentOpenTrigger?.querySelector(`ixfx-menu-container`);\n if (container) {\n container.setAttribute(`data-input-mode`, inputMode);\n }\n });\n }\n\n #onMenuTriggerClose = (): void => {\n document.removeEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });\n this.#currentOpenTrigger = null;\n this.#menuOpenedByKeyboard = false;\n requestAnimationFrame(() => {\n this.shadowRoot?.querySelector<HTMLElement>(`.host-container`)?.focus();\n });\n };\n\n #onMenuKeyNav = (e: KeyboardEvent): void => {\n // Only handle ArrowLeft/ArrowRight - close menu and navigate to previous/next breadcrumb segment\n // ArrowDown/ArrowUp should pass through to let the menu handle them\n const container = this.#currentOpenTrigger?.querySelector(`ixfx-menu-container`);\n if (!container || !this.#currentOpenTrigger?.isOpen)\n return;\n\n switch (e.key) {\n case `ArrowLeft`:\n case `ArrowRight`: {\n e.preventDefault();\n e.stopPropagation();\n this.#currentOpenTrigger.closeMenu();\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n break;\n const pathNodes = this.#findPath(r, sel) ?? [r];\n const totalItems = pathNodes.length + (this.#hasChildOptions() ? 1 : 0);\n const currentTickled = this.tickled.tickledId ?? -1;\n if (e.key === `ArrowLeft`) {\n if (currentTickled > 0) {\n this.tickled.handleKeyboardNavigation(`previous`);\n }\n } else {\n if (currentTickled < totalItems - 1) {\n this.tickled.handleKeyboardNavigation(`next`);\n }\n }\n break;\n }\n }\n };\n\n #onKeyDown = (e: KeyboardEvent): void => {\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n const totalItems = pathNodes.length + (this.#hasChildOptions() ? 1 : 0);\n const currentTickled = this.tickled.tickledId ?? -1;\n\n switch (e.key) {\n case `ArrowRight`: {\n e.preventDefault();\n if (currentTickled < totalItems - 1) {\n this.tickled.handleKeyboardNavigation(`next`);\n } else if (currentTickled === totalItems - 1) {\n this.#shiftFocusToNarrowedText();\n }\n break;\n }\n case `ArrowLeft`: {\n e.preventDefault();\n if (currentTickled > 0) {\n this.tickled.handleKeyboardNavigation(`previous`);\n }\n break;\n }\n case `ArrowDown`:\n case `ArrowUp`: {\n if (this.tickled.tickledId !== undefined) {\n e.preventDefault();\n if (this.#currentOpenTrigger?.isOpen) {\n // Menu is already open - dispatch ArrowDown to the popover element for it to handle\n const container = this.#currentOpenTrigger.querySelector(`ixfx-menu-container`);\n const popover = container?.shadowRoot?.querySelector(`.popover`);\n if (popover) {\n popover.dispatchEvent(new KeyboardEvent(`keydown`, { key: e.key, bubbles: true }));\n }\n } else {\n this.#handleOpenCaretMenu();\n }\n }\n break;\n }\n case `Enter`: {\n e.preventDefault();\n this.#handleEnter();\n break;\n }\n case `Escape`: {\n e.preventDefault();\n this._menuOpen = false;\n this.tickled.clearTickled();\n this.blur();\n break;\n }\n case `Tab`: {\n if (e.shiftKey) {\n e.preventDefault();\n this.#shiftFocusToPath();\n } else if (currentTickled === totalItems - 1) {\n e.preventDefault();\n this._menuOpen = false;\n this._focusOnNarrowedText = true;\n const narrowedText = this.shadowRoot?.querySelector(`ixfx-narrowed-text`);\n if (narrowedText) {\n narrowedText.focus();\n }\n }\n break;\n }\n }\n };\n\n #handleEnter() {\n const r = this.root;\n const sel = this.selectedNode;\n if (!r || !sel)\n return;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n const hasChildOptions = this.#hasChildOptions();\n const currentTickled = this.tickled.tickledId ?? -1;\n\n if (currentTickled < pathNodes.length) {\n const node = pathNodes[currentTickled];\n this.#setSelected(node);\n this._menuOpen = false;\n this.dispatchEvent(new CustomEvent<CrumbNavigationItemClickDetail>(`item-click`, {\n detail: { node, depth: currentTickled },\n bubbles: true,\n composed: true,\n }));\n } else if (hasChildOptions && currentTickled === pathNodes.length) {\n this._menuOpen = true;\n this.#menuOpenedByKeyboard = true;\n const trigger = this.shadowRoot?.querySelector<MenuTrigger>(`#child-options-trigger`);\n if (trigger) {\n this.#currentOpenTrigger = trigger;\n document.addEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });\n trigger.openMenu();\n this.#propagateInputModeToMenu();\n }\n }\n }\n\n #shiftFocusToNarrowedText() {\n const narrowedText = this.shadowRoot?.querySelector(`ixfx-narrowed-text`);\n if (narrowedText) {\n this._focusOnNarrowedText = true;\n narrowedText.focus();\n }\n }\n\n #shiftFocusToPath() {\n this._focusOnNarrowedText = false;\n const hostContainer = this.shadowRoot?.querySelector<HTMLElement>(`.host-container`);\n if (hostContainer) {\n hostContainer.focus();\n }\n }\n\n #onNarrowedTextBlur = (): void => {\n this._focusOnNarrowedText = false;\n this.#shiftFocusToPath();\n };\n\n #onNarrowedTextShiftTab = (): void => {\n this._focusOnNarrowedText = false;\n this.#shiftFocusToPath();\n };\n\n // --- TreeComponent methods ---\n\n select(node: TreeNode): void {\n this.#setSelected(node);\n }\n\n deselect(_node: TreeNode): void {\n // Crumb navigation is single-selection; deselect navigates to parent or root\n }\n\n clearSelection(): void {\n if (this.root)\n this.#setSelected(this.root);\n }\n\n getNodes(): ReadonlyArray<{ node: TreeNode; depth: number }> {\n if (!this.root)\n return [];\n const result: Array<{ node: TreeNode; depth: number }> = [];\n const visit = (node: TreeNode, depth: number) => {\n result.push({ node, depth });\n if (node.children) {\n for (const child of node.children) visit(child, depth + 1);\n }\n };\n for (const child of this.root.children ?? []) visit(child, 0);\n return result;\n }\n\n // --- Lifecycle ---\n\n override updated(changedProps: PropertyValues): void {\n if (changedProps.has(`model`)) {\n this.#modelUnsubscribe?.();\n this.#modelUnsubscribe = undefined;\n const model = this.model;\n if (model) {\n this.root = model.root;\n this.#modelUnsubscribe = model._subscribe((event) => {\n if (event.type === `root`) {\n this.root = event.root;\n this.requestUpdate();\n }\n });\n }\n }\n this.#runLayoutUpdate(changedProps);\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this.addEventListener(`click`, this.#onHostClick);\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener(`click`, this.#onHostClick);\n this.#modelUnsubscribe?.();\n this.#modelUnsubscribe = undefined;\n document.removeEventListener(`keydown`, this.#onMenuKeyNav, { capture: true });\n this.#currentOpenTrigger = null;\n }\n\n #runLayoutUpdate(_changedProperties: PropertyValues): void {\n if (!this.shadowRoot)\n return;\n\n const hsiElement: HTMLElement | null = this.shadowRoot.querySelector(`.horiz-select-items`);\n if (!hsiElement)\n return;\n\n const ulElement: HTMLElement | null = hsiElement.querySelector(`ul`);\n if (!ulElement)\n return;\n\n const menuTrigger: HTMLElement | null = this.shadowRoot.querySelector(`ixfx-menu-trigger`);\n if (!menuTrigger)\n return;\n\n if (ulElement.getBoundingClientRect().width > hsiElement.getBoundingClientRect().width) {\n menuTrigger.style.display = `inline-flex`;\n } else {\n menuTrigger.style.display = `none`;\n }\n\n for (const li of ulElement.querySelectorAll(`li`)) {\n const key = li.getAttribute(`data-key`) ?? ``;\n if (key === this.#previousSelectionKey) {\n this.#scrollToValue(li);\n break;\n }\n }\n }\n\n #scrollToValue(li: HTMLLIElement) {\n let l = li.offsetLeft;\n\n const ul = li.parentElement;\n if (!ul)\n return;\n l -= ul.offsetLeft;\n\n const horizSelectItems = ul.parentElement;\n if (!horizSelectItems)\n return;\n horizSelectItems.scroll({ left: l, top: 0, behavior: `smooth` });\n\n const horizSelect = horizSelectItems.parentElement;\n if (!horizSelect)\n return;\n horizSelect.style.minWidth = `${li.getBoundingClientRect().width}px`;\n }\n\n #abortPending() {\n if (this.#pendingController) {\n this.#pendingController.abort();\n this.#pendingController = undefined;\n this.#pendingNode = undefined;\n }\n }\n\n #findPath(node: TreeNode, target: TreeNode, acc: TreeNode[] = []): TreeNode[] | undefined {\n const path = [...acc, node];\n if (node === target)\n return path;\n if (!node.children)\n return undefined;\n for (const child of node.children) {\n const result = this.#findPath(child, target, path);\n if (result)\n return result;\n }\n return undefined;\n }\n\n #setSelected(node: TreeNode) {\n const previous = this.selectedNode;\n if (previous) {\n this.#previousSelectionKey = previous.item?.key ?? ``;\n } else {\n this.#previousSelectionKey = ``;\n }\n const previousSet: ReadonlySet<TreeNode> = previous ? new Set([previous]) : new Set();\n this.selectedNode = node;\n this._selectedNodes = new Set([node]);\n\n this.dispatchEvent(new CustomEvent<TreeSelectDetail>(`select`, {\n detail: { selected: new Set([node]), previous: previousSet },\n bubbles: true,\n composed: true,\n }));\n }\n\n #onLabelClick(node: TreeNode, depth: number) {\n this._openIdx = -1;\n this.#setSelected(node);\n this.dispatchEvent(new CustomEvent<CrumbNavigationItemClickDetail>(`item-click`, {\n detail: { node, depth },\n bubbles: true,\n composed: true,\n }));\n }\n\n #onCaretClick(node: TreeNode, depth: number, e: MouseEvent) {\n e.preventDefault();\n e.stopPropagation();\n\n if (this._openIdx === depth) {\n this._openIdx = -1;\n return;\n }\n this._openIdx = depth;\n\n if (node.children === undefined && this.#pendingNode !== node) {\n this.#abortPending();\n this.#pendingNode = node;\n const controller = new AbortController();\n this.#pendingController = controller;\n\n if (this.loadChildren) {\n this.#invokeLoadChildren(node, depth, controller).catch(() => {});\n }\n }\n\n this.requestUpdate();\n }\n\n async #invokeLoadChildren(node: TreeNode, depth: number, controller: AbortController): Promise<void> {\n try {\n const children = [...await collectDataResult(\n this.loadChildren!({ node, depth }, controller.signal),\n controller.signal,\n )];\n if (controller.signal.aborted)\n return;\n node.children = children;\n this.#pendingNode = undefined;\n this.#pendingController = undefined;\n this.dispatchEvent(new CustomEvent<CrumbNavigationExpandDetail>(`expand`, {\n detail: { node, depth },\n bubbles: true,\n composed: true,\n }));\n this.requestUpdate();\n } catch {\n if (controller.signal.aborted)\n return;\n node.children = [];\n this.#pendingNode = undefined;\n this.#pendingController = undefined;\n this.requestUpdate();\n }\n }\n\n #onSegmentMenuCommand(e: CustomEvent, node: TreeNode, depth: number) {\n const key = e.detail.command;\n const child = node.children?.find(c => c.item.key === key);\n if (child) {\n this.#onChildClick(child, depth + 1);\n }\n }\n\n #onChildClick(node: TreeNode, depth: number) {\n this._openIdx = -1;\n this.#setSelected(node);\n this.dispatchEvent(new CustomEvent<CrumbNavigationItemClickDetail>(`item-click`, {\n detail: { node, depth },\n bubbles: true,\n composed: true,\n }));\n }\n\n /** Navigate to a node by key path. Returns false if any key is not found in already-loaded children. */\n navigateTo(keys: readonly string[]): boolean {\n if (!this.root?.children)\n return false;\n let current: TreeNode | undefined = this.root;\n for (const key of keys) {\n const found: TreeNode | undefined = current?.children?.find(n => n.item.key === key);\n if (!found)\n return false;\n current = found;\n }\n if (current && current !== this.root) {\n this.#setSelected(current);\n }\n return true;\n }\n\n /** Navigate to the first node matching the predicate. Returns false if not found. */\n navigateToNode(predicate: (node: TreeNode) => boolean): boolean {\n if (!this.root)\n return false;\n const keyPath = this.#findNodePath(this.root.children ?? [], predicate);\n if (!keyPath)\n return false;\n return this.navigateTo(keyPath);\n }\n\n #findNodePath(\n nodes: TreeNode[],\n predicate: (node: TreeNode) => boolean,\n prefix: string[] = [],\n ): string[] | undefined {\n for (const node of nodes) {\n const path = [...prefix, node.item.key];\n if (predicate(node))\n return path;\n if (node.children?.length) {\n const result = this.#findNodePath(node.children, predicate, path);\n if (result)\n return result;\n }\n }\n return undefined;\n }\n\n #onMenuCommand(e: CustomEvent) {\n const node = this.selectedNode;\n if (!node?.children)\n return;\n\n const key = e.detail.command;\n const child = node.children.find(c => c.item.key === key);\n if (child) {\n const depth = this.root ? (this.#findPath(this.root, node)?.length ?? 1) : 1;\n this.#onChildClick(child, depth);\n }\n }\n\n render() {\n const r = this.root;\n const sel = this.selectedNode;\n\n if (!r || !sel) {\n return html``;\n }\n\n this.inputMode = this.tickled.inputMode;\n\n const pathNodes = this.#findPath(r, sel) ?? [r];\n const _hasChildOptions = this.#hasChildOptions();\n\n const parts = pathNodes.map((node, i) => {\n const isLast = i === pathNodes.length - 1;\n const isPending = this.#pendingNode === node;\n const isOpen = this._openIdx === i;\n const hasChildren = node.item.isLeaf !== true && (node.children === undefined || node.children.length > 0);\n const showCaret = !isLast && hasChildren;\n const isTickled = this.tickled.isTickled(i);\n\n const menuItems = (node.children ?? []).map(c => html`\n <ixfx-menu-item \n label=\"${c.item.label}\" \n command=\"${c.item.key}\"\n icon-name=\"${c.item.icon ?? nothing}\"\n ></ixfx-menu-item>\n `);\n\n return html`\n <div class=\"item crumb-segment ${isTickled ? `tickled` : ``}\"\n @pointerenter=${() => {\n this.tickled.handlePointerEnter(i);\n this.dispatchEvent(new CustomEvent<TreeTickleDetail>(`tickle`, { detail: { node, depth: i }, bubbles: true, composed: true }));\n }}\n >\n <span class=\"label\" @click=${() => this.#onLabelClick(node, i)}>${node.item.label}</span>\n ${showCaret\n ? html`\n <span class=\"caret ${isOpen ? `open` : ``} ${isPending ? `pending` : ``}\">\n ${isPending\n ? html`<span class=\"loading-spinner\"></span>`\n : html`\n <ixfx-menu-trigger mode=\"trigger\" label=\"›\" @menu-command=${(e: CustomEvent) => this.#onSegmentMenuCommand(e, node, i)}>\n <ixfx-menu-container slot=\"menu\">\n ${menuItems}\n </ixfx-menu-container>\n </ixfx-menu-trigger>\n `\n }\n </span>\n `\n : nothing\n }\n </div>\n `;\n });\n\n const childOptions = this.#renderChildOptions();\n const isLastItemTickled = this.tickled.isTickled(pathNodes.length);\n return html`\n <div\n class=\"host-container\"\n tabindex=\"0\"\n @focus=${this.#onFocus}\n @blur=${this.#onBlur}\n @keydown=${this.#onKeyDown}\n @click=${this.#onHostClick}\n @menu-trigger-close=${this.#onMenuTriggerClose}\n @pointerleave=${(e: PointerEvent) => this.tickled.handlePointerLeave(e)}\n >\n <div class=\"parts\">${parts}<div class=\"trailing\"></div></div>\n ${childOptions\n ? html`\n <ixfx-menu-trigger\n id=\"child-options-trigger\"\n class=\"item separator-trigger ${isLastItemTickled ? `tickled` : ``}\"\n mode=\"trigger\"\n label=\"›\"\n @menu-command=${this.#onMenuCommand}\n @pointerenter=${() => this.tickled.handlePointerEnter(pathNodes.length)}\n >\n <ixfx-menu-container slot=\"menu\">\n ${(this.selectedNode?.children ?? []).map(c => html`\n <ixfx-menu-item \n label=\"${c.item.label}\" \n command=\"${c.item.key}\"\n icon-name=\"${c.item.icon ?? nothing}\"\n ></ixfx-menu-item>\n `)}\n </ixfx-menu-container>\n </ixfx-menu-trigger>\n `\n : nothing}\n ${childOptions}\n </div>\n `;\n }\n\n #renderChildOptions() {\n const s = this.selectedNode;\n if (s === undefined) {\n return nothing;\n }\n\n const isPending = this.#pendingNode === s;\n const children = s.children ?? [];\n\n if (children.length === 0 && !isPending) {\n return nothing;\n }\n\n if (isPending) {\n return html`\n <div class=\"horiz-select\">\n <div class=\"horiz-select-items\">\n <span class=\"loading-spinner\"></span>\n </div>\n </div>\n `;\n }\n\n return html`\n <ixfx-narrowed-text\n class=\"horiz-select\"\n selection-mode=\"single\"\n orientation=\"horizontal\"\n nowrap\n width=${this.#getChildOptionsWidth()}\n @change=${this.#onNarrowedTextChange}\n @narrowed-text-blur=${this.#onNarrowedTextBlur}\n @narrowed-text-shift-tab=${this.#onNarrowedTextShiftTab}\n >\n ${children.map(c => html`\n <span data-value=\"${c.item.key}\" data-label=\"${c.item.label}\"></span>\n `)}\n </ixfx-narrowed-text>\n `;\n }\n\n #onNarrowedTextChange(e: CustomEvent) {\n e.stopPropagation();\n const detail = e.detail as { item: { value: string } };\n const node = this.selectedNode;\n if (!node?.children)\n return;\n\n const child = node.children.find(c => c.item.key === detail.item.value);\n if (child) {\n const depth = this.root ? (this.#findPath(this.root, node)?.length ?? 1) : 1;\n this.#onChildClick(child, depth);\n }\n }\n\n #getChildOptionsWidth(): string {\n return `var(--child-options-width, 50ch)`;\n }\n\n static styles = [themeFallbacks, tickledStyles, tickledItemStyles, css`\n :host {\n --text-highlight: var(--accent);\n --separator: var(--surface-muted-text);\n --padding-s: var(--space-xs);\n display: flex;\n overflow: scroll;\n width: 100%;\n scroll-snap-type: x mandatory;\n scrollbar-width: none;\n\n /* Breadcrumb tickled overrides — no layout shift: keep transparent border at rest */\n --item-padding: 0;\n }\n\n :host(.focused) {\n outline: none;\n }\n\n :host(:focus-within) .host-container {\n outline: 2px solid var(--accent);\n outline-offset: 2px;\n }\n\n .host-container {\n display: flex;\n width: 100%;\n outline: none;\n }\n\n .parts {\n display: flex;\n }\n\n .trailing {\n flex: 1;\n min-width: 1em;\n cursor: pointer;\n }\n\n .crumb-segment {\n display: flex;\n align-items: center;\n }\n\n .label {\n cursor: pointer;\n margin-right: var(--padding-s);\n white-space: nowrap;\n }\n\n .caret {\n position: relative;\n cursor: pointer;\n padding: var(--padding-m);\n margin-left: var(--padding-s);\n margin-right: var(--padding-s);\n color: var(--separator);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease-in-out;\n }\n\n .caret.open {\n background: color-mix(in srgb, var(--surface-5) 40%, transparent);\n }\n\n .caret.pending {\n display: inline-flex;\n }\n\n .caret > ixfx-menu-trigger {\n display: inline-flex;\n margin: 0;\n --_trigger-hover-bg: transparent;\n --_trigger-hover-opacity: 0.6;\n }\n\n .caret > ixfx-menu-trigger::part(base) {\n background: none;\n border: none;\n color: inherit;\n padding: 0;\n cursor: pointer;\n font-size: inherit;\n line-height: 1;\n }\n\n .caret > ixfx-menu-trigger::part(base):hover {\n background: none;\n opacity: 0.6;\n }\n\n .separator {\n margin-left: var(--padding-s);\n margin-right: var(--padding-s);\n color: var(--separator);\n }\n\n .separator-trigger {\n display: inline-flex;\n margin-left: var(--padding-s);\n margin-right: var(--padding-s);\n --_trigger-hover-bg: transparent;\n --_trigger-hover-opacity: 0.6;\n }\n\n .separator-trigger::part(base) {\n background: none;\n border: none;\n color: var(--separator);\n padding: 0;\n cursor: pointer;\n font-size: inherit;\n line-height: 1;\n }\n\n .separator-trigger::part(base):hover {\n background: none;\n opacity: 0.6;\n }\n\n .separator-trigger.tickled::part(base) {\n }\n\n ixfx-menu-trigger {\n display: none;\n }\n\n .horiz-select > ixfx-menu-trigger {\n display: inline-flex;\n }\n\n .horiz-select {\n display: flex;\n min-width: 5ch;\n }\n\n .loading-spinner {\n display: inline-block;\n width: 12px;\n height: 12px;\n border: 2px solid var(--surface-5);\n border-top-color: var(--accent);\n border-radius: 50%;\n animation: crumb-spin 0.7s linear infinite;\n }\n\n @keyframes crumb-spin {\n to { transform: rotate(360deg); }\n }\n\n ::slotted(*), option {\n user-select: none;\n scroll-snap-align: start;\n }\n `];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ixfx-crumb-navigation\": CrumbNavigationElement;\n }\n}\n\nexport interface CrumbNavigationElementEventMap extends TreeComponentEventMap {\n 'item-click': TreeItemClickEvent;\n 'expand': TreeExpandEvent;\n 'select': TreeSelectEvent;\n 'tickle': TreeTickleEvent;\n 'activate': TreeActivateEvent;\n}\n\nexport interface CrumbNavigationElement {\n addEventListener: (<K extends keyof CrumbNavigationElementEventMap>(\n type: K,\n listener: (this: CrumbNavigationElement, event: CrumbNavigationElementEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ) => void) & ((\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ) => void);\n}\n"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  import { LitElement } from "lit";
2
-
3
2
  //#region src/data-display/data-display.d.ts
4
3
  type RendererStyle = `led` | `plot` | `plot-xy` | `plot-heat` | `plot-histogram` | `time-elapsed` | `hide`;
5
4
  type ConfigEntry = readonly [path: string, style: RendererStyle, options?: Record<string, unknown>];
@@ -25,7 +24,7 @@ declare global {
25
24
  interface HTMLElementTagNameMap {
26
25
  'ixfx-data-display': DataDisplayComponent;
27
26
  }
28
- } //# sourceMappingURL=data-display.d.ts.map
27
+ }
29
28
  //#endregion
30
29
  export { ConfigEntry, DataDisplayComponent, FormattingOptions, RendererStyle };
31
30
  //# sourceMappingURL=data-display.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-display.d.ts","names":[],"sources":["../src/data-display/data-display.ts"],"mappings":";;;KAOY,aAAA;AAAA,KASA,WAAA,aACV,IAAA,UACA,KAAA,EAAO,aAAA,EACP,OAAA,GAAU,MAAM;AAAA,KAGN,iBAAA;EAAA,SACD,SAAA;EAAA,SACA,YAAY;AAAA;AAAA,cAWV,oBAAA,SAA6B,UAAA;EAAA;SACxB,MAAA,gBAAM,SAAA;EAqCtB,OAAA;EAEA,aAAA,EAAe,MAAA;EACf,UAAA,EAAY,WAAA;;EAYH,iBAAA;EAKT,SAAA,CAAU,MAAA,EAAQ,WAAA;EAalB,WAAA,CAAY,CAAA,WAAY,OAAA,GAAS,iBAAA;EAqBjC,WAAA,CAAY,CAAA,EAAG,MAAA;EAQf,UAAA,CAAW,KAAA,EAAO,MAAA;EAMlB,WAAA,CAAY,IAAA,UAAc,IAAA,IAAQ,MAAA,EAAQ,WAAA,YAAuB,WAAA;AAAA;AAAA,QA6V3D,MAAA;EAAA,UACI,qBAAA;IACR,mBAAA,EAAqB,oBAAoB;EAAA;AAAA"}
1
+ {"version":3,"file":"data-display.d.ts","names":[],"sources":["../src/data-display/data-display.ts"],"mappings":";;KAOY;KASA,wBACV,cACA,OAAO,eACP,UAAU;KAGA;WACD;WACA;;cAWE,6BAA6B;;SACxB,sBAAM;EAqCtB;EAEA,eAAe;EACf,YAAY;;EAYH;EAKT,UAAU,QAAQ;EAalB,YAAY,YAAY,UAAS;EAqBjC,YAAY,GAAG;EAQf,WAAW,OAAO;EAMlB,YAAY,cAAc,QAAQ,QAAQ,uBAAuB;;QA6V3D;YACI;IACR,qBAAqB"}
@@ -1,8 +1,8 @@
1
1
  import { t as themeFallbacks } from "./fallbacks-pNMOMx38.js";
2
- import { n as safeCustomElement, t as __decorate } from "./decorate-DdjvVHS-.js";
3
- import { c as round, s as rangeStream } from "./dist-CA13FvMn.js";
2
+ import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
4
3
  import { LitElement, css } from "lit";
5
4
  import { property } from "lit/decorators.js";
5
+ import { rangeStream, round } from "@ixfx/numbers";
6
6
  //#region src/data-display/data-display.ts
7
7
  let DataDisplayComponent = class DataDisplayComponent extends LitElement {
8
8
  static {
@@ -121,15 +121,16 @@ let DataDisplayComponent = class DataDisplayComponent extends LitElement {
121
121
  }
122
122
  continue;
123
123
  }
124
- if (typeof value === `object` && value !== null && !Array.isArray(value)) if (this.#hasDescendantConfig(fullPath)) this.#walk(value, fullPath, activePaths);
125
- else if (this.automap) {
126
- const row = this.#ensureRow(fullPath, key);
127
- this.#renderNestedDisplay(row, value, true);
124
+ if (typeof value === `object` && value !== null && !Array.isArray(value)) {
125
+ if (this.#hasDescendantConfig(fullPath)) this.#walk(value, fullPath, activePaths);
126
+ else if (this.automap) {
127
+ const row = this.#ensureRow(fullPath, key);
128
+ this.#renderNestedDisplay(row, value, true);
129
+ } else {
130
+ const row = this.#ensureRow(fullPath, key);
131
+ this.#renderNestedDisplay(row, value);
132
+ }
128
133
  } else {
129
- const row = this.#ensureRow(fullPath, key);
130
- this.#renderNestedDisplay(row, value);
131
- }
132
- else {
133
134
  const autoStyle = this.#determineAutoStyle(value);
134
135
  if (autoStyle !== void 0) {
135
136
  const row = this.#ensureRow(fullPath, key);
@@ -210,13 +211,15 @@ let DataDisplayComponent = class DataDisplayComponent extends LitElement {
210
211
  case `plot`:
211
212
  if (typeof value === `number`) {
212
213
  if (changed) el.add(value);
213
- } else if (typeof value === `object` && value !== null && changed) if (Array.isArray(value)) {
214
- const record = {};
215
- value.forEach((v, i) => {
216
- if (typeof v === `number`) record[String(i)] = v;
217
- });
218
- if (Object.keys(record).length > 0) el.addData(record);
219
- } else el.addData(value);
214
+ } else if (typeof value === `object` && value !== null && changed) {
215
+ if (Array.isArray(value)) {
216
+ const record = {};
217
+ value.forEach((v, i) => {
218
+ if (typeof v === `number`) record[String(i)] = v;
219
+ });
220
+ if (Object.keys(record).length > 0) el.addData(record);
221
+ } else el.addData(value);
222
+ }
220
223
  this.#applyPlotOptions(el, style, options);
221
224
  break;
222
225
  case `plot-xy`:
@@ -228,9 +231,7 @@ let DataDisplayComponent = class DataDisplayComponent extends LitElement {
228
231
  if (typeof value === `number` && changed) el.add(value);
229
232
  this.#applyPlotOptions(el, style, options);
230
233
  break;
231
- case `time-elapsed`:
232
- el.textContent = this.#formatTimeElapsed(value);
233
- break;
234
+ case `time-elapsed`: el.textContent = this.#formatTimeElapsed(value);
234
235
  }
235
236
  this.#previousValues.set(path, value);
236
237
  }
@@ -276,9 +277,10 @@ let DataDisplayComponent = class DataDisplayComponent extends LitElement {
276
277
  #formatTimeElapsed(value) {
277
278
  let timestamp;
278
279
  if (value instanceof Date) timestamp = value.getTime();
279
- else if (typeof value === `number`) if (value > 0xe8d4a51000) timestamp = value;
280
- else timestamp = Date.now();
281
- else if (typeof value === `string`) timestamp = new Date(value).getTime();
280
+ else if (typeof value === `number`) {
281
+ if (value > 0xe8d4a51000) timestamp = value;
282
+ else timestamp = Date.now();
283
+ } else if (typeof value === `string`) timestamp = new Date(value).getTime();
282
284
  else return String(value);
283
285
  if (Number.isNaN(timestamp)) return String(value);
284
286
  const elapsed = Date.now() - timestamp;
@@ -1 +1 @@
1
- {"version":3,"file":"data-display.js","names":["#config","#previousValues","#rangeStreams","#currentData","#renderAll","#walk","#cleanupPaths","#ensureRow","#updateRenderer","#hasDescendantConfig","#renderNestedDisplay","#determineAutoStyle","#renderText","#rendererTag","#getOrCreateRendererElement","#applyValue","#applyLed","#applyPlotOptions","#applyPlotXy","#formatTimeElapsed","customElement"],"sources":["../src/data-display/data-display.ts"],"sourcesContent":["import { rangeStream, round } from \"@ixfx/numbers\";\n\nimport { css, LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\n\nexport type RendererStyle\n = | `led`\n | `plot`\n | `plot-xy`\n | `plot-heat`\n | `plot-histogram`\n | `time-elapsed`\n | `hide`;\n\nexport type ConfigEntry = readonly [\n path: string,\n style: RendererStyle,\n options?: Record<string, unknown>,\n];\n\nexport type FormattingOptions = {\n readonly precision?: number;\n readonly roundNumbers?: number;\n};\n\ntype ConfigRecord = {\n readonly style: RendererStyle;\n readonly options?: Record<string, unknown>;\n};\n\ntype RangeStream = ReturnType<typeof rangeStream>;\n\n@customElement(`ixfx-data-display`)\nexport class DataDisplayComponent extends LitElement {\n static override styles = [themeFallbacks, css`\n :host {\n display: block;\n width: fit-content;\n }\n section {\n background: var(--surface-3);\n color: var(--surface-2-text);\n border: var(--border);\n padding: var(--space-m);\n font-family: var(--font-mono);\n display: grid;\n grid-template-columns: auto auto;\n column-gap: var(--space-s);\n }\n .row {\n display: contents;\n }\n .row > label {\n font-weight: bold;\n text-align: end;\n justify-self: end;\n padding: 2px 0;\n }\n .row > :not(label) {\n padding: 2px 0;\n }\n .row > ixfx-led {\n align-self: center;\n }\n .value {\n font-variant-numeric: tabular-nums;\n white-space: pre;\n }\n `];\n\n @property({ type: Boolean })\n automap = false;\n\n previousValue: Record<string, unknown> | undefined;\n _container: HTMLElement;\n\n #config = new Map<string, ConfigRecord>();\n #previousValues = new Map<string, unknown>();\n #rangeStreams = new Map<string, RangeStream>();\n #currentData: Record<string, unknown> | undefined;\n\n constructor() {\n super();\n this._container = document.createElement(`section`);\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this.renderRoot.append(this._container);\n }\n\n configure(config: ConfigEntry[]) {\n this.#config.clear();\n for (const [path, style, options] of config) {\n this.#config.set(path, { style, options });\n }\n this._container.innerHTML = ``;\n this.#previousValues.clear();\n this.#rangeStreams.clear();\n if (this.#currentData !== undefined) {\n this.#renderAll(this.#currentData);\n }\n }\n\n formatValue(v: unknown, options: FormattingOptions = {}): string {\n if (v === null)\n return `(null)`;\n if (v === undefined)\n return `(undefined)`;\n if (typeof v === `boolean`)\n return v ? `true` : `false`;\n if (typeof v === `string`)\n return `\"${v}\"`;\n if (typeof v === `number`) {\n let vAsNumber = v;\n if (options.roundNumbers !== undefined)\n vAsNumber = round(options.roundNumbers, v);\n if (options.precision !== undefined)\n return vAsNumber.toFixed(options.precision);\n const formatted = vAsNumber.toFixed(2);\n return vAsNumber >= 0 ? ` ${formatted}` : formatted;\n }\n return JSON.stringify(v);\n }\n\n displayData(o: Record<string, unknown> | unknown[]) {\n if (o === null) {\n this.innerHTML = ``;\n return;\n }\n this.#renderAll(o as Record<string, unknown>);\n }\n\n updateData(value: Record<string, unknown>) {\n this.#currentData = value;\n this.#renderAll(value);\n this.previousValue = value;\n }\n\n getOrCreate(path: string, init?: (parent: HTMLElement) => void): HTMLElement {\n const element = this.renderRoot.querySelector(`#${path}`) as HTMLElement | null;\n if (element !== null)\n return element;\n\n const elementCreated = document.createElement(`div`);\n elementCreated.id = path;\n if (init)\n init(elementCreated);\n this._container.append(elementCreated);\n return elementCreated;\n }\n\n #renderAll(data: Record<string, unknown>) {\n const activePaths = new Set<string>();\n this.#walk(data, ``, activePaths);\n this.#cleanupPaths(activePaths);\n }\n\n #walk(\n data: Record<string, unknown>,\n basePath: string,\n activePaths: Set<string>,\n ) {\n for (const [key, value] of Object.entries(data)) {\n const fullPath = basePath ? `${basePath}.${key}` : key;\n activePaths.add(fullPath);\n\n const config = this.#config.get(fullPath);\n\n if (config !== undefined) {\n if (config.style !== `hide`) {\n const row = this.#ensureRow(fullPath, key);\n this.#updateRenderer(row, fullPath, config.style, value, config.options);\n }\n continue;\n }\n\n if (typeof value === `object` && value !== null && !Array.isArray(value)) {\n if (this.#hasDescendantConfig(fullPath)) {\n this.#walk(value as Record<string, unknown>, fullPath, activePaths);\n } else if (this.automap) {\n const row = this.#ensureRow(fullPath, key);\n this.#renderNestedDisplay(row, value as Record<string, unknown>, true);\n } else {\n const row = this.#ensureRow(fullPath, key);\n this.#renderNestedDisplay(row, value as Record<string, unknown>);\n }\n } else {\n const autoStyle = this.#determineAutoStyle(value);\n if (autoStyle !== undefined) {\n const row = this.#ensureRow(fullPath, key);\n this.#updateRenderer(row, fullPath, autoStyle, value, undefined);\n } else {\n const row = this.#ensureRow(fullPath, key);\n this.#renderText(row, this.formatValue(value));\n }\n }\n }\n }\n\n #hasDescendantConfig(path: string): boolean {\n const prefix = path ? `${path}.` : ``;\n for (const configPath of this.#config.keys()) {\n if (configPath.startsWith(prefix))\n return true;\n }\n return false;\n }\n\n #determineAutoStyle(value: unknown): RendererStyle | undefined {\n if (!this.automap)\n return undefined;\n if (typeof value === `boolean`)\n return `led`;\n if (typeof value === `number`)\n return `plot`;\n return undefined;\n }\n\n #ensureRow(path: string, label: string): HTMLElement {\n const id = `path-${path}`;\n let row = this.renderRoot.querySelector(`#${CSS.escape(id)}`) as HTMLElement | null;\n if (row !== null)\n return row;\n\n row = document.createElement(`div`);\n row.id = id;\n row.classList.add(`row`);\n\n const labelEl = document.createElement(`label`);\n labelEl.textContent = label;\n row.append(labelEl);\n\n this._container.append(row);\n return row;\n }\n\n #updateRenderer(\n row: HTMLElement,\n path: string,\n style: RendererStyle,\n value: unknown,\n options?: Record<string, unknown>,\n ) {\n const tag = this.#rendererTag(style, value);\n if (tag === null)\n return;\n\n const el = this.#getOrCreateRendererElement(row, tag);\n if (el === null)\n return;\n\n this.#applyValue(el, tag, style, path, value, options);\n }\n\n #rendererTag(style: RendererStyle, value: unknown): string | null {\n switch (style) {\n case `hide`:\n return null;\n case `led`:\n return `ixfx-led`;\n case `plot`:\n if (typeof value === `number`)\n return `ixfx-plot-single-axis`;\n if (typeof value === `object` && value !== null)\n return `ixfx-plot-multi-axis`;\n return `span`;\n case `plot-xy`:\n return `ixfx-plot-xy-axis`;\n case `plot-heat`:\n case `plot-histogram`:\n return `ixfx-plot-histogram`;\n case `time-elapsed`:\n return `span`;\n }\n }\n\n #getOrCreateRendererElement(row: HTMLElement, tag: string): HTMLElement | null {\n const existing = row.querySelector(`:scope > [data-renderer]`) as HTMLElement | null;\n if (existing !== null) {\n if (existing.tagName.toLowerCase() === tag)\n return existing;\n existing.remove();\n }\n const el = document.createElement(tag);\n el.dataset.renderer = ``;\n if (tag.startsWith(`ixfx-plot`)) {\n (el as HTMLElement).style.height = `1.4em`;\n if (tag === `ixfx-plot-xy-axis`) {\n (el as HTMLElement).style.width = `1.4em`;\n } else {\n (el as HTMLElement).style.width = `5em`;\n }\n }\n row.append(el);\n return el;\n }\n\n #applyValue(\n el: HTMLElement,\n _tag: string,\n style: RendererStyle,\n path: string,\n value: unknown,\n options?: Record<string, unknown>,\n ) {\n const prev = this.#previousValues.get(path);\n const changed = prev !== value;\n\n switch (style) {\n case `led`:\n this.#applyLed(el, path, value, options);\n break;\n\n case `plot`:\n if (typeof value === `number`) {\n if (changed) {\n (el as any).add(value);\n }\n } else if (typeof value === `object` && value !== null && changed) {\n if (Array.isArray(value)) {\n const record: Record<string, number> = {};\n value.forEach((v: unknown, i: number) => {\n if (typeof v === `number`)\n record[String(i)] = v;\n });\n if (Object.keys(record).length > 0) {\n (el as any).addData(record);\n }\n } else {\n (el as any).addData(value as Record<string, number>);\n }\n }\n this.#applyPlotOptions(el, style, options);\n break;\n\n case `plot-xy`:\n if (changed) {\n this.#applyPlotXy(el, value);\n }\n this.#applyPlotOptions(el, style, options);\n break;\n // @ts-expect-error fallthrough allowed\n case `plot-heat`:\n el.style.setProperty(`--plot-histogram-bar-length`, `1`);\n // falls through\n case `plot-histogram`:\n if (typeof value === `number` && changed) {\n (el as any).add(value);\n }\n this.#applyPlotOptions(el, style, options);\n break;\n\n case `time-elapsed`:\n el.textContent = this.#formatTimeElapsed(value);\n break;\n }\n\n this.#previousValues.set(path, value);\n }\n\n #applyLed(el: HTMLElement, path: string, value: unknown, options?: Record<string, unknown>) {\n const led = el as any;\n\n if (typeof value === `boolean`) {\n led.lit = value;\n led.value = value ? 1 : 0;\n } else if (typeof value === `number`) {\n let rs = this.#rangeStreams.get(path);\n if (rs === undefined) {\n rs = rangeStream();\n this.#rangeStreams.set(path, rs);\n }\n const range = rs.seen(value);\n const normalized = range.max !== range.min\n ? (value - range.min) / (range.max - range.min)\n : 0.5;\n led.value = normalized;\n led.lit = normalized > 0.3;\n }\n\n if (options?.color !== undefined)\n led.color = options.color;\n }\n\n #applyPlotXy(el: HTMLElement, value: unknown) {\n const xy = el as any;\n\n if (Array.isArray(value) && value.length >= 2) {\n xy.add(value[0], value[1]);\n } else if (typeof value === `object` && value !== null) {\n const obj = value as Record<string, number>;\n if (`x` in obj && `y` in obj) {\n xy.add(obj.x, obj.y);\n } else {\n const entries = Object.entries(obj).filter(([_, v]) => typeof v === `number`);\n if (entries.length >= 2) {\n xy.add(entries[0][1], entries[1][1]);\n }\n }\n }\n }\n\n #applyPlotOptions(el: HTMLElement, _style: RendererStyle, options?: Record<string, unknown>) {\n if (options === undefined)\n return;\n\n const target = el as any;\n\n if (typeof options.capacity === `number`)\n target.capacity = options.capacity;\n if (typeof options.resolution === `number`)\n target.resolution = options.resolution;\n if (typeof options.drawStyle === `string`)\n target.drawStyle = options.drawStyle;\n if (typeof options.orientation === `string`)\n target.orientation = options.orientation;\n if (typeof options.layout === `string`)\n target.layout = options.layout;\n }\n\n #formatTimeElapsed(value: unknown): string {\n let timestamp: number;\n\n if (value instanceof Date) {\n timestamp = value.getTime();\n } else if (typeof value === `number`) {\n if (value > 1e12) {\n timestamp = value;\n } else {\n timestamp = Date.now();\n }\n } else if (typeof value === `string`) {\n timestamp = new Date(value).getTime();\n } else {\n return String(value);\n }\n\n if (Number.isNaN(timestamp))\n return String(value);\n\n const elapsed = Date.now() - timestamp;\n const abs = Math.abs(elapsed);\n\n if (abs < 1000)\n return `${abs}ms`;\n if (abs < 60000)\n return `${(abs / 1000).toFixed(1)}s`;\n if (abs < 3600000)\n return `${(abs / 60000).toFixed(1)}mins`;\n if (abs < 86400000)\n return `${(abs / 3600000).toFixed(1)}h`;\n return `${(abs / 86400000).toFixed(1)}d`;\n }\n\n #renderText(row: HTMLElement, text: string) {\n let valueEl = row.querySelector(`:scope > .value`) as HTMLElement | null;\n if (valueEl === null) {\n valueEl = document.createElement(`span`);\n valueEl.classList.add(`value`);\n row.append(valueEl);\n }\n valueEl.textContent = text;\n }\n\n #renderNestedDisplay(row: HTMLElement, data: Record<string, unknown>, automapChild = false) {\n let child = row.querySelector(`:scope > ixfx-data-display`) as DataDisplayComponent | null;\n if (child === null) {\n child = document.createElement(`ixfx-data-display`) as DataDisplayComponent;\n row.append(child);\n }\n child.automap = automapChild;\n child.updateData(data);\n }\n\n #cleanupPaths(activePaths: Set<string>) {\n const rows = this._container.querySelectorAll<HTMLElement>(`[id^=\"path-\"]`);\n for (const row of rows) {\n const path = row.id.slice(5);\n if (!activePaths.has(path)) {\n row.remove();\n this.#rangeStreams.delete(path);\n this.#previousValues.delete(path);\n }\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-data-display': DataDisplayComponent;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"data-display.js","names":["#config","#previousValues","#rangeStreams","#currentData","#renderAll","#walk","#cleanupPaths","#ensureRow","#updateRenderer","#hasDescendantConfig","#renderNestedDisplay","#determineAutoStyle","#renderText","#rendererTag","#getOrCreateRendererElement","#applyValue","#applyLed","#applyPlotOptions","#applyPlotXy","#formatTimeElapsed","customElement"],"sources":["../src/data-display/data-display.ts"],"sourcesContent":["import { rangeStream, round } from \"@ixfx/numbers\";\n\nimport { css, LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\n\nexport type RendererStyle\n = | `led`\n | `plot`\n | `plot-xy`\n | `plot-heat`\n | `plot-histogram`\n | `time-elapsed`\n | `hide`;\n\nexport type ConfigEntry = readonly [\n path: string,\n style: RendererStyle,\n options?: Record<string, unknown>,\n];\n\nexport type FormattingOptions = {\n readonly precision?: number;\n readonly roundNumbers?: number;\n};\n\ntype ConfigRecord = {\n readonly style: RendererStyle;\n readonly options?: Record<string, unknown>;\n};\n\ntype RangeStream = ReturnType<typeof rangeStream>;\n\n@customElement(`ixfx-data-display`)\nexport class DataDisplayComponent extends LitElement {\n static override styles = [themeFallbacks, css`\n :host {\n display: block;\n width: fit-content;\n }\n section {\n background: var(--surface-3);\n color: var(--surface-2-text);\n border: var(--border);\n padding: var(--space-m);\n font-family: var(--font-mono);\n display: grid;\n grid-template-columns: auto auto;\n column-gap: var(--space-s);\n }\n .row {\n display: contents;\n }\n .row > label {\n font-weight: bold;\n text-align: end;\n justify-self: end;\n padding: 2px 0;\n }\n .row > :not(label) {\n padding: 2px 0;\n }\n .row > ixfx-led {\n align-self: center;\n }\n .value {\n font-variant-numeric: tabular-nums;\n white-space: pre;\n }\n `];\n\n @property({ type: Boolean })\n automap = false;\n\n previousValue: Record<string, unknown> | undefined;\n _container: HTMLElement;\n\n #config = new Map<string, ConfigRecord>();\n #previousValues = new Map<string, unknown>();\n #rangeStreams = new Map<string, RangeStream>();\n #currentData: Record<string, unknown> | undefined;\n\n constructor() {\n super();\n this._container = document.createElement(`section`);\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this.renderRoot.append(this._container);\n }\n\n configure(config: ConfigEntry[]) {\n this.#config.clear();\n for (const [path, style, options] of config) {\n this.#config.set(path, { style, options });\n }\n this._container.innerHTML = ``;\n this.#previousValues.clear();\n this.#rangeStreams.clear();\n if (this.#currentData !== undefined) {\n this.#renderAll(this.#currentData);\n }\n }\n\n formatValue(v: unknown, options: FormattingOptions = {}): string {\n if (v === null)\n return `(null)`;\n if (v === undefined)\n return `(undefined)`;\n if (typeof v === `boolean`)\n return v ? `true` : `false`;\n if (typeof v === `string`)\n return `\"${v}\"`;\n if (typeof v === `number`) {\n let vAsNumber = v;\n if (options.roundNumbers !== undefined)\n vAsNumber = round(options.roundNumbers, v);\n if (options.precision !== undefined)\n return vAsNumber.toFixed(options.precision);\n const formatted = vAsNumber.toFixed(2);\n return vAsNumber >= 0 ? ` ${formatted}` : formatted;\n }\n return JSON.stringify(v);\n }\n\n displayData(o: Record<string, unknown> | unknown[]) {\n if (o === null) {\n this.innerHTML = ``;\n return;\n }\n this.#renderAll(o as Record<string, unknown>);\n }\n\n updateData(value: Record<string, unknown>) {\n this.#currentData = value;\n this.#renderAll(value);\n this.previousValue = value;\n }\n\n getOrCreate(path: string, init?: (parent: HTMLElement) => void): HTMLElement {\n const element = this.renderRoot.querySelector(`#${path}`) as HTMLElement | null;\n if (element !== null)\n return element;\n\n const elementCreated = document.createElement(`div`);\n elementCreated.id = path;\n if (init)\n init(elementCreated);\n this._container.append(elementCreated);\n return elementCreated;\n }\n\n #renderAll(data: Record<string, unknown>) {\n const activePaths = new Set<string>();\n this.#walk(data, ``, activePaths);\n this.#cleanupPaths(activePaths);\n }\n\n #walk(\n data: Record<string, unknown>,\n basePath: string,\n activePaths: Set<string>,\n ) {\n for (const [key, value] of Object.entries(data)) {\n const fullPath = basePath ? `${basePath}.${key}` : key;\n activePaths.add(fullPath);\n\n const config = this.#config.get(fullPath);\n\n if (config !== undefined) {\n if (config.style !== `hide`) {\n const row = this.#ensureRow(fullPath, key);\n this.#updateRenderer(row, fullPath, config.style, value, config.options);\n }\n continue;\n }\n\n if (typeof value === `object` && value !== null && !Array.isArray(value)) {\n if (this.#hasDescendantConfig(fullPath)) {\n this.#walk(value as Record<string, unknown>, fullPath, activePaths);\n } else if (this.automap) {\n const row = this.#ensureRow(fullPath, key);\n this.#renderNestedDisplay(row, value as Record<string, unknown>, true);\n } else {\n const row = this.#ensureRow(fullPath, key);\n this.#renderNestedDisplay(row, value as Record<string, unknown>);\n }\n } else {\n const autoStyle = this.#determineAutoStyle(value);\n if (autoStyle !== undefined) {\n const row = this.#ensureRow(fullPath, key);\n this.#updateRenderer(row, fullPath, autoStyle, value, undefined);\n } else {\n const row = this.#ensureRow(fullPath, key);\n this.#renderText(row, this.formatValue(value));\n }\n }\n }\n }\n\n #hasDescendantConfig(path: string): boolean {\n const prefix = path ? `${path}.` : ``;\n for (const configPath of this.#config.keys()) {\n if (configPath.startsWith(prefix))\n return true;\n }\n return false;\n }\n\n #determineAutoStyle(value: unknown): RendererStyle | undefined {\n if (!this.automap)\n return undefined;\n if (typeof value === `boolean`)\n return `led`;\n if (typeof value === `number`)\n return `plot`;\n return undefined;\n }\n\n #ensureRow(path: string, label: string): HTMLElement {\n const id = `path-${path}`;\n let row = this.renderRoot.querySelector(`#${CSS.escape(id)}`) as HTMLElement | null;\n if (row !== null)\n return row;\n\n row = document.createElement(`div`);\n row.id = id;\n row.classList.add(`row`);\n\n const labelEl = document.createElement(`label`);\n labelEl.textContent = label;\n row.append(labelEl);\n\n this._container.append(row);\n return row;\n }\n\n #updateRenderer(\n row: HTMLElement,\n path: string,\n style: RendererStyle,\n value: unknown,\n options?: Record<string, unknown>,\n ) {\n const tag = this.#rendererTag(style, value);\n if (tag === null)\n return;\n\n const el = this.#getOrCreateRendererElement(row, tag);\n if (el === null)\n return;\n\n this.#applyValue(el, tag, style, path, value, options);\n }\n\n #rendererTag(style: RendererStyle, value: unknown): string | null {\n switch (style) {\n case `hide`:\n return null;\n case `led`:\n return `ixfx-led`;\n case `plot`:\n if (typeof value === `number`)\n return `ixfx-plot-single-axis`;\n if (typeof value === `object` && value !== null)\n return `ixfx-plot-multi-axis`;\n return `span`;\n case `plot-xy`:\n return `ixfx-plot-xy-axis`;\n case `plot-heat`:\n case `plot-histogram`:\n return `ixfx-plot-histogram`;\n case `time-elapsed`:\n return `span`;\n }\n }\n\n #getOrCreateRendererElement(row: HTMLElement, tag: string): HTMLElement | null {\n const existing = row.querySelector(`:scope > [data-renderer]`) as HTMLElement | null;\n if (existing !== null) {\n if (existing.tagName.toLowerCase() === tag)\n return existing;\n existing.remove();\n }\n const el = document.createElement(tag);\n el.dataset.renderer = ``;\n if (tag.startsWith(`ixfx-plot`)) {\n (el as HTMLElement).style.height = `1.4em`;\n if (tag === `ixfx-plot-xy-axis`) {\n (el as HTMLElement).style.width = `1.4em`;\n } else {\n (el as HTMLElement).style.width = `5em`;\n }\n }\n row.append(el);\n return el;\n }\n\n #applyValue(\n el: HTMLElement,\n _tag: string,\n style: RendererStyle,\n path: string,\n value: unknown,\n options?: Record<string, unknown>,\n ) {\n const prev = this.#previousValues.get(path);\n const changed = prev !== value;\n\n switch (style) {\n case `led`:\n this.#applyLed(el, path, value, options);\n break;\n\n case `plot`:\n if (typeof value === `number`) {\n if (changed) {\n (el as any).add(value);\n }\n } else if (typeof value === `object` && value !== null && changed) {\n if (Array.isArray(value)) {\n const record: Record<string, number> = {};\n value.forEach((v: unknown, i: number) => {\n if (typeof v === `number`)\n record[String(i)] = v;\n });\n if (Object.keys(record).length > 0) {\n (el as any).addData(record);\n }\n } else {\n (el as any).addData(value as Record<string, number>);\n }\n }\n this.#applyPlotOptions(el, style, options);\n break;\n\n case `plot-xy`:\n if (changed) {\n this.#applyPlotXy(el, value);\n }\n this.#applyPlotOptions(el, style, options);\n break;\n // @ts-expect-error fallthrough allowed\n case `plot-heat`:\n el.style.setProperty(`--plot-histogram-bar-length`, `1`);\n // falls through\n case `plot-histogram`:\n if (typeof value === `number` && changed) {\n (el as any).add(value);\n }\n this.#applyPlotOptions(el, style, options);\n break;\n\n case `time-elapsed`:\n el.textContent = this.#formatTimeElapsed(value);\n break;\n }\n\n this.#previousValues.set(path, value);\n }\n\n #applyLed(el: HTMLElement, path: string, value: unknown, options?: Record<string, unknown>) {\n const led = el as any;\n\n if (typeof value === `boolean`) {\n led.lit = value;\n led.value = value ? 1 : 0;\n } else if (typeof value === `number`) {\n let rs = this.#rangeStreams.get(path);\n if (rs === undefined) {\n rs = rangeStream();\n this.#rangeStreams.set(path, rs);\n }\n const range = rs.seen(value);\n const normalized = range.max !== range.min\n ? (value - range.min) / (range.max - range.min)\n : 0.5;\n led.value = normalized;\n led.lit = normalized > 0.3;\n }\n\n if (options?.color !== undefined)\n led.color = options.color;\n }\n\n #applyPlotXy(el: HTMLElement, value: unknown) {\n const xy = el as any;\n\n if (Array.isArray(value) && value.length >= 2) {\n xy.add(value[0], value[1]);\n } else if (typeof value === `object` && value !== null) {\n const obj = value as Record<string, number>;\n if (`x` in obj && `y` in obj) {\n xy.add(obj.x, obj.y);\n } else {\n const entries = Object.entries(obj).filter(([_, v]) => typeof v === `number`);\n if (entries.length >= 2) {\n xy.add(entries[0][1], entries[1][1]);\n }\n }\n }\n }\n\n #applyPlotOptions(el: HTMLElement, _style: RendererStyle, options?: Record<string, unknown>) {\n if (options === undefined)\n return;\n\n const target = el as any;\n\n if (typeof options.capacity === `number`)\n target.capacity = options.capacity;\n if (typeof options.resolution === `number`)\n target.resolution = options.resolution;\n if (typeof options.drawStyle === `string`)\n target.drawStyle = options.drawStyle;\n if (typeof options.orientation === `string`)\n target.orientation = options.orientation;\n if (typeof options.layout === `string`)\n target.layout = options.layout;\n }\n\n #formatTimeElapsed(value: unknown): string {\n let timestamp: number;\n\n if (value instanceof Date) {\n timestamp = value.getTime();\n } else if (typeof value === `number`) {\n if (value > 1e12) {\n timestamp = value;\n } else {\n timestamp = Date.now();\n }\n } else if (typeof value === `string`) {\n timestamp = new Date(value).getTime();\n } else {\n return String(value);\n }\n\n if (Number.isNaN(timestamp))\n return String(value);\n\n const elapsed = Date.now() - timestamp;\n const abs = Math.abs(elapsed);\n\n if (abs < 1000)\n return `${abs}ms`;\n if (abs < 60000)\n return `${(abs / 1000).toFixed(1)}s`;\n if (abs < 3600000)\n return `${(abs / 60000).toFixed(1)}mins`;\n if (abs < 86400000)\n return `${(abs / 3600000).toFixed(1)}h`;\n return `${(abs / 86400000).toFixed(1)}d`;\n }\n\n #renderText(row: HTMLElement, text: string) {\n let valueEl = row.querySelector(`:scope > .value`) as HTMLElement | null;\n if (valueEl === null) {\n valueEl = document.createElement(`span`);\n valueEl.classList.add(`value`);\n row.append(valueEl);\n }\n valueEl.textContent = text;\n }\n\n #renderNestedDisplay(row: HTMLElement, data: Record<string, unknown>, automapChild = false) {\n let child = row.querySelector(`:scope > ixfx-data-display`) as DataDisplayComponent | null;\n if (child === null) {\n child = document.createElement(`ixfx-data-display`) as DataDisplayComponent;\n row.append(child);\n }\n child.automap = automapChild;\n child.updateData(data);\n }\n\n #cleanupPaths(activePaths: Set<string>) {\n const rows = this._container.querySelectorAll<HTMLElement>(`[id^=\"path-\"]`);\n for (const row of rows) {\n const path = row.id.slice(5);\n if (!activePaths.has(path)) {\n row.remove();\n this.#rangeStreams.delete(path);\n this.#previousValues.delete(path);\n }\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-data-display': DataDisplayComponent;\n }\n}\n"],"mappings":"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"}
@@ -6,7 +6,7 @@
6
6
  */
7
7
  async function collectDataResult(result, signal) {
8
8
  if (Array.isArray(result)) return result;
9
- if (Symbol.asyncIterator in Object(result)) {
9
+ if (Symbol.asyncIterator in new Object(result)) {
10
10
  const items = [];
11
11
  for await (const batch of result) {
12
12
  if (signal.aborted) return items;
@@ -20,4 +20,4 @@ async function collectDataResult(result, signal) {
20
20
  //#endregion
21
21
  export { collectDataResult as t };
22
22
 
23
- //# sourceMappingURL=data-provider-DgI909FP.js.map
23
+ //# sourceMappingURL=data-provider-35TyWclX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-provider-35TyWclX.js","names":[],"sources":["../src/common/data-provider.ts"],"sourcesContent":["/**\n * Shared data-provider contract used by components that render a list of items.\n *\n * A provider is a simple callable — the consuming component (via DataController)\n * manages the request lifecycle, cancellation, and reactive state.\n */\n\n/**\n * One batch of items within a streaming provider response.\n *\n * For sync and async one-shot providers, the DataController synthesises a single\n * DataBatch internally — you only need this type when writing a streaming provider.\n */\nexport type DataBatch<T> = {\n /** Items delivered in this batch. */\n readonly items: readonly T[];\n /**\n * When true, replace all previously accumulated items with this batch instead\n * of appending. Useful for re-ranked or filtered results mid-stream.\n * Default: false (append).\n */\n replace?: boolean;\n /**\n * Provider's current estimate of the total number of items that will be\n * delivered across all batches. Enables progress percentage in the consumer.\n * May be refined in subsequent batches as the estimate improves.\n * Omit when the total is unknown.\n */\n total?: number;\n};\n\n/**\n * The three return modes a provider may use.\n * DataController normalises all three — callers can mix modes freely.\n *\n * - `readonly T[]` — sync, items available immediately\n * - `Promise<readonly T[]>` — async one-shot, resolves to the full result\n * - `AsyncIterable<DataBatch<T>>` — streaming, batches arrive over time\n */\nexport type DataProviderResult<T>\n = | readonly T[]\n | Promise<readonly T[]>\n | AsyncIterable<DataBatch<T>>;\n\n/**\n * A data provider callable.\n *\n * @typeParam TQuery - The input that scopes the request (e.g. `string` for\n * autocomplete, `{ node, depth }` for a tree branch, `void` for a plain list).\n * @typeParam TItem - The item type produced.\n *\n * The AbortSignal is cancelled when the consumer supersedes the request (e.g.\n * a new query arrives before the previous one completes). Streaming providers\n * should check `signal.aborted` between yields or pass the signal to their\n * underlying fetch calls.\n */\nexport type IDataProvider<TQuery, TItem> = (\n query: TQuery,\n signal: AbortSignal,\n) => DataProviderResult<TItem>;\n\n/**\n * Collects all items from any DataProviderResult into a flat array.\n * Useful for components that need a complete list before rendering (e.g. tree branches).\n * Respects the AbortSignal — stops accumulating if cancelled mid-stream.\n */\nexport async function collectDataResult<T>(\n result: DataProviderResult<T>,\n signal: AbortSignal,\n): Promise<readonly T[]> {\n if (Array.isArray(result))\n return result as T[];\n if (Symbol.asyncIterator in new Object(result)) {\n const items: T[] = [];\n for await (const batch of result as AsyncIterable<DataBatch<T>>) {\n if (signal.aborted)\n return items;\n if (batch.replace)\n items.length = 0;\n items.push(...(batch.items as T[]));\n }\n return items;\n }\n return result as Promise<readonly T[]>;\n}\n"],"mappings":";;;;;;AAkEA,eAAsB,kBACpB,QACA,QACuB;CACvB,IAAI,MAAM,QAAQ,MAAM,GACtB,OAAO;CACT,IAAI,OAAO,iBAAiB,IAAI,OAAO,MAAM,GAAG;EAC9C,MAAM,QAAa,CAAC;EACpB,WAAW,MAAM,SAAS,QAAuC;GAC/D,IAAI,OAAO,SACT,OAAO;GACT,IAAI,MAAM,SACR,MAAM,SAAS;GACjB,MAAM,KAAK,GAAI,MAAM,KAAa;EACpC;EACA,OAAO;CACT;CACA,OAAO;AACT"}