@react-x11/components 0.8.0 → 0.10.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 (721) hide show
  1. package/README.md +105 -38
  2. package/dist/charts/node.d.ts +12 -2
  3. package/dist/charts/node.d.ts.map +1 -1
  4. package/dist/charts/node.js +50 -16
  5. package/dist/charts/node.js.map +1 -1
  6. package/dist/charts/render.d.ts +12 -3
  7. package/dist/charts/render.d.ts.map +1 -1
  8. package/dist/charts/render.js +94 -25
  9. package/dist/charts/render.js.map +1 -1
  10. package/dist/code/index.d.ts.map +1 -1
  11. package/dist/code/index.js +3 -1
  12. package/dist/code/index.js.map +1 -1
  13. package/dist/code-editor/completion.d.ts.map +1 -1
  14. package/dist/code-editor/completion.js +3 -2
  15. package/dist/code-editor/completion.js.map +1 -1
  16. package/dist/code-editor/index.d.ts.map +1 -1
  17. package/dist/code-editor/index.js +19 -0
  18. package/dist/code-editor/index.js.map +1 -1
  19. package/dist/code-editor/node.d.ts +177 -7
  20. package/dist/code-editor/node.d.ts.map +1 -1
  21. package/dist/code-editor/node.js +1329 -164
  22. package/dist/code-editor/node.js.map +1 -1
  23. package/dist/code-language/languages/glsl.d.ts.map +1 -1
  24. package/dist/code-language/languages/glsl.js +10 -2
  25. package/dist/code-language/languages/glsl.js.map +1 -1
  26. package/dist/code-language/languages/javascript.d.ts.map +1 -1
  27. package/dist/code-language/languages/javascript.js +18 -3
  28. package/dist/code-language/languages/javascript.js.map +1 -1
  29. package/dist/code-language/languages/json.d.ts.map +1 -1
  30. package/dist/code-language/languages/json.js +10 -2
  31. package/dist/code-language/languages/json.js.map +1 -1
  32. package/dist/code-language/languages/shell.d.ts.map +1 -1
  33. package/dist/code-language/languages/shell.js +10 -2
  34. package/dist/code-language/languages/shell.js.map +1 -1
  35. package/dist/code-language/languages/sql.d.ts.map +1 -1
  36. package/dist/code-language/languages/sql.js +20 -2
  37. package/dist/code-language/languages/sql.js.map +1 -1
  38. package/dist/code-language/stream.d.ts +22 -0
  39. package/dist/code-language/stream.d.ts.map +1 -1
  40. package/dist/code-language/stream.js +259 -9
  41. package/dist/code-language/stream.js.map +1 -1
  42. package/dist/code-language/types.d.ts +5 -4
  43. package/dist/code-language/types.d.ts.map +1 -1
  44. package/dist/codeblock/index.d.ts +13 -2
  45. package/dist/codeblock/index.d.ts.map +1 -1
  46. package/dist/codeblock/index.js +20 -3
  47. package/dist/codeblock/index.js.map +1 -1
  48. package/dist/embed/client.d.ts +48 -3
  49. package/dist/embed/client.d.ts.map +1 -1
  50. package/dist/embed/client.js +79 -5
  51. package/dist/embed/client.js.map +1 -1
  52. package/dist/embed/index.d.ts +1 -1
  53. package/dist/embed/index.d.ts.map +1 -1
  54. package/dist/embed/index.js +1 -1
  55. package/dist/embed/index.js.map +1 -1
  56. package/dist/flow/draw.d.ts +50 -0
  57. package/dist/flow/draw.d.ts.map +1 -1
  58. package/dist/flow/draw.js +132 -33
  59. package/dist/flow/draw.js.map +1 -1
  60. package/dist/flow/gl/color.d.ts +13 -0
  61. package/dist/flow/gl/color.d.ts.map +1 -0
  62. package/dist/flow/gl/color.js +82 -0
  63. package/dist/flow/gl/color.js.map +1 -0
  64. package/dist/flow/gl/index.d.ts +60 -0
  65. package/dist/flow/gl/index.d.ts.map +1 -0
  66. package/dist/flow/gl/index.js +283 -0
  67. package/dist/flow/gl/index.js.map +1 -0
  68. package/dist/flow/gl/pack.d.ts +133 -0
  69. package/dist/flow/gl/pack.d.ts.map +1 -0
  70. package/dist/flow/gl/pack.js +408 -0
  71. package/dist/flow/gl/pack.js.map +1 -0
  72. package/dist/flow/gl/renderer.d.ts +95 -0
  73. package/dist/flow/gl/renderer.d.ts.map +1 -0
  74. package/dist/flow/gl/renderer.js +459 -0
  75. package/dist/flow/gl/renderer.js.map +1 -0
  76. package/dist/flow/gl/shaders.d.ts +79 -0
  77. package/dist/flow/gl/shaders.d.ts.map +1 -0
  78. package/dist/flow/gl/shaders.js +346 -0
  79. package/dist/flow/gl/shaders.js.map +1 -0
  80. package/dist/flow/gl/text.d.ts +318 -0
  81. package/dist/flow/gl/text.d.ts.map +1 -0
  82. package/dist/flow/gl/text.js +1103 -0
  83. package/dist/flow/gl/text.js.map +1 -0
  84. package/dist/flow/index.d.ts +1 -1
  85. package/dist/flow/index.d.ts.map +1 -1
  86. package/dist/flow/index.js +619 -64
  87. package/dist/flow/index.js.map +1 -1
  88. package/dist/flow/node.d.ts +621 -72
  89. package/dist/flow/node.d.ts.map +1 -1
  90. package/dist/flow/node.js +2253 -1018
  91. package/dist/flow/node.js.map +1 -1
  92. package/dist/flow/paint.d.ts +35 -0
  93. package/dist/flow/paint.d.ts.map +1 -0
  94. package/dist/flow/paint.js +393 -0
  95. package/dist/flow/paint.js.map +1 -0
  96. package/dist/flow/paths.d.ts +14 -0
  97. package/dist/flow/paths.d.ts.map +1 -1
  98. package/dist/flow/paths.js +45 -19
  99. package/dist/flow/paths.js.map +1 -1
  100. package/dist/flow/scene.d.ts +584 -0
  101. package/dist/flow/scene.d.ts.map +1 -0
  102. package/dist/flow/scene.js +1453 -0
  103. package/dist/flow/scene.js.map +1 -0
  104. package/dist/flow/types.d.ts +111 -1
  105. package/dist/flow/types.d.ts.map +1 -1
  106. package/dist/html/controls.d.ts +28 -0
  107. package/dist/html/controls.d.ts.map +1 -1
  108. package/dist/html/controls.js +52 -2
  109. package/dist/html/controls.js.map +1 -1
  110. package/dist/html/css/calc.d.ts +14 -0
  111. package/dist/html/css/calc.d.ts.map +1 -0
  112. package/dist/html/css/calc.js +344 -0
  113. package/dist/html/css/calc.js.map +1 -0
  114. package/dist/html/css/cascade.d.ts +240 -6
  115. package/dist/html/css/cascade.d.ts.map +1 -1
  116. package/dist/html/css/cascade.js +1327 -66
  117. package/dist/html/css/cascade.js.map +1 -1
  118. package/dist/html/css/color.d.ts +23 -0
  119. package/dist/html/css/color.d.ts.map +1 -0
  120. package/dist/html/css/color.js +740 -0
  121. package/dist/html/css/color.js.map +1 -0
  122. package/dist/html/css/content.d.ts +92 -0
  123. package/dist/html/css/content.d.ts.map +1 -0
  124. package/dist/html/css/content.js +388 -0
  125. package/dist/html/css/content.js.map +1 -0
  126. package/dist/html/css/counter-styles.d.ts +76 -0
  127. package/dist/html/css/counter-styles.d.ts.map +1 -0
  128. package/dist/html/css/counter-styles.js +893 -0
  129. package/dist/html/css/counter-styles.js.map +1 -0
  130. package/dist/html/css/decode.d.ts +12 -0
  131. package/dist/html/css/decode.d.ts.map +1 -0
  132. package/dist/html/css/decode.js +116 -0
  133. package/dist/html/css/decode.js.map +1 -0
  134. package/dist/html/css/parse.d.ts +110 -10
  135. package/dist/html/css/parse.d.ts.map +1 -1
  136. package/dist/html/css/parse.js +1473 -180
  137. package/dist/html/css/parse.js.map +1 -1
  138. package/dist/html/css/style.d.ts +498 -15
  139. package/dist/html/css/style.d.ts.map +1 -1
  140. package/dist/html/css/style.js +3698 -206
  141. package/dist/html/css/style.js.map +1 -1
  142. package/dist/html/css/ua.d.ts.map +1 -1
  143. package/dist/html/css/ua.js +57 -11
  144. package/dist/html/css/ua.js.map +1 -1
  145. package/dist/html/css/values.d.ts +37 -3
  146. package/dist/html/css/values.d.ts.map +1 -1
  147. package/dist/html/css/values.js +122 -48
  148. package/dist/html/css/values.js.map +1 -1
  149. package/dist/html/css/vars.d.ts +52 -0
  150. package/dist/html/css/vars.d.ts.map +1 -0
  151. package/dist/html/css/vars.js +358 -0
  152. package/dist/html/css/vars.js.map +1 -0
  153. package/dist/html/dom.d.ts +30 -4
  154. package/dist/html/dom.d.ts.map +1 -1
  155. package/dist/html/dom.js +278 -17
  156. package/dist/html/dom.js.map +1 -1
  157. package/dist/html/fonts.d.ts +106 -0
  158. package/dist/html/fonts.d.ts.map +1 -0
  159. package/dist/html/fonts.js +565 -0
  160. package/dist/html/fonts.js.map +1 -0
  161. package/dist/html/gif.d.ts +15 -0
  162. package/dist/html/gif.d.ts.map +1 -0
  163. package/dist/html/gif.js +229 -0
  164. package/dist/html/gif.js.map +1 -0
  165. package/dist/html/index.d.ts +50 -11
  166. package/dist/html/index.d.ts.map +1 -1
  167. package/dist/html/index.js +115 -9
  168. package/dist/html/index.js.map +1 -1
  169. package/dist/html/layout/block.d.ts +226 -3
  170. package/dist/html/layout/block.d.ts.map +1 -1
  171. package/dist/html/layout/block.js +2937 -197
  172. package/dist/html/layout/block.js.map +1 -1
  173. package/dist/html/layout/boxes.d.ts +340 -17
  174. package/dist/html/layout/boxes.d.ts.map +1 -1
  175. package/dist/html/layout/boxes.js +1714 -182
  176. package/dist/html/layout/boxes.js.map +1 -1
  177. package/dist/html/layout/cache.d.ts +58 -0
  178. package/dist/html/layout/cache.d.ts.map +1 -0
  179. package/dist/html/layout/cache.js +224 -0
  180. package/dist/html/layout/cache.js.map +1 -0
  181. package/dist/html/layout/collapse.d.ts +45 -0
  182. package/dist/html/layout/collapse.d.ts.map +1 -0
  183. package/dist/html/layout/collapse.js +246 -0
  184. package/dist/html/layout/collapse.js.map +1 -0
  185. package/dist/html/layout/css-grid.d.ts +7 -0
  186. package/dist/html/layout/css-grid.d.ts.map +1 -0
  187. package/dist/html/layout/css-grid.js +900 -0
  188. package/dist/html/layout/css-grid.js.map +1 -0
  189. package/dist/html/layout/flex.d.ts.map +1 -1
  190. package/dist/html/layout/flex.js +1025 -89
  191. package/dist/html/layout/flex.js.map +1 -1
  192. package/dist/html/layout/floats.d.ts +45 -6
  193. package/dist/html/layout/floats.d.ts.map +1 -1
  194. package/dist/html/layout/floats.js +113 -14
  195. package/dist/html/layout/floats.js.map +1 -1
  196. package/dist/html/layout/grid-lines.d.ts +39 -0
  197. package/dist/html/layout/grid-lines.d.ts.map +1 -0
  198. package/dist/html/layout/grid-lines.js +119 -0
  199. package/dist/html/layout/grid-lines.js.map +1 -0
  200. package/dist/html/layout/grid.d.ts +53 -0
  201. package/dist/html/layout/grid.d.ts.map +1 -0
  202. package/dist/html/layout/grid.js +153 -0
  203. package/dist/html/layout/grid.js.map +1 -0
  204. package/dist/html/layout/inline.d.ts +151 -1
  205. package/dist/html/layout/inline.d.ts.map +1 -1
  206. package/dist/html/layout/inline.js +3375 -174
  207. package/dist/html/layout/inline.js.map +1 -1
  208. package/dist/html/layout/shaping.d.ts +6 -0
  209. package/dist/html/layout/shaping.d.ts.map +1 -0
  210. package/dist/html/layout/shaping.js +100 -0
  211. package/dist/html/layout/shaping.js.map +1 -0
  212. package/dist/html/layout/table.d.ts +3 -0
  213. package/dist/html/layout/table.d.ts.map +1 -1
  214. package/dist/html/layout/table.js +681 -175
  215. package/dist/html/layout/table.js.map +1 -1
  216. package/dist/html/layout/tracks.d.ts +44 -0
  217. package/dist/html/layout/tracks.d.ts.map +1 -0
  218. package/dist/html/layout/tracks.js +349 -0
  219. package/dist/html/layout/tracks.js.map +1 -0
  220. package/dist/html/node.d.ts +172 -5
  221. package/dist/html/node.d.ts.map +1 -1
  222. package/dist/html/node.js +1336 -103
  223. package/dist/html/node.js.map +1 -1
  224. package/dist/html/paint.d.ts +92 -3
  225. package/dist/html/paint.d.ts.map +1 -1
  226. package/dist/html/paint.js +3503 -141
  227. package/dist/html/paint.js.map +1 -1
  228. package/dist/html/resources.d.ts +60 -14
  229. package/dist/html/resources.d.ts.map +1 -1
  230. package/dist/html/resources.js +122 -36
  231. package/dist/html/resources.js.map +1 -1
  232. package/dist/html/surfaces.d.ts +23 -0
  233. package/dist/html/surfaces.d.ts.map +1 -0
  234. package/dist/html/surfaces.js +68 -0
  235. package/dist/html/surfaces.js.map +1 -0
  236. package/dist/html/svg.d.ts +80 -0
  237. package/dist/html/svg.d.ts.map +1 -0
  238. package/dist/html/svg.js +435 -0
  239. package/dist/html/svg.js.map +1 -0
  240. package/dist/html/url.d.ts +23 -0
  241. package/dist/html/url.d.ts.map +1 -0
  242. package/dist/html/url.js +80 -0
  243. package/dist/html/url.js.map +1 -0
  244. package/dist/index.d.ts +2 -2
  245. package/dist/index.d.ts.map +1 -1
  246. package/dist/index.js +1 -1
  247. package/dist/index.js.map +1 -1
  248. package/dist/internal/collate.d.ts +3 -0
  249. package/dist/internal/collate.d.ts.map +1 -0
  250. package/dist/internal/collate.js +11 -0
  251. package/dist/internal/collate.js.map +1 -0
  252. package/dist/{markdown → internal/markdown}/ast.d.ts +23 -0
  253. package/dist/internal/markdown/ast.d.ts.map +1 -0
  254. package/dist/internal/markdown/ast.js +22 -0
  255. package/dist/internal/markdown/ast.js.map +1 -0
  256. package/dist/internal/markdown/parse.d.ts.map +1 -0
  257. package/dist/{markdown → internal/markdown}/parse.js +221 -30
  258. package/dist/internal/markdown/parse.js.map +1 -0
  259. package/dist/internal/markdown/stringify.d.ts +4 -0
  260. package/dist/internal/markdown/stringify.d.ts.map +1 -0
  261. package/dist/internal/markdown/stringify.js +684 -0
  262. package/dist/internal/markdown/stringify.js.map +1 -0
  263. package/dist/internal/markdown/tags.d.ts.map +1 -0
  264. package/dist/internal/markdown/tags.js.map +1 -0
  265. package/dist/internal/prewarm.d.ts +18 -0
  266. package/dist/internal/prewarm.d.ts.map +1 -0
  267. package/dist/internal/prewarm.js +42 -0
  268. package/dist/internal/prewarm.js.map +1 -0
  269. package/dist/internal/scroll.d.ts +3 -2
  270. package/dist/internal/scroll.d.ts.map +1 -1
  271. package/dist/internal/scroll.js +1 -0
  272. package/dist/internal/scroll.js.map +1 -1
  273. package/dist/internal/sdf.d.ts +20 -0
  274. package/dist/internal/sdf.d.ts.map +1 -0
  275. package/dist/internal/sdf.js +216 -0
  276. package/dist/internal/sdf.js.map +1 -0
  277. package/dist/internal/splice.d.ts +12 -0
  278. package/dist/internal/splice.d.ts.map +1 -0
  279. package/dist/internal/splice.js +23 -0
  280. package/dist/internal/splice.js.map +1 -0
  281. package/dist/internal/window.d.ts +12 -0
  282. package/dist/internal/window.d.ts.map +1 -1
  283. package/dist/internal/window.js +23 -6
  284. package/dist/internal/window.js.map +1 -1
  285. package/dist/maps/anchors.d.ts +103 -0
  286. package/dist/maps/anchors.d.ts.map +1 -0
  287. package/dist/maps/anchors.js +790 -0
  288. package/dist/maps/anchors.js.map +1 -0
  289. package/dist/maps/controller.d.ts +340 -0
  290. package/dist/maps/controller.d.ts.map +1 -0
  291. package/dist/maps/controller.js +822 -0
  292. package/dist/maps/controller.js.map +1 -0
  293. package/dist/maps/gl/buckets.d.ts +99 -0
  294. package/dist/maps/gl/buckets.d.ts.map +1 -0
  295. package/dist/maps/gl/buckets.js +365 -0
  296. package/dist/maps/gl/buckets.js.map +1 -0
  297. package/dist/maps/gl/build-worker.d.ts +15 -0
  298. package/dist/maps/gl/build-worker.d.ts.map +1 -0
  299. package/dist/maps/gl/build-worker.js +44 -0
  300. package/dist/maps/gl/build-worker.js.map +1 -0
  301. package/dist/maps/gl/color.d.ts +8 -0
  302. package/dist/maps/gl/color.d.ts.map +1 -0
  303. package/dist/maps/gl/color.js +57 -0
  304. package/dist/maps/gl/color.js.map +1 -0
  305. package/dist/maps/gl/cover.d.ts +70 -0
  306. package/dist/maps/gl/cover.d.ts.map +1 -0
  307. package/dist/maps/gl/cover.js +137 -0
  308. package/dist/maps/gl/cover.js.map +1 -0
  309. package/dist/maps/gl/index.d.ts +3 -0
  310. package/dist/maps/gl/index.d.ts.map +1 -0
  311. package/dist/maps/gl/index.js +20 -0
  312. package/dist/maps/gl/index.js.map +1 -0
  313. package/dist/maps/gl/markers.d.ts +28 -0
  314. package/dist/maps/gl/markers.d.ts.map +1 -0
  315. package/dist/maps/gl/markers.js +60 -0
  316. package/dist/maps/gl/markers.js.map +1 -0
  317. package/dist/maps/gl/overlays.d.ts +68 -0
  318. package/dist/maps/gl/overlays.d.ts.map +1 -0
  319. package/dist/maps/gl/overlays.js +300 -0
  320. package/dist/maps/gl/overlays.js.map +1 -0
  321. package/dist/maps/gl/pane.d.ts +12 -0
  322. package/dist/maps/gl/pane.d.ts.map +1 -0
  323. package/dist/maps/gl/pane.js +37 -0
  324. package/dist/maps/gl/pane.js.map +1 -0
  325. package/dist/maps/gl/placement.d.ts +124 -0
  326. package/dist/maps/gl/placement.d.ts.map +1 -0
  327. package/dist/maps/gl/placement.js +642 -0
  328. package/dist/maps/gl/placement.js.map +1 -0
  329. package/dist/maps/gl/renderer.d.ts +384 -0
  330. package/dist/maps/gl/renderer.d.ts.map +1 -0
  331. package/dist/maps/gl/renderer.js +1184 -0
  332. package/dist/maps/gl/renderer.js.map +1 -0
  333. package/dist/maps/gl/shaders.d.ts +121 -0
  334. package/dist/maps/gl/shaders.d.ts.map +1 -0
  335. package/dist/maps/gl/shaders.js +453 -0
  336. package/dist/maps/gl/shaders.js.map +1 -0
  337. package/dist/maps/gl/store.d.ts +125 -0
  338. package/dist/maps/gl/store.d.ts.map +1 -0
  339. package/dist/maps/gl/store.js +512 -0
  340. package/dist/maps/gl/store.js.map +1 -0
  341. package/dist/maps/gl/text.d.ts +283 -0
  342. package/dist/maps/gl/text.d.ts.map +1 -0
  343. package/dist/maps/gl/text.js +698 -0
  344. package/dist/maps/gl/text.js.map +1 -0
  345. package/dist/maps/gl/view.d.ts +345 -0
  346. package/dist/maps/gl/view.d.ts.map +1 -0
  347. package/dist/maps/gl/view.js +1209 -0
  348. package/dist/maps/gl/view.js.map +1 -0
  349. package/dist/maps/icons.d.ts +32 -0
  350. package/dist/maps/icons.d.ts.map +1 -0
  351. package/dist/maps/icons.js +151 -0
  352. package/dist/maps/icons.js.map +1 -0
  353. package/dist/maps/index.d.ts +3 -1
  354. package/dist/maps/index.d.ts.map +1 -1
  355. package/dist/maps/index.js +218 -52
  356. package/dist/maps/index.js.map +1 -1
  357. package/dist/maps/labels.d.ts +91 -18
  358. package/dist/maps/labels.d.ts.map +1 -1
  359. package/dist/maps/labels.js +376 -140
  360. package/dist/maps/labels.js.map +1 -1
  361. package/dist/maps/node.d.ts +179 -56
  362. package/dist/maps/node.d.ts.map +1 -1
  363. package/dist/maps/node.js +663 -537
  364. package/dist/maps/node.js.map +1 -1
  365. package/dist/maps/overlay.d.ts +72 -9
  366. package/dist/maps/overlay.d.ts.map +1 -1
  367. package/dist/maps/overlay.js +108 -28
  368. package/dist/maps/overlay.js.map +1 -1
  369. package/dist/maps/paint.d.ts +3 -0
  370. package/dist/maps/paint.d.ts.map +1 -1
  371. package/dist/maps/paint.js.map +1 -1
  372. package/dist/maps/proj.d.ts +62 -0
  373. package/dist/maps/proj.d.ts.map +1 -1
  374. package/dist/maps/proj.js +101 -0
  375. package/dist/maps/proj.js.map +1 -1
  376. package/dist/maps/renderer.d.ts +69 -0
  377. package/dist/maps/renderer.d.ts.map +1 -0
  378. package/dist/maps/renderer.js +66 -0
  379. package/dist/maps/renderer.js.map +1 -0
  380. package/dist/maps/sources.d.ts +30 -6
  381. package/dist/maps/sources.d.ts.map +1 -1
  382. package/dist/maps/sources.js +22 -3
  383. package/dist/maps/sources.js.map +1 -1
  384. package/dist/maps/style.d.ts +35 -0
  385. package/dist/maps/style.d.ts.map +1 -1
  386. package/dist/maps/style.js.map +1 -1
  387. package/dist/maps/styles.d.ts +12 -0
  388. package/dist/maps/styles.d.ts.map +1 -1
  389. package/dist/maps/styles.js +120 -6
  390. package/dist/maps/styles.js.map +1 -1
  391. package/dist/maps/theme.d.ts +19 -0
  392. package/dist/maps/theme.d.ts.map +1 -0
  393. package/dist/maps/theme.js +44 -0
  394. package/dist/maps/theme.js.map +1 -0
  395. package/dist/maps/tiles.d.ts +147 -27
  396. package/dist/maps/tiles.d.ts.map +1 -1
  397. package/dist/maps/tiles.js +221 -54
  398. package/dist/maps/tiles.js.map +1 -1
  399. package/dist/maps/types.d.ts +213 -21
  400. package/dist/maps/types.d.ts.map +1 -1
  401. package/dist/markdown/expressions.d.ts +1 -1
  402. package/dist/markdown/expressions.d.ts.map +1 -1
  403. package/dist/markdown/expressions.js.map +1 -1
  404. package/dist/markdown/index.d.ts +7 -6
  405. package/dist/markdown/index.d.ts.map +1 -1
  406. package/dist/markdown/index.js +121 -50
  407. package/dist/markdown/index.js.map +1 -1
  408. package/dist/markdown/spans.d.ts +1 -1
  409. package/dist/markdown/spans.d.ts.map +1 -1
  410. package/dist/markdown/spans.js +6 -0
  411. package/dist/markdown/spans.js.map +1 -1
  412. package/dist/media-player/index.d.ts +11 -3
  413. package/dist/media-player/index.d.ts.map +1 -1
  414. package/dist/media-player/index.js +13 -2
  415. package/dist/media-player/index.js.map +1 -1
  416. package/dist/qml/containers.d.ts.map +1 -1
  417. package/dist/qml/containers.js +6 -1
  418. package/dist/qml/containers.js.map +1 -1
  419. package/dist/qml/interaction.d.ts.map +1 -1
  420. package/dist/qml/interaction.js +38 -5
  421. package/dist/qml/interaction.js.map +1 -1
  422. package/dist/qml/layouts.d.ts.map +1 -1
  423. package/dist/qml/layouts.js +21 -6
  424. package/dist/qml/layouts.js.map +1 -1
  425. package/dist/qml/qtquick.d.ts.map +1 -1
  426. package/dist/qml/qtquick.js +9 -2
  427. package/dist/qml/qtquick.js.map +1 -1
  428. package/dist/qml/react.d.ts.map +1 -1
  429. package/dist/qml/react.js +9 -7
  430. package/dist/qml/react.js.map +1 -1
  431. package/dist/reorder/clock.d.ts +7 -0
  432. package/dist/reorder/clock.d.ts.map +1 -0
  433. package/dist/reorder/clock.js +26 -0
  434. package/dist/reorder/clock.js.map +1 -0
  435. package/dist/reorder/index.d.ts +25 -3
  436. package/dist/reorder/index.d.ts.map +1 -1
  437. package/dist/reorder/index.js +64 -19
  438. package/dist/reorder/index.js.map +1 -1
  439. package/dist/rich-text-editor/clipboard.d.ts +23 -0
  440. package/dist/rich-text-editor/clipboard.d.ts.map +1 -0
  441. package/dist/rich-text-editor/clipboard.js +307 -0
  442. package/dist/rich-text-editor/clipboard.js.map +1 -0
  443. package/dist/rich-text-editor/collab.d.ts +32 -0
  444. package/dist/rich-text-editor/collab.d.ts.map +1 -0
  445. package/dist/rich-text-editor/collab.js +55 -0
  446. package/dist/rich-text-editor/collab.js.map +1 -0
  447. package/dist/rich-text-editor/commands.d.ts +50 -0
  448. package/dist/rich-text-editor/commands.d.ts.map +1 -0
  449. package/dist/rich-text-editor/commands.js +376 -0
  450. package/dist/rich-text-editor/commands.js.map +1 -0
  451. package/dist/rich-text-editor/drag.d.ts +68 -0
  452. package/dist/rich-text-editor/drag.d.ts.map +1 -0
  453. package/dist/rich-text-editor/drag.js +148 -0
  454. package/dist/rich-text-editor/drag.js.map +1 -0
  455. package/dist/rich-text-editor/html.d.ts +145 -0
  456. package/dist/rich-text-editor/html.d.ts.map +1 -0
  457. package/dist/rich-text-editor/html.js +516 -0
  458. package/dist/rich-text-editor/html.js.map +1 -0
  459. package/dist/rich-text-editor/index.d.ts +252 -0
  460. package/dist/rich-text-editor/index.d.ts.map +1 -0
  461. package/dist/rich-text-editor/index.js +856 -0
  462. package/dist/rich-text-editor/index.js.map +1 -0
  463. package/dist/rich-text-editor/inline.d.ts +94 -0
  464. package/dist/rich-text-editor/inline.d.ts.map +1 -0
  465. package/dist/rich-text-editor/inline.js +252 -0
  466. package/dist/rich-text-editor/inline.js.map +1 -0
  467. package/dist/rich-text-editor/keymap.d.ts +71 -0
  468. package/dist/rich-text-editor/keymap.d.ts.map +1 -0
  469. package/dist/rich-text-editor/keymap.js +394 -0
  470. package/dist/rich-text-editor/keymap.js.map +1 -0
  471. package/dist/rich-text-editor/keys.d.ts +40 -0
  472. package/dist/rich-text-editor/keys.d.ts.map +1 -0
  473. package/dist/rich-text-editor/keys.js +202 -0
  474. package/dist/rich-text-editor/keys.js.map +1 -0
  475. package/dist/rich-text-editor/look.d.ts +71 -0
  476. package/dist/rich-text-editor/look.d.ts.map +1 -0
  477. package/dist/rich-text-editor/look.js +342 -0
  478. package/dist/rich-text-editor/look.js.map +1 -0
  479. package/dist/rich-text-editor/markdown.d.ts +18 -0
  480. package/dist/rich-text-editor/markdown.d.ts.map +1 -0
  481. package/dist/rich-text-editor/markdown.js +496 -0
  482. package/dist/rich-text-editor/markdown.js.map +1 -0
  483. package/dist/rich-text-editor/marks.d.ts +9 -0
  484. package/dist/rich-text-editor/marks.d.ts.map +1 -0
  485. package/dist/rich-text-editor/marks.js +83 -0
  486. package/dist/rich-text-editor/marks.js.map +1 -0
  487. package/dist/rich-text-editor/nodes.d.ts +135 -0
  488. package/dist/rich-text-editor/nodes.d.ts.map +1 -0
  489. package/dist/rich-text-editor/nodes.js +397 -0
  490. package/dist/rich-text-editor/nodes.js.map +1 -0
  491. package/dist/rich-text-editor/render.d.ts +68 -0
  492. package/dist/rich-text-editor/render.d.ts.map +1 -0
  493. package/dist/rich-text-editor/render.js +518 -0
  494. package/dist/rich-text-editor/render.js.map +1 -0
  495. package/dist/rich-text-editor/schema.d.ts +16 -0
  496. package/dist/rich-text-editor/schema.d.ts.map +1 -0
  497. package/dist/rich-text-editor/schema.js +386 -0
  498. package/dist/rich-text-editor/schema.js.map +1 -0
  499. package/dist/rich-text-editor/store.d.ts +11 -0
  500. package/dist/rich-text-editor/store.d.ts.map +1 -0
  501. package/dist/rich-text-editor/store.js +43 -0
  502. package/dist/rich-text-editor/store.js.map +1 -0
  503. package/dist/rich-text-editor/suggest.d.ts +127 -0
  504. package/dist/rich-text-editor/suggest.d.ts.map +1 -0
  505. package/dist/rich-text-editor/suggest.js +0 -0
  506. package/dist/rich-text-editor/suggest.js.map +1 -0
  507. package/dist/rich-text-editor/tables.d.ts +41 -0
  508. package/dist/rich-text-editor/tables.d.ts.map +1 -0
  509. package/dist/rich-text-editor/tables.js +204 -0
  510. package/dist/rich-text-editor/tables.js.map +1 -0
  511. package/dist/rich-text-editor/toolbar.d.ts +58 -0
  512. package/dist/rich-text-editor/toolbar.d.ts.map +1 -0
  513. package/dist/rich-text-editor/toolbar.js +548 -0
  514. package/dist/rich-text-editor/toolbar.js.map +1 -0
  515. package/dist/rich-text-editor/view.d.ts +368 -0
  516. package/dist/rich-text-editor/view.d.ts.map +1 -0
  517. package/dist/rich-text-editor/view.js +1968 -0
  518. package/dist/rich-text-editor/view.js.map +1 -0
  519. package/dist/rich-text-editor/virtual.d.ts +54 -0
  520. package/dist/rich-text-editor/virtual.d.ts.map +1 -0
  521. package/dist/rich-text-editor/virtual.js +279 -0
  522. package/dist/rich-text-editor/virtual.js.map +1 -0
  523. package/dist/richtext/node.d.ts +71 -4
  524. package/dist/richtext/node.d.ts.map +1 -1
  525. package/dist/richtext/node.js +233 -28
  526. package/dist/richtext/node.js.map +1 -1
  527. package/dist/richtext/runs.d.ts +13 -8
  528. package/dist/richtext/runs.d.ts.map +1 -1
  529. package/dist/richtext/runs.js +18 -8
  530. package/dist/richtext/runs.js.map +1 -1
  531. package/dist/table/index.d.ts.map +1 -1
  532. package/dist/table/index.js +23 -0
  533. package/dist/table/index.js.map +1 -1
  534. package/dist/table/rows.d.ts +3 -2
  535. package/dist/table/rows.d.ts.map +1 -1
  536. package/dist/table/rows.js +20 -6
  537. package/dist/table/rows.js.map +1 -1
  538. package/dist/terminal/backends.d.ts +4 -1
  539. package/dist/terminal/backends.d.ts.map +1 -1
  540. package/dist/terminal/backends.js.map +1 -1
  541. package/dist/terminal/index.d.ts +18 -7
  542. package/dist/terminal/index.d.ts.map +1 -1
  543. package/dist/terminal/index.js +32 -11
  544. package/dist/terminal/index.js.map +1 -1
  545. package/dist/terminal/vt/pty.d.ts +13 -2
  546. package/dist/terminal/vt/pty.d.ts.map +1 -1
  547. package/dist/terminal/vt/pty.js +18 -3
  548. package/dist/terminal/vt/pty.js.map +1 -1
  549. package/dist/terminal-output/index.d.ts.map +1 -1
  550. package/dist/terminal-output/index.js +6 -1
  551. package/dist/terminal-output/index.js.map +1 -1
  552. package/dist/three/canvas.d.ts.map +1 -1
  553. package/dist/three/canvas.js +85 -7
  554. package/dist/three/canvas.js.map +1 -1
  555. package/dist/three/events.d.ts +22 -4
  556. package/dist/three/events.d.ts.map +1 -1
  557. package/dist/three/events.js +34 -4
  558. package/dist/three/events.js.map +1 -1
  559. package/dist/tree/index.d.ts.map +1 -1
  560. package/dist/tree/index.js +17 -0
  561. package/dist/tree/index.js.map +1 -1
  562. package/package.json +59 -31
  563. package/src/charts/node.ts +68 -28
  564. package/src/charts/render.ts +120 -30
  565. package/src/code/index.ts +3 -1
  566. package/src/code-editor/completion.ts +3 -2
  567. package/src/code-editor/index.ts +19 -0
  568. package/src/code-editor/node.ts +1574 -184
  569. package/src/code-language/languages/glsl.ts +12 -2
  570. package/src/code-language/languages/javascript.ts +21 -4
  571. package/src/code-language/languages/json.ts +12 -2
  572. package/src/code-language/languages/shell.ts +12 -2
  573. package/src/code-language/languages/sql.ts +22 -2
  574. package/src/code-language/stream.ts +257 -17
  575. package/src/code-language/types.ts +5 -4
  576. package/src/codeblock/index.ts +20 -3
  577. package/src/embed/client.ts +102 -8
  578. package/src/embed/index.ts +2 -0
  579. package/src/flow/draw.ts +167 -41
  580. package/src/flow/gl/color.ts +85 -0
  581. package/src/flow/gl/index.ts +342 -0
  582. package/src/flow/gl/pack.ts +585 -0
  583. package/src/flow/gl/renderer.ts +679 -0
  584. package/src/flow/gl/shaders.ts +371 -0
  585. package/src/flow/gl/text.ts +1295 -0
  586. package/src/flow/index.ts +794 -67
  587. package/src/flow/node.ts +2496 -1256
  588. package/src/flow/paint.ts +511 -0
  589. package/src/flow/paths.ts +80 -15
  590. package/src/flow/scene.ts +2199 -0
  591. package/src/flow/types.ts +113 -1
  592. package/src/html/controls.ts +73 -2
  593. package/src/html/css/calc.ts +385 -0
  594. package/src/html/css/cascade.ts +1403 -62
  595. package/src/html/css/color.ts +755 -0
  596. package/src/html/css/content.ts +417 -0
  597. package/src/html/css/counter-styles.ts +973 -0
  598. package/src/html/css/decode.ts +130 -0
  599. package/src/html/css/parse.ts +1514 -160
  600. package/src/html/css/style.ts +4102 -222
  601. package/src/html/css/ua.ts +58 -12
  602. package/src/html/css/values.ts +150 -50
  603. package/src/html/css/vars.ts +348 -0
  604. package/src/html/dom.ts +284 -17
  605. package/src/html/fonts.ts +641 -0
  606. package/src/html/gif.ts +233 -0
  607. package/src/html/index.ts +180 -20
  608. package/src/html/layout/block.ts +3456 -230
  609. package/src/html/layout/boxes.ts +2100 -190
  610. package/src/html/layout/cache.ts +289 -0
  611. package/src/html/layout/collapse.ts +317 -0
  612. package/src/html/layout/css-grid.ts +1063 -0
  613. package/src/html/layout/flex.ts +1115 -106
  614. package/src/html/layout/floats.ts +128 -14
  615. package/src/html/layout/grid-lines.ts +141 -0
  616. package/src/html/layout/grid.ts +181 -0
  617. package/src/html/layout/inline.ts +3943 -192
  618. package/src/html/layout/shaping.ts +140 -0
  619. package/src/html/layout/table.ts +696 -186
  620. package/src/html/layout/tracks.ts +437 -0
  621. package/src/html/node.ts +1486 -121
  622. package/src/html/paint.ts +4293 -169
  623. package/src/html/resources.ts +161 -50
  624. package/src/html/surfaces.ts +81 -0
  625. package/src/html/svg.ts +493 -0
  626. package/src/html/url.ts +86 -0
  627. package/src/index.ts +4 -0
  628. package/src/internal/collate.ts +12 -0
  629. package/src/{markdown → internal/markdown}/ast.ts +35 -7
  630. package/src/{markdown → internal/markdown}/parse.ts +288 -35
  631. package/src/internal/markdown/stringify.ts +772 -0
  632. package/src/internal/prewarm.ts +45 -0
  633. package/src/internal/scroll.ts +5 -3
  634. package/src/internal/sdf.ts +227 -0
  635. package/src/internal/splice.ts +25 -0
  636. package/src/internal/window.ts +36 -5
  637. package/src/maps/anchors.ts +913 -0
  638. package/src/maps/controller.ts +1084 -0
  639. package/src/maps/gl/buckets.ts +461 -0
  640. package/src/maps/gl/build-worker.ts +66 -0
  641. package/src/maps/gl/color.ts +62 -0
  642. package/src/maps/gl/cover.ts +205 -0
  643. package/src/maps/gl/index.ts +23 -0
  644. package/src/maps/gl/markers.ts +83 -0
  645. package/src/maps/gl/overlays.ts +379 -0
  646. package/src/maps/gl/pane.ts +42 -0
  647. package/src/maps/gl/placement.ts +968 -0
  648. package/src/maps/gl/renderer.ts +1660 -0
  649. package/src/maps/gl/shaders.ts +489 -0
  650. package/src/maps/gl/store.ts +615 -0
  651. package/src/maps/gl/text.ts +868 -0
  652. package/src/maps/gl/view.ts +1489 -0
  653. package/src/maps/icons.ts +183 -0
  654. package/src/maps/index.ts +274 -81
  655. package/src/maps/labels.ts +457 -144
  656. package/src/maps/node.ts +832 -665
  657. package/src/maps/overlay.ts +148 -43
  658. package/src/maps/paint.ts +3 -0
  659. package/src/maps/proj.ts +118 -0
  660. package/src/maps/renderer.ts +155 -0
  661. package/src/maps/sources.ts +43 -6
  662. package/src/maps/style.ts +32 -0
  663. package/src/maps/styles.ts +215 -4
  664. package/src/maps/theme.ts +51 -0
  665. package/src/maps/tiles.ts +253 -62
  666. package/src/maps/types.ts +213 -21
  667. package/src/markdown/expressions.ts +5 -1
  668. package/src/markdown/index.ts +163 -78
  669. package/src/markdown/spans.ts +6 -1
  670. package/src/media-player/index.ts +18 -4
  671. package/src/qml/containers.tsx +6 -1
  672. package/src/qml/interaction.tsx +42 -5
  673. package/src/qml/layouts.tsx +21 -6
  674. package/src/qml/qtquick.tsx +9 -2
  675. package/src/qml/react.tsx +7 -5
  676. package/src/reorder/clock.ts +27 -0
  677. package/src/reorder/index.ts +100 -27
  678. package/src/rich-text-editor/clipboard.ts +439 -0
  679. package/src/rich-text-editor/collab.ts +91 -0
  680. package/src/rich-text-editor/commands.ts +448 -0
  681. package/src/rich-text-editor/dom-globals.d.ts +23 -0
  682. package/src/rich-text-editor/drag.ts +211 -0
  683. package/src/rich-text-editor/html.ts +619 -0
  684. package/src/rich-text-editor/index.ts +1364 -0
  685. package/src/rich-text-editor/inline.ts +345 -0
  686. package/src/rich-text-editor/keymap.ts +510 -0
  687. package/src/rich-text-editor/keys.ts +228 -0
  688. package/src/rich-text-editor/look.ts +427 -0
  689. package/src/rich-text-editor/markdown.ts +653 -0
  690. package/src/rich-text-editor/marks.ts +101 -0
  691. package/src/rich-text-editor/nodes.ts +497 -0
  692. package/src/rich-text-editor/render.ts +837 -0
  693. package/src/rich-text-editor/schema.ts +431 -0
  694. package/src/rich-text-editor/store.ts +39 -0
  695. package/src/rich-text-editor/suggest.ts +597 -0
  696. package/src/rich-text-editor/tables.ts +272 -0
  697. package/src/rich-text-editor/toolbar.ts +724 -0
  698. package/src/rich-text-editor/view.ts +2287 -0
  699. package/src/rich-text-editor/virtual.ts +372 -0
  700. package/src/richtext/node.ts +294 -44
  701. package/src/richtext/runs.ts +23 -12
  702. package/src/table/index.ts +29 -0
  703. package/src/table/rows.ts +18 -8
  704. package/src/terminal/backends.ts +4 -1
  705. package/src/terminal/index.ts +47 -15
  706. package/src/terminal/vt/pty.ts +16 -2
  707. package/src/terminal-output/index.ts +6 -1
  708. package/src/three/canvas.ts +102 -8
  709. package/src/three/events.ts +49 -9
  710. package/src/tree/index.ts +19 -0
  711. package/dist/markdown/ast.d.ts.map +0 -1
  712. package/dist/markdown/ast.js +0 -17
  713. package/dist/markdown/ast.js.map +0 -1
  714. package/dist/markdown/parse.d.ts.map +0 -1
  715. package/dist/markdown/parse.js.map +0 -1
  716. package/dist/markdown/tags.d.ts.map +0 -1
  717. package/dist/markdown/tags.js.map +0 -1
  718. /package/dist/{markdown → internal/markdown}/parse.d.ts +0 -0
  719. /package/dist/{markdown → internal/markdown}/tags.d.ts +0 -0
  720. /package/dist/{markdown → internal/markdown}/tags.js +0 -0
  721. /package/src/{markdown → internal/markdown}/tags.ts +0 -0
@@ -14,11 +14,12 @@
14
14
  // an app imports the component that needs it, so `sideEffects: false` stays
15
15
  // honest. Do not move it into `../index.ts` (AGENTS.md, "Tree-shaking is a
16
16
  // constraint").
17
- import React, { useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
18
- import { Renderer } from 'react-x11';
17
+ import React, { useEffect, useLayoutEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
18
+ import { Renderer, useApp, useScale, useSupports, useTheme } from 'react-x11';
19
19
  import { registerElement, registeredElements } from 'react-x11/host';
20
20
  import { createStyles, flattenStyle } from 'react-x11/style';
21
- import { applyEdgeChanges, applyNodeChanges } from './model.js';
21
+ import { applyEdgeChanges, applyNodeChanges, resolvePalette } from './model.js';
22
+ import { CULL_MARGIN } from './scene.js';
22
23
  import { ELEMENT, FlowGraphNode, SELF_DAMAGED_PROPS } from './node.js';
23
24
  if (!registeredElements().includes(ELEMENT)) {
24
25
  registerElement(ELEMENT, {
@@ -49,6 +50,19 @@ const styles = createStyles({
49
50
  pane: { flexGrow: 1, overflow: 'hidden' },
50
51
  clip: { overflow: 'hidden' },
51
52
  fill: { flexGrow: 1 },
53
+ // Over the pane, holding the bodies' layer and clipping it to the pane:
54
+ // a 2D pan carries the layer's pixels in its blit, and what the layer can
55
+ // paint outside the pane — in the border round it — would be repainted
56
+ // on every step (`_blitPan` in ./node.ts).
57
+ bodiesClip: {
58
+ position: 'absolute',
59
+ left: 0,
60
+ top: 0,
61
+ right: 0,
62
+ bottom: 0,
63
+ overflow: 'hidden',
64
+ pointerEvents: 'box-none',
65
+ },
52
66
  });
53
67
  /**
54
68
  * Commit a state update before returning, whatever lane the surrounding
@@ -71,6 +85,132 @@ const flushSync = typeof Renderer
71
85
  .flushSyncFromReconciler === 'function'
72
86
  ? (fn) => void Renderer.flushSyncFromReconciler(fn)
73
87
  : (fn) => fn();
88
+ let glModule = null;
89
+ let glLoading = null;
90
+ /** Load the GL renderer, once per process however many panes ask. A failed
91
+ * load is forgotten, so the next pane to ask tries again. */
92
+ function loadGl() {
93
+ glLoading ??= import('./gl/index.js').then((module) => (glModule = module), (error) => {
94
+ glLoading = null;
95
+ throw error;
96
+ });
97
+ return glLoading;
98
+ }
99
+ /** How far a card's handles and grips ink outside its box — the canvas
100
+ * its card is painted on in the bodies' layer reaches that far round it. */
101
+ const CARD_INK = CULL_MARGIN;
102
+ /** The grid the bodies' layer grows to, in logical pixels. Every card is
103
+ * placed relative to the layer's corner, so a corner that followed the
104
+ * cards exactly moved — and moved every card with it — whenever the one
105
+ * being dragged was the outermost; grown to this grid it moves only when
106
+ * a card crosses a line of it. */
107
+ const EXTENT_STEP = 256;
108
+ /** A number per object, for a card's cache key: a style or a handle list
109
+ * that changed is a new object, and its card is painted again. */
110
+ const serials = new WeakMap();
111
+ let serial = 0;
112
+ function serialOf(node) {
113
+ let n = serials.get(node);
114
+ if (n === undefined)
115
+ serials.set(node, (n = ++serial));
116
+ return n;
117
+ }
118
+ /**
119
+ * What of a node its card draws, for the card's cache key: the label, the
120
+ * description, the style and the handles. A body's own data — a queue
121
+ * length, a chart's points — is none of it: keyed on the node object, a
122
+ * live body that patched its data repainted its card on every patch, the
123
+ * title's text shaped and drawn again for nothing. A type that paints its
124
+ * own card may draw anything of the node, so it is keyed on the node whole.
125
+ */
126
+ function cardShows(node, type) {
127
+ if (type.paint)
128
+ return `n${serialOf(node)}`;
129
+ const data = node.data;
130
+ const style = node.style ? serialOf(node.style) : 0;
131
+ const handles = node.handles ? serialOf(node.handles) : 0;
132
+ return (`${style}:${handles}:${String(data?.label ?? '')}` +
133
+ `\u0000${String(data?.description ?? '')}`);
134
+ }
135
+ /** Roles a press means something to — the body keeps those presses. */
136
+ const INTERACTIVE_ROLES = new Set([
137
+ 'button',
138
+ 'checkbox',
139
+ 'radio',
140
+ 'switch',
141
+ 'slider',
142
+ 'spinbutton',
143
+ 'textbox',
144
+ 'searchbox',
145
+ 'combobox',
146
+ 'listbox',
147
+ 'option',
148
+ 'menuitem',
149
+ 'tab',
150
+ 'link',
151
+ 'scrollbar',
152
+ ]);
153
+ /**
154
+ * Whether a press on `n` is the body's own: a control, something that
155
+ * listens for the press, something whose cursor says it can be clicked or
156
+ * typed into, or something that scrolls. Everything else in a body — its
157
+ * padding, a label, a progress bar — is the card, and a press there is the
158
+ * card's: it selects and drags the node, as it would on a card with no body.
159
+ */
160
+ function interactive(n) {
161
+ const props = n.props ?? {};
162
+ if (typeof props.onMouseDown === 'function' ||
163
+ typeof props.onClick === 'function' ||
164
+ typeof props.onPress === 'function' ||
165
+ typeof props.onChange === 'function' ||
166
+ typeof props.onMouseUp === 'function') {
167
+ return true;
168
+ }
169
+ if (typeof props.role === 'string' && INTERACTIVE_ROLES.has(props.role)) {
170
+ return true;
171
+ }
172
+ if (typeof props.tabIndex === 'number' && props.tabIndex >= 0)
173
+ return true;
174
+ const cursor = n.style?.cursor;
175
+ if (cursor === 'pointer' || cursor === 'text')
176
+ return true;
177
+ if (n.kind === 'textinput' || n.kind === 'textarea')
178
+ return true;
179
+ return Boolean(n.canScroll?.(0, 1) || n.canScroll?.(1, 0));
180
+ }
181
+ /** The event as the pane reads it: its coordinates taken out of the unit of
182
+ * the body they landed in (`scale`, the zoom) and into the window's. */
183
+ function inPaneUnits(ev, sink) {
184
+ const ratio = (ev.target?.scale ?? 1) / (sink.scale || 1);
185
+ return Object.assign(Object.create(ev), {
186
+ x: ev.x * ratio,
187
+ y: ev.y * ratio,
188
+ });
189
+ }
190
+ /**
191
+ * The same node, as far as its body can tell: every field but `position`.
192
+ *
193
+ * Identity is not the test. A drag — and every commit of a controlled graph
194
+ * — hands the pane a *new* node object each step with only its position
195
+ * changed, so comparing identity called `render` on every step of every
196
+ * drag: 60 renders with unchanged `data` in a 60-step drag, counted by
197
+ * `examples/flow-stress.tsx`. Any other field that changes — `data`,
198
+ * `selected`, `style`, a size — still re-renders, as it must.
199
+ */
200
+ function sameButPosition(a, b) {
201
+ if (a === b)
202
+ return true;
203
+ const keys = Object.keys(a);
204
+ if (keys.length !== Object.keys(b).length)
205
+ return false;
206
+ for (const key of keys) {
207
+ if (key === 'position')
208
+ continue;
209
+ if (!Object.is(a[key], b[key]))
210
+ return false;
211
+ }
212
+ return true;
213
+ }
74
214
  /**
75
215
  * One mounted node body. Memoized so that a *move* re-renders nothing: a
76
216
  * drag or a pan changes only the overlay box's `left`/`top` — the body's
@@ -95,11 +235,94 @@ const FlowNodeBody = React.memo(function FlowNodeBody(props) {
95
235
  },
96
236
  });
97
237
  }, (a, b) => a.type === b.type &&
98
- a.node === b.node &&
238
+ sameButPosition(a.node, b.node) &&
99
239
  a.selected === b.selected &&
100
240
  a.zoom === b.zoom &&
101
241
  a.width === b.width &&
102
242
  a.height === b.height);
243
+ /**
244
+ * One mounted node: its card, painted by the pane's own 2D painter
245
+ * (`FlowGraphNode.paintCard`), and its body over it. A component of its own
246
+ * so that React can skip it: every prop is a value or a reference that
247
+ * holds while the card does, and a drag re-renders the card that moved.
248
+ */
249
+ const FlowBodyCard = React.memo(function FlowBodyCard(props) {
250
+ const { body, node, type } = props;
251
+ const { card } = body;
252
+ // The two boxes are two units. The outer one is the pane's: it is
253
+ // positioned and clipped in the same logical window pixels the pane
254
+ // painted the card in, so the body lands on the card exactly. The inner
255
+ // one is the body's, and `scale` is what makes the difference between
256
+ // them the zoom (react-x11#449, core 2.6): every length under it is
257
+ // multiplied by that factor, so a body sized in graph units comes out at
258
+ // the size the card is drawn at, with its text shaped at that size rather
259
+ // than stretched.
260
+ const width = body.width / body.zoom;
261
+ const height = body.height / body.zoom;
262
+ const bodyBox = React.createElement('box', {
263
+ key: 'body',
264
+ style: {
265
+ position: 'absolute',
266
+ left: body.x - card.x + CARD_INK,
267
+ top: body.y - card.y + CARD_INK,
268
+ width: body.width,
269
+ height: body.height,
270
+ // A body is free to overflow what it was given — a popup's
271
+ // fallback, a long line — and this is what stops it spilling over
272
+ // the graph.
273
+ overflow: 'hidden',
274
+ // Opaque, in the card's own fill: the card painted under it shows
275
+ // none of what a transparent body would let through.
276
+ backgroundColor: props.fill,
277
+ },
278
+ }, React.createElement('box', {
279
+ scale: body.zoom,
280
+ // Sized in the unit it establishes, which is what makes it fill the
281
+ // outer box at every zoom.
282
+ style: { width, height },
283
+ }, React.createElement(FlowNodeBody, {
284
+ type,
285
+ node,
286
+ selected: body.selected,
287
+ zoom: body.zoom,
288
+ // Graph units, like everything else the body sees.
289
+ x: body.x / body.zoom,
290
+ y: body.y / body.zoom,
291
+ width,
292
+ height,
293
+ })));
294
+ // The card, just under its body: the bodies share one layer over every
295
+ // card the graph draws, so without it a body covered the header, border
296
+ // and handles of any card over its own.
297
+ const cardCanvas = React.createElement('canvas', {
298
+ key: 'card',
299
+ style: {
300
+ position: 'absolute',
301
+ left: 0,
302
+ top: 0,
303
+ width: card.width + CARD_INK * 2,
304
+ height: card.height + CARD_INK * 2,
305
+ pointerEvents: 'none',
306
+ },
307
+ cacheKey: props.cacheKey,
308
+ onDraw: props.onDraw,
309
+ });
310
+ return React.createElement('box', {
311
+ style: {
312
+ position: 'absolute',
313
+ left: props.left + (props.offsetX ?? 0),
314
+ top: props.top + (props.offsetY ?? 0),
315
+ width: props.width,
316
+ height: props.height,
317
+ // the card's presses are the pane's; its body's are the body's
318
+ pointerEvents: 'box-none',
319
+ ...(props.hidden === undefined
320
+ ? null
321
+ : { display: props.hidden ? 'none' : 'flex' }),
322
+ },
323
+ ...props.handlers,
324
+ }, cardCanvas, bodyBox);
325
+ });
103
326
  /**
104
327
  * A directed graph.
105
328
  *
@@ -127,8 +350,11 @@ const FlowNodeBody = React.memo(function FlowNodeBody(props) {
127
350
  * uncontrolled form, where the pane owns the arrays.
128
351
  */
129
352
  export function Flow(props) {
130
- const { nodes, defaultNodes, edges, defaultEdges, onNodesChange, onEdgesChange, onSelectionChange, onWheel, style, ref, ...rest } = props;
353
+ const { nodes, defaultNodes, edges, defaultEdges, onNodesChange, onEdgesChange, onSelectionChange, onWheel, style, ref, renderer, onFrame, onError, ...rest } = props;
131
354
  const pane = useRef(null);
355
+ // whether the surface draws the graph, as of the last render — read by a
356
+ // layout effect declared before the surface is decided
357
+ const drawsGlRef = useRef(false);
132
358
  const [ownNodes, setOwnNodes] = useState(() => defaultNodes ?? []);
133
359
  const [ownEdges, setOwnEdges] = useState(() => defaultEdges ?? []);
134
360
  const controlledNodes = nodes !== undefined;
@@ -155,12 +381,14 @@ export function Flow(props) {
155
381
  // it: the ref attaches after the commit that created the node, and a
156
382
  // handle built once must still work for the whole mount.
157
383
  getViewport: () => pane.current?.getViewport() ?? { x: 0, y: 0, zoom: 1 },
158
- setViewport: (viewport) => pane.current?.setViewport(viewport),
159
- zoomIn: (step) => pane.current?.zoomIn(step),
160
- zoomOut: (step) => pane.current?.zoomOut(step),
161
- zoomTo: (zoom) => pane.current?.zoomTo(zoom),
162
- fitView: (options) => pane.current?.fitView(options),
163
- setCenter: (x, y, options) => pane.current?.setCenter(x, y, options),
384
+ // the ones that move the viewport, as calls through the handle
385
+ // (`FlowGraphNode.fromHandle`): their bodies commit with the pan
386
+ setViewport: (viewport) => pane.current?.fromHandle(() => pane.current?.setViewport(viewport)),
387
+ zoomIn: (step) => pane.current?.fromHandle(() => pane.current?.zoomIn(step)),
388
+ zoomOut: (step) => pane.current?.fromHandle(() => pane.current?.zoomOut(step)),
389
+ zoomTo: (zoom) => pane.current?.fromHandle(() => pane.current?.zoomTo(zoom)),
390
+ fitView: (options) => pane.current?.fromHandle(() => pane.current?.fitView(options)),
391
+ setCenter: (x, y, options) => pane.current?.fromHandle(() => pane.current?.setCenter(x, y, options)),
164
392
  screenToFlowPosition: (point) => pane.current?.screenToFlowPosition(point) ?? point,
165
393
  flowToScreenPosition: (point) => pane.current?.flowToScreenPosition(point) ?? point,
166
394
  getNodeBounds: (id) => pane.current?.getNodeBounds(id) ?? null,
@@ -197,21 +425,53 @@ export function Flow(props) {
197
425
  flat.flexBasis !== undefined;
198
426
  // --- mounted node bodies ------------------------------------------------
199
427
  //
200
- // Only the node types that asked for one cost anything: with no `render`
201
- // in the registry the pane is never given `onNodeBodies`, never computes a
202
- // rect, and this half of the component is one `useState` that stays empty.
428
+ // Only the nodes whose type asked for one cost anything: with none in the
429
+ // graph the pane is never given `onNodeBodies`, never computes a rect, and
430
+ // this half of the component is one `useState` that stays empty. Asked of
431
+ // the nodes and not of the registry, because the registry is an app's
432
+ // whole vocabulary: a type with a body that no node uses is not a body,
433
+ // and it cost a graph of plain cards the GL surface on XQuartz (below) —
434
+ // the stress example registers its widget types for every scene, and its
435
+ // lattices drew in 2D there, a node dragged at 20 fps where GL drags it
436
+ // at 75. A scan per render of the nodes, a few microseconds at 2,000.
203
437
  const { nodeTypes } = rest;
204
- const mounts = useMemo(() => nodeTypes
205
- ? Object.values(nodeTypes).some((type) => type?.render != null)
206
- : false, [nodeTypes]);
438
+ const bodyTypes = useMemo(() => {
439
+ if (!nodeTypes)
440
+ return null;
441
+ const names = Object.keys(nodeTypes).filter((name) => nodeTypes[name]?.render != null);
442
+ return names.length > 0 ? new Set(names) : null;
443
+ }, [nodeTypes]);
444
+ const mounts = useMemo(() => bodyTypes != null &&
445
+ currentNodes.some((node) => bodyTypes.has(node.type ?? 'default')), [bodyTypes, currentNodes]);
207
446
  const [bodies, setBodies] = useState([]);
208
- // Gesture-time emissions commit inline (see `flushSync` above); the rest —
209
- // a programmatic `fitView`, the first paint — take the ordinary path.
210
- const handleBodies = (next, sync) => {
447
+ // Where the graph's origin sits in the pane. The bodies are laid out in
448
+ // one box placed here, so a pan — which moves this and nothing else — is
449
+ // one style change rather than a render of every body.
450
+ const [origin, setOrigin] = useState({ x: 0, y: 0 });
451
+ // Hidden while a zoom moves, and nothing else about them touched — see
452
+ // `_holdBodies` in ./node.ts for what re-scaling them every step cost.
453
+ const [held, setHeld] = useState(false);
454
+ // Where the minimap and controls are, painted over the bodies when there
455
+ // are any to be over.
456
+ const [panels, setPanels] = useState([]);
457
+ const panelCanvases = useRef([]);
458
+ // Gesture-time emissions commit inline (see `flushSync` above), and so do a
459
+ // handle's — a programmatic pan (`FlowGraphNode.fromHandle`). One made
460
+ // while React is already committing, a pan from a layout effect, is not
461
+ // flushed there: the reconciler runs it at sync priority as the commit
462
+ // ends. The rest — the first paint, what the pane's own frames emit — take
463
+ // the ordinary path.
464
+ const handleBodies = (next, sync, at, hold) => {
465
+ const apply = () => {
466
+ // the same array on a pan: React bails out of this update
467
+ setBodies(next);
468
+ setOrigin((was) => (was.x === at.x && was.y === at.y ? was : at));
469
+ setHeld(hold);
470
+ };
211
471
  if (sync)
212
- flushSync(() => setBodies(next));
472
+ flushSync(apply);
213
473
  else
214
- setBodies(next);
474
+ apply();
215
475
  };
216
476
  const byId = useMemo(() => {
217
477
  const map = new Map();
@@ -220,51 +480,336 @@ export function Flow(props) {
220
480
  map.set(node.id, node);
221
481
  return map;
222
482
  }, [mounts, currentNodes]);
223
- const overlays = mounts
224
- ? bodies.map((body) => {
483
+ // Every box the bodies are laid out in sits on the device-pixel grid.
484
+ // Layout rounds a box's two edges to whole device pixels separately, so at
485
+ // a fractional scale (1.25, 1.5) a box that moved by a fraction of a
486
+ // device pixel also changed size by one — and core moves a `<glarea>`
487
+ // child's pixels on its pane only when it moved and nothing else
488
+ // (sidorares/react-x11#644): a pan over bodies repainted every one of
489
+ // them, every step. On the grid, a pan moves the layer by whole pixels
490
+ // and every card in it by exactly as many.
491
+ const rootScale = useScale();
492
+ // the pane's own, where it is mounted: a `scale` prop above it counts
493
+ const deviceScale = pane.current?.scale ?? rootScale;
494
+ const snap = (v) => Math.round(v * deviceScale) / deviceScale;
495
+ // The box the bodies are laid out in covers exactly them. It has to have a
496
+ // real size: core culls a child whose *own* box is off screen or outside
497
+ // a clipping ancestor before it looks at the child's subtree, and a 0×0
498
+ // box at the graph's origin is off screen whenever the graph has been
499
+ // panned past the pane's top-left — which took every body with it.
500
+ const extent = useMemo(() => {
501
+ if (bodies.length === 0)
502
+ return { x: 0, y: 0, width: 0, height: 0 };
503
+ let x0 = Infinity;
504
+ let y0 = Infinity;
505
+ let x1 = -Infinity;
506
+ let y1 = -Infinity;
507
+ for (const { card } of bodies) {
508
+ x0 = Math.min(x0, card.x - CARD_INK);
509
+ y0 = Math.min(y0, card.y - CARD_INK);
510
+ x1 = Math.max(x1, card.x + card.width + CARD_INK);
511
+ y1 = Math.max(y1, card.y + card.height + CARD_INK);
512
+ }
513
+ const out = (v, up) => snap((up ? Math.ceil : Math.floor)(v / EXTENT_STEP) * EXTENT_STEP);
514
+ x0 = out(x0, false);
515
+ y0 = out(y0, false);
516
+ x1 = out(x1, true);
517
+ y1 = out(y1, true);
518
+ return { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
519
+ }, [bodies, deviceScale]);
520
+ // The fill a card is drawn in, which its body's box takes too.
521
+ const theme = useTheme();
522
+ const nodeFill = resolvePalette(theme, rest.palette).nodeBackground;
523
+ // One `onDraw` per card for as long as what paints cards holds: core
524
+ // repaints a canvas whose `onDraw` is a new function (react-x11
525
+ // src/nodes/canvas.js), and a closure made per render made every step of
526
+ // a drag repaint every card on screen and every body over them — 36
527
+ // claims, past the frame's rect cap, one rect the size of the pane. What a
528
+ // card shows is in its `cacheKey`; the palette, the theme and the node
529
+ // types are what paint it, and a change to any of them starts over.
530
+ const cardPaint = useMemo(() => ({
531
+ drawers: new Map(),
532
+ }), [theme, rest.palette, nodeTypes]);
533
+ const drawCard = (id) => {
534
+ let draw = cardPaint.drawers.get(id);
535
+ if (!draw) {
536
+ draw = (ctx, info) => pane.current?.paintCard(id, ctx, info.node.abs);
537
+ cardPaint.drawers.set(id, draw);
538
+ }
539
+ return draw;
540
+ };
541
+ // One card per body, each a memoized component: a drag step moves one
542
+ // card and hands the others the same props they had — the same body
543
+ // object (`_emitBodies` reuses it), the same node object, the same
544
+ // `onDraw` — so React re-renders the card that moved and bails out of the
545
+ // rest. Built as one element list per render, which a pan does not
546
+ // trigger: the box they sit in moves, and nothing here is asked.
547
+ const cards = useMemo(() => {
548
+ if (!mounts)
549
+ return null;
550
+ const out = [];
551
+ for (const body of bodies) {
225
552
  const node = byId.get(body.id);
226
553
  const type = node && nodeTypes?.[node.type ?? 'default'];
227
554
  if (!node || !type?.render)
228
- return null;
229
- // The two boxes are two units. The outer one is the pane's: it is
230
- // positioned and clipped in the same logical window pixels the pane
231
- // painted the card in, so the body lands on the card exactly. The
232
- // inner one is the body's, and `scale` is what makes the difference
233
- // between them the zoom (react-x11#449, core 2.6): every length
234
- // under it is multiplied by that factor, so a body sized in graph
235
- // units comes out at the size the card is drawn at, with its text
236
- // shaped at that size rather than stretched.
237
- const width = body.width / body.zoom;
238
- const height = body.height / body.zoom;
239
- return React.createElement('box', {
240
- key: body.id,
241
- style: {
242
- position: 'absolute',
243
- left: body.x,
244
- top: body.y,
245
- width: body.width,
246
- height: body.height,
247
- // A body is free to overflow what it was given — a popup's
248
- // fallback, a long line — and this is what stops it spilling
249
- // over the graph.
250
- overflow: 'hidden',
251
- },
252
- }, React.createElement('box', {
253
- scale: body.zoom,
254
- // Sized in the unit it establishes, which is what makes it
255
- // fill the outer box at every zoom.
256
- style: { width, height },
257
- }, React.createElement(FlowNodeBody, {
258
- type: type,
555
+ continue;
556
+ const { card } = body;
557
+ // on the grid, like the layer (`snap` above)
558
+ const left = snap(card.x - CARD_INK);
559
+ const top = snap(card.y - CARD_INK);
560
+ out.push({
561
+ body,
259
562
  node: node,
260
- selected: body.selected,
261
- zoom: body.zoom,
262
- // Graph units, like everything else the body sees.
263
- x: body.x / body.zoom,
264
- y: body.y / body.zoom,
265
- width,
266
- height,
267
- })));
563
+ type: type,
564
+ left: left - extent.x,
565
+ top: top - extent.y,
566
+ // Sized from the card alone, not as the gap between two edges each
567
+ // put on the grid: at 1.25x a card dragged a fraction of a pixel
568
+ // grew or shrank by one as its edges rounded apart, and a box that
569
+ // changed size is no longer a box that only moved — every step of
570
+ // a drag measured the content floors and repainted the card where
571
+ // core would have moved it. The box draws nothing and takes no
572
+ // pointer; the canvas and the body inside it keep sizes of their
573
+ // own.
574
+ width: snap(card.width + CARD_INK * 2),
575
+ height: snap(card.height + CARD_INK * 2),
576
+ fill: node.style?.background ??
577
+ nodeFill,
578
+ // Cached until something it shows changes (`cardShows`): a new
579
+ // label or style repaints it, a body's own data does not.
580
+ cacheKey: `${body.id}:${cardShows(node, type)}:` +
581
+ `${card.width}x${card.height}:` +
582
+ `${body.zoom}:${body.selected}:${body.hovered}:` +
583
+ `${serialOf(cardPaint)}`,
584
+ onDraw: drawCard(body.id),
585
+ });
586
+ }
587
+ return out;
588
+ }, [
589
+ mounts,
590
+ bodies,
591
+ extent,
592
+ byId,
593
+ nodeTypes,
594
+ nodeFill,
595
+ deviceScale,
596
+ cardPaint,
597
+ ]);
598
+ const overlays = cards?.map((props) => React.createElement(FlowBodyCard, { key: props.body.id, ...props }));
599
+ // A wheel over a body is a wheel over the graph. Core runs the wheel's
600
+ // default action on the node under the pointer and scrolls up from there,
601
+ // and the bodies are the pane's siblings, not its children — so over a
602
+ // card's body the pane never heard it, and zooming a graph whose cards
603
+ // are mostly bodies stalled wherever the pointer rested. Forwarded unless
604
+ // something between the pointer and the pane can scroll that way itself:
605
+ // a list inside a card keeps its wheel.
606
+ const forwardWheel = useMemo(() => (ev) => {
607
+ const node = pane.current;
608
+ const wheel = ev;
609
+ if (!node || wheel.defaultPrevented)
610
+ return;
611
+ const stop = node.parent;
612
+ for (let n = wheel.target; n && n !== stop; n = n.parent) {
613
+ if (n.canScroll?.(wheel.deltaX, wheel.deltaY))
614
+ return;
615
+ }
616
+ node.defaultWheel(inPaneUnits(wheel, node));
617
+ wheel.preventDefault();
618
+ }, []);
619
+ // A press on a body's card-like part is a press on the card. Core runs a
620
+ // press's default actions — select, drag, and the drag's steps and
621
+ // release — on the node that took it, so a body took them all: the cards
622
+ // of a graph whose nodes are mostly body could not be selected or dragged
623
+ // by most of their area. A press that bubbles up here from something that
624
+ // is not a control is the pane's instead: its default is vetoed on the
625
+ // body, the pointer captured so the drag and the release come back here
626
+ // wherever they wander, and each step handed to the pane.
627
+ const pressing = useRef(false);
628
+ const forwardPress = useMemo(() => {
629
+ // From the pressed node up to the bodies' box — which listens for the
630
+ // press itself, and is where the walk stops.
631
+ const within = (ev, sink) => {
632
+ for (let n = ev.target; n && n !== sink.parent; n = n.parent) {
633
+ if (n.props?.onMouseDown === handlers.onMouseDown)
634
+ return true;
635
+ if (interactive(n))
636
+ return false;
637
+ }
638
+ return true;
639
+ };
640
+ const handlers = {
641
+ onMouseDown: (ev) => {
642
+ const press = ev;
643
+ const sink = pane.current;
644
+ if (!sink || press.defaultPrevented || (press.button ?? 1) !== 1)
645
+ return;
646
+ if (!within(press, sink))
647
+ return;
648
+ pressing.current = true;
649
+ press.preventDefault();
650
+ press.capturePointer?.();
651
+ sink.defaultMouseDown?.(inPaneUnits(press, sink));
652
+ },
653
+ onMouseMove: (ev) => {
654
+ if (!pressing.current)
655
+ return;
656
+ const sink = pane.current;
657
+ sink?.defaultMouseDrag?.(inPaneUnits(ev, sink));
658
+ },
659
+ onMouseUp: (ev) => {
660
+ if (!pressing.current)
661
+ return;
662
+ pressing.current = false;
663
+ const sink = pane.current;
664
+ sink?.defaultMouseUp?.(inPaneUnits(ev, sink));
665
+ },
666
+ };
667
+ return handlers;
668
+ }, []);
669
+ // what each card forwards on its own where it is the surface's child
670
+ const directHandlers = useMemo(() => ({ onWheel: forwardWheel, ...forwardPress }), [forwardWheel, forwardPress]);
671
+ const bodiesLayer = useRef(null);
672
+ const layer = overlays && overlays.length > 0
673
+ ? React.createElement('box', {
674
+ key: 'bodies',
675
+ ref: bodiesLayer,
676
+ style: {
677
+ position: 'absolute',
678
+ left: snap(origin.x) + extent.x,
679
+ top: snap(origin.y) + extent.y,
680
+ width: extent.width,
681
+ height: extent.height,
682
+ // The box spans every body, the gaps between them and the
683
+ // cards' headers with them — taking the pointer itself, it ate
684
+ // every press in that span: no pan, no pane click, no selecting
685
+ // a node by its header. Its bodies take the pointer; it does not.
686
+ pointerEvents: 'box-none',
687
+ // held through a zoom gesture: see `_holdBodies` in ./node.ts
688
+ display: held ? 'none' : 'flex',
689
+ },
690
+ onWheel: forwardWheel,
691
+ ...forwardPress,
692
+ }, overlays)
693
+ : null;
694
+ // The box a 2D pan carries along with the pane's pixels (`_blitPan`).
695
+ useLayoutEffect(() => {
696
+ pane.current?.setBodiesLayer(drawsGlRef.current ? null : bodiesLayer.current);
697
+ });
698
+ // The cards whose canvases are on screen, told to the pane once they are,
699
+ // so the 2D pane stops drawing them itself — and the empty set while
700
+ // bodies are held out of a zoom, when their cards are the pane's again.
701
+ // The GL world draws every card whatever this says (`_cardInLayer`).
702
+ useLayoutEffect(() => {
703
+ const shown = new Set();
704
+ if (mounts && !held)
705
+ for (const body of bodies)
706
+ shown.add(body.id);
707
+ pane.current?.setShownBodies(shown);
708
+ }, [mounts, held, bodies]);
709
+ // The minimap and the controls over the bodies: the bodies' layer is over
710
+ // the graph, so panels the graph drew went under any card that reached
711
+ // them. Painted by the pane (`paintPanels`) on canvases after the layer,
712
+ // which take no pointer — a press on a button is the pane's, as before.
713
+ const panelLayer = mounts && panels.length > 0
714
+ ? panels.map((rect, i) => React.createElement('canvas', {
715
+ key: `panel-${i}`,
716
+ ref: (node) => {
717
+ panelCanvases.current[i] = node;
718
+ },
719
+ style: {
720
+ position: 'absolute',
721
+ left: rect.x,
722
+ top: rect.y,
723
+ width: rect.width,
724
+ height: rect.height,
725
+ pointerEvents: 'none',
726
+ },
727
+ onDraw: (ctx, info) => pane.current?.paintPanels(ctx, info.node.abs),
728
+ }))
729
+ : null;
730
+ useLayoutEffect(() => {
731
+ const live = panelCanvases.current
732
+ .slice(0, panelLayer?.length ?? 0)
733
+ .filter((c) => c != null);
734
+ pane.current?.setPanelCanvases(live);
735
+ }, [panelLayer?.length, panels]);
736
+ // On X11 a <glarea>'s children are not composited over its frame: each
737
+ // child gets an opaque child window, as big as the region it reaches,
738
+ // filled with the surface's clear colour (react-x11's src/gloverlay.js).
739
+ // The bodies' one box reaches every card and the gaps between them, so it
740
+ // became one window over the whole view: cards and bodies, and not one
741
+ // edge. There each card is the surface's child in its own right, placed
742
+ // at the origin itself, and a pane covers a card and nothing more. Where
743
+ // panes composite (Cocoa) the one box stays — a pan moves it alone.
744
+ const app = useApp();
745
+ const composited = typeof app?.createOverlayPane === 'function';
746
+ // …and on XQuartz not shown at all: the macOS window server composites
747
+ // every GL surface there above everything the X server draws, panes
748
+ // included. Core says so (`useSupports('glOverlay')` false, from the first
749
+ // render — sidorares/react-x11#653), and there a graph with nodes whose
750
+ // types mount bodies draws with the 2D renderer: for as long as it has
751
+ // one, not per zoom, so the surface does not come and go as bodies mount.
752
+ const overlaySupported = useSupports('glOverlay');
753
+ const cardsDirect = [];
754
+ if (cards && !composited) {
755
+ const offsetX = snap(origin.x) + extent.x;
756
+ const offsetY = snap(origin.y) + extent.y;
757
+ for (const props of cards) {
758
+ cardsDirect.push(React.createElement(FlowBodyCard, {
759
+ key: props.body.id,
760
+ ...props,
761
+ offsetX,
762
+ offsetY,
763
+ hidden: held,
764
+ handlers: directHandlers,
765
+ }));
766
+ }
767
+ }
768
+ // --- the GL surface -----------------------------------------------------
769
+ //
770
+ // Loaded when it is asked for and not before — see `./gl/index.ts` for why
771
+ // the import is dynamic. Until it arrives, and for good once it has failed,
772
+ // the pane draws itself: `renderer` reaches the element only while a
773
+ // surface is there to draw, so there is never a frame with neither.
774
+ const wantGl = renderer === 'gl';
775
+ const [gl, setGl] = useState(glModule);
776
+ const [glFailed, setGlFailed] = useState(false);
777
+ const latestError = useRef(onError);
778
+ latestError.current = onError;
779
+ const failGl = useMemo(() => (error) => {
780
+ setGlFailed(true);
781
+ latestError.current?.(error);
782
+ }, []);
783
+ useEffect(() => {
784
+ if (!wantGl || gl || glFailed)
785
+ return;
786
+ let live = true;
787
+ loadGl().then((module) => {
788
+ if (live)
789
+ setGl(module);
790
+ }, (error) => {
791
+ if (live)
792
+ failGl(error instanceof Error ? error : new Error(String(error)));
793
+ });
794
+ return () => {
795
+ live = false;
796
+ };
797
+ }, [wantGl, gl, glFailed]);
798
+ const drawsGl = wantGl && gl != null && !glFailed && !(mounts && !overlaySupported);
799
+ drawsGlRef.current = drawsGl;
800
+ const surface = drawsGl
801
+ ? React.createElement(gl.FlowGlSurface, {
802
+ key: 'gl',
803
+ pane,
804
+ clearColor: resolvePalette(theme, rest.palette).background,
805
+ onFrame: onFrame,
806
+ onError: failGl,
807
+ // A `<glarea>`'s children are drawn over its surface, so that is
808
+ // where the bodies go under GL — beside the pane, they would be
809
+ // under it.
810
+ children: composited
811
+ ? [layer, panelLayer]
812
+ : [cardsDirect.length > 0 ? cardsDirect : null, panelLayer],
268
813
  })
269
814
  : null;
270
815
  // The pane and the bodies are siblings rather than parent and children:
@@ -285,10 +830,20 @@ export function Flow(props) {
285
830
  // `<flowgraph>` element zooms and hovers on its own.
286
831
  onWheel,
287
832
  onNodeBodies: mounts ? handleBodies : undefined,
833
+ onPanels: mounts ? setPanels : undefined,
834
+ renderer: drawsGl ? 'gl' : undefined,
835
+ // the element reports the 2D renderer's frames, the surface the GL
836
+ // one's — one callback either way
837
+ onFrame,
288
838
  style: styles.fill,
289
839
  role: 'group',
290
840
  'aria-label': rest['aria-label'] ?? 'Flow graph',
291
- }), overlays);
841
+ }),
842
+ // After the pane, so the surface covers exactly its box — and with the
843
+ // bodies inside it under GL, or beside the pane without.
844
+ surface, drawsGl || !layer
845
+ ? null
846
+ : React.createElement('box', { key: 'bodies-clip', style: styles.bodiesClip }, layer), drawsGl ? null : panelLayer);
292
847
  }
293
848
  /**
294
849
  * `useState` for nodes, with the change handler `<Flow>` wants already