@react-x11/components 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (783) hide show
  1. package/README.md +979 -21
  2. package/dist/ansi/cast.d.ts +48 -0
  3. package/dist/ansi/cast.d.ts.map +1 -0
  4. package/dist/ansi/cast.js +135 -0
  5. package/dist/ansi/cast.js.map +1 -0
  6. package/dist/ansi/index.d.ts +10 -0
  7. package/dist/ansi/index.d.ts.map +1 -0
  8. package/dist/ansi/index.js +27 -0
  9. package/dist/ansi/index.js.map +1 -0
  10. package/dist/ansi/palette.d.ts +79 -0
  11. package/dist/ansi/palette.d.ts.map +1 -0
  12. package/dist/ansi/palette.js +155 -0
  13. package/dist/ansi/palette.js.map +1 -0
  14. package/dist/ansi/parse.d.ts +114 -0
  15. package/dist/ansi/parse.d.ts.map +1 -0
  16. package/dist/ansi/parse.js +687 -0
  17. package/dist/ansi/parse.js.map +1 -0
  18. package/dist/ansi/sgr.d.ts +87 -0
  19. package/dist/ansi/sgr.d.ts.map +1 -0
  20. package/dist/ansi/sgr.js +302 -0
  21. package/dist/ansi/sgr.js.map +1 -0
  22. package/dist/ansi/utf8.d.ts +15 -0
  23. package/dist/ansi/utf8.d.ts.map +1 -0
  24. package/dist/ansi/utf8.js +82 -0
  25. package/dist/ansi/utf8.js.map +1 -0
  26. package/dist/calendar/Calendar.d.ts +136 -0
  27. package/dist/calendar/Calendar.d.ts.map +1 -0
  28. package/dist/calendar/Calendar.js +460 -0
  29. package/dist/calendar/Calendar.js.map +1 -0
  30. package/dist/calendar/DatePicker.d.ts +52 -0
  31. package/dist/calendar/DatePicker.d.ts.map +1 -0
  32. package/dist/calendar/DatePicker.js +257 -0
  33. package/dist/calendar/DatePicker.js.map +1 -0
  34. package/dist/calendar/dates.d.ts +90 -0
  35. package/dist/calendar/dates.d.ts.map +1 -0
  36. package/dist/calendar/dates.js +236 -0
  37. package/dist/calendar/dates.js.map +1 -0
  38. package/dist/calendar/index.d.ts +8 -0
  39. package/dist/calendar/index.d.ts.map +1 -0
  40. package/dist/calendar/index.js +15 -0
  41. package/dist/calendar/index.js.map +1 -0
  42. package/dist/charts/components.d.ts +141 -0
  43. package/dist/charts/components.d.ts.map +1 -0
  44. package/dist/charts/components.js +580 -0
  45. package/dist/charts/components.js.map +1 -0
  46. package/dist/charts/data.d.ts +198 -0
  47. package/dist/charts/data.d.ts.map +1 -0
  48. package/dist/charts/data.js +616 -0
  49. package/dist/charts/data.js.map +1 -0
  50. package/dist/charts/hx.d.ts +21 -0
  51. package/dist/charts/hx.d.ts.map +1 -0
  52. package/dist/charts/hx.js +15 -0
  53. package/dist/charts/hx.js.map +1 -0
  54. package/dist/charts/index.d.ts +27 -0
  55. package/dist/charts/index.d.ts.map +1 -0
  56. package/dist/charts/index.js +38 -0
  57. package/dist/charts/index.js.map +1 -0
  58. package/dist/charts/node.d.ts +96 -0
  59. package/dist/charts/node.d.ts.map +1 -0
  60. package/dist/charts/node.js +720 -0
  61. package/dist/charts/node.js.map +1 -0
  62. package/dist/charts/render.d.ts +153 -0
  63. package/dist/charts/render.d.ts.map +1 -0
  64. package/dist/charts/render.js +762 -0
  65. package/dist/charts/render.js.map +1 -0
  66. package/dist/charts/scale.d.ts +42 -0
  67. package/dist/charts/scale.d.ts.map +1 -0
  68. package/dist/charts/scale.js +173 -0
  69. package/dist/charts/scale.js.map +1 -0
  70. package/dist/charts/spec.d.ts +91 -0
  71. package/dist/charts/spec.d.ts.map +1 -0
  72. package/dist/charts/spec.js +33 -0
  73. package/dist/charts/spec.js.map +1 -0
  74. package/dist/charts/timers.d.ts +6 -0
  75. package/dist/charts/timers.d.ts.map +1 -0
  76. package/dist/charts/timers.js +14 -0
  77. package/dist/charts/timers.js.map +1 -0
  78. package/dist/code/hx.d.ts +24 -0
  79. package/dist/code/hx.d.ts.map +1 -0
  80. package/dist/code/hx.js +25 -0
  81. package/dist/code/hx.js.map +1 -0
  82. package/dist/code/index.d.ts +45 -0
  83. package/dist/code/index.d.ts.map +1 -0
  84. package/dist/code/index.js +93 -0
  85. package/dist/code/index.js.map +1 -0
  86. package/dist/code-editor/completion.d.ts +26 -0
  87. package/dist/code-editor/completion.d.ts.map +1 -0
  88. package/dist/code-editor/completion.js +129 -0
  89. package/dist/code-editor/completion.js.map +1 -0
  90. package/dist/code-editor/doc.d.ts +35 -0
  91. package/dist/code-editor/doc.d.ts.map +1 -0
  92. package/dist/code-editor/doc.js +162 -0
  93. package/dist/code-editor/doc.js.map +1 -0
  94. package/dist/code-editor/hx.d.ts +13 -0
  95. package/dist/code-editor/hx.d.ts.map +1 -0
  96. package/dist/code-editor/hx.js +10 -0
  97. package/dist/code-editor/hx.js.map +1 -0
  98. package/dist/code-editor/index.d.ts +88 -0
  99. package/dist/code-editor/index.d.ts.map +1 -0
  100. package/dist/code-editor/index.js +401 -0
  101. package/dist/code-editor/index.js.map +1 -0
  102. package/dist/code-editor/node.d.ts +343 -0
  103. package/dist/code-editor/node.d.ts.map +1 -0
  104. package/dist/code-editor/node.js +1521 -0
  105. package/dist/code-editor/node.js.map +1 -0
  106. package/dist/code-language/hljs.d.ts +47 -0
  107. package/dist/code-language/hljs.d.ts.map +1 -0
  108. package/dist/code-language/hljs.js +211 -0
  109. package/dist/code-language/hljs.js.map +1 -0
  110. package/dist/code-language/index.d.ts +22 -0
  111. package/dist/code-language/index.d.ts.map +1 -0
  112. package/dist/code-language/index.js +20 -0
  113. package/dist/code-language/index.js.map +1 -0
  114. package/dist/code-language/languages/glsl.d.ts +4 -0
  115. package/dist/code-language/languages/glsl.d.ts.map +1 -0
  116. package/dist/code-language/languages/glsl.js +99 -0
  117. package/dist/code-language/languages/glsl.js.map +1 -0
  118. package/dist/code-language/languages/javascript.d.ts +10 -0
  119. package/dist/code-language/languages/javascript.d.ts.map +1 -0
  120. package/dist/code-language/languages/javascript.js +360 -0
  121. package/dist/code-language/languages/javascript.js.map +1 -0
  122. package/dist/code-language/languages/json.d.ts +4 -0
  123. package/dist/code-language/languages/json.d.ts.map +1 -0
  124. package/dist/code-language/languages/json.js +68 -0
  125. package/dist/code-language/languages/json.js.map +1 -0
  126. package/dist/code-language/languages/shell.d.ts +4 -0
  127. package/dist/code-language/languages/shell.d.ts.map +1 -0
  128. package/dist/code-language/languages/shell.js +189 -0
  129. package/dist/code-language/languages/shell.js.map +1 -0
  130. package/dist/code-language/languages/sql.d.ts +11 -0
  131. package/dist/code-language/languages/sql.d.ts.map +1 -0
  132. package/dist/code-language/languages/sql.js +133 -0
  133. package/dist/code-language/languages/sql.js.map +1 -0
  134. package/dist/code-language/lezer.d.ts +24 -0
  135. package/dist/code-language/lezer.d.ts.map +1 -0
  136. package/dist/code-language/lezer.js +148 -0
  137. package/dist/code-language/lezer.js.map +1 -0
  138. package/dist/code-language/registry.d.ts +19 -0
  139. package/dist/code-language/registry.d.ts.map +1 -0
  140. package/dist/code-language/registry.js +56 -0
  141. package/dist/code-language/registry.js.map +1 -0
  142. package/dist/code-language/runs.d.ts +35 -0
  143. package/dist/code-language/runs.d.ts.map +1 -0
  144. package/dist/code-language/runs.js +88 -0
  145. package/dist/code-language/runs.js.map +1 -0
  146. package/dist/code-language/stream.d.ts +70 -0
  147. package/dist/code-language/stream.d.ts.map +1 -0
  148. package/dist/code-language/stream.js +243 -0
  149. package/dist/code-language/stream.js.map +1 -0
  150. package/dist/code-language/textmate.d.ts +27 -0
  151. package/dist/code-language/textmate.d.ts.map +1 -0
  152. package/dist/code-language/textmate.js +86 -0
  153. package/dist/code-language/textmate.js.map +1 -0
  154. package/dist/code-language/theme.d.ts +26 -0
  155. package/dist/code-language/theme.d.ts.map +1 -0
  156. package/dist/code-language/theme.js +108 -0
  157. package/dist/code-language/theme.js.map +1 -0
  158. package/dist/code-language/timers.d.ts +7 -0
  159. package/dist/code-language/timers.d.ts.map +1 -0
  160. package/dist/code-language/timers.js +22 -0
  161. package/dist/code-language/timers.js.map +1 -0
  162. package/dist/code-language/types.d.ts +173 -0
  163. package/dist/code-language/types.d.ts.map +1 -0
  164. package/dist/code-language/types.js +41 -0
  165. package/dist/code-language/types.js.map +1 -0
  166. package/dist/codeblock/index.d.ts +69 -0
  167. package/dist/codeblock/index.d.ts.map +1 -0
  168. package/dist/codeblock/index.js +85 -0
  169. package/dist/codeblock/index.js.map +1 -0
  170. package/dist/color-picker/ColorField.d.ts +39 -0
  171. package/dist/color-picker/ColorField.d.ts.map +1 -0
  172. package/dist/color-picker/ColorField.js +239 -0
  173. package/dist/color-picker/ColorField.js.map +1 -0
  174. package/dist/color-picker/ColorPicker.d.ts +109 -0
  175. package/dist/color-picker/ColorPicker.d.ts.map +1 -0
  176. package/dist/color-picker/ColorPicker.js +757 -0
  177. package/dist/color-picker/ColorPicker.js.map +1 -0
  178. package/dist/color-picker/color.d.ts +105 -0
  179. package/dist/color-picker/color.d.ts.map +1 -0
  180. package/dist/color-picker/color.js +313 -0
  181. package/dist/color-picker/color.js.map +1 -0
  182. package/dist/color-picker/index.d.ts +8 -0
  183. package/dist/color-picker/index.d.ts.map +1 -0
  184. package/dist/color-picker/index.js +19 -0
  185. package/dist/color-picker/index.js.map +1 -0
  186. package/dist/desktop-calendar/eds.d.ts +102 -0
  187. package/dist/desktop-calendar/eds.d.ts.map +1 -0
  188. package/dist/desktop-calendar/eds.js +356 -0
  189. package/dist/desktop-calendar/eds.js.map +1 -0
  190. package/dist/desktop-calendar/ical.d.ts +63 -0
  191. package/dist/desktop-calendar/ical.d.ts.map +1 -0
  192. package/dist/desktop-calendar/ical.js +57 -0
  193. package/dist/desktop-calendar/ical.js.map +1 -0
  194. package/dist/desktop-calendar/index.d.ts +72 -0
  195. package/dist/desktop-calendar/index.d.ts.map +1 -0
  196. package/dist/desktop-calendar/index.js +213 -0
  197. package/dist/desktop-calendar/index.js.map +1 -0
  198. package/dist/embed/client.d.ts +121 -0
  199. package/dist/embed/client.d.ts.map +1 -0
  200. package/dist/embed/client.js +203 -0
  201. package/dist/embed/client.js.map +1 -0
  202. package/dist/embed/host.d.ts +96 -0
  203. package/dist/embed/host.d.ts.map +1 -0
  204. package/dist/embed/host.js +266 -0
  205. package/dist/embed/host.js.map +1 -0
  206. package/dist/embed/index.d.ts +5 -0
  207. package/dist/embed/index.d.ts.map +1 -0
  208. package/dist/embed/index.js +13 -0
  209. package/dist/embed/index.js.map +1 -0
  210. package/dist/embed/timers.d.ts +6 -0
  211. package/dist/embed/timers.d.ts.map +1 -0
  212. package/dist/embed/timers.js +16 -0
  213. package/dist/embed/timers.js.map +1 -0
  214. package/dist/flow/draw.d.ts +45 -0
  215. package/dist/flow/draw.d.ts.map +1 -0
  216. package/dist/flow/draw.js +295 -0
  217. package/dist/flow/draw.js.map +1 -0
  218. package/dist/flow/index.d.ts +64 -0
  219. package/dist/flow/index.d.ts.map +1 -0
  220. package/dist/flow/index.js +306 -0
  221. package/dist/flow/index.js.map +1 -0
  222. package/dist/flow/model.d.ts +158 -0
  223. package/dist/flow/model.d.ts.map +1 -0
  224. package/dist/flow/model.js +566 -0
  225. package/dist/flow/model.js.map +1 -0
  226. package/dist/flow/node.d.ts +429 -0
  227. package/dist/flow/node.d.ts.map +1 -0
  228. package/dist/flow/node.js +3025 -0
  229. package/dist/flow/node.js.map +1 -0
  230. package/dist/flow/paths.d.ts +43 -0
  231. package/dist/flow/paths.d.ts.map +1 -0
  232. package/dist/flow/paths.js +327 -0
  233. package/dist/flow/paths.js.map +1 -0
  234. package/dist/flow/types.d.ts +561 -0
  235. package/dist/flow/types.d.ts.map +1 -0
  236. package/dist/flow/types.js +2 -0
  237. package/dist/flow/types.js.map +1 -0
  238. package/dist/formula/hx.d.ts +24 -0
  239. package/dist/formula/hx.d.ts.map +1 -0
  240. package/dist/formula/hx.js +25 -0
  241. package/dist/formula/hx.js.map +1 -0
  242. package/dist/formula/index.d.ts +74 -0
  243. package/dist/formula/index.d.ts.map +1 -0
  244. package/dist/formula/index.js +155 -0
  245. package/dist/formula/index.js.map +1 -0
  246. package/dist/formula/katex.d.ts +78 -0
  247. package/dist/formula/katex.d.ts.map +1 -0
  248. package/dist/formula/katex.js +130 -0
  249. package/dist/formula/katex.js.map +1 -0
  250. package/dist/formula/layout.d.ts +103 -0
  251. package/dist/formula/layout.d.ts.map +1 -0
  252. package/dist/formula/layout.js +716 -0
  253. package/dist/formula/layout.js.map +1 -0
  254. package/dist/formula/node.d.ts +50 -0
  255. package/dist/formula/node.d.ts.map +1 -0
  256. package/dist/formula/node.js +351 -0
  257. package/dist/formula/node.js.map +1 -0
  258. package/dist/html/controls.d.ts +48 -0
  259. package/dist/html/controls.d.ts.map +1 -0
  260. package/dist/html/controls.js +195 -0
  261. package/dist/html/controls.js.map +1 -0
  262. package/dist/html/css/cascade.d.ts +51 -0
  263. package/dist/html/css/cascade.d.ts.map +1 -0
  264. package/dist/html/css/cascade.js +552 -0
  265. package/dist/html/css/cascade.js.map +1 -0
  266. package/dist/html/css/parse.d.ts +74 -0
  267. package/dist/html/css/parse.d.ts.map +1 -0
  268. package/dist/html/css/parse.js +464 -0
  269. package/dist/html/css/parse.js.map +1 -0
  270. package/dist/html/css/style.d.ts +142 -0
  271. package/dist/html/css/style.d.ts.map +1 -0
  272. package/dist/html/css/style.js +1145 -0
  273. package/dist/html/css/style.js.map +1 -0
  274. package/dist/html/css/ua.d.ts +5 -0
  275. package/dist/html/css/ua.d.ts.map +1 -0
  276. package/dist/html/css/ua.js +171 -0
  277. package/dist/html/css/ua.js.map +1 -0
  278. package/dist/html/css/values.d.ts +78 -0
  279. package/dist/html/css/values.d.ts.map +1 -0
  280. package/dist/html/css/values.js +330 -0
  281. package/dist/html/css/values.js.map +1 -0
  282. package/dist/html/dom.d.ts +112 -0
  283. package/dist/html/dom.d.ts.map +1 -0
  284. package/dist/html/dom.js +374 -0
  285. package/dist/html/dom.js.map +1 -0
  286. package/dist/html/hx.d.ts +24 -0
  287. package/dist/html/hx.d.ts.map +1 -0
  288. package/dist/html/hx.js +29 -0
  289. package/dist/html/hx.js.map +1 -0
  290. package/dist/html/index.d.ts +137 -0
  291. package/dist/html/index.d.ts.map +1 -0
  292. package/dist/html/index.js +339 -0
  293. package/dist/html/index.js.map +1 -0
  294. package/dist/html/layout/block.d.ts +58 -0
  295. package/dist/html/layout/block.d.ts.map +1 -0
  296. package/dist/html/layout/block.js +724 -0
  297. package/dist/html/layout/block.js.map +1 -0
  298. package/dist/html/layout/boxes.d.ts +261 -0
  299. package/dist/html/layout/boxes.d.ts.map +1 -0
  300. package/dist/html/layout/boxes.js +725 -0
  301. package/dist/html/layout/boxes.js.map +1 -0
  302. package/dist/html/layout/flex.d.ts +16 -0
  303. package/dist/html/layout/flex.d.ts.map +1 -0
  304. package/dist/html/layout/flex.js +242 -0
  305. package/dist/html/layout/flex.js.map +1 -0
  306. package/dist/html/layout/floats.d.ts +50 -0
  307. package/dist/html/layout/floats.d.ts.map +1 -0
  308. package/dist/html/layout/floats.js +110 -0
  309. package/dist/html/layout/floats.js.map +1 -0
  310. package/dist/html/layout/inline.d.ts +44 -0
  311. package/dist/html/layout/inline.d.ts.map +1 -0
  312. package/dist/html/layout/inline.js +700 -0
  313. package/dist/html/layout/inline.js.map +1 -0
  314. package/dist/html/layout/table.d.ts +5 -0
  315. package/dist/html/layout/table.d.ts.map +1 -0
  316. package/dist/html/layout/table.js +340 -0
  317. package/dist/html/layout/table.js.map +1 -0
  318. package/dist/html/node.d.ts +149 -0
  319. package/dist/html/node.d.ts.map +1 -0
  320. package/dist/html/node.js +861 -0
  321. package/dist/html/node.js.map +1 -0
  322. package/dist/html/paint.d.ts +48 -0
  323. package/dist/html/paint.d.ts.map +1 -0
  324. package/dist/html/paint.js +495 -0
  325. package/dist/html/paint.js.map +1 -0
  326. package/dist/html/resources.d.ts +48 -0
  327. package/dist/html/resources.d.ts.map +1 -0
  328. package/dist/html/resources.js +156 -0
  329. package/dist/html/resources.js.map +1 -0
  330. package/dist/index.d.ts +48 -0
  331. package/dist/index.d.ts.map +1 -0
  332. package/dist/index.js +92 -0
  333. package/dist/index.js.map +1 -0
  334. package/dist/internal/heights.d.ts +81 -0
  335. package/dist/internal/heights.d.ts.map +1 -0
  336. package/dist/internal/heights.js +193 -0
  337. package/dist/internal/heights.js.map +1 -0
  338. package/dist/internal/hx.d.ts +24 -0
  339. package/dist/internal/hx.d.ts.map +1 -0
  340. package/dist/internal/hx.js +27 -0
  341. package/dist/internal/hx.js.map +1 -0
  342. package/dist/internal/text.d.ts +6 -0
  343. package/dist/internal/text.d.ts.map +1 -0
  344. package/dist/internal/text.js +44 -0
  345. package/dist/internal/text.js.map +1 -0
  346. package/dist/internal/timers.d.ts +8 -0
  347. package/dist/internal/timers.d.ts.map +1 -0
  348. package/dist/internal/timers.js +22 -0
  349. package/dist/internal/timers.js.map +1 -0
  350. package/dist/internal/widget.d.ts +40 -0
  351. package/dist/internal/widget.d.ts.map +1 -0
  352. package/dist/internal/widget.js +44 -0
  353. package/dist/internal/widget.js.map +1 -0
  354. package/dist/markdown/ast.d.ts +126 -0
  355. package/dist/markdown/ast.d.ts.map +1 -0
  356. package/dist/markdown/ast.js +8 -0
  357. package/dist/markdown/ast.js.map +1 -0
  358. package/dist/markdown/hx.d.ts +24 -0
  359. package/dist/markdown/hx.d.ts.map +1 -0
  360. package/dist/markdown/hx.js +25 -0
  361. package/dist/markdown/hx.js.map +1 -0
  362. package/dist/markdown/index.d.ts +90 -0
  363. package/dist/markdown/index.d.ts.map +1 -0
  364. package/dist/markdown/index.js +413 -0
  365. package/dist/markdown/index.js.map +1 -0
  366. package/dist/markdown/parse.d.ts +8 -0
  367. package/dist/markdown/parse.d.ts.map +1 -0
  368. package/dist/markdown/parse.js +911 -0
  369. package/dist/markdown/parse.js.map +1 -0
  370. package/dist/markdown/spans.d.ts +20 -0
  371. package/dist/markdown/spans.d.ts.map +1 -0
  372. package/dist/markdown/spans.js +96 -0
  373. package/dist/markdown/spans.js.map +1 -0
  374. package/dist/media-player/backends.d.ts +64 -0
  375. package/dist/media-player/backends.d.ts.map +1 -0
  376. package/dist/media-player/backends.js +110 -0
  377. package/dist/media-player/backends.js.map +1 -0
  378. package/dist/media-player/control.d.ts +40 -0
  379. package/dist/media-player/control.d.ts.map +1 -0
  380. package/dist/media-player/control.js +44 -0
  381. package/dist/media-player/control.js.map +1 -0
  382. package/dist/media-player/hx.d.ts +24 -0
  383. package/dist/media-player/hx.d.ts.map +1 -0
  384. package/dist/media-player/hx.js +25 -0
  385. package/dist/media-player/hx.js.map +1 -0
  386. package/dist/media-player/index.d.ts +107 -0
  387. package/dist/media-player/index.d.ts.map +1 -0
  388. package/dist/media-player/index.js +219 -0
  389. package/dist/media-player/index.js.map +1 -0
  390. package/dist/media-player/mpv.d.ts +4 -0
  391. package/dist/media-player/mpv.d.ts.map +1 -0
  392. package/dist/media-player/mpv.js +120 -0
  393. package/dist/media-player/mpv.js.map +1 -0
  394. package/dist/media-player/vlc.d.ts +8 -0
  395. package/dist/media-player/vlc.d.ts.map +1 -0
  396. package/dist/media-player/vlc.js +83 -0
  397. package/dist/media-player/vlc.js.map +1 -0
  398. package/dist/richtext/index.d.ts +19 -0
  399. package/dist/richtext/index.d.ts.map +1 -0
  400. package/dist/richtext/index.js +4 -0
  401. package/dist/richtext/index.js.map +1 -0
  402. package/dist/richtext/links.d.ts +12 -0
  403. package/dist/richtext/links.d.ts.map +1 -0
  404. package/dist/richtext/links.js +64 -0
  405. package/dist/richtext/links.js.map +1 -0
  406. package/dist/richtext/menu.d.ts +11 -0
  407. package/dist/richtext/menu.d.ts.map +1 -0
  408. package/dist/richtext/menu.js +43 -0
  409. package/dist/richtext/menu.js.map +1 -0
  410. package/dist/richtext/node.d.ts +151 -0
  411. package/dist/richtext/node.d.ts.map +1 -0
  412. package/dist/richtext/node.js +255 -0
  413. package/dist/richtext/node.js.map +1 -0
  414. package/dist/richtext/runs.d.ts +92 -0
  415. package/dist/richtext/runs.d.ts.map +1 -0
  416. package/dist/richtext/runs.js +158 -0
  417. package/dist/richtext/runs.js.map +1 -0
  418. package/dist/table/hx.d.ts +24 -0
  419. package/dist/table/hx.d.ts.map +1 -0
  420. package/dist/table/hx.js +25 -0
  421. package/dist/table/hx.js.map +1 -0
  422. package/dist/table/index.d.ts +169 -0
  423. package/dist/table/index.d.ts.map +1 -0
  424. package/dist/table/index.js +844 -0
  425. package/dist/table/index.js.map +1 -0
  426. package/dist/table/rows.d.ts +136 -0
  427. package/dist/table/rows.d.ts.map +1 -0
  428. package/dist/table/rows.js +146 -0
  429. package/dist/table/rows.js.map +1 -0
  430. package/dist/terminal/backends.d.ts +105 -0
  431. package/dist/terminal/backends.d.ts.map +1 -0
  432. package/dist/terminal/backends.js +185 -0
  433. package/dist/terminal/backends.js.map +1 -0
  434. package/dist/terminal/hx.d.ts +24 -0
  435. package/dist/terminal/hx.d.ts.map +1 -0
  436. package/dist/terminal/hx.js +25 -0
  437. package/dist/terminal/hx.js.map +1 -0
  438. package/dist/terminal/index.d.ts +160 -0
  439. package/dist/terminal/index.d.ts.map +1 -0
  440. package/dist/terminal/index.js +344 -0
  441. package/dist/terminal/index.js.map +1 -0
  442. package/dist/terminal/title.d.ts +24 -0
  443. package/dist/terminal/title.d.ts.map +1 -0
  444. package/dist/terminal/title.js +129 -0
  445. package/dist/terminal/title.js.map +1 -0
  446. package/dist/terminal/vt/colors.d.ts +63 -0
  447. package/dist/terminal/vt/colors.d.ts.map +1 -0
  448. package/dist/terminal/vt/colors.js +203 -0
  449. package/dist/terminal/vt/colors.js.map +1 -0
  450. package/dist/terminal/vt/diff.d.ts +117 -0
  451. package/dist/terminal/vt/diff.d.ts.map +1 -0
  452. package/dist/terminal/vt/diff.js +358 -0
  453. package/dist/terminal/vt/diff.js.map +1 -0
  454. package/dist/terminal/vt/fonts.d.ts +92 -0
  455. package/dist/terminal/vt/fonts.d.ts.map +1 -0
  456. package/dist/terminal/vt/fonts.js +178 -0
  457. package/dist/terminal/vt/fonts.js.map +1 -0
  458. package/dist/terminal/vt/index.d.ts +78 -0
  459. package/dist/terminal/vt/index.d.ts.map +1 -0
  460. package/dist/terminal/vt/index.js +312 -0
  461. package/dist/terminal/vt/index.js.map +1 -0
  462. package/dist/terminal/vt/keys.d.ts +74 -0
  463. package/dist/terminal/vt/keys.d.ts.map +1 -0
  464. package/dist/terminal/vt/keys.js +309 -0
  465. package/dist/terminal/vt/keys.js.map +1 -0
  466. package/dist/terminal/vt/mouse.d.ts +44 -0
  467. package/dist/terminal/vt/mouse.d.ts.map +1 -0
  468. package/dist/terminal/vt/mouse.js +106 -0
  469. package/dist/terminal/vt/mouse.js.map +1 -0
  470. package/dist/terminal/vt/node.d.ts +246 -0
  471. package/dist/terminal/vt/node.d.ts.map +1 -0
  472. package/dist/terminal/vt/node.js +1068 -0
  473. package/dist/terminal/vt/node.js.map +1 -0
  474. package/dist/terminal/vt/pty.d.ts +81 -0
  475. package/dist/terminal/vt/pty.d.ts.map +1 -0
  476. package/dist/terminal/vt/pty.js +201 -0
  477. package/dist/terminal/vt/pty.js.map +1 -0
  478. package/dist/terminal/vt/renderer.d.ts +179 -0
  479. package/dist/terminal/vt/renderer.d.ts.map +1 -0
  480. package/dist/terminal/vt/renderer.js +357 -0
  481. package/dist/terminal/vt/renderer.js.map +1 -0
  482. package/dist/terminal/vt/timers.d.ts +6 -0
  483. package/dist/terminal/vt/timers.d.ts.map +1 -0
  484. package/dist/terminal/vt/timers.js +16 -0
  485. package/dist/terminal/vt/timers.js.map +1 -0
  486. package/dist/terminal/vt/xterm.d.ts +142 -0
  487. package/dist/terminal/vt/xterm.d.ts.map +1 -0
  488. package/dist/terminal/vt/xterm.js +32 -0
  489. package/dist/terminal/vt/xterm.js.map +1 -0
  490. package/dist/terminal-output/hx.d.ts +24 -0
  491. package/dist/terminal-output/hx.d.ts.map +1 -0
  492. package/dist/terminal-output/hx.js +25 -0
  493. package/dist/terminal-output/hx.js.map +1 -0
  494. package/dist/terminal-output/index.d.ts +92 -0
  495. package/dist/terminal-output/index.d.ts.map +1 -0
  496. package/dist/terminal-output/index.js +179 -0
  497. package/dist/terminal-output/index.js.map +1 -0
  498. package/dist/terminal-output/runs.d.ts +27 -0
  499. package/dist/terminal-output/runs.d.ts.map +1 -0
  500. package/dist/terminal-output/runs.js +66 -0
  501. package/dist/terminal-output/runs.js.map +1 -0
  502. package/dist/three/canvas.d.ts +46 -0
  503. package/dist/three/canvas.d.ts.map +1 -0
  504. package/dist/three/canvas.js +305 -0
  505. package/dist/three/canvas.js.map +1 -0
  506. package/dist/three/events.d.ts +64 -0
  507. package/dist/three/events.d.ts.map +1 -0
  508. package/dist/three/events.js +146 -0
  509. package/dist/three/events.js.map +1 -0
  510. package/dist/three/geometries.d.ts +89 -0
  511. package/dist/three/geometries.d.ts.map +1 -0
  512. package/dist/three/geometries.js +345 -0
  513. package/dist/three/geometries.js.map +1 -0
  514. package/dist/three/globals.d.ts +7 -0
  515. package/dist/three/globals.d.ts.map +1 -0
  516. package/dist/three/globals.js +20 -0
  517. package/dist/three/globals.js.map +1 -0
  518. package/dist/three/hx.d.ts +9 -0
  519. package/dist/three/hx.d.ts.map +1 -0
  520. package/dist/three/hx.js +10 -0
  521. package/dist/three/hx.js.map +1 -0
  522. package/dist/three/index.d.ts +22 -0
  523. package/dist/three/index.d.ts.map +1 -0
  524. package/dist/three/index.js +24 -0
  525. package/dist/three/index.js.map +1 -0
  526. package/dist/three/jsx-dev-runtime.d.ts +19 -0
  527. package/dist/three/jsx-dev-runtime.d.ts.map +1 -0
  528. package/dist/three/jsx-dev-runtime.js +2 -0
  529. package/dist/three/jsx-dev-runtime.js.map +1 -0
  530. package/dist/three/jsx-runtime.d.ts +19 -0
  531. package/dist/three/jsx-runtime.d.ts.map +1 -0
  532. package/dist/three/jsx-runtime.js +2 -0
  533. package/dist/three/jsx-runtime.js.map +1 -0
  534. package/dist/three/jsx.d.ts +198 -0
  535. package/dist/three/jsx.d.ts.map +1 -0
  536. package/dist/three/jsx.js +2 -0
  537. package/dist/three/jsx.js.map +1 -0
  538. package/dist/three/materials.d.ts +125 -0
  539. package/dist/three/materials.d.ts.map +1 -0
  540. package/dist/three/materials.js +229 -0
  541. package/dist/three/materials.js.map +1 -0
  542. package/dist/three/math.d.ts +146 -0
  543. package/dist/three/math.d.ts.map +1 -0
  544. package/dist/three/math.js +464 -0
  545. package/dist/three/math.js.map +1 -0
  546. package/dist/three/objects.d.ts +185 -0
  547. package/dist/three/objects.d.ts.map +1 -0
  548. package/dist/three/objects.js +309 -0
  549. package/dist/three/objects.js.map +1 -0
  550. package/dist/three/passes.d.ts +54 -0
  551. package/dist/three/passes.d.ts.map +1 -0
  552. package/dist/three/passes.js +78 -0
  553. package/dist/three/passes.js.map +1 -0
  554. package/dist/three/postprocess.d.ts +85 -0
  555. package/dist/three/postprocess.d.ts.map +1 -0
  556. package/dist/three/postprocess.js +503 -0
  557. package/dist/three/postprocess.js.map +1 -0
  558. package/dist/three/raycast.d.ts +24 -0
  559. package/dist/three/raycast.d.ts.map +1 -0
  560. package/dist/three/raycast.js +138 -0
  561. package/dist/three/raycast.js.map +1 -0
  562. package/dist/three/reconciler.d.ts +48 -0
  563. package/dist/three/reconciler.d.ts.map +1 -0
  564. package/dist/three/reconciler.js +416 -0
  565. package/dist/three/reconciler.js.map +1 -0
  566. package/dist/three/renderer-direct.d.ts +102 -0
  567. package/dist/three/renderer-direct.d.ts.map +1 -0
  568. package/dist/three/renderer-direct.js +782 -0
  569. package/dist/three/renderer-direct.js.map +1 -0
  570. package/dist/three/renderer-indirect.d.ts +68 -0
  571. package/dist/three/renderer-indirect.d.ts.map +1 -0
  572. package/dist/three/renderer-indirect.js +438 -0
  573. package/dist/three/renderer-indirect.js.map +1 -0
  574. package/dist/three/store.d.ts +81 -0
  575. package/dist/three/store.d.ts.map +1 -0
  576. package/dist/three/store.js +110 -0
  577. package/dist/three/store.js.map +1 -0
  578. package/dist/timeline/hx.d.ts +18 -0
  579. package/dist/timeline/hx.d.ts.map +1 -0
  580. package/dist/timeline/hx.js +10 -0
  581. package/dist/timeline/hx.js.map +1 -0
  582. package/dist/timeline/index.d.ts +152 -0
  583. package/dist/timeline/index.d.ts.map +1 -0
  584. package/dist/timeline/index.js +383 -0
  585. package/dist/timeline/index.js.map +1 -0
  586. package/dist/tray-host/hx.d.ts +24 -0
  587. package/dist/tray-host/hx.d.ts.map +1 -0
  588. package/dist/tray-host/hx.js +25 -0
  589. package/dist/tray-host/hx.js.map +1 -0
  590. package/dist/tray-host/index.d.ts +110 -0
  591. package/dist/tray-host/index.d.ts.map +1 -0
  592. package/dist/tray-host/index.js +191 -0
  593. package/dist/tray-host/index.js.map +1 -0
  594. package/dist/tray-host/manager.d.ts +137 -0
  595. package/dist/tray-host/manager.d.ts.map +1 -0
  596. package/dist/tray-host/manager.js +462 -0
  597. package/dist/tray-host/manager.js.map +1 -0
  598. package/dist/tray-host/notify.d.ts +22 -0
  599. package/dist/tray-host/notify.d.ts.map +1 -0
  600. package/dist/tray-host/notify.js +74 -0
  601. package/dist/tray-host/notify.js.map +1 -0
  602. package/dist/tray-host/protocol.d.ts +106 -0
  603. package/dist/tray-host/protocol.d.ts.map +1 -0
  604. package/dist/tray-host/protocol.js +191 -0
  605. package/dist/tray-host/protocol.js.map +1 -0
  606. package/dist/tree/hx.d.ts +24 -0
  607. package/dist/tree/hx.d.ts.map +1 -0
  608. package/dist/tree/hx.js +25 -0
  609. package/dist/tree/hx.js.map +1 -0
  610. package/dist/tree/index.d.ts +221 -0
  611. package/dist/tree/index.d.ts.map +1 -0
  612. package/dist/tree/index.js +716 -0
  613. package/dist/tree/index.js.map +1 -0
  614. package/dist/tree/internal.d.ts +18 -0
  615. package/dist/tree/internal.d.ts.map +1 -0
  616. package/dist/tree/internal.js +66 -0
  617. package/dist/tree/internal.js.map +1 -0
  618. package/dist/tree/rows.d.ts +177 -0
  619. package/dist/tree/rows.d.ts.map +1 -0
  620. package/dist/tree/rows.js +179 -0
  621. package/dist/tree/rows.js.map +1 -0
  622. package/package.json +166 -12
  623. package/src/ansi/cast.ts +159 -0
  624. package/src/ansi/index.ts +53 -0
  625. package/src/ansi/palette.ts +226 -0
  626. package/src/ansi/parse.ts +780 -0
  627. package/src/ansi/sgr.ts +380 -0
  628. package/src/ansi/utf8.ts +84 -0
  629. package/src/calendar/Calendar.ts +744 -0
  630. package/src/calendar/DatePicker.ts +368 -0
  631. package/src/calendar/dates.ts +307 -0
  632. package/src/calendar/index.ts +51 -0
  633. package/src/charts/components.ts +864 -0
  634. package/src/charts/data.ts +776 -0
  635. package/src/charts/hx.ts +39 -0
  636. package/src/charts/index.ts +99 -0
  637. package/src/charts/node.ts +932 -0
  638. package/src/charts/render.ts +982 -0
  639. package/src/charts/scale.ts +214 -0
  640. package/src/charts/spec.ts +122 -0
  641. package/src/charts/timers.ts +24 -0
  642. package/src/code/hx.ts +51 -0
  643. package/src/code/index.ts +174 -0
  644. package/src/code-editor/completion.ts +161 -0
  645. package/src/code-editor/doc.ts +198 -0
  646. package/src/code-editor/hx.ts +26 -0
  647. package/src/code-editor/index.ts +615 -0
  648. package/src/code-editor/node.ts +1926 -0
  649. package/src/code-language/hljs.ts +302 -0
  650. package/src/code-language/index.ts +51 -0
  651. package/src/code-language/languages/glsl.ts +120 -0
  652. package/src/code-language/languages/javascript.ts +419 -0
  653. package/src/code-language/languages/json.ts +72 -0
  654. package/src/code-language/languages/shell.ts +221 -0
  655. package/src/code-language/languages/sql.ts +165 -0
  656. package/src/code-language/lezer.ts +190 -0
  657. package/src/code-language/registry.ts +66 -0
  658. package/src/code-language/runs.ts +128 -0
  659. package/src/code-language/stream.ts +306 -0
  660. package/src/code-language/textmate.ts +134 -0
  661. package/src/code-language/theme.ts +124 -0
  662. package/src/code-language/timers.ts +36 -0
  663. package/src/code-language/types.ts +252 -0
  664. package/src/codeblock/index.ts +146 -0
  665. package/src/color-picker/ColorField.ts +333 -0
  666. package/src/color-picker/ColorPicker.ts +1069 -0
  667. package/src/color-picker/color.ts +399 -0
  668. package/src/color-picker/index.ts +50 -0
  669. package/src/desktop-calendar/eds.ts +484 -0
  670. package/src/desktop-calendar/ical.ts +119 -0
  671. package/src/desktop-calendar/index.ts +287 -0
  672. package/src/embed/client.ts +311 -0
  673. package/src/embed/host.ts +432 -0
  674. package/src/embed/index.ts +33 -0
  675. package/src/embed/timers.ts +32 -0
  676. package/src/flow/draw.ts +418 -0
  677. package/src/flow/index.ts +473 -0
  678. package/src/flow/model.ts +687 -0
  679. package/src/flow/node.ts +3694 -0
  680. package/src/flow/paths.ts +403 -0
  681. package/src/flow/types.ts +634 -0
  682. package/src/formula/hx.ts +51 -0
  683. package/src/formula/index.ts +243 -0
  684. package/src/formula/katex.ts +209 -0
  685. package/src/formula/layout.ts +876 -0
  686. package/src/formula/node.ts +467 -0
  687. package/src/html/controls.ts +244 -0
  688. package/src/html/css/cascade.ts +606 -0
  689. package/src/html/css/parse.ts +500 -0
  690. package/src/html/css/style.ts +1371 -0
  691. package/src/html/css/ua.ts +174 -0
  692. package/src/html/css/values.ts +358 -0
  693. package/src/html/dom.ts +410 -0
  694. package/src/html/hx.ts +55 -0
  695. package/src/html/index.ts +545 -0
  696. package/src/html/layout/block.ts +876 -0
  697. package/src/html/layout/boxes.ts +981 -0
  698. package/src/html/layout/flex.ts +297 -0
  699. package/src/html/layout/floats.ts +125 -0
  700. package/src/html/layout/inline.ts +870 -0
  701. package/src/html/layout/table.ts +380 -0
  702. package/src/html/node.ts +967 -0
  703. package/src/html/paint.ts +605 -0
  704. package/src/html/resources.ts +214 -0
  705. package/src/index.ts +638 -0
  706. package/src/internal/heights.ts +211 -0
  707. package/src/internal/hx.ts +53 -0
  708. package/src/internal/text.ts +44 -0
  709. package/src/internal/timers.ts +44 -0
  710. package/src/internal/widget.ts +92 -0
  711. package/src/markdown/ast.ts +163 -0
  712. package/src/markdown/hx.ts +51 -0
  713. package/src/markdown/index.ts +686 -0
  714. package/src/markdown/parse.ts +1037 -0
  715. package/src/markdown/spans.ts +143 -0
  716. package/src/media-player/backends.ts +155 -0
  717. package/src/media-player/control.ts +70 -0
  718. package/src/media-player/hx.ts +51 -0
  719. package/src/media-player/index.ts +378 -0
  720. package/src/media-player/mpv.ts +146 -0
  721. package/src/media-player/vlc.ts +97 -0
  722. package/src/richtext/index.ts +42 -0
  723. package/src/richtext/links.ts +78 -0
  724. package/src/richtext/menu.ts +49 -0
  725. package/src/richtext/node.ts +406 -0
  726. package/src/richtext/runs.ts +253 -0
  727. package/src/table/hx.ts +51 -0
  728. package/src/table/index.ts +1219 -0
  729. package/src/table/rows.ts +275 -0
  730. package/src/terminal/backends.ts +242 -0
  731. package/src/terminal/hx.ts +51 -0
  732. package/src/terminal/index.ts +574 -0
  733. package/src/terminal/title.ts +172 -0
  734. package/src/terminal/vt/colors.ts +247 -0
  735. package/src/terminal/vt/diff.ts +467 -0
  736. package/src/terminal/vt/fonts.ts +233 -0
  737. package/src/terminal/vt/index.ts +443 -0
  738. package/src/terminal/vt/keys.ts +369 -0
  739. package/src/terminal/vt/mouse.ts +144 -0
  740. package/src/terminal/vt/node.ts +1242 -0
  741. package/src/terminal/vt/pty.ts +334 -0
  742. package/src/terminal/vt/renderer.ts +555 -0
  743. package/src/terminal/vt/timers.ts +31 -0
  744. package/src/terminal/vt/xterm.ts +193 -0
  745. package/src/terminal-output/hx.ts +51 -0
  746. package/src/terminal-output/index.ts +340 -0
  747. package/src/terminal-output/runs.ts +79 -0
  748. package/src/three/canvas.ts +451 -0
  749. package/src/three/events.ts +197 -0
  750. package/src/three/geometries.ts +429 -0
  751. package/src/three/globals.ts +34 -0
  752. package/src/three/hx.ts +22 -0
  753. package/src/three/index.ts +98 -0
  754. package/src/three/jsx-dev-runtime.ts +27 -0
  755. package/src/three/jsx-runtime.ts +38 -0
  756. package/src/three/jsx.ts +275 -0
  757. package/src/three/materials.ts +270 -0
  758. package/src/three/math.ts +585 -0
  759. package/src/three/objects.ts +397 -0
  760. package/src/three/passes.ts +90 -0
  761. package/src/three/postprocess.ts +677 -0
  762. package/src/three/raycast.ts +189 -0
  763. package/src/three/react-reconciler.d.ts +50 -0
  764. package/src/three/reconciler.ts +624 -0
  765. package/src/three/renderer-direct.ts +1055 -0
  766. package/src/three/renderer-indirect.ts +570 -0
  767. package/src/three/store.ts +207 -0
  768. package/src/timeline/hx.ts +31 -0
  769. package/src/timeline/index.ts +603 -0
  770. package/src/tray-host/hx.ts +51 -0
  771. package/src/tray-host/index.ts +331 -0
  772. package/src/tray-host/manager.ts +639 -0
  773. package/src/tray-host/notify.ts +102 -0
  774. package/src/tray-host/protocol.ts +235 -0
  775. package/src/tree/hx.ts +51 -0
  776. package/src/tree/index.ts +1087 -0
  777. package/src/tree/internal.ts +87 -0
  778. package/src/tree/rows.ts +334 -0
  779. package/src/index.d.ts +0 -2
  780. package/src/index.js +0 -9
  781. package/src/sparkline/index.d.ts +0 -29
  782. package/src/sparkline/index.js +0 -50
  783. package/src/sparkline/node.js +0 -72
@@ -0,0 +1,932 @@
1
+ // The retained node behind `<chartplot>`: one paint pass for the grid, the
2
+ // axes and every series, the render-host caches (scatter grids, the density
3
+ // image surface), and the hit-test answers the tooltip layer asks through a
4
+ // ref.
5
+ //
6
+ // The perf-relevant structure, in one place:
7
+ //
8
+ // - **Nothing happens off-paint.** Pyramids, x indexes and stack tops are
9
+ // built by the first paint that needs them and extended incrementally;
10
+ // a `ChartData` append while this node is entirely outside its window's
11
+ // viewport does not even schedule a frame — scrolling back repaints
12
+ // from current data anyway.
13
+ // - **The scales are computed once per (geometry, data, spec, theme) and
14
+ // memoized**, so a hover asking `hitAt` between frames costs a lookup,
15
+ // not a re-derivation.
16
+ // - **Formatters and stats callbacks ride identity-stable props** (the
17
+ // component layer keeps one mutable object), so re-renders of the React
18
+ // tree above contribute no damage of their own. The hover overlays do
19
+ // overlap the plot, so their damage strips repaint this node — at its
20
+ // usual pixel-bounded cost, which is the actual guarantee: a hover
21
+ // frame is O(width) commands whatever the point count.
22
+
23
+ import { Node } from 'react-x11/node';
24
+ import type {
25
+ Context2D,
26
+ MeasureConstraints,
27
+ MeasuredSize,
28
+ } from 'react-x11/node';
29
+ import type { Style } from 'react-x11/style';
30
+ import { Surface } from 'react-x11/ntk';
31
+
32
+ import type {
33
+ ChartDataLike,
34
+ ChartSourceData,
35
+ NumericColumn,
36
+ ResolvedColumn,
37
+ } from './data.js';
38
+ import {
39
+ buildStackTops,
40
+ isChartDataLike,
41
+ minMaxRange,
42
+ nearestIndex,
43
+ numericColumn,
44
+ pyramidFor,
45
+ resolveColumn,
46
+ xIndexFor,
47
+ } from './data.js';
48
+ import type { BandScale, LinearScale } from './scale.js';
49
+ import {
50
+ bandScale,
51
+ formatNumberTick,
52
+ formatTimeTick,
53
+ linearScale,
54
+ linearTicks,
55
+ niceDomain,
56
+ timeTicks,
57
+ } from './scale.js';
58
+ import type { ChartFrameStats, PlotSpec, SeriesSpec } from './spec.js';
59
+ import { resolveThemeColor } from './spec.js';
60
+ import type {
61
+ FrameStatsSink,
62
+ PlotContext,
63
+ PlotRect,
64
+ RenderHost,
65
+ ScatterGrid,
66
+ SeriesGeometry,
67
+ } from './render.js';
68
+ import { canPath, makeScatterGrid, renderSeries } from './render.js';
69
+ import { microtask, now } from './timers.js';
70
+
71
+ /** The element name — registration key, node kind and JSX tag alike. */
72
+ export const ELEMENT = 'chartplot';
73
+
74
+ /** Formatter channel. The component layer keeps ONE mutable object per
75
+ * chart and updates its fields, so the prop's identity never changes and a
76
+ * formatter defined inline never damages the plot. */
77
+ export interface ChartFormatters {
78
+ x?: (value: number | string) => string;
79
+ y?: (value: number) => string;
80
+ }
81
+
82
+ export interface ChartPlotProps {
83
+ spec: PlotSpec;
84
+ data: ChartSourceData;
85
+ formatters?: ChartFormatters;
86
+ /** Reported once per painted frame, off the paint stack. */
87
+ onFrameStats?: (stats: ChartFrameStats) => void;
88
+ style?: Style | Style[];
89
+ }
90
+
91
+ /** What the tooltip layer gets for a pointer position. */
92
+ export interface ChartHit {
93
+ index: number;
94
+ /** The x value at that index — a label for band axes. */
95
+ xValue: number | string;
96
+ /** Snap position for the crosshair, window coordinates. */
97
+ px: number;
98
+ /** The x domain's width (0 for band axes) — what a time-axis tooltip
99
+ * sizes its default header format to, exactly as the ticks do. */
100
+ xSpan: number;
101
+ plot: PlotRect;
102
+ points: {
103
+ id: string;
104
+ label: string;
105
+ color: string;
106
+ value: number;
107
+ py: number;
108
+ }[];
109
+ }
110
+
111
+ export type NtkApp = ConstructorParameters<typeof Node>[2];
112
+
113
+ /** The slice of ntk's font service axis labels go through. Absent on the
114
+ * mock backend, and every use below treats that as "skip the text". */
115
+ interface FontsLike {
116
+ layout(
117
+ content: string,
118
+ style: Record<string, unknown>,
119
+ ): {
120
+ width: number;
121
+ height: number;
122
+ draw(ctx: unknown, x: number, y: number): void;
123
+ };
124
+ }
125
+
126
+ interface SurfaceLike {
127
+ getContext(name: string): {
128
+ createImageData(
129
+ w: number,
130
+ h: number,
131
+ ): {
132
+ width: number;
133
+ height: number;
134
+ data: Uint8ClampedArray;
135
+ };
136
+ putImageData(data: unknown, x: number, y: number): void;
137
+ destroy?(): void;
138
+ };
139
+ destroy(): void;
140
+ }
141
+
142
+ type SurfaceCtor = new (
143
+ app: unknown,
144
+ options: { width: number; height: number },
145
+ ) => SurfaceLike;
146
+
147
+ // `react-x11/ntk` types loosely on purpose; older ntk has no Surface at all
148
+ const SurfaceClass = (Surface ?? null) as unknown as SurfaceCtor | null;
149
+
150
+ const MIN_PAINT_PX = 8;
151
+ const PAD_TOP = 6;
152
+ const PAD_RIGHT = 8;
153
+ const TICK_GAP = 6;
154
+ const X_AXIS_HEIGHT = 22;
155
+ const LABEL_CACHE_MAX = 256;
156
+
157
+ interface AxisTick {
158
+ /** position in window px along the tick's axis */
159
+ px: number;
160
+ label: string;
161
+ }
162
+
163
+ /** Everything derived from (abs, data, spec, theme): scales, gutters,
164
+ * ticks, per-series geometry. One computation serves paint and hitAt. */
165
+ interface Layout {
166
+ key: string;
167
+ plot: PlotRect;
168
+ xScale: LinearScale | BandScale;
169
+ yScale: LinearScale;
170
+ xTicks: AxisTick[];
171
+ yTicks: AxisTick[];
172
+ geoms: SeriesGeometry[];
173
+ /** the x column (band labels / hit values), when there is one */
174
+ xCol: ResolvedColumn | null;
175
+ prepMs: number;
176
+ }
177
+
178
+ interface StackEntry {
179
+ /** identity key of the member columns + their epochs */
180
+ epochKey: string;
181
+ builtN: number;
182
+ layers: Float64Array[];
183
+ /** stable pyramid-cache hosts, one per layer */
184
+ hosts: object[];
185
+ /** bumped on rebuild so wrapped columns invalidate their pyramids */
186
+ rebuilds: number;
187
+ }
188
+
189
+ export class ChartPlotNode extends Node {
190
+ private _layoutCache: Layout | null = null;
191
+ private _labelLayouts = new Map<
192
+ string,
193
+ {
194
+ width: number;
195
+ height: number;
196
+ draw(ctx: unknown, x: number, y: number): void;
197
+ }
198
+ >();
199
+ private _scatterGrids = new Map<string, ScatterGrid>();
200
+ private _stacks = new Map<string, StackEntry>();
201
+ private _unsubscribe: (() => void) | null = null;
202
+ private _image: {
203
+ w: number;
204
+ h: number;
205
+ surface: SurfaceLike;
206
+ sctx: ReturnType<SurfaceLike['getContext']>;
207
+ data: { width: number; height: number; data: Uint8ClampedArray };
208
+ /** what the surface currently holds — a repaint with the same content
209
+ * (a crosshair moving over a dense scatter) is one composite, no
210
+ * refill and no re-upload */
211
+ contentKey: string;
212
+ } | null = null;
213
+
214
+ constructor(props: Record<string, unknown>, app: NtkApp) {
215
+ super(ELEMENT, props, app);
216
+ this.a11yRole = 'img';
217
+ this._subscribeData(props.data);
218
+ }
219
+
220
+ private _props(): Partial<ChartPlotProps> {
221
+ return this.props as unknown as Partial<ChartPlotProps>;
222
+ }
223
+
224
+ override applyProps(
225
+ nextProps: Record<string, unknown>,
226
+ prevProps: Record<string, unknown>,
227
+ ): void {
228
+ if (nextProps.data !== prevProps.data) {
229
+ this._subscribeData(nextProps.data);
230
+ }
231
+ super.applyProps(nextProps, prevProps);
232
+ }
233
+
234
+ private _subscribeData(data: unknown): void {
235
+ this._unsubscribe?.();
236
+ this._unsubscribe = null;
237
+ if (data && isChartDataLike(data as ChartSourceData)) {
238
+ this._unsubscribe = (data as ChartDataLike).subscribe(() => {
239
+ if (this.destroyed) return;
240
+ // A chart nobody can see skips even the invalidation: scrolling it
241
+ // back into view repaints from current data, so no frame is owed.
242
+ if (this._fullyOffscreen()) return;
243
+ this.invalidate(false, this, 'content');
244
+ });
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Entirely outside the owning window, by public geometry alone. Core
250
+ * culls the *paint* of offscreen nodes on its own; this is only about
251
+ * skipping the invalidation a streaming append would otherwise schedule.
252
+ * Conservative: any doubt answers "maybe visible".
253
+ */
254
+ private _fullyOffscreen(): boolean {
255
+ const root = this.root;
256
+ if (!root || root === this) return true;
257
+ const win = root.abs;
258
+ const a = this.abs;
259
+ if (!win || !a || win.width <= 0) return false;
260
+ return (
261
+ a.x + a.width <= 0 ||
262
+ a.y + a.height <= 0 ||
263
+ a.x >= win.width ||
264
+ a.y >= win.height
265
+ );
266
+ }
267
+
268
+ override destroySubtree(): void {
269
+ this._unsubscribe?.();
270
+ this._unsubscribe = null;
271
+ this._image?.sctx.destroy?.();
272
+ this._image?.surface.destroy();
273
+ this._image = null;
274
+ super.destroySubtree();
275
+ }
276
+
277
+ /** A chart with no styled size still shows up usefully — the HTML canvas
278
+ * default, scaled a little. Flex sizing overrides it as usual. */
279
+ override measureContent(constraints: MeasureConstraints): MeasuredSize {
280
+ return {
281
+ width: Math.min(480, constraints.width),
282
+ height: Math.min(260, constraints.height),
283
+ };
284
+ }
285
+
286
+ // --- data plumbing -------------------------------------------------------
287
+
288
+ private _dataVersion(spec: PlotSpec, data: ChartSourceData): string {
289
+ // cheap and exact: every column's (epoch, n) — appends and window
290
+ // shifts both land here, so the layout memo can key on it
291
+ const parts: string[] = [];
292
+ const seen = new Set<string>();
293
+ const push = (key: string | null) => {
294
+ if (!key || seen.has(key)) return;
295
+ seen.add(key);
296
+ const col = resolveColumn(data, key);
297
+ parts.push(col ? `${key}=${col.epoch}:${col.n}` : `${key}=∅`);
298
+ };
299
+ push(spec.x.key);
300
+ for (const s of spec.series) push(s.id);
301
+ return parts.join(',');
302
+ }
303
+
304
+ /** Wrap a stack layer as a column with a stable cache host, so its
305
+ * pyramid survives the layer array being reallocated by growth. */
306
+ private _stackColumn(
307
+ entry: StackEntry,
308
+ layer: number,
309
+ n: number,
310
+ ): NumericColumn {
311
+ return {
312
+ values: entry.layers[layer],
313
+ n,
314
+ host: entry.hosts[layer],
315
+ epoch: entry.rebuilds,
316
+ numeric: true,
317
+ };
318
+ }
319
+
320
+ /**
321
+ * Cumulative tops for a stack group, extended incrementally on append
322
+ * and rebuilt when membership or history changes.
323
+ */
324
+ private _stackTops(
325
+ stackId: string,
326
+ members: { id: string; col: NumericColumn }[],
327
+ ): StackEntry {
328
+ const epochKey = members.map((m) => `${m.id}:${m.col.epoch}`).join('|');
329
+ const n = members.reduce((min, m) => Math.min(min, m.col.n), Infinity);
330
+ let entry = this._stacks.get(stackId);
331
+ if (!entry || entry.epochKey !== epochKey) {
332
+ entry = {
333
+ epochKey,
334
+ builtN: 0,
335
+ layers: members.map(() => new Float64Array(0)),
336
+ hosts: members.map(() => ({})),
337
+ rebuilds: (entry?.rebuilds ?? 0) + 1,
338
+ };
339
+ this._stacks.set(stackId, entry);
340
+ }
341
+ if (entry.builtN < n) {
342
+ if (entry.builtN === 0) {
343
+ entry.layers = buildStackTops(
344
+ members.map((m) => m.col.values),
345
+ n,
346
+ );
347
+ } else {
348
+ for (let j = 0; j < members.length; j++) {
349
+ const old = entry.layers[j];
350
+ const next = new Float64Array(n);
351
+ next.set(old.subarray(0, entry.builtN));
352
+ entry.layers[j] = next;
353
+ }
354
+ for (let i = entry.builtN; i < n; i++) {
355
+ let below = 0;
356
+ for (let j = 0; j < members.length; j++) {
357
+ const v = members[j].col.values[i] as number;
358
+ below += Number.isNaN(v) ? 0 : v;
359
+ entry.layers[j][i] = below;
360
+ }
361
+ }
362
+ }
363
+ entry.builtN = n;
364
+ }
365
+ return entry;
366
+ }
367
+
368
+ // --- layout --------------------------------------------------------------
369
+
370
+ private _themeRecord(): Record<string, unknown> | null {
371
+ return this.theme;
372
+ }
373
+
374
+ private _color(token: string, fallback: string): string {
375
+ const v = resolveThemeColor(token, this._themeRecord());
376
+ return v === '#888888' && token.startsWith('$') ? fallback : v;
377
+ }
378
+
379
+ /** Measure one label through the font service, cached. Null without a
380
+ * font service (the mock backend) — callers fall back to fixed gutters. */
381
+ private _label(
382
+ text: string,
383
+ size: number,
384
+ color: string,
385
+ ): {
386
+ width: number;
387
+ height: number;
388
+ draw(ctx: unknown, x: number, y: number): void;
389
+ } | null {
390
+ const key = `${size}|${color}|${text}`;
391
+ const hit = this._labelLayouts.get(key);
392
+ if (hit) return hit;
393
+ const fonts = (this.app as { fonts?: FontsLike } | null)?.fonts;
394
+ if (!fonts) return null;
395
+ const ts = this.resolvedTextStyle();
396
+ const layout = fonts.layout(text, {
397
+ family: ts.family,
398
+ size,
399
+ weight: ts.weight,
400
+ style: ts.style,
401
+ color,
402
+ });
403
+ if (this._labelLayouts.size >= LABEL_CACHE_MAX) this._labelLayouts.clear();
404
+ this._labelLayouts.set(key, layout);
405
+ return layout;
406
+ }
407
+
408
+ private _layout(): Layout | null {
409
+ const { spec, data, formatters } = this._props();
410
+ if (!spec || !data) return null;
411
+ const box = this.contentBox();
412
+ if (box.width < MIN_PAINT_PX || box.height < MIN_PAINT_PX) return null;
413
+
414
+ const dataVersion = this._dataVersion(spec, data);
415
+ const key = [
416
+ box.x,
417
+ box.y,
418
+ box.width,
419
+ box.height,
420
+ dataVersion,
421
+ // spec is memoized by the component layer, so identity is enough —
422
+ // but it is an object, so it goes into the key by a WeakRef-free
423
+ // trick: the cache also stores the reference and compares it below
424
+ ].join('|');
425
+ const cached = this._layoutCache;
426
+ if (
427
+ cached &&
428
+ cached.key === key &&
429
+ this._cachedSpec === spec &&
430
+ this._cachedTheme === this.theme
431
+ ) {
432
+ return cached;
433
+ }
434
+
435
+ const t0 = now();
436
+ const theme = this._themeRecord();
437
+ const labelSize = Math.max(
438
+ 9,
439
+ Math.round(this.resolvedTextStyle().size * 0.8),
440
+ );
441
+ const labelColor = this._color('$textMuted', '#777777');
442
+
443
+ // -- columns
444
+ const xCol = spec.x.key ? resolveColumn(data, spec.x.key) : null;
445
+ const xNum = numericColumn(xCol);
446
+ const xIdx = xNum ? xIndexFor(xNum) : null;
447
+
448
+ // series → raw columns (missing columns drop the series this frame)
449
+ const raw: { spec: SeriesSpec; col: NumericColumn }[] = [];
450
+ for (const s of spec.series) {
451
+ const col = numericColumn(resolveColumn(data, s.id));
452
+ if (col) raw.push({ spec: s, col });
453
+ }
454
+
455
+ // -- x kind
456
+ const anyBar = raw.some((r) => r.spec.type === 'bar');
457
+ let xKind: 'band' | 'linear' | 'time';
458
+ if (spec.x.type === 'band') xKind = 'band';
459
+ else if (spec.x.type === 'time') xKind = 'time';
460
+ else if (spec.x.type === 'linear') xKind = 'linear';
461
+ else xKind = anyBar || (xCol !== null && !xCol.numeric) ? 'band' : 'linear';
462
+
463
+ // -- stacks: replace y with cumulative tops, base with the layer below
464
+ const stackGroups = new Map<string, { id: string; col: NumericColumn }[]>();
465
+ for (const r of raw) {
466
+ if (!r.spec.stackId || (r.spec.type !== 'bar' && r.spec.type !== 'area'))
467
+ continue;
468
+ const list = stackGroups.get(r.spec.stackId) ?? [];
469
+ list.push({ id: r.spec.id, col: r.col });
470
+ stackGroups.set(r.spec.stackId, list);
471
+ }
472
+ // bar slots: stacked bars share one, everything else gets its own
473
+ const barSlots: string[] = [];
474
+ for (const r of raw) {
475
+ if (r.spec.type !== 'bar') continue;
476
+ const slot = r.spec.stackId ?? r.spec.id;
477
+ if (!barSlots.includes(slot)) barSlots.push(slot);
478
+ }
479
+
480
+ const geoms: SeriesGeometry[] = [];
481
+ let yMin = Infinity;
482
+ let yMax = -Infinity;
483
+ const seenStackLayer = new Map<string, number>();
484
+ for (const r of raw) {
485
+ let y: NumericColumn = r.col;
486
+ let base: NumericColumn | number = 0;
487
+ const stacked =
488
+ r.spec.stackId && (r.spec.type === 'bar' || r.spec.type === 'area')
489
+ ? stackGroups.get(r.spec.stackId)
490
+ : undefined;
491
+ if (stacked && stacked.length > 1) {
492
+ const entry = this._stackTops(r.spec.stackId!, stacked);
493
+ const layer = seenStackLayer.get(r.spec.stackId!) ?? 0;
494
+ seenStackLayer.set(r.spec.stackId!, layer + 1);
495
+ const n = entry.builtN;
496
+ y = this._stackColumn(entry, layer, n);
497
+ base = layer > 0 ? this._stackColumn(entry, layer - 1, n) : 0;
498
+ }
499
+ // y extent through the pyramid: O(1) after the first build, and the
500
+ // build is the prep dense paint needs anyway
501
+ if (y.n > 0) {
502
+ const pyr = pyramidFor(y);
503
+ const mm = { min: 0, max: 0 };
504
+ minMaxRange(pyr, y.values, 0, y.n, mm);
505
+ if (mm.min <= mm.max) {
506
+ if (mm.min < yMin) yMin = mm.min;
507
+ if (mm.max > yMax) yMax = mm.max;
508
+ }
509
+ }
510
+ const grounded =
511
+ r.spec.type === 'bar' ||
512
+ (r.spec.type === 'area' && typeof base === 'number');
513
+ if (grounded) {
514
+ if (yMin > 0) yMin = 0;
515
+ if (yMax < 0) yMax = 0;
516
+ }
517
+ geoms.push({
518
+ spec: r.spec,
519
+ y,
520
+ base,
521
+ x: xKind === 'band' ? null : xNum,
522
+ xIdx: xKind === 'band' ? null : xIdx,
523
+ group: {
524
+ index: Math.max(0, barSlots.indexOf(r.spec.stackId ?? r.spec.id)),
525
+ count: Math.max(1, barSlots.length),
526
+ },
527
+ color: resolveThemeColor(r.spec.color, theme),
528
+ });
529
+ }
530
+
531
+ // -- y domain and ticks
532
+ const [autoY0, autoY1] = niceDomain(yMin, yMax, spec.y.ticks);
533
+ const yD0 = spec.y.domain[0] === 'auto' ? autoY0 : spec.y.domain[0];
534
+ const yD1 = spec.y.domain[1] === 'auto' ? autoY1 : spec.y.domain[1];
535
+ const fmtY = formatters?.y ?? formatNumberTick;
536
+ const yTickValues = spec.y.hide ? [] : linearTicks(yD0, yD1, spec.y.ticks);
537
+ const yTickLabels = yTickValues.map((v) => fmtY(v));
538
+
539
+ // -- gutters (the y gutter measures its own labels; fixed on the mock)
540
+ let left = 0;
541
+ if (!spec.y.hide) {
542
+ if (spec.y.width !== 'auto') {
543
+ left = spec.y.width;
544
+ } else {
545
+ let max = 0;
546
+ for (const text of yTickLabels) {
547
+ const l = this._label(text, labelSize, labelColor);
548
+ if (!l) {
549
+ max = 34;
550
+ break;
551
+ }
552
+ if (l.width > max) max = l.width;
553
+ }
554
+ left = Math.ceil(max) + TICK_GAP + 2;
555
+ }
556
+ }
557
+ const bottom = spec.x.hide ? 0 : spec.x.height || X_AXIS_HEIGHT;
558
+ const plot: PlotRect = {
559
+ x: box.x + left,
560
+ y: box.y + PAD_TOP,
561
+ width: Math.max(1, box.width - left - PAD_RIGHT),
562
+ height: Math.max(1, box.height - PAD_TOP - bottom),
563
+ };
564
+
565
+ const yScale = linearScale(yD0, yD1, plot.y + plot.height, plot.y);
566
+ const yTicks: AxisTick[] = yTickValues.map((v, i) => ({
567
+ px: yScale.scale(v),
568
+ label: yTickLabels[i],
569
+ }));
570
+
571
+ // -- x scale and ticks
572
+ let xScale: LinearScale | BandScale;
573
+ let xTicks: AxisTick[] = [];
574
+ const fmtX = formatters?.x;
575
+ if (xKind === 'band') {
576
+ const n = xCol ? xCol.n : (geoms[0]?.y.n ?? 0);
577
+ xScale = bandScale(n, plot.x, plot.x + plot.width);
578
+ if (!spec.x.hide && n > 0) {
579
+ // at most `ticks` evenly-strided band labels
580
+ const step = Math.max(1, Math.ceil(n / Math.max(1, spec.x.ticks)));
581
+ for (let i = 0; i < n; i += step) {
582
+ const value = xCol ? xCol.values[i] : i;
583
+ const label = fmtX ? fmtX(value as number | string) : String(value);
584
+ xTicks.push({ px: xScale.center(i), label });
585
+ }
586
+ }
587
+ } else {
588
+ let d0: number;
589
+ let d1: number;
590
+ if (xNum && xIdx && xIdx.min <= xIdx.max) {
591
+ d0 = xIdx.min;
592
+ d1 = xIdx.max;
593
+ } else {
594
+ d0 = 0;
595
+ d1 = Math.max(1, (geoms[0]?.y.n ?? 1) - 1);
596
+ }
597
+ if (spec.x.domain[0] !== 'auto') d0 = spec.x.domain[0];
598
+ if (spec.x.domain[1] !== 'auto') d1 = spec.x.domain[1];
599
+ if (d0 === d1) [d0, d1] = niceDomain(d0, d1);
600
+ xScale = linearScale(d0, d1, plot.x, plot.x + plot.width);
601
+ if (!spec.x.hide) {
602
+ const values =
603
+ xKind === 'time'
604
+ ? timeTicks(d0, d1, spec.x.ticks)
605
+ : linearTicks(d0, d1, spec.x.ticks);
606
+ const span = d1 - d0;
607
+ xTicks = values.map((v) => ({
608
+ px: xScale.scale(v),
609
+ label: fmtX
610
+ ? fmtX(v)
611
+ : xKind === 'time'
612
+ ? formatTimeTick(v, span)
613
+ : formatNumberTick(v),
614
+ }));
615
+ }
616
+ }
617
+
618
+ const layout: Layout = {
619
+ key,
620
+ plot,
621
+ xScale,
622
+ yScale,
623
+ xTicks,
624
+ yTicks,
625
+ geoms,
626
+ xCol,
627
+ prepMs: now() - t0,
628
+ };
629
+ this._layoutCache = layout;
630
+ this._cachedSpec = spec;
631
+ this._cachedTheme = this.theme;
632
+ return layout;
633
+ }
634
+
635
+ private _cachedSpec: PlotSpec | undefined;
636
+ private _cachedTheme: Record<string, unknown> | null | undefined;
637
+
638
+ // --- render host ---------------------------------------------------------
639
+
640
+ private _host(): RenderHost {
641
+ return {
642
+ scatterGrid: (id, key, _n) => {
643
+ let grid = this._scatterGrids.get(id);
644
+ if (!grid || grid.key !== key) {
645
+ const [cell, gw, gh] = key.split('|');
646
+ grid = makeScatterGrid(key, Number(cell), Number(gw), Number(gh));
647
+ this._scatterGrids.set(id, grid);
648
+ }
649
+ return grid;
650
+ },
651
+ blitImage: (x, y, w, h, fill, contentKey) => {
652
+ const app = this.app as {
653
+ display?: { Render?: unknown };
654
+ } | null;
655
+ if (!SurfaceClass || !app?.display?.Render) return false;
656
+ const ctx = this._paintCtx;
657
+ if (!ctx || typeof ctx.drawImage !== 'function') return false;
658
+ try {
659
+ if (this._image && (this._image.w !== w || this._image.h !== h)) {
660
+ this._image.sctx.destroy?.();
661
+ this._image.surface.destroy();
662
+ this._image = null;
663
+ }
664
+ if (!this._image) {
665
+ const surface = new SurfaceClass(this.app, { width: w, height: h });
666
+ const sctx = surface.getContext('2d');
667
+ this._image = {
668
+ w,
669
+ h,
670
+ surface,
671
+ sctx,
672
+ data: sctx.createImageData(w, h),
673
+ contentKey: '',
674
+ };
675
+ }
676
+ const img = this._image;
677
+ // an unchanged content key means the retained surface already
678
+ // holds these pixels: a repaint (a crosshair crossing the plot)
679
+ // is one composite, not a megabyte re-upload
680
+ if (!contentKey || img.contentKey !== contentKey) {
681
+ img.data.data.fill(0);
682
+ fill(img.data.data);
683
+ img.sctx.putImageData(img.data, 0, 0);
684
+ img.contentKey = contentKey ?? '';
685
+ }
686
+ ctx.drawImage!(img.surface, x, y);
687
+ return true;
688
+ } catch {
689
+ // a server that refuses the pixmap: the rect path is still right
690
+ return false;
691
+ }
692
+ },
693
+ };
694
+ }
695
+
696
+ private _paintCtx: PlotContext | null = null;
697
+
698
+ // --- painting ------------------------------------------------------------
699
+
700
+ override paint(ctx: Context2D): void {
701
+ super.paint(ctx);
702
+ const t0 = now();
703
+ const layout = this._layout();
704
+ if (!layout) return;
705
+ const c = ctx as PlotContext;
706
+ if (typeof c.fillRect !== 'function') return;
707
+ this._paintCtx = c;
708
+
709
+ const stats: FrameStatsSink = {
710
+ pointsSpanned: 0,
711
+ commands: 0,
712
+ estimatedWireBytes: 0,
713
+ series: [],
714
+ };
715
+ const { spec } = this._props();
716
+ const { plot } = layout;
717
+
718
+ this._paintGridAndAxes(c, layout, stats);
719
+
720
+ // one rectangular clip around the series pass: server-side fast paths
721
+ // stay available, and sparse strokes cannot escape the plot
722
+ const clipped =
723
+ canPath(c) &&
724
+ typeof c.rect === 'function' &&
725
+ typeof c.clip === 'function';
726
+ if (clipped) {
727
+ c.save();
728
+ c.beginPath?.();
729
+ c.rect?.(plot.x, plot.y, plot.width, plot.height);
730
+ c.clip?.();
731
+ }
732
+ const env = {
733
+ ctx: c,
734
+ plot,
735
+ xScale: layout.xScale,
736
+ yScale: layout.yScale,
737
+ stats,
738
+ host: this._host(),
739
+ };
740
+ for (const geom of layout.geoms) renderSeries(env, geom);
741
+ if (clipped) c.restore();
742
+ this._paintCtx = null;
743
+
744
+ const onFrameStats = spec ? this._props().onFrameStats : undefined;
745
+ if (onFrameStats) {
746
+ const report: ChartFrameStats = {
747
+ prepMs: layout.prepMs,
748
+ paintMs: now() - t0,
749
+ pointsSpanned: stats.pointsSpanned,
750
+ commands: stats.commands,
751
+ estimatedWireBytes: stats.estimatedWireBytes,
752
+ series: stats.series,
753
+ };
754
+ microtask(() => {
755
+ if (!this.destroyed) onFrameStats(report);
756
+ });
757
+ }
758
+ }
759
+
760
+ private _paintGridAndAxes(
761
+ ctx: PlotContext,
762
+ layout: Layout,
763
+ stats: FrameStatsSink,
764
+ ): void {
765
+ const { spec } = this._props();
766
+ if (!spec) return;
767
+ const { plot, xTicks, yTicks } = layout;
768
+ const lineColor = this._color('$border', '#cccccc');
769
+ const labelColor = this._color('$textMuted', '#777777');
770
+ const labelSize = Math.max(
771
+ 9,
772
+ Math.round(this.resolvedTextStyle().size * 0.8),
773
+ );
774
+
775
+ // grid: 1px rules batched into one request per direction
776
+ if (spec.grid) {
777
+ const rects: number[] = [];
778
+ if (spec.grid.horizontal) {
779
+ for (const t of yTicks) {
780
+ const y = Math.round(t.px);
781
+ if (y > plot.y && y < plot.y + plot.height) {
782
+ rects.push(plot.x, y, plot.width, 1);
783
+ }
784
+ }
785
+ }
786
+ if (spec.grid.vertical) {
787
+ for (const t of xTicks) {
788
+ const x = Math.round(t.px);
789
+ if (x > plot.x && x < plot.x + plot.width) {
790
+ rects.push(x, plot.y, 1, plot.height);
791
+ }
792
+ }
793
+ }
794
+ if (rects.length) {
795
+ ctx.save();
796
+ ctx.fillStyle = lineColor;
797
+ if (ctx.globalAlpha !== undefined) ctx.globalAlpha = 0.45;
798
+ if (typeof ctx.fillRects === 'function') ctx.fillRects(rects);
799
+ else {
800
+ for (let i = 0; i + 3 < rects.length; i += 4) {
801
+ ctx.fillRect(rects[i], rects[i + 1], rects[i + 2], rects[i + 3]);
802
+ }
803
+ }
804
+ ctx.restore();
805
+ stats.commands++;
806
+ stats.estimatedWireBytes += (rects.length / 4) * 8;
807
+ }
808
+ }
809
+
810
+ // axis lines
811
+ const axisRects: number[] = [];
812
+ if (!spec.x.hide) {
813
+ axisRects.push(plot.x, plot.y + plot.height, plot.width, 1);
814
+ }
815
+ if (!spec.y.hide) axisRects.push(plot.x - 1, plot.y, 1, plot.height + 1);
816
+ if (axisRects.length) {
817
+ ctx.save();
818
+ ctx.fillStyle = lineColor;
819
+ if (typeof ctx.fillRects === 'function') ctx.fillRects(axisRects);
820
+ else {
821
+ for (let i = 0; i + 3 < axisRects.length; i += 4) {
822
+ ctx.fillRect(
823
+ axisRects[i],
824
+ axisRects[i + 1],
825
+ axisRects[i + 2],
826
+ axisRects[i + 3],
827
+ );
828
+ }
829
+ }
830
+ ctx.restore();
831
+ stats.commands++;
832
+ stats.estimatedWireBytes += (axisRects.length / 4) * 8;
833
+ }
834
+
835
+ // labels: glyphs are cached server-side, layouts cached here
836
+ if (!spec.y.hide) {
837
+ for (const t of yTicks) {
838
+ const l = this._label(t.label, labelSize, labelColor);
839
+ if (!l) continue;
840
+ l.draw(ctx, plot.x - TICK_GAP - l.width, t.px - l.height / 2);
841
+ stats.commands++;
842
+ }
843
+ }
844
+ if (!spec.x.hide) {
845
+ const baseY = plot.y + plot.height + 4;
846
+ let lastRight = -Infinity;
847
+ for (const t of xTicks) {
848
+ const l = this._label(t.label, labelSize, labelColor);
849
+ if (!l) continue;
850
+ const x = t.px - l.width / 2;
851
+ // drop labels that would collide rather than letting them smear
852
+ if (x < lastRight + 4) continue;
853
+ lastRight = x + l.width;
854
+ l.draw(ctx, x, baseY);
855
+ stats.commands++;
856
+ }
857
+ }
858
+ }
859
+
860
+ // --- the tooltip's questions --------------------------------------------
861
+
862
+ /** The plot rectangle in window coordinates, for overlay positioning. */
863
+ plotRect(): PlotRect | null {
864
+ return this._layout()?.plot ?? null;
865
+ }
866
+
867
+ /**
868
+ * What is under a window-coordinate pointer x: the snapped index, its x
869
+ * value, and every series' value and pixel position there. Null outside
870
+ * the data or before layout. O(log n) against sorted data.
871
+ */
872
+ hitAt(winX: number): ChartHit | null {
873
+ const layout = this._layout();
874
+ const { spec } = this._props();
875
+ if (!layout || !spec || layout.geoms.length === 0) return null;
876
+ const { plot, xScale, yScale } = layout;
877
+ const clamped = Math.max(plot.x, Math.min(plot.x + plot.width, winX));
878
+
879
+ let index: number;
880
+ let px: number;
881
+ let xValue: number | string;
882
+ if (xScale.kind === 'band') {
883
+ index = xScale.indexAt(clamped);
884
+ if (index < 0) return null;
885
+ px = xScale.center(index);
886
+ xValue = layout.xCol
887
+ ? (layout.xCol.values[index] as number | string)
888
+ : index;
889
+ } else {
890
+ const xv = xScale.invert(clamped);
891
+ const g0 = layout.geoms[0];
892
+ if (g0.x && g0.xIdx) {
893
+ index = nearestIndex(
894
+ g0.xIdx,
895
+ g0.x.values,
896
+ Math.min(g0.x.n, g0.y.n),
897
+ xv,
898
+ );
899
+ if (index < 0) return null;
900
+ xValue = g0.x.values[index] as number;
901
+ px = xScale.scale(xValue);
902
+ } else {
903
+ index = Math.max(0, Math.min(g0.y.n - 1, Math.round(xv)));
904
+ xValue = index;
905
+ px = xScale.scale(index);
906
+ }
907
+ }
908
+
909
+ const points: ChartHit['points'] = [];
910
+ for (const geom of layout.geoms) {
911
+ // the tooltip reports the raw series value, not the stack top
912
+ const rawCol = numericColumn(
913
+ resolveColumn(this._props().data as ChartSourceData, geom.spec.id),
914
+ );
915
+ if (!rawCol || index >= rawCol.n) continue;
916
+ const value = rawCol.values[index] as number;
917
+ if (Number.isNaN(value)) continue;
918
+ // the marker sits on what is painted — the stack top for stacked series
919
+ const painted = geom.y.values[index] as number;
920
+ points.push({
921
+ id: geom.spec.id,
922
+ label: geom.spec.label,
923
+ color: geom.color,
924
+ value,
925
+ py: yScale.scale(Number.isNaN(painted) ? value : painted),
926
+ });
927
+ }
928
+ if (points.length === 0) return null;
929
+ const xSpan = xScale.kind === 'band' ? 0 : xScale.d1 - xScale.d0;
930
+ return { index, xValue, px, xSpan, plot, points };
931
+ }
932
+ }