@react-x11/components 0.9.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 (550) hide show
  1. package/README.md +10 -4
  2. package/dist/charts/node.d.ts +11 -1
  3. package/dist/charts/node.d.ts.map +1 -1
  4. package/dist/charts/node.js +44 -14
  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/flow/draw.d.ts +50 -0
  49. package/dist/flow/draw.d.ts.map +1 -1
  50. package/dist/flow/draw.js +132 -33
  51. package/dist/flow/draw.js.map +1 -1
  52. package/dist/flow/gl/color.d.ts +13 -0
  53. package/dist/flow/gl/color.d.ts.map +1 -0
  54. package/dist/flow/gl/color.js +82 -0
  55. package/dist/flow/gl/color.js.map +1 -0
  56. package/dist/flow/gl/index.d.ts +60 -0
  57. package/dist/flow/gl/index.d.ts.map +1 -0
  58. package/dist/flow/gl/index.js +283 -0
  59. package/dist/flow/gl/index.js.map +1 -0
  60. package/dist/flow/gl/pack.d.ts +133 -0
  61. package/dist/flow/gl/pack.d.ts.map +1 -0
  62. package/dist/flow/gl/pack.js +408 -0
  63. package/dist/flow/gl/pack.js.map +1 -0
  64. package/dist/flow/gl/renderer.d.ts +95 -0
  65. package/dist/flow/gl/renderer.d.ts.map +1 -0
  66. package/dist/flow/gl/renderer.js +459 -0
  67. package/dist/flow/gl/renderer.js.map +1 -0
  68. package/dist/flow/gl/shaders.d.ts +79 -0
  69. package/dist/flow/gl/shaders.d.ts.map +1 -0
  70. package/dist/flow/gl/shaders.js +346 -0
  71. package/dist/flow/gl/shaders.js.map +1 -0
  72. package/dist/flow/gl/text.d.ts +318 -0
  73. package/dist/flow/gl/text.d.ts.map +1 -0
  74. package/dist/flow/gl/text.js +1103 -0
  75. package/dist/flow/gl/text.js.map +1 -0
  76. package/dist/flow/index.d.ts +1 -1
  77. package/dist/flow/index.d.ts.map +1 -1
  78. package/dist/flow/index.js +619 -64
  79. package/dist/flow/index.js.map +1 -1
  80. package/dist/flow/node.d.ts +621 -72
  81. package/dist/flow/node.d.ts.map +1 -1
  82. package/dist/flow/node.js +2253 -1018
  83. package/dist/flow/node.js.map +1 -1
  84. package/dist/flow/paint.d.ts +35 -0
  85. package/dist/flow/paint.d.ts.map +1 -0
  86. package/dist/flow/paint.js +393 -0
  87. package/dist/flow/paint.js.map +1 -0
  88. package/dist/flow/paths.d.ts +14 -0
  89. package/dist/flow/paths.d.ts.map +1 -1
  90. package/dist/flow/paths.js +45 -19
  91. package/dist/flow/paths.js.map +1 -1
  92. package/dist/flow/scene.d.ts +584 -0
  93. package/dist/flow/scene.d.ts.map +1 -0
  94. package/dist/flow/scene.js +1453 -0
  95. package/dist/flow/scene.js.map +1 -0
  96. package/dist/flow/types.d.ts +111 -1
  97. package/dist/flow/types.d.ts.map +1 -1
  98. package/dist/html/controls.d.ts +28 -0
  99. package/dist/html/controls.d.ts.map +1 -1
  100. package/dist/html/controls.js +52 -2
  101. package/dist/html/controls.js.map +1 -1
  102. package/dist/html/css/calc.d.ts +14 -0
  103. package/dist/html/css/calc.d.ts.map +1 -0
  104. package/dist/html/css/calc.js +344 -0
  105. package/dist/html/css/calc.js.map +1 -0
  106. package/dist/html/css/cascade.d.ts +240 -6
  107. package/dist/html/css/cascade.d.ts.map +1 -1
  108. package/dist/html/css/cascade.js +1327 -66
  109. package/dist/html/css/cascade.js.map +1 -1
  110. package/dist/html/css/color.d.ts +23 -0
  111. package/dist/html/css/color.d.ts.map +1 -0
  112. package/dist/html/css/color.js +740 -0
  113. package/dist/html/css/color.js.map +1 -0
  114. package/dist/html/css/content.d.ts +92 -0
  115. package/dist/html/css/content.d.ts.map +1 -0
  116. package/dist/html/css/content.js +388 -0
  117. package/dist/html/css/content.js.map +1 -0
  118. package/dist/html/css/counter-styles.d.ts +76 -0
  119. package/dist/html/css/counter-styles.d.ts.map +1 -0
  120. package/dist/html/css/counter-styles.js +893 -0
  121. package/dist/html/css/counter-styles.js.map +1 -0
  122. package/dist/html/css/decode.d.ts +12 -0
  123. package/dist/html/css/decode.d.ts.map +1 -0
  124. package/dist/html/css/decode.js +116 -0
  125. package/dist/html/css/decode.js.map +1 -0
  126. package/dist/html/css/parse.d.ts +110 -10
  127. package/dist/html/css/parse.d.ts.map +1 -1
  128. package/dist/html/css/parse.js +1473 -180
  129. package/dist/html/css/parse.js.map +1 -1
  130. package/dist/html/css/style.d.ts +498 -15
  131. package/dist/html/css/style.d.ts.map +1 -1
  132. package/dist/html/css/style.js +3698 -206
  133. package/dist/html/css/style.js.map +1 -1
  134. package/dist/html/css/ua.d.ts.map +1 -1
  135. package/dist/html/css/ua.js +57 -11
  136. package/dist/html/css/ua.js.map +1 -1
  137. package/dist/html/css/values.d.ts +37 -3
  138. package/dist/html/css/values.d.ts.map +1 -1
  139. package/dist/html/css/values.js +122 -48
  140. package/dist/html/css/values.js.map +1 -1
  141. package/dist/html/css/vars.d.ts +52 -0
  142. package/dist/html/css/vars.d.ts.map +1 -0
  143. package/dist/html/css/vars.js +358 -0
  144. package/dist/html/css/vars.js.map +1 -0
  145. package/dist/html/dom.d.ts +30 -4
  146. package/dist/html/dom.d.ts.map +1 -1
  147. package/dist/html/dom.js +278 -17
  148. package/dist/html/dom.js.map +1 -1
  149. package/dist/html/fonts.d.ts +106 -0
  150. package/dist/html/fonts.d.ts.map +1 -0
  151. package/dist/html/fonts.js +565 -0
  152. package/dist/html/fonts.js.map +1 -0
  153. package/dist/html/gif.d.ts +15 -0
  154. package/dist/html/gif.d.ts.map +1 -0
  155. package/dist/html/gif.js +229 -0
  156. package/dist/html/gif.js.map +1 -0
  157. package/dist/html/index.d.ts +50 -11
  158. package/dist/html/index.d.ts.map +1 -1
  159. package/dist/html/index.js +115 -9
  160. package/dist/html/index.js.map +1 -1
  161. package/dist/html/layout/block.d.ts +226 -3
  162. package/dist/html/layout/block.d.ts.map +1 -1
  163. package/dist/html/layout/block.js +2937 -197
  164. package/dist/html/layout/block.js.map +1 -1
  165. package/dist/html/layout/boxes.d.ts +340 -17
  166. package/dist/html/layout/boxes.d.ts.map +1 -1
  167. package/dist/html/layout/boxes.js +1714 -182
  168. package/dist/html/layout/boxes.js.map +1 -1
  169. package/dist/html/layout/cache.d.ts +58 -0
  170. package/dist/html/layout/cache.d.ts.map +1 -0
  171. package/dist/html/layout/cache.js +224 -0
  172. package/dist/html/layout/cache.js.map +1 -0
  173. package/dist/html/layout/collapse.d.ts +45 -0
  174. package/dist/html/layout/collapse.d.ts.map +1 -0
  175. package/dist/html/layout/collapse.js +246 -0
  176. package/dist/html/layout/collapse.js.map +1 -0
  177. package/dist/html/layout/css-grid.d.ts +7 -0
  178. package/dist/html/layout/css-grid.d.ts.map +1 -0
  179. package/dist/html/layout/css-grid.js +900 -0
  180. package/dist/html/layout/css-grid.js.map +1 -0
  181. package/dist/html/layout/flex.d.ts.map +1 -1
  182. package/dist/html/layout/flex.js +1025 -89
  183. package/dist/html/layout/flex.js.map +1 -1
  184. package/dist/html/layout/floats.d.ts +45 -6
  185. package/dist/html/layout/floats.d.ts.map +1 -1
  186. package/dist/html/layout/floats.js +113 -14
  187. package/dist/html/layout/floats.js.map +1 -1
  188. package/dist/html/layout/grid-lines.d.ts +39 -0
  189. package/dist/html/layout/grid-lines.d.ts.map +1 -0
  190. package/dist/html/layout/grid-lines.js +119 -0
  191. package/dist/html/layout/grid-lines.js.map +1 -0
  192. package/dist/html/layout/grid.d.ts +53 -0
  193. package/dist/html/layout/grid.d.ts.map +1 -0
  194. package/dist/html/layout/grid.js +153 -0
  195. package/dist/html/layout/grid.js.map +1 -0
  196. package/dist/html/layout/inline.d.ts +151 -1
  197. package/dist/html/layout/inline.d.ts.map +1 -1
  198. package/dist/html/layout/inline.js +3375 -174
  199. package/dist/html/layout/inline.js.map +1 -1
  200. package/dist/html/layout/shaping.d.ts +6 -0
  201. package/dist/html/layout/shaping.d.ts.map +1 -0
  202. package/dist/html/layout/shaping.js +100 -0
  203. package/dist/html/layout/shaping.js.map +1 -0
  204. package/dist/html/layout/table.d.ts +3 -0
  205. package/dist/html/layout/table.d.ts.map +1 -1
  206. package/dist/html/layout/table.js +681 -175
  207. package/dist/html/layout/table.js.map +1 -1
  208. package/dist/html/layout/tracks.d.ts +44 -0
  209. package/dist/html/layout/tracks.d.ts.map +1 -0
  210. package/dist/html/layout/tracks.js +349 -0
  211. package/dist/html/layout/tracks.js.map +1 -0
  212. package/dist/html/node.d.ts +169 -4
  213. package/dist/html/node.d.ts.map +1 -1
  214. package/dist/html/node.js +1331 -100
  215. package/dist/html/node.js.map +1 -1
  216. package/dist/html/paint.d.ts +92 -3
  217. package/dist/html/paint.d.ts.map +1 -1
  218. package/dist/html/paint.js +3503 -141
  219. package/dist/html/paint.js.map +1 -1
  220. package/dist/html/resources.d.ts +60 -14
  221. package/dist/html/resources.d.ts.map +1 -1
  222. package/dist/html/resources.js +122 -36
  223. package/dist/html/resources.js.map +1 -1
  224. package/dist/html/surfaces.d.ts +23 -0
  225. package/dist/html/surfaces.d.ts.map +1 -0
  226. package/dist/html/surfaces.js +68 -0
  227. package/dist/html/surfaces.js.map +1 -0
  228. package/dist/html/svg.d.ts +80 -0
  229. package/dist/html/svg.d.ts.map +1 -0
  230. package/dist/html/svg.js +435 -0
  231. package/dist/html/svg.js.map +1 -0
  232. package/dist/html/url.d.ts +23 -0
  233. package/dist/html/url.d.ts.map +1 -0
  234. package/dist/html/url.js +80 -0
  235. package/dist/html/url.js.map +1 -0
  236. package/dist/index.d.ts +1 -1
  237. package/dist/index.d.ts.map +1 -1
  238. package/dist/index.js.map +1 -1
  239. package/dist/internal/collate.d.ts +3 -0
  240. package/dist/internal/collate.d.ts.map +1 -0
  241. package/dist/internal/collate.js +11 -0
  242. package/dist/internal/collate.js.map +1 -0
  243. package/dist/internal/markdown/ast.d.ts +11 -0
  244. package/dist/internal/markdown/ast.d.ts.map +1 -1
  245. package/dist/internal/markdown/parse.d.ts.map +1 -1
  246. package/dist/internal/markdown/parse.js +109 -8
  247. package/dist/internal/markdown/parse.js.map +1 -1
  248. package/dist/internal/prewarm.d.ts +18 -0
  249. package/dist/internal/prewarm.d.ts.map +1 -0
  250. package/dist/internal/prewarm.js +42 -0
  251. package/dist/internal/prewarm.js.map +1 -0
  252. package/dist/internal/sdf.d.ts +20 -0
  253. package/dist/internal/sdf.d.ts.map +1 -0
  254. package/dist/internal/sdf.js +216 -0
  255. package/dist/internal/sdf.js.map +1 -0
  256. package/dist/internal/splice.d.ts +12 -0
  257. package/dist/internal/splice.d.ts.map +1 -0
  258. package/dist/internal/splice.js +23 -0
  259. package/dist/internal/splice.js.map +1 -0
  260. package/dist/internal/window.d.ts +12 -0
  261. package/dist/internal/window.d.ts.map +1 -1
  262. package/dist/internal/window.js +23 -6
  263. package/dist/internal/window.js.map +1 -1
  264. package/dist/maps/anchors.d.ts +6 -1
  265. package/dist/maps/anchors.d.ts.map +1 -1
  266. package/dist/maps/anchors.js +260 -1
  267. package/dist/maps/anchors.js.map +1 -1
  268. package/dist/maps/controller.d.ts +57 -0
  269. package/dist/maps/controller.d.ts.map +1 -1
  270. package/dist/maps/controller.js +97 -18
  271. package/dist/maps/controller.js.map +1 -1
  272. package/dist/maps/gl/buckets.d.ts +5 -1
  273. package/dist/maps/gl/buckets.d.ts.map +1 -1
  274. package/dist/maps/gl/buckets.js +5 -2
  275. package/dist/maps/gl/buckets.js.map +1 -1
  276. package/dist/maps/gl/build-worker.d.ts +2 -0
  277. package/dist/maps/gl/build-worker.d.ts.map +1 -1
  278. package/dist/maps/gl/build-worker.js +1 -1
  279. package/dist/maps/gl/build-worker.js.map +1 -1
  280. package/dist/maps/gl/cover.d.ts +23 -4
  281. package/dist/maps/gl/cover.d.ts.map +1 -1
  282. package/dist/maps/gl/cover.js +61 -48
  283. package/dist/maps/gl/cover.js.map +1 -1
  284. package/dist/maps/gl/placement.d.ts +21 -8
  285. package/dist/maps/gl/placement.d.ts.map +1 -1
  286. package/dist/maps/gl/placement.js +133 -58
  287. package/dist/maps/gl/placement.js.map +1 -1
  288. package/dist/maps/gl/renderer.d.ts +36 -4
  289. package/dist/maps/gl/renderer.d.ts.map +1 -1
  290. package/dist/maps/gl/renderer.js +81 -24
  291. package/dist/maps/gl/renderer.js.map +1 -1
  292. package/dist/maps/gl/shaders.d.ts +18 -17
  293. package/dist/maps/gl/shaders.d.ts.map +1 -1
  294. package/dist/maps/gl/shaders.js +34 -32
  295. package/dist/maps/gl/shaders.js.map +1 -1
  296. package/dist/maps/gl/store.d.ts +10 -0
  297. package/dist/maps/gl/store.d.ts.map +1 -1
  298. package/dist/maps/gl/store.js +47 -4
  299. package/dist/maps/gl/store.js.map +1 -1
  300. package/dist/maps/gl/text.d.ts +153 -24
  301. package/dist/maps/gl/text.d.ts.map +1 -1
  302. package/dist/maps/gl/text.js +379 -63
  303. package/dist/maps/gl/text.js.map +1 -1
  304. package/dist/maps/gl/view.d.ts +293 -2
  305. package/dist/maps/gl/view.d.ts.map +1 -1
  306. package/dist/maps/gl/view.js +317 -82
  307. package/dist/maps/gl/view.js.map +1 -1
  308. package/dist/maps/icons.d.ts +32 -0
  309. package/dist/maps/icons.d.ts.map +1 -0
  310. package/dist/maps/icons.js +151 -0
  311. package/dist/maps/icons.js.map +1 -0
  312. package/dist/maps/index.d.ts +2 -0
  313. package/dist/maps/index.d.ts.map +1 -1
  314. package/dist/maps/index.js +2 -0
  315. package/dist/maps/index.js.map +1 -1
  316. package/dist/maps/labels.d.ts +56 -4
  317. package/dist/maps/labels.d.ts.map +1 -1
  318. package/dist/maps/labels.js +213 -46
  319. package/dist/maps/labels.js.map +1 -1
  320. package/dist/maps/node.d.ts +17 -0
  321. package/dist/maps/node.d.ts.map +1 -1
  322. package/dist/maps/node.js +64 -30
  323. package/dist/maps/node.js.map +1 -1
  324. package/dist/maps/proj.d.ts +48 -0
  325. package/dist/maps/proj.d.ts.map +1 -1
  326. package/dist/maps/proj.js +73 -0
  327. package/dist/maps/proj.js.map +1 -1
  328. package/dist/maps/sources.d.ts +5 -3
  329. package/dist/maps/sources.d.ts.map +1 -1
  330. package/dist/maps/sources.js +5 -3
  331. package/dist/maps/sources.js.map +1 -1
  332. package/dist/maps/style.d.ts +35 -0
  333. package/dist/maps/style.d.ts.map +1 -1
  334. package/dist/maps/style.js.map +1 -1
  335. package/dist/maps/styles.d.ts +12 -0
  336. package/dist/maps/styles.d.ts.map +1 -1
  337. package/dist/maps/styles.js +120 -6
  338. package/dist/maps/styles.js.map +1 -1
  339. package/dist/maps/tiles.d.ts +31 -11
  340. package/dist/maps/tiles.d.ts.map +1 -1
  341. package/dist/maps/tiles.js +61 -27
  342. package/dist/maps/tiles.js.map +1 -1
  343. package/dist/maps/types.d.ts +28 -4
  344. package/dist/maps/types.d.ts.map +1 -1
  345. package/dist/markdown/index.d.ts.map +1 -1
  346. package/dist/markdown/index.js +112 -43
  347. package/dist/markdown/index.js.map +1 -1
  348. package/dist/markdown/spans.d.ts.map +1 -1
  349. package/dist/markdown/spans.js +6 -0
  350. package/dist/markdown/spans.js.map +1 -1
  351. package/dist/qml/containers.d.ts.map +1 -1
  352. package/dist/qml/containers.js +6 -1
  353. package/dist/qml/containers.js.map +1 -1
  354. package/dist/qml/interaction.d.ts.map +1 -1
  355. package/dist/qml/interaction.js +38 -5
  356. package/dist/qml/interaction.js.map +1 -1
  357. package/dist/qml/layouts.d.ts.map +1 -1
  358. package/dist/qml/layouts.js +21 -6
  359. package/dist/qml/layouts.js.map +1 -1
  360. package/dist/qml/qtquick.d.ts.map +1 -1
  361. package/dist/qml/qtquick.js +9 -2
  362. package/dist/qml/qtquick.js.map +1 -1
  363. package/dist/qml/react.d.ts.map +1 -1
  364. package/dist/qml/react.js +9 -7
  365. package/dist/qml/react.js.map +1 -1
  366. package/dist/reorder/clock.d.ts +7 -0
  367. package/dist/reorder/clock.d.ts.map +1 -0
  368. package/dist/reorder/clock.js +26 -0
  369. package/dist/reorder/clock.js.map +1 -0
  370. package/dist/reorder/index.d.ts +25 -3
  371. package/dist/reorder/index.d.ts.map +1 -1
  372. package/dist/reorder/index.js +64 -19
  373. package/dist/reorder/index.js.map +1 -1
  374. package/dist/rich-text-editor/index.d.ts +0 -11
  375. package/dist/rich-text-editor/index.d.ts.map +1 -1
  376. package/dist/rich-text-editor/index.js +35 -1
  377. package/dist/rich-text-editor/index.js.map +1 -1
  378. package/dist/rich-text-editor/keymap.d.ts.map +1 -1
  379. package/dist/rich-text-editor/keymap.js +2 -1
  380. package/dist/rich-text-editor/keymap.js.map +1 -1
  381. package/dist/rich-text-editor/keys.d.ts +17 -6
  382. package/dist/rich-text-editor/keys.d.ts.map +1 -1
  383. package/dist/rich-text-editor/keys.js +135 -26
  384. package/dist/rich-text-editor/keys.js.map +1 -1
  385. package/dist/rich-text-editor/marks.d.ts +9 -0
  386. package/dist/rich-text-editor/marks.d.ts.map +1 -0
  387. package/dist/rich-text-editor/marks.js +83 -0
  388. package/dist/rich-text-editor/marks.js.map +1 -0
  389. package/dist/rich-text-editor/render.d.ts.map +1 -1
  390. package/dist/rich-text-editor/render.js +28 -10
  391. package/dist/rich-text-editor/render.js.map +1 -1
  392. package/dist/rich-text-editor/toolbar.d.ts.map +1 -1
  393. package/dist/rich-text-editor/toolbar.js +1 -1
  394. package/dist/rich-text-editor/toolbar.js.map +1 -1
  395. package/dist/rich-text-editor/virtual.d.ts.map +1 -1
  396. package/dist/rich-text-editor/virtual.js +17 -0
  397. package/dist/rich-text-editor/virtual.js.map +1 -1
  398. package/dist/richtext/node.d.ts +46 -2
  399. package/dist/richtext/node.d.ts.map +1 -1
  400. package/dist/richtext/node.js +187 -4
  401. package/dist/richtext/node.js.map +1 -1
  402. package/dist/richtext/runs.d.ts +13 -8
  403. package/dist/richtext/runs.d.ts.map +1 -1
  404. package/dist/richtext/runs.js +18 -8
  405. package/dist/richtext/runs.js.map +1 -1
  406. package/dist/table/index.d.ts.map +1 -1
  407. package/dist/table/index.js +23 -0
  408. package/dist/table/index.js.map +1 -1
  409. package/dist/table/rows.d.ts +3 -2
  410. package/dist/table/rows.d.ts.map +1 -1
  411. package/dist/table/rows.js +20 -6
  412. package/dist/table/rows.js.map +1 -1
  413. package/dist/terminal/index.d.ts.map +1 -1
  414. package/dist/terminal/index.js +4 -0
  415. package/dist/terminal/index.js.map +1 -1
  416. package/dist/terminal/vt/pty.d.ts +13 -2
  417. package/dist/terminal/vt/pty.d.ts.map +1 -1
  418. package/dist/terminal/vt/pty.js +18 -3
  419. package/dist/terminal/vt/pty.js.map +1 -1
  420. package/dist/terminal-output/index.d.ts.map +1 -1
  421. package/dist/terminal-output/index.js +6 -1
  422. package/dist/terminal-output/index.js.map +1 -1
  423. package/dist/three/canvas.d.ts.map +1 -1
  424. package/dist/three/canvas.js +85 -7
  425. package/dist/three/canvas.js.map +1 -1
  426. package/dist/three/events.d.ts +22 -4
  427. package/dist/three/events.d.ts.map +1 -1
  428. package/dist/three/events.js +34 -4
  429. package/dist/three/events.js.map +1 -1
  430. package/dist/tree/index.d.ts.map +1 -1
  431. package/dist/tree/index.js +17 -0
  432. package/dist/tree/index.js.map +1 -1
  433. package/package.json +42 -33
  434. package/src/charts/node.ts +62 -26
  435. package/src/charts/render.ts +120 -30
  436. package/src/code/index.ts +3 -1
  437. package/src/code-editor/completion.ts +3 -2
  438. package/src/code-editor/index.ts +19 -0
  439. package/src/code-editor/node.ts +1574 -184
  440. package/src/code-language/languages/glsl.ts +12 -2
  441. package/src/code-language/languages/javascript.ts +21 -4
  442. package/src/code-language/languages/json.ts +12 -2
  443. package/src/code-language/languages/shell.ts +12 -2
  444. package/src/code-language/languages/sql.ts +22 -2
  445. package/src/code-language/stream.ts +257 -17
  446. package/src/code-language/types.ts +5 -4
  447. package/src/codeblock/index.ts +20 -3
  448. package/src/flow/draw.ts +167 -41
  449. package/src/flow/gl/color.ts +85 -0
  450. package/src/flow/gl/index.ts +342 -0
  451. package/src/flow/gl/pack.ts +585 -0
  452. package/src/flow/gl/renderer.ts +679 -0
  453. package/src/flow/gl/shaders.ts +371 -0
  454. package/src/flow/gl/text.ts +1295 -0
  455. package/src/flow/index.ts +794 -67
  456. package/src/flow/node.ts +2496 -1256
  457. package/src/flow/paint.ts +511 -0
  458. package/src/flow/paths.ts +80 -15
  459. package/src/flow/scene.ts +2199 -0
  460. package/src/flow/types.ts +113 -1
  461. package/src/html/controls.ts +73 -2
  462. package/src/html/css/calc.ts +385 -0
  463. package/src/html/css/cascade.ts +1403 -62
  464. package/src/html/css/color.ts +755 -0
  465. package/src/html/css/content.ts +417 -0
  466. package/src/html/css/counter-styles.ts +973 -0
  467. package/src/html/css/decode.ts +130 -0
  468. package/src/html/css/parse.ts +1514 -160
  469. package/src/html/css/style.ts +4102 -222
  470. package/src/html/css/ua.ts +58 -12
  471. package/src/html/css/values.ts +150 -50
  472. package/src/html/css/vars.ts +348 -0
  473. package/src/html/dom.ts +284 -17
  474. package/src/html/fonts.ts +641 -0
  475. package/src/html/gif.ts +233 -0
  476. package/src/html/index.ts +180 -20
  477. package/src/html/layout/block.ts +3456 -230
  478. package/src/html/layout/boxes.ts +2100 -190
  479. package/src/html/layout/cache.ts +289 -0
  480. package/src/html/layout/collapse.ts +317 -0
  481. package/src/html/layout/css-grid.ts +1063 -0
  482. package/src/html/layout/flex.ts +1115 -106
  483. package/src/html/layout/floats.ts +128 -14
  484. package/src/html/layout/grid-lines.ts +141 -0
  485. package/src/html/layout/grid.ts +181 -0
  486. package/src/html/layout/inline.ts +3943 -192
  487. package/src/html/layout/shaping.ts +140 -0
  488. package/src/html/layout/table.ts +696 -186
  489. package/src/html/layout/tracks.ts +437 -0
  490. package/src/html/node.ts +1481 -118
  491. package/src/html/paint.ts +4293 -169
  492. package/src/html/resources.ts +161 -50
  493. package/src/html/surfaces.ts +81 -0
  494. package/src/html/svg.ts +493 -0
  495. package/src/html/url.ts +86 -0
  496. package/src/index.ts +2 -0
  497. package/src/internal/collate.ts +12 -0
  498. package/src/internal/markdown/ast.ts +11 -0
  499. package/src/internal/markdown/parse.ts +154 -11
  500. package/src/internal/prewarm.ts +45 -0
  501. package/src/internal/sdf.ts +227 -0
  502. package/src/internal/splice.ts +25 -0
  503. package/src/internal/window.ts +36 -5
  504. package/src/maps/anchors.ts +307 -1
  505. package/src/maps/controller.ts +116 -31
  506. package/src/maps/gl/buckets.ts +5 -1
  507. package/src/maps/gl/build-worker.ts +13 -2
  508. package/src/maps/gl/cover.ts +79 -44
  509. package/src/maps/gl/placement.ts +221 -69
  510. package/src/maps/gl/renderer.ts +104 -20
  511. package/src/maps/gl/shaders.ts +35 -32
  512. package/src/maps/gl/store.ts +66 -17
  513. package/src/maps/gl/text.ts +444 -71
  514. package/src/maps/gl/view.ts +361 -96
  515. package/src/maps/icons.ts +183 -0
  516. package/src/maps/index.ts +4 -0
  517. package/src/maps/labels.ts +269 -49
  518. package/src/maps/node.ts +82 -49
  519. package/src/maps/proj.ts +87 -0
  520. package/src/maps/sources.ts +5 -3
  521. package/src/maps/style.ts +32 -0
  522. package/src/maps/styles.ts +215 -4
  523. package/src/maps/tiles.ts +64 -31
  524. package/src/maps/types.ts +28 -4
  525. package/src/markdown/index.ts +149 -67
  526. package/src/markdown/spans.ts +5 -0
  527. package/src/qml/containers.tsx +6 -1
  528. package/src/qml/interaction.tsx +42 -5
  529. package/src/qml/layouts.tsx +21 -6
  530. package/src/qml/qtquick.tsx +9 -2
  531. package/src/qml/react.tsx +7 -5
  532. package/src/reorder/clock.ts +27 -0
  533. package/src/reorder/index.ts +100 -27
  534. package/src/rich-text-editor/index.ts +34 -1
  535. package/src/rich-text-editor/keymap.ts +1 -1
  536. package/src/rich-text-editor/keys.ts +135 -26
  537. package/src/rich-text-editor/marks.ts +101 -0
  538. package/src/rich-text-editor/render.ts +49 -12
  539. package/src/rich-text-editor/toolbar.ts +1 -1
  540. package/src/rich-text-editor/virtual.ts +25 -0
  541. package/src/richtext/node.ts +235 -14
  542. package/src/richtext/runs.ts +23 -12
  543. package/src/table/index.ts +29 -0
  544. package/src/table/rows.ts +18 -8
  545. package/src/terminal/index.ts +4 -0
  546. package/src/terminal/vt/pty.ts +16 -2
  547. package/src/terminal-output/index.ts +6 -1
  548. package/src/three/canvas.ts +102 -8
  549. package/src/three/events.ts +49 -9
  550. package/src/tree/index.ts +19 -0
@@ -0,0 +1,101 @@
1
+ // `toggleMark` from prosemirror-commands, with one difference: a mark is
2
+ // added the way prosemirror-transform already removes one.
3
+ //
4
+ // Its `addMark` makes a step for each run of text that lacks the mark, and a
5
+ // run ends where its textblock does. Bold over a document of 1,700 paragraphs
6
+ // is 1,700 steps, and each step copies the document's top-level children:
7
+ // quadratic in blocks, 425 ms a toggle over the sweep's 600 KB report.
8
+ // `removeMark` joins its runs across blocks already.
9
+ //
10
+ // `addMarkAcross` joins consecutive inline nodes that lack the mark whatever
11
+ // lies between them, which can only be block structure. An `AddMarkStep`
12
+ // marks the inline nodes of its range whose parent allows the mark and leaves
13
+ // everything else alone, and its inverse removes the mark from those same
14
+ // nodes, every one of which lacked it. So the document, the undo, and a
15
+ // position mapped through the transaction (a mark step maps nothing) are
16
+ // what they were. A node that already has the mark, or cannot take it, ends
17
+ // the run, as it did.
18
+
19
+ import { toggleMark as pmToggleMark } from 'prosemirror-commands';
20
+ import type { Attrs, Mark, MarkType } from 'prosemirror-model';
21
+ import type { Command, EditorState } from 'prosemirror-state';
22
+ import {
23
+ AddMarkStep,
24
+ RemoveMarkStep,
25
+ type Transform,
26
+ } from 'prosemirror-transform';
27
+
28
+ interface Run {
29
+ from: number;
30
+ to: number;
31
+ }
32
+
33
+ /** `tr.addMark(from, to, mark)`, one step for a run however many blocks it crosses. */
34
+ export function addMarkAcross(
35
+ tr: Transform,
36
+ from: number,
37
+ to: number,
38
+ mark: Mark,
39
+ ): Transform {
40
+ const removed: Array<Run & { mark: Mark }> = [];
41
+ const added: Run[] = [];
42
+ let removing: (Run & { mark: Mark }) | null = null;
43
+ let adding: Run | null = null;
44
+ tr.doc.nodesBetween(from, to, (node, pos, parent) => {
45
+ if (!node.isInline) return;
46
+ const marks = node.marks;
47
+ if (
48
+ mark.isInSet(marks) ||
49
+ !parent ||
50
+ !parent.type.allowsMarkType(mark.type)
51
+ ) {
52
+ adding = null;
53
+ return;
54
+ }
55
+ const start = Math.max(pos, from);
56
+ const end = Math.min(pos + node.nodeSize, to);
57
+ // the marks this one excludes come off first, run for run as addMark does
58
+ const newSet = mark.addToSet(marks);
59
+ for (const other of marks) {
60
+ if (other.isInSet(newSet)) continue;
61
+ if (removing && removing.to === start && removing.mark.eq(other))
62
+ removing.to = end;
63
+ else removed.push((removing = { from: start, to: end, mark: other }));
64
+ }
65
+ if (adding) adding.to = end;
66
+ else added.push((adding = { from: start, to: end }));
67
+ });
68
+ for (const r of removed) tr.step(new RemoveMarkStep(r.from, r.to, r.mark));
69
+ for (const a of added) tr.step(new AddMarkStep(a.from, a.to, mark));
70
+ return tr;
71
+ }
72
+
73
+ /** prosemirror-commands' `toggleMark`, adding through `addMarkAcross`. */
74
+ export function toggleMark(
75
+ markType: MarkType,
76
+ attrs: Attrs | null = null,
77
+ options?: Parameters<typeof pmToggleMark>[2],
78
+ ): Command {
79
+ const command = pmToggleMark(markType, attrs, options);
80
+ return (state, dispatch, view) =>
81
+ command(dispatch ? addingAcross(state) : state, dispatch, view);
82
+ }
83
+
84
+ /**
85
+ * The state as the command sees it: every transaction it starts adds marks
86
+ * through `addMarkAcross`. Only that transaction's own `addMark` is replaced,
87
+ * so nothing else in the process changes.
88
+ */
89
+ function addingAcross(state: EditorState): EditorState {
90
+ return new Proxy(state, {
91
+ get(target, prop) {
92
+ if (prop !== 'tr') return Reflect.get(target, prop, target);
93
+ const tr = target.tr;
94
+ tr.addMark = (from: number, to: number, mark: Mark) => {
95
+ addMarkAcross(tr, from, to, mark);
96
+ return tr;
97
+ };
98
+ return tr;
99
+ },
100
+ });
101
+ }
@@ -147,6 +147,53 @@ function isOrdered(list: PMNode): boolean {
147
147
  return domTagOf(list.type.spec, list)?.tag === 'ol';
148
148
  }
149
149
 
150
+ /**
151
+ * The element last made for a block, by its node. A block whose node, key
152
+ * and surroundings are what they were gets that element back, and React
153
+ * bails out of an element it has rendered before without so much as
154
+ * comparing its props — so a keystroke reconciles the block it changed,
155
+ * where it made and compared an element for every block in view: a hundred
156
+ * of them in a long document's window. Weak, so a node nobody draws any
157
+ * more takes its element with it.
158
+ */
159
+ const madeFor = new WeakMap<
160
+ PMNode,
161
+ {
162
+ key: string;
163
+ ctx: RenderContext;
164
+ bctx: BlockContext;
165
+ at: number;
166
+ register: RowProps['register'] | null;
167
+ element: ReactElement;
168
+ }
169
+ >();
170
+
171
+ function blockElement(
172
+ node: PMNode,
173
+ key: string,
174
+ ctx: RenderContext,
175
+ bctx: BlockContext,
176
+ at: number,
177
+ register: RowProps['register'] | null,
178
+ ): ReactElement {
179
+ const made = madeFor.get(node);
180
+ if (
181
+ made &&
182
+ made.key === key &&
183
+ made.ctx === ctx &&
184
+ made.bctx === bctx &&
185
+ made.at === at &&
186
+ made.register === register
187
+ ) {
188
+ return made.element;
189
+ }
190
+ const element = register
191
+ ? h(BlockRow, { key, blockKey: key, node, ctx, bctx, at, register })
192
+ : h(BlockView, { key, blockKey: key, node, ctx, bctx });
193
+ madeFor.set(node, { key, ctx, bctx, at, register, element });
194
+ return element;
195
+ }
196
+
150
197
  /** The blocks inside `parent`, whose content starts at `contentStart`. */
151
198
  export function renderBlocks(
152
199
  parent: PMNode,
@@ -158,7 +205,7 @@ export function renderBlocks(
158
205
  parent.forEach((child, offset) => {
159
206
  const pos = contentStart + offset;
160
207
  const key = ctx.view.keys.keyAt(pos) ?? `p${pos}`;
161
- out.push(h(BlockView, { key, blockKey: key, node: child, ctx, bctx }));
208
+ out.push(blockElement(child, key, ctx, bctx, -1, null));
162
209
  });
163
210
  return out;
164
211
  }
@@ -288,17 +335,7 @@ export function renderBlockRange(
288
335
  doc.forEach((child, offset, index) => {
289
336
  if (index < first || index >= last) return;
290
337
  const key = ctx.view.keys.keyAt(offset) ?? `p${offset}`;
291
- out.push(
292
- h(BlockRow, {
293
- key,
294
- blockKey: key,
295
- node: child,
296
- ctx,
297
- bctx: PLAIN,
298
- at: index,
299
- register,
300
- }),
301
- );
338
+ out.push(blockElement(child, key, ctx, PLAIN, index, register));
302
339
  });
303
340
  return out;
304
341
  }
@@ -30,7 +30,6 @@ import type { ReactElement, ReactNode } from 'react';
30
30
  import type { MouseEvent as X11MouseEvent } from 'react-x11';
31
31
  import { tint } from 'react-x11/style';
32
32
  import type { Style } from 'react-x11/style';
33
- import { toggleMark } from 'prosemirror-commands';
34
33
  import { redo, redoDepth, undo, undoDepth } from 'prosemirror-history';
35
34
  import type { Schema } from 'prosemirror-model';
36
35
  import type { Command, EditorState } from 'prosemirror-state';
@@ -48,6 +47,7 @@ import {
48
47
  toggleWrap,
49
48
  } from './commands.js';
50
49
  import type { EditorLook } from './look.js';
50
+ import { toggleMark } from './marks.js';
51
51
  import {
52
52
  addColumnAfter,
53
53
  addColumnBefore,
@@ -131,11 +131,36 @@ export function useBlockWindow(inputs: BlockWindowInputs): BlockWindowState {
131
131
  }
132
132
  heights.sync(rows, estimate);
133
133
 
134
+ /**
135
+ * One drawn block into the index, for the window's trim: it drops a block
136
+ * only once the index knows the height it is laid out at, and a scroll
137
+ * reaches the blocks behind it long before `measure` below has run — so
138
+ * it dropped none, and a scroll through a long document kept every block
139
+ * it passed mounted (the flick `<Table>` and `<Tree>` had, and the same
140
+ * hook: `measure` on the window's inputs).
141
+ */
142
+ const measureDrawn = useCallback(
143
+ (id: RowKey, at: number): boolean => {
144
+ const drawn = nodes.current.get(id);
145
+ if (!drawn || drawn.at !== at || !(drawn.node.abs.height > 0)) {
146
+ return false;
147
+ }
148
+ heights.measure(
149
+ id,
150
+ at,
151
+ drawn.node.abs.height / scaleOf(drawn.node) + gapRef.current,
152
+ );
153
+ return heights.isMeasured(at);
154
+ },
155
+ [heights],
156
+ );
157
+
134
158
  const win = useVirtualWindow({
135
159
  box,
136
160
  heights,
137
161
  rows,
138
162
  exact: false,
163
+ measure: measureDrawn,
139
164
  virtualizing,
140
165
  overscan: DEFAULT_OVERSCAN,
141
166
  prefetch: DEFAULT_PREFETCH,
@@ -82,6 +82,10 @@ export interface TextRun {
82
82
  weight?: number | 'normal' | 'bold';
83
83
  style?: 'normal' | 'italic';
84
84
  color?: string;
85
+ /** Pixels added after every glyph — CSS's `letter-spacing`. Both text
86
+ * engines take it on a span, and it passes through to them as the rest
87
+ * of the ntk vocabulary does. */
88
+ letterSpacing?: number;
85
89
  /** Fill painted behind the run — the inline-code chip. */
86
90
  bg?: string;
87
91
  /**
@@ -101,16 +105,37 @@ export interface TextRun {
101
105
  * sub-parameters, which a captured terminal session carries. Ignored
102
106
  * without `underline`, which is what says the rule exists at all. */
103
107
  underlineStyle?: 'single' | 'double' | 'curly' | 'dotted' | 'dashed';
108
+ /** How far below the baseline the underline's top is, and how thick it
109
+ * is, in the unit `size` is in — CSS's `text-underline-offset` and
110
+ * `text-decoration-thickness`. Unset, two pixels below and one thick. */
111
+ underlineOffset?: number;
112
+ underlineThickness?: number;
104
113
  /** 1px rule through the x-height, in this colour — `~~del~~`. */
105
114
  strike?: string;
106
115
  /** Link target. `null` is a link still streaming in (not clickable). */
107
116
  href?: string | null;
117
+ /** OpenType features the run is shaped with, by tag — `{ tnum: 1 }`,
118
+ * `{ liga: 0 }` — which both text engines take on a span. A run's fields
119
+ * are compared by identity (`sameRuns`), so the same features should be
120
+ * the same object. */
121
+ features?: Readonly<Record<string, number>>;
122
+ /** Runs that share a truthy `nowrap` have no break inside them or between
123
+ * them — the text of one element with `white-space: nowrap`, the element
124
+ * being the value. ntk's, from 8.13.0; CoreText breaks as it would. */
125
+ nowrap?: unknown;
126
+ /** Shaped on its own: ntk shapes a word that runs across spans shaped
127
+ * alike as one, kerned and joined across them, and a run marked so is
128
+ * kept apart from the ones either side of it — as CSS keeps the text
129
+ * either side of an inline box's margin, border or padding. ntk's, from
130
+ * 8.14.2. */
131
+ shapeApart?: boolean;
108
132
  }
109
133
 
110
134
  /** The props `<richtext>` takes. */
111
135
  export interface RichTextProps {
112
- /** The styled runs. Give a stable array identity — the layout cache and
113
- * the streaming path both key off it. */
136
+ /** The styled runs. Give a stable array identity where you can — the
137
+ * streaming path keys off it; an equal new array keeps its layout, for
138
+ * one pass over the runs (`sameRuns`). */
114
139
  runs: TextRun[];
115
140
  /** False lays the text out at its natural width, unwrapped — code. */
116
141
  wrap?: boolean;
@@ -178,6 +203,113 @@ interface FontsLike {
178
203
  ): TextLayoutLike;
179
204
  }
180
205
 
206
+ /** Spacing that tells runs apart and moves nothing: an engine that merges
207
+ * adjacent runs alike (CoreText) keeps a tab's space to itself. */
208
+ const HAIR = 1e-6;
209
+
210
+ /**
211
+ * The runs with each tab laid out as a space of its own, letter-spaced to
212
+ * the next stop: every eight spaces from its line's start, and past one
213
+ * less than half a "0" on (CSS Text 3, 4.2's `tab-size`). Neither engine
214
+ * sets a tab so — ntk has no glyph for one and draws a box, and CoreText
215
+ * stops every 28 points — so a tab-indented fence in `<Markdown>` or a
216
+ * `<Code>` block came out boxed or ragged. The space is the tab's length,
217
+ * so every offset holds, and the text a selection copies keeps its tabs.
218
+ * Placed from a first layout that has each tab as an unspaced space; a
219
+ * later tab on a line moves by what the ones before it added.
220
+ */
221
+ function tabbedRuns(
222
+ fonts: FontsLike,
223
+ runs: TextRun[],
224
+ base: Record<string, unknown>,
225
+ ): TextRun[] {
226
+ const out: TextRun[] = [];
227
+ const tabs: { at: number; index: number }[] = [];
228
+ let units = 0;
229
+ for (const run of runs) {
230
+ const text = run.text;
231
+ if (!text.includes('\t')) {
232
+ out.push(run);
233
+ units += text.length;
234
+ continue;
235
+ }
236
+ let done = 0;
237
+ for (let p = text.indexOf('\t'); p >= 0; p = text.indexOf('\t', p + 1)) {
238
+ if (p > done) out.push({ ...run, text: text.slice(done, p) });
239
+ tabs.push({ at: units + p, index: out.length });
240
+ out.push({
241
+ ...run,
242
+ text: ' ',
243
+ letterSpacing: (run.letterSpacing ?? 0) + tabs.length * HAIR,
244
+ });
245
+ done = p + 1;
246
+ }
247
+ if (done < text.length) out.push({ ...run, text: text.slice(done) });
248
+ units += text.length;
249
+ }
250
+ const natural = fonts.layout(out, base, {});
251
+ const found = new Map<number, { x: number; line: number }>();
252
+ natural.lines.forEach((line, i) => {
253
+ for (const run of line.runs ?? []) {
254
+ found.set(run.start, { x: line.x + run.x, line: i });
255
+ }
256
+ });
257
+ /** The room tabs have added to each line so far. */
258
+ const added = new Map<number, number>();
259
+ for (const tab of tabs) {
260
+ const run = out[tab.index];
261
+ const face = {
262
+ ...base,
263
+ ...(run.family !== undefined ? { family: run.family } : null),
264
+ ...(run.size !== undefined ? { size: run.size } : null),
265
+ ...(run.weight !== undefined ? { weight: run.weight } : null),
266
+ ...(run.style !== undefined ? { style: run.style } : null),
267
+ };
268
+ const space = advanceOf(fonts, face, ' ');
269
+ const every = 8 * space;
270
+ const own = space + (run.letterSpacing ?? 0);
271
+ const at = found.get(tab.at) ?? natural.caretPosition(tab.at);
272
+ const before = added.get(at.line) ?? 0;
273
+ const x = at.x + before;
274
+ let advance = own;
275
+ if (every > 0) {
276
+ let stop = (Math.floor(x / every) + 1) * every;
277
+ if (stop - x < advanceOf(fonts, face, '0') / 2) stop += every;
278
+ advance = stop - x;
279
+ }
280
+ out[tab.index] = {
281
+ ...run,
282
+ letterSpacing: (run.letterSpacing ?? 0) + advance - own,
283
+ };
284
+ added.set(at.line, before + advance - own);
285
+ }
286
+ return out;
287
+ }
288
+
289
+ /** A character's advance in a face: between two letters, so that no engine
290
+ * drops it as a line's end. Kept per engine and face: a file indented with
291
+ * tabs asks for it thousands of times. */
292
+ function advanceOf(
293
+ fonts: FontsLike,
294
+ face: Record<string, unknown>,
295
+ char: string,
296
+ ): number {
297
+ let kept = ADVANCES.get(fonts);
298
+ if (!kept) ADVANCES.set(fonts, (kept = new Map()));
299
+ const key = `${face.family}|${face.size}|${face.weight}|${face.style}|${char}`;
300
+ let advance = kept.get(key);
301
+ if (advance === undefined) {
302
+ advance =
303
+ fonts.layout([{ ...face, text: `x${char}x` } as TextRun], face, {})
304
+ .width -
305
+ fonts.layout([{ ...face, text: 'xx' } as TextRun], face, {}).width;
306
+ kept.set(key, advance);
307
+ }
308
+ return advance;
309
+ }
310
+
311
+ const ADVANCES = new WeakMap<FontsLike, Map<string, number>>();
312
+
181
313
  /**
182
314
  * The bands a highlight over `[start, end)` fills, in layout coordinates —
183
315
  * one per line, and more than one on a line that changes direction. The
@@ -212,9 +344,38 @@ function rangeBands(
212
344
  return bands;
213
345
  }
214
346
 
347
+ /**
348
+ * Whether two `runs` props say the same thing. A component that builds its
349
+ * runs in render hands over a new array whenever it renders, whether or not
350
+ * the text changed — the rich text editor does on every keystroke, for
351
+ * paragraphs the keystroke never reached — and the array's identity was
352
+ * all a layout cache cleared on. A run's fields are all primitives, so one
353
+ * shallow pass decides it, where the layout it spares is a paragraph shaped
354
+ * and broken again.
355
+ */
356
+ function sameRuns(a: unknown, b: unknown): boolean {
357
+ if (a === b) return true;
358
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) {
359
+ return false;
360
+ }
361
+ for (let i = 0; i < a.length; i++) {
362
+ const x = a[i] as Record<string, unknown>;
363
+ const y = b[i] as Record<string, unknown>;
364
+ if (x === y) continue;
365
+ if (!x || !y) return false;
366
+ const keys = Object.keys(x);
367
+ if (keys.length !== Object.keys(y).length) return false;
368
+ for (const key of keys) if (x[key] !== y[key]) return false;
369
+ }
370
+ return true;
371
+ }
372
+
215
373
  export class RichTextNode extends Node {
216
374
  private _layouts = new Map<string, TextLayoutLike | null>();
217
375
  private _text: string | null = null;
376
+ /** The runs as laid out where a tab is among them, and what from. */
377
+ private _tabbed: { from: TextRun[]; scale: number; to: TextRun[] } | null =
378
+ null;
218
379
 
219
380
  /**
220
381
  * `kind` is for a subclass registered under a name of its own — the rich
@@ -266,21 +427,36 @@ export class RichTextNode extends Node {
266
427
  let layout: TextLayoutLike | null = null;
267
428
  if (fonts) {
268
429
  const s = this._scale;
269
- layout = fonts.layout(
270
- this._deviceRuns(s),
271
- { family: 'sans-serif', size: 14 * s },
272
- {
273
- maxWidth: Number.isFinite(maxWidth) ? maxWidth : undefined,
274
- lineHeight: this.style.lineHeight,
275
- align: this.style.textAlign,
276
- },
277
- );
430
+ const base = { family: 'sans-serif', size: 14 * s };
431
+ layout = fonts.layout(this._tabRuns(fonts, base, s), base, {
432
+ maxWidth: Number.isFinite(maxWidth) ? maxWidth : undefined,
433
+ lineHeight: this.style.lineHeight,
434
+ align: this.style.textAlign,
435
+ });
278
436
  }
279
437
  if (this._layouts.size > 32) this._layouts.clear();
280
438
  this._layouts.set(key, layout);
281
439
  return layout;
282
440
  }
283
441
 
442
+ /** The runs with their tabs set to their stops (`tabbedRuns`), found
443
+ * once for a list of runs: most have none, and are handed on as they
444
+ * are. */
445
+ private _tabRuns(
446
+ fonts: FontsLike,
447
+ base: Record<string, unknown>,
448
+ scale: number,
449
+ ): TextRun[] {
450
+ const from = this._runs();
451
+ const runs = this._deviceRuns(scale);
452
+ if (!runs.some((run) => run.text.includes('\t'))) return runs;
453
+ const kept = this._tabbed;
454
+ if (kept && kept.from === from && kept.scale === scale) return kept.to;
455
+ const to = tabbedRuns(fonts, runs, base);
456
+ this._tabbed = { from, scale, to };
457
+ return to;
458
+ }
459
+
284
460
  // --- units ---------------------------------------------------------------
285
461
  //
286
462
  // The layout, `abs` and the paint are device pixels (react-x11's
@@ -305,7 +481,20 @@ export class RichTextNode extends Node {
305
481
  const runs = this._runs();
306
482
  if (scale === 1) return runs;
307
483
  return runs.map((r) =>
308
- typeof r.size === 'number' ? { ...r, size: r.size * scale } : r,
484
+ typeof r.size === 'number' ||
485
+ r.underlineOffset !== undefined ||
486
+ r.underlineThickness !== undefined
487
+ ? {
488
+ ...r,
489
+ ...(typeof r.size === 'number' ? { size: r.size * scale } : null),
490
+ ...(r.underlineOffset !== undefined
491
+ ? { underlineOffset: r.underlineOffset * scale }
492
+ : null),
493
+ ...(r.underlineThickness !== undefined
494
+ ? { underlineThickness: r.underlineThickness * scale }
495
+ : null),
496
+ }
497
+ : r,
309
498
  );
310
499
  }
311
500
 
@@ -327,15 +516,34 @@ export class RichTextNode extends Node {
327
516
  ): void {
328
517
  super.applyProps(nextProps, prevProps);
329
518
  if (
330
- nextProps.runs !== prevProps.runs ||
331
- nextProps.wrap !== prevProps.wrap
519
+ nextProps.wrap !== prevProps.wrap ||
520
+ !sameRuns(nextProps.runs, prevProps.runs)
332
521
  ) {
333
522
  this._layouts.clear();
334
523
  this._text = null;
524
+ this._tabbed = null;
335
525
  this.invalidateMeasure('content');
336
526
  }
337
527
  }
338
528
 
529
+ /** A new `runs` array that says what the last one said changes nothing
530
+ * drawn — see `sameRuns`. */
531
+ override paintChanged(
532
+ nextProps: Record<string, unknown>,
533
+ prevProps: Record<string, unknown>,
534
+ ): boolean {
535
+ if (
536
+ nextProps.runs !== prevProps.runs &&
537
+ sameRuns(nextProps.runs, prevProps.runs)
538
+ ) {
539
+ return super.paintChanged(
540
+ { ...nextProps, runs: prevProps.runs },
541
+ prevProps,
542
+ );
543
+ }
544
+ return super.paintChanged(nextProps, prevProps);
545
+ }
546
+
339
547
  override destroySubtree(): void {
340
548
  this._layouts.clear();
341
549
  super.destroySubtree();
@@ -440,6 +648,19 @@ export class RichTextNode extends Node {
440
648
  ctx.restore();
441
649
  }
442
650
 
651
+ /**
652
+ * How far this element draws past its box: a code chip is padded two
653
+ * pixels past the run behind it (`paintRunBackgrounds`), and at the start
654
+ * or the end of a line the pad is outside the box. Said for every
655
+ * paragraph, chips or not — core reads it when it rebuilds the paint
656
+ * bounds a claim covers, and the claim after an edit that took the last
657
+ * chip away still has to cover the chip the frame before drew. An older
658
+ * core never asks.
659
+ */
660
+ override paintOverhang(): number {
661
+ return Math.round(2 * this.scale);
662
+ }
663
+
443
664
  /**
444
665
  * The selection band, between the run backgrounds and the ink. The default
445
666
  * is core's document selection: the band the `selectable` surface above
@@ -34,10 +34,10 @@ export function canFill(ctx: unknown): ctx is FillContext {
34
34
  *
35
35
  * `span` and `run` are what ntk's layout hands back and what every
36
36
  * decoration is read from: the span the run came from, markers and all, and
37
- * the face it was shaped with. Both are optional because react-x11's Cocoa
38
- * engine (2.3.x) reports only a run's geometry — `{ x, width, start, end }`
39
- * — and a paint that assumed the rest threw on the first paragraph on
40
- * macOS. A run without its span has no decoration to draw; a run without
37
+ * the face it was shaped with. Both are optional because an engine may
38
+ * report only a run's geometry — `{ x, width, start, end }` — as react-x11's
39
+ * Windows engine does and its Cocoa engine did before 2.22.8, and a paint
40
+ * that assumed the rest threw on the first paragraph on macOS. A run without its span has no decoration to draw; a run without
41
41
  * its face takes its vertical extent from the line, which both engines
42
42
  * report.
43
43
  */
@@ -102,7 +102,8 @@ let warnedSpanless = false;
102
102
  * Say so, once, when a laid-out run arrives without the span it came from:
103
103
  * every decoration is read off that span, so none will be drawn, and a
104
104
  * document that suddenly has no code chips or link underlines should not be
105
- * a mystery. react-x11's Cocoa engine (2.3.x) is the one that does this.
105
+ * a mystery. react-x11's Windows engine does this, and its Cocoa engine did
106
+ * before 2.22.8.
106
107
  *
107
108
  * `process` and `console` come off `globalThis` because `src/` compiles
108
109
  * with `types: []` — a Node global that wandered in would fail the build
@@ -120,7 +121,8 @@ function warnSpanless(): void {
120
121
  '@react-x11/components: the text engine handed back laid-out runs ' +
121
122
  'without their spans, so run decorations (backgrounds, underlines, ' +
122
123
  "strikethrough) and inline link hit-testing are off. react-x11's " +
123
- "Cocoa text engine (2.3.x) does this; ntk's does not.",
124
+ 'Windows text engine does this, as its Cocoa engine did before ' +
125
+ "2.22.8; ntk's does not.",
124
126
  );
125
127
  }
126
128
 
@@ -174,30 +176,39 @@ export function paintRunBackgrounds(
174
176
  }
175
177
  }
176
178
 
177
- /** The rules that sit **over** the glyphs: link underlines, strikethrough.
178
- * A rule is one logical pixel thick — `scale` device pixels, so a link on a
179
- * 2x panel is underlined as heavily as on a 1x one, not with a hairline. */
179
+ /** The rules drawn with a run: its underline and its strikethrough. A rule
180
+ * is one logical pixel thick — `scale` device pixels, so a link on a 2x
181
+ * panel is underlined as heavily as on a 1x one, not with a hairline —
182
+ * and an underline two below the baseline, where the run sets neither
183
+ * (`underlineThickness`, `underlineOffset`, in device pixels by now).
184
+ * `rules` picks a pass: CSS draws an underline under the glyphs and a
185
+ * line through over them (CSS 2.1 Appendix E), which is two passes around
186
+ * the glyphs'; drawn in one, both go over. */
180
187
  export function paintRunRules(
181
188
  ctx: FillContext,
182
189
  line: LaidLine,
183
190
  dx: number,
184
191
  dy: number,
185
192
  scale = 1,
193
+ rules: 'under' | 'over' | 'all' = 'all',
186
194
  ): void {
187
195
  const t = ruleThickness(scale);
188
196
  for (const r of line.runs) {
189
197
  const span = r.span;
190
198
  if (!span) continue;
191
- const { underline, strike } = span;
199
+ const underline = rules !== 'over' ? span.underline : undefined;
200
+ const strike = rules !== 'under' ? span.strike : undefined;
192
201
  if (underline) {
193
202
  ctx.fillStyle = underline;
194
203
  underlineRule(
195
204
  ctx,
196
205
  Math.round(dx + line.x + r.x),
197
- Math.round(dy + line.baseline + 2 * t),
206
+ Math.round(dy + line.baseline + (span.underlineOffset ?? 2 * t)),
198
207
  Math.ceil(r.width),
199
208
  span.underlineStyle ?? 'single',
200
- t,
209
+ span.underlineThickness === undefined
210
+ ? t
211
+ : Math.max(1, Math.round(span.underlineThickness)),
201
212
  );
202
213
  }
203
214
  if (strike) {