@ixfx/components 0.13.2 → 0.13.4

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 (306) hide show
  1. package/bundle/index.d.ts +1649 -128
  2. package/bundle/index.js +1595 -44437
  3. package/bundle/rolldown-runtime-CEoa-xHZ.js +1 -0
  4. package/dist/ac-text.d.ts +2 -3
  5. package/dist/ac-text.js +0 -2
  6. package/dist/{ac-token-TCLAZeVg.d.ts → ac-token--_vCHXWw.d.ts} +2 -3
  7. package/dist/ac-token.d.ts +1 -1
  8. package/dist/ac-token.js +1 -3
  9. package/dist/button-B7mgqtxR.js +0 -2
  10. package/dist/{button-CTL45aBl.d.ts → button-BYuf72aR.d.ts} +2 -3
  11. package/dist/button.d.ts +1 -1
  12. package/dist/checkbox.d.ts +1 -2
  13. package/dist/checkbox.js +0 -2
  14. package/dist/checked-select-CglRukbP.d.ts +1 -2
  15. package/dist/checked-select-lDgAQQ7v.js +0 -2
  16. package/dist/colour-picker-BCMU7W7R.js +0 -2
  17. package/dist/colour-picker.d.ts +1 -1
  18. package/dist/crumbs.d.ts +2 -3
  19. package/dist/crumbs.js +1 -3
  20. package/dist/data-controller-DOlmqNKb.js +0 -2
  21. package/dist/data-display.d.ts +1 -2
  22. package/dist/data-display.js +0 -2
  23. package/dist/{data-grid-Ck1Qx2H1.d.ts → data-grid-BtBZt8M1.d.ts} +10 -9
  24. package/dist/data-grid-FHr7wZ_k.js +2108 -0
  25. package/dist/data-grid.d.ts +1 -1
  26. package/dist/data-grid.js +1 -1923
  27. package/dist/data-provider-35TyWclX.js +0 -2
  28. package/dist/data-provider-BAn_-oR1.d.ts +1 -2
  29. package/dist/decorate-VRK8rslU.js +0 -2
  30. package/dist/defaults-B4ePs4LB.js +0 -2
  31. package/dist/detail-list-BfYHNh6B.js +1999 -0
  32. package/dist/{detail-list-C1xzr1z7.d.ts → detail-list-u2rWnAXQ.d.ts} +13 -5
  33. package/dist/detail-list.d.ts +2 -2
  34. package/dist/detail-list.js +1 -1680
  35. package/dist/drag-ghost-DtSDvjri.js +0 -2
  36. package/dist/editable-label-rzXkjf1H.d.ts +1 -2
  37. package/dist/editable-label.js +0 -2
  38. package/dist/fallbacks-DQ_5OsmR.js +0 -2
  39. package/dist/{flat-list-Ohxqsy0g.d.ts → flat-list-DNnTQ65v.d.ts} +3 -4
  40. package/dist/flat-list.d.ts +1 -1
  41. package/dist/flat-list.js +5 -3
  42. package/dist/form-CsXJX15p.js +0 -2
  43. package/dist/form.d.ts +1 -2
  44. package/dist/{grid-list-pefLORIr.d.ts → grid-list-BLnV9oZE.d.ts} +9 -3
  45. package/dist/{grid-list-DjIl910A.js → grid-list-CkU8gHCh.js} +189 -42
  46. package/dist/grid-list.d.ts +1 -1
  47. package/dist/grid-list.js +1 -1
  48. package/dist/{grouped-item-lister-Bhyo-dkH.d.ts → grouped-item-lister-DETte0Dh.d.ts} +2 -3
  49. package/dist/grouped-item-lister.d.ts +1 -1
  50. package/dist/grouped-item-lister.js +0 -2
  51. package/dist/grouping-CUKgmkMm.d.ts +1 -2
  52. package/dist/grouping-RYPnHkrS.js +0 -2
  53. package/dist/handle-DAXs7kbJ.js +0 -2
  54. package/dist/hex-editor-Caq8vNQk.d.ts +1 -2
  55. package/dist/hex-editor-DiYpgIKs.js +0 -2
  56. package/dist/highlight-B-eQrhhb.js +0 -2
  57. package/dist/icon-1gpwtPx8.js +0 -2
  58. package/dist/{icon-DR_3rSyZ.d.ts → icon-CDGprSdE.d.ts} +2 -3
  59. package/dist/icons.d.ts +2 -2
  60. package/dist/icons.js +0 -2
  61. package/dist/{incr-search-D91M4Ozq.js → incr-search-JIhwB49y.js} +26 -6
  62. package/dist/incr-search.d.ts +1 -1
  63. package/dist/incr-search.js +1 -1
  64. package/dist/{index-Dq30pOnn.d.ts → index-B-hzcIP0.d.ts} +3 -4
  65. package/dist/{index-CxZ61DO1.d.ts → index-BYIRgv49.d.ts} +9 -3
  66. package/dist/index-CCC0G1nO.d.ts +324 -0
  67. package/dist/{index-garxxqgV.d.ts → index-CYndvTWH.d.ts} +2 -3
  68. package/dist/{index-BUB5SICW.d.ts → index-CoqtMSd9.d.ts} +2 -3
  69. package/dist/index-DV3iaUBW.d.ts +1 -2
  70. package/dist/{index-CJ5fshD3.d.ts → index-UvnoZUAo.d.ts} +2 -3
  71. package/dist/index-o-CWDt11.d.ts +1 -2
  72. package/dist/{index-BOUaDIW-.d.ts → index-tq6f8007.d.ts} +2 -3
  73. package/dist/index.d.ts +21 -22
  74. package/dist/index.js +48 -29
  75. package/dist/item-appearance-BjcMyauw.js +0 -2
  76. package/dist/keyboard-B5xD7Fz-.js +0 -2
  77. package/dist/labelled-input-base-BFa4xlYV.js +0 -2
  78. package/dist/{labelled-input-base-Dp_9KP0G.d.ts → labelled-input-base-DiTme1JO.d.ts} +2 -3
  79. package/dist/labelled-radial-input.d.ts +3 -4
  80. package/dist/labelled-radial-input.js +0 -2
  81. package/dist/labelled-range-input.d.ts +1 -1
  82. package/dist/labelled-range-input.js +0 -2
  83. package/dist/labelled-slider-input-FdCRi6st.js +0 -2
  84. package/dist/labelled-slider-input.d.ts +1 -1
  85. package/dist/led.d.ts +1 -2
  86. package/dist/led.js +0 -2
  87. package/dist/list-group-header.d.ts +2 -3
  88. package/dist/list-group-header.js +0 -2
  89. package/dist/list-item-animation-BUoEKi5s.js +0 -2
  90. package/dist/list-native-drag-controller-B9xO0XWn.js +0 -2
  91. package/dist/list-native-drag-controller-ChIi3eK5.d.ts +1 -2
  92. package/dist/list-selection-controller-BeE70lbB.js +0 -2
  93. package/dist/list-selection-types-PjKdhF-a.d.ts +1 -2
  94. package/dist/list-viewport-types-BRZsLcvp.d.ts +1 -2
  95. package/dist/menu-CwcXXeLM.js +0 -2
  96. package/dist/menu-item-BDEekBVy.js +0 -2
  97. package/dist/{menu-item-B0zqw2xp.d.ts → menu-item-bF6narIz.d.ts} +2 -3
  98. package/dist/menu.d.ts +2 -2
  99. package/dist/miller.d.ts +2 -3
  100. package/dist/miller.js +146 -102
  101. package/dist/narrowed-text.js +1 -3
  102. package/dist/notification-pill-DyZydXoZ.d.ts +1 -2
  103. package/dist/notifier.js +0 -2
  104. package/dist/pan-text-CoYmt2qd.d.ts +1 -2
  105. package/dist/pan-text-CqtvjPyK.js +0 -2
  106. package/dist/panel.d.ts +2 -3
  107. package/dist/panel.js +0 -2
  108. package/dist/polar-pad.d.ts +1 -2
  109. package/dist/polar-pad.js +0 -2
  110. package/dist/popup-D80sj2QC.js +0 -2
  111. package/dist/prominence-DlFShic3.js +0 -2
  112. package/dist/radial-input-DU6t2hYO.d.ts +1 -2
  113. package/dist/radial-input-KMVltQfe.js +0 -2
  114. package/dist/range-input.d.ts +1 -2
  115. package/dist/range-input.js +0 -2
  116. package/dist/range.d.ts +1 -2
  117. package/dist/range.js +0 -2
  118. package/dist/registry-BEtb8_wB.js +0 -2
  119. package/dist/{scroll-fade-BrNUIYnm.js → scroll-fade-Xx28D7mH.js} +11 -7
  120. package/dist/select-horiz.d.ts +1 -2
  121. package/dist/select-horiz.js +1 -3
  122. package/dist/slider-input-BxURAAmD.d.ts +1 -2
  123. package/dist/slider-input-ByHdotzp.js +0 -2
  124. package/dist/snackbar.d.ts +1 -2
  125. package/dist/snackbar.js +0 -2
  126. package/dist/snap-container.d.ts +1 -2
  127. package/dist/snap-container.js +0 -2
  128. package/dist/{split-layout-CXotkdbx.js → split-layout-Deoxy47d.js} +5 -2
  129. package/dist/{split-layout-C5SYbDrq.d.ts → split-layout-JK3xWVX2.d.ts} +2 -3
  130. package/dist/split-layout.d.ts +1 -1
  131. package/dist/split-layout.js +1 -1
  132. package/dist/swipe.d.ts +1 -2
  133. package/dist/swipe.js +0 -2
  134. package/dist/{tab-list-v8mKX7Fu.d.ts → tab-list-CexFFg6O.d.ts} +3 -5
  135. package/dist/tabs.d.ts +1 -1
  136. package/dist/tabs.js +23 -3
  137. package/dist/tickled-controller-D-HZymaZ.js +0 -2
  138. package/dist/tickled-controller-DodxD3eQ.d.ts +1 -2
  139. package/dist/tickled-styles-BrAHEj1q.js +0 -2
  140. package/dist/timeline-BP1Ux2EV.js +0 -2
  141. package/dist/{titlebar-B5zSTZnF.d.ts → titlebar-Tqu-VvMU.d.ts} +2 -3
  142. package/dist/titlebar.d.ts +1 -1
  143. package/dist/titlebar.js +0 -2
  144. package/dist/tooltip-BlvBUQxx.d.ts +1 -2
  145. package/dist/tooltip-CJt3WLmN.js +0 -2
  146. package/dist/transitory-label.d.ts +1 -2
  147. package/dist/transitory-label.js +0 -2
  148. package/dist/{tree-DGveys4K.js → tree-DD8OaqsK.js} +1009 -231
  149. package/dist/tree-component-Cj8V3uar.d.ts +1 -2
  150. package/dist/tree.d.ts +4 -267
  151. package/dist/tree.js +1 -1
  152. package/dist/types-DQ7KOUIj.d.ts +1 -2
  153. package/dist/{vertical-list-CqBc-t8w.d.ts → vertical-list-m7GJtXwv.d.ts} +3 -3
  154. package/dist/vertical-list.d.ts +1 -1
  155. package/dist/vertical-list.js +114 -27
  156. package/dist/wheel-nudge-By5s_ioH.d.ts +1 -2
  157. package/dist/wheel-nudge-D5rmht3v.js +0 -2
  158. package/dist/xy-axis-CyMd_Bn1.js +0 -2
  159. package/dist/xy-axis-DQqd2yXJ.d.ts +1 -2
  160. package/dist/xy-pad.d.ts +1 -2
  161. package/dist/xy-pad.js +0 -2
  162. package/docs-user/data-grid.md +74 -4
  163. package/docs-user/detail-list.md +65 -0
  164. package/docs-user/grid-list.md +81 -4
  165. package/docs-user/index.json +2 -2
  166. package/docs-user/miller.md +59 -3
  167. package/docs-user/tree.md +63 -2
  168. package/docs-user/vertical-list.md +9 -1
  169. package/package.json +6 -1
  170. package/bundle/index.d.ts.map +0 -1
  171. package/bundle/index.js.map +0 -1
  172. package/bundle/rolldown-runtime-D7D4PA-g.js +0 -13
  173. package/dist/ac-text.d.ts.map +0 -1
  174. package/dist/ac-text.js.map +0 -1
  175. package/dist/ac-token-TCLAZeVg.d.ts.map +0 -1
  176. package/dist/ac-token.js.map +0 -1
  177. package/dist/button-B7mgqtxR.js.map +0 -1
  178. package/dist/button-CTL45aBl.d.ts.map +0 -1
  179. package/dist/checkbox.d.ts.map +0 -1
  180. package/dist/checkbox.js.map +0 -1
  181. package/dist/checked-select-CglRukbP.d.ts.map +0 -1
  182. package/dist/checked-select-lDgAQQ7v.js.map +0 -1
  183. package/dist/colour-picker-BCMU7W7R.js.map +0 -1
  184. package/dist/crumbs.d.ts.map +0 -1
  185. package/dist/crumbs.js.map +0 -1
  186. package/dist/data-controller-DOlmqNKb.js.map +0 -1
  187. package/dist/data-display.d.ts.map +0 -1
  188. package/dist/data-display.js.map +0 -1
  189. package/dist/data-grid-Ck1Qx2H1.d.ts.map +0 -1
  190. package/dist/data-grid.js.map +0 -1
  191. package/dist/data-provider-35TyWclX.js.map +0 -1
  192. package/dist/data-provider-BAn_-oR1.d.ts.map +0 -1
  193. package/dist/decorate-VRK8rslU.js.map +0 -1
  194. package/dist/defaults-B4ePs4LB.js.map +0 -1
  195. package/dist/detail-list-C1xzr1z7.d.ts.map +0 -1
  196. package/dist/detail-list.js.map +0 -1
  197. package/dist/drag-ghost-DtSDvjri.js.map +0 -1
  198. package/dist/editable-label-rzXkjf1H.d.ts.map +0 -1
  199. package/dist/editable-label.js.map +0 -1
  200. package/dist/fallbacks-DQ_5OsmR.js.map +0 -1
  201. package/dist/flat-list-Ohxqsy0g.d.ts.map +0 -1
  202. package/dist/flat-list.js.map +0 -1
  203. package/dist/form-CsXJX15p.js.map +0 -1
  204. package/dist/form.d.ts.map +0 -1
  205. package/dist/grid-list-DjIl910A.js.map +0 -1
  206. package/dist/grid-list-pefLORIr.d.ts.map +0 -1
  207. package/dist/grouped-item-lister-Bhyo-dkH.d.ts.map +0 -1
  208. package/dist/grouped-item-lister.js.map +0 -1
  209. package/dist/grouping-CUKgmkMm.d.ts.map +0 -1
  210. package/dist/grouping-RYPnHkrS.js.map +0 -1
  211. package/dist/handle-DAXs7kbJ.js.map +0 -1
  212. package/dist/hex-editor-Caq8vNQk.d.ts.map +0 -1
  213. package/dist/hex-editor-DiYpgIKs.js.map +0 -1
  214. package/dist/highlight-B-eQrhhb.js.map +0 -1
  215. package/dist/icon-1gpwtPx8.js.map +0 -1
  216. package/dist/icon-DR_3rSyZ.d.ts.map +0 -1
  217. package/dist/icons.js.map +0 -1
  218. package/dist/incr-search-D91M4Ozq.js.map +0 -1
  219. package/dist/index-BOUaDIW-.d.ts.map +0 -1
  220. package/dist/index-BUB5SICW.d.ts.map +0 -1
  221. package/dist/index-CJ5fshD3.d.ts.map +0 -1
  222. package/dist/index-CxZ61DO1.d.ts.map +0 -1
  223. package/dist/index-DV3iaUBW.d.ts.map +0 -1
  224. package/dist/index-Dq30pOnn.d.ts.map +0 -1
  225. package/dist/index-garxxqgV.d.ts.map +0 -1
  226. package/dist/index-o-CWDt11.d.ts.map +0 -1
  227. package/dist/index.d.ts.map +0 -1
  228. package/dist/index.js.map +0 -1
  229. package/dist/item-appearance-BjcMyauw.js.map +0 -1
  230. package/dist/keyboard-B5xD7Fz-.js.map +0 -1
  231. package/dist/labelled-input-base-BFa4xlYV.js.map +0 -1
  232. package/dist/labelled-input-base-Dp_9KP0G.d.ts.map +0 -1
  233. package/dist/labelled-radial-input.d.ts.map +0 -1
  234. package/dist/labelled-radial-input.js.map +0 -1
  235. package/dist/labelled-range-input.js.map +0 -1
  236. package/dist/labelled-slider-input-FdCRi6st.js.map +0 -1
  237. package/dist/led.d.ts.map +0 -1
  238. package/dist/led.js.map +0 -1
  239. package/dist/list-group-header.d.ts.map +0 -1
  240. package/dist/list-group-header.js.map +0 -1
  241. package/dist/list-item-animation-BUoEKi5s.js.map +0 -1
  242. package/dist/list-native-drag-controller-B9xO0XWn.js.map +0 -1
  243. package/dist/list-native-drag-controller-ChIi3eK5.d.ts.map +0 -1
  244. package/dist/list-selection-controller-BeE70lbB.js.map +0 -1
  245. package/dist/list-selection-types-PjKdhF-a.d.ts.map +0 -1
  246. package/dist/list-viewport-types-BRZsLcvp.d.ts.map +0 -1
  247. package/dist/menu-CwcXXeLM.js.map +0 -1
  248. package/dist/menu-item-B0zqw2xp.d.ts.map +0 -1
  249. package/dist/menu-item-BDEekBVy.js.map +0 -1
  250. package/dist/miller.d.ts.map +0 -1
  251. package/dist/miller.js.map +0 -1
  252. package/dist/narrowed-text.js.map +0 -1
  253. package/dist/notification-pill-DyZydXoZ.d.ts.map +0 -1
  254. package/dist/notifier.js.map +0 -1
  255. package/dist/pan-text-CoYmt2qd.d.ts.map +0 -1
  256. package/dist/pan-text-CqtvjPyK.js.map +0 -1
  257. package/dist/panel.d.ts.map +0 -1
  258. package/dist/panel.js.map +0 -1
  259. package/dist/polar-pad.d.ts.map +0 -1
  260. package/dist/polar-pad.js.map +0 -1
  261. package/dist/popup-D80sj2QC.js.map +0 -1
  262. package/dist/prominence-DlFShic3.js.map +0 -1
  263. package/dist/radial-input-DU6t2hYO.d.ts.map +0 -1
  264. package/dist/radial-input-KMVltQfe.js.map +0 -1
  265. package/dist/range-input.d.ts.map +0 -1
  266. package/dist/range-input.js.map +0 -1
  267. package/dist/range.d.ts.map +0 -1
  268. package/dist/range.js.map +0 -1
  269. package/dist/registry-BEtb8_wB.js.map +0 -1
  270. package/dist/scroll-fade-BrNUIYnm.js.map +0 -1
  271. package/dist/select-horiz.d.ts.map +0 -1
  272. package/dist/select-horiz.js.map +0 -1
  273. package/dist/slider-input-BxURAAmD.d.ts.map +0 -1
  274. package/dist/slider-input-ByHdotzp.js.map +0 -1
  275. package/dist/snackbar.d.ts.map +0 -1
  276. package/dist/snackbar.js.map +0 -1
  277. package/dist/snap-container.d.ts.map +0 -1
  278. package/dist/snap-container.js.map +0 -1
  279. package/dist/split-layout-C5SYbDrq.d.ts.map +0 -1
  280. package/dist/split-layout-CXotkdbx.js.map +0 -1
  281. package/dist/swipe.d.ts.map +0 -1
  282. package/dist/swipe.js.map +0 -1
  283. package/dist/tab-list-v8mKX7Fu.d.ts.map +0 -1
  284. package/dist/tabs.js.map +0 -1
  285. package/dist/tickled-controller-D-HZymaZ.js.map +0 -1
  286. package/dist/tickled-controller-DodxD3eQ.d.ts.map +0 -1
  287. package/dist/tickled-styles-BrAHEj1q.js.map +0 -1
  288. package/dist/timeline-BP1Ux2EV.js.map +0 -1
  289. package/dist/titlebar-B5zSTZnF.d.ts.map +0 -1
  290. package/dist/titlebar.js.map +0 -1
  291. package/dist/tooltip-BlvBUQxx.d.ts.map +0 -1
  292. package/dist/tooltip-CJt3WLmN.js.map +0 -1
  293. package/dist/transitory-label.d.ts.map +0 -1
  294. package/dist/transitory-label.js.map +0 -1
  295. package/dist/tree-DGveys4K.js.map +0 -1
  296. package/dist/tree-component-Cj8V3uar.d.ts.map +0 -1
  297. package/dist/tree.d.ts.map +0 -1
  298. package/dist/types-DQ7KOUIj.d.ts.map +0 -1
  299. package/dist/vertical-list-CqBc-t8w.d.ts.map +0 -1
  300. package/dist/vertical-list.js.map +0 -1
  301. package/dist/wheel-nudge-By5s_ioH.d.ts.map +0 -1
  302. package/dist/wheel-nudge-D5rmht3v.js.map +0 -1
  303. package/dist/xy-axis-CyMd_Bn1.js.map +0 -1
  304. package/dist/xy-axis-DQqd2yXJ.d.ts.map +0 -1
  305. package/dist/xy-pad.d.ts.map +0 -1
  306. package/dist/xy-pad.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"swipe.d.ts","names":[],"sources":["../src/swipe/swipe.ts"],"mappings":";;;KAmCY;WAA8B;;KAC9B,kBAAkB,YAAY;UAEzB;EACf,OAAO;;UAGQ;EACf,oBAAoB,gBAAgB,sBAClC,MAAM,GACN,WAAW,MAAM,cAAc,OAAO,qBAAqB,aAC3D,oBAAoB,sCAEpB,cACA,UAAU,oCACV,oBAAoB;;QAIhB;YACI;IACR,cAAc;;;;cAKL,qBAAqB;;EACJ;EACA;EACA;EACA;UAEpB;UACA;UACA;UACA;UACA;UAEA;UACA;UACA;UAEA;UACA;UACA;UACA;UACA;;;;;;;;;EAiDC,iBAAiB,WAAW,gBAAgB,OAAO;EAUnD;EAaA;UAUD;UAcA;SAoFQ,QAAQ;EA8Bf,UAAU,kBAAkB"}
package/dist/swipe.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"swipe.js","names":["#removeWindowListeners","#emitInput","#scheduleRetraction","#cancelAnimation","#onWindowPointerUp","#onWindowPointerCancel","#startRetraction","#renderBars","customElement"],"sources":["../src/swipe/swipe.ts"],"sourcesContent":["/* eslint-disable ts/no-unsafe-declaration-merging */\n/**\n * <ixfx-swipe> — Touch-friendly swipe/nudge component.\n *\n * User taps and drags to generate a value in range [-1, 1].\n * A drag of full component width = ±1. Value is emitted only on pointerup.\n *\n * Properties\n * barSpacing – center-to-center pixel distance between bars (default 20)\n * barWidth – pixel width of each bar (default 14)\n * debounceMs – ms pause after release before retraction begins (default 200)\n * retractDurationMs – ms for the spring-back animation (default 400)\n * lighttouch – boolean — wheel adjusts the value on hover instead of requiring focus\n *\n * Mouse wheel: up = +0.1, down = -0.1; Shift halves to ±0.05. Each tick fires\n * `input` and triggers the same retraction animation as a drag release. See\n * `docs/infra-mousewheel.md`.\n *\n * CSS custom properties\n * --swipe-color-a – fill for even-indexed bars (default var(--surface-4))\n * --swipe-color-b – fill for odd-indexed bars (default var(--surface-5))\n * --swipe-border-color – border color (default var(--border))\n *\n * Events\n * input – CustomEvent<{ detail: { value: number } }>, bubbles + composed\n */\nimport type { CSSResultGroup } from 'lit';\nimport type { WheelDirection } from '../mixins/wheel-nudge.js';\nimport { css, html, LitElement, svg } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { WheelNudgeMixin } from '../mixins/wheel-nudge.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { prominenceStyles } from '../styles/prominence.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\n\nexport type SwipeInputDetail = { readonly value: number };\nexport type SwipeInputEvent = CustomEvent<SwipeInputDetail>;\n\nexport interface SwipeElementEventMap {\n input: SwipeInputEvent;\n}\n\nexport interface SwipeElement {\n addEventListener: (<K extends keyof SwipeElementEventMap>(\n type: K,\n listener: (this: SwipeElement, event: SwipeElementEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ) => void) & ((\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ) => void);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-swipe': SwipeElement;\n }\n}\n\n@customElement(`ixfx-swipe`)\nexport class SwipeElement extends WheelNudgeMixin(LitElement) {\n @property({ type: Number }) barSpacing = 20;\n @property({ type: Number }) barWidth = 14;\n @property({ type: Number }) debounceMs = 200;\n @property({ type: Number }) retractDurationMs = 400;\n\n private _startX = 0;\n private _currentX = 0;\n private _pointerId: number | null = null;\n private _componentWidth = 0;\n private _isDragging = false;\n\n private _offset = 0;\n private _width = 0;\n private _height = 0;\n\n private _animRafId: number | null = null;\n private _debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private _animStartOffset = 0;\n private _animStartTime: number | null = null;\n private _resizeObserver: ResizeObserver | null = null;\n\n #onWindowPointerUp = (e: PointerEvent): void => {\n if (e.pointerId !== this._pointerId)\n return;\n this.#removeWindowListeners();\n\n const rect = this.getBoundingClientRect();\n const inside = e.clientX >= rect.left && e.clientX <= rect.right\n && e.clientY >= rect.top && e.clientY <= rect.bottom;\n\n if (inside) {\n const deltaX = this._currentX - this._startX;\n const value = Math.max(-1, Math.min(1, deltaX / this._componentWidth));\n this.#emitInput(value);\n }\n\n this._isDragging = false;\n this._pointerId = null;\n this.#scheduleRetraction();\n };\n\n #onWindowPointerCancel = (e: PointerEvent): void => {\n if (e.pointerId !== this._pointerId)\n return;\n this.#removeWindowListeners();\n this._isDragging = false;\n this._pointerId = null;\n this.#scheduleRetraction();\n };\n\n #emitInput(value: number): void {\n this.dispatchEvent(\n new CustomEvent<SwipeInputDetail>(`input`, {\n detail: { value },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /**\n * Wheel handler — installed by WheelNudgeMixin on the host. Emits `input`\n * synchronously on each tick (matching the user-confirmed \"mirror drag\"\n * semantic) and schedules the same retraction animation the drag releases\n * with, so the visual resets after a short idle.\n *\n * Step size: 10% of the [-1, 1] value range (= 0.1). Shift halves to 0.05.\n */\n override _applyWheelDelta(direction: WheelDirection, event: WheelEvent): void {\n this.#cancelAnimation();\n const step = event.shiftKey ? 0.05 : 0.1;\n const value = Math.max(-1, Math.min(1, direction * step));\n this.#emitInput(value);\n this._offset = value * this._height * 0.5;\n this.requestUpdate();\n this.#scheduleRetraction();\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (!entry)\n return;\n this._width = entry.contentRect.width;\n this._height = entry.contentRect.height;\n this.requestUpdate();\n });\n this._resizeObserver.observe(this);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._resizeObserver?.disconnect();\n this._resizeObserver = null;\n this.#cancelAnimation();\n this.#removeWindowListeners();\n this._isDragging = false;\n this._pointerId = null;\n }\n\n private _onPointerDown = (e: PointerEvent): void => {\n e.preventDefault();\n this.#cancelAnimation();\n const target = e.target as HTMLElement;\n target.setPointerCapture(e.pointerId);\n this._pointerId = e.pointerId;\n this._startX = e.clientX;\n this._currentX = e.clientX;\n this._componentWidth = this.getBoundingClientRect().width;\n this._isDragging = true;\n window.addEventListener(`pointerup`, this.#onWindowPointerUp);\n window.addEventListener(`pointercancel`, this.#onWindowPointerCancel);\n };\n\n private _onPointerMove = (e: PointerEvent): void => {\n if (!this._isDragging || e.pointerId !== this._pointerId)\n return;\n this._currentX = e.clientX;\n const deltaX = this._currentX - this._startX;\n const ratio = Math.max(-1, Math.min(1, deltaX / this._componentWidth));\n this._offset = ratio * this._height * 0.5;\n this.requestUpdate();\n };\n\n #removeWindowListeners(): void {\n window.removeEventListener(`pointerup`, this.#onWindowPointerUp);\n window.removeEventListener(`pointercancel`, this.#onWindowPointerCancel);\n }\n\n #scheduleRetraction(): void {\n if (this._debounceTimer !== null)\n clearTimeout(this._debounceTimer);\n this._debounceTimer = setTimeout(() => {\n this._debounceTimer = null;\n this.#startRetraction();\n }, this.debounceMs);\n }\n\n #startRetraction(): void {\n this._animStartOffset = this._offset;\n this._animStartTime = null;\n\n const animate = (time: number): void => {\n if (this._animStartTime === null)\n this._animStartTime = time;\n const elapsed = time - this._animStartTime;\n const t = Math.min(elapsed / this.retractDurationMs, 1);\n const eased = 1 - (1 - t) ** 3;\n this._offset = this._animStartOffset * (1 - eased);\n this.requestUpdate();\n\n if (t < 1) {\n this._animRafId = requestAnimationFrame(animate);\n } else {\n this._offset = 0;\n this._animRafId = null;\n this.requestUpdate();\n }\n };\n\n this._animRafId = requestAnimationFrame(animate);\n }\n\n #cancelAnimation(): void {\n if (this._animRafId !== null) {\n cancelAnimationFrame(this._animRafId);\n this._animRafId = null;\n }\n if (this._debounceTimer !== null) {\n clearTimeout(this._debounceTimer);\n this._debounceTimer = null;\n }\n }\n\n #renderBars(): ReturnType<typeof svg> {\n const w = this._width;\n const h = this._height;\n const off = this._offset;\n const { barSpacing, barWidth } = this;\n if (w === 0 || h === 0)\n return svg``;\n\n const half = barWidth / 2;\n const mid = h / 2;\n const count = Math.ceil(w / barSpacing) + 1;\n\n return svg`${Array.from({ length: count }, (_, i) => {\n const cx = i * barSpacing;\n const x0 = cx - half;\n const x1 = cx + half;\n const colorVar = i % 2 === 0\n ? `var(--swipe-color-a, var(--surface-4))`\n : `var(--swipe-color-b, var(--surface-5))`;\n const d = `M${x0},0 L${x1},0 L${x1 + off},${mid} L${x1},${h} L${x0},${h} L${x0 + off},${mid}Z`;\n return svg`<path d=${d} style=\"fill:${colorVar}\"></path>`;\n })}`;\n }\n\n static override styles: CSSResultGroup = [themeFallbacks, prominenceStyles, css`\n :host {\n display: block;\n user-select: none;\n touch-action: none;\n width: 100%;\n height: 2.5rem;\n --swipe-border-color: var(--border);\n }\n\n .swipe-area {\n position: relative;\n width: 100%;\n height: 100%;\n cursor: grab;\n border: var(--swipe-border-color);\n overflow: hidden;\n }\n\n .swipe-area:active {\n cursor: grabbing;\n }\n\n svg {\n display: block;\n width: 100%;\n height: 100%;\n }\n `];\n\n override render(): ReturnType<typeof html> {\n return html`\n <div\n class=\"swipe-area\"\n @pointerdown=${this._onPointerDown}\n @pointermove=${this._onPointerMove}\n >\n <svg aria-hidden=\"true\">${this.#renderBars()}</svg>\n </div>\n `;\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tab-list-v8mKX7Fu.d.ts","names":[],"sources":["../src/tabs/tab-list-item.ts","../src/tabs/tab-list.ts"],"mappings":";;;;;;;;;;;cAiBa,2BAA2B;EAEtC;EAGA;;;;;;;EASA;EAGA;EAGA;EAGA;EAGA,UAAU;UAEO;UACA;UACA;UACT;UACA;UACA;EAEC;EAwBA;EAWA,QAAQ,SAAS;UAQlB;UAUA;UAWA;UAIA;UAIA;;;;;;;UAUA;UASA;;;;;UAaA;UAiBA;;;;;;UASA;EAIC;EAOA,wBAAM;UA+BP;SAWQ,sBAAM;;QAyLhB;YACI;IACR,sBAAsB;;;;;;;;;;KCvZd;WACD;WACA;WACA;;KAGC,qBAAqB,YAAY;KAEjC;WACD;WACA;WACA;;KAGC,sBAAsB,YAAY;KAElC;cAMC,uBAAuB;;EAElC;EAGA;EAGA;EAGA;;;;;;EAQA;EAGA;EAGA,UAAU;EA4BD,wBAAM;EAgEN;EAUA,QAAQ,mBAAmB;EAiHpC,sBAAkB;EAwBlB,cAAc,IAAI;SAwaX,sBAAM;;QAyKP;YACI;IACR,iBAAiB"}
package/dist/tabs.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"tabs.js","names":["#refreshItems","#syncIndicatorColors","#syncHideLabels","#syncLabelNogrow","#isVertical","#selectPrevious","#selectNext","#dragState","#abortDrag","#endDrag","#containerEl","#suppressNextClick","#findDragTarget","#items","#onPointerMove","#onPointerUp","#onPointerCancel","#beginDrag","#computeGapIndex","#commitDrag","#containerClass","#computeCaretStyle","#onKeyUp","#onSlotClick","#onPointerDown","#onKeyDown","#onWheel","#onSlotChange","#onToolbarSlotChange","#isSelected","#createGhost","customElement"],"sources":["../src/tabs/tab-list.ts"],"sourcesContent":["import type { PropertyValues } from \"lit\";\nimport type { DragGhost } from \"../util/drag-ghost.js\";\nimport type { TabListItemElement } from \"./tab-list-item.js\";\nimport { css, html, LitElement, nothing } from \"lit\";\nimport { property } from \"lit/decorators.js\";\nimport { themeFallbacks } from \"../styles/fallbacks.js\";\nimport { scrollFadeStyles } from \"../styles/scroll-fade.js\";\nimport { safeCustomElement as customElement } from \"../util/custom-elements.js\";\nimport { createDragGhost } from \"../util/drag-ghost.js\";\n\n/**\n * Events\n * 'change' - new tab selected { previous:string, selected:string, for:string }\n * 'reorder' - tab moved within the list { id:string, fromIndex:number, toIndex:number }\n */\nexport type TabListChangeDetail = {\n readonly previous: string | undefined;\n readonly selected: string;\n readonly for: string;\n};\n\nexport type TabListChangeEvent = CustomEvent<TabListChangeDetail>;\n\nexport type TabListReorderDetail = {\n readonly id: string;\n readonly fromIndex: number;\n readonly toIndex: number;\n};\n\nexport type TabListReorderEvent = CustomEvent<TabListReorderDetail>;\n\nexport type TabListDragMode = `off` | `reorder`;\n\n/** Pointer movement threshold (px) before a press becomes a drag. */\nconst DRAG_THRESHOLD_PX = 5;\n\n@customElement(`ixfx-tab-list`)\nexport class TabListElement extends LitElement {\n @property({ type: String })\n orientation: `horizontal` | `vertical-stack` | `vertical-side` = `horizontal`;\n\n @property({ type: Boolean })\n flip = false;\n\n @property({ type: Boolean })\n scrollable = false;\n\n @property({ type: Boolean, attribute: `hide-labels` })\n hideLabels = false;\n\n /**\n * Labels of the child items do not stretch to fill each tab\n * (`flex: 0 0 auto`), so status content sits next to the label text.\n * Mirrored onto every item as a `label-nogrow` attribute.\n */\n @property({ type: Boolean, attribute: `label-nogrow` })\n labelNogrow = false;\n\n @property({ type: Boolean, reflect: true })\n shrink = false;\n\n @property({ type: String, attribute: `drag-mode` })\n dragMode: TabListDragMode = `off`;\n\n #items: TabListItemElement[] = [];\n\n // ── Drag state (not reactive) ────────────────────────────────────────\n #dragState: {\n pointerId: number;\n source: TabListItemElement;\n fromIndex: number;\n startX: number;\n startY: number;\n active: boolean;\n ghost: DragGhost | null;\n gapIndex: number | undefined;\n } | null = null;\n\n #suppressNextClick = false;\n\n get #isVertical(): boolean {\n return this.orientation === `vertical-stack` || this.orientation === `vertical-side`;\n }\n\n get #containerClass(): string {\n const base = this.scrollable ? `${this.orientation} scrollable` : this.orientation;\n const fadeClass = this.scrollable ? (this.#isVertical ? `scroll-fade-y` : `scroll-fade-x`) : ``;\n return [base, fadeClass, this.dragMode === `reorder` ? `reorder` : ``].filter(Boolean).join(` `);\n }\n\n override render() {\n const caretStyle = this.#computeCaretStyle();\n return html`\n <div class=\"outer ${this.orientation}\">\n <div\n tabindex=0\n @keyup=${this.#onKeyUp}\n @click=${this.#onSlotClick}\n @pointerdown=${this.#onPointerDown}\n @keydown=${this.#onKeyDown}\n @wheel=${this.#onWheel}\n id=\"container\"\n class=${this.#containerClass}\n >\n <slot @slotchange=${this.#onSlotChange}></slot>\n ${caretStyle\n ? html`<div class=\"drop-caret\" style=${caretStyle}></div>`\n : nothing}\n </div>\n <div class=\"list-toolbar ${this.orientation}\" part=\"list-toolbar\">\n <slot name=\"toolbar\" @slotchange=${this.#onToolbarSlotChange}></slot>\n </div>\n </div>`;\n }\n\n #onSlotChange = () => {\n this.updateComplete.then(() => {\n this.#refreshItems();\n this.#syncIndicatorColors();\n this.#syncHideLabels();\n this.#syncLabelNogrow();\n });\n };\n\n /**\n * Re-read the assigned tab items. Some environments do not fire slotchange\n * for a slot's initial assignment, so firstUpdated also calls this before\n * syncing item attributes.\n */\n #refreshItems(): void {\n this.#items = (this.shadowRoot?.querySelector(`slot:not([name])`) as HTMLSlotElement)\n ?.assignedElements({ flatten: true }) as TabListItemElement[] ?? [];\n }\n\n #onToolbarSlotChange = () => {\n const slot = this.shadowRoot?.querySelector(`slot[name=\"toolbar\"]`) as HTMLSlotElement | null;\n const assigned = slot?.assignedElements() ?? [];\n const has = assigned.length > 0;\n this.toggleAttribute(`has-toolbar`, has);\n const toolbarDiv = this.shadowRoot?.querySelector(`.list-toolbar`) as HTMLElement | null;\n if (toolbarDiv)\n toolbarDiv.hidden = !has;\n\n // Force ixfx-toolbar to re-measure after slot assignment\n if (has) {\n const toolbar = assigned[0];\n if (toolbar?.tagName === `IXFX-TOOLBAR`) {\n requestAnimationFrame(() => {\n (toolbar as any)?._scheduleMeasure?.();\n });\n }\n }\n };\n\n override firstUpdated() {\n this.updateComplete.then(() => {\n this.#refreshItems();\n this.#syncIndicatorColors();\n this.#syncHideLabels();\n this.#syncLabelNogrow();\n this.#onToolbarSlotChange();\n });\n }\n\n override updated(changedProperties: PropertyValues): void {\n super.updated(changedProperties);\n this.classList.toggle(`scrollable`, this.scrollable);\n if (changedProperties.has(`dragMode`)) {\n this.toggleAttribute(`drag-mode`, this.dragMode !== `off`);\n }\n if (changedProperties.has(`hideLabels`)) {\n this.#syncHideLabels();\n }\n if (changedProperties.has(`labelNogrow`)) {\n this.#syncLabelNogrow();\n }\n }\n\n #syncHideLabels() {\n for (const item of this.#items) {\n if (this.hideLabels) {\n item.setAttribute(`hide-labels`, ``);\n } else {\n item.removeAttribute(`hide-labels`);\n }\n }\n }\n\n #syncLabelNogrow() {\n for (const item of this.#items) {\n if (this.labelNogrow) {\n item.setAttribute(`label-nogrow`, ``);\n } else {\n item.removeAttribute(`label-nogrow`);\n }\n }\n }\n\n #syncIndicatorColors() {\n for (const item of this.#items) {\n item.style.setProperty(`--indicator-color-bottom`, `transparent`);\n item.style.setProperty(`--indicator-color-top`, `transparent`);\n item.style.setProperty(`--indicator-color-left`, `transparent`);\n item.style.setProperty(`--indicator-color-right`, `transparent`);\n\n if (item.hasAttribute(`selected`)) {\n if (this.orientation === `horizontal` && !this.flip) {\n item.style.setProperty(`--indicator-color-bottom`, `var(--accent)`);\n } else if (this.orientation === `horizontal` && this.flip) {\n item.style.setProperty(`--indicator-color-top`, `var(--accent)`);\n } else if (this.#isVertical && !this.flip) {\n item.style.setProperty(`--indicator-color-right`, `var(--accent)`);\n } else if (this.#isVertical && this.flip) {\n item.style.setProperty(`--indicator-color-left`, `var(--accent)`);\n }\n }\n }\n }\n\n #onKeyUp = (event: KeyboardEvent) => {\n const key = event.key;\n if (this.#isVertical) {\n if (key === `ArrowUp`) {\n this.#selectPrevious();\n } else if (key === `ArrowDown`) {\n this.#selectNext();\n }\n } else {\n if (key === `ArrowRight`) {\n this.#selectNext();\n } else if (key === `ArrowLeft`) {\n this.#selectPrevious();\n }\n }\n };\n\n // Escape during drag aborts it (and tears down listeners / releases capture)\n #onKeyDown = (event: KeyboardEvent): void => {\n const state = this.#dragState;\n if (event.key !== `Escape` || !state?.active)\n return;\n event.preventDefault();\n const pointerId = state.pointerId;\n this.#abortDrag();\n this.#endDrag(pointerId);\n };\n\n /**\n * Translate vertical wheel deltas into horizontal scroll on a scrollable\n * horizontal list (and vice-versa for vertical lists). Without this, the\n * default browser behaviour only scrolls horizontally with Shift+wheel or a\n * physical horizontal wheel — neither of which most users reach for on a\n * VS Code-style tab strip.\n *\n * Only kicks in when the list is actually scrollable (overflow content\n * present), and is a no-op when nothing is scrollable in that direction.\n */\n #onWheel = (event: WheelEvent): void => {\n if (!this.scrollable)\n return;\n const el = this.#containerEl;\n if (!el)\n return;\n\n if (!this.#isVertical) {\n if (event.deltaY === 0 || el.scrollWidth <= el.clientWidth)\n return;\n el.scrollLeft = el.scrollLeft + event.deltaY;\n event.preventDefault();\n } else {\n if (event.deltaX === 0 || el.scrollHeight <= el.clientHeight)\n return;\n el.scrollTop = el.scrollTop + event.deltaX;\n event.preventDefault();\n }\n };\n\n getSelectedElement() {\n for (const el of this.#items) {\n if (this.#isSelected(el))\n return el;\n }\n // Fallback: #items may not be populated yet (slotchange hasn't fired).\n // Query the slot directly to find the selected element.\n const slot = this.shadowRoot?.querySelector(`slot`);\n if (slot) {\n const els = (slot as HTMLSlotElement).assignedElements({ flatten: true });\n for (const el of els) {\n if (this.#isSelected(el as HTMLElement))\n return el as TabListItemElement;\n }\n }\n }\n\n #isSelected(el: HTMLElement) {\n const v = el.getAttribute(`selected`);\n if (v === null)\n return false;\n return (el.hasAttribute(`selected`));\n }\n\n selectElement(el: HTMLElement) {\n const existing = this.getSelectedElement();\n if (existing) {\n existing.removeAttribute(`selected`);\n existing.style.setProperty(`--indicator-color-bottom`, `transparent`);\n existing.style.setProperty(`--indicator-color-top`, `transparent`);\n existing.style.setProperty(`--indicator-color-left`, `transparent`);\n existing.style.setProperty(`--indicator-color-right`, `transparent`);\n }\n\n el.setAttribute(`selected`, ``);\n\n if (this.orientation === `horizontal` && !this.flip) {\n el.style.setProperty(`--indicator-color-bottom`, `var(--accent)`);\n } else if (this.orientation === `horizontal` && this.flip) {\n el.style.setProperty(`--indicator-color-top`, `var(--accent)`);\n } else if (this.#isVertical && !this.flip) {\n el.style.setProperty(`--indicator-color-right`, `var(--accent)`);\n } else if (this.#isVertical && this.flip) {\n el.style.setProperty(`--indicator-color-left`, `var(--accent)`);\n }\n }\n\n #selectNext() {\n let found = false;\n for (const el of this.#items) {\n if (this.#isSelected(el) && !found) {\n found = true;\n } else if (found) {\n this.selectElement(el);\n break;\n }\n }\n }\n\n #selectPrevious() {\n let prev: HTMLElement | undefined;\n for (const el of this.#items) {\n if (this.#isSelected(el) && prev) {\n this.selectElement(prev);\n } else {\n prev = el;\n }\n }\n }\n\n #onSlotClick = (event: MouseEvent) => {\n if (this.#suppressNextClick) {\n this.#suppressNextClick = false;\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n this.focus();\n const t = (event.target as HTMLElement).closest(`ixfx-tab-list-item`);\n if (!t)\n return;\n const previous = this.getSelectedElement();\n this.selectElement(t);\n\n const forId = t.getAttribute(`for`);\n const previousId = previous?.id;\n this.dispatchEvent(new CustomEvent<TabListChangeDetail>(`change`, {\n bubbles: true,\n detail: {\n previous: previousId,\n selected: t.id,\n for: forId ?? ``,\n },\n }));\n };\n\n // ── Drag handling ────────────────────────────────────────────────────\n\n /**\n * Walk composedPath looking for the nearest ancestor tab-list-item, but bail\n * if the path goes through a `.close-btn` or `.toolbar` (so close/toolbar\n * buttons always win — same delegation pattern used by tooltip-controller).\n */\n #findDragTarget(event: PointerEvent): TabListItemElement | null {\n if (this.dragMode === `off`)\n return null;\n\n const path = event.composedPath();\n let item: TabListItemElement | null = null;\n for (const node of path) {\n if (!(node instanceof HTMLElement))\n continue;\n if (node.classList.contains(`close-btn`) || node.classList.contains(`toolbar`)) {\n return null;\n }\n if (!item && node.tagName === `IXFX-TAB-LIST-ITEM`) {\n item = node as TabListItemElement;\n }\n }\n return item;\n }\n\n #onPointerDown = (event: PointerEvent): void => {\n if (this.dragMode !== `reorder`)\n return;\n if (event.button !== 0)\n return;\n const target = this.#findDragTarget(event);\n if (!target)\n return;\n\n const fromIndex = this.#items.indexOf(target);\n if (fromIndex < 0)\n return;\n\n // Don't capture the pointer yet — doing so on pointerdown would redirect\n // the trailing click event to the capture target (the container), so the\n // click handler would see a container DIV as its target instead of the\n // tab-list-item and `closest('ixfx-tab-list-item')` would return null.\n // We capture only once the drag actually activates (#beginDrag). Until\n // then, an ordinary press still produces a normal click on the tab.\n\n this.#dragState = {\n pointerId: event.pointerId,\n source: target,\n fromIndex,\n startX: event.clientX,\n startY: event.clientY,\n active: false,\n ghost: null,\n gapIndex: undefined,\n };\n\n // Listen at window level for move/up so we don't lose events if the\n // pointer exits the host before pointerup fires.\n window.addEventListener(`pointermove`, this.#onPointerMove);\n window.addEventListener(`pointerup`, this.#onPointerUp);\n window.addEventListener(`pointercancel`, this.#onPointerCancel);\n };\n\n #onPointerMove = (event: PointerEvent): void => {\n const state = this.#dragState;\n if (!state || event.pointerId !== state.pointerId)\n return;\n\n const dx = event.clientX - state.startX;\n const dy = event.clientY - state.startY;\n const distance = Math.hypot(dx, dy);\n\n if (!state.active) {\n if (distance < DRAG_THRESHOLD_PX)\n return;\n this.#beginDrag(event);\n }\n\n state.ghost?.move(event.clientX, event.clientY);\n\n const gap = this.#computeGapIndex(event.clientX, event.clientY);\n if (gap !== state.gapIndex) {\n state.gapIndex = gap;\n this.requestUpdate();\n }\n };\n\n #onPointerUp = (event: PointerEvent): void => {\n const state = this.#dragState;\n if (!state || event.pointerId !== state.pointerId)\n return;\n\n if (state.active) {\n const gap = this.#computeGapIndex(event.clientX, event.clientY);\n this.#commitDrag(state.source, state.fromIndex, gap);\n }\n this.#endDrag(event.pointerId);\n };\n\n #onPointerCancel = (event: PointerEvent): void => {\n const state = this.#dragState;\n if (!state || event.pointerId !== state.pointerId)\n return;\n this.#abortDrag();\n this.#endDrag(event.pointerId);\n };\n\n #beginDrag(event: PointerEvent): void {\n const state = this.#dragState;\n if (!state || state.active)\n return;\n\n // Now that we know we're dragging, capture the pointer so pointermove/up\n // events keep flowing even if the pointer leaves the host element.\n try {\n this.#containerEl?.setPointerCapture(event.pointerId);\n } catch {\n // setPointerCapture can throw if pointer is already captured elsewhere;\n // fall through — window listeners still catch move/up.\n }\n\n state.active = true;\n state.source.setAttribute(`drag-source`, ``);\n\n state.ghost = this.#createGhost(state.source);\n if (state.ghost) {\n state.ghost.move(event.clientX, event.clientY);\n }\n }\n\n #abortDrag(): void {\n const state = this.#dragState;\n if (!state)\n return;\n state.source.removeAttribute(`drag-source`);\n if (state.gapIndex !== undefined) {\n state.gapIndex = undefined;\n this.requestUpdate();\n }\n // Caller is responsible for invoking #endDrag to release pointer capture,\n // tear down listeners, and destroy the ghost.\n }\n\n #endDrag(pointerId: number): void {\n const state = this.#dragState;\n if (!state)\n return;\n\n state.ghost?.destroy();\n state.ghost = null;\n this.#dragState = null;\n\n window.removeEventListener(`pointermove`, this.#onPointerMove);\n window.removeEventListener(`pointerup`, this.#onPointerUp);\n window.removeEventListener(`pointercancel`, this.#onPointerCancel);\n\n try {\n this.#containerEl?.releasePointerCapture(pointerId);\n } catch { /* already released */ }\n\n // #dragState is a private field, not a Lit-reactive property — setting it\n // to null doesn't trigger a re-render on its own. Without this, the caret\n // (and any other drag-time UI) would remain in the DOM after the drag\n // ends, even though the next render would clear them.\n this.requestUpdate();\n }\n\n #commitDrag(source: TabListItemElement, fromIndex: number, gapIndex: number | undefined): void {\n source.removeAttribute(`drag-source`);\n\n // gapIndex is an index into the without-source siblings array: 0 = before\n // the first sibling, siblings.length = after the last. The siblings array\n // already excludes source, so we can insert directly at that position\n // using siblings[gapIndex] as the reference (or null to append).\n const siblings = this.#items.filter(el => el !== source);\n const target = gapIndex === undefined\n ? siblings.length\n : Math.max(0, Math.min(gapIndex, siblings.length));\n\n const parent = source.parentNode;\n if (!parent)\n return;\n\n const ref = siblings[target] ?? null;\n parent.insertBefore(source, ref);\n\n const toIndex = Array.prototype.indexOf.call(parent.children, source);\n if (toIndex === fromIndex) {\n // Dropped in the same gap the item already occupies — no reorder, and no\n // click suppression (a real click on the same tab is still meaningful).\n return;\n }\n\n // Refresh cached #items so subsequent drags / queries see the new order\n // (slotchange does NOT fire on reorder, only on add/remove).\n this.#items = (this.shadowRoot?.querySelector(`slot`) as HTMLSlotElement)\n ?.assignedElements({ flatten: true }) as TabListItemElement[] ?? [];\n this.#syncIndicatorColors();\n\n // A real reorder just happened. The trailing click event (which the\n // browser still fires after pointerup) would re-select whatever is under\n // the release point — not what the user wanted. Suppress it.\n this.#suppressNextClick = true;\n\n this.dispatchEvent(new CustomEvent<TabListReorderDetail>(`reorder`, {\n bubbles: true,\n detail: {\n id: source.id,\n fromIndex,\n toIndex,\n },\n }));\n }\n\n #createGhost(source: TabListItemElement): DragGhost | null {\n const content = document.createElement(`span`);\n content.style.display = `inline-flex`;\n content.style.alignItems = `center`;\n content.style.gap = `var(--space-xs, 4px)`;\n content.style.minWidth = `0`;\n\n const iconName = source.iconName;\n if (iconName) {\n const icon = document.createElement(`ixfx-icon`) as HTMLElement & { name: string };\n icon.name = iconName;\n content.appendChild(icon);\n }\n\n // Reconstruct label text from light-DOM children that aren't slotted.\n // We want the text content of the source item, excluding `slot=\"toolbar\"`\n // descendants (the close button lives inside the item's shadow DOM, not\n // its light DOM, so it isn't part of childNodes here).\n const label = document.createElement(`span`);\n label.textContent = (source.textContent ?? ``).trim();\n label.style.overflow = `hidden`;\n label.style.textOverflow = `ellipsis`;\n label.style.whiteSpace = `nowrap`;\n content.appendChild(label);\n\n try {\n return createDragGhost({ anchor: source, content });\n } catch {\n return null;\n }\n }\n\n /**\n * Compute the index of the gap nearest the pointer, ignoring the source item.\n * Returns 0..#items.length-1; undefined if no siblings.\n *\n * Per the plan: drag-mode=\"reorder\" has \"no sense of breaking out\", so the\n * perpendicular axis is ignored — the pointer always resolves to some gap.\n */\n #computeGapIndex(clientX: number, clientY: number): number | undefined {\n const state = this.#dragState;\n if (!state)\n return undefined;\n const siblings = this.#items.filter(el => el !== state.source);\n if (siblings.length === 0)\n return 0;\n\n const useX = !this.#isVertical;\n\n let bestGap = 0;\n let bestDist = Infinity;\n\n // For each sibling, decide: gap is \"before this sibling\" or \"after\" based\n // on which side of the midpoint the pointer is on. Pick the gap whose\n // position (the midpoint if \"before\", the edge if \"after\") is closest to\n // the pointer on the relevant axis.\n for (let i = 0; i < siblings.length; i++) {\n const rect = siblings[i].getBoundingClientRect();\n const start = useX ? rect.left : rect.top;\n const end = useX ? rect.right : rect.bottom;\n const mid = (start + end) / 2;\n const pos = useX ? clientX : clientY;\n\n // Two candidate gaps: before this sibling (at `start`) and after (at `end`).\n // \"Before\" gap index = i; \"after\" gap index = i + 1.\n const dStart = Math.abs(pos - start);\n const dMid = Math.abs(pos - mid);\n const dEnd = Math.abs(pos - end);\n\n // Heuristic: if pointer is left/above midpoint, prefer the \"before\" gap;\n // otherwise prefer the \"after\" gap. Within those, the closer edge wins.\n const preferBefore = pos < mid;\n if (preferBefore) {\n // Gap i (before this sibling)\n if (dStart < bestDist) {\n bestDist = dStart;\n bestGap = i;\n }\n } else {\n // Gap i+1 (after this sibling)\n if (dEnd < bestDist) {\n bestDist = dEnd;\n bestGap = i + 1;\n }\n }\n // The midpoint-distance is mostly redundant with the above but handles\n // ties near the boundary cleanly — no-op for the chosen gap.\n void dMid;\n }\n\n return bestGap;\n }\n\n #computeCaretStyle(): string | undefined {\n const state = this.#dragState;\n if (!state?.active || state.gapIndex === undefined)\n return undefined;\n\n const siblings = this.#items.filter(el => el !== state.source);\n if (siblings.length === 0)\n return undefined;\n\n const useX = !this.#isVertical;\n const containerRect = this.#containerEl?.getBoundingClientRect();\n if (!containerRect)\n return undefined;\n\n const gap = Math.max(0, Math.min(state.gapIndex, siblings.length));\n let rect: DOMRect | null = null;\n if (gap < siblings.length) {\n rect = siblings[gap].getBoundingClientRect();\n } else {\n // After the last sibling: use its trailing edge\n const last = siblings[siblings.length - 1].getBoundingClientRect();\n rect = last;\n }\n\n if (useX) {\n const x = (gap < siblings.length ? rect.left : rect.right) - containerRect.left;\n const y = 0;\n const h = containerRect.height;\n const w = 2;\n return `transform: translate(${x - w / 2}px, ${y}px); width: ${w}px; height: ${h}px;`;\n } else {\n const y = (gap < siblings.length ? rect.top : rect.bottom) - containerRect.top;\n const x = 0;\n const w = containerRect.width;\n const h = 2;\n return `transform: translate(${x}px, ${y - h / 2}px); width: ${w}px; height: ${h}px;`;\n }\n }\n\n get #containerEl(): HTMLElement | null {\n return this.shadowRoot?.getElementById(`container`) ?? null;\n }\n\n static styles = [themeFallbacks, scrollFadeStyles(`x`), scrollFadeStyles(`y`), css`\n :host {\n display: inline-block;\n --activated-colour: var(--accent);\n --colour: var(--surface-3-text);\n --scroll-max-height: 200px;\n --allow-overflow: hidden;\n color: var(--colour);\n border: var(--border, none);\n border-color: var(--surface-5);\n border-radius: var(--radius-l, 8px) var(--radius-l, 8px) 0 0;\n\n }\n :host(.scrollable) {\n max-height: var(--scroll-max-height);\n }\n :host([hide-labels]) {\n display: inline-flex;\n width: auto;\n }\n text {\n user-select:none;\n }\n .outer {\n display: flex;\n width: 100%;\n height: 100%;\n gap: var(--space-s);\n align-items: stretch;\n box-sizing: border-box;\n }\n .outer.horizontal {\n flex-direction: row;\n align-items: center;\n }\n .outer.vertical-stack,\n .outer.vertical-side {\n flex-direction: column;\n }\n .list-toolbar {\n display: flex;\n align-items: center;\n gap: var(--space-xs);\n flex: 0 0 auto;\n width: max-content;\n max-width: 50%;\n overflow: visible;\n }\n .list-toolbar.horizontal ::slotted(*:not(ixfx-toolbar)) {\n margin-left: auto;\n }\n .list-toolbar[hidden] {\n display: none !important;\n }\n .list-toolbar[hidden] {\n display: none !important;\n }\n ::slotted(ixfx-toolbar) {\n --toolbar-bg: transparent;\n --toolbar-border: none;\n --toolbar-padding: 0;\n width: max-content;\n max-width: 100%;\n min-width: 150px;\n flex-shrink: 0;\n }\n #container {\n display:flex;\n position: relative;\n flex: 1 1 0%;\n min-width: 0;\n min-height: 0;\n }\n .outer.vertical-stack #container,\n .outer.vertical-side #container {\n flex: 1 1 auto;\n height: 100%;\n }\n #container.horizontal {\n flex-direction: row;\n overflow: hidden;\n }\n #container.horizontal.scrollable {\n overflow-x: scroll;\n --allow-overflow: visible;\n scrollbar-width: none;\n }\n #container.horizontal.scrollable::-webkit-scrollbar {\n display: none;\n }\n #container.horizontal.scrollable ::slotted(ixfx-tab-list-item) {\n flex-shrink: 0;\n }\n #container.vertical-stack {\n flex-direction: column;\n height: 100%;\n }\n #container.vertical-stack.flip {\n flex-direction: column-reverse;\n }\n #container.vertical-stack.scrollable {\n overflow-y: scroll;\n max-height: var(--scroll-max-height);\n --allow-overflow: visible;\n scrollbar-width: none;\n }\n #container.vertical-stack.scrollable::-webkit-scrollbar {\n display: none;\n }\n #container.vertical-side {\n flex-direction: column;\n height: 100%;\n }\n #container.vertical-side.flip {\n flex-direction: column-reverse;\n }\n #container.vertical-side.scrollable {\n overflow-y: scroll;\n max-height: var(--scroll-max-height);\n --allow-overflow: visible;\n scrollbar-width: none;\n }\n #container.vertical-side.scrollable::-webkit-scrollbar {\n display: none;\n }\n\n ::slotted(ixfx-tab-list-item) {\n flex: 1 1 auto;\n min-width: 0;\n }\n\n :host([shrink]) ::slotted(ixfx-tab-list-item) {\n flex: 0 0 auto;\n }\n\n #container.vertical-side ::slotted(ixfx-tab-list-item) {\n writing-mode: vertical-lr;\n text-orientation: mixed;\n }\n #container.vertical-side.flip ::slotted(ixfx-tab-list-item) {\n writing-mode: vertical-rl;\n text-orientation: mixed;\n }\n\n /* Drag affordances — opt-in via drag-mode=\"reorder\" on the host (list). */\n #container.reorder ::slotted(ixfx-tab-list-item) {\n cursor: grab;\n }\n :host([drag-mode]) ::slotted(ixfx-tab-list-item[drag-source]) {\n cursor: grabbing;\n opacity: 0.4;\n transition: opacity var(--transition, 0.15s ease-out);\n }\n\n /* Insertion caret shown during an active drag. */\n .drop-caret {\n position: absolute;\n background: var(--accent);\n border-radius: 1px;\n pointer-events: none;\n z-index: 1;\n }\n\n ::slotted(.activated) {\n --colour: var(--activated-colour);\n }\n `];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ixfx-tab-list\": TabListElement;\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tickled-controller-D-HZymaZ.js","names":[],"sources":["../src/interaction/tickled-controller.ts"],"sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\n/**\n * Represents an item that can be tickled (highlighted via hover or keyboard navigation)\n */\nexport type TickledItem<T = unknown> = {\n /**\n * Unique identifier for the item (e.g., index, id, path)\n */\n readonly id: T;\n\n /**\n * Whether the item is currently enabled/interactive\n */\n readonly enabled?: boolean;\n};\n\n/**\n * Input mode determines which mechanism controls the tickled state\n */\nexport type InputMode = `keyboard` | `mouse`;\n\n/**\n * Configuration for TickledController\n */\nexport type TickledControllerConfig<T> = {\n /**\n * Function to retrieve all items that can be tickled\n */\n getItems: () => ReadonlyArray<TickledItem<T>>;\n\n /**\n * Optional callback when an item becomes tickled\n * Use this for side effects like opening submenus\n * @param id - The id of the newly tickled item, or undefined if nothing is tickled\n */\n onTickle?: (id: T | undefined) => void;\n\n /**\n * Optional callback fired after any state change (tickled id or input mode)\n * Use this to sync DOM attributes for slotted content that can't use reactive rendering\n *\n * For components that render items directly, this is usually not needed as\n * Lit's reactive rendering will handle updates automatically via requestUpdate()\n *\n * @example\n * ```ts\n * onStateChange: () => {\n * // Sync data-tickled attributes for slotted items\n * const items = this.getItems();\n * items.forEach((item, i) => {\n * if (this.tickled.isTickled(i)) {\n * item.setAttribute('data-tickled', '');\n * } else {\n * item.removeAttribute('data-tickled');\n * }\n * });\n * }\n * ```\n */\n onStateChange?: () => void;\n\n /**\n * Optional initial input mode (defaults to 'mouse')\n */\n initialInputMode?: InputMode;\n\n /**\n * When this returns `true`, pointer hover no longer drives the cursor:\n * `handlePointerEnter` / `handlePointerLeave` become no-ops and hover never\n * switches the input mode to `mouse`. Keyboard navigation, programmatic\n * `focus()` / `setTickled()`, and click handling are unaffected. Read on every\n * hover event, so a host can flip it via a reactive property. Default: `false`.\n */\n hoverDisabled?: () => boolean;\n\n /**\n * Whether keyboard navigation wraps from last to first and vice versa.\n * - 'stop' (default): navigation stops at the boundary\n * - 'wrap': navigation wraps around\n */\n itemWrap?: `stop` | `wrap`;\n};\n\n/**\n * ReactiveController that manages \"tickled\" state for interactive lists.\n *\n * A \"tickled\" item is one that is under active attention via hover (mouse mode)\n * or keyboard focus (keyboard mode). Only one item can be tickled at a time.\n *\n * The input mode determines which mechanism controls tickled state:\n * - Mouse mode: hover controls tickled, keyboard navigation ignored\n * - Keyboard mode: keyboard navigation controls tickled, hover ignored\n *\n * Last interaction wins - any mouse hover switches to mouse mode, any keyboard\n * navigation switches to keyboard mode.\n *\n * ## Global Mouse Tracking\n *\n * This controller uses a single, ref-counted global `pointermove` listener (shared\n * across all instances) to track actual mouse movement. This prevents `pointerenter`\n * events caused by content scrolling from incorrectly switching to mouse mode when\n * the user is actually using keyboard navigation. The listener is attached when the\n * first host connects and removed once the last host disconnects.\n *\n * @example\n * ```ts\n * class MyList extends LitElement {\n * private tickled = new TickledController(this, {\n * getItems: () => this.items.map((item, i) => ({ id: i, enabled: !item.disabled })),\n * onTickle: (id) => {\n * // Optional: perform side effect when item is tickled\n * console.log('Tickled item:', id);\n * }\n * });\n *\n * render() {\n * return html`\n * <ul @pointerleave=${(e) => this.tickled.handlePointerLeave(e)}>\n * ${this.items.map((item, i) => html`\n * <li\n * class=\"item ${this.tickled.isTickled(i) ? 'tickled' : ''}\"\n * @pointerenter=${() => this.tickled.handlePointerEnter(i)}\n * >${item.label}</li>\n * `)}\n * </ul>\n * `;\n * }\n *\n * private handleKeyDown(e: KeyboardEvent) {\n * if (e.key === 'ArrowDown') {\n * this.tickled.handleKeyboardNavigation('next');\n * } else if (e.key === 'ArrowUp') {\n * this.tickled.handleKeyboardNavigation('previous');\n * }\n * }\n * }\n * ```\n */\nexport class TickledController<T = number> implements ReactiveController {\n private host: ReactiveControllerHost;\n private config: TickledControllerConfig<T>;\n private _tickledId: T | undefined = undefined;\n private _inputMode: InputMode;\n private hoverDisabled: () => boolean;\n\n private static _lastMouseClientX: number = Number.NaN;\n private static _lastMouseClientY: number = Number.NaN;\n private static _mouseMovedSinceKeyboard: boolean = true;\n private static _listenerRefCount: number = 0;\n\n private static readonly _onGlobalPointerMove = (e: PointerEvent): void => {\n TickledController.handleGlobalPointerMove(e.clientX, e.clientY);\n };\n\n constructor(host: ReactiveControllerHost, config: TickledControllerConfig<T>) {\n this.host = host;\n this.config = config;\n this._inputMode = config.initialInputMode ?? `mouse`;\n this.hoverDisabled = config.hoverDisabled ?? (() => false);\n host.addController(this);\n }\n\n hostConnected(): void {\n if (TickledController._listenerRefCount === 0) {\n document.addEventListener(`pointermove`, TickledController._onGlobalPointerMove, { passive: true });\n }\n TickledController._listenerRefCount++;\n }\n\n hostDisconnected(): void {\n TickledController._listenerRefCount--;\n if (TickledController._listenerRefCount === 0) {\n document.removeEventListener(`pointermove`, TickledController._onGlobalPointerMove);\n }\n }\n\n /**\n * Get the current input mode\n */\n get inputMode(): InputMode {\n return this._inputMode;\n }\n\n /**\n * Get the currently tickled item id\n */\n get tickledId(): T | undefined {\n return this._tickledId;\n }\n\n /**\n * The item currently under the cursor, or `undefined`. Alias of `tickledId`\n * for parity with other controllers.\n */\n get current(): T | undefined {\n return this._tickledId;\n }\n\n /**\n * Move the cursor programmatically (e.g. to reveal a match or re-seat it\n * after the item set changed). Does not change the input mode. Alias of\n * `setTickled`.\n */\n focus(id: T | undefined): void {\n this.setTickled(id);\n }\n\n /**\n * Check if a specific item is tickled\n */\n isTickled(id: T): boolean {\n return this._tickledId === id;\n }\n\n /**\n * Handle global pointer move event.\n * Called automatically by the global listener.\n * Tracks mouse movement to distinguish real hover from content scrolling.\n */\n private static handleGlobalPointerMove(clientX: number, clientY: number): void {\n if (!Number.isNaN(TickledController._lastMouseClientX)) {\n if (\n clientX !== TickledController._lastMouseClientX\n || clientY !== TickledController._lastMouseClientY\n ) {\n TickledController._mouseMovedSinceKeyboard = true;\n }\n }\n TickledController._lastMouseClientX = clientX;\n TickledController._lastMouseClientY = clientY;\n }\n\n /**\n * Ignore hover (pointerenter / pointerleave) until the pointer genuinely\n * moves. Call this when something other than the pointer changes what is\n * under it — a keypress, or the item set being swapped.\n */\n static ignoreHoverUntilPointerMoves(): void {\n TickledController._mouseMovedSinceKeyboard = false;\n }\n\n /**\n * Check if actual mouse movement has occurred since last keyboard interaction.\n * Used to distinguish real hover/leave from content-scrolling-induced events.\n */\n static get hasMouseMovedSinceKeyboard(): boolean {\n return TickledController._mouseMovedSinceKeyboard;\n }\n\n /**\n * Handle pointer enter event on an item (mouse hover).\n * Only processes if actual mouse movement is detected (not content scrolling).\n * Switches to mouse mode and tickles the item.\n */\n handlePointerEnter(id: T): void {\n if (this.hoverDisabled()) {\n return;\n }\n\n if (!TickledController._mouseMovedSinceKeyboard) {\n return;\n }\n\n const items = this.config.getItems();\n const item = items.find(item => item.id === id);\n if (item && item.enabled === false) {\n return;\n }\n\n const modeChanged = this._inputMode !== `mouse`;\n this._inputMode = `mouse`;\n\n const previousId = this._tickledId;\n this._tickledId = id;\n\n this.host.requestUpdate();\n\n if (previousId !== id && this.config.onTickle) {\n this.config.onTickle(id);\n }\n\n if ((previousId !== id || modeChanged) && this.config.onStateChange) {\n this.config.onStateChange();\n }\n }\n\n /**\n * Handle pointer leave event on an item.\n * Only clears tickled state if actual mouse movement is detected.\n * @param _e The pointer event (not used, but kept for API compatibility)\n */\n handlePointerLeave(_e: PointerEvent): void {\n if (this.hoverDisabled()) {\n return;\n }\n if (TickledController._mouseMovedSinceKeyboard) {\n this.clearTickled();\n }\n }\n\n /**\n * Handle keyboard navigation.\n * Switches to keyboard mode and moves tickled state.\n *\n * @param direction - 'next', 'previous', 'first', 'last', or specific id\n */\n handleKeyboardNavigation(direction: `next` | `previous` | `first` | `last` | T): void {\n const modeChanged = this._inputMode !== `keyboard`;\n this._inputMode = `keyboard`;\n // Rows that scroll under a resting pointer must not steal the cursor.\n TickledController.ignoreHoverUntilPointerMoves();\n\n const items = this.config.getItems();\n const enabledItems = items.filter(item => item.enabled !== false);\n\n if (enabledItems.length === 0) {\n return;\n }\n\n let newId: T | undefined;\n\n if (direction === `first`) {\n newId = enabledItems[0].id;\n } else if (direction === `last`) {\n newId = enabledItems.at(-1)?.id;\n } else if (direction === `next` || direction === `previous`) {\n const currentIndex = enabledItems.findIndex(item => item.id === this._tickledId);\n const wrap = this.config.itemWrap === `wrap`;\n\n if (currentIndex === -1) {\n newId = direction === `next` ? enabledItems[0].id : enabledItems.at(-1)?.id;\n } else {\n const delta = direction === `next` ? 1 : -1;\n let newIndex = currentIndex + delta;\n\n if (newIndex >= 0 && newIndex < enabledItems.length) {\n newId = enabledItems[newIndex].id;\n } else if (wrap) {\n // Wrap around\n if (newIndex < 0) {\n newIndex = enabledItems.length - 1;\n } else {\n newIndex = 0;\n }\n newId = enabledItems[newIndex].id;\n }\n // If newIndex is out of bounds and wrap is disabled, keep current tickled item\n }\n } else {\n const item = enabledItems.find(item => item.id === direction);\n if (item) {\n newId = item.id;\n }\n }\n\n if (newId !== undefined) {\n const previousId = this._tickledId;\n this._tickledId = newId;\n this.host.requestUpdate();\n\n if (previousId !== newId && this.config.onTickle) {\n this.config.onTickle(newId);\n }\n\n if ((previousId !== newId || modeChanged) && this.config.onStateChange) {\n this.config.onStateChange();\n }\n }\n }\n\n /**\n * Manually set the tickled item (useful for programmatic control).\n * Does NOT change input mode.\n */\n setTickled(id: T | undefined): void {\n const previousId = this._tickledId;\n this._tickledId = id;\n this.host.requestUpdate();\n\n if (previousId !== id && this.config.onTickle) {\n this.config.onTickle(id);\n }\n\n if (previousId !== id && this.config.onStateChange) {\n this.config.onStateChange();\n }\n }\n\n /**\n * Clear the tickled state (e.g., on pointer leave).\n * Note: For pointer leave events, prefer using handlePointerLeave() which\n * checks for actual mouse movement.\n */\n clearTickled(): void {\n if (this._tickledId !== undefined) {\n this._tickledId = undefined;\n this.host.requestUpdate();\n\n if (this.config.onTickle) {\n this.config.onTickle(undefined);\n }\n\n if (this.config.onStateChange) {\n this.config.onStateChange();\n }\n }\n }\n\n /**\n * Manually set the input mode.\n * When switching to keyboard mode, resets the mouse movement tracking.\n */\n setInputMode(mode: InputMode): void {\n if (this._inputMode !== mode) {\n this._inputMode = mode;\n this.host.requestUpdate();\n\n if (mode === `keyboard`) {\n TickledController._mouseMovedSinceKeyboard = false;\n }\n\n if (this.config.onStateChange) {\n this.config.onStateChange();\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2IA,IAAa,oBAAb,MAAa,kBAA4D;;EAO5B,KAAA,oBAAA;;;EACA,KAAA,oBAAA;;;EACQ,KAAA,2BAAA;;;EACR,KAAA,oBAAA;;;EAEK,KAAA,wBAAA,MAA0B;GACxE,kBAAkB,wBAAwB,EAAE,SAAS,EAAE,OAAO;EAChE;;CAEA,YAAY,MAA8B,QAAoC;EAb1C,KAAA,aAAA,KAAA;EAclC,KAAK,OAAO;EACZ,KAAK,SAAS;EACd,KAAK,aAAa,OAAO,oBAAoB;EAC7C,KAAK,gBAAgB,OAAO,wBAAwB;EACpD,KAAK,cAAc,IAAI;CACzB;CAEA,gBAAsB;EACpB,IAAI,kBAAkB,sBAAsB,GAC1C,SAAS,iBAAiB,eAAe,kBAAkB,sBAAsB,EAAE,SAAS,KAAK,CAAC;EAEpG,kBAAkB;CACpB;CAEA,mBAAyB;EACvB,kBAAkB;EAClB,IAAI,kBAAkB,sBAAsB,GAC1C,SAAS,oBAAoB,eAAe,kBAAkB,oBAAoB;CAEtF;;;;CAKA,IAAI,YAAuB;EACzB,OAAO,KAAK;CACd;;;;CAKA,IAAI,YAA2B;EAC7B,OAAO,KAAK;CACd;;;;;CAMA,IAAI,UAAyB;EAC3B,OAAO,KAAK;CACd;;;;;;CAOA,MAAM,IAAyB;EAC7B,KAAK,WAAW,EAAE;CACpB;;;;CAKA,UAAU,IAAgB;EACxB,OAAO,KAAK,eAAe;CAC7B;;;;;;CAOA,OAAe,wBAAwB,SAAiB,SAAuB;EAC7E,IAAI,CAAC,OAAO,MAAM,kBAAkB,iBAAiB,GAEjD;OAAA,YAAY,kBAAkB,qBAC3B,YAAY,kBAAkB,mBAEjC,kBAAkB,2BAA2B;EAAA;EAGjD,kBAAkB,oBAAoB;EACtC,kBAAkB,oBAAoB;CACxC;;;;;;CAOA,OAAO,+BAAqC;EAC1C,kBAAkB,2BAA2B;CAC/C;;;;;CAMA,WAAW,6BAAsC;EAC/C,OAAO,kBAAkB;CAC3B;;;;;;CAOA,mBAAmB,IAAa;EAC9B,IAAI,KAAK,cAAc,GACrB;EAGF,IAAI,CAAC,kBAAkB,0BACrB;EAIF,MAAM,OADQ,KAAK,OAAO,SACT,CAAC,CAAC,MAAK,SAAQ,KAAK,OAAO,EAAE;EAC9C,IAAI,QAAQ,KAAK,YAAY,OAC3B;EAGF,MAAM,cAAc,KAAK,eAAe;EACxC,KAAK,aAAa;EAElB,MAAM,aAAa,KAAK;EACxB,KAAK,aAAa;EAElB,KAAK,KAAK,cAAc;EAExB,IAAI,eAAe,MAAM,KAAK,OAAO,UACnC,KAAK,OAAO,SAAS,EAAE;EAGzB,KAAK,eAAe,MAAM,gBAAgB,KAAK,OAAO,eACpD,KAAK,OAAO,cAAc;CAE9B;;;;;;CAOA,mBAAmB,IAAwB;EACzC,IAAI,KAAK,cAAc,GACrB;EAEF,IAAI,kBAAkB,0BACpB,KAAK,aAAa;CAEtB;;;;;;;CAQA,yBAAyB,WAA6D;EACpF,MAAM,cAAc,KAAK,eAAe;EACxC,KAAK,aAAa;EAElB,kBAAkB,6BAA6B;EAG/C,MAAM,eADQ,KAAK,OAAO,SACD,CAAC,CAAC,QAAO,SAAQ,KAAK,YAAY,KAAK;EAEhE,IAAI,aAAa,WAAW,GAC1B;EAGF,IAAI;EAEJ,IAAI,cAAc,SAChB,QAAQ,aAAa,EAAE,CAAC;OACnB,IAAI,cAAc,QACvB,QAAQ,aAAa,GAAG,EAAE,CAAC,EAAE;OACxB,IAAI,cAAc,UAAU,cAAc,YAAY;GAC3D,MAAM,eAAe,aAAa,WAAU,SAAQ,KAAK,OAAO,KAAK,UAAU;GAC/E,MAAM,OAAO,KAAK,OAAO,aAAa;GAEtC,IAAI,iBAAiB,IACnB,QAAQ,cAAc,SAAS,aAAa,EAAE,CAAC,KAAK,aAAa,GAAG,EAAE,CAAC,EAAE;QACpE;IAEL,IAAI,WAAW,gBADD,cAAc,SAAS,IAAI;IAGzC,IAAI,YAAY,KAAK,WAAW,aAAa,QAC3C,QAAQ,aAAa,SAAS,CAAC;SAC1B,IAAI,MAAM;KAEf,IAAI,WAAW,GACb,WAAW,aAAa,SAAS;UAEjC,WAAW;KAEb,QAAQ,aAAa,SAAS,CAAC;IACjC;GAEF;EACF,OAAO;GACL,MAAM,OAAO,aAAa,MAAK,SAAQ,KAAK,OAAO,SAAS;GAC5D,IAAI,MACF,QAAQ,KAAK;EAEjB;EAEA,IAAI,UAAU,KAAA,GAAW;GACvB,MAAM,aAAa,KAAK;GACxB,KAAK,aAAa;GAClB,KAAK,KAAK,cAAc;GAExB,IAAI,eAAe,SAAS,KAAK,OAAO,UACtC,KAAK,OAAO,SAAS,KAAK;GAG5B,KAAK,eAAe,SAAS,gBAAgB,KAAK,OAAO,eACvD,KAAK,OAAO,cAAc;EAE9B;CACF;;;;;CAMA,WAAW,IAAyB;EAClC,MAAM,aAAa,KAAK;EACxB,KAAK,aAAa;EAClB,KAAK,KAAK,cAAc;EAExB,IAAI,eAAe,MAAM,KAAK,OAAO,UACnC,KAAK,OAAO,SAAS,EAAE;EAGzB,IAAI,eAAe,MAAM,KAAK,OAAO,eACnC,KAAK,OAAO,cAAc;CAE9B;;;;;;CAOA,eAAqB;EACnB,IAAI,KAAK,eAAe,KAAA,GAAW;GACjC,KAAK,aAAa,KAAA;GAClB,KAAK,KAAK,cAAc;GAExB,IAAI,KAAK,OAAO,UACd,KAAK,OAAO,SAAS,KAAA,CAAS;GAGhC,IAAI,KAAK,OAAO,eACd,KAAK,OAAO,cAAc;EAE9B;CACF;;;;;CAMA,aAAa,MAAuB;EAClC,IAAI,KAAK,eAAe,MAAM;GAC5B,KAAK,aAAa;GAClB,KAAK,KAAK,cAAc;GAExB,IAAI,SAAS,YACX,kBAAkB,2BAA2B;GAG/C,IAAI,KAAK,OAAO,eACd,KAAK,OAAO,cAAc;EAE9B;CACF;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tickled-controller-DodxD3eQ.d.ts","names":[],"sources":["../src/interaction/tickled-controller.ts"],"mappings":";;;;;KAKY,YAAY;;;;WAIb,IAAI;;;;WAKJ;;;;;KAMC;;;;KAKA,wBAAwB;;;;EAIlC,gBAAgB,cAAc,YAAY;;;;;;EAO1C,YAAY,IAAI;;;;;;;;;;;;;;;;;;;;;;;EAwBhB;;;;EAKA,mBAAmB;;;;;;;;EASnB;;;;;;EAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA0DW,kBAAkB,uBAAuB;UAC5C;UACA;UACA;UACA;UACA;iBAEO;iBACA;iBACA;iBACA;0BAES;EAIZ,YAAA,MAAM,wBAAwB,QAAQ,wBAAwB;EAQ1E;EAOA;;;;MAUI,aAAa;;;;MAOb,aAAa;;;;;MAQb,WAAW;;;;;;EASf,MAAM,IAAI;;;;EAOV,UAAU,IAAI;;;;;;iBASC;;;;;;SAkBR;;;;;aAQI;;;;;;EASX,mBAAmB,IAAI;;;;;;EAqCvB,mBAAmB,IAAI;;;;;;;EAevB,yBAAyB,oDAAoD;;;;;EAoE7E,WAAW,IAAI;;;;;;EAmBf;;;;;EAmBA,aAAa,MAAM"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tickled-styles-BrAHEj1q.js","names":[],"sources":["../src/interaction/tickled-styles.ts"],"sourcesContent":["import { css } from 'lit';\n\n/**\n * Shared CSS styles for tickled interaction pattern.\n *\n * Tickled state is controlled via the `.tickled` CSS class (applied by TickledController).\n * The `tickledItemStyles` provides base styling that all tickled components should use.\n *\n * ## CSS Variable Contract\n *\n * **Style variables** — `tickledItemStyles` only consumes these via `var()`; it\n * defines no defaults itself. Fallback values (used when no theme CSS is loaded)\n * are registered in `themeFallbacks` (`../styles/fallbacks.ts`) and mirror the\n * documented base theme in `user-theming.md`:\n * - `--item-bg`, `--item-bg-tickled`, `--item-bg-selected`, `--item-bg-selected-tickled`\n * - `--item-border`, `--item-border-tickled`, `--item-border-selected` (full border shorthands, not colours)\n * - `--item-text-tickled`, `--item-text-selected`\n * - `--item-padding`, `--item-border-radius`, `--item-icon-spacing`\n *\n * ## Usage\n *\n * Components should import both `tickledStyles` and `tickledItemStyles`:\n *\n * ```ts\n * import { tickledStyles, tickledItemStyles } from '../interaction/index.js';\n *\n * class MyComponent extends LitElement {\n * static styles = [\n * tickledStyles,\n * tickledItemStyles,\n * css`\n * :host {\n * --item-bg-tickled: #e0e0e0;\n * --item-bg-selected: #1976d2;\n * }\n * `\n * ];\n * }\n * ```\n */\n\nexport const tickledStyles = css`\n /**\n * No suppression needed - tickled styling is always active.\n */\n`;\n\n/**\n * Shared item styling for tickled components.\n *\n * Provides base styles for interactive items with tickled and selected states.\n * Components should import this in addition to `tickledStyles` and can override\n * CSS variables to customize appearance.\n */\nexport const tickledItemStyles = css`\n .item {\n display: inline-flex;\n align-items: center;\n gap: var(--item-icon-spacing);\n padding: var(--item-padding);\n background: var(--item-bg);\n border: var(--item-border);\n border-radius: var(--item-border-radius);\n cursor: pointer;\n user-select: none;\n white-space: nowrap;\n transition: background var(--transition, 0.1s ease-out), border-color var(--transition, 0.1s ease-out);\n }\n\n .item.tickled {\n background: var(--item-bg-tickled);\n border: var(--item-border-tickled);\n color: var(--item-text-tickled);\n }\n\n .item.selected {\n background: var(--item-bg-selected);\n border: var(--item-border-selected);\n color: var(--item-text-selected);\n }\n\n .item.selected.tickled {\n background: var(--item-bg-selected-tickled);\n outline: 2px dashed var(--surface-3);\n outline-offset: -2px;\n }\n`;"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,MAAa,gBAAgB,GAAG;;;;;;;;;;;;AAahC,MAAa,oBAAoB,GAAG"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"timeline-BP1Ux2EV.js","names":["#host","#config","#onTrackSelect","#bpm","#updateFormatLabel","#timeSignatureNumerator","#timeSignatureDenominator","#dragging","#startScreenY","#startHeight","#fireResizeEvent","#isInResizeZone","#pointerId","#resetDrag","#onPointerMove","#onPointerDown","#onPointerUp","#onPointerCancel","customElement","#hasInitializedZoom","#initZoomToFit","#initVerticalZoomToFit","#recomputeTrackLayout","#deriveViewRange","#deriveVerticalZoom","#syncVCanvas","#invalidateCanvas","#cssVarsCache","#getViewportWidth","#vcanvas","#axisHeight","#minPpu","#applyTrackResize","#tabWidth","#getTotalBaseHeight","#getViewportHeight","#getLargestBaseTrackHeight","#getSmallestBaseTrackHeight","#vScrollOffset","#fireSelectionChange","#pendingVerticalZoomToFit","#drawCallback","#onScrollVirtual","#cleanupInteractions","#resizeObserver","#onResize","#syncVCanvasVertical","#positionTabs","#syncVerticalScroll","#prevTickledId","#onVAxisPointerDown","#onVAxisPointerMove","#onVAxisPointerUp","#onTrackResizeMove","#onTrackResizeEnd","#onVZoomInput","#onHZoomInput","#syncVCanvasScroll","customElement"],"sources":["../src/timeline/timeline-controller.ts","../src/timeline/timeline-draw.ts","../src/timeline/timeline-interactions.ts","../src/timeline/timeline-styles.ts","../src/timeline/timeline-track-tabs.ts","../src/timeline/timeline-element.ts"],"sourcesContent":["import type { GridResolution, TimelineEvent, TimelineTrackSelectDetail, UserScale, ViewRange } from './types.js';\n\n/**\n * Configuration for the TimelineController external adapter.\n */\nexport type TimelineControllerConfig = {\n readonly logicalMin: number;\n readonly logicalMax: number;\n readonly labelFormatter?: (value: number) => string;\n readonly gridResolver?: (viewRange: ViewRange, userScale: UserScale) => GridResolution;\n};\n\n/**\n * Minimal interface the controller expects from the timeline element.\n * Avoids coupling to the concrete element class.\n */\ntype TimelineHost = {\n formatLabel: (v: number) => string;\n setViewRange: (r: ViewRange) => void;\n min: number;\n max: number;\n userScale: string;\n getTrackEvents: (trackKey: string) => TimelineEvent[];\n get selectedIds(): readonly string[];\n set selectedIds(ids: readonly string[]);\n addEventListener: (type: string, listener: EventListener) => void;\n removeEventListener: (type: string, listener: EventListener) => void;\n};\n\n/**\n * External adapter class that can configure a timeline element\n * with musical time, custom label formatting, etc.\n *\n * The controller has no import of any timeline element type.\n * Users create a controller, pass it the component instance,\n * and the controller calls the component's public API.\n */\nexport class TimelineController {\n #host: TimelineHost;\n #config: TimelineControllerConfig;\n #bpm = 120;\n #timeSignatureNumerator = 4;\n #timeSignatureDenominator = 4;\n\n constructor(timeline: TimelineHost, config: TimelineControllerConfig) {\n this.#host = timeline;\n this.#config = config;\n\n // Apply initial configuration\n timeline.min = config.logicalMin;\n timeline.max = config.logicalMax;\n\n if (config.labelFormatter) {\n timeline.formatLabel = config.labelFormatter;\n }\n\n timeline.addEventListener(`track-select`, this.#onTrackSelect as EventListener);\n }\n\n /** Update the tempo (BPM) for musical time calculations. */\n setTempo(bpm: number): void {\n this.#bpm = bpm;\n this.#updateFormatLabel();\n }\n\n /** Update the time signature for musical time calculations. */\n setTimeSignature(numerator: number, denominator: number): void {\n this.#timeSignatureNumerator = numerator;\n this.#timeSignatureDenominator = denominator;\n this.#updateFormatLabel();\n }\n\n /** Set the visible view range on the timeline. */\n setViewRange(range: ViewRange): void {\n this.#host.setViewRange(range);\n }\n\n /** Clean up any resources held by the controller. */\n dispose(): void {\n this.#host.removeEventListener(`track-select`, this.#onTrackSelect as EventListener);\n }\n\n #onTrackSelect = (e: Event): void => {\n const detail = (e as CustomEvent<TimelineTrackSelectDetail>).detail;\n const trackEventIds = this.#host.getTrackEvents(detail.trackKey).map(e => e.id);\n\n if (detail.shiftKey) {\n const current = new Set(this.#host.selectedIds);\n for (const id of trackEventIds) {\n if (current.has(id)) {\n current.delete(id);\n } else {\n current.add(id);\n }\n }\n this.#host.selectedIds = [...current];\n } else {\n this.#host.selectedIds = trackEventIds;\n }\n };\n\n #updateFormatLabel(): void {\n if (this.#config.labelFormatter) {\n // User provided a custom formatter — don't override\n return;\n }\n\n const _bpm = this.#bpm;\n const num = this.#timeSignatureNumerator;\n\n // Musical time formatter: convert logical units to bars:beats\n this.#host.formatLabel = (v: number) => {\n const beatsPerBar = num;\n const totalBeats = v; // Assume 1 logical unit = 1 beat\n const bar = Math.floor(totalBeats / beatsPerBar) + 1;\n const beat = Math.floor(totalBeats % beatsPerBar) + 1;\n return `${bar}.${beat}`;\n };\n }\n}\n","import type { DragTarget, GridMode, GridResolution, TimelineEvent, TrackLayout, UserScale, ViewRange } from './types.js';\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport type CssVars = Record<string, string>;\n\nexport type Rect = {\n x: number;\n y: number;\n width: number;\n height: number;\n};\n\n// ── Grid resolution ───────────────────────────────────────────────────\n\nconst NICE_STEPS = [1, 2, 5, 10];\n\n/**\n * Dispatch to adaptive or fixed grid mode.\n */\nexport function resolveGrid(viewRange: ViewRange, userScale: UserScale, viewportWidth: number, mode: GridMode = `adaptive`, fixedMinorStep?: number, ppu?: number): GridResolution {\n if (mode === `fixed` && fixedMinorStep !== undefined && ppu !== undefined) {\n return resolveFixedGrid(fixedMinorStep, ppu);\n }\n return resolveAdaptiveGrid(viewRange, userScale, viewportWidth);\n}\n\n/**\n * Compute a nice major/minor grid resolution for the current view.\n * Uses a 1-2-5-10 \"nice number\" algorithm.\n */\nfunction resolveAdaptiveGrid(viewRange: ViewRange, userScale: UserScale, viewportWidth: number): GridResolution {\n const span = viewRange.max - viewRange.min;\n if (span <= 0 || viewportWidth <= 0) {\n return { majorStep: 100, minorDivisions: 4, minorStep: 25 };\n }\n\n // Target ~60-120px between major gridlines\n const densityMultiplier = scaleMultiplier(userScale);\n const targetPx = 80 * densityMultiplier;\n const targetMajors = Math.max(2, Math.floor(viewportWidth / targetPx));\n const rawStep = span / targetMajors;\n\n // Find nearest \"nice\" step\n const magnitude = 10 ** Math.floor(Math.log10(rawStep));\n let bestStep = magnitude;\n for (const n of NICE_STEPS) {\n const candidate = n * magnitude;\n if (candidate >= rawStep * 0.8) {\n bestStep = candidate;\n break;\n }\n }\n\n // Minor divisions: 4 for most, 5 for steps of 5/10\n const normalised = bestStep / magnitude;\n const minorDivisions = normalised === 5 || normalised === 10 ? 5 : 4;\n const minorStep = bestStep / minorDivisions;\n\n return { majorStep: bestStep, minorDivisions, minorStep };\n}\n\n/**\n * Fixed grid: user specifies a base minor step in logical units.\n * If the minor step at current zoom would produce lines < 5px apart,\n * double the effective step until they're >= 5px.\n * Major = 4× effective minor.\n */\nfunction resolveFixedGrid(baseMinorStep: number, ppu: number): GridResolution {\n const MIN_PX_BETWEEN = 5;\n let effectiveMinor = baseMinorStep;\n\n // Double until minor gridlines are at least MIN_PX_BETWEEN apart\n while (effectiveMinor * ppu < MIN_PX_BETWEEN && effectiveMinor < 1e12) {\n effectiveMinor *= 2;\n }\n\n const minorDivisions = 4;\n const majorStep = effectiveMinor * minorDivisions;\n return { majorStep, minorDivisions, minorStep: effectiveMinor };\n}\n\nfunction scaleMultiplier(scale: UserScale): number {\n switch (scale) {\n case `x-wide`: return 2.0;\n case `wide`: return 1.5;\n case `normal`: return 1.0;\n case `slim`: return 0.7;\n case `x-slim`: return 0.5;\n default: return 1.0;\n }\n}\n\n// ── Draw: major/minor grid ────────────────────────────────────────────\n\nexport function drawMajorMinorGrid(ctx: CanvasRenderingContext2D, region: Rect, resolution: GridResolution, altMajorBg: boolean, vars: CssVars, ppu: number): void {\n const { majorStep, minorStep } = resolution;\n if (majorStep <= 0)\n return;\n\n const regionEnd = region.x + region.width;\n\n // Draw alternating major background tints\n if (altMajorBg) {\n const altColor = vars[`--timeline-alt-major-bg`] ?? `rgba(255,255,255,0.03)`;\n ctx.fillStyle = altColor;\n const firstMajor = Math.floor(region.x / majorStep);\n for (let i = firstMajor; i * majorStep < regionEnd; i++) {\n if (i % 2 !== 0) {\n const x = i * majorStep * ppu;\n ctx.fillRect(x, region.y, majorStep * ppu, region.height);\n }\n }\n }\n\n // Minor gridlines\n if (minorStep > 0) {\n ctx.strokeStyle = vars[`--timeline-grid-minor-color`] ?? `rgba(255,255,255,0.05)`;\n ctx.lineWidth = Number.parseFloat(vars[`--timeline-grid-minor-width`] ?? `0.5`);\n ctx.beginPath();\n const firstMinor = Math.floor(region.x / minorStep) * minorStep;\n for (let val = firstMinor; val < regionEnd; val += minorStep) {\n // Skip positions that are major gridlines\n if (Math.abs(val % majorStep) < minorStep * 0.01)\n continue;\n const px = val * ppu;\n ctx.moveTo(px, region.y);\n ctx.lineTo(px, region.y + region.height);\n }\n ctx.stroke();\n }\n\n // Major gridlines\n ctx.strokeStyle = vars[`--timeline-grid-major-color`] ?? `rgba(255,255,255,0.12)`;\n ctx.lineWidth = Number.parseFloat(vars[`--timeline-grid-major-width`] ?? `1`);\n ctx.beginPath();\n const firstMajor = Math.floor(region.x / majorStep) * majorStep;\n for (let val = firstMajor; val < regionEnd; val += majorStep) {\n const px = val * ppu;\n ctx.moveTo(px, region.y);\n ctx.lineTo(px, region.y + region.height);\n }\n ctx.stroke();\n}\n\n// ── Draw: axis labels ─────────────────────────────────────────────────\n\n/**\n * Draw the axis header band. With 2D virtualization the axis is \"sticky\" —\n * it is always drawn at the current vertical scroll position (`scrollTop`)\n * so it appears fixed at the viewport top.\n */\nexport function drawAxis(ctx: CanvasRenderingContext2D, region: Rect, resolution: GridResolution, axisHeight: number, formatLabel: (v: number) => string, vars: CssVars, ppu: number, scrollTop = 0): void {\n const { majorStep } = resolution;\n if (majorStep <= 0 || axisHeight <= 0)\n return;\n\n // Axis band occupies [scrollTop, scrollTop + axisHeight] in logical Y\n const axisTop = scrollTop;\n const axisBottom = scrollTop + axisHeight;\n\n // Only draw if this tile's region overlaps the axis band\n if (region.y + region.height < axisTop || region.y > axisBottom)\n return;\n\n const regionEnd = region.x + region.width;\n\n // How far major gridlines extend into the axis band (from the bottom)\n const tickHeight = 6;\n const bgHeight = axisHeight - tickHeight;\n\n // 1. Solid background covers upper portion; leaves bottom strip for gridline ticks.\n const bgColor = vars[`--timeline-bg`] ?? `#111`;\n ctx.fillStyle = bgColor;\n const bgLeft = region.x * ppu;\n ctx.fillRect(bgLeft, axisTop, region.width * ppu, bgHeight);\n\n // 2. Major gridline ticks extending into the axis band\n ctx.strokeStyle = vars[`--timeline-grid-major-color`] ?? `rgba(255,255,255,0.12)`;\n ctx.lineWidth = Number.parseFloat(vars[`--timeline-grid-major-width`] ?? `1`);\n ctx.beginPath();\n const firstMajor = Math.ceil(region.x / majorStep) * majorStep;\n for (let val = firstMajor; val < regionEnd; val += majorStep) {\n const px = val * ppu;\n ctx.moveTo(px, axisTop + bgHeight);\n ctx.lineTo(px, axisBottom);\n }\n ctx.stroke();\n\n // 3. Bottom border\n ctx.strokeStyle = vars[`--timeline-grid-major-color`] ?? `rgba(255,255,255,0.12)`;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(bgLeft, axisBottom);\n ctx.lineTo(bgLeft + region.width * ppu, axisBottom);\n ctx.stroke();\n\n // 4. Labels to the right of each major gridline\n const labelColor = vars[`--timeline-axis-label-color`] ?? `rgba(255,255,255,0.5)`;\n ctx.fillStyle = labelColor;\n ctx.font = `11px system-ui, sans-serif`;\n ctx.textBaseline = `middle`;\n ctx.textAlign = `left`;\n\n const labelPadding = 4;\n for (let val = firstMajor; val < regionEnd; val += majorStep) {\n const px = val * ppu;\n ctx.fillText(formatLabel(val), px + labelPadding, axisTop + bgHeight / 2);\n }\n\n // Reset textAlign for subsequent draw calls\n ctx.textAlign = `start`;\n}\n\n// ── Draw: track backgrounds ───────────────────────────────────────────\n\nexport type TrackInfo = {\n readonly key: string;\n readonly color?: string;\n};\n\nexport function drawTrackBackgrounds(ctx: CanvasRenderingContext2D, region: Rect, trackLayout: readonly TrackLayout[], tracks: readonly TrackInfo[], vars: CssVars, ppu: number): void {\n const bgDefault = vars[`--timeline-track-bg`] ?? `#1a1a1a`;\n const bgAlt = vars[`--timeline-track-bg-alt`] ?? `#1e1e1e`;\n\n for (let i = 0; i < trackLayout.length; i++) {\n const layout = trackLayout[i];\n // Skip if entirely outside the drawn region vertically\n if (layout.y + layout.height < region.y)\n continue;\n if (layout.y > region.y + region.height)\n break;\n\n const track = tracks.find(t => t.key === layout.trackKey);\n const bg = track?.color ? `${track.color}22` : (i % 2 === 0 ? bgDefault : bgAlt);\n\n ctx.fillStyle = bg;\n ctx.fillRect(region.x * ppu, layout.y, region.width * ppu, layout.height);\n\n // Subtle separator line between tracks\n ctx.strokeStyle = vars[`--timeline-grid-major-color`] ?? `rgba(255,255,255,0.12)`;\n ctx.lineWidth = 0.5;\n ctx.beginPath();\n ctx.moveTo(region.x * ppu, layout.y + layout.height);\n ctx.lineTo((region.x + region.width) * ppu, layout.y + layout.height);\n ctx.stroke();\n }\n}\n\n// ── Draw: event rectangles ────────────────────────────────────────────\n\nexport function drawEventRects(ctx: CanvasRenderingContext2D, region: Rect, events: readonly TimelineEvent[], trackLayout: readonly TrackLayout[], selectedIds: ReadonlySet<string>, tickledId: string | undefined, drag: DragTarget, vars: CssVars, ppu: number): void {\n const eventBg = vars[`--timeline-event-bg`] ?? `#3498db`;\n const eventSelectedBg = vars[`--timeline-event-selected-bg`] ?? `#5dade2`;\n const eventTickledBg = vars[`--timeline-event-tickled-bg`] ?? `#444`;\n const eventLabelColor = vars[`--timeline-event-label-color`] ?? `#fff`;\n const radius = Number.parseFloat(vars[`--timeline-event-radius`] ?? `4`);\n\n const regionEnd = region.x + region.width;\n const padding = 3; // vertical padding inside track\n\n for (const evt of events) {\n // Skip events outside horizontal view\n if (evt.end < region.x || evt.start > regionEnd)\n continue;\n\n const layout = trackLayout.find(l => l.trackKey === evt.trackKey);\n if (!layout)\n continue;\n\n // Skip events outside vertical region\n if (layout.y + layout.height < region.y)\n continue;\n if (layout.y > region.y + region.height)\n continue;\n\n // Compute provisional position during drag\n let isDragging = false;\n\n if (drag.kind === `event-move` && drag.eventId === evt.id) {\n isDragging = true;\n } else if (drag.kind === `event-start` && drag.eventId === evt.id) {\n isDragging = true;\n } else if (drag.kind === `event-end` && drag.eventId === evt.id) {\n isDragging = true;\n }\n\n const x = evt.start * ppu;\n const w = (evt.end - evt.start) * ppu;\n const y = layout.y + padding;\n const h = layout.height - padding * 2;\n\n if (w < 1)\n continue;\n\n // Choose fill color\n const isSelected = selectedIds.has(evt.id);\n const isTickled = tickledId === evt.id;\n let fill: string;\n if (isSelected) {\n fill = eventSelectedBg;\n } else if (isTickled) {\n fill = eventTickledBg;\n } else {\n fill = evt.color ?? eventBg;\n }\n\n // Draw rounded rect\n ctx.fillStyle = fill;\n ctx.beginPath();\n drawRoundRect(ctx, x, y, w, h, Math.min(radius, w / 2, h / 2));\n ctx.fill();\n\n // Drag outline\n if (isDragging) {\n ctx.strokeStyle = `#fff`;\n ctx.lineWidth = 1.5;\n ctx.beginPath();\n drawRoundRect(ctx, x, y, w, h, Math.min(radius, w / 2, h / 2));\n ctx.stroke();\n }\n\n // Selection outline\n if (isSelected && !isDragging) {\n ctx.strokeStyle = eventSelectedBg;\n ctx.lineWidth = 1;\n ctx.beginPath();\n drawRoundRect(ctx, x, y, w, h, Math.min(radius, w / 2, h / 2));\n ctx.stroke();\n }\n\n // Label (only if wide enough in pixels)\n if (w >= 40 && evt.label) {\n ctx.fillStyle = eventLabelColor;\n ctx.font = `11px system-ui, sans-serif`;\n ctx.textBaseline = `middle`;\n ctx.save();\n ctx.beginPath();\n ctx.rect(x + 4, y, w - 8, h);\n ctx.clip();\n ctx.fillText(evt.label, x + 6, y + h / 2);\n ctx.restore();\n }\n }\n}\n\n// ── Draw: marquee selection rectangle ─────────────────────────────────\n\nexport function drawMarquee(ctx: CanvasRenderingContext2D, drag: DragTarget, ppu: number): void {\n if (drag.kind !== `marquee`)\n return;\n\n const x1 = Math.min(drag.startLogicalX, drag.currentLogicalX) * ppu;\n const x2 = Math.max(drag.startLogicalX, drag.currentLogicalX) * ppu;\n const y1 = Math.min(drag.startY, drag.currentY);\n const y2 = Math.max(drag.startY, drag.currentY);\n\n ctx.fillStyle = `rgba(100, 150, 255, 0.15)`;\n ctx.fillRect(x1, y1, x2 - x1, y2 - y1);\n\n ctx.strokeStyle = `rgba(100, 150, 255, 0.6)`;\n ctx.lineWidth = 1;\n ctx.strokeRect(x1, y1, x2 - x1, y2 - y1);\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────\n\nfunction drawRoundRect(ctx: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, r: number): void {\n r = Math.max(0, r);\n ctx.moveTo(x + r, y);\n ctx.arcTo(x + w, y, x + w, y + h, r);\n ctx.arcTo(x + w, y + h, x, y + h, r);\n ctx.arcTo(x, y + h, x, y, r);\n ctx.arcTo(x, y, x + w, y, r);\n ctx.closePath();\n}\n\n// ── CSS variable resolution helper ────────────────────────────────────\n\nconst TIMELINE_CSS_VARS = [\n `--timeline-bg`,\n `--timeline-track-bg`,\n `--timeline-track-bg-alt`,\n `--timeline-alt-major-bg`,\n `--timeline-grid-major-color`,\n `--timeline-grid-minor-color`,\n `--timeline-grid-major-width`,\n `--timeline-grid-minor-width`,\n `--timeline-event-bg`,\n `--timeline-event-selected-bg`,\n `--timeline-event-tickled-bg`,\n `--timeline-event-label-color`,\n `--timeline-event-radius`,\n `--timeline-axis-label-color`,\n] as const;\n\nexport function resolveCssVars(host: HTMLElement): CssVars {\n const computed = getComputedStyle(host);\n const vars: CssVars = {};\n for (const v of TIMELINE_CSS_VARS) {\n vars[v] = computed.getPropertyValue(v).trim();\n }\n return vars;\n}\n","import type { IxfxTimelineElement } from './timeline-element.js';\nimport type { GridResolution, TimelineEvent, TimelineEventMoveDetail, TimelineEventResizeDetail, TimelineSelectionChangeDetail, TrackLayout } from './types.js';\nimport { resolveGrid } from './timeline-draw.js';\n\n// Minimal type for the x-vcanvas element\ntype VCanvasElement = HTMLElement & {\n convertFromViewportToCanvas: (x: number, y: number) => { x: number; y: number };\n viewportWidth: number;\n viewportHeight: number;\n logicalScrollTop: number;\n invalidateAll: () => void;\n invalidateRegion: (x: number, y: number, w: number, h: number) => void;\n};\n\n/** Hit zone near the edge of an event (px in screen space) */\nconst EDGE_HIT_PX = 8;\n\n// ── Coordinate conversion ─────────────────────────────────────────────\n\n/**\n * Convert a vcanvas logical (pixel) coordinate to timeline logical units.\n * vcanvas pixel coordinates are in the 1:1 pixel space; divide by ppu then add min.\n */\nfunction canvasToTimeline(canvasX: number, ppu: number, min: number): number {\n return canvasX / ppu + min;\n}\n\n/**\n * Convert screen-space pixel distance to timeline logical units.\n * Used for edge hit threshold: how many logical units does EDGE_HIT_PX correspond to.\n */\nfunction pxToLogicalUnits(ppu: number): number {\n return ppu > 0 ? 1 / ppu : 1;\n}\n\n// ── Hit testing ───────────────────────────────────────────────────────\n\ntype HitResult\n = | { kind: `none` }\n | { kind: `event-move`; eventId: string; trackKey: string; offsetX: number }\n | { kind: `event-start`; eventId: string }\n | { kind: `event-end`; eventId: string }\n | { kind: `empty`; logicalX: number; y: number; trackKey: string | undefined };\n\nfunction hitTest(logicalX: number, y: number, events: readonly TimelineEvent[], trackLayout: readonly TrackLayout[], ppu: number): HitResult {\n // Find which track was clicked\n const track = trackLayout.find(tl => y >= tl.y && y < tl.y + tl.height);\n if (!track) {\n return { kind: `empty`, logicalX, y, trackKey: undefined };\n }\n\n // Edge threshold in logical units\n const edgeThreshold = EDGE_HIT_PX * pxToLogicalUnits(ppu);\n const trackEvents = events.filter(e => e.trackKey === track.trackKey);\n\n for (const evt of trackEvents) {\n if (logicalX < evt.start || logicalX > evt.end)\n continue;\n\n // Within event — check edges\n if (logicalX <= evt.start + edgeThreshold) {\n return { kind: `event-start`, eventId: evt.id };\n }\n if (logicalX >= evt.end - edgeThreshold) {\n return { kind: `event-end`, eventId: evt.id };\n }\n return {\n kind: `event-move`,\n eventId: evt.id,\n trackKey: track.trackKey,\n offsetX: logicalX - evt.start,\n };\n }\n\n return { kind: `empty`, logicalX, y, trackKey: track.trackKey };\n}\n\n// ── Find track at Y position ──────────────────────────────────────────\n\nfunction trackAtY(y: number, trackLayout: readonly TrackLayout[]): string | undefined {\n const track = trackLayout.find(tl => y >= tl.y && y < tl.y + tl.height);\n return track?.trackKey;\n}\n\n// ── Axis zoom helpers ─────────────────────────────────────────────────\n\n/** Sensitivity: how many pixels of vertical drag = 1 e-fold of zoom */\nconst ZOOM_SENSITIVITY_PX = 100;\n\n/** Total pointer movement (px) before an axis drag activates */\nexport const DRAG_ACTIVATION_PX = 5;\n\n/** Per-axis deadzone (px) — small off-axis movement is ignored */\nexport const AXIS_DEADZONE_PX = 4;\n\n/**\n * Subtract a deadzone from a value.\n * Returns 0 if |value| <= deadzone, otherwise value shifted toward zero by deadzone.\n */\nexport function applyDeadzone(value: number, deadzone: number): number {\n return Math.abs(value) > deadzone ? value - Math.sign(value) * deadzone : 0;\n}\n\n/**\n * Compute new ppu + viewMin from an axis-zoom drag.\n * Vertical delta (dy) controls zoom (up = zoom in, down = zoom out), anchored at `anchorUnit`.\n * Horizontal delta (dx) controls pan.\n *\n * Returns { ppu, viewMin } — the caller uses host.setZoomPan() to apply.\n */\nfunction computeAxisZoom(startViewMin: number, startPpu: number, anchorUnit: number, dx: number, dy: number): { ppu: number; viewMin: number } {\n // Zoom: exponential scale factor from vertical drag (drag up = zoom in)\n const zoomFactor = Math.exp(-dy / ZOOM_SENSITIVITY_PX);\n const newPpu = startPpu * zoomFactor;\n\n // Anchor: the anchorUnit should stay at the same fraction of the viewport.\n // At startPpu, its screen position was: (anchorUnit - startViewMin) * startPpu\n // At newPpu, we want the same screen position, so:\n // (anchorUnit - newMin) * newPpu = (anchorUnit - startViewMin) * startPpu\n // newMin = anchorUnit - (anchorUnit - startViewMin) * startPpu / newPpu\n const anchorScreenX = (anchorUnit - startViewMin) * startPpu;\n let newMin = anchorUnit - anchorScreenX / newPpu;\n\n // Pan: horizontal drag shifts the view in screen pixels, convert to timeline units\n if (newPpu > 0) {\n newMin += -dx / newPpu;\n }\n\n // Don't clamp here — host.setZoomPan() handles clamping via #deriveViewRange\n return { ppu: newPpu, viewMin: newMin };\n}\n\n/**\n * Compute new vertical view range from a v-axis-zoom drag.\n * Horizontal delta (dx) controls zoom (right = zoom in, left = zoom out),\n * anchored at `anchorBaseY` (a position in base-height units).\n * Vertical delta (dy) controls pan (drag down = scroll down through tracks).\n *\n * Returns { vMin, vMax } — the caller uses host.setVerticalZoomPan() to apply.\n */\nexport function computeVerticalAxisZoom(startVMin: number, startVMax: number, startVScale: number, anchorBaseY: number, dx: number, dy: number): { vMin: number; vMax: number } {\n const startSpan = startVMax - startVMin;\n\n // Zoom: exponential scale factor from horizontal drag (right = zoom in)\n const zoomFactor = Math.exp(-dx / ZOOM_SENSITIVITY_PX);\n const newSpan = startSpan * zoomFactor;\n\n // Anchor: keep anchorBaseY at the same visual fraction\n const anchorFrac = startSpan > 0\n ? (anchorBaseY - startVMin) / startSpan\n : 0.5;\n let newMin = anchorBaseY - anchorFrac * newSpan;\n\n // Pan: vertical drag shifts the view in screen pixels, convert to base-height units\n if (startVScale > 0) {\n newMin += dy / startVScale;\n }\n\n // Don't clamp here — host.setVerticalZoomPan() handles clamping via #deriveVerticalZoom\n return { vMin: newMin, vMax: newMin + newSpan };\n}\n\n// ── Attach interactions ───────────────────────────────────────────────\n\n/**\n * Attaches pointer and keyboard interaction handlers to the timeline.\n * Returns a cleanup function.\n */\nexport function attachTimelineInteractions(host: IxfxTimelineElement, vcanvasEl: VCanvasElement): (() => void) {\n const ac = new AbortController();\n const signal = ac.signal;\n\n // ── Pointer down on vcanvas ───────────────────────────────────────\n vcanvasEl.addEventListener(`pointerdown`, (e: PointerEvent) => {\n const ppu = host.pxPerUnit;\n const canvasCoord = vcanvasEl.convertFromViewportToCanvas(e.offsetX, e.offsetY);\n // canvasCoord.x is in vcanvas logical space which is pure timeline pixel space\n const lx = canvasToTimeline(canvasCoord.x, ppu, host.min);\n const ly = canvasCoord.y;\n\n // Check if click is in the axis header band → start axis-zoom\n // Axis is \"sticky\" at the current logicalScrollTop\n const axisTop = vcanvasEl.logicalScrollTop;\n if (ly >= axisTop && ly < axisTop + host.axisHeight) {\n vcanvasEl.setPointerCapture(e.pointerId);\n host._drag = {\n kind: `axis-zoom`,\n anchorUnit: lx,\n startScreenX: e.screenX,\n startScreenY: e.screenY,\n startViewMin: host._viewRange.min,\n startPpu: ppu,\n };\n return;\n }\n\n const hit = hitTest(lx, ly, host._internalEvents, host._trackLayout, ppu);\n\n if (e.shiftKey && hit.kind === `event-move`) {\n // SHIFT+click toggles selection\n toggleSelection(host, hit.eventId);\n return;\n }\n\n if (hit.kind === `event-move`) {\n // Start move drag\n vcanvasEl.setPointerCapture(e.pointerId);\n host._drag = {\n kind: `event-move`,\n eventId: hit.eventId,\n originTrackKey: hit.trackKey,\n offsetX: hit.offsetX,\n };\n return;\n }\n\n if (hit.kind === `event-start`) {\n vcanvasEl.setPointerCapture(e.pointerId);\n host._drag = { kind: `event-start`, eventId: hit.eventId };\n return;\n }\n\n if (hit.kind === `event-end`) {\n vcanvasEl.setPointerCapture(e.pointerId);\n host._drag = { kind: `event-end`, eventId: hit.eventId };\n return;\n }\n\n if (hit.kind === `empty`) {\n // Start marquee or clear selection\n vcanvasEl.setPointerCapture(e.pointerId);\n host._drag = {\n kind: `marquee`,\n startLogicalX: lx,\n startY: ly,\n currentLogicalX: lx,\n currentY: ly,\n };\n }\n }, { signal });\n\n // ── Pointer move ──────────────────────────────────────────────────\n vcanvasEl.addEventListener(`pointermove`, (e: PointerEvent) => {\n const drag = host._drag;\n if (drag.kind === `none`) {\n // Tickle (hover) detection\n handleHover(host, vcanvasEl, e);\n return;\n }\n\n const ppu = host.pxPerUnit;\n const canvasCoord = vcanvasEl.convertFromViewportToCanvas(e.offsetX, e.offsetY);\n // canvasCoord.x is in vcanvas logical space which is pure timeline pixel space\n const lx = canvasToTimeline(canvasCoord.x, ppu, host.min);\n const ly = canvasCoord.y;\n\n if (drag.kind === `axis-zoom`) {\n const rawDx = e.screenX - drag.startScreenX;\n const rawDy = e.screenY - drag.startScreenY;\n\n // Activation threshold — don't start until enough total movement\n if (Math.abs(rawDx) + Math.abs(rawDy) < DRAG_ACTIVATION_PX)\n return;\n\n // Per-axis deadzone — ignore small off-axis movement\n const dx = applyDeadzone(rawDx, AXIS_DEADZONE_PX);\n const dy = applyDeadzone(rawDy, AXIS_DEADZONE_PX);\n\n const result = computeAxisZoom(\n drag.startViewMin,\n drag.startPpu,\n drag.anchorUnit,\n dx,\n dy,\n );\n host.setZoomPan(result.viewMin, result.ppu);\n return;\n }\n\n if (drag.kind === `marquee`) {\n host._drag = { ...drag, currentLogicalX: lx, currentY: ly };\n vcanvasEl.invalidateAll();\n return;\n }\n\n if (drag.kind === `event-move`) {\n const evt = host._internalEvents.find(ev => ev.id === drag.eventId);\n if (!evt)\n return;\n const duration = evt.end - evt.start;\n const rawLx = lx;\n const rawLy = ly;\n const newStart = lx - drag.offsetX;\n const newEnd = newStart + duration;\n const newTrackKey = trackAtY(ly, host._trackLayout) ?? evt.trackKey;\n\n const ppu = host.pxPerUnit;\n const grid: GridResolution = resolveGrid(\n host._viewRange,\n host.userScale,\n vcanvasEl.viewportWidth,\n host.gridMode,\n host.minorStep,\n ppu,\n );\n\n const snapped = host.processDrag(\n drag.eventId,\n rawLx,\n rawLy,\n newStart,\n newEnd,\n newTrackKey,\n drag.originTrackKey,\n grid,\n );\n\n host._internalEvents = host._internalEvents.map(ev =>\n ev.id === drag.eventId\n ? { ...ev, start: snapped.start, end: snapped.end, trackKey: snapped.trackKey }\n : ev,\n );\n vcanvasEl.invalidateAll();\n return;\n }\n\n if (drag.kind === `event-start`) {\n const evt = host._internalEvents.find(ev => ev.id === drag.eventId);\n if (!evt)\n return;\n const newStart = Math.min(lx, evt.end - 1);\n host._internalEvents = host._internalEvents.map(ev =>\n ev.id === drag.eventId ? { ...ev, start: newStart } : ev,\n );\n vcanvasEl.invalidateAll();\n return;\n }\n\n if (drag.kind === `event-end`) {\n const evt = host._internalEvents.find(ev => ev.id === drag.eventId);\n if (!evt)\n return;\n const newEnd = Math.max(lx, evt.start + 1);\n host._internalEvents = host._internalEvents.map(ev =>\n ev.id === drag.eventId ? { ...ev, end: newEnd } : ev,\n );\n vcanvasEl.invalidateAll();\n }\n }, { signal });\n\n // ── Pointer up ────────────────────────────────────────────────────\n vcanvasEl.addEventListener(`pointerup`, (e: PointerEvent) => {\n const drag = host._drag;\n vcanvasEl.releasePointerCapture(e.pointerId);\n\n if (drag.kind === `axis-zoom`) {\n // Final zoom/pan is already applied continuously in pointermove\n host._drag = { kind: `none` };\n return;\n }\n\n if (drag.kind === `marquee`) {\n // Compute marquee selection\n const x1 = Math.min(drag.startLogicalX, drag.currentLogicalX);\n const x2 = Math.max(drag.startLogicalX, drag.currentLogicalX);\n const y1 = Math.min(drag.startY, drag.currentY);\n const y2 = Math.max(drag.startY, drag.currentY);\n\n // Check if it was just a click (no drag distance)\n if (Math.abs(x2 - x1) < 2 && Math.abs(y2 - y1) < 2) {\n // Click on empty space — clear selection\n host._selectedIds = new Set();\n fireSelectionChange(host);\n } else {\n // Select events intersecting the marquee\n const selected = new Set<string>();\n for (const evt of host._internalEvents) {\n const layout = host._trackLayout.find(l => l.trackKey === evt.trackKey);\n if (!layout)\n continue;\n const evtTop = layout.y + 3;\n const evtBottom = layout.y + layout.height - 3;\n\n // Intersection test\n if (evt.end >= x1 && evt.start <= x2 && evtBottom >= y1 && evtTop <= y2) {\n selected.add(evt.id);\n }\n }\n host._selectedIds = selected;\n fireSelectionChange(host);\n }\n\n host._drag = { kind: `none` };\n vcanvasEl.invalidateAll();\n return;\n }\n\n if (drag.kind === `event-move`) {\n const evt = host._internalEvents.find(ev => ev.id === drag.eventId);\n if (evt) {\n host.dispatchEvent(\n new CustomEvent<TimelineEventMoveDetail>(`event-move`, {\n detail: {\n eventId: evt.id,\n fromTrackKey: drag.originTrackKey,\n toTrackKey: evt.trackKey,\n start: evt.start,\n end: evt.end,\n },\n bubbles: true,\n composed: true,\n }),\n );\n }\n host._drag = { kind: `none` };\n return;\n }\n\n if (drag.kind === `event-start` || drag.kind === `event-end`) {\n const evt = host._internalEvents.find(ev => ev.id === drag.eventId);\n if (evt) {\n host.dispatchEvent(\n new CustomEvent<TimelineEventResizeDetail>(`event-resize`, {\n detail: {\n eventId: evt.id,\n start: evt.start,\n end: evt.end,\n },\n bubbles: true,\n composed: true,\n }),\n );\n }\n host._drag = { kind: `none` };\n return;\n }\n\n host._drag = { kind: `none` };\n }, { signal });\n\n // ── Pointer leave (clear tickle) ──────────────────────────────────\n vcanvasEl.addEventListener(`pointerleave`, () => {\n if (host._tickledId !== undefined) {\n host._tickledId = undefined;\n vcanvasEl.invalidateAll();\n }\n }, { signal });\n\n return () => ac.abort();\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────\n\nfunction handleHover(host: IxfxTimelineElement, vcanvasEl: VCanvasElement, e: PointerEvent): void {\n const ppu = host.pxPerUnit;\n const canvasCoord = vcanvasEl.convertFromViewportToCanvas(e.offsetX, e.offsetY);\n // canvasCoord.x is in vcanvas logical space which is pure timeline pixel space\n const lx = canvasToTimeline(canvasCoord.x, ppu, host.min);\n const ly = canvasCoord.y;\n\n // Axis band: show appropriate cursor (sticky at logicalScrollTop)\n const axisTop = vcanvasEl.logicalScrollTop;\n if (ly >= axisTop && ly < axisTop + host.axisHeight) {\n vcanvasEl.style.cursor = `col-resize`;\n // Clear tickle if any\n if (host._tickledId !== undefined) {\n host._tickledId = undefined;\n vcanvasEl.invalidateAll();\n }\n return;\n }\n\n const hit = hitTest(lx, ly, host._internalEvents, host._trackLayout, ppu);\n\n let newTickledId: string | undefined;\n if (hit.kind === `event-move` || hit.kind === `event-start` || hit.kind === `event-end`) {\n newTickledId = hit.eventId;\n }\n\n // Update cursor\n if (hit.kind === `event-start` || hit.kind === `event-end`) {\n vcanvasEl.style.cursor = `ew-resize`;\n } else if (hit.kind === `event-move`) {\n vcanvasEl.style.cursor = `grab`;\n } else {\n vcanvasEl.style.cursor = `crosshair`;\n }\n\n if (newTickledId !== host._tickledId) {\n host._tickledId = newTickledId;\n vcanvasEl.invalidateAll();\n }\n}\n\nfunction toggleSelection(host: IxfxTimelineElement, eventId: string): void {\n const next = new Set(host._selectedIds);\n if (next.has(eventId)) {\n next.delete(eventId);\n } else {\n next.add(eventId);\n }\n host._selectedIds = next;\n fireSelectionChange(host);\n host.getVCanvas()?.invalidateAll();\n}\n\nfunction fireSelectionChange(host: IxfxTimelineElement): void {\n host.dispatchEvent(\n new CustomEvent<TimelineSelectionChangeDetail>(`selection-change`, {\n detail: { selectedIds: [...host._selectedIds] },\n bubbles: true,\n composed: true,\n }),\n );\n}\n","import { css } from 'lit';\n\nexport const timelineStyles = css`\n :host {\n /* Layout */\n --timeline-axis-height: 24px;\n --timeline-tab-width: 120px;\n\n /* Backgrounds */\n --timeline-bg: var(--content, #111);\n --timeline-track-bg: var(--surface-2);\n --timeline-track-bg-alt: var(--surface-3);\n --timeline-alt-major-bg: color-mix(in oklch, var(--surface-3) 40%, transparent);\n --timeline-meta-bg: var(--surface-2);\n\n /* Grid */\n --timeline-grid-major-color: var(--surface-5);\n --timeline-grid-minor-color: var(--surface-4);\n --timeline-grid-major-width: 1px;\n --timeline-grid-minor-width: 0.5px;\n\n /* Events */\n --timeline-event-bg: var(--accent);\n --timeline-event-selected-bg: color-mix(in oklch, var(--accent) 80%, white);\n --timeline-event-tickled-bg: var(--surface-6);\n --timeline-event-label-color: var(--accent-text);\n --timeline-event-radius: var(--radius-s, 4px);\n\n /* Tabs */\n --timeline-tab-bg: var(--surface-3);\n --timeline-tab-text: var(--surface-3-text);\n --timeline-tab-selected-bg: var(--accent);\n\n /* Axis */\n --timeline-axis-label-color: var(--surface-muted-text);\n\n /* Resizer */\n --timeline-resizer-color: var(--surface-5);\n\n display: grid;\n grid-template-rows: 1fr auto auto auto;\n background: var(--timeline-bg);\n overflow: hidden;\n position: relative;\n }\n\n /* ── Content wrapper ───────────────────────────────────────────────── */\n\n .content-wrapper {\n display: grid;\n grid-template-columns: 1fr auto;\n overflow: hidden;\n min-height: 0;\n }\n\n /* ── Vertical zoom (right sidebar) ─────────────────────────────────── */\n\n .v-zoom {\n padding: 6px 4px;\n padding-top: var(--timeline-axis-height);\n display: flex;\n align-items: stretch;\n width: 30px;\n box-sizing: content-box;\n }\n\n .v-zoom ixfx-range-multi {\n height: 100%;\n width: 100%;\n }\n\n /* ── Content area ──────────────────────────────────────────────────── */\n\n .content-area {\n position: relative;\n display: grid;\n grid-template-columns: var(--timeline-tab-width) 1fr;\n overflow: hidden;\n min-height: 0;\n }\n\n /* ── Tab column (sits beside vcanvas) ────────────────────────────── */\n\n .tab-column {\n position: relative;\n overflow: hidden;\n z-index: 2;\n }\n\n .tab-column ixfx-timeline-track-tab {\n position: absolute;\n left: 0;\n width: 100%;\n box-sizing: border-box;\n pointer-events: auto;\n }\n\n /* ── Vertical axis interaction zone ─────────────────────────────────── */\n\n .v-axis-zone {\n position: absolute;\n top: 0;\n left: 0;\n width: var(--timeline-tab-width);\n height: 100%;\n cursor: ns-resize;\n z-index: 3;\n }\n\n /* ── VCanvas ───────────────────────────────────────────────────────── */\n\n .content-area x-vcanvas {\n width: 100%;\n height: 100%;\n display: block;\n --scrollbar-width: none;\n }\n\n /* ── Horizontal zoom ───────────────────────────────────────────────── */\n\n .h-zoom {\n padding: 4px 8px;\n padding-left: var(--timeline-tab-width);\n padding-right: 38px; /* align with v-zoom column (30px + 2×4px padding) */\n }\n\n .h-zoom ixfx-range-multi {\n width: 100%;\n }\n\n /* ── Meta area ─────────────────────────────────────────────────────── */\n\n .meta-resizer {\n display: none;\n height: 6px;\n cursor: ns-resize;\n background: var(--timeline-resizer-color);\n }\n\n .meta-resizer.visible {\n display: block;\n }\n\n .meta-area {\n display: none;\n background: var(--timeline-meta-bg);\n overflow: hidden;\n }\n\n .meta-area.visible {\n display: block;\n }\n`;\n","import type { TimelineTrackResizeDetail } from './types.js';\nimport { css, html, LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { handleStyles } from '../styles/handle.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\n\n/** Minimum track height in px */\nconst MIN_TRACK_HEIGHT = 24;\n\n/** How close to the bottom edge the pointer must be (px) to trigger resize */\nconst EDGE_ZONE_PX = 6;\n\n/**\n * A single track tab in the timeline's left margin.\n * Displays the track label, optional drag handle for reordering,\n * and handles vertical resize via bottom-edge drag.\n *\n * Fires:\n * - `track-resize-move` (composed, bubbles) — live preview during drag\n * - `track-resize` (composed, bubbles) — final value on pointerup\n *\n * Both carry `TimelineTrackResizeDetail` in their `detail`.\n */\n@customElement(`ixfx-timeline-track-tab`)\nexport class TimelineTrackTabElement extends LitElement {\n static override styles = [themeFallbacks, handleStyles, css`\n :host {\n display: flex;\n align-items: center;\n background: color-mix(in oklch, var(--timeline-tab-bg, #2a2a2a) 70%, transparent);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n color: var(--timeline-tab-text, #ccc);\n font-size: 0.75rem;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n cursor: pointer;\n user-select: none;\n border-bottom: 1px solid var(--timeline-grid-major-color, rgba(255,255,255,0.12));\n box-sizing: border-box;\n position: relative;\n }\n\n :host([selected]) {\n background: color-mix(in oklch, var(--timeline-tab-selected-bg, #3498db) 75%, transparent);\n color: white;\n }\n\n .handle {\n display: none;\n cursor: grab;\n margin: 0 4px;\n --ixfx-handle-spot-size: 12px;\n --ixfx-handle-dot-size: 3px;\n }\n\n :host([reorderable]) .handle {\n display: inline-block;\n }\n\n .label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n padding: 0 8px;\n }\n `];\n\n @property({ type: String }) label = ``;\n @property({ type: String, attribute: `track-key` }) trackKey = ``;\n @property({ type: Boolean, reflect: true }) selected = false;\n @property({ type: Boolean, reflect: true }) reorderable = false;\n @property({ type: Boolean, reflect: true }) resizable = false;\n\n // ── Private drag state (not reactive — no re-render needed) ─────────\n #dragging = false;\n #startScreenY = 0;\n #startHeight = 0;\n #pointerId: number | undefined = undefined;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener(`pointermove`, this.#onPointerMove);\n this.addEventListener(`pointerdown`, this.#onPointerDown);\n this.addEventListener(`pointerup`, this.#onPointerUp);\n this.addEventListener(`pointercancel`, this.#onPointerCancel);\n this.addEventListener(`lostpointercapture`, this.#onPointerCancel);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener(`pointermove`, this.#onPointerMove);\n this.removeEventListener(`pointerdown`, this.#onPointerDown);\n this.removeEventListener(`pointerup`, this.#onPointerUp);\n this.removeEventListener(`pointercancel`, this.#onPointerCancel);\n this.removeEventListener(`lostpointercapture`, this.#onPointerCancel);\n this.#dragging = false;\n }\n\n protected override render() {\n return html`\n <span class=\"handle ixfx-handle\" data-handle=\"dotted\" data-shape=\"spot\" part=\"handle\"></span>\n <span class=\"label\">${this.label}</span>\n `;\n }\n\n // ── Helpers ──────────────────────────────────────────────────────────\n\n /** Is the pointer within the bottom edge zone? */\n #isInResizeZone(e: PointerEvent): boolean {\n if (!this.resizable)\n return false;\n const rect = this.getBoundingClientRect();\n return e.clientY >= rect.bottom - EDGE_ZONE_PX;\n }\n\n #fireResizeEvent(eventName: string, height: number): void {\n this.dispatchEvent(\n new CustomEvent<TimelineTrackResizeDetail>(eventName, {\n detail: { trackKey: this.trackKey, height },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n // ── Pointer handlers ────────────────────────────────────────────────\n\n #onPointerMove = (e: PointerEvent): void => {\n if (this.#dragging) {\n // During drag: compute new height from delta\n const dy = e.screenY - this.#startScreenY;\n const newHeight = Math.max(MIN_TRACK_HEIGHT, this.#startHeight + dy);\n this.#fireResizeEvent(`track-resize-move`, newHeight);\n return;\n }\n\n // Hover: show ns-resize cursor when near bottom edge\n if (this.#isInResizeZone(e)) {\n this.style.cursor = `ns-resize`;\n } else {\n this.style.cursor = ``;\n }\n };\n\n #onPointerDown = (e: PointerEvent): void => {\n if (!this.#isInResizeZone(e))\n return;\n\n // Prevent the click handler on the parent from firing (track-select)\n e.stopPropagation();\n e.preventDefault();\n\n this.#dragging = true;\n this.#startScreenY = e.screenY;\n this.#startHeight = this.offsetHeight;\n this.#pointerId = e.pointerId;\n this.setPointerCapture(e.pointerId);\n };\n\n #onPointerUp = (e: PointerEvent): void => {\n if (!this.#dragging)\n return;\n\n const dy = e.screenY - this.#startScreenY;\n const finalHeight = Math.max(MIN_TRACK_HEIGHT, this.#startHeight + dy);\n\n this.#fireResizeEvent(`track-resize`, finalHeight);\n this.#resetDrag(e.pointerId);\n };\n\n #onPointerCancel = (_e: Event): void => {\n if (!this.#dragging)\n return;\n this.#resetDrag(this.#pointerId);\n };\n\n #resetDrag(pointerId?: number): void {\n this.#dragging = false;\n this.#startScreenY = 0;\n this.#startHeight = 0;\n if (pointerId !== undefined) {\n try {\n this.releasePointerCapture(pointerId);\n } catch { /* already released */ }\n }\n this.#pointerId = undefined;\n this.style.cursor = ``;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-timeline-track-tab': TimelineTrackTabElement;\n }\n}\n","/* eslint-disable ts/no-unsafe-declaration-merging */\nimport type { PropertyValues } from 'lit';\nimport type { CssVars, Rect } from './timeline-draw.js';\nimport type {\n DragSnappingFn,\n DragTarget,\n GridMode,\n GridResolution,\n TimelineElementEventMap,\n TimelineEvent,\n TimelineSelectionChangeDetail,\n TimelineTickleChangeDetail,\n TimelineTrack,\n TimelineTrackResizeDetail,\n TimelineTrackSelectDetail,\n TrackHeightMode,\n TrackLayout,\n UserScale,\n ViewRange,\n} from './types.js';\nimport { html, LitElement, nothing } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\nimport {\n drawAxis,\n drawEventRects,\n drawMajorMinorGrid,\n drawMarquee,\n drawTrackBackgrounds,\n resolveCssVars,\n resolveGrid,\n} from './timeline-draw.js';\nimport { applyDeadzone, attachTimelineInteractions, AXIS_DEADZONE_PX, computeVerticalAxisZoom, DRAG_ACTIVATION_PX } from './timeline-interactions.js';\nimport { timelineStyles } from './timeline-styles.js';\nimport './timeline-track-tabs.js';\n\nimport '@clinth/vcanvas';\n\n// Minimal type for the x-vcanvas element we need\ntype VCanvasElement = HTMLElement & {\n logicalWidth: number;\n logicalHeight: number;\n logicalScrollLeft: number;\n logicalScrollTop: number;\n viewportWidth: number;\n viewportHeight: number;\n drawCallback: ((ctx: CanvasRenderingContext2D, region: Rect, signal: AbortSignal) => void) | null;\n invalidateAll: () => void;\n invalidateRegion: (x: number, y: number, w: number, h: number) => void;\n convertFromViewportToCanvas: (x: number, y: number) => { x: number; y: number };\n convertFromCanvasToViewport: (x: number, y: number) => { x: number; y: number };\n};\n\n/** Reasonable maximum ppu to prevent infinite zoom-in */\nconst MAX_PPU = 10_000;\n\n/** Minimum rendered track height (~1.5em) at max zoom-out */\nconst MIN_TRACK_RENDER_HEIGHT = 24;\n\n@customElement(`ixfx-timeline`)\nexport class IxfxTimelineElement extends LitElement {\n static override styles = [timelineStyles];\n\n // ── Public properties ───────────────────────────────────────────────\n @property({ type: Array }) tracks: TimelineTrack[] = [];\n @property({ type: Array }) events: TimelineEvent[] = [];\n @property({ type: Number }) min = 0;\n @property({ type: Number }) max = 1000;\n @property({ type: String, attribute: `track-height` }) trackHeight: TrackHeightMode = `fixed`;\n @property({ type: String, attribute: `user-scale` }) userScale: UserScale = `normal`;\n @property({ type: Boolean }) reorderable = false;\n @property({ type: Boolean, attribute: `meta` }) metaEnabled = false;\n @property({ type: Boolean, attribute: `alt-major-bg` }) altMajorBg = false;\n @property({ type: Number, attribute: `default-track-height` }) defaultTrackHeight = 48;\n @property({ type: String, attribute: `grid-mode` }) gridMode: GridMode = `adaptive`;\n @property({ type: Number, attribute: `minor-step` }) minorStep = 10;\n @property({ type: Object }) onDragging: DragSnappingFn | null = null;\n\n /** Set by TimelineController — formats logical value to label string */\n formatLabel: (v: number) => string = String;\n\n // ── Internal state ──────────────────────────────────────────────────\n /**\n * _ppu (pixels per unit) is the PRIMARY horizontal zoom state.\n * _viewRange.min is the PRIMARY horizontal pan state.\n * _viewRange.max is DERIVED: min + viewportWidth / _ppu.\n */\n @state() _ppu = 1;\n @state() _viewRange: ViewRange = { min: 0, max: 4000 };\n\n /**\n * Vertical zoom/pan state. Analogous to horizontal:\n * - _vViewRange is in \"base height units\" (pre-scale track pixels).\n * - _vScale = viewportHeight / (b - a). When range spans all base height, all tracks fit.\n * - _vScrollOffset = _vViewRange.min * _vScale — the pixel offset applied to content.\n */\n @state() _vViewRange: ViewRange = { min: 0, max: 1 };\n @state() _vScale = 1.0;\n\n @state() _selectedIds: Set<string> = new Set();\n @state() _tickledId: string | undefined = undefined;\n @state() _drag: DragTarget = { kind: `none` };\n @state() _metaHeight = 120;\n @state() _trackHeightOverrides: Map<string, number> = new Map();\n @state() _trackLayout: TrackLayout[] = [];\n @state() _internalEvents: TimelineEvent[] = [];\n @state() _internalTracks: TimelineTrack[] = [];\n\n // ── Private refs ────────────────────────────────────────────────────\n #vcanvas: VCanvasElement | null = null;\n #cssVarsCache: CssVars = {};\n #cleanupInteractions: (() => void) | null = null;\n #axisHeight = 24;\n #prevTickledId: string | undefined = undefined;\n #resizeObserver: ResizeObserver | null = null;\n #pendingVerticalZoomToFit = false;\n #hasInitializedZoom = false;\n\n // ── Computed getters (for interactions module) ──────────────────────\n\n /** Pixels per logical unit — the zoom level */\n get pxPerUnit(): number {\n return this._ppu;\n }\n\n /** Height of the axis header band in pixels */\n get axisHeight(): number {\n return this.#axisHeight;\n }\n\n /** Width of the track tab area in pixels (from --timeline-tab-width CSS var) */\n get tabWidth(): number {\n return this.#tabWidth;\n }\n\n // ── Viewport helpers ────────────────────────────────────────────────\n\n #getViewportWidth(): number {\n const raw = this.#vcanvas?.viewportWidth\n ?? (this.#vcanvas as HTMLElement | null)?.clientWidth\n ?? 800;\n return raw;\n }\n\n /** Minimum ppu: fits the full total range into the viewport */\n #minPpu(): number {\n const totalSpan = this.max - this.min;\n if (totalSpan <= 0)\n return 1;\n const vpWidth = this.#getViewportWidth();\n return vpWidth / totalSpan;\n }\n\n // ── Vertical viewport helpers ───────────────────────────────────────\n\n /** Available vertical pixels for track content (excludes axis) */\n #getViewportHeight(): number {\n return this.#vcanvas?.viewportHeight\n ?? (this.#vcanvas as HTMLElement | null)?.clientHeight\n ?? 300;\n }\n\n /**\n * Total base height: sum of all visible track base heights (before vScale).\n * This is the \"total range\" for the vertical slider.\n */\n #getTotalBaseHeight(): number {\n let total = 0;\n for (const track of this._internalTracks) {\n if (track.hidden)\n continue;\n const override = this._trackHeightOverrides.get(track.key);\n total += override ?? track.height ?? this.defaultTrackHeight;\n }\n return total || 1; // avoid zero\n }\n\n /** Smallest base height among visible tracks (before vScale) */\n #getSmallestBaseTrackHeight(): number {\n let smallest = Infinity;\n for (const track of this._internalTracks) {\n if (track.hidden)\n continue;\n const override = this._trackHeightOverrides.get(track.key);\n const h = override ?? track.height ?? this.defaultTrackHeight;\n if (h < smallest)\n smallest = h;\n }\n return smallest === Infinity ? this.defaultTrackHeight : smallest;\n }\n\n /** Largest base height among visible tracks (before vScale) */\n #getLargestBaseTrackHeight(): number {\n let largest = 0;\n for (const track of this._internalTracks) {\n if (track.hidden)\n continue;\n const override = this._trackHeightOverrides.get(track.key);\n const h = override ?? track.height ?? this.defaultTrackHeight;\n if (h > largest)\n largest = h;\n }\n return largest || this.defaultTrackHeight;\n }\n\n /**\n * Derive vScale and vViewRange from a given vertical view range.\n * viewportHeight / span = scale factor applied to base track heights.\n * The axis header takes up fixed space, so available height for tracks is reduced.\n */\n #deriveVerticalZoom(vMin: number, vMax: number): void {\n const totalBase = this.#getTotalBaseHeight();\n const vpHeight = this.#getViewportHeight() - this.#axisHeight;\n\n // Clamp range to [0, totalBase]\n let a = vMin;\n let b = vMax;\n\n // Min span (max zoom-in): largest visible track fills the viewport\n const largestBase = this.#getLargestBaseTrackHeight();\n const minSpan = Math.max(largestBase, totalBase * 0.05);\n\n // Max span (max zoom-out): smallest visible track must not shrink below MIN_TRACK_RENDER_HEIGHT\n // Since renderedHeight = baseHeight * vScale and vScale = vpHeight / span,\n // we need: smallestBase * (vpHeight / span) >= MIN_TRACK_RENDER_HEIGHT\n // → span <= vpHeight * smallestBase / MIN_TRACK_RENDER_HEIGHT\n const smallestBase = this.#getSmallestBaseTrackHeight();\n const maxSpanFromMinHeight = vpHeight > 0\n ? vpHeight * smallestBase / MIN_TRACK_RENDER_HEIGHT\n : totalBase;\n const maxSpan = Math.min(totalBase, maxSpanFromMinHeight);\n\n let span = b - a;\n if (span < minSpan) {\n const center = (a + b) / 2;\n a = center - minSpan / 2;\n b = center + minSpan / 2;\n span = minSpan;\n }\n if (span > maxSpan) {\n const center = (a + b) / 2;\n a = center - maxSpan / 2;\n b = center + maxSpan / 2;\n span = maxSpan;\n }\n\n if (b > totalBase) {\n b = totalBase;\n a = Math.max(0, b - span);\n }\n if (a < 0) {\n a = 0;\n b = Math.min(totalBase, a + span);\n }\n\n this._vViewRange = { min: a, max: b };\n this._vScale = vpHeight > 0 ? vpHeight / (b - a) : 1;\n }\n\n /** Reset vertical zoom to fit all tracks */\n #initVerticalZoomToFit(): void {\n const totalBase = this.#getTotalBaseHeight();\n this.#deriveVerticalZoom(0, totalBase);\n }\n\n /** Pixel offset to scroll the content area */\n get #vScrollOffset(): number {\n return this._vViewRange.min * this._vScale;\n }\n\n /**\n * Derive viewRange from ppu + viewMin, clamped to [min, max].\n * Returns a new ViewRange.\n */\n #deriveViewRange(viewMin: number, ppu: number): ViewRange {\n const vpWidth = this.#getViewportWidth();\n const viewSpan = ppu > 0 ? vpWidth / ppu : (this.max - this.min);\n let newMin = viewMin;\n let newMax = newMin + viewSpan;\n\n // Clamp: don't let max exceed total max\n if (newMax > this.max) {\n newMax = this.max;\n newMin = Math.max(this.min, newMax - viewSpan);\n }\n // Clamp: don't let min go below total min\n if (newMin < this.min) {\n newMin = this.min;\n newMax = Math.min(this.max, newMin + viewSpan);\n }\n\n return { min: newMin, max: newMax };\n }\n\n // ── Public methods: zoom & pan ──────────────────────────────────────\n\n /** Set the zoom level (pixels per logical unit) */\n setPpu(ppu: number): void {\n this._ppu = Math.max(this.#minPpu(), Math.min(ppu, MAX_PPU));\n this._viewRange = this.#deriveViewRange(this._viewRange.min, this._ppu);\n }\n\n /**\n * Set the view range. ppu is back-computed from the span.\n * Use for programmatic view changes (e.g. TimelineController).\n */\n setViewRange(range: ViewRange): void {\n const vpWidth = this.#getViewportWidth();\n const span = range.max - range.min;\n if (span > 0) {\n this._ppu = Math.max(this.#minPpu(), Math.min(vpWidth / span, MAX_PPU));\n }\n this._viewRange = this.#deriveViewRange(range.min, this._ppu);\n }\n\n /**\n * Set zoom + pan atomically. Used by axis-zoom interaction.\n * viewMin is the left edge in timeline units; ppu is the new zoom level.\n */\n setZoomPan(viewMin: number, ppu: number): void {\n this._ppu = Math.max(this.#minPpu(), Math.min(ppu, MAX_PPU));\n this._viewRange = this.#deriveViewRange(viewMin, this._ppu);\n }\n\n /**\n * Set vertical zoom + pan atomically. Used by v-axis-zoom interaction.\n * vMin/vMax define the vertical view range in base-height units.\n */\n setVerticalZoomPan(vMin: number, vMax: number): void {\n this.#deriveVerticalZoom(vMin, vMax);\n }\n\n selectAll(): void {\n this._selectedIds = new Set(this._internalEvents.map(e => e.id));\n this.#fireSelectionChange();\n this.#invalidateCanvas();\n }\n\n deselectAll(): void {\n this._selectedIds = new Set();\n this.#fireSelectionChange();\n this.#invalidateCanvas();\n }\n\n getTrackEvents(trackKey: string): TimelineEvent[] {\n return this._internalEvents.filter(e => e.trackKey === trackKey);\n }\n\n get selectedIds(): readonly string[] {\n return [...this._selectedIds];\n }\n\n set selectedIds(ids: readonly string[]) {\n this._selectedIds = new Set(ids);\n this.#fireSelectionChange();\n this.#invalidateCanvas();\n }\n\n selectTrack(key: string, shiftKey: boolean = false): void {\n this.dispatchEvent(\n new CustomEvent<TimelineTrackSelectDetail>(`track-select`, {\n detail: { trackKey: key, shiftKey },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /** Resets all track height overrides to the default height and resets vertical zoom. */\n resetTrackHeights(): void {\n this._trackHeightOverrides = new Map();\n this.#pendingVerticalZoomToFit = true;\n // willUpdate will see the flag and reset vertical zoom during the same update cycle\n }\n\n /** Default no-op snapping - no modification of drag values */\n static defaultDragSnapping: DragSnappingFn = () => ({});\n\n /** Grid-snapping - snaps start/end to nearest minor gridline */\n static gridSnapping: DragSnappingFn = (detail) => {\n const { gridResolution, currentStart, currentEnd } = detail;\n const { minorStep } = gridResolution;\n return {\n start: Math.round(currentStart / minorStep) * minorStep,\n end: Math.round(currentEnd / minorStep) * minorStep,\n };\n };\n\n /**\n * Called by timeline-interactions during drag.\n * Applies onDragging callback if set, then fires 'dragging' event.\n * Returns constrained values.\n */\n processDrag(\n eventId: string,\n rawLogicalX: number,\n rawY: number,\n currentStart: number,\n currentEnd: number,\n currentTrackKey: string,\n originTrackKey: string,\n gridResolution: GridResolution,\n ): { start: number; end: number; trackKey: string } {\n let constrainedStart = currentStart;\n let constrainedEnd = currentEnd;\n let constrainedTrackKey = currentTrackKey;\n\n if (this.onDragging) {\n const result = this.onDragging({\n eventId,\n rawLogicalX,\n rawY,\n currentStart,\n currentEnd,\n currentTrackKey,\n gridResolution,\n originTrackKey,\n });\n constrainedStart = result.start ?? currentStart;\n constrainedEnd = result.end ?? currentEnd;\n constrainedTrackKey = result.trackKey ?? currentTrackKey;\n }\n\n this.dispatchEvent(\n new CustomEvent(`dragging`, {\n detail: {\n eventId,\n start: constrainedStart,\n end: constrainedEnd,\n trackKey: constrainedTrackKey,\n rawLogicalX,\n rawY,\n originTrackKey,\n },\n bubbles: true,\n composed: true,\n }),\n );\n\n return {\n start: constrainedStart,\n end: constrainedEnd,\n trackKey: constrainedTrackKey,\n };\n }\n\n /** Returns the vcanvas element (for timeline-interactions) */\n getVCanvas(): VCanvasElement | null {\n return this.#vcanvas;\n }\n\n /** Returns the currently hovered (tickled) event, or null if none. */\n get tickledEvent(): TimelineEvent | null {\n if (this._tickledId === undefined)\n return null;\n return this._internalEvents.find(e => e.id === this._tickledId) ?? null;\n }\n\n // ── Lifecycle ───────────────────────────────────────────────────────\n\n protected override firstUpdated(): void {\n this.#vcanvas = this.shadowRoot?.querySelector(`x-vcanvas`) as VCanvasElement | null;\n\n if (this.#vcanvas) {\n this.#vcanvas.drawCallback = this.#drawCallback;\n this.#vcanvas.addEventListener(`scroll-virtual`, this.#onScrollVirtual as EventListener);\n this.#cleanupInteractions = attachTimelineInteractions(this, this.#vcanvas);\n\n // Watch for viewport resizes — adjust viewRange.max, keep ppu stable.\n // The observer fires immediately with the initial size, which handles\n // the initial zoom-to-fit without setting state in firstUpdated.\n this.#resizeObserver = new ResizeObserver(this.#onResize);\n this.#resizeObserver.observe(this.#vcanvas);\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#cleanupInteractions?.();\n this.#cleanupInteractions = null;\n this.#resizeObserver?.disconnect();\n this.#resizeObserver = null;\n }\n\n /**\n * willUpdate runs before render — safe to set @state() properties here\n * without triggering an additional update cycle. All state derivation\n * (internal copies, track layout, vertical zoom) happens here.\n */\n protected override willUpdate(changedProps: PropertyValues): void {\n // Sync external tracks/events into internal managed copies on shallow change\n let needsLayoutRecompute = false;\n let needsVerticalZoomReset = false;\n let needsHorizontalZoomToFit = false;\n\n if (changedProps.has(`tracks`)) {\n this._internalTracks = [...this.tracks];\n needsLayoutRecompute = true;\n needsVerticalZoomReset = true;\n }\n if (changedProps.has(`events`)) {\n this._internalEvents = [...this.events];\n }\n if (changedProps.has(`trackHeight`)) {\n // Mode changed — clear per-track overrides when leaving 'free' mode\n if (this.trackHeight !== `free` && this._trackHeightOverrides.size > 0) {\n this._trackHeightOverrides = new Map();\n }\n needsLayoutRecompute = true;\n needsVerticalZoomReset = true;\n }\n if (changedProps.has(`_vScale`) || changedProps.has(`defaultTrackHeight`) || changedProps.has(`_trackHeightOverrides`)) {\n needsLayoutRecompute = true;\n }\n if (changedProps.has(`min`) || changedProps.has(`max`)) {\n needsHorizontalZoomToFit = true;\n }\n\n // Consume pending zoom-to-fit flag (from resetTrackHeights)\n if (this.#pendingVerticalZoomToFit) {\n this.#pendingVerticalZoomToFit = false;\n needsVerticalZoomReset = true;\n }\n\n // Horizontal zoom-to-fit when total range changes\n if (needsHorizontalZoomToFit) {\n this.#initZoomToFit();\n }\n // Vertical zoom reset must happen BEFORE layout recompute (layout uses _vScale)\n if (needsVerticalZoomReset) {\n this.#initVerticalZoomToFit();\n }\n if (needsLayoutRecompute) {\n this.#recomputeTrackLayout();\n }\n }\n\n /**\n * updated runs after render — for DOM side-effects only (syncing vcanvas,\n * scrolling, invalidating canvas, dispatching events).\n */\n protected override updated(changedProps: PropertyValues): void {\n if (changedProps.has(`_ppu`) || changedProps.has(`_viewRange`) || changedProps.has(`min`) || changedProps.has(`max`)) {\n this.#syncVCanvas();\n this.#invalidateCanvas();\n }\n if (changedProps.has(`events`) || changedProps.has(`userScale`) || changedProps.has(`altMajorBg`) || changedProps.has(`gridMode`) || changedProps.has(`minorStep`)) {\n this.#invalidateCanvas();\n }\n if (changedProps.has(`_trackLayout`)) {\n this.#syncVCanvasVertical();\n this.#positionTabs();\n this.#invalidateCanvas();\n }\n\n // Sync vertical zoom/pan to vcanvas logicalScrollTop + logicalHeight\n if (changedProps.has(`_vViewRange`) || changedProps.has(`_vScale`)) {\n this.#syncVerticalScroll();\n this.#invalidateCanvas();\n }\n\n if (this._tickledId !== this.#prevTickledId) {\n this.#prevTickledId = this._tickledId;\n this.dispatchEvent(\n new CustomEvent<TimelineTickleChangeDetail>(`tickle-change`, {\n detail: { event: this.tickledEvent },\n bubbles: true,\n composed: true,\n }),\n );\n }\n }\n\n protected override render() {\n const totalBaseHeight = this.#getTotalBaseHeight();\n\n return html`\n <div class=\"content-wrapper\">\n <div class=\"content-area\">\n <div class=\"v-axis-zone\"\n @pointerdown=${this.#onVAxisPointerDown}\n @pointermove=${this.#onVAxisPointerMove}\n @pointerup=${this.#onVAxisPointerUp}\n @pointercancel=${this.#onVAxisPointerUp}\n ></div>\n <div class=\"tab-column\">\n ${this._internalTracks\n .filter(t => !t.hidden)\n .map((t) => {\n const layout = this._trackLayout.find(l => l.trackKey === t.key);\n if (!layout)\n return nothing;\n return html`\n <ixfx-timeline-track-tab\n .label=${t.label}\n track-key=\"${t.key}\"\n ?resizable=${this.trackHeight !== `none`}\n ?reorderable=${this.reorderable}\n @click=${(e: MouseEvent) => this.selectTrack(t.key, e.shiftKey)}\n @track-resize-move=${this.#onTrackResizeMove}\n @track-resize=${this.#onTrackResizeEnd}\n ></ixfx-timeline-track-tab>\n `;\n })}\n </div>\n <x-vcanvas></x-vcanvas>\n </div>\n <div class=\"v-zoom\">\n <ixfx-range-multi\n orientation=\"vertical\"\n min=\"0\"\n max=\"${totalBaseHeight}\"\n a=\"${this._vViewRange.min}\"\n b=\"${this._vViewRange.max}\"\n step=\"any\"\n crossover=\"stop\"\n resize-mode=\"bipolar-flex\"\n @input=${this.#onVZoomInput}\n ></ixfx-range-multi>\n </div>\n </div>\n\n <div class=\"h-zoom\">\n <ixfx-range-multi\n min=\"${this.min}\"\n max=\"${this.max}\"\n a=\"${this._viewRange.min}\"\n b=\"${this._viewRange.max}\"\n crossover=\"stop\"\n resize-mode=\"bipolar-flex\"\n @input=${this.#onHZoomInput}\n ></ixfx-range-multi>\n </div>\n\n <div class=\"meta-resizer ${this.metaEnabled ? `visible` : ``}\"></div>\n <div class=\"meta-area ${this.metaEnabled ? `visible` : ``}\" style=\"height:${this._metaHeight}px\"></div>\n `;\n }\n\n // ── VCanvas wiring ──────────────────────────────────────────────────\n\n /** Compute initial ppu to fit 80% of the range, then derive viewRange */\n #initZoomToFit(): void {\n const vpWidth = this.#getViewportWidth();\n const totalSpan = this.max - this.min;\n const zoomFactor = 0.8;\n this._ppu = totalSpan > 0 ? vpWidth / (totalSpan * zoomFactor) : 1;\n this._viewRange = { min: this.min, max: this.min + totalSpan * zoomFactor };\n this.#syncVCanvas();\n // ResizeObserver will re-derive viewRange once vcanvas has its final layout\n }\n\n #syncVCanvas(): void {\n if (!this.#vcanvas)\n return;\n const totalSpan = this.max - this.min;\n // logicalWidth = pure timeline content width in pixels (no tab offset)\n this.#vcanvas.logicalWidth = totalSpan * this._ppu;\n this.#syncVCanvasVertical();\n this.#syncVCanvasScroll();\n }\n\n /** Sync logicalHeight and logicalScrollTop to the vcanvas */\n #syncVCanvasVertical(): void {\n if (!this.#vcanvas)\n return;\n const totalHeight = this._trackLayout.reduce((sum, tl) => sum + tl.height, 0);\n const canvasHeight = Math.max(totalHeight, 40) + this.#axisHeight;\n this.#vcanvas.logicalHeight = canvasHeight;\n this.#vcanvas.logicalScrollTop = this.#vScrollOffset;\n }\n\n #syncVCanvasScroll(): void {\n if (!this.#vcanvas)\n return;\n // Scroll position in logical pixels: pure timeline scroll offset (no tab area)\n this.#vcanvas.logicalScrollLeft = (this._viewRange.min - this.min) * this._ppu;\n }\n\n #invalidateCanvas(): void {\n this.#vcanvas?.invalidateAll();\n }\n\n /** Called by ResizeObserver when vcanvas/content-area changes size */\n #onResize = (_entries: ResizeObserverEntry[]): void => {\n if (!this.#hasInitializedZoom) {\n // First resize after mount — compute initial zoom-to-fit\n this.#hasInitializedZoom = true;\n this.#initZoomToFit();\n this.#initVerticalZoomToFit();\n this.#recomputeTrackLayout();\n } else {\n // Subsequent resizes — keep ppu/vViewRange, re-derive from new viewport size\n this._viewRange = this.#deriveViewRange(this._viewRange.min, this._ppu);\n this.#deriveVerticalZoom(this._vViewRange.min, this._vViewRange.max);\n }\n this.#syncVCanvas();\n\n this.#invalidateCanvas();\n };\n\n #drawCallback = (ctx: CanvasRenderingContext2D, region: Rect, _signal: AbortSignal): void => {\n const ppu = this._ppu;\n\n // Convert pixel region back to timeline logical units for culling.\n // region.x is in vcanvas logical pixels (pure timeline content, no tab offset).\n const logicalRegion: Rect = {\n x: region.x / ppu + this.min,\n y: region.y,\n width: region.width / ppu,\n height: region.height,\n };\n\n // Resolve CSS vars once per frame\n this.#cssVarsCache = resolveCssVars(this);\n\n const grid = resolveGrid(\n this._viewRange,\n this.userScale,\n this.#getViewportWidth(),\n this.gridMode,\n this.minorStep,\n ppu,\n );\n\n // 1. Track backgrounds\n const trackInfos = this._internalTracks.map(t => ({ key: t.key, color: t.color }));\n drawTrackBackgrounds(ctx, logicalRegion, this._trackLayout, trackInfos, this.#cssVarsCache, ppu);\n\n // 2. Grid\n drawMajorMinorGrid(ctx, logicalRegion, grid, this.altMajorBg, this.#cssVarsCache, ppu);\n\n // 3. Event rects\n drawEventRects(\n ctx,\n logicalRegion,\n this._internalEvents,\n this._trackLayout,\n this._selectedIds,\n this._tickledId,\n this._drag,\n this.#cssVarsCache,\n ppu,\n );\n\n // 4. Marquee\n drawMarquee(ctx, this._drag, ppu);\n\n // 5. Axis (drawn last so it overlays grid lines in the axis band)\n const scrollTop = this.#vcanvas?.logicalScrollTop ?? 0;\n drawAxis(ctx, logicalRegion, grid, this.#axisHeight, this.formatLabel, this.#cssVarsCache, ppu, scrollTop);\n };\n\n // ── Scroll / axis labels ────────────────────────────────────────────\n\n #onScrollVirtual = (e: Event): void => {\n const detail = (e as CustomEvent<{\n logicalScrollLeft: number;\n logicalScrollTop: number;\n viewportStartLogical: number;\n viewportEndLogical: number;\n userGesture?: boolean;\n }>).detail;\n\n // Only react to user-initiated scrolls to avoid feedback loops\n if (detail.userGesture === false)\n return;\n\n const ppu = this._ppu;\n if (ppu <= 0)\n return;\n\n // Horizontal: convert pixel scroll position to timeline units (no tab offset)\n const viewMin = detail.logicalScrollLeft / ppu + this.min;\n this._viewRange = this.#deriveViewRange(viewMin, ppu);\n\n // Vertical: reverse-derive _vViewRange from the new logicalScrollTop\n // logicalScrollTop = _vViewRange.min * _vScale, so _vViewRange.min = logicalScrollTop / _vScale\n if (this._vScale > 0) {\n const span = this._vViewRange.max - this._vViewRange.min;\n const newVMin = detail.logicalScrollTop / this._vScale;\n this.#deriveVerticalZoom(newVMin, newVMin + span);\n }\n };\n\n // ── Private helpers ─────────────────────────────────────────────────\n\n #recomputeTrackLayout(): void {\n const layout: TrackLayout[] = [];\n let y = this.#axisHeight;\n for (const track of this._internalTracks) {\n if (track.hidden)\n continue;\n const override = this._trackHeightOverrides.get(track.key);\n const baseHeight = override ?? track.height ?? this.defaultTrackHeight;\n const height = Math.round(baseHeight * this._vScale);\n layout.push({ trackKey: track.key, y, height });\n y += height;\n }\n this._trackLayout = layout;\n }\n\n /**\n * Range slider handler.\n * Slider controls zoom (via span) + pan (via position).\n * Derive ppu from the span the slider produces.\n */\n #onHZoomInput = (e: Event): void => {\n const detail = (e as CustomEvent<{ a: number; b: number }>).detail;\n const span = detail.b - detail.a;\n const vpWidth = this.#getViewportWidth();\n if (span > 0) {\n this._ppu = Math.max(this.#minPpu(), Math.min(vpWidth / span, MAX_PPU));\n }\n this._viewRange = this.#deriveViewRange(detail.a, this._ppu);\n this.#syncVCanvas();\n };\n\n /**\n * Vertical range slider handler.\n * Slider controls vertical zoom (via span) + vertical pan (via position).\n * Derive _vScale from the span the slider produces.\n */\n #onVZoomInput = (e: Event): void => {\n const detail = (e as CustomEvent<{ a: number; b: number }>).detail;\n this.#deriveVerticalZoom(detail.a, detail.b);\n };\n\n // ── Vertical axis drag-zoom handlers ──────────────────────────────────\n\n #onVAxisPointerDown = (e: PointerEvent): void => {\n const zone = e.currentTarget as HTMLElement;\n zone.setPointerCapture(e.pointerId);\n e.stopPropagation(); // prevent track-tab click/select\n e.preventDefault();\n\n // Compute anchor in base-height units from the click Y position\n // The zone covers the track area (below the axis header padding)\n const rect = zone.getBoundingClientRect();\n const clickFrac = rect.height > 0\n ? (e.clientY - rect.top) / rect.height\n : 0.5;\n const span = this._vViewRange.max - this._vViewRange.min;\n const anchorBaseY = this._vViewRange.min + clickFrac * span;\n\n this._drag = {\n kind: `v-axis-zoom`,\n anchorBaseY,\n startScreenX: e.screenX,\n startScreenY: e.screenY,\n startVMin: this._vViewRange.min,\n startVMax: this._vViewRange.max,\n startVScale: this._vScale,\n };\n };\n\n #onVAxisPointerMove = (e: PointerEvent): void => {\n if (this._drag.kind !== `v-axis-zoom`)\n return;\n const drag = this._drag;\n\n const rawDx = e.screenX - drag.startScreenX;\n const rawDy = e.screenY - drag.startScreenY;\n\n // Activation threshold — don't start until enough total movement\n if (Math.abs(rawDx) + Math.abs(rawDy) < DRAG_ACTIVATION_PX)\n return;\n\n // Per-axis deadzone — ignore small off-axis movement\n const dx = applyDeadzone(rawDx, AXIS_DEADZONE_PX);\n const dy = applyDeadzone(rawDy, AXIS_DEADZONE_PX);\n\n const result = computeVerticalAxisZoom(\n drag.startVMin,\n drag.startVMax,\n drag.startVScale,\n drag.anchorBaseY,\n dx,\n dy,\n );\n this.setVerticalZoomPan(result.vMin, result.vMax);\n };\n\n #onVAxisPointerUp = (e: PointerEvent): void => {\n if (this._drag.kind !== `v-axis-zoom`)\n return;\n (e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId);\n this._drag = { kind: `none` };\n };\n\n /** Sync vertical scroll position to vcanvas logicalScrollTop */\n #syncVerticalScroll(): void {\n this.#syncVCanvasVertical();\n this.#positionTabs();\n }\n\n /**\n * Position track tabs in the .tab-column via absolute CSS positioning.\n * Applies a vertical translateY to offset for the current vertical scroll.\n */\n #positionTabs(): void {\n const tabColumn = this.shadowRoot?.querySelector<HTMLElement>(`.tab-column`);\n if (!tabColumn)\n return;\n\n const scrollTop = this.#vcanvas?.logicalScrollTop ?? 0;\n tabColumn.style.transform = `translateY(${-scrollTop}px)`;\n\n for (const layout of this._trackLayout) {\n const tab = tabColumn.querySelector<HTMLElement>(\n `ixfx-timeline-track-tab[track-key=\"${layout.trackKey}\"]`,\n );\n if (!tab)\n continue;\n tab.style.top = `${layout.y}px`;\n tab.style.height = `${layout.height}px`;\n }\n }\n\n /** Read the tab width from the CSS custom property */\n get #tabWidth(): number {\n const raw = getComputedStyle(this).getPropertyValue(`--timeline-tab-width`).trim();\n return Number.parseInt(raw, 10) || 120;\n }\n\n // ── Track resize handlers ────────────────────────────────────────────\n\n /** Live preview during drag — update heights but don't fire public event */\n #onTrackResizeMove = (e: Event): void => {\n const { trackKey, height } = (e as CustomEvent<TimelineTrackResizeDetail>).detail;\n this.#applyTrackResize(trackKey, height);\n };\n\n /** Final resize on pointerup — apply height and fire public event */\n #onTrackResizeEnd = (e: Event): void => {\n const { trackKey, height } = (e as CustomEvent<TimelineTrackResizeDetail>).detail;\n this.#applyTrackResize(trackKey, height);\n\n this.dispatchEvent(\n new CustomEvent<TimelineTrackResizeDetail>(`track-resize`, {\n detail: { trackKey, height },\n bubbles: true,\n composed: true,\n }),\n );\n };\n\n /**\n * Apply track height based on the current `trackHeight` mode.\n * - `fixed`: sets `defaultTrackHeight` (all tracks change uniformly)\n * - `free`: sets per-track override in `_trackHeightOverrides`\n * - `none`: should never be called (resize is disabled)\n */\n #applyTrackResize(trackKey: string, height: number): void {\n if (this.trackHeight === `fixed`) {\n this.defaultTrackHeight = height;\n } else if (this.trackHeight === `free`) {\n const next = new Map(this._trackHeightOverrides);\n next.set(trackKey, height);\n this._trackHeightOverrides = next;\n }\n // `updated()` will trigger #recomputeTrackLayout via defaultTrackHeight or _trackHeightOverrides change\n }\n\n #fireSelectionChange(): void {\n this.dispatchEvent(\n new CustomEvent<TimelineSelectionChangeDetail>(`selection-change`, {\n detail: { selectedIds: [...this._selectedIds] },\n bubbles: true,\n composed: true,\n }),\n );\n }\n}\n\n// ── Global tag name registration ──────────────────────────────────────\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-timeline': IxfxTimelineElement;\n }\n}\n\n// ── Module-scope interface merge (typed addEventListener) ─────────────\nexport interface IxfxTimelineElement {\n addEventListener: (<K extends keyof TimelineElementEventMap>(\n type: K,\n listener: (this: IxfxTimelineElement, event: TimelineElementEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ) => void) & ((\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ) => void);\n}\n"],"mappings":";;;;;;;;;;;;;;;AAqCA,IAAa,qBAAb,MAAgC;CAC9B;CACA;CACA,OAAO;CACP,0BAA0B;CAC1B,4BAA4B;CAE5B,YAAY,UAAwB,QAAkC;EACpE,KAAKA,QAAQ;EACb,KAAKC,UAAU;EAGf,SAAS,MAAM,OAAO;EACtB,SAAS,MAAM,OAAO;EAEtB,IAAI,OAAO,gBACT,SAAS,cAAc,OAAO;EAGhC,SAAS,iBAAiB,gBAAgB,KAAKC,cAA+B;CAChF;;CAGA,SAAS,KAAmB;EAC1B,KAAKC,OAAO;EACZ,KAAKC,mBAAmB;CAC1B;;CAGA,iBAAiB,WAAmB,aAA2B;EAC7D,KAAKC,0BAA0B;EAC/B,KAAKC,4BAA4B;EACjC,KAAKF,mBAAmB;CAC1B;;CAGA,aAAa,OAAwB;EACnC,KAAKJ,MAAM,aAAa,KAAK;CAC/B;;CAGA,UAAgB;EACd,KAAKA,MAAM,oBAAoB,gBAAgB,KAAKE,cAA+B;CACrF;CAEA,kBAAkB,MAAmB;EACnC,MAAM,SAAU,EAA6C;EAC7D,MAAM,gBAAgB,KAAKF,MAAM,eAAe,OAAO,QAAQ,CAAC,CAAC,KAAI,MAAK,EAAE,EAAE;EAE9E,IAAI,OAAO,UAAU;GACnB,MAAM,UAAU,IAAI,IAAI,KAAKA,MAAM,WAAW;GAC9C,KAAK,MAAM,MAAM,eACf,IAAI,QAAQ,IAAI,EAAE,GAChB,QAAQ,OAAO,EAAE;QAEjB,QAAQ,IAAI,EAAE;GAGlB,KAAKA,MAAM,cAAc,CAAC,GAAG,OAAO;EACtC,OACE,KAAKA,MAAM,cAAc;CAE7B;CAEA,qBAA2B;EACzB,IAAI,KAAKC,QAAQ,gBAEf;EAGW,KAAKE;EAClB,MAAM,MAAM,KAAKE;EAGjB,KAAKL,MAAM,eAAe,MAAc;GACtC,MAAM,cAAc;GACpB,MAAM,aAAa;GAGnB,OAAO,GAFK,KAAK,MAAM,aAAa,WAAW,IAAI,EAErC,GADD,KAAK,MAAM,aAAa,WAAW,IAAI;EAEtD;CACF;AACF;;;ACxGA,MAAM,aAAa;CAAC;CAAG;CAAG;CAAG;AAAE;;;;AAK/B,SAAgB,YAAY,WAAsB,WAAsB,eAAuB,OAAiB,YAAY,gBAAyB,KAA8B;CACjL,IAAI,SAAS,WAAW,mBAAmB,KAAA,KAAa,QAAQ,KAAA,GAC9D,OAAO,iBAAiB,gBAAgB,GAAG;CAE7C,OAAO,oBAAoB,WAAW,WAAW,aAAa;AAChE;;;;;AAMA,SAAS,oBAAoB,WAAsB,WAAsB,eAAuC;CAC9G,MAAM,OAAO,UAAU,MAAM,UAAU;CACvC,IAAI,QAAQ,KAAK,iBAAiB,GAChC,OAAO;EAAE,WAAW;EAAK,gBAAgB;EAAG,WAAW;CAAG;CAK5D,MAAM,WAAW,KADS,gBAAgB,SACJ;CAEtC,MAAM,UAAU,OADK,KAAK,IAAI,GAAG,KAAK,MAAM,gBAAgB,QAAQ,CAClC;CAGlC,MAAM,YAAY,MAAM,KAAK,MAAM,KAAK,MAAM,OAAO,CAAC;CACtD,IAAI,WAAW;CACf,KAAK,MAAM,KAAK,YAAY;EAC1B,MAAM,YAAY,IAAI;EACtB,IAAI,aAAa,UAAU,IAAK;GAC9B,WAAW;GACX;EACF;CACF;CAGA,MAAM,aAAa,WAAW;CAC9B,MAAM,iBAAiB,eAAe,KAAK,eAAe,KAAK,IAAI;CACnE,MAAM,YAAY,WAAW;CAE7B,OAAO;EAAE,WAAW;EAAU;EAAgB;CAAU;AAC1D;;;;;;;AAQA,SAAS,iBAAiB,eAAuB,KAA6B;CAC5E,MAAM,iBAAiB;CACvB,IAAI,iBAAiB;CAGrB,OAAO,iBAAiB,MAAM,kBAAkB,iBAAiB,cAC/D,kBAAkB;CAGpB,MAAM,iBAAiB;CAEvB,OAAO;EAAE,WADS,iBAAiB;EACf;EAAgB,WAAW;CAAe;AAChE;AAEA,SAAS,gBAAgB,OAA0B;CACjD,QAAQ,OAAR;EACE,KAAK,UAAU,OAAO;EACtB,KAAK,QAAQ,OAAO;EACpB,KAAK,UAAU,OAAO;EACtB,KAAK,QAAQ,OAAO;EACpB,KAAK,UAAU,OAAO;EACtB,SAAS,OAAO;CAClB;AACF;AAIA,SAAgB,mBAAmB,KAA+B,QAAc,YAA4B,YAAqB,MAAe,KAAmB;CACjK,MAAM,EAAE,WAAW,cAAc;CACjC,IAAI,aAAa,GACf;CAEF,MAAM,YAAY,OAAO,IAAI,OAAO;CAGpC,IAAI,YAAY;EAEd,IAAI,YADa,KAAK,8BAA8B;EAEpD,MAAM,aAAa,KAAK,MAAM,OAAO,IAAI,SAAS;EAClD,KAAK,IAAI,IAAI,YAAY,IAAI,YAAY,WAAW,KAClD,IAAI,IAAI,MAAM,GAAG;GACf,MAAM,IAAI,IAAI,YAAY;GAC1B,IAAI,SAAS,GAAG,OAAO,GAAG,YAAY,KAAK,OAAO,MAAM;EAC1D;CAEJ;CAGA,IAAI,YAAY,GAAG;EACjB,IAAI,cAAc,KAAK,kCAAkC;EACzD,IAAI,YAAY,OAAO,WAAW,KAAK,kCAAkC,KAAK;EAC9E,IAAI,UAAU;EACd,MAAM,aAAa,KAAK,MAAM,OAAO,IAAI,SAAS,IAAI;EACtD,KAAK,IAAI,MAAM,YAAY,MAAM,WAAW,OAAO,WAAW;GAE5D,IAAI,KAAK,IAAI,MAAM,SAAS,IAAI,YAAY,KAC1C;GACF,MAAM,KAAK,MAAM;GACjB,IAAI,OAAO,IAAI,OAAO,CAAC;GACvB,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,MAAM;EACzC;EACA,IAAI,OAAO;CACb;CAGA,IAAI,cAAc,KAAK,kCAAkC;CACzD,IAAI,YAAY,OAAO,WAAW,KAAK,kCAAkC,GAAG;CAC5E,IAAI,UAAU;CACd,MAAM,aAAa,KAAK,MAAM,OAAO,IAAI,SAAS,IAAI;CACtD,KAAK,IAAI,MAAM,YAAY,MAAM,WAAW,OAAO,WAAW;EAC5D,MAAM,KAAK,MAAM;EACjB,IAAI,OAAO,IAAI,OAAO,CAAC;EACvB,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,MAAM;CACzC;CACA,IAAI,OAAO;AACb;;;;;;AASA,SAAgB,SAAS,KAA+B,QAAc,YAA4B,YAAoB,aAAoC,MAAe,KAAa,YAAY,GAAS;CACzM,MAAM,EAAE,cAAc;CACtB,IAAI,aAAa,KAAK,cAAc,GAClC;CAGF,MAAM,UAAU;CAChB,MAAM,aAAa,YAAY;CAG/B,IAAI,OAAO,IAAI,OAAO,SAAS,WAAW,OAAO,IAAI,YACnD;CAEF,MAAM,YAAY,OAAO,IAAI,OAAO;CAIpC,MAAM,WAAW,aAAa;CAI9B,IAAI,YADY,KAAK,oBAAoB;CAEzC,MAAM,SAAS,OAAO,IAAI;CAC1B,IAAI,SAAS,QAAQ,SAAS,OAAO,QAAQ,KAAK,QAAQ;CAG1D,IAAI,cAAc,KAAK,kCAAkC;CACzD,IAAI,YAAY,OAAO,WAAW,KAAK,kCAAkC,GAAG;CAC5E,IAAI,UAAU;CACd,MAAM,aAAa,KAAK,KAAK,OAAO,IAAI,SAAS,IAAI;CACrD,KAAK,IAAI,MAAM,YAAY,MAAM,WAAW,OAAO,WAAW;EAC5D,MAAM,KAAK,MAAM;EACjB,IAAI,OAAO,IAAI,UAAU,QAAQ;EACjC,IAAI,OAAO,IAAI,UAAU;CAC3B;CACA,IAAI,OAAO;CAGX,IAAI,cAAc,KAAK,kCAAkC;CACzD,IAAI,YAAY;CAChB,IAAI,UAAU;CACd,IAAI,OAAO,QAAQ,UAAU;CAC7B,IAAI,OAAO,SAAS,OAAO,QAAQ,KAAK,UAAU;CAClD,IAAI,OAAO;CAIX,IAAI,YADe,KAAK,kCAAkC;CAE1D,IAAI,OAAO;CACX,IAAI,eAAe;CACnB,IAAI,YAAY;CAEhB,MAAM,eAAe;CACrB,KAAK,IAAI,MAAM,YAAY,MAAM,WAAW,OAAO,WAAW;EAC5D,MAAM,KAAK,MAAM;EACjB,IAAI,SAAS,YAAY,GAAG,GAAG,KAAK,cAAc,UAAU,WAAW,CAAC;CAC1E;CAGA,IAAI,YAAY;AAClB;AASA,SAAgB,qBAAqB,KAA+B,QAAc,aAAqC,QAA8B,MAAe,KAAmB;CACrL,MAAM,YAAY,KAAK,0BAA0B;CACjD,MAAM,QAAQ,KAAK,8BAA8B;CAEjD,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;EAC3C,MAAM,SAAS,YAAY;EAE3B,IAAI,OAAO,IAAI,OAAO,SAAS,OAAO,GACpC;EACF,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,QAC/B;EAEF,MAAM,QAAQ,OAAO,MAAK,MAAK,EAAE,QAAQ,OAAO,QAAQ;EAGxD,IAAI,YAFO,OAAO,QAAQ,GAAG,MAAM,MAAM,MAAO,IAAI,MAAM,IAAI,YAAY;EAG1E,IAAI,SAAS,OAAO,IAAI,KAAK,OAAO,GAAG,OAAO,QAAQ,KAAK,OAAO,MAAM;EAGxE,IAAI,cAAc,KAAK,kCAAkC;EACzD,IAAI,YAAY;EAChB,IAAI,UAAU;EACd,IAAI,OAAO,OAAO,IAAI,KAAK,OAAO,IAAI,OAAO,MAAM;EACnD,IAAI,QAAQ,OAAO,IAAI,OAAO,SAAS,KAAK,OAAO,IAAI,OAAO,MAAM;EACpE,IAAI,OAAO;CACb;AACF;AAIA,SAAgB,eAAe,KAA+B,QAAc,QAAkC,aAAqC,aAAkC,WAA+B,MAAkB,MAAe,KAAmB;CACtQ,MAAM,UAAU,KAAK,0BAA0B;CAC/C,MAAM,kBAAkB,KAAK,mCAAmC;CAChE,MAAM,iBAAiB,KAAK,kCAAkC;CAC9D,MAAM,kBAAkB,KAAK,mCAAmC;CAChE,MAAM,SAAS,OAAO,WAAW,KAAK,8BAA8B,GAAG;CAEvE,MAAM,YAAY,OAAO,IAAI,OAAO;CACpC,MAAM,UAAU;CAEhB,KAAK,MAAM,OAAO,QAAQ;EAExB,IAAI,IAAI,MAAM,OAAO,KAAK,IAAI,QAAQ,WACpC;EAEF,MAAM,SAAS,YAAY,MAAK,MAAK,EAAE,aAAa,IAAI,QAAQ;EAChE,IAAI,CAAC,QACH;EAGF,IAAI,OAAO,IAAI,OAAO,SAAS,OAAO,GACpC;EACF,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,QAC/B;EAGF,IAAI,aAAa;EAEjB,IAAI,KAAK,SAAS,gBAAgB,KAAK,YAAY,IAAI,IACrD,aAAa;OACR,IAAI,KAAK,SAAS,iBAAiB,KAAK,YAAY,IAAI,IAC7D,aAAa;OACR,IAAI,KAAK,SAAS,eAAe,KAAK,YAAY,IAAI,IAC3D,aAAa;EAGf,MAAM,IAAI,IAAI,QAAQ;EACtB,MAAM,KAAK,IAAI,MAAM,IAAI,SAAS;EAClC,MAAM,IAAI,OAAO,IAAI;EACrB,MAAM,IAAI,OAAO,SAAS;EAE1B,IAAI,IAAI,GACN;EAGF,MAAM,aAAa,YAAY,IAAI,IAAI,EAAE;EACzC,MAAM,YAAY,cAAc,IAAI;EACpC,IAAI;EACJ,IAAI,YACF,OAAO;OACF,IAAI,WACT,OAAO;OAEP,OAAO,IAAI,SAAS;EAItB,IAAI,YAAY;EAChB,IAAI,UAAU;EACd,cAAc,KAAK,GAAG,GAAG,GAAG,GAAG,KAAK,IAAI,QAAQ,IAAI,GAAG,IAAI,CAAC,CAAC;EAC7D,IAAI,KAAK;EAGT,IAAI,YAAY;GACd,IAAI,cAAc;GAClB,IAAI,YAAY;GAChB,IAAI,UAAU;GACd,cAAc,KAAK,GAAG,GAAG,GAAG,GAAG,KAAK,IAAI,QAAQ,IAAI,GAAG,IAAI,CAAC,CAAC;GAC7D,IAAI,OAAO;EACb;EAGA,IAAI,cAAc,CAAC,YAAY;GAC7B,IAAI,cAAc;GAClB,IAAI,YAAY;GAChB,IAAI,UAAU;GACd,cAAc,KAAK,GAAG,GAAG,GAAG,GAAG,KAAK,IAAI,QAAQ,IAAI,GAAG,IAAI,CAAC,CAAC;GAC7D,IAAI,OAAO;EACb;EAGA,IAAI,KAAK,MAAM,IAAI,OAAO;GACxB,IAAI,YAAY;GAChB,IAAI,OAAO;GACX,IAAI,eAAe;GACnB,IAAI,KAAK;GACT,IAAI,UAAU;GACd,IAAI,KAAK,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC;GAC3B,IAAI,KAAK;GACT,IAAI,SAAS,IAAI,OAAO,IAAI,GAAG,IAAI,IAAI,CAAC;GACxC,IAAI,QAAQ;EACd;CACF;AACF;AAIA,SAAgB,YAAY,KAA+B,MAAkB,KAAmB;CAC9F,IAAI,KAAK,SAAS,WAChB;CAEF,MAAM,KAAK,KAAK,IAAI,KAAK,eAAe,KAAK,eAAe,IAAI;CAChE,MAAM,KAAK,KAAK,IAAI,KAAK,eAAe,KAAK,eAAe,IAAI;CAChE,MAAM,KAAK,KAAK,IAAI,KAAK,QAAQ,KAAK,QAAQ;CAC9C,MAAM,KAAK,KAAK,IAAI,KAAK,QAAQ,KAAK,QAAQ;CAE9C,IAAI,YAAY;CAChB,IAAI,SAAS,IAAI,IAAI,KAAK,IAAI,KAAK,EAAE;CAErC,IAAI,cAAc;CAClB,IAAI,YAAY;CAChB,IAAI,WAAW,IAAI,IAAI,KAAK,IAAI,KAAK,EAAE;AACzC;AAIA,SAAS,cAAc,KAA+B,GAAW,GAAW,GAAW,GAAW,GAAiB;CACjH,IAAI,KAAK,IAAI,GAAG,CAAC;CACjB,IAAI,OAAO,IAAI,GAAG,CAAC;CACnB,IAAI,MAAM,IAAI,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC;CACnC,IAAI,MAAM,IAAI,GAAG,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC;CACnC,IAAI,MAAM,GAAG,IAAI,GAAG,GAAG,GAAG,CAAC;CAC3B,IAAI,MAAM,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC;CAC3B,IAAI,UAAU;AAChB;AAIA,MAAM,oBAAoB;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,SAAgB,eAAe,MAA4B;CACzD,MAAM,WAAW,iBAAiB,IAAI;CACtC,MAAM,OAAgB,CAAC;CACvB,KAAK,MAAM,KAAK,mBACd,KAAK,KAAK,SAAS,iBAAiB,CAAC,CAAC,CAAC,KAAK;CAE9C,OAAO;AACT;;;;ACpYA,MAAM,cAAc;;;;;AAQpB,SAAS,iBAAiB,SAAiB,KAAa,KAAqB;CAC3E,OAAO,UAAU,MAAM;AACzB;;;;;AAMA,SAAS,iBAAiB,KAAqB;CAC7C,OAAO,MAAM,IAAI,IAAI,MAAM;AAC7B;AAWA,SAAS,QAAQ,UAAkB,GAAW,QAAkC,aAAqC,KAAwB;CAE3I,MAAM,QAAQ,YAAY,MAAK,OAAM,KAAK,GAAG,KAAK,IAAI,GAAG,IAAI,GAAG,MAAM;CACtE,IAAI,CAAC,OACH,OAAO;EAAE,MAAM;EAAS;EAAU;EAAG,UAAU,KAAA;CAAU;CAI3D,MAAM,gBAAgB,cAAc,iBAAiB,GAAG;CACxD,MAAM,cAAc,OAAO,QAAO,MAAK,EAAE,aAAa,MAAM,QAAQ;CAEpE,KAAK,MAAM,OAAO,aAAa;EAC7B,IAAI,WAAW,IAAI,SAAS,WAAW,IAAI,KACzC;EAGF,IAAI,YAAY,IAAI,QAAQ,eAC1B,OAAO;GAAE,MAAM;GAAe,SAAS,IAAI;EAAG;EAEhD,IAAI,YAAY,IAAI,MAAM,eACxB,OAAO;GAAE,MAAM;GAAa,SAAS,IAAI;EAAG;EAE9C,OAAO;GACL,MAAM;GACN,SAAS,IAAI;GACb,UAAU,MAAM;GAChB,SAAS,WAAW,IAAI;EAC1B;CACF;CAEA,OAAO;EAAE,MAAM;EAAS;EAAU;EAAG,UAAU,MAAM;CAAS;AAChE;AAIA,SAAS,SAAS,GAAW,aAAyD;CAEpF,OADc,YAAY,MAAK,OAAM,KAAK,GAAG,KAAK,IAAI,GAAG,IAAI,GAAG,MACrD,CAAC,EAAE;AAChB;;AAKA,MAAM,sBAAsB;;;;;AAY5B,SAAgB,cAAc,OAAe,UAA0B;CACrE,OAAO,KAAK,IAAI,KAAK,IAAI,WAAW,QAAQ,KAAK,KAAK,KAAK,IAAI,WAAW;AAC5E;;;;;;;;AASA,SAAS,gBAAgB,cAAsB,UAAkB,YAAoB,IAAY,IAA8C;CAG7I,MAAM,SAAS,WADI,KAAK,IAAI,CAAC,KAAK,mBACC;CAQnC,IAAI,SAAS,cADU,aAAa,gBAAgB,WACV;CAG1C,IAAI,SAAS,GACX,UAAU,CAAC,KAAK;CAIlB,OAAO;EAAE,KAAK;EAAQ,SAAS;CAAO;AACxC;;;;;;;;;AAUA,SAAgB,wBAAwB,WAAmB,WAAmB,aAAqB,aAAqB,IAAY,IAA4C;CAC9K,MAAM,YAAY,YAAY;CAI9B,MAAM,UAAU,YADG,KAAK,IAAI,CAAC,KAAK,mBACG;CAMrC,IAAI,SAAS,eAHM,YAAY,KAC1B,cAAc,aAAa,YAC5B,MACoC;CAGxC,IAAI,cAAc,GAChB,UAAU,KAAK;CAIjB,OAAO;EAAE,MAAM;EAAQ,MAAM,SAAS;CAAQ;AAChD;;;;;AAQA,SAAgB,2BAA2B,MAA2B,WAAyC;CAC7G,MAAM,KAAK,IAAI,gBAAgB;CAC/B,MAAM,SAAS,GAAG;CAGlB,UAAU,iBAAiB,gBAAgB,MAAoB;EAC7D,MAAM,MAAM,KAAK;EACjB,MAAM,cAAc,UAAU,4BAA4B,EAAE,SAAS,EAAE,OAAO;EAE9E,MAAM,KAAK,iBAAiB,YAAY,GAAG,KAAK,KAAK,GAAG;EACxD,MAAM,KAAK,YAAY;EAIvB,MAAM,UAAU,UAAU;EAC1B,IAAI,MAAM,WAAW,KAAK,UAAU,KAAK,YAAY;GACnD,UAAU,kBAAkB,EAAE,SAAS;GACvC,KAAK,QAAQ;IACX,MAAM;IACN,YAAY;IACZ,cAAc,EAAE;IAChB,cAAc,EAAE;IAChB,cAAc,KAAK,WAAW;IAC9B,UAAU;GACZ;GACA;EACF;EAEA,MAAM,MAAM,QAAQ,IAAI,IAAI,KAAK,iBAAiB,KAAK,cAAc,GAAG;EAExE,IAAI,EAAE,YAAY,IAAI,SAAS,cAAc;GAE3C,gBAAgB,MAAM,IAAI,OAAO;GACjC;EACF;EAEA,IAAI,IAAI,SAAS,cAAc;GAE7B,UAAU,kBAAkB,EAAE,SAAS;GACvC,KAAK,QAAQ;IACX,MAAM;IACN,SAAS,IAAI;IACb,gBAAgB,IAAI;IACpB,SAAS,IAAI;GACf;GACA;EACF;EAEA,IAAI,IAAI,SAAS,eAAe;GAC9B,UAAU,kBAAkB,EAAE,SAAS;GACvC,KAAK,QAAQ;IAAE,MAAM;IAAe,SAAS,IAAI;GAAQ;GACzD;EACF;EAEA,IAAI,IAAI,SAAS,aAAa;GAC5B,UAAU,kBAAkB,EAAE,SAAS;GACvC,KAAK,QAAQ;IAAE,MAAM;IAAa,SAAS,IAAI;GAAQ;GACvD;EACF;EAEA,IAAI,IAAI,SAAS,SAAS;GAExB,UAAU,kBAAkB,EAAE,SAAS;GACvC,KAAK,QAAQ;IACX,MAAM;IACN,eAAe;IACf,QAAQ;IACR,iBAAiB;IACjB,UAAU;GACZ;EACF;CACF,GAAG,EAAE,OAAO,CAAC;CAGb,UAAU,iBAAiB,gBAAgB,MAAoB;EAC7D,MAAM,OAAO,KAAK;EAClB,IAAI,KAAK,SAAS,QAAQ;GAExB,YAAY,MAAM,WAAW,CAAC;GAC9B;EACF;EAEA,MAAM,MAAM,KAAK;EACjB,MAAM,cAAc,UAAU,4BAA4B,EAAE,SAAS,EAAE,OAAO;EAE9E,MAAM,KAAK,iBAAiB,YAAY,GAAG,KAAK,KAAK,GAAG;EACxD,MAAM,KAAK,YAAY;EAEvB,IAAI,KAAK,SAAS,aAAa;GAC7B,MAAM,QAAQ,EAAE,UAAU,KAAK;GAC/B,MAAM,QAAQ,EAAE,UAAU,KAAK;GAG/B,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAA,GAClC;GAGF,MAAM,KAAK,cAAc,OAAA,CAAuB;GAChD,MAAM,KAAK,cAAc,OAAA,CAAuB;GAEhD,MAAM,SAAS,gBACb,KAAK,cACL,KAAK,UACL,KAAK,YACL,IACA,EACF;GACA,KAAK,WAAW,OAAO,SAAS,OAAO,GAAG;GAC1C;EACF;EAEA,IAAI,KAAK,SAAS,WAAW;GAC3B,KAAK,QAAQ;IAAE,GAAG;IAAM,iBAAiB;IAAI,UAAU;GAAG;GAC1D,UAAU,cAAc;GACxB;EACF;EAEA,IAAI,KAAK,SAAS,cAAc;GAC9B,MAAM,MAAM,KAAK,gBAAgB,MAAK,OAAM,GAAG,OAAO,KAAK,OAAO;GAClE,IAAI,CAAC,KACH;GACF,MAAM,WAAW,IAAI,MAAM,IAAI;GAC/B,MAAM,QAAQ;GACd,MAAM,QAAQ;GACd,MAAM,WAAW,KAAK,KAAK;GAC3B,MAAM,SAAS,WAAW;GAC1B,MAAM,cAAc,SAAS,IAAI,KAAK,YAAY,KAAK,IAAI;GAE3D,MAAM,MAAM,KAAK;GACjB,MAAM,OAAuB,YAC3B,KAAK,YACL,KAAK,WACL,UAAU,eACV,KAAK,UACL,KAAK,WACL,GACF;GAEA,MAAM,UAAU,KAAK,YACnB,KAAK,SACL,OACA,OACA,UACA,QACA,aACA,KAAK,gBACL,IACF;GAEA,KAAK,kBAAkB,KAAK,gBAAgB,KAAI,OAC9C,GAAG,OAAO,KAAK,UACX;IAAE,GAAG;IAAI,OAAO,QAAQ;IAAO,KAAK,QAAQ;IAAK,UAAU,QAAQ;GAAS,IAC5E,EACN;GACA,UAAU,cAAc;GACxB;EACF;EAEA,IAAI,KAAK,SAAS,eAAe;GAC/B,MAAM,MAAM,KAAK,gBAAgB,MAAK,OAAM,GAAG,OAAO,KAAK,OAAO;GAClE,IAAI,CAAC,KACH;GACF,MAAM,WAAW,KAAK,IAAI,IAAI,IAAI,MAAM,CAAC;GACzC,KAAK,kBAAkB,KAAK,gBAAgB,KAAI,OAC9C,GAAG,OAAO,KAAK,UAAU;IAAE,GAAG;IAAI,OAAO;GAAS,IAAI,EACxD;GACA,UAAU,cAAc;GACxB;EACF;EAEA,IAAI,KAAK,SAAS,aAAa;GAC7B,MAAM,MAAM,KAAK,gBAAgB,MAAK,OAAM,GAAG,OAAO,KAAK,OAAO;GAClE,IAAI,CAAC,KACH;GACF,MAAM,SAAS,KAAK,IAAI,IAAI,IAAI,QAAQ,CAAC;GACzC,KAAK,kBAAkB,KAAK,gBAAgB,KAAI,OAC9C,GAAG,OAAO,KAAK,UAAU;IAAE,GAAG;IAAI,KAAK;GAAO,IAAI,EACpD;GACA,UAAU,cAAc;EAC1B;CACF,GAAG,EAAE,OAAO,CAAC;CAGb,UAAU,iBAAiB,cAAc,MAAoB;EAC3D,MAAM,OAAO,KAAK;EAClB,UAAU,sBAAsB,EAAE,SAAS;EAE3C,IAAI,KAAK,SAAS,aAAa;GAE7B,KAAK,QAAQ,EAAE,MAAM,OAAO;GAC5B;EACF;EAEA,IAAI,KAAK,SAAS,WAAW;GAE3B,MAAM,KAAK,KAAK,IAAI,KAAK,eAAe,KAAK,eAAe;GAC5D,MAAM,KAAK,KAAK,IAAI,KAAK,eAAe,KAAK,eAAe;GAC5D,MAAM,KAAK,KAAK,IAAI,KAAK,QAAQ,KAAK,QAAQ;GAC9C,MAAM,KAAK,KAAK,IAAI,KAAK,QAAQ,KAAK,QAAQ;GAG9C,IAAI,KAAK,IAAI,KAAK,EAAE,IAAI,KAAK,KAAK,IAAI,KAAK,EAAE,IAAI,GAAG;IAElD,KAAK,+BAAe,IAAI,IAAI;IAC5B,oBAAoB,IAAI;GAC1B,OAAO;IAEL,MAAM,2BAAW,IAAI,IAAY;IACjC,KAAK,MAAM,OAAO,KAAK,iBAAiB;KACtC,MAAM,SAAS,KAAK,aAAa,MAAK,MAAK,EAAE,aAAa,IAAI,QAAQ;KACtE,IAAI,CAAC,QACH;KACF,MAAM,SAAS,OAAO,IAAI;KAC1B,MAAM,YAAY,OAAO,IAAI,OAAO,SAAS;KAG7C,IAAI,IAAI,OAAO,MAAM,IAAI,SAAS,MAAM,aAAa,MAAM,UAAU,IACnE,SAAS,IAAI,IAAI,EAAE;IAEvB;IACA,KAAK,eAAe;IACpB,oBAAoB,IAAI;GAC1B;GAEA,KAAK,QAAQ,EAAE,MAAM,OAAO;GAC5B,UAAU,cAAc;GACxB;EACF;EAEA,IAAI,KAAK,SAAS,cAAc;GAC9B,MAAM,MAAM,KAAK,gBAAgB,MAAK,OAAM,GAAG,OAAO,KAAK,OAAO;GAClE,IAAI,KACF,KAAK,cACH,IAAI,YAAqC,cAAc;IACrD,QAAQ;KACN,SAAS,IAAI;KACb,cAAc,KAAK;KACnB,YAAY,IAAI;KAChB,OAAO,IAAI;KACX,KAAK,IAAI;IACX;IACA,SAAS;IACT,UAAU;GACZ,CAAC,CACH;GAEF,KAAK,QAAQ,EAAE,MAAM,OAAO;GAC5B;EACF;EAEA,IAAI,KAAK,SAAS,iBAAiB,KAAK,SAAS,aAAa;GAC5D,MAAM,MAAM,KAAK,gBAAgB,MAAK,OAAM,GAAG,OAAO,KAAK,OAAO;GAClE,IAAI,KACF,KAAK,cACH,IAAI,YAAuC,gBAAgB;IACzD,QAAQ;KACN,SAAS,IAAI;KACb,OAAO,IAAI;KACX,KAAK,IAAI;IACX;IACA,SAAS;IACT,UAAU;GACZ,CAAC,CACH;GAEF,KAAK,QAAQ,EAAE,MAAM,OAAO;GAC5B;EACF;EAEA,KAAK,QAAQ,EAAE,MAAM,OAAO;CAC9B,GAAG,EAAE,OAAO,CAAC;CAGb,UAAU,iBAAiB,sBAAsB;EAC/C,IAAI,KAAK,eAAe,KAAA,GAAW;GACjC,KAAK,aAAa,KAAA;GAClB,UAAU,cAAc;EAC1B;CACF,GAAG,EAAE,OAAO,CAAC;CAEb,aAAa,GAAG,MAAM;AACxB;AAIA,SAAS,YAAY,MAA2B,WAA2B,GAAuB;CAChG,MAAM,MAAM,KAAK;CACjB,MAAM,cAAc,UAAU,4BAA4B,EAAE,SAAS,EAAE,OAAO;CAE9E,MAAM,KAAK,iBAAiB,YAAY,GAAG,KAAK,KAAK,GAAG;CACxD,MAAM,KAAK,YAAY;CAGvB,MAAM,UAAU,UAAU;CAC1B,IAAI,MAAM,WAAW,KAAK,UAAU,KAAK,YAAY;EACnD,UAAU,MAAM,SAAS;EAEzB,IAAI,KAAK,eAAe,KAAA,GAAW;GACjC,KAAK,aAAa,KAAA;GAClB,UAAU,cAAc;EAC1B;EACA;CACF;CAEA,MAAM,MAAM,QAAQ,IAAI,IAAI,KAAK,iBAAiB,KAAK,cAAc,GAAG;CAExE,IAAI;CACJ,IAAI,IAAI,SAAS,gBAAgB,IAAI,SAAS,iBAAiB,IAAI,SAAS,aAC1E,eAAe,IAAI;CAIrB,IAAI,IAAI,SAAS,iBAAiB,IAAI,SAAS,aAC7C,UAAU,MAAM,SAAS;MACpB,IAAI,IAAI,SAAS,cACtB,UAAU,MAAM,SAAS;MAEzB,UAAU,MAAM,SAAS;CAG3B,IAAI,iBAAiB,KAAK,YAAY;EACpC,KAAK,aAAa;EAClB,UAAU,cAAc;CAC1B;AACF;AAEA,SAAS,gBAAgB,MAA2B,SAAuB;CACzE,MAAM,OAAO,IAAI,IAAI,KAAK,YAAY;CACtC,IAAI,KAAK,IAAI,OAAO,GAClB,KAAK,OAAO,OAAO;MAEnB,KAAK,IAAI,OAAO;CAElB,KAAK,eAAe;CACpB,oBAAoB,IAAI;CACxB,KAAK,WAAW,CAAC,EAAE,cAAc;AACnC;AAEA,SAAS,oBAAoB,MAAiC;CAC5D,KAAK,cACH,IAAI,YAA2C,oBAAoB;EACjE,QAAQ,EAAE,aAAa,CAAC,GAAG,KAAK,YAAY,EAAE;EAC9C,SAAS;EACT,UAAU;CACZ,CAAC,CACH;AACF;;;AChgBA,MAAa,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACMjC,MAAM,mBAAmB;;AAGzB,MAAM,eAAe;AAcd,IAAM,0BAAN,MAAM,gCAAgC,WAAW;;;EA6ClB,KAAA,QAAA;EAC2B,KAAA,WAAA;EACR,KAAA,WAAA;EACG,KAAA,cAAA;EACF,KAAA,YAAA;EAG5C,KAAA,YAAA;EACI,KAAA,gBAAA;EACD,KAAA,eAAA;EACkB,KAAA,aAAA,KAAA;EAkDf,KAAA,kBAAA,MAA0B;GAC1C,IAAI,KAAKO,WAAW;IAElB,MAAM,KAAK,EAAE,UAAU,KAAKC;IAC5B,MAAM,YAAY,KAAK,IAAI,kBAAkB,KAAKC,eAAe,EAAE;IACnE,KAAKC,iBAAiB,qBAAqB,SAAS;IACpD;GACF;GAGA,IAAI,KAAKC,gBAAgB,CAAC,GACxB,KAAK,MAAM,SAAS;QAEpB,KAAK,MAAM,SAAS;EAExB;EAEkB,KAAA,kBAAA,MAA0B;GAC1C,IAAI,CAAC,KAAKA,gBAAgB,CAAC,GACzB;GAGF,EAAE,gBAAgB;GAClB,EAAE,eAAe;GAEjB,KAAKJ,YAAY;GACjB,KAAKC,gBAAgB,EAAE;GACvB,KAAKC,eAAe,KAAK;GACzB,KAAKG,aAAa,EAAE;GACpB,KAAK,kBAAkB,EAAE,SAAS;EACpC;EAEgB,KAAA,gBAAA,MAA0B;GACxC,IAAI,CAAC,KAAKL,WACR;GAEF,MAAM,KAAK,EAAE,UAAU,KAAKC;GAC5B,MAAM,cAAc,KAAK,IAAI,kBAAkB,KAAKC,eAAe,EAAE;GAErE,KAAKC,iBAAiB,gBAAgB,WAAW;GACjD,KAAKG,WAAW,EAAE,SAAS;EAC7B;EAEoB,KAAA,oBAAA,OAAoB;GACtC,IAAI,CAAC,KAAKN,WACR;GACF,KAAKM,WAAW,KAAKD,UAAU;EACjC;;;EAvJyB,KAAA,SAAA;GAAC;GAAgB;GAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0C1D;;CASD;CACA;CACA;CACA;CAEA,oBAAmC;EACjC,MAAM,kBAAkB;EACxB,KAAK,iBAAiB,eAAe,KAAKE,cAAc;EACxD,KAAK,iBAAiB,eAAe,KAAKC,cAAc;EACxD,KAAK,iBAAiB,aAAa,KAAKC,YAAY;EACpD,KAAK,iBAAiB,iBAAiB,KAAKC,gBAAgB;EAC5D,KAAK,iBAAiB,sBAAsB,KAAKA,gBAAgB;CACnE;CAEA,uBAAsC;EACpC,MAAM,qBAAqB;EAC3B,KAAK,oBAAoB,eAAe,KAAKH,cAAc;EAC3D,KAAK,oBAAoB,eAAe,KAAKC,cAAc;EAC3D,KAAK,oBAAoB,aAAa,KAAKC,YAAY;EACvD,KAAK,oBAAoB,iBAAiB,KAAKC,gBAAgB;EAC/D,KAAK,oBAAoB,sBAAsB,KAAKA,gBAAgB;EACpE,KAAKV,YAAY;CACnB;CAEA,SAA4B;EAC1B,OAAO,IAAI;;4BAEa,KAAK,MAAM;;CAErC;;CAKA,gBAAgB,GAA0B;EACxC,IAAI,CAAC,KAAK,WACR,OAAO;EACT,MAAM,OAAO,KAAK,sBAAsB;EACxC,OAAO,EAAE,WAAW,KAAK,SAAS;CACpC;CAEA,iBAAiB,WAAmB,QAAsB;EACxD,KAAK,cACH,IAAI,YAAuC,WAAW;GACpD,QAAQ;IAAE,UAAU,KAAK;IAAU;GAAO;GAC1C,SAAS;GACT,UAAU;EACZ,CAAC,CACH;CACF;CAIA;CAiBA;CAeA;CAWA;CAMA,WAAW,WAA0B;EACnC,KAAKA,YAAY;EACjB,KAAKC,gBAAgB;EACrB,KAAKC,eAAe;EACpB,IAAI,cAAc,KAAA,GAChB,IAAI;GACF,KAAK,sBAAsB,SAAS;EACtC,QAAQ,CAAyB;EAEnC,KAAKG,aAAa,KAAA;EAClB,KAAK,MAAM,SAAS;CACtB;AACF;AAzHG,WAAA,CAAA,SAAS,EAAE,MAAM,OAAO,CAAC,CAAA,GAAA,wBAAA,WAAA,SAAA,KAAA,CAAA;AACzB,WAAA,CAAA,SAAS;CAAE,MAAM;CAAQ,WAAW;AAAY,CAAC,CAAA,GAAA,wBAAA,WAAA,YAAA,KAAA,CAAA;AACjD,WAAA,CAAA,SAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,wBAAA,WAAA,YAAA,KAAA,CAAA;AACzC,WAAA,CAAA,SAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,wBAAA,WAAA,eAAA,KAAA,CAAA;AACzC,WAAA,CAAA,SAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,wBAAA,WAAA,aAAA,KAAA,CAAA;AAlD3CM,0BAAAA,WAAAA,CAAAA,kBAAc,yBAAyB,CAAA,GAAA,uBAAA;;;;AC8BxC,MAAM,UAAU;;AAGhB,MAAM,0BAA0B;AAGzB,IAAM,sBAAN,MAAM,4BAA4B,WAAW;;;EAIG,KAAA,SAAA,CAAC;EACD,KAAA,SAAA,CAAC;EACpB,KAAA,MAAA;EACA,KAAA,MAAA;EACoD,KAAA,cAAA;EACV,KAAA,YAAA;EACjC,KAAA,cAAA;EACmB,KAAA,cAAA;EACO,KAAA,aAAA;EACe,KAAA,qBAAA;EACX,KAAA,WAAA;EACR,KAAA,YAAA;EACD,KAAA,aAAA;EAG3B,KAAA,cAAA;EAQrB,KAAA,OAAA;EACiB,KAAA,aAAA;GAAE,KAAK;GAAG,KAAK;EAAK;EAQnB,KAAA,cAAA;GAAE,KAAK;GAAG,KAAK;EAAE;EAChC,KAAA,UAAA;EAEkB,KAAA,+BAAA,IAAI,IAAI;EACH,KAAA,aAAA,KAAA;EACb,KAAA,QAAA,EAAE,MAAM,OAAO;EACrB,KAAA,cAAA;EAC+B,KAAA,wCAAA,IAAI,IAAI;EACvB,KAAA,eAAA,CAAC;EACI,KAAA,kBAAA,CAAC;EACD,KAAA,kBAAA,CAAC;EAGX,KAAA,WAAA;EACT,KAAA,gBAAA,CAAC;EACkB,KAAA,uBAAA;EAC9B,KAAA,cAAA;EACuB,KAAA,iBAAA,KAAA;EACI,KAAA,kBAAA;EACb,KAAA,4BAAA;EACN,KAAA,sBAAA;EAwjBT,KAAA,aAAA,aAA0C;GACrD,IAAI,CAAC,KAAKC,qBAAqB;IAE7B,KAAKA,sBAAsB;IAC3B,KAAKC,eAAe;IACpB,KAAKC,uBAAuB;IAC5B,KAAKC,sBAAsB;GAC7B,OAAO;IAEL,KAAK,aAAa,KAAKC,iBAAiB,KAAK,WAAW,KAAK,KAAK,IAAI;IACtE,KAAKC,oBAAoB,KAAK,YAAY,KAAK,KAAK,YAAY,GAAG;GACrE;GACA,KAAKC,aAAa;GAElB,KAAKC,kBAAkB;EACzB;EAEiB,KAAA,iBAAA,KAA+B,QAAc,YAA+B;GAC3F,MAAM,MAAM,KAAK;GAIjB,MAAM,gBAAsB;IAC1B,GAAG,OAAO,IAAI,MAAM,KAAK;IACzB,GAAG,OAAO;IACV,OAAO,OAAO,QAAQ;IACtB,QAAQ,OAAO;GACjB;GAGA,KAAKC,gBAAgB,eAAe,IAAI;GAExC,MAAM,OAAO,YACX,KAAK,YACL,KAAK,WACL,KAAKC,kBAAkB,GACvB,KAAK,UACL,KAAK,WACL,GACF;GAGA,MAAM,aAAa,KAAK,gBAAgB,KAAI,OAAM;IAAE,KAAK,EAAE;IAAK,OAAO,EAAE;GAAM,EAAE;GACjF,qBAAqB,KAAK,eAAe,KAAK,cAAc,YAAY,KAAKD,eAAe,GAAG;GAG/F,mBAAmB,KAAK,eAAe,MAAM,KAAK,YAAY,KAAKA,eAAe,GAAG;GAGrF,eACE,KACA,eACA,KAAK,iBACL,KAAK,cACL,KAAK,cACL,KAAK,YACL,KAAK,OACL,KAAKA,eACL,GACF;GAGA,YAAY,KAAK,KAAK,OAAO,GAAG;GAGhC,MAAM,YAAY,KAAKE,UAAU,oBAAoB;GACrD,SAAS,KAAK,eAAe,MAAM,KAAKC,aAAa,KAAK,aAAa,KAAKH,eAAe,KAAK,SAAS;EAC3G;EAIoB,KAAA,oBAAA,MAAmB;GACrC,MAAM,SAAU,EAMZ;GAGJ,IAAI,OAAO,gBAAgB,OACzB;GAEF,MAAM,MAAM,KAAK;GACjB,IAAI,OAAO,GACT;GAGF,MAAM,UAAU,OAAO,oBAAoB,MAAM,KAAK;GACtD,KAAK,aAAa,KAAKJ,iBAAiB,SAAS,GAAG;GAIpD,IAAI,KAAK,UAAU,GAAG;IACpB,MAAM,OAAO,KAAK,YAAY,MAAM,KAAK,YAAY;IACrD,MAAM,UAAU,OAAO,mBAAmB,KAAK;IAC/C,KAAKC,oBAAoB,SAAS,UAAU,IAAI;GAClD;EACF;EAwBiB,KAAA,iBAAA,MAAmB;GAClC,MAAM,SAAU,EAA4C;GAC5D,MAAM,OAAO,OAAO,IAAI,OAAO;GAC/B,MAAM,UAAU,KAAKI,kBAAkB;GACvC,IAAI,OAAO,GACT,KAAK,OAAO,KAAK,IAAI,KAAKG,QAAQ,GAAG,KAAK,IAAI,UAAU,MAAM,OAAO,CAAC;GAExE,KAAK,aAAa,KAAKR,iBAAiB,OAAO,GAAG,KAAK,IAAI;GAC3D,KAAKE,aAAa;EACpB;EAOiB,KAAA,iBAAA,MAAmB;GAClC,MAAM,SAAU,EAA4C;GAC5D,KAAKD,oBAAoB,OAAO,GAAG,OAAO,CAAC;EAC7C;EAIuB,KAAA,uBAAA,MAA0B;GAC/C,MAAM,OAAO,EAAE;GACf,KAAK,kBAAkB,EAAE,SAAS;GAClC,EAAE,gBAAgB;GAClB,EAAE,eAAe;GAIjB,MAAM,OAAO,KAAK,sBAAsB;GACxC,MAAM,YAAY,KAAK,SAAS,KAC3B,EAAE,UAAU,KAAK,OAAO,KAAK,SAC9B;GACJ,MAAM,OAAO,KAAK,YAAY,MAAM,KAAK,YAAY;GACrD,MAAM,cAAc,KAAK,YAAY,MAAM,YAAY;GAEvD,KAAK,QAAQ;IACX,MAAM;IACN;IACA,cAAc,EAAE;IAChB,cAAc,EAAE;IAChB,WAAW,KAAK,YAAY;IAC5B,WAAW,KAAK,YAAY;IAC5B,aAAa,KAAK;GACpB;EACF;EAEuB,KAAA,uBAAA,MAA0B;GAC/C,IAAI,KAAK,MAAM,SAAS,eACtB;GACF,MAAM,OAAO,KAAK;GAElB,MAAM,QAAQ,EAAE,UAAU,KAAK;GAC/B,MAAM,QAAQ,EAAE,UAAU,KAAK;GAG/B,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAA,GAClC;GAGF,MAAM,KAAK,cAAc,OAAA,CAAuB;GAChD,MAAM,KAAK,cAAc,OAAA,CAAuB;GAEhD,MAAM,SAAS,wBACb,KAAK,WACL,KAAK,WACL,KAAK,aACL,KAAK,aACL,IACA,EACF;GACA,KAAK,mBAAmB,OAAO,MAAM,OAAO,IAAI;EAClD;EAEqB,KAAA,qBAAA,MAA0B;GAC7C,IAAI,KAAK,MAAM,SAAS,eACtB;GACF,EAAG,cAA8B,sBAAsB,EAAE,SAAS;GAClE,KAAK,QAAQ,EAAE,MAAM,OAAO;EAC9B;EAwCsB,KAAA,sBAAA,MAAmB;GACvC,MAAM,EAAE,UAAU,WAAY,EAA6C;GAC3E,KAAKQ,kBAAkB,UAAU,MAAM;EACzC;EAGqB,KAAA,qBAAA,MAAmB;GACtC,MAAM,EAAE,UAAU,WAAY,EAA6C;GAC3E,KAAKA,kBAAkB,UAAU,MAAM;GAEvC,KAAK,cACH,IAAI,YAAuC,gBAAgB;IACzD,QAAQ;KAAE;KAAU;IAAO;IAC3B,SAAS;IACT,UAAU;GACZ,CAAC,CACH;EACF;;;EAp3ByB,KAAA,SAAA,CAAC,cAAc;;CAgDxC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;;CAKA,IAAI,YAAoB;EACtB,OAAO,KAAK;CACd;;CAGA,IAAI,aAAqB;EACvB,OAAO,KAAKF;CACd;;CAGA,IAAI,WAAmB;EACrB,OAAO,KAAKG;CACd;CAIA,oBAA4B;EAI1B,OAHY,KAAKJ,UAAU,iBACrB,KAAKA,UAAiC,eACvC;CAEP;;CAGA,UAAkB;EAChB,MAAM,YAAY,KAAK,MAAM,KAAK;EAClC,IAAI,aAAa,GACf,OAAO;EAET,OADgB,KAAKD,kBACR,IAAI;CACnB;;CAKA,qBAA6B;EAC3B,OAAO,KAAKC,UAAU,kBAChB,KAAKA,UAAiC,gBACvC;CACP;;;;;CAMA,sBAA8B;EAC5B,IAAI,QAAQ;EACZ,KAAK,MAAM,SAAS,KAAK,iBAAiB;GACxC,IAAI,MAAM,QACR;GACF,MAAM,WAAW,KAAK,sBAAsB,IAAI,MAAM,GAAG;GACzD,SAAS,YAAY,MAAM,UAAU,KAAK;EAC5C;EACA,OAAO,SAAS;CAClB;;CAGA,8BAAsC;EACpC,IAAI,WAAW;EACf,KAAK,MAAM,SAAS,KAAK,iBAAiB;GACxC,IAAI,MAAM,QACR;GAEF,MAAM,IADW,KAAK,sBAAsB,IAAI,MAAM,GACrC,KAAK,MAAM,UAAU,KAAK;GAC3C,IAAI,IAAI,UACN,WAAW;EACf;EACA,OAAO,aAAa,WAAW,KAAK,qBAAqB;CAC3D;;CAGA,6BAAqC;EACnC,IAAI,UAAU;EACd,KAAK,MAAM,SAAS,KAAK,iBAAiB;GACxC,IAAI,MAAM,QACR;GAEF,MAAM,IADW,KAAK,sBAAsB,IAAI,MAAM,GACrC,KAAK,MAAM,UAAU,KAAK;GAC3C,IAAI,IAAI,SACN,UAAU;EACd;EACA,OAAO,WAAW,KAAK;CACzB;;;;;;CAOA,oBAAoB,MAAc,MAAoB;EACpD,MAAM,YAAY,KAAKK,oBAAoB;EAC3C,MAAM,WAAW,KAAKC,mBAAmB,IAAI,KAAKL;EAGlD,IAAI,IAAI;EACR,IAAI,IAAI;EAGR,MAAM,cAAc,KAAKM,2BAA2B;EACpD,MAAM,UAAU,KAAK,IAAI,aAAa,YAAY,GAAI;EAMtD,MAAM,eAAe,KAAKC,4BAA4B;EACtD,MAAM,uBAAuB,WAAW,IACpC,WAAW,eAAe,0BAC1B;EACJ,MAAM,UAAU,KAAK,IAAI,WAAW,oBAAoB;EAExD,IAAI,OAAO,IAAI;EACf,IAAI,OAAO,SAAS;GAClB,MAAM,UAAU,IAAI,KAAK;GACzB,IAAI,SAAS,UAAU;GACvB,IAAI,SAAS,UAAU;GACvB,OAAO;EACT;EACA,IAAI,OAAO,SAAS;GAClB,MAAM,UAAU,IAAI,KAAK;GACzB,IAAI,SAAS,UAAU;GACvB,IAAI,SAAS,UAAU;GACvB,OAAO;EACT;EAEA,IAAI,IAAI,WAAW;GACjB,IAAI;GACJ,IAAI,KAAK,IAAI,GAAG,IAAI,IAAI;EAC1B;EACA,IAAI,IAAI,GAAG;GACT,IAAI;GACJ,IAAI,KAAK,IAAI,WAAW,IAAI,IAAI;EAClC;EAEA,KAAK,cAAc;GAAE,KAAK;GAAG,KAAK;EAAE;EACpC,KAAK,UAAU,WAAW,IAAI,YAAY,IAAI,KAAK;CACrD;;CAGA,yBAA+B;EAC7B,MAAM,YAAY,KAAKH,oBAAoB;EAC3C,KAAKV,oBAAoB,GAAG,SAAS;CACvC;;CAGA,IAAIc,iBAAyB;EAC3B,OAAO,KAAK,YAAY,MAAM,KAAK;CACrC;;;;;CAMA,iBAAiB,SAAiB,KAAwB;EACxD,MAAM,UAAU,KAAKV,kBAAkB;EACvC,MAAM,WAAW,MAAM,IAAI,UAAU,MAAO,KAAK,MAAM,KAAK;EAC5D,IAAI,SAAS;EACb,IAAI,SAAS,SAAS;EAGtB,IAAI,SAAS,KAAK,KAAK;GACrB,SAAS,KAAK;GACd,SAAS,KAAK,IAAI,KAAK,KAAK,SAAS,QAAQ;EAC/C;EAEA,IAAI,SAAS,KAAK,KAAK;GACrB,SAAS,KAAK;GACd,SAAS,KAAK,IAAI,KAAK,KAAK,SAAS,QAAQ;EAC/C;EAEA,OAAO;GAAE,KAAK;GAAQ,KAAK;EAAO;CACpC;;CAKA,OAAO,KAAmB;EACxB,KAAK,OAAO,KAAK,IAAI,KAAKG,QAAQ,GAAG,KAAK,IAAI,KAAK,OAAO,CAAC;EAC3D,KAAK,aAAa,KAAKR,iBAAiB,KAAK,WAAW,KAAK,KAAK,IAAI;CACxE;;;;;CAMA,aAAa,OAAwB;EACnC,MAAM,UAAU,KAAKK,kBAAkB;EACvC,MAAM,OAAO,MAAM,MAAM,MAAM;EAC/B,IAAI,OAAO,GACT,KAAK,OAAO,KAAK,IAAI,KAAKG,QAAQ,GAAG,KAAK,IAAI,UAAU,MAAM,OAAO,CAAC;EAExE,KAAK,aAAa,KAAKR,iBAAiB,MAAM,KAAK,KAAK,IAAI;CAC9D;;;;;CAMA,WAAW,SAAiB,KAAmB;EAC7C,KAAK,OAAO,KAAK,IAAI,KAAKQ,QAAQ,GAAG,KAAK,IAAI,KAAK,OAAO,CAAC;EAC3D,KAAK,aAAa,KAAKR,iBAAiB,SAAS,KAAK,IAAI;CAC5D;;;;;CAMA,mBAAmB,MAAc,MAAoB;EACnD,KAAKC,oBAAoB,MAAM,IAAI;CACrC;CAEA,YAAkB;EAChB,KAAK,eAAe,IAAI,IAAI,KAAK,gBAAgB,KAAI,MAAK,EAAE,EAAE,CAAC;EAC/D,KAAKe,qBAAqB;EAC1B,KAAKb,kBAAkB;CACzB;CAEA,cAAoB;EAClB,KAAK,+BAAe,IAAI,IAAI;EAC5B,KAAKa,qBAAqB;EAC1B,KAAKb,kBAAkB;CACzB;CAEA,eAAe,UAAmC;EAChD,OAAO,KAAK,gBAAgB,QAAO,MAAK,EAAE,aAAa,QAAQ;CACjE;CAEA,IAAI,cAAiC;EACnC,OAAO,CAAC,GAAG,KAAK,YAAY;CAC9B;CAEA,IAAI,YAAY,KAAwB;EACtC,KAAK,eAAe,IAAI,IAAI,GAAG;EAC/B,KAAKa,qBAAqB;EAC1B,KAAKb,kBAAkB;CACzB;CAEA,YAAY,KAAa,WAAoB,OAAa;EACxD,KAAK,cACH,IAAI,YAAuC,gBAAgB;GACzD,QAAQ;IAAE,UAAU;IAAK;GAAS;GAClC,SAAS;GACT,UAAU;EACZ,CAAC,CACH;CACF;;CAGA,oBAA0B;EACxB,KAAK,wCAAwB,IAAI,IAAI;EACrC,KAAKc,4BAA4B;CAEnC;;EAGoD,KAAA,6BAAA,CAAC;;;EAGd,KAAA,gBAAA,WAAW;GAChD,MAAM,EAAE,gBAAgB,cAAc,eAAe;GACrD,MAAM,EAAE,cAAc;GACtB,OAAO;IACL,OAAO,KAAK,MAAM,eAAe,SAAS,IAAI;IAC9C,KAAK,KAAK,MAAM,aAAa,SAAS,IAAI;GAC5C;EACF;;;;;;;CAOA,YACE,SACA,aACA,MACA,cACA,YACA,iBACA,gBACA,gBACkD;EAClD,IAAI,mBAAmB;EACvB,IAAI,iBAAiB;EACrB,IAAI,sBAAsB;EAE1B,IAAI,KAAK,YAAY;GACnB,MAAM,SAAS,KAAK,WAAW;IAC7B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;GACF,CAAC;GACD,mBAAmB,OAAO,SAAS;GACnC,iBAAiB,OAAO,OAAO;GAC/B,sBAAsB,OAAO,YAAY;EAC3C;EAEA,KAAK,cACH,IAAI,YAAY,YAAY;GAC1B,QAAQ;IACN;IACA,OAAO;IACP,KAAK;IACL,UAAU;IACV;IACA;IACA;GACF;GACA,SAAS;GACT,UAAU;EACZ,CAAC,CACH;EAEA,OAAO;GACL,OAAO;GACP,KAAK;GACL,UAAU;EACZ;CACF;;CAGA,aAAoC;EAClC,OAAO,KAAKX;CACd;;CAGA,IAAI,eAAqC;EACvC,IAAI,KAAK,eAAe,KAAA,GACtB,OAAO;EACT,OAAO,KAAK,gBAAgB,MAAK,MAAK,EAAE,OAAO,KAAK,UAAU,KAAK;CACrE;CAIA,eAAwC;EACtC,KAAKA,WAAW,KAAK,YAAY,cAAc,WAAW;EAE1D,IAAI,KAAKA,UAAU;GACjB,KAAKA,SAAS,eAAe,KAAKY;GAClC,KAAKZ,SAAS,iBAAiB,kBAAkB,KAAKa,gBAAiC;GACvF,KAAKC,uBAAuB,2BAA2B,MAAM,KAAKd,QAAQ;GAK1E,KAAKe,kBAAkB,IAAI,eAAe,KAAKC,SAAS;GACxD,KAAKD,gBAAgB,QAAQ,KAAKf,QAAQ;EAC5C;CACF;CAEA,uBAAsC;EACpC,MAAM,qBAAqB;EAC3B,KAAKc,uBAAuB;EAC5B,KAAKA,uBAAuB;EAC5B,KAAKC,iBAAiB,WAAW;EACjC,KAAKA,kBAAkB;CACzB;;;;;;CAOA,WAA8B,cAAoC;EAEhE,IAAI,uBAAuB;EAC3B,IAAI,yBAAyB;EAC7B,IAAI,2BAA2B;EAE/B,IAAI,aAAa,IAAI,QAAQ,GAAG;GAC9B,KAAK,kBAAkB,CAAC,GAAG,KAAK,MAAM;GACtC,uBAAuB;GACvB,yBAAyB;EAC3B;EACA,IAAI,aAAa,IAAI,QAAQ,GAC3B,KAAK,kBAAkB,CAAC,GAAG,KAAK,MAAM;EAExC,IAAI,aAAa,IAAI,aAAa,GAAG;GAEnC,IAAI,KAAK,gBAAgB,UAAU,KAAK,sBAAsB,OAAO,GACnE,KAAK,wCAAwB,IAAI,IAAI;GAEvC,uBAAuB;GACvB,yBAAyB;EAC3B;EACA,IAAI,aAAa,IAAI,SAAS,KAAK,aAAa,IAAI,oBAAoB,KAAK,aAAa,IAAI,uBAAuB,GACnH,uBAAuB;EAEzB,IAAI,aAAa,IAAI,KAAK,KAAK,aAAa,IAAI,KAAK,GACnD,2BAA2B;EAI7B,IAAI,KAAKJ,2BAA2B;GAClC,KAAKA,4BAA4B;GACjC,yBAAyB;EAC3B;EAGA,IAAI,0BACF,KAAKpB,eAAe;EAGtB,IAAI,wBACF,KAAKC,uBAAuB;EAE9B,IAAI,sBACF,KAAKC,sBAAsB;CAE/B;;;;;CAMA,QAA2B,cAAoC;EAC7D,IAAI,aAAa,IAAI,MAAM,KAAK,aAAa,IAAI,YAAY,KAAK,aAAa,IAAI,KAAK,KAAK,aAAa,IAAI,KAAK,GAAG;GACpH,KAAKG,aAAa;GAClB,KAAKC,kBAAkB;EACzB;EACA,IAAI,aAAa,IAAI,QAAQ,KAAK,aAAa,IAAI,WAAW,KAAK,aAAa,IAAI,YAAY,KAAK,aAAa,IAAI,UAAU,KAAK,aAAa,IAAI,WAAW,GAC/J,KAAKA,kBAAkB;EAEzB,IAAI,aAAa,IAAI,cAAc,GAAG;GACpC,KAAKoB,qBAAqB;GAC1B,KAAKC,cAAc;GACnB,KAAKrB,kBAAkB;EACzB;EAGA,IAAI,aAAa,IAAI,aAAa,KAAK,aAAa,IAAI,SAAS,GAAG;GAClE,KAAKsB,oBAAoB;GACzB,KAAKtB,kBAAkB;EACzB;EAEA,IAAI,KAAK,eAAe,KAAKuB,gBAAgB;GAC3C,KAAKA,iBAAiB,KAAK;GAC3B,KAAK,cACH,IAAI,YAAwC,iBAAiB;IAC3D,QAAQ,EAAE,OAAO,KAAK,aAAa;IACnC,SAAS;IACT,UAAU;GACZ,CAAC,CACH;EACF;CACF;CAEA,SAA4B;EAC1B,MAAM,kBAAkB,KAAKf,oBAAoB;EAEjD,OAAO,IAAI;;;;2BAIY,KAAKgB,oBAAoB;2BACzB,KAAKC,oBAAoB;yBAC3B,KAAKC,kBAAkB;6BACnB,KAAKA,kBAAkB;;;cAGtC,KAAK,gBACJ,QAAO,MAAK,CAAC,EAAE,MAAM,CAAC,CACtB,KAAK,MAAM;GAEV,IAAI,CADW,KAAK,aAAa,MAAK,MAAK,EAAE,aAAa,EAAE,GAClD,GACR,OAAO;GACT,OAAO,IAAI;;6BAEE,EAAE,MAAM;iCACJ,EAAE,IAAI;iCACN,KAAK,gBAAgB,OAAO;mCAC1B,KAAK,YAAY;8BACtB,MAAkB,KAAK,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE;yCAC3C,KAAKC,mBAAmB;oCAC7B,KAAKC,kBAAkB;;;EAG7C,CAAC,EAAE;;;;;;;;mBAQE,gBAAgB;iBAClB,KAAK,YAAY,IAAI;iBACrB,KAAK,YAAY,IAAI;;;;qBAIjB,KAAKC,cAAc;;;;;;;iBAOvB,KAAK,IAAI;iBACT,KAAK,IAAI;eACX,KAAK,WAAW,IAAI;eACpB,KAAK,WAAW,IAAI;;;mBAGhB,KAAKC,cAAc;;;;iCAIL,KAAK,cAAc,YAAY,GAAG;8BACrC,KAAK,cAAc,YAAY,GAAG,kBAAkB,KAAK,YAAY;;CAEjG;;CAKA,iBAAuB;EACrB,MAAM,UAAU,KAAK5B,kBAAkB;EACvC,MAAM,YAAY,KAAK,MAAM,KAAK;EAClC,MAAM,aAAa;EACnB,KAAK,OAAO,YAAY,IAAI,WAAW,YAAY,cAAc;EACjE,KAAK,aAAa;GAAE,KAAK,KAAK;GAAK,KAAK,KAAK,MAAM,YAAY;EAAW;EAC1E,KAAKH,aAAa;CAEpB;CAEA,eAAqB;EACnB,IAAI,CAAC,KAAKI,UACR;EACF,MAAM,YAAY,KAAK,MAAM,KAAK;EAElC,KAAKA,SAAS,eAAe,YAAY,KAAK;EAC9C,KAAKiB,qBAAqB;EAC1B,KAAKW,mBAAmB;CAC1B;;CAGA,uBAA6B;EAC3B,IAAI,CAAC,KAAK5B,UACR;EACF,MAAM,cAAc,KAAK,aAAa,QAAQ,KAAK,OAAO,MAAM,GAAG,QAAQ,CAAC;EAC5E,MAAM,eAAe,KAAK,IAAI,aAAa,EAAE,IAAI,KAAKC;EACtD,KAAKD,SAAS,gBAAgB;EAC9B,KAAKA,SAAS,mBAAmB,KAAKS;CACxC;CAEA,qBAA2B;EACzB,IAAI,CAAC,KAAKT,UACR;EAEF,KAAKA,SAAS,qBAAqB,KAAK,WAAW,MAAM,KAAK,OAAO,KAAK;CAC5E;CAEA,oBAA0B;EACxB,KAAKA,UAAU,cAAc;CAC/B;;CAGA;CAiBA;CAsDA;CAgCA,wBAA8B;EAC5B,MAAM,SAAwB,CAAC;EAC/B,IAAI,IAAI,KAAKC;EACb,KAAK,MAAM,SAAS,KAAK,iBAAiB;GACxC,IAAI,MAAM,QACR;GAEF,MAAM,aADW,KAAK,sBAAsB,IAAI,MAAM,GAC5B,KAAK,MAAM,UAAU,KAAK;GACpD,MAAM,SAAS,KAAK,MAAM,aAAa,KAAK,OAAO;GACnD,OAAO,KAAK;IAAE,UAAU,MAAM;IAAK;IAAG;GAAO,CAAC;GAC9C,KAAK;EACP;EACA,KAAK,eAAe;CACtB;;;;;;CAOA;;;;;;CAgBA;CAOA;CA0BA;CA2BA;;CAQA,sBAA4B;EAC1B,KAAKgB,qBAAqB;EAC1B,KAAKC,cAAc;CACrB;;;;;CAMA,gBAAsB;EACpB,MAAM,YAAY,KAAK,YAAY,cAA2B,aAAa;EAC3E,IAAI,CAAC,WACH;EAEF,MAAM,YAAY,KAAKlB,UAAU,oBAAoB;EACrD,UAAU,MAAM,YAAY,cAAc,CAAC,UAAU;EAErD,KAAK,MAAM,UAAU,KAAK,cAAc;GACtC,MAAM,MAAM,UAAU,cACpB,sCAAsC,OAAO,SAAS,GACxD;GACA,IAAI,CAAC,KACH;GACF,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE;GAC5B,IAAI,MAAM,SAAS,GAAG,OAAO,OAAO;EACtC;CACF;;CAGA,IAAII,YAAoB;EACtB,MAAM,MAAM,iBAAiB,IAAI,CAAC,CAAC,iBAAiB,sBAAsB,CAAC,CAAC,KAAK;EACjF,OAAO,OAAO,SAAS,KAAK,EAAE,KAAK;CACrC;;CAKA;;CAMA;;;;;;;CAmBA,kBAAkB,UAAkB,QAAsB;EACxD,IAAI,KAAK,gBAAgB,SACvB,KAAK,qBAAqB;OACrB,IAAI,KAAK,gBAAgB,QAAQ;GACtC,MAAM,OAAO,IAAI,IAAI,KAAK,qBAAqB;GAC/C,KAAK,IAAI,UAAU,MAAM;GACzB,KAAK,wBAAwB;EAC/B;CAEF;CAEA,uBAA6B;EAC3B,KAAK,cACH,IAAI,YAA2C,oBAAoB;GACjE,QAAQ,EAAE,aAAa,CAAC,GAAG,KAAK,YAAY,EAAE;GAC9C,SAAS;GACT,UAAU;EACZ,CAAC,CACH;CACF;AACF;AA74BG,WAAA,CAAA,SAAS,EAAE,MAAM,MAAM,CAAC,CAAA,GAAA,oBAAA,WAAA,UAAA,KAAA,CAAA;AACxB,WAAA,CAAA,SAAS,EAAE,MAAM,MAAM,CAAC,CAAA,GAAA,oBAAA,WAAA,UAAA,KAAA,CAAA;AACxB,WAAA,CAAA,SAAS,EAAE,MAAM,OAAO,CAAC,CAAA,GAAA,oBAAA,WAAA,OAAA,KAAA,CAAA;AACzB,WAAA,CAAA,SAAS,EAAE,MAAM,OAAO,CAAC,CAAA,GAAA,oBAAA,WAAA,OAAA,KAAA,CAAA;AACzB,WAAA,CAAA,SAAS;CAAE,MAAM;CAAQ,WAAW;AAAe,CAAC,CAAA,GAAA,oBAAA,WAAA,eAAA,KAAA,CAAA;AACpD,WAAA,CAAA,SAAS;CAAE,MAAM;CAAQ,WAAW;AAAa,CAAC,CAAA,GAAA,oBAAA,WAAA,aAAA,KAAA,CAAA;AAClD,WAAA,CAAA,SAAS,EAAE,MAAM,QAAQ,CAAC,CAAA,GAAA,oBAAA,WAAA,eAAA,KAAA,CAAA;AAC1B,WAAA,CAAA,SAAS;CAAE,MAAM;CAAS,WAAW;AAAO,CAAC,CAAA,GAAA,oBAAA,WAAA,eAAA,KAAA,CAAA;AAC7C,WAAA,CAAA,SAAS;CAAE,MAAM;CAAS,WAAW;AAAe,CAAC,CAAA,GAAA,oBAAA,WAAA,cAAA,KAAA,CAAA;AACrD,WAAA,CAAA,SAAS;CAAE,MAAM;CAAQ,WAAW;AAAuB,CAAC,CAAA,GAAA,oBAAA,WAAA,sBAAA,KAAA,CAAA;AAC5D,WAAA,CAAA,SAAS;CAAE,MAAM;CAAQ,WAAW;AAAY,CAAC,CAAA,GAAA,oBAAA,WAAA,YAAA,KAAA,CAAA;AACjD,WAAA,CAAA,SAAS;CAAE,MAAM;CAAQ,WAAW;AAAa,CAAC,CAAA,GAAA,oBAAA,WAAA,aAAA,KAAA,CAAA;AAClD,WAAA,CAAA,SAAS,EAAE,MAAM,OAAO,CAAC,CAAA,GAAA,oBAAA,WAAA,cAAA,KAAA,CAAA;AAWzB,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,QAAA,KAAA,CAAA;AACN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,cAAA,KAAA,CAAA;AAQN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,eAAA,KAAA,CAAA;AACN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,WAAA,KAAA,CAAA;AAEN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,gBAAA,KAAA,CAAA;AACN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,cAAA,KAAA,CAAA;AACN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,SAAA,KAAA,CAAA;AACN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,eAAA,KAAA,CAAA;AACN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,yBAAA,KAAA,CAAA;AACN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,gBAAA,KAAA,CAAA;AACN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,mBAAA,KAAA,CAAA;AACN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,mBAAA,KAAA,CAAA;AA/CRyB,sBAAAA,WAAAA,CAAAA,kBAAc,eAAe,CAAA,GAAA,mBAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"titlebar-B5zSTZnF.d.ts","names":[],"sources":["../src/titlebar/titlebar.ts"],"mappings":";;;KAOY;KACA;KACA;UAEK;WACN;;KAGC,sBAAsB,YAAY;KAClC,qBAAqB;UAEhB;EACf,QAAQ;EACR,OAAO;;;;;;;;;;;;;;cAgBI,wBAAwB;EACP;EACwB;EACiB,aAAa;EACjB,SAAS;EAC7C;;EAEe;EACA;EACiB,mBAAmB;UAExE;UAaA;UASA;YAIW,wBAAM;SAkET,sBAAM;;QA4RhB;YACI;IACR,iBAAiB;;;UAIJ;EACf,oBAAoB,gBAAgB,yBAClC,MAAM,GACN,WAAW,MAAM,iBAAiB,OAAO,wBAAwB,aACjE,oBAAoB,sCAEpB,cACA,UAAU,oCACV,oBAAoB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"titlebar.js","names":["customElement"],"sources":["../src/titlebar/titlebar.ts"],"sourcesContent":["/* eslint-disable ts/no-unsafe-declaration-merging */\nimport { css, html, LitElement, nothing } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\nimport '../icons/icon.js';\n\nexport type TitlebarOrientation = `horizontal` | `vertical`;\nexport type TitlebarVariant = `titlebar` | `midline` | `tree`;\nexport type TitlebarToggleInteraction = `implicit` | `explicit` | `disabled`;\n\nexport interface TitlebarToggleDetail {\n readonly collapsed: boolean;\n}\n\nexport type TitlebarToggleEvent = CustomEvent<TitlebarToggleDetail>;\nexport type TitlebarCloseEvent = CustomEvent<void>;\n\nexport interface TitlebarElementEventMap {\n toggle: TitlebarToggleEvent;\n close: TitlebarCloseEvent;\n}\n\n/**\n * Standalone titlebar chrome: title, icon, toolbar slot, close button and\n * optional collapse/expand caret. Extracted from `ixfx-panel`.\n *\n * Collapsing is opt-in via `collapsible`. When absent, no caret is shown and\n * `toggle-interaction` is inert. `close` is fired without removing the\n * element — the host decides what closing means.\n *\n * CSS variables\n * `--titlebar-background` – bar fill (default: `var(--surface-4)`).\n * Set to `transparent` for a translucent header over blurred content.\n */\n@customElement(`ixfx-titlebar`)\nexport class TitlebarElement extends LitElement {\n @property({ type: String }) title = ``;\n @property({ type: String, attribute: `icon-name` }) iconName = ``;\n @property({ type: String, attribute: `orientation`, reflect: true }) orientation: TitlebarOrientation = `horizontal`;\n @property({ type: String, attribute: `variant`, reflect: true }) variant: TitlebarVariant = `titlebar`;\n @property({ type: Boolean }) closable = false;\n /** Show the collapse/expand caret and enable toggle behaviour. */\n @property({ type: Boolean, reflect: true }) collapsible = false;\n @property({ type: Boolean, reflect: true }) collapsed = false;\n @property({ type: String, attribute: `toggle-interaction` }) toggleInteraction: TitlebarToggleInteraction = `implicit`;\n\n private _onToggleClick() {\n if (!this.collapsible)\n return;\n this.collapsed = !this.collapsed;\n this.dispatchEvent(\n new CustomEvent<TitlebarToggleDetail>(`toggle`, {\n detail: { collapsed: this.collapsed },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private _onCloseClick() {\n this.dispatchEvent(\n new CustomEvent<void>(`close`, {\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private _getCaretIcon(): string {\n return `chevron-down`;\n }\n\n protected override render() {\n const caretIcon = this._getCaretIcon();\n const isVertical = this.orientation === `vertical`;\n const showCaret = this.collapsible && this.toggleInteraction !== `disabled`;\n const implicitToggle = this.collapsible && this.toggleInteraction === `implicit`;\n\n const caretRotation = isVertical\n ? (this.collapsed ? `` : `-90deg`)\n : (this.collapsed ? `-90deg` : ``);\n\n const treeVariant = this.variant === `tree`;\n\n return html`\n <div\n class=\"bar\"\n role=\"toolbar\"\n @click=${implicitToggle ? this._onToggleClick : nothing}\n >\n ${treeVariant && showCaret\n ? html`\n <button\n class=\"caret-btn\"\n type=\"button\"\n aria-label=${this.collapsed ? `Expand panel` : `Collapse panel`}\n @click=${this._onToggleClick}\n >\n <ixfx-icon name=${caretIcon} prominence .rotate=${caretRotation.length > 0 ? caretRotation : nothing}></ixfx-icon>\n </button>\n `\n : nothing}\n <div class=\"title-text-wrapper\">\n ${this.iconName ? html`<ixfx-icon class=\"title-icon\" name=${this.iconName}></ixfx-icon>` : nothing}\n <span class=\"title-text\">${this.title}</span>\n </div>\n\n <div class=\"toolbar\" @click=${(e: Event) => e.stopPropagation()}>\n <slot name=\"toolbar\"></slot>\n ${this.closable\n ? html`\n <button\n class=\"close-btn\"\n type=\"button\"\n aria-label=\"Close panel\"\n @click=${this._onCloseClick}\n >\n <ixfx-icon name=\"close\"></ixfx-icon>\n </button>\n `\n : nothing}\n ${!treeVariant && showCaret\n ? html`\n <button\n class=\"caret-btn\"\n type=\"button\"\n aria-label=${this.collapsed ? `Expand panel` : `Collapse panel`}\n @click=${this._onToggleClick}\n >\n <ixfx-icon name=${caretIcon} prominence .rotate=${caretRotation.length > 0 ? caretRotation : nothing}></ixfx-icon>\n </button>\n `\n : nothing}\n </div>\n </div>\n `;\n }\n\n static override styles = [themeFallbacks, css`\n :host {\n --titlebar-background: var(--surface-4);\n\n display: block;\n box-sizing: border-box;\n }\n\n .bar {\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: var(--space-s) var(--space-m);\n background: var(--titlebar-background);\n color: var(--surface-3-text);\n min-height: 2em;\n height: 100%;\n flex-shrink: 0;\n box-sizing: border-box;\n }\n\n :host([orientation=\"vertical\"]) .bar {\n flex-direction: row;\n min-width: 2em;\n writing-mode: vertical-rl;\n text-orientation: mixed;\n }\n\n .caret-btn,\n .close-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n padding: var(--space-xs);\n margin: 0;\n cursor: pointer;\n color: inherit;\n border-radius: var(--radius-s);\n transition: background var(--transition);\n opacity: var(--prominence-idle-opacity);\n }\n\n .caret-btn:hover,\n .close-btn:hover {\n background: var(--surface-5);\n opacity: var(--prominence-tickled-opacity);\n }\n\n .caret-btn:focus-visible,\n .close-btn:focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 1px;\n }\n\n ixfx-icon {\n width: 1.25em;\n height: 1.25em;\n transition: transform var(--transition);\n }\n\n .title-icon {\n flex-shrink: 0;\n }\n\n .title-text {\n flex: 1;\n padding-left: 1ch;\n font-family: var(--font-family);\n font-size: var(--text-m);\n font-weight: var(--font-weight-bold, 600);\n white-space: nowrap;\n overflow: hidden;\n align-self: center;\n text-overflow: ellipsis;\n user-select: none;\n -webkit-user-select: none;\n }\n\n :host([collapsible][toggle-interaction=\"implicit\"]) .bar {\n cursor: pointer;\n }\n\n :host([orientation=\"vertical\"]) .title-text {\n writing-mode: vertical-rl;\n padding-left: 0;\n padding-bottom: 1ch;\n text-orientation: mixed;\n transform: rotate(180deg);\n }\n\n .toolbar {\n display: flex;\n align-items: center;\n gap: var(--space-xs);\n margin-left: auto;\n }\n\n :host([orientation=\"vertical\"]) .toolbar {\n flex-direction: column;\n margin-left: 0;\n margin-top: auto;\n writing-mode: horizontal-tb;\n }\n\n slot[name=\"toolbar\"] {\n display: contents;\n }\n\n ::slotted(slot[name=\"toolbar\"]) {\n display: contents;\n }\n\n .title-text-wrapper {\n display: flex;\n padding: 0 var(--space-s);\n }\n\n /* === Midline variant === */\n\n :host([variant=\"midline\"]) .bar {\n background: transparent;\n padding: var(--space-xs) var(--space-m);\n min-height: unset;\n position: relative;\n }\n\n :host([variant=\"midline\"][orientation=\"vertical\"]) .bar {\n padding: var(--space-m) var(--space-xs);\n min-width: unset;\n }\n\n :host([variant=\"midline\"]) .title-text-wrapper {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: var(--space-s);\n background: var(--surface-3);\n }\n\n :host([variant=\"midline\"]) .title-text {\n font-weight: normal;\n color: var(--surface-3-text);\n padding: 0 0.5ch 0 0.5ch;\n background: transparent;\n box-shadow: none;\n flex: unset;\n width: auto;\n white-space: nowrap;\n }\n\n :host([variant=\"midline\"]) .title-icon {\n background: transparent;\n flex-shrink: 0;\n }\n\n :host([variant=\"midline\"]) .caret-btn {\n position: relative;\n z-index: 1;\n background: var(--surface-3);\n opacity: 1;\n }\n\n :host([variant=\"midline\"][orientation=\"vertical\"]) .title-text {\n transform: rotate(180deg);\n padding: 0.5ch 0 0.5ch 0ch;\n }\n\n :host([variant=\"midline\"]) .toolbar {\n position: relative;\n z-index: 2;\n background: var(--surface-3);\n margin-left: 0;\n }\n\n :host([variant=\"midline\"][orientation=\"horizontal\"]) .toolbar {\n margin-left: auto;\n }\n\n /* Debossed line runs from after title-text to before toolbar */\n :host([variant=\"midline\"]) .bar::after {\n content: '';\n position: absolute;\n top: 50%;\n left: 0;\n right: 0;\n height: 1px;\n transform: translateY(-50%);\n background: var(--surface-2);\n box-shadow:\n 0 -1px 0 var(--surface-5),\n 0 1px 0 var(--surface-1);\n z-index: 0;\n }\n\n /* For vertical midline, line runs vertically */\n :host([variant=\"midline\"][orientation=\"vertical\"]) .bar::after {\n top: 0;\n bottom: 0;\n left: 50%;\n right: unset;\n width: 1px;\n height: 100%;\n transform: translateX(-50%);\n box-shadow:\n -1px 0 0 var(--surface-5),\n 1px 0 0 var(--surface-1);\n }\n\n /* === Tree variant: VS Code explorer / Outline style === */\n :host([variant=\"tree\"]) .bar {\n background: transparent;\n padding: 0 var(--space-xs);\n min-height: unset;\n gap: var(--space-xs);\n }\n\n :host([variant=\"tree\"][orientation=\"vertical\"]) .bar {\n padding: var(--space-xs) 0;\n flex-direction: column;\n min-width: unset;\n writing-mode: horizontal-tb;\n }\n\n :host([variant=\"tree\"]) .title-text-wrapper {\n display: inline-flex;\n align-items: center;\n gap: var(--space-xs);\n padding: 0;\n background: transparent;\n }\n\n :host([variant=\"tree\"]) .title-icon {\n background: transparent;\n flex-shrink: 0;\n }\n\n :host([variant=\"tree\"]) .title-text {\n font-weight: normal;\n color: var(--surface-3-text);\n padding: 0;\n background: transparent;\n box-shadow: none;\n flex: unset;\n width: auto;\n white-space: nowrap;\n }\n\n :host([variant=\"tree\"][orientation=\"vertical\"]) .title-text {\n writing-mode: vertical-rl;\n transform: rotate(180deg);\n padding: 0;\n }\n\n :host([variant=\"tree\"]) .caret-btn {\n background: transparent;\n opacity: var(--prominence-idle-opacity);\n padding: 0;\n }\n\n :host([variant=\"tree\"]) .caret-btn:hover {\n background: transparent;\n opacity: var(--prominence-tickled-opacity);\n }\n\n :host([variant=\"tree\"]) .toolbar {\n margin-left: auto;\n }\n\n :host([variant=\"tree\"][orientation=\"vertical\"]) .toolbar {\n flex-direction: row;\n margin-left: 0;\n margin-top: auto;\n }\n\n :host([variant=\"tree\"]) ixfx-icon {\n width: 1em;\n height: 1em;\n }\n `];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-titlebar': TitlebarElement;\n }\n}\n\nexport interface TitlebarElement {\n addEventListener: (<K extends keyof TitlebarElementEventMap>(\n type: K,\n listener: (this: TitlebarElement, event: TitlebarElementEventMap[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 +0,0 @@
1
- {"version":3,"file":"tooltip-BlvBUQxx.d.ts","names":[],"sources":["../src/util/tooltip.ts"],"mappings":";;KAQY,uBAAuB;KACvB;cAoCC,uBAAuB;;EACzB;SAKF,kBAAmB;SAEnB,kBAAkB;EAYzB,oBAAoB;EAGpB,aAAa;EAGb;EAGA;EAGA;YAgBU,wBAAM;YA+BN;;QAKJ;YACI;IACR,gBAAgB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tooltip-CJt3WLmN.js","names":[],"sources":["../src/styles/tooltip.ts"],"sourcesContent":["import { css } from \"lit\";\n\nexport const tooltipValueStyles = css`\n\n output.tooltip {\n user-select: none;\n position: fixed;\n position-anchor: var(--anchor-id);\n }\n\n .tooltip-type-number {\n font-family: monospace;\n }\n\n .tooltip-orientation-top { \n position-area: block-start;\n margin-block: -100%;\n }\n\n .tooltip-orientation-bottom { \n position-area: block-end;\n margin-block: 10px;\n }\n\n .tooltip-orientation-right { \n position-area: inline-end;\n margin-inline: 10px;\n }\n\n .tooltip-orientation-left { \n position-area: inline-start;\n margin-inline: -100%;\n }\n\n ixfx-tooltip {\n --tooltip-background: var(--surface-5);\n --tooltip-color: var(--surface-5-text);\n opacity: 0;\n transition: opacity .2s ease, translate .2s ease;\n color: var(--tooltip-color);\n pointer-events: none;\n font-variant-numeric: tabular-nums;\n\n button:is(:hover, :focus-visible) + & {\n opacity:1;\n }\n\n input:is(:hover, :focus-visible) + & {\n opacity:1;\n }\n }\n \n .tooltip-style-bubble {\n padding-block: .5ex;\n padding-inline: 1ex;\n \n /* tether arrow styles */\n /* https://www.smashingmagazine.com/2024/01/css-border-image-property/ */\n --b: 1ex; \n --h: 1ex; \n\n border-image: fill 0//var(--h) conic-gradient(var(--tooltip-background) 0 0); \n \n &.tooltip-orientation-top {\n margin-block-end: 1ex;\n clip-path: \n polygon(0 100%,0 0,100% 0,100% 100%,\n calc(50% + var(--b)/2) 100%,\n 50% calc(100% + var(--h)),\n calc(50% - var(--b)/2) 100%);\n }\n \n &.tooltip-orientation-right {\n margin-inline-start: 1ex;\n clip-path: \n polygon(0 100%,100% 100%,100% 0,0 0,\n 0 calc(50% - var(--b)/2),\n calc(-1*var(--h)) 50%,\n 0 calc(50% + var(--b)/2));\n }\n \n &.tooltip-orientation-bottom {\n margin-block-start: 1ex;\n clip-path: \n polygon(0 0,100% 0,100% 100%,0 100%,\n calc(50% - var(--b)/2) 0,\n 50% calc(-1*var(--h)),\n calc(50% + var(--b)/2) 0);\n }\n \n &.tooltip-orientation-left {\n margin-inline-end: 1ex;\n clip-path: \n polygon(0 0,100% 0,100% 100%,0 100%,\n 100% calc(50% - var(--b)/2),\n calc(100% + var(--h)) 50%,\n 100% calc(50% + var(--b)/2));\n }\n } \n `;"],"mappings":";;AAEA,MAAa,qBAAqB,GAAG"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"transitory-label.d.ts","names":[],"sources":["../src/transitory-label/transitory-label.ts"],"mappings":";;KAMY;cAKC,+BAA+B;;EACd;EACA,QAAQ;EACR;EACA;UAEX;UACA;UACA;UACA;UAET;UACA;EAER,QAAQ,aAAa,QAAQ;YAKV,QAAQ,SAAS;UAa5B;UAWA;YAgDW,wBAAM;SA4BT,sBAAM;;QAuIhB;YACI;IACR,yBAAyB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"transitory-label.js","names":["#onLastCharOut","#renderCharSwap","#onOutgoingEnd","customElement"],"sources":["../src/transitory-label/transitory-label.ts"],"sourcesContent":["import type { PropertyValues } from 'lit';\nimport { css, html, LitElement, nothing } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { keyed } from 'lit/directives/keyed.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\n\nexport type Effect = `slide-right` | `slide-left` | `slide-up` | `slide-down` | `fade` | `character-swap`;\n\ntype QueueEntry = { text: string; effect: Effect };\n\n@customElement(`ixfx-transitory-label`)\nexport class TransitoryLabelElement extends LitElement {\n @property({ type: String }) text = ``;\n @property({ type: String }) effect: Effect = `fade`;\n @property({ type: Number }) duration = 300;\n @property({ type: String }) easing = `ease`;\n\n @state() private _currentText = ``;\n @state() private _outgoingText = ``;\n @state() private _activeEffect: Effect | undefined;\n @state() private _transitionId = 0;\n\n private _queue: QueueEntry[] = [];\n private _pendingEffect: Effect | undefined;\n\n setText(msg: string, effect: Effect): void {\n this._pendingEffect = effect;\n this.text = msg;\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(`text`) && this.text !== this._currentText) {\n const effect = this._pendingEffect ?? this.effect;\n this._pendingEffect = undefined;\n\n if (this._activeEffect !== undefined) {\n this._queue.push({ text: this.text, effect });\n } else {\n this._startTransition(this.text, effect);\n }\n }\n }\n\n private _startTransition(newText: string, effect: Effect): void {\n const prevText = this._currentText;\n this._currentText = newText;\n this._outgoingText = prevText;\n\n if (prevText !== ``) {\n this._transitionId++;\n this._activeEffect = effect;\n }\n }\n\n private _onTransitionEnd(): void {\n this._outgoingText = ``;\n this._activeEffect = undefined;\n\n if (this._queue.length > 0) {\n const next = this._queue.shift()!;\n this._startTransition(next.text, next.effect);\n }\n }\n\n #onOutgoingEnd = (): void => {\n this._onTransitionEnd();\n };\n\n #onLastCharOut = (): void => {\n this._onTransitionEnd();\n };\n\n #renderCharSwap() {\n const charDuration = Math.round(this.duration * 0.3);\n const charStagger = Math.round(this.duration * 0.1);\n const currentChars = this._currentText.split(``);\n const outgoingChars = this._outgoingText.split(``);\n const lastIdx = outgoingChars.length - 1;\n\n const charStyle = (i: number) =>\n `animation-duration:${charDuration}ms;animation-delay:${i * charStagger}ms;animation-timing-function:${this.easing}`;\n\n return html`\n ${keyed(`cc${this._transitionId}`, html`\n <span class=\"layer current char-swap\">\n ${currentChars.map((ch, i) => html`<span class=\"char in\" style=${charStyle(i)}>${ch}</span>`)}\n </span>\n `)}\n ${this._outgoingText\n ? keyed(this._transitionId, html`\n <span class=\"layer outgoing char-swap\">\n ${outgoingChars.map((ch, i) => html`<span\n class=\"char out\"\n style=${charStyle(i)}\n @animationend=${i === lastIdx ? this.#onLastCharOut : undefined}\n >${ch}</span>`)}\n </span>\n `)\n : nothing}\n `;\n }\n\n protected override render() {\n if (this._activeEffect === `character-swap`) {\n return html`<span class=\"container\">${this.#renderCharSwap()}</span>`;\n }\n\n const effect = this._activeEffect ?? ``;\n const durStyle = this._activeEffect\n ? `animation-duration:${this.duration}ms;animation-timing-function:${this.easing}`\n : ``;\n\n return html`\n <span class=\"container\">\n ${this._outgoingText\n ? keyed(this._transitionId, html`\n <span class=\"layer outgoing ${effect}\" style=${durStyle} @animationend=${this.#onOutgoingEnd}>\n ${this._outgoingText}\n </span>\n `)\n : nothing}\n ${keyed(`c${this._transitionId}`, html`\n <span class=\"layer current ${effect}\" style=${durStyle}>\n ${this._currentText}\n </span>\n `)}\n </span>\n `;\n }\n\n static override styles = css`\n :host {\n display: inline-block;\n --transitory-label-easing: ease;\n }\n\n .container {\n display: inline-grid;\n overflow: hidden;\n }\n\n .layer {\n grid-area: 1 / 1;\n white-space: nowrap;\n }\n\n .layer.outgoing {\n pointer-events: none;\n }\n\n /* slide-right */\n .layer.current.slide-right {\n transform: translateX(-100%);\n animation: tl-slide-in-left var(--transitory-label-easing) forwards;\n }\n .layer.outgoing.slide-right {\n animation: tl-slide-out-right var(--transitory-label-easing) forwards;\n }\n\n @keyframes tl-slide-in-left {\n from { transform: translateX(-100%); }\n to { transform: translateX(0); }\n }\n @keyframes tl-slide-out-right {\n from { transform: translateX(0); }\n to { transform: translateX(100%); }\n }\n\n /* slide-left */\n .layer.current.slide-left {\n transform: translateX(100%);\n animation: tl-slide-in-right var(--transitory-label-easing) forwards;\n }\n .layer.outgoing.slide-left {\n animation: tl-slide-out-left var(--transitory-label-easing) forwards;\n }\n\n @keyframes tl-slide-in-right {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n }\n @keyframes tl-slide-out-left {\n from { transform: translateX(0); }\n to { transform: translateX(-100%); }\n }\n\n /* slide-up */\n .layer.current.slide-up {\n transform: translateY(100%);\n animation: tl-slide-in-bottom var(--transitory-label-easing) forwards;\n }\n .layer.outgoing.slide-up {\n animation: tl-slide-out-top var(--transitory-label-easing) forwards;\n }\n\n @keyframes tl-slide-in-bottom {\n from { transform: translateY(100%); }\n to { transform: translateY(0); }\n }\n @keyframes tl-slide-out-top {\n from { transform: translateY(0); }\n to { transform: translateY(-100%); }\n }\n\n /* slide-down */\n .layer.current.slide-down {\n transform: translateY(-100%);\n animation: tl-slide-in-top var(--transitory-label-easing) forwards;\n }\n .layer.outgoing.slide-down {\n animation: tl-slide-out-bottom var(--transitory-label-easing) forwards;\n }\n\n @keyframes tl-slide-in-top {\n from { transform: translateY(-100%); }\n to { transform: translateY(0); }\n }\n @keyframes tl-slide-out-bottom {\n from { transform: translateY(0); }\n to { transform: translateY(100%); }\n }\n\n /* fade */\n .layer.current.fade {\n opacity: 0;\n animation: tl-fade-in var(--transitory-label-easing) forwards;\n }\n .layer.outgoing.fade {\n animation: tl-fade-out var(--transitory-label-easing) forwards;\n }\n\n @keyframes tl-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n @keyframes tl-fade-out {\n from { opacity: 1; }\n to { opacity: 0; }\n }\n\n /* character-swap */\n .char {\n display: inline-block;\n }\n\n .char.in {\n opacity: 0;\n animation: tl-char-in var(--transitory-label-easing) forwards;\n }\n\n .char.out {\n animation: tl-char-out var(--transitory-label-easing) forwards;\n }\n\n @keyframes tl-char-in {\n from { opacity: 0; transform: translateY(-0.3em) scale(0.8); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n }\n @keyframes tl-char-out {\n from { opacity: 1; transform: translateY(0) scale(1); }\n to { opacity: 0; transform: translateY(0.3em) scale(0.8); }\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-transitory-label': TransitoryLabelElement;\n }\n}\n"],"mappings":"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"}