@react-x11/components 0.7.1 → 0.9.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 (354) hide show
  1. package/README.md +295 -51
  2. package/dist/charts/node.d.ts +1 -1
  3. package/dist/charts/node.d.ts.map +1 -1
  4. package/dist/charts/node.js +6 -2
  5. package/dist/charts/node.js.map +1 -1
  6. package/dist/color-picker/ColorPicker.d.ts.map +1 -1
  7. package/dist/color-picker/ColorPicker.js +43 -33
  8. package/dist/color-picker/ColorPicker.js.map +1 -1
  9. package/dist/embed/client.d.ts +48 -3
  10. package/dist/embed/client.d.ts.map +1 -1
  11. package/dist/embed/client.js +79 -5
  12. package/dist/embed/client.js.map +1 -1
  13. package/dist/embed/index.d.ts +1 -1
  14. package/dist/embed/index.d.ts.map +1 -1
  15. package/dist/embed/index.js +1 -1
  16. package/dist/embed/index.js.map +1 -1
  17. package/dist/html/node.d.ts +3 -1
  18. package/dist/html/node.d.ts.map +1 -1
  19. package/dist/html/node.js +7 -5
  20. package/dist/html/node.js.map +1 -1
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +1 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/{markdown → internal/markdown}/ast.d.ts +12 -0
  26. package/dist/internal/markdown/ast.d.ts.map +1 -0
  27. package/dist/internal/markdown/ast.js +22 -0
  28. package/dist/internal/markdown/ast.js.map +1 -0
  29. package/dist/internal/markdown/parse.d.ts.map +1 -0
  30. package/dist/{markdown → internal/markdown}/parse.js +112 -22
  31. package/dist/internal/markdown/parse.js.map +1 -0
  32. package/dist/internal/markdown/stringify.d.ts +4 -0
  33. package/dist/internal/markdown/stringify.d.ts.map +1 -0
  34. package/dist/internal/markdown/stringify.js +684 -0
  35. package/dist/internal/markdown/stringify.js.map +1 -0
  36. package/dist/internal/markdown/tags.d.ts.map +1 -0
  37. package/dist/internal/markdown/tags.js.map +1 -0
  38. package/dist/internal/scroll.d.ts +3 -2
  39. package/dist/internal/scroll.d.ts.map +1 -1
  40. package/dist/internal/scroll.js +33 -15
  41. package/dist/internal/scroll.js.map +1 -1
  42. package/dist/internal/units.d.ts +2 -0
  43. package/dist/internal/units.d.ts.map +1 -0
  44. package/dist/internal/units.js +35 -0
  45. package/dist/internal/units.js.map +1 -0
  46. package/dist/internal/window.d.ts.map +1 -1
  47. package/dist/internal/window.js +4 -2
  48. package/dist/internal/window.js.map +1 -1
  49. package/dist/maps/anchors.d.ts +98 -0
  50. package/dist/maps/anchors.d.ts.map +1 -0
  51. package/dist/maps/anchors.js +531 -0
  52. package/dist/maps/anchors.js.map +1 -0
  53. package/dist/maps/controller.d.ts +283 -0
  54. package/dist/maps/controller.d.ts.map +1 -0
  55. package/dist/maps/controller.js +743 -0
  56. package/dist/maps/controller.js.map +1 -0
  57. package/dist/maps/gl/buckets.d.ts +95 -0
  58. package/dist/maps/gl/buckets.d.ts.map +1 -0
  59. package/dist/maps/gl/buckets.js +362 -0
  60. package/dist/maps/gl/buckets.js.map +1 -0
  61. package/dist/maps/gl/build-worker.d.ts +13 -0
  62. package/dist/maps/gl/build-worker.d.ts.map +1 -0
  63. package/dist/maps/gl/build-worker.js +44 -0
  64. package/dist/maps/gl/build-worker.js.map +1 -0
  65. package/dist/maps/gl/color.d.ts +8 -0
  66. package/dist/maps/gl/color.d.ts.map +1 -0
  67. package/dist/maps/gl/color.js +57 -0
  68. package/dist/maps/gl/color.js.map +1 -0
  69. package/dist/maps/gl/cover.d.ts +51 -0
  70. package/dist/maps/gl/cover.d.ts.map +1 -0
  71. package/dist/maps/gl/cover.js +124 -0
  72. package/dist/maps/gl/cover.js.map +1 -0
  73. package/dist/maps/gl/index.d.ts +3 -0
  74. package/dist/maps/gl/index.d.ts.map +1 -0
  75. package/dist/maps/gl/index.js +20 -0
  76. package/dist/maps/gl/index.js.map +1 -0
  77. package/dist/maps/gl/markers.d.ts +28 -0
  78. package/dist/maps/gl/markers.d.ts.map +1 -0
  79. package/dist/maps/gl/markers.js +60 -0
  80. package/dist/maps/gl/markers.js.map +1 -0
  81. package/dist/maps/gl/overlays.d.ts +68 -0
  82. package/dist/maps/gl/overlays.d.ts.map +1 -0
  83. package/dist/maps/gl/overlays.js +300 -0
  84. package/dist/maps/gl/overlays.js.map +1 -0
  85. package/dist/maps/gl/pane.d.ts +12 -0
  86. package/dist/maps/gl/pane.d.ts.map +1 -0
  87. package/dist/maps/gl/pane.js +37 -0
  88. package/dist/maps/gl/pane.js.map +1 -0
  89. package/dist/maps/gl/placement.d.ts +111 -0
  90. package/dist/maps/gl/placement.d.ts.map +1 -0
  91. package/dist/maps/gl/placement.js +567 -0
  92. package/dist/maps/gl/placement.js.map +1 -0
  93. package/dist/maps/gl/renderer.d.ts +352 -0
  94. package/dist/maps/gl/renderer.d.ts.map +1 -0
  95. package/dist/maps/gl/renderer.js +1127 -0
  96. package/dist/maps/gl/renderer.js.map +1 -0
  97. package/dist/maps/gl/shaders.d.ts +120 -0
  98. package/dist/maps/gl/shaders.d.ts.map +1 -0
  99. package/dist/maps/gl/shaders.js +451 -0
  100. package/dist/maps/gl/shaders.js.map +1 -0
  101. package/dist/maps/gl/store.d.ts +115 -0
  102. package/dist/maps/gl/store.d.ts.map +1 -0
  103. package/dist/maps/gl/store.js +469 -0
  104. package/dist/maps/gl/store.js.map +1 -0
  105. package/dist/maps/gl/text.d.ts +154 -0
  106. package/dist/maps/gl/text.d.ts.map +1 -0
  107. package/dist/maps/gl/text.js +382 -0
  108. package/dist/maps/gl/text.js.map +1 -0
  109. package/dist/maps/gl/view.d.ts +54 -0
  110. package/dist/maps/gl/view.d.ts.map +1 -0
  111. package/dist/maps/gl/view.js +974 -0
  112. package/dist/maps/gl/view.js.map +1 -0
  113. package/dist/maps/index.d.ts +1 -1
  114. package/dist/maps/index.d.ts.map +1 -1
  115. package/dist/maps/index.js +216 -52
  116. package/dist/maps/index.js.map +1 -1
  117. package/dist/maps/labels.d.ts +37 -16
  118. package/dist/maps/labels.d.ts.map +1 -1
  119. package/dist/maps/labels.js +188 -119
  120. package/dist/maps/labels.js.map +1 -1
  121. package/dist/maps/node.d.ts +162 -56
  122. package/dist/maps/node.d.ts.map +1 -1
  123. package/dist/maps/node.js +607 -515
  124. package/dist/maps/node.js.map +1 -1
  125. package/dist/maps/overlay.d.ts +72 -9
  126. package/dist/maps/overlay.d.ts.map +1 -1
  127. package/dist/maps/overlay.js +108 -28
  128. package/dist/maps/overlay.js.map +1 -1
  129. package/dist/maps/paint.d.ts +3 -0
  130. package/dist/maps/paint.d.ts.map +1 -1
  131. package/dist/maps/paint.js.map +1 -1
  132. package/dist/maps/proj.d.ts +14 -0
  133. package/dist/maps/proj.d.ts.map +1 -1
  134. package/dist/maps/proj.js +28 -0
  135. package/dist/maps/proj.js.map +1 -1
  136. package/dist/maps/renderer.d.ts +69 -0
  137. package/dist/maps/renderer.d.ts.map +1 -0
  138. package/dist/maps/renderer.js +66 -0
  139. package/dist/maps/renderer.js.map +1 -0
  140. package/dist/maps/sources.d.ts +25 -3
  141. package/dist/maps/sources.d.ts.map +1 -1
  142. package/dist/maps/sources.js +17 -0
  143. package/dist/maps/sources.js.map +1 -1
  144. package/dist/maps/theme.d.ts +19 -0
  145. package/dist/maps/theme.d.ts.map +1 -0
  146. package/dist/maps/theme.js +44 -0
  147. package/dist/maps/theme.js.map +1 -0
  148. package/dist/maps/tiles.d.ts +117 -17
  149. package/dist/maps/tiles.d.ts.map +1 -1
  150. package/dist/maps/tiles.js +163 -30
  151. package/dist/maps/tiles.js.map +1 -1
  152. package/dist/maps/types.d.ts +188 -20
  153. package/dist/maps/types.d.ts.map +1 -1
  154. package/dist/markdown/expressions.d.ts +1 -1
  155. package/dist/markdown/expressions.d.ts.map +1 -1
  156. package/dist/markdown/expressions.js.map +1 -1
  157. package/dist/markdown/index.d.ts +7 -6
  158. package/dist/markdown/index.d.ts.map +1 -1
  159. package/dist/markdown/index.js +9 -7
  160. package/dist/markdown/index.js.map +1 -1
  161. package/dist/markdown/spans.d.ts +1 -1
  162. package/dist/markdown/spans.d.ts.map +1 -1
  163. package/dist/media-player/index.d.ts +11 -3
  164. package/dist/media-player/index.d.ts.map +1 -1
  165. package/dist/media-player/index.js +13 -2
  166. package/dist/media-player/index.js.map +1 -1
  167. package/dist/rich-text-editor/clipboard.d.ts +23 -0
  168. package/dist/rich-text-editor/clipboard.d.ts.map +1 -0
  169. package/dist/rich-text-editor/clipboard.js +307 -0
  170. package/dist/rich-text-editor/clipboard.js.map +1 -0
  171. package/dist/rich-text-editor/collab.d.ts +32 -0
  172. package/dist/rich-text-editor/collab.d.ts.map +1 -0
  173. package/dist/rich-text-editor/collab.js +55 -0
  174. package/dist/rich-text-editor/collab.js.map +1 -0
  175. package/dist/rich-text-editor/commands.d.ts +50 -0
  176. package/dist/rich-text-editor/commands.d.ts.map +1 -0
  177. package/dist/rich-text-editor/commands.js +376 -0
  178. package/dist/rich-text-editor/commands.js.map +1 -0
  179. package/dist/rich-text-editor/drag.d.ts +68 -0
  180. package/dist/rich-text-editor/drag.d.ts.map +1 -0
  181. package/dist/rich-text-editor/drag.js +148 -0
  182. package/dist/rich-text-editor/drag.js.map +1 -0
  183. package/dist/rich-text-editor/html.d.ts +145 -0
  184. package/dist/rich-text-editor/html.d.ts.map +1 -0
  185. package/dist/rich-text-editor/html.js +516 -0
  186. package/dist/rich-text-editor/html.js.map +1 -0
  187. package/dist/rich-text-editor/index.d.ts +263 -0
  188. package/dist/rich-text-editor/index.d.ts.map +1 -0
  189. package/dist/rich-text-editor/index.js +822 -0
  190. package/dist/rich-text-editor/index.js.map +1 -0
  191. package/dist/rich-text-editor/inline.d.ts +94 -0
  192. package/dist/rich-text-editor/inline.d.ts.map +1 -0
  193. package/dist/rich-text-editor/inline.js +252 -0
  194. package/dist/rich-text-editor/inline.js.map +1 -0
  195. package/dist/rich-text-editor/keymap.d.ts +71 -0
  196. package/dist/rich-text-editor/keymap.d.ts.map +1 -0
  197. package/dist/rich-text-editor/keymap.js +393 -0
  198. package/dist/rich-text-editor/keymap.js.map +1 -0
  199. package/dist/rich-text-editor/keys.d.ts +29 -0
  200. package/dist/rich-text-editor/keys.d.ts.map +1 -0
  201. package/dist/rich-text-editor/keys.js +93 -0
  202. package/dist/rich-text-editor/keys.js.map +1 -0
  203. package/dist/rich-text-editor/look.d.ts +71 -0
  204. package/dist/rich-text-editor/look.d.ts.map +1 -0
  205. package/dist/rich-text-editor/look.js +342 -0
  206. package/dist/rich-text-editor/look.js.map +1 -0
  207. package/dist/rich-text-editor/markdown.d.ts +18 -0
  208. package/dist/rich-text-editor/markdown.d.ts.map +1 -0
  209. package/dist/rich-text-editor/markdown.js +496 -0
  210. package/dist/rich-text-editor/markdown.js.map +1 -0
  211. package/dist/rich-text-editor/nodes.d.ts +135 -0
  212. package/dist/rich-text-editor/nodes.d.ts.map +1 -0
  213. package/dist/rich-text-editor/nodes.js +397 -0
  214. package/dist/rich-text-editor/nodes.js.map +1 -0
  215. package/dist/rich-text-editor/render.d.ts +68 -0
  216. package/dist/rich-text-editor/render.d.ts.map +1 -0
  217. package/dist/rich-text-editor/render.js +500 -0
  218. package/dist/rich-text-editor/render.js.map +1 -0
  219. package/dist/rich-text-editor/schema.d.ts +16 -0
  220. package/dist/rich-text-editor/schema.d.ts.map +1 -0
  221. package/dist/rich-text-editor/schema.js +386 -0
  222. package/dist/rich-text-editor/schema.js.map +1 -0
  223. package/dist/rich-text-editor/store.d.ts +11 -0
  224. package/dist/rich-text-editor/store.d.ts.map +1 -0
  225. package/dist/rich-text-editor/store.js +43 -0
  226. package/dist/rich-text-editor/store.js.map +1 -0
  227. package/dist/rich-text-editor/suggest.d.ts +127 -0
  228. package/dist/rich-text-editor/suggest.d.ts.map +1 -0
  229. package/dist/rich-text-editor/suggest.js +0 -0
  230. package/dist/rich-text-editor/suggest.js.map +1 -0
  231. package/dist/rich-text-editor/tables.d.ts +41 -0
  232. package/dist/rich-text-editor/tables.d.ts.map +1 -0
  233. package/dist/rich-text-editor/tables.js +204 -0
  234. package/dist/rich-text-editor/tables.js.map +1 -0
  235. package/dist/rich-text-editor/toolbar.d.ts +58 -0
  236. package/dist/rich-text-editor/toolbar.d.ts.map +1 -0
  237. package/dist/rich-text-editor/toolbar.js +548 -0
  238. package/dist/rich-text-editor/toolbar.js.map +1 -0
  239. package/dist/rich-text-editor/view.d.ts +368 -0
  240. package/dist/rich-text-editor/view.d.ts.map +1 -0
  241. package/dist/rich-text-editor/view.js +1968 -0
  242. package/dist/rich-text-editor/view.js.map +1 -0
  243. package/dist/rich-text-editor/virtual.d.ts +54 -0
  244. package/dist/rich-text-editor/virtual.d.ts.map +1 -0
  245. package/dist/rich-text-editor/virtual.js +262 -0
  246. package/dist/rich-text-editor/virtual.js.map +1 -0
  247. package/dist/richtext/node.d.ts +25 -2
  248. package/dist/richtext/node.d.ts.map +1 -1
  249. package/dist/richtext/node.js +46 -24
  250. package/dist/richtext/node.js.map +1 -1
  251. package/dist/table/index.d.ts.map +1 -1
  252. package/dist/table/index.js +14 -5
  253. package/dist/table/index.js.map +1 -1
  254. package/dist/terminal/backends.d.ts +4 -1
  255. package/dist/terminal/backends.d.ts.map +1 -1
  256. package/dist/terminal/backends.js.map +1 -1
  257. package/dist/terminal/index.d.ts +18 -7
  258. package/dist/terminal/index.d.ts.map +1 -1
  259. package/dist/terminal/index.js +28 -11
  260. package/dist/terminal/index.js.map +1 -1
  261. package/dist/terminal/vt/node.d.ts +56 -3
  262. package/dist/terminal/vt/node.d.ts.map +1 -1
  263. package/dist/terminal/vt/node.js +106 -26
  264. package/dist/terminal/vt/node.js.map +1 -1
  265. package/dist/terminal/vt/renderer.d.ts +4 -0
  266. package/dist/terminal/vt/renderer.d.ts.map +1 -1
  267. package/dist/terminal/vt/renderer.js +14 -5
  268. package/dist/terminal/vt/renderer.js.map +1 -1
  269. package/dist/tree/index.d.ts.map +1 -1
  270. package/dist/tree/index.js +6 -4
  271. package/dist/tree/index.js.map +1 -1
  272. package/package.json +23 -4
  273. package/src/charts/node.ts +6 -2
  274. package/src/color-picker/ColorPicker.ts +107 -81
  275. package/src/embed/client.ts +102 -8
  276. package/src/embed/index.ts +2 -0
  277. package/src/html/node.ts +7 -5
  278. package/src/index.ts +2 -0
  279. package/src/{markdown → internal/markdown}/ast.ts +24 -7
  280. package/src/{markdown → internal/markdown}/parse.ts +134 -24
  281. package/src/internal/markdown/stringify.ts +772 -0
  282. package/src/internal/scroll.ts +39 -18
  283. package/src/internal/units.ts +34 -0
  284. package/src/internal/window.ts +4 -2
  285. package/src/maps/anchors.ts +607 -0
  286. package/src/maps/controller.ts +999 -0
  287. package/src/maps/gl/buckets.ts +457 -0
  288. package/src/maps/gl/build-worker.ts +55 -0
  289. package/src/maps/gl/color.ts +62 -0
  290. package/src/maps/gl/cover.ts +170 -0
  291. package/src/maps/gl/index.ts +23 -0
  292. package/src/maps/gl/markers.ts +83 -0
  293. package/src/maps/gl/overlays.ts +379 -0
  294. package/src/maps/gl/pane.ts +42 -0
  295. package/src/maps/gl/placement.ts +816 -0
  296. package/src/maps/gl/renderer.ts +1576 -0
  297. package/src/maps/gl/shaders.ts +486 -0
  298. package/src/maps/gl/store.ts +566 -0
  299. package/src/maps/gl/text.ts +495 -0
  300. package/src/maps/gl/view.ts +1224 -0
  301. package/src/maps/index.ts +270 -81
  302. package/src/maps/labels.ts +214 -121
  303. package/src/maps/node.ts +763 -629
  304. package/src/maps/overlay.ts +148 -43
  305. package/src/maps/paint.ts +3 -0
  306. package/src/maps/proj.ts +31 -0
  307. package/src/maps/renderer.ts +155 -0
  308. package/src/maps/sources.ts +38 -3
  309. package/src/maps/theme.ts +51 -0
  310. package/src/maps/tiles.ts +191 -33
  311. package/src/maps/types.ts +188 -20
  312. package/src/markdown/expressions.ts +5 -1
  313. package/src/markdown/index.ts +14 -11
  314. package/src/markdown/spans.ts +1 -1
  315. package/src/media-player/index.ts +18 -4
  316. package/src/rich-text-editor/clipboard.ts +439 -0
  317. package/src/rich-text-editor/collab.ts +91 -0
  318. package/src/rich-text-editor/commands.ts +448 -0
  319. package/src/rich-text-editor/dom-globals.d.ts +23 -0
  320. package/src/rich-text-editor/drag.ts +211 -0
  321. package/src/rich-text-editor/html.ts +619 -0
  322. package/src/rich-text-editor/index.ts +1331 -0
  323. package/src/rich-text-editor/inline.ts +345 -0
  324. package/src/rich-text-editor/keymap.ts +510 -0
  325. package/src/rich-text-editor/keys.ts +119 -0
  326. package/src/rich-text-editor/look.ts +427 -0
  327. package/src/rich-text-editor/markdown.ts +653 -0
  328. package/src/rich-text-editor/nodes.ts +497 -0
  329. package/src/rich-text-editor/render.ts +800 -0
  330. package/src/rich-text-editor/schema.ts +431 -0
  331. package/src/rich-text-editor/store.ts +39 -0
  332. package/src/rich-text-editor/suggest.ts +597 -0
  333. package/src/rich-text-editor/tables.ts +272 -0
  334. package/src/rich-text-editor/toolbar.ts +724 -0
  335. package/src/rich-text-editor/view.ts +2287 -0
  336. package/src/rich-text-editor/virtual.ts +347 -0
  337. package/src/richtext/node.ts +59 -30
  338. package/src/table/index.ts +14 -5
  339. package/src/terminal/backends.ts +4 -1
  340. package/src/terminal/index.ts +43 -15
  341. package/src/terminal/vt/node.ts +128 -29
  342. package/src/terminal/vt/renderer.ts +27 -5
  343. package/src/tree/index.ts +6 -4
  344. package/dist/markdown/ast.d.ts.map +0 -1
  345. package/dist/markdown/ast.js +0 -17
  346. package/dist/markdown/ast.js.map +0 -1
  347. package/dist/markdown/parse.d.ts.map +0 -1
  348. package/dist/markdown/parse.js.map +0 -1
  349. package/dist/markdown/tags.d.ts.map +0 -1
  350. package/dist/markdown/tags.js.map +0 -1
  351. /package/dist/{markdown → internal/markdown}/parse.d.ts +0 -0
  352. /package/dist/{markdown → internal/markdown}/tags.d.ts +0 -0
  353. /package/dist/{markdown → internal/markdown}/tags.js +0 -0
  354. /package/src/{markdown → internal/markdown}/tags.ts +0 -0
@@ -0,0 +1,345 @@
1
+ // A textblock's inline content as the runs `<richtext>` lays out, and the map
2
+ // between the two coordinate systems that meet there.
3
+ //
4
+ // ProseMirror counts a position in UTF-16 units of document text, with every
5
+ // inline node that is not text counting one. `<richtext>` counts code points
6
+ // of the string it draws. The two differ exactly where the editor draws
7
+ // something the document does not hold one for one: an image drawn as its
8
+ // alt text, a hard break drawn as a line feed, a widget — the placeholder, a
9
+ // composition's preedit, a plugin's decoration — drawn with no document
10
+ // width at all, and the space an empty paragraph is drawn with so it has a
11
+ // line to put a caret on. `InlineMap` is the one bridge, total and monotonic
12
+ // both ways, the way `<CodeEditor>`'s tab map is (src/code-editor/doc.ts):
13
+ // getting it right once is the whole game.
14
+ //
15
+ // Pure: no React, no react-x11 — so every rule in it is asserted with no
16
+ // display (test/rich-text-editor-model.test.ts).
17
+ import type { Mark, Node as PMNode } from 'prosemirror-model';
18
+
19
+ import type { TextRun } from '../richtext/node.js';
20
+ import { codePointAtOffset, codeUnitOffsets } from '../internal/text.js';
21
+
22
+ /** A run's look, without its text. */
23
+ export type RunStyle = Omit<TextRun, 'text'>;
24
+
25
+ export type SegmentKind = 'text' | 'atom' | 'widget' | 'filler';
26
+
27
+ /** One stretch of the drawn string and the document offsets it stands for. */
28
+ export interface InlineSegment {
29
+ kind: SegmentKind;
30
+ /** Offsets inside the textblock's content. `to - from` is the text's
31
+ * length, 1 for an atom, 0 for a widget or the filler. */
32
+ from: number;
33
+ to: number;
34
+ /** Where it is in the drawn string, in UTF-16 units. */
35
+ dFrom: number;
36
+ dTo: number;
37
+ /** A widget's ProseMirror `side`: negative draws it before a caret at its
38
+ * position, zero or positive after. */
39
+ side: number;
40
+ }
41
+
42
+ export class InlineMap {
43
+ private offsets: number[] | null = null;
44
+
45
+ constructor(
46
+ /** The drawn string — the runs' texts, concatenated. */
47
+ readonly text: string,
48
+ /** The textblock's `content.size`. */
49
+ readonly size: number,
50
+ readonly segments: readonly InlineSegment[],
51
+ ) {}
52
+
53
+ private units(): number[] {
54
+ return (this.offsets ??= codeUnitOffsets(this.text));
55
+ }
56
+
57
+ /** How many code points are drawn. */
58
+ get length(): number {
59
+ return this.units().length - 1;
60
+ }
61
+
62
+ /** A code point index as a UTF-16 offset into `text`. */
63
+ unitOf(cp: number): number {
64
+ const units = this.units();
65
+ return units[Math.max(0, Math.min(Math.round(cp), units.length - 1))];
66
+ }
67
+
68
+ /** A UTF-16 offset as a code point index, rounded down to a character. */
69
+ cpOf(unit: number): number {
70
+ return codePointAtOffset(this.units(), unit);
71
+ }
72
+
73
+ /**
74
+ * Where a caret at document offset `pos` is drawn, as a code point index.
75
+ * Widgets at `pos` with a negative side are drawn before the caret and the
76
+ * rest after it — ProseMirror's rule, which is what puts the caret of an
77
+ * empty document before its placeholder.
78
+ */
79
+ toDisplay(pos: number): number {
80
+ const p = Math.max(0, Math.min(pos, this.size));
81
+ let d = 0;
82
+ for (const seg of this.segments) {
83
+ if (seg.kind === 'widget' || seg.kind === 'filler') {
84
+ if (seg.from < p) {
85
+ d = seg.dTo;
86
+ continue;
87
+ }
88
+ if (seg.from > p) break;
89
+ if (seg.kind === 'widget' && seg.side < 0) {
90
+ d = seg.dTo;
91
+ continue;
92
+ }
93
+ break;
94
+ }
95
+ if (seg.to <= p) {
96
+ d = seg.dTo;
97
+ continue;
98
+ }
99
+ if (seg.from >= p) break;
100
+ // strictly inside: only text is wider than one position
101
+ d = seg.dFrom + (p - seg.from);
102
+ break;
103
+ }
104
+ return this.cpOf(d);
105
+ }
106
+
107
+ /**
108
+ * The document offset a drawn code point stands for: inside text, the
109
+ * character's own offset; inside an atom's label, its nearer edge; inside
110
+ * a widget or the filler, the position it is drawn at.
111
+ */
112
+ toDoc(cp: number): number {
113
+ const d = this.unitOf(cp);
114
+ for (const seg of this.segments) {
115
+ if (d > seg.dTo) continue;
116
+ if (d === seg.dTo) return seg.to;
117
+ switch (seg.kind) {
118
+ case 'text':
119
+ return seg.from + (d - seg.dFrom);
120
+ case 'atom':
121
+ return d - seg.dFrom < (seg.dTo - seg.dFrom) / 2 ? seg.from : seg.to;
122
+ default:
123
+ return seg.from;
124
+ }
125
+ }
126
+ return this.size;
127
+ }
128
+ }
129
+
130
+ /** How a textblock's content looks: derived by the component from the
131
+ * theme, the node's type and the `markStyles` seam. */
132
+ export interface InlineLook {
133
+ /** The block's own text — family, size, weight, colour. */
134
+ base: RunStyle;
135
+ /** A mark's contribution, merged over what is under it in rank order. */
136
+ mark(mark: Mark, under: RunStyle): RunStyle;
137
+ /** What an inline leaf that is not text is drawn as. A hard break is
138
+ * `'\n'`; an image, its alt text in a chip. */
139
+ atom(node: PMNode): { text: string; style?: RunStyle };
140
+ /** A code block's text as runs — tokenized, when there is a language. */
141
+ code?(text: string): TextRun[];
142
+ }
143
+
144
+ /** An inline decoration, in offsets inside the textblock. */
145
+ export interface InlineDecoration {
146
+ from: number;
147
+ to: number;
148
+ style: RunStyle;
149
+ }
150
+
151
+ /** A widget: text drawn at a position with no document width. */
152
+ export interface InlineWidget {
153
+ pos: number;
154
+ side: number;
155
+ text: string;
156
+ style?: RunStyle;
157
+ }
158
+
159
+ interface Piece {
160
+ dFrom: number;
161
+ dTo: number;
162
+ style: RunStyle;
163
+ }
164
+
165
+ const STYLE_KEYS = [
166
+ 'family',
167
+ 'size',
168
+ 'weight',
169
+ 'style',
170
+ 'color',
171
+ 'bg',
172
+ 'bgFill',
173
+ 'underline',
174
+ 'underlineStyle',
175
+ 'strike',
176
+ 'href',
177
+ ] as const;
178
+
179
+ function sameStyle(a: RunStyle, b: RunStyle): boolean {
180
+ for (const key of STYLE_KEYS) if (a[key] !== b[key]) return false;
181
+ return true;
182
+ }
183
+
184
+ function overlay(
185
+ pieces: Piece[],
186
+ a: number,
187
+ b: number,
188
+ style: RunStyle,
189
+ ): Piece[] {
190
+ const out: Piece[] = [];
191
+ for (const p of pieces) {
192
+ if (p.dTo <= a || p.dFrom >= b) {
193
+ out.push(p);
194
+ continue;
195
+ }
196
+ if (p.dFrom < a) out.push({ dFrom: p.dFrom, dTo: a, style: p.style });
197
+ out.push({
198
+ dFrom: Math.max(p.dFrom, a),
199
+ dTo: Math.min(p.dTo, b),
200
+ style: { ...p.style, ...style },
201
+ });
202
+ if (p.dTo > b) out.push({ dFrom: b, dTo: p.dTo, style: p.style });
203
+ }
204
+ return out;
205
+ }
206
+
207
+ /**
208
+ * The runs for a textblock, and the map from them back to the document.
209
+ *
210
+ * Decorations style text and atoms and never widgets, which is
211
+ * ProseMirror's rule too: a widget is somebody else's drawing. Adjacent
212
+ * runs that come out looking the same are merged, so an ordinary paragraph
213
+ * is one run however many decorations touched it.
214
+ */
215
+ export function buildInline(
216
+ block: PMNode,
217
+ look: InlineLook,
218
+ decorations: readonly InlineDecoration[] = [],
219
+ widgets: readonly InlineWidget[] = [],
220
+ ): { runs: TextRun[]; map: InlineMap } {
221
+ const size = block.content.size;
222
+ const segments: InlineSegment[] = [];
223
+ let pieces: Piece[] = [];
224
+ let display = '';
225
+
226
+ const push = (
227
+ kind: SegmentKind,
228
+ from: number,
229
+ to: number,
230
+ text: string,
231
+ style: RunStyle,
232
+ side = 0,
233
+ ): void => {
234
+ const dFrom = display.length;
235
+ display += text;
236
+ segments.push({ kind, from, to, dFrom, dTo: display.length, side });
237
+ pieces.push({ dFrom, dTo: display.length, style });
238
+ };
239
+
240
+ const pending = widgets
241
+ .filter((w) => w.text !== '')
242
+ .map((w) => ({ ...w, pos: Math.max(0, Math.min(w.pos, size)) }))
243
+ .sort((a, b) => a.pos - b.pos || a.side - b.side);
244
+ let next = 0;
245
+ const widgetsUpTo = (pos: number): void => {
246
+ while (next < pending.length && pending[next].pos <= pos) {
247
+ const w = pending[next++];
248
+ push(
249
+ 'widget',
250
+ w.pos,
251
+ w.pos,
252
+ w.text,
253
+ { ...look.base, ...w.style },
254
+ w.side,
255
+ );
256
+ }
257
+ };
258
+
259
+ const styleOf = (marks: readonly Mark[]): RunStyle => {
260
+ let style = look.base;
261
+ for (const mark of marks) style = { ...style, ...look.mark(mark, style) };
262
+ return style;
263
+ };
264
+
265
+ const tokens =
266
+ look.code && block.type.spec.code && pending.length === 0
267
+ ? look.code(block.textContent)
268
+ : null;
269
+ if (tokens) {
270
+ // A code block holds text and nothing else, so its tokens are its
271
+ // pieces and the whole of it is one segment.
272
+ display = block.textContent;
273
+ if (display) {
274
+ segments.push({
275
+ kind: 'text',
276
+ from: 0,
277
+ to: size,
278
+ dFrom: 0,
279
+ dTo: display.length,
280
+ side: 0,
281
+ });
282
+ }
283
+ let d = 0;
284
+ for (const run of tokens) {
285
+ const { text, ...style } = run;
286
+ pieces.push({ dFrom: d, dTo: d + text.length, style });
287
+ d += text.length;
288
+ }
289
+ } else {
290
+ block.forEach((child, offset) => {
291
+ widgetsUpTo(offset);
292
+ if (child.isText) {
293
+ // a widget can sit inside a text node — a preedit mid-word — so the
294
+ // text is cut at every widget position it spans
295
+ const text = child.text ?? '';
296
+ const style = styleOf(child.marks);
297
+ const end = offset + child.nodeSize;
298
+ let at = offset;
299
+ while (next < pending.length && pending[next].pos < end) {
300
+ const cut = pending[next].pos;
301
+ if (cut > at)
302
+ push('text', at, cut, text.slice(at - offset, cut - offset), style);
303
+ at = Math.max(at, cut);
304
+ widgetsUpTo(cut);
305
+ }
306
+ if (end > at) push('text', at, end, text.slice(at - offset), style);
307
+ } else {
308
+ const atom = look.atom(child);
309
+ push('atom', offset, offset + 1, atom.text || '', {
310
+ ...styleOf(child.marks),
311
+ ...atom.style,
312
+ });
313
+ }
314
+ });
315
+ }
316
+ widgetsUpTo(size);
317
+
318
+ // A line needs something on it to have a height, and a caret needs a
319
+ // line: an empty block is drawn as one space, and so is the line a
320
+ // trailing hard break opens. Both map back to the position they follow.
321
+ if (display === '') push('filler', 0, 0, ' ', look.base);
322
+ else if (display.endsWith('\n')) push('filler', size, size, ' ', look.base);
323
+
324
+ for (const deco of decorations) {
325
+ for (const seg of segments) {
326
+ if (seg.kind !== 'text' && seg.kind !== 'atom') continue;
327
+ const from = Math.max(deco.from, seg.from);
328
+ const to = Math.min(deco.to, seg.to);
329
+ if (to <= from) continue;
330
+ const a = seg.kind === 'text' ? seg.dFrom + (from - seg.from) : seg.dFrom;
331
+ const b = seg.kind === 'text' ? seg.dFrom + (to - seg.from) : seg.dTo;
332
+ pieces = overlay(pieces, a, b, deco.style);
333
+ }
334
+ }
335
+
336
+ const runs: TextRun[] = [];
337
+ for (const p of pieces) {
338
+ if (p.dTo <= p.dFrom) continue;
339
+ const text = display.slice(p.dFrom, p.dTo);
340
+ const prev = runs[runs.length - 1];
341
+ if (prev && sameStyle(prev, p.style)) prev.text += text;
342
+ else runs.push({ ...p.style, text });
343
+ }
344
+ return { runs, map: new InlineMap(display, size, segments) };
345
+ }