@react-x11/components 0.9.0 → 0.11.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 (579) 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 +27 -24
  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/index.d.ts +1 -1
  24. package/dist/code-language/index.d.ts.map +1 -1
  25. package/dist/code-language/index.js +1 -1
  26. package/dist/code-language/index.js.map +1 -1
  27. package/dist/code-language/languages/glsl.d.ts.map +1 -1
  28. package/dist/code-language/languages/glsl.js +10 -2
  29. package/dist/code-language/languages/glsl.js.map +1 -1
  30. package/dist/code-language/languages/javascript.d.ts.map +1 -1
  31. package/dist/code-language/languages/javascript.js +18 -3
  32. package/dist/code-language/languages/javascript.js.map +1 -1
  33. package/dist/code-language/languages/json.d.ts.map +1 -1
  34. package/dist/code-language/languages/json.js +10 -2
  35. package/dist/code-language/languages/json.js.map +1 -1
  36. package/dist/code-language/languages/shell.d.ts.map +1 -1
  37. package/dist/code-language/languages/shell.js +10 -2
  38. package/dist/code-language/languages/shell.js.map +1 -1
  39. package/dist/code-language/languages/sql.d.ts.map +1 -1
  40. package/dist/code-language/languages/sql.js +20 -2
  41. package/dist/code-language/languages/sql.js.map +1 -1
  42. package/dist/code-language/runs.d.ts +31 -0
  43. package/dist/code-language/runs.d.ts.map +1 -1
  44. package/dist/code-language/runs.js +105 -0
  45. package/dist/code-language/runs.js.map +1 -1
  46. package/dist/code-language/stream.d.ts +22 -0
  47. package/dist/code-language/stream.d.ts.map +1 -1
  48. package/dist/code-language/stream.js +259 -9
  49. package/dist/code-language/stream.js.map +1 -1
  50. package/dist/code-language/types.d.ts +5 -4
  51. package/dist/code-language/types.d.ts.map +1 -1
  52. package/dist/codeblock/index.d.ts +26 -2
  53. package/dist/codeblock/index.d.ts.map +1 -1
  54. package/dist/codeblock/index.js +57 -4
  55. package/dist/codeblock/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 +262 -6
  115. package/dist/html/css/cascade.d.ts.map +1 -1
  116. package/dist/html/css/cascade.js +1373 -67
  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 +501 -15
  139. package/dist/html/css/style.d.ts.map +1 -1
  140. package/dist/html/css/style.js +3729 -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 +65 -16
  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 +3077 -219
  172. package/dist/html/layout/block.js.map +1 -1
  173. package/dist/html/layout/boxes.d.ts +367 -17
  174. package/dist/html/layout/boxes.d.ts.map +1 -1
  175. package/dist/html/layout/boxes.js +1742 -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 +154 -1
  205. package/dist/html/layout/inline.d.ts.map +1 -1
  206. package/dist/html/layout/inline.js +3598 -175
  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 +169 -4
  221. package/dist/html/node.d.ts.map +1 -1
  222. package/dist/html/node.js +1429 -137
  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 +3635 -107
  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 +442 -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 +1 -1
  245. package/dist/index.d.ts.map +1 -1
  246. package/dist/index.js.map +1 -1
  247. package/dist/internal/codelines.d.ts +42 -0
  248. package/dist/internal/codelines.d.ts.map +1 -0
  249. package/dist/internal/codelines.js +170 -0
  250. package/dist/internal/codelines.js.map +1 -0
  251. package/dist/internal/collate.d.ts +3 -0
  252. package/dist/internal/collate.d.ts.map +1 -0
  253. package/dist/internal/collate.js +11 -0
  254. package/dist/internal/collate.js.map +1 -0
  255. package/dist/internal/markdown/ast.d.ts +11 -0
  256. package/dist/internal/markdown/ast.d.ts.map +1 -1
  257. package/dist/internal/markdown/parse.d.ts.map +1 -1
  258. package/dist/internal/markdown/parse.js +109 -8
  259. package/dist/internal/markdown/parse.js.map +1 -1
  260. package/dist/internal/prewarm.d.ts +18 -0
  261. package/dist/internal/prewarm.d.ts.map +1 -0
  262. package/dist/internal/prewarm.js +42 -0
  263. package/dist/internal/prewarm.js.map +1 -0
  264. package/dist/internal/sdf.d.ts +20 -0
  265. package/dist/internal/sdf.d.ts.map +1 -0
  266. package/dist/internal/sdf.js +216 -0
  267. package/dist/internal/sdf.js.map +1 -0
  268. package/dist/internal/splice.d.ts +12 -0
  269. package/dist/internal/splice.d.ts.map +1 -0
  270. package/dist/internal/splice.js +23 -0
  271. package/dist/internal/splice.js.map +1 -0
  272. package/dist/internal/window.d.ts +12 -0
  273. package/dist/internal/window.d.ts.map +1 -1
  274. package/dist/internal/window.js +23 -6
  275. package/dist/internal/window.js.map +1 -1
  276. package/dist/maps/anchors.d.ts +6 -1
  277. package/dist/maps/anchors.d.ts.map +1 -1
  278. package/dist/maps/anchors.js +260 -1
  279. package/dist/maps/anchors.js.map +1 -1
  280. package/dist/maps/controller.d.ts +57 -0
  281. package/dist/maps/controller.d.ts.map +1 -1
  282. package/dist/maps/controller.js +97 -18
  283. package/dist/maps/controller.js.map +1 -1
  284. package/dist/maps/gl/buckets.d.ts +5 -1
  285. package/dist/maps/gl/buckets.d.ts.map +1 -1
  286. package/dist/maps/gl/buckets.js +5 -2
  287. package/dist/maps/gl/buckets.js.map +1 -1
  288. package/dist/maps/gl/build-worker.d.ts +2 -0
  289. package/dist/maps/gl/build-worker.d.ts.map +1 -1
  290. package/dist/maps/gl/build-worker.js +1 -1
  291. package/dist/maps/gl/build-worker.js.map +1 -1
  292. package/dist/maps/gl/cover.d.ts +23 -4
  293. package/dist/maps/gl/cover.d.ts.map +1 -1
  294. package/dist/maps/gl/cover.js +61 -48
  295. package/dist/maps/gl/cover.js.map +1 -1
  296. package/dist/maps/gl/placement.d.ts +21 -8
  297. package/dist/maps/gl/placement.d.ts.map +1 -1
  298. package/dist/maps/gl/placement.js +133 -58
  299. package/dist/maps/gl/placement.js.map +1 -1
  300. package/dist/maps/gl/renderer.d.ts +36 -4
  301. package/dist/maps/gl/renderer.d.ts.map +1 -1
  302. package/dist/maps/gl/renderer.js +81 -24
  303. package/dist/maps/gl/renderer.js.map +1 -1
  304. package/dist/maps/gl/shaders.d.ts +18 -17
  305. package/dist/maps/gl/shaders.d.ts.map +1 -1
  306. package/dist/maps/gl/shaders.js +34 -32
  307. package/dist/maps/gl/shaders.js.map +1 -1
  308. package/dist/maps/gl/store.d.ts +10 -0
  309. package/dist/maps/gl/store.d.ts.map +1 -1
  310. package/dist/maps/gl/store.js +47 -4
  311. package/dist/maps/gl/store.js.map +1 -1
  312. package/dist/maps/gl/text.d.ts +153 -24
  313. package/dist/maps/gl/text.d.ts.map +1 -1
  314. package/dist/maps/gl/text.js +379 -63
  315. package/dist/maps/gl/text.js.map +1 -1
  316. package/dist/maps/gl/view.d.ts +293 -2
  317. package/dist/maps/gl/view.d.ts.map +1 -1
  318. package/dist/maps/gl/view.js +317 -82
  319. package/dist/maps/gl/view.js.map +1 -1
  320. package/dist/maps/icons.d.ts +32 -0
  321. package/dist/maps/icons.d.ts.map +1 -0
  322. package/dist/maps/icons.js +151 -0
  323. package/dist/maps/icons.js.map +1 -0
  324. package/dist/maps/index.d.ts +2 -0
  325. package/dist/maps/index.d.ts.map +1 -1
  326. package/dist/maps/index.js +2 -0
  327. package/dist/maps/index.js.map +1 -1
  328. package/dist/maps/labels.d.ts +56 -4
  329. package/dist/maps/labels.d.ts.map +1 -1
  330. package/dist/maps/labels.js +213 -46
  331. package/dist/maps/labels.js.map +1 -1
  332. package/dist/maps/node.d.ts +17 -0
  333. package/dist/maps/node.d.ts.map +1 -1
  334. package/dist/maps/node.js +64 -30
  335. package/dist/maps/node.js.map +1 -1
  336. package/dist/maps/proj.d.ts +48 -0
  337. package/dist/maps/proj.d.ts.map +1 -1
  338. package/dist/maps/proj.js +73 -0
  339. package/dist/maps/proj.js.map +1 -1
  340. package/dist/maps/sources.d.ts +5 -3
  341. package/dist/maps/sources.d.ts.map +1 -1
  342. package/dist/maps/sources.js +5 -3
  343. package/dist/maps/sources.js.map +1 -1
  344. package/dist/maps/style.d.ts +35 -0
  345. package/dist/maps/style.d.ts.map +1 -1
  346. package/dist/maps/style.js.map +1 -1
  347. package/dist/maps/styles.d.ts +12 -0
  348. package/dist/maps/styles.d.ts.map +1 -1
  349. package/dist/maps/styles.js +120 -6
  350. package/dist/maps/styles.js.map +1 -1
  351. package/dist/maps/tiles.d.ts +31 -11
  352. package/dist/maps/tiles.d.ts.map +1 -1
  353. package/dist/maps/tiles.js +61 -27
  354. package/dist/maps/tiles.js.map +1 -1
  355. package/dist/maps/types.d.ts +28 -4
  356. package/dist/maps/types.d.ts.map +1 -1
  357. package/dist/markdown/index.d.ts.map +1 -1
  358. package/dist/markdown/index.js +209 -68
  359. package/dist/markdown/index.js.map +1 -1
  360. package/dist/markdown/spans.d.ts.map +1 -1
  361. package/dist/markdown/spans.js +6 -0
  362. package/dist/markdown/spans.js.map +1 -1
  363. package/dist/qml/containers.d.ts.map +1 -1
  364. package/dist/qml/containers.js +6 -1
  365. package/dist/qml/containers.js.map +1 -1
  366. package/dist/qml/interaction.d.ts.map +1 -1
  367. package/dist/qml/interaction.js +38 -5
  368. package/dist/qml/interaction.js.map +1 -1
  369. package/dist/qml/layouts.d.ts.map +1 -1
  370. package/dist/qml/layouts.js +21 -6
  371. package/dist/qml/layouts.js.map +1 -1
  372. package/dist/qml/qtquick.d.ts.map +1 -1
  373. package/dist/qml/qtquick.js +9 -2
  374. package/dist/qml/qtquick.js.map +1 -1
  375. package/dist/qml/react.d.ts.map +1 -1
  376. package/dist/qml/react.js +9 -7
  377. package/dist/qml/react.js.map +1 -1
  378. package/dist/reorder/clock.d.ts +7 -0
  379. package/dist/reorder/clock.d.ts.map +1 -0
  380. package/dist/reorder/clock.js +26 -0
  381. package/dist/reorder/clock.js.map +1 -0
  382. package/dist/reorder/index.d.ts +25 -3
  383. package/dist/reorder/index.d.ts.map +1 -1
  384. package/dist/reorder/index.js +64 -19
  385. package/dist/reorder/index.js.map +1 -1
  386. package/dist/rich-text-editor/index.d.ts +0 -11
  387. package/dist/rich-text-editor/index.d.ts.map +1 -1
  388. package/dist/rich-text-editor/index.js +38 -9
  389. package/dist/rich-text-editor/index.js.map +1 -1
  390. package/dist/rich-text-editor/keymap.d.ts.map +1 -1
  391. package/dist/rich-text-editor/keymap.js +2 -1
  392. package/dist/rich-text-editor/keymap.js.map +1 -1
  393. package/dist/rich-text-editor/keys.d.ts +17 -6
  394. package/dist/rich-text-editor/keys.d.ts.map +1 -1
  395. package/dist/rich-text-editor/keys.js +135 -26
  396. package/dist/rich-text-editor/keys.js.map +1 -1
  397. package/dist/rich-text-editor/markdown.d.ts.map +1 -1
  398. package/dist/rich-text-editor/markdown.js +30 -1
  399. package/dist/rich-text-editor/markdown.js.map +1 -1
  400. package/dist/rich-text-editor/marks.d.ts +9 -0
  401. package/dist/rich-text-editor/marks.d.ts.map +1 -0
  402. package/dist/rich-text-editor/marks.js +83 -0
  403. package/dist/rich-text-editor/marks.js.map +1 -0
  404. package/dist/rich-text-editor/render.d.ts.map +1 -1
  405. package/dist/rich-text-editor/render.js +28 -10
  406. package/dist/rich-text-editor/render.js.map +1 -1
  407. package/dist/rich-text-editor/replace.d.ts +13 -0
  408. package/dist/rich-text-editor/replace.d.ts.map +1 -0
  409. package/dist/rich-text-editor/replace.js +64 -0
  410. package/dist/rich-text-editor/replace.js.map +1 -0
  411. package/dist/rich-text-editor/toolbar.d.ts.map +1 -1
  412. package/dist/rich-text-editor/toolbar.js +1 -1
  413. package/dist/rich-text-editor/toolbar.js.map +1 -1
  414. package/dist/rich-text-editor/virtual.d.ts.map +1 -1
  415. package/dist/rich-text-editor/virtual.js +17 -0
  416. package/dist/rich-text-editor/virtual.js.map +1 -1
  417. package/dist/richtext/node.d.ts +46 -2
  418. package/dist/richtext/node.d.ts.map +1 -1
  419. package/dist/richtext/node.js +187 -4
  420. package/dist/richtext/node.js.map +1 -1
  421. package/dist/richtext/runs.d.ts +13 -8
  422. package/dist/richtext/runs.d.ts.map +1 -1
  423. package/dist/richtext/runs.js +18 -8
  424. package/dist/richtext/runs.js.map +1 -1
  425. package/dist/table/index.d.ts.map +1 -1
  426. package/dist/table/index.js +23 -0
  427. package/dist/table/index.js.map +1 -1
  428. package/dist/table/rows.d.ts +3 -2
  429. package/dist/table/rows.d.ts.map +1 -1
  430. package/dist/table/rows.js +20 -6
  431. package/dist/table/rows.js.map +1 -1
  432. package/dist/terminal/index.d.ts.map +1 -1
  433. package/dist/terminal/index.js +4 -0
  434. package/dist/terminal/index.js.map +1 -1
  435. package/dist/terminal/vt/pty.d.ts +13 -2
  436. package/dist/terminal/vt/pty.d.ts.map +1 -1
  437. package/dist/terminal/vt/pty.js +18 -3
  438. package/dist/terminal/vt/pty.js.map +1 -1
  439. package/dist/terminal-output/index.d.ts.map +1 -1
  440. package/dist/terminal-output/index.js +103 -23
  441. package/dist/terminal-output/index.js.map +1 -1
  442. package/dist/terminal-output/runs.d.ts +4 -1
  443. package/dist/terminal-output/runs.d.ts.map +1 -1
  444. package/dist/terminal-output/runs.js +5 -1
  445. package/dist/terminal-output/runs.js.map +1 -1
  446. package/dist/three/canvas.d.ts.map +1 -1
  447. package/dist/three/canvas.js +85 -7
  448. package/dist/three/canvas.js.map +1 -1
  449. package/dist/three/events.d.ts +22 -4
  450. package/dist/three/events.d.ts.map +1 -1
  451. package/dist/three/events.js +34 -4
  452. package/dist/three/events.js.map +1 -1
  453. package/dist/tree/index.d.ts.map +1 -1
  454. package/dist/tree/index.js +17 -0
  455. package/dist/tree/index.js.map +1 -1
  456. package/package.json +42 -33
  457. package/src/charts/node.ts +62 -26
  458. package/src/charts/render.ts +120 -30
  459. package/src/code/index.ts +36 -32
  460. package/src/code-editor/completion.ts +3 -2
  461. package/src/code-editor/index.ts +19 -0
  462. package/src/code-editor/node.ts +1574 -184
  463. package/src/code-language/index.ts +1 -1
  464. package/src/code-language/languages/glsl.ts +12 -2
  465. package/src/code-language/languages/javascript.ts +21 -4
  466. package/src/code-language/languages/json.ts +12 -2
  467. package/src/code-language/languages/shell.ts +12 -2
  468. package/src/code-language/languages/sql.ts +22 -2
  469. package/src/code-language/runs.ts +111 -1
  470. package/src/code-language/stream.ts +257 -17
  471. package/src/code-language/types.ts +5 -4
  472. package/src/codeblock/index.ts +68 -4
  473. package/src/flow/draw.ts +167 -41
  474. package/src/flow/gl/color.ts +85 -0
  475. package/src/flow/gl/index.ts +342 -0
  476. package/src/flow/gl/pack.ts +585 -0
  477. package/src/flow/gl/renderer.ts +679 -0
  478. package/src/flow/gl/shaders.ts +371 -0
  479. package/src/flow/gl/text.ts +1295 -0
  480. package/src/flow/index.ts +794 -67
  481. package/src/flow/node.ts +2496 -1256
  482. package/src/flow/paint.ts +511 -0
  483. package/src/flow/paths.ts +80 -15
  484. package/src/flow/scene.ts +2199 -0
  485. package/src/flow/types.ts +113 -1
  486. package/src/html/controls.ts +73 -2
  487. package/src/html/css/calc.ts +385 -0
  488. package/src/html/css/cascade.ts +1481 -62
  489. package/src/html/css/color.ts +755 -0
  490. package/src/html/css/content.ts +417 -0
  491. package/src/html/css/counter-styles.ts +973 -0
  492. package/src/html/css/decode.ts +130 -0
  493. package/src/html/css/parse.ts +1514 -160
  494. package/src/html/css/style.ts +4131 -223
  495. package/src/html/css/ua.ts +66 -17
  496. package/src/html/css/values.ts +150 -50
  497. package/src/html/css/vars.ts +348 -0
  498. package/src/html/dom.ts +284 -17
  499. package/src/html/fonts.ts +641 -0
  500. package/src/html/gif.ts +233 -0
  501. package/src/html/index.ts +180 -20
  502. package/src/html/layout/block.ts +3560 -208
  503. package/src/html/layout/boxes.ts +2141 -190
  504. package/src/html/layout/cache.ts +289 -0
  505. package/src/html/layout/collapse.ts +317 -0
  506. package/src/html/layout/css-grid.ts +1063 -0
  507. package/src/html/layout/flex.ts +1115 -106
  508. package/src/html/layout/floats.ts +128 -14
  509. package/src/html/layout/grid-lines.ts +141 -0
  510. package/src/html/layout/grid.ts +181 -0
  511. package/src/html/layout/inline.ts +4187 -192
  512. package/src/html/layout/shaping.ts +140 -0
  513. package/src/html/layout/table.ts +696 -186
  514. package/src/html/layout/tracks.ts +437 -0
  515. package/src/html/node.ts +1585 -156
  516. package/src/html/paint.ts +4582 -267
  517. package/src/html/resources.ts +161 -50
  518. package/src/html/surfaces.ts +81 -0
  519. package/src/html/svg.ts +504 -0
  520. package/src/html/url.ts +86 -0
  521. package/src/index.ts +2 -0
  522. package/src/internal/codelines.ts +200 -0
  523. package/src/internal/collate.ts +12 -0
  524. package/src/internal/markdown/ast.ts +11 -0
  525. package/src/internal/markdown/parse.ts +154 -11
  526. package/src/internal/prewarm.ts +45 -0
  527. package/src/internal/sdf.ts +227 -0
  528. package/src/internal/splice.ts +25 -0
  529. package/src/internal/window.ts +36 -5
  530. package/src/maps/anchors.ts +307 -1
  531. package/src/maps/controller.ts +116 -31
  532. package/src/maps/gl/buckets.ts +5 -1
  533. package/src/maps/gl/build-worker.ts +13 -2
  534. package/src/maps/gl/cover.ts +79 -44
  535. package/src/maps/gl/placement.ts +221 -69
  536. package/src/maps/gl/renderer.ts +104 -20
  537. package/src/maps/gl/shaders.ts +35 -32
  538. package/src/maps/gl/store.ts +66 -17
  539. package/src/maps/gl/text.ts +444 -71
  540. package/src/maps/gl/view.ts +361 -96
  541. package/src/maps/icons.ts +183 -0
  542. package/src/maps/index.ts +4 -0
  543. package/src/maps/labels.ts +269 -49
  544. package/src/maps/node.ts +82 -49
  545. package/src/maps/proj.ts +87 -0
  546. package/src/maps/sources.ts +5 -3
  547. package/src/maps/style.ts +32 -0
  548. package/src/maps/styles.ts +215 -4
  549. package/src/maps/tiles.ts +64 -31
  550. package/src/maps/types.ts +28 -4
  551. package/src/markdown/index.ts +293 -92
  552. package/src/markdown/spans.ts +5 -0
  553. package/src/qml/containers.tsx +6 -1
  554. package/src/qml/interaction.tsx +42 -5
  555. package/src/qml/layouts.tsx +21 -6
  556. package/src/qml/qtquick.tsx +9 -2
  557. package/src/qml/react.tsx +7 -5
  558. package/src/reorder/clock.ts +27 -0
  559. package/src/reorder/index.ts +100 -27
  560. package/src/rich-text-editor/index.ts +37 -12
  561. package/src/rich-text-editor/keymap.ts +1 -1
  562. package/src/rich-text-editor/keys.ts +135 -26
  563. package/src/rich-text-editor/markdown.ts +36 -1
  564. package/src/rich-text-editor/marks.ts +101 -0
  565. package/src/rich-text-editor/render.ts +49 -12
  566. package/src/rich-text-editor/replace.ts +85 -0
  567. package/src/rich-text-editor/toolbar.ts +1 -1
  568. package/src/rich-text-editor/virtual.ts +25 -0
  569. package/src/richtext/node.ts +235 -14
  570. package/src/richtext/runs.ts +23 -12
  571. package/src/table/index.ts +29 -0
  572. package/src/table/rows.ts +18 -8
  573. package/src/terminal/index.ts +4 -0
  574. package/src/terminal/vt/pty.ts +16 -2
  575. package/src/terminal-output/index.ts +129 -31
  576. package/src/terminal-output/runs.ts +16 -2
  577. package/src/three/canvas.ts +102 -8
  578. package/src/three/events.ts +49 -9
  579. package/src/tree/index.ts +19 -0
@@ -23,12 +23,34 @@
23
23
  // the leaf shape costs is stretch — a stretched item's box grows but its
24
24
  // contents are not re-laid at the stretched height.
25
25
  import { Yoga, layoutLoaded } from 'react-x11/yoga';
26
- import type { Node as YogaNode } from 'react-x11/yoga';
26
+ import type { Config as YogaConfig, Node as YogaNode } from 'react-x11/yoga';
27
27
 
28
- import { AUTO, isPct, resolveOrNull } from '../css/values.js';
29
- import type { ComputedStyle } from '../css/style.js';
30
- import { Box } from './boxes.js';
31
- import { moveTo, resolveEdges } from './block.js';
28
+ import { AUTO, gapOf, isPct, resolve, resolveOrNull } from '../css/values.js';
29
+ import { scrolls } from '../css/style.js';
30
+ import type { ComputedStyle, ContentSize } from '../css/style.js';
31
+ import { Box, PAINT_ORDER, isBlank } from './boxes.js';
32
+ import {
33
+ FLEXED_HEIGHT,
34
+ MIN_CONTENT_PROBE,
35
+ clampHeight,
36
+ clampWidth,
37
+ contentSizedWidth,
38
+ exactMinContent,
39
+ intrinsicWidth,
40
+ measureIntrinsicWidth,
41
+ moveTo,
42
+ percentBaseInside,
43
+ percentHeightsIn,
44
+ positionOutOfFlow,
45
+ replacedRatio,
46
+ transferredHeight,
47
+ transferredWidth,
48
+ heightFromWidth,
49
+ widthFromHeight,
50
+ resolveEdges,
51
+ } from './block.js';
52
+ import { layoutGrid } from './css-grid.js';
53
+ import { firstBaselineIn } from './inline.js';
32
54
  import type { LayoutContext } from './block.js';
33
55
 
34
56
  // `react-x11/yoga` re-exports yoga's own declarations, so the node shape and
@@ -37,6 +59,22 @@ import type { LayoutContext } from './block.js';
37
59
  // `react-x11/ntk` (a deliberately loose record).
38
60
  const Y = Yoga;
39
61
 
62
+ /**
63
+ * The config this engine's flex trees are made in: off the pixel grid, as
64
+ * the rest of its layout is, since its paint snaps each box's edges. On
65
+ * the grid, Yoga rounds a measured item's size up and the next item's
66
+ * start to the nearest, and two items that met at a fraction overlapped
67
+ * by a pixel. Its own, not core's, whose grid its own layout keeps.
68
+ */
69
+ let config: YogaConfig | null = null;
70
+ function flexConfig(): YogaConfig {
71
+ if (config === null) {
72
+ config = Y.Config.create();
73
+ config.setPointScaleFactor(0);
74
+ }
75
+ return config;
76
+ }
77
+
40
78
  /**
41
79
  * Lay out a flex container's children. Returns the content height.
42
80
  *
@@ -54,52 +92,395 @@ export function layoutFlex(
54
92
  ctx: LayoutContext,
55
93
  contentWidth: number,
56
94
  ): number {
95
+ // a grid container is one of these to the box tree, and laid out apart
96
+ if (box.style.grid) return layoutGrid(box, ctx, contentWidth);
57
97
  if (!layoutLoaded()) return layoutAsBlockFallback(box, ctx, contentWidth);
98
+ // Each flex box in a flex item runs its Yoga pass inside the measure of
99
+ // the one around it, and Yoga's own stack runs out at about a hundred and
100
+ // fifty of them — a `RuntimeError` out of the layout. Past this many, one
101
+ // is laid out as blocks: the markup of a broken page, not of a design.
102
+ const depth = ctx.flexDepth ?? 0;
103
+ if (depth >= FLEX_DEPTH) return layoutAsBlockFallback(box, ctx, contentWidth);
58
104
 
59
- const root = Y.Node.create();
105
+ const root = Y.Node.create(flexConfig());
60
106
  applyContainer(root, box.style);
61
- root.setWidth(contentWidth);
62
- const height = resolveOrNull(box.style.height, NaN);
107
+ // the gaps, a percentage of the content box's size along them where it
108
+ // has one, and else of nothing (CSS Box Alignment 3, 8.3)
109
+ const rowGap = gapOf(box.style.rowGap, percentBaseInside(box));
110
+ const columnGap = gapOf(box.style.columnGap, contentWidth);
111
+ if (rowGap) root.setGap(Y.GUTTER_ROW, rowGap);
112
+ if (columnGap) root.setGap(Y.GUTTER_COLUMN, columnGap);
113
+ // Laid out at no width limit — a flex item's max-content measured, a
114
+ // table column's — the container is as wide as its content, which Yoga
115
+ // works out from an `auto` width. Handed an infinite one, it took it for
116
+ // a width, grew a `flex: 1` item to fill it, placed its text at 1.7e38,
117
+ // and the measure that asked came back vast: a row beside such an item
118
+ // was squeezed to wrap every word.
119
+ const bounded = Number.isFinite(contentWidth);
120
+ if (bounded) root.setWidth(contentWidth);
121
+ // The content box's height, where it is definite: a length or a
122
+ // percentage that resolves, or what `aspect-ratio` makes of the width —
123
+ // less the padding and borders a `border-box` height holds, which put
124
+ // `h-16 py-2 items-center` eight pixels low. Where it is not, the limits
125
+ // on it, so a column `min-h-screen` gives its `flex-1` the rest.
126
+ const definite = percentBaseInside(box);
127
+ const height = Number.isFinite(definite) ? definite : null;
63
128
  if (height !== null) root.setHeight(height);
64
- else root.setHeightAuto();
129
+ else {
130
+ root.setHeightAuto();
131
+ const extra = box.verticalExtra;
132
+ const min = clampHeight(box, extra) - extra;
133
+ if (min > 0) root.setMinHeight(min);
134
+ const max = clampHeight(box, Infinity) - extra;
135
+ if (Number.isFinite(max)) root.setMaxHeight(Math.max(0, max));
136
+ }
65
137
 
66
- const items: { box: Box; node: YogaNode }[] = [];
138
+ const flowing: Box[] = [];
139
+ let reordered = false;
67
140
  for (const child of box.children) {
68
- if (child.kind === 'text' && !child.text.trim()) continue;
141
+ if (child.kind === 'text' && isBlank(child.text)) continue;
69
142
  if (child.outOfFlow) {
70
- ctx.positioned.push({ box: child, containing: box });
143
+ positionOutOfFlow(child, box, ctx, true);
71
144
  continue;
72
145
  }
73
- const node = Y.Node.create();
146
+ if (child.style.order !== 0) reordered = true;
147
+ flowing.push(child);
148
+ }
149
+ // in `order`, and where two have the same, in the document's (CSS
150
+ // Flexbox 5.4): Yoga places its children in the order they were given,
151
+ // and paint paints them in it
152
+ if (reordered) {
153
+ flowing.sort((a, b) => a.style.order - b.style.order);
154
+ PAINT_ORDER.set(
155
+ box,
156
+ [...box.children].sort((a, b) => orderOf(a) - orderOf(b)),
157
+ );
158
+ } else PAINT_ORDER.delete(box);
159
+
160
+ const items: { box: Box; node: YogaNode; laid: Laid }[] = [];
161
+ for (const child of flowing) {
162
+ const node = Y.Node.create(flexConfig());
74
163
  resolveEdges(child, contentWidth);
75
- applyItem(node, child, ctx, contentWidth);
164
+ const laid: Laid = { width: NaN, height: NaN, set: NaN, stretch: NaN };
165
+ applyItem(node, child, ctx, contentWidth, laid, height !== null);
76
166
  root.insertChild(node, items.length);
77
- items.push({ box: child, node });
167
+ items.push({ box: child, node, laid });
168
+ }
169
+
170
+ const direction =
171
+ box.style.direction === 'rtl' ? Y.DIRECTION_RTL : Y.DIRECTION_LTR;
172
+ const row = box.style.flexDirection.startsWith('row');
173
+ const calculate = (): void =>
174
+ root.calculateLayout(
175
+ bounded ? contentWidth : Number.NaN,
176
+ height ?? Number.NaN,
177
+ direction,
178
+ );
179
+ ctx.flexDepth = depth + 1;
180
+ try {
181
+ calculate();
182
+ // an item Yoga shrank under what its content comes to is kept to it,
183
+ // and the row is laid out again (`autoMinimums`) — which may shrink
184
+ // another under its own, a few times over at most
185
+ for (
186
+ let pass = 0;
187
+ pass < 4 && autoMinimums(items, row, ctx, contentWidth);
188
+ pass += 1
189
+ ) {
190
+ calculate();
191
+ }
192
+ } finally {
193
+ ctx.flexDepth = depth;
78
194
  }
79
195
 
80
- root.calculateLayout(
81
- contentWidth,
82
- height ?? Number.NaN,
83
- box.style.direction === 'rtl' ? Y.DIRECTION_RTL : Y.DIRECTION_LTR,
196
+ // Yoga aligns the lines of a box that wraps, or aligns by baselines, in
197
+ // one pass of its own, which drops a margin (`lineMarginFix`)
198
+ const baselines =
199
+ box.style.alignItems === 'baseline' ||
200
+ items.some(({ box: child }) => child.style.alignSelf === 'baseline');
201
+ let bottom = placeItems(
202
+ box,
203
+ ctx,
204
+ items,
205
+ row,
206
+ height,
207
+ box.style.flexWrap === 'wrap' || baselines,
84
208
  );
209
+ // Items aligned by their baselines, which Yoga cannot see, are aligned
210
+ // with their baselines known (`baselineLines`)
211
+ // by the flex layout again, set at their lines' starts with the margins
212
+ // that put their baselines together, which makes each line as tall as
213
+ // that does
214
+ const lines = row && baselines ? baselineLines(box.style, items) : null;
215
+ if (lines) {
216
+ // every one of them, and the box's own `baseline` too, which is what
217
+ // takes Yoga down that pass
218
+ const started = new Set<Box>();
219
+ for (const line of lines) {
220
+ line.forEach(({ box: child, node }, i) => {
221
+ node.setAlignSelf(Y.ALIGN_FLEX_START);
222
+ node.setMargin(Y.EDGE_TOP, line.margins[i]);
223
+ started.add(child);
224
+ });
225
+ }
226
+ if (box.style.alignItems === 'baseline') {
227
+ root.setAlignItems(Y.ALIGN_FLEX_START);
228
+ }
229
+ ctx.flexDepth = depth + 1;
230
+ try {
231
+ calculate();
232
+ } finally {
233
+ ctx.flexDepth = depth;
234
+ }
235
+ bottom = placeItems(
236
+ box,
237
+ ctx,
238
+ items,
239
+ row,
240
+ height,
241
+ box.style.flexWrap === 'wrap',
242
+ started,
243
+ );
244
+ }
245
+
246
+ // A replaced item with a ratio that is stretched across a line of a
247
+ // definite size takes its flex base size from the stretched one through
248
+ // the ratio (CSS Flexbox 9.2 and 9.8), where Yoga took its natural size —
249
+ // which Yoga's own `aspectRatio` would do for its border box, where a
250
+ // replaced element's ratio is its content box's. Laid out again with it.
251
+ // where the line's cross size is definite: one line, in a box of that
252
+ // size of its own (9.8)
253
+ const definiteCross =
254
+ box.style.flexWrap === 'nowrap' && (row ? height !== null : bounded);
255
+ if (definiteCross && keepRatios(box, items, row)) {
256
+ ctx.flexDepth = depth + 1;
257
+ try {
258
+ calculate();
259
+ } finally {
260
+ ctx.flexDepth = depth;
261
+ }
262
+ bottom = placeItems(
263
+ box,
264
+ ctx,
265
+ items,
266
+ row,
267
+ height,
268
+ box.style.flexWrap === 'wrap' || baselines,
269
+ );
270
+ }
271
+
272
+ const contentHeight = root.getComputedHeight();
273
+ root.freeRecursive();
274
+ return Math.max(contentHeight, bottom - box.contentY);
275
+ }
276
+
277
+ /** Give each replaced item with a ratio that its line stretched the flex
278
+ * base size the ratio makes of the stretched size; whether any changed. */
279
+ function keepRatios(
280
+ container: Box,
281
+ items: readonly { box: Box; node: YogaNode }[],
282
+ row: boolean,
283
+ ): boolean {
284
+ let changed = false;
285
+ for (const { box, node } of items) {
286
+ if (box.kind !== 'replaced' || !stretches(box, container.style, row)) {
287
+ continue;
288
+ }
289
+ const style = box.style;
290
+ if ((row ? style.width : style.height) !== AUTO) continue;
291
+ const ratio = replacedRatio(box);
292
+ if (!(ratio > 0)) continue;
293
+ const basis = row
294
+ ? Math.max(0, node.getComputedHeight() - box.verticalExtra) * ratio +
295
+ box.horizontalExtra
296
+ : Math.max(0, node.getComputedWidth() - box.horizontalExtra) / ratio +
297
+ box.verticalExtra;
298
+ const main = row ? node.getComputedWidth() : node.getComputedHeight();
299
+ if (Math.abs(basis - main) < 0.5) continue;
300
+ node.setFlexBasis(basis);
301
+ changed = true;
302
+ }
303
+ return changed;
304
+ }
305
+
306
+ /**
307
+ * A replaced row item's automatic least width, its border box (CSS
308
+ * Flexbox 4.5): its natural width, or through its ratio what a height of
309
+ * its own makes of it, and no more than a width of its own, within its
310
+ * `max-width`. Null where it has neither a natural width nor a ratio to
311
+ * take one through.
312
+ */
313
+ function replacedMinimum(box: Box, containingWidth: number): number | null {
314
+ const style = box.style;
315
+ const own = box.intrinsic;
316
+ const ratio = replacedRatio(box);
317
+ const hx = style.boxSizing === 'border-box' ? box.horizontalExtra : 0;
318
+ const vx = style.boxSizing === 'border-box' ? box.verticalExtra : 0;
319
+ const base = box.percentHeightBase;
320
+ const height = resolveOrNull(style.height, base);
321
+ let content: number | null =
322
+ height !== null && ratio > 0
323
+ ? Math.max(0, height - vx) * ratio
324
+ : own && !(own.missing & 1)
325
+ ? own.width
326
+ : null;
327
+ if (content === null) return null;
328
+ // and through its ratio, within its least and greatest heights
329
+ if (ratio > 0) {
330
+ const least =
331
+ style.minHeight === AUTO ? null : resolveOrNull(style.minHeight, base);
332
+ if (least !== null)
333
+ content = Math.max(content, Math.max(0, least - vx) * ratio);
334
+ const most =
335
+ style.maxHeight === 'none' ? null : resolveOrNull(style.maxHeight, base);
336
+ if (most !== null)
337
+ content = Math.min(content, Math.max(0, most - vx) * ratio);
338
+ }
339
+ const width = resolveOrNull(style.width, containingWidth);
340
+ if (width !== null) content = Math.min(content, Math.max(0, width - hx));
341
+ if (style.maxWidth !== 'none') {
342
+ const most = resolveOrNull(style.maxWidth, containingWidth);
343
+ if (most !== null) content = Math.min(content, Math.max(0, most - hx));
344
+ }
345
+ return content + box.horizontalExtra;
346
+ }
85
347
 
348
+ /** A row item's `flex-basis: content`, its border box: its max-content
349
+ * width, or a replaced element's natural one. */
350
+ function contentBasis(
351
+ box: Box,
352
+ ctx: LayoutContext,
353
+ containingWidth: number,
354
+ ): number {
355
+ if (box.kind === 'replaced') {
356
+ const own = box.intrinsic;
357
+ if (own && !(own.missing & 1)) return own.width + box.horizontalExtra;
358
+ }
359
+ // a ratio's is a definite height through it, whatever the width says
360
+ const fromRatio = ratioBasis(box);
361
+ if (fromRatio !== null) return fromRatio;
362
+ const room = Math.max(0, containingWidth - box.marginLeft - box.marginRight);
363
+ return contentSizedWidth(box, ctx, 'max-content', room, containingWidth);
364
+ }
365
+
366
+ /**
367
+ * The border-box width a row item's ratio makes of a definite height: its
368
+ * own, a length or a percentage of a flex box of a definite height, or the
369
+ * one line of such a flex box that stretches it across (CSS Flexbox 9.2,
370
+ * 9.4). Null where it has no ratio or no such height.
371
+ */
372
+ function ratioBasis(box: Box): number | null {
373
+ const style = box.style;
374
+ const aspect = style.aspectRatio;
375
+ const flex = box.parent;
376
+ if (!aspect || box.kind === 'replaced' || !flex) return null;
377
+ const room = percentBaseInside(flex);
378
+ let height = resolveOrNull(style.height, room);
379
+ let outer: number;
380
+ if (height !== null) {
381
+ outer =
382
+ style.boxSizing === 'border-box'
383
+ ? Math.max(height, box.verticalExtra)
384
+ : height + box.verticalExtra;
385
+ } else {
386
+ const align =
387
+ style.alignSelf === AUTO ? flex.style.alignItems : style.alignSelf;
388
+ if (
389
+ align !== 'stretch' ||
390
+ flex.style.flexWrap !== 'nowrap' ||
391
+ !Number.isFinite(room) ||
392
+ style.marginTop === AUTO ||
393
+ style.marginBottom === AUTO
394
+ ) {
395
+ return null;
396
+ }
397
+ height = room - box.marginTop - box.marginBottom;
398
+ outer = Math.max(height, box.verticalExtra);
399
+ }
400
+ return widthFromHeight(box, clampHeight(box, outer));
401
+ }
402
+
403
+ /** A column item's flex base size where it has a ratio and a width of
404
+ * its own, its border box: the width, within its limits, through the
405
+ * ratio. */
406
+ function ratioHeightBasis(box: Box, containingWidth: number): number | null {
407
+ const style = box.style;
408
+ if (style.width === AUTO || style.widthKeyword || box.kind === 'replaced') {
409
+ return null;
410
+ }
411
+ const set = resolveOrNull(style.width, containingWidth);
412
+ if (set === null) return null;
413
+ const outer =
414
+ style.boxSizing === 'border-box'
415
+ ? Math.max(set, box.horizontalExtra)
416
+ : set + box.horizontalExtra;
417
+ return heightFromWidth(box, clampWidth(box, outer, containingWidth));
418
+ }
419
+
420
+ /** A child's `order`, which an absolutely positioned one takes as 0 when
421
+ * it is painted among the items. */
422
+ function orderOf(box: Box): number {
423
+ return box.outOfFlow || box.kind === 'text' ? 0 : box.style.order;
424
+ }
425
+
426
+ /** Lay each item out where the flex layout put it, at the size it gave it,
427
+ * and answer where the lowest ends. `started` are items set at their
428
+ * lines' starts whatever their own alignment says (`baselineLines`). */
429
+ function placeItems(
430
+ box: Box,
431
+ ctx: LayoutContext,
432
+ items: readonly { box: Box; node: YogaNode; laid: Laid }[],
433
+ row: boolean,
434
+ height: number | null,
435
+ /** Whether Yoga aligned the lines in its pass that drops a margin. */
436
+ lined: boolean,
437
+ started?: ReadonlySet<Box>,
438
+ ): number {
86
439
  let bottom = 0;
87
- for (const { box: child, node } of items) {
88
- const left = box.contentX + node.getComputedLeft();
89
- const top = box.contentY + node.getComputedTop();
90
- const width = node.getComputedWidth();
440
+ for (const { box: child, node, laid } of items) {
441
+ const across = lined
442
+ ? lineMarginFix(box.style, child, node, row, started?.has(child))
443
+ : 0;
444
+ const left = box.contentX + node.getComputedLeft() + (row ? 0 : across);
445
+ const top = box.contentY + node.getComputedTop() + (row ? across : 0);
446
+ const width = meant(
447
+ node.getComputedWidth(),
448
+ laid.set,
449
+ laid.stretch,
450
+ laid.width,
451
+ );
91
452
  const itemHeight = node.getComputedHeight();
92
453
  // The item is laid out again at the width the flex pass settled on: the
93
454
  // measure function answered a question, and the answer is not a layout —
94
455
  // its line breaks were computed against a width that may have changed
95
- // when a sibling grew.
96
- layoutItemAt(child, ctx, left, top, width, itemHeight);
456
+ // when a sibling grew. Unless the last answer was at that width, which
457
+ // is a layout the item still has (Yoga's widths are float32s).
458
+ // Its height is definite where the flex layout made it so (CSS Flexbox
459
+ // 9.8): stretched across a row's line, or flexed in a column of a
460
+ // height of its own. What is in it takes its percentages of that —
461
+ // the `h-full` in a stretched sidebar — where they had nothing to be
462
+ // of, and the item is laid out again for them.
463
+ const definite = row
464
+ ? stretches(child, box.style)
465
+ ? itemHeight
466
+ : null
467
+ : height !== null
468
+ ? itemHeight
469
+ : null;
470
+ layoutItemAt(
471
+ child,
472
+ ctx,
473
+ left,
474
+ top,
475
+ width,
476
+ itemHeight,
477
+ laid,
478
+ definite,
479
+ !row,
480
+ );
97
481
  bottom = Math.max(bottom, top + child.height);
98
482
  }
99
-
100
- const contentHeight = root.getComputedHeight();
101
- root.freeRecursive();
102
- return Math.max(contentHeight, bottom - box.contentY);
483
+ return bottom;
103
484
  }
104
485
 
105
486
  function layoutItemAt(
@@ -109,34 +490,66 @@ function layoutItemAt(
109
490
  y: number,
110
491
  width: number,
111
492
  height: number,
493
+ laid: Laid,
494
+ /** Its border box's height where the flex layout made it definite. */
495
+ definite: number | null,
496
+ /** Whether its height is the one the flex layout gave it, in a column,
497
+ * whatever its own says: flexed, it is shrunk as well as grown. */
498
+ column = false,
112
499
  ): void {
113
- if (box.kind === 'text' || box.kind === 'break') {
500
+ // a replaced item is the size the flex layout made it — flexed,
501
+ // stretched — which its natural size was only the start of
502
+ if (box.kind === 'text' || box.kind === 'break' || box.kind === 'replaced') {
114
503
  box.x = x;
115
504
  box.y = y;
116
505
  box.width = width;
117
506
  box.height = height;
118
507
  return;
119
508
  }
509
+ const inner =
510
+ definite === null || !percentHeightsIn(box)
511
+ ? null
512
+ : Math.max(0, definite - box.verticalExtra);
513
+ if (inner !== null && !Object.is(inner, percentBaseInside(box))) {
514
+ FLEXED_HEIGHT.set(box, inner);
515
+ try {
516
+ ctx.layoutSubtree(box, width);
517
+ } finally {
518
+ FLEXED_HEIGHT.delete(box);
519
+ }
520
+ }
120
521
  // `measureBox` lays the box out at (0, 0); re-running it at the final width
121
522
  // and then moving it is one pass, not two, because the second call is the
122
- // one whose result is kept.
123
- ctx.layoutSubtree(box, width);
523
+ // one whose result is kept — or no pass, where the last measure was at
524
+ // this width. An item Yoga never measured has none, NaN, and is laid out.
525
+ else if (Math.abs(laid.width - width) <= 0.01) box.height = laid.height;
526
+ else ctx.layoutSubtree(box, width);
124
527
  // A stretched item is taller than its content, and the box has to say so
125
- // or its background stops short of the row.
126
- if (height > box.height) box.height = height;
528
+ // or its background stops short of the row — and it is no taller than its
529
+ // line where its content is, or than what its ratio makes of its width:
530
+ // its height is the line's (CSS Flexbox 9.4, step 11).
531
+ if (height > box.height || column || definite !== null) box.height = height;
127
532
  moveTo(box, x, y);
128
533
  }
129
534
 
535
+ // What a new Yoga node already is is not said again. A call into the
536
+ // engine costs more than the arithmetic it asks for, and a Tailwind page is
537
+ // a flex box in every list item: saying every default made the calls into
538
+ // Yoga two fifths of laying one out. A node's defaults are column, no wrap,
539
+ // start, stretch, start (for its lines), no growing, no shrinking, `auto`
540
+ // basis and size, and nothing on any edge.
541
+
130
542
  function applyContainer(node: YogaNode, style: ComputedStyle): void {
131
- node.setFlexDirection(
132
- FLEX_DIRECTION[style.flexDirection] ?? Y.FLEX_DIRECTION_ROW,
133
- );
134
- node.setFlexWrap(WRAP[style.flexWrap] ?? Y.WRAP_NO_WRAP);
135
- node.setJustifyContent(JUSTIFY[style.justifyContent] ?? Y.JUSTIFY_FLEX_START);
136
- node.setAlignItems(ALIGN[style.alignItems] ?? Y.ALIGN_STRETCH);
137
- node.setAlignContent(ALIGN[style.alignContent] ?? Y.ALIGN_STRETCH);
138
- if (style.rowGap) node.setGap(Y.GUTTER_ROW, style.rowGap);
139
- if (style.columnGap) node.setGap(Y.GUTTER_COLUMN, style.columnGap);
543
+ const direction = FLEX_DIRECTION[style.flexDirection] ?? Y.FLEX_DIRECTION_ROW;
544
+ if (direction !== Y.FLEX_DIRECTION_COLUMN) node.setFlexDirection(direction);
545
+ const wrap = WRAP[style.flexWrap] ?? Y.WRAP_NO_WRAP;
546
+ if (wrap !== Y.WRAP_NO_WRAP) node.setFlexWrap(wrap);
547
+ const justify = JUSTIFY[mainJustify(style)] ?? Y.JUSTIFY_FLEX_START;
548
+ if (justify !== Y.JUSTIFY_FLEX_START) node.setJustifyContent(justify);
549
+ const items = ALIGN[style.alignItems] ?? Y.ALIGN_STRETCH;
550
+ if (items !== Y.ALIGN_STRETCH) node.setAlignItems(items);
551
+ const lines = ALIGN[style.alignContent] ?? Y.ALIGN_STRETCH;
552
+ if (lines !== Y.ALIGN_FLEX_START) node.setAlignContent(lines);
140
553
  }
141
554
 
142
555
  function applyItem(
@@ -144,107 +557,677 @@ function applyItem(
144
557
  box: Box,
145
558
  ctx: LayoutContext,
146
559
  containingWidth: number,
560
+ laid: Laid,
561
+ /** Whether the flex box has a height of its own. */
562
+ tall: boolean,
147
563
  ): void {
148
564
  const style = box.style;
149
- node.setMargin(Y.EDGE_TOP, box.marginTop);
150
- node.setMargin(Y.EDGE_RIGHT, box.marginRight);
151
- node.setMargin(Y.EDGE_BOTTOM, box.marginBottom);
152
- node.setMargin(Y.EDGE_LEFT, box.marginLeft);
153
- node.setFlexGrow(style.flexGrow);
154
- node.setFlexShrink(style.flexShrink);
565
+ laid.stretch = containingWidth - box.marginLeft - box.marginRight;
566
+ // an `auto` margin takes the free space on its side, which is how
567
+ // `margin-left: auto` puts an item at the end of its row (CSS Flexbox
568
+ // 8.1); Yoga does that itself
569
+ const margin = (edge: number, len: unknown, px: number) => {
570
+ if (len === AUTO) node.setMarginAuto(edge);
571
+ else if (px) node.setMargin(edge, px);
572
+ };
573
+ margin(Y.EDGE_TOP, style.marginTop, box.marginTop);
574
+ margin(Y.EDGE_RIGHT, style.marginRight, box.marginRight);
575
+ margin(Y.EDGE_BOTTOM, style.marginBottom, box.marginBottom);
576
+ margin(Y.EDGE_LEFT, style.marginLeft, box.marginLeft);
577
+ if (style.flexGrow) node.setFlexGrow(style.flexGrow);
578
+ if (style.flexShrink) node.setFlexShrink(style.flexShrink);
155
579
  if (style.alignSelf !== AUTO)
156
580
  node.setAlignSelf(ALIGN[style.alignSelf] ?? Y.ALIGN_AUTO);
157
581
 
158
- setLength(
159
- style.width,
160
- containingWidth,
161
- node.setWidth.bind(node),
162
- node.setWidthPercent.bind(node),
163
- node.setWidthAuto.bind(node),
164
- );
165
- setLength(
166
- style.height,
167
- NaN,
168
- node.setHeight.bind(node),
169
- node.setHeightPercent.bind(node),
170
- node.setHeightAuto.bind(node),
171
- );
582
+ // Yoga's sizes are border boxes, as `box-sizing: border-box` has them;
583
+ // a `content-box` length is the content's, and the item's padding and
584
+ // border go on top of it
585
+ const across = style.boxSizing === 'border-box' ? 0 : box.horizontalExtra;
586
+ const down = style.boxSizing === 'border-box' ? 0 : box.verticalExtra;
587
+ if (style.width !== AUTO) {
588
+ laid.set = setLength(node, true, style.width, containingWidth, across);
589
+ }
590
+ if (style.height !== AUTO) setLength(node, false, style.height, NaN, down);
172
591
  const minWidth = resolveOrNull(style.minWidth, containingWidth);
173
- if (minWidth !== null) node.setMinWidth(minWidth);
592
+ if (minWidth !== null) node.setMinWidth(minWidth + across);
174
593
  if (style.maxWidth !== 'none') {
175
594
  const maxWidth = resolveOrNull(style.maxWidth, containingWidth);
176
- if (maxWidth !== null) node.setMaxWidth(maxWidth);
595
+ if (maxWidth !== null) node.setMaxWidth(maxWidth + across);
596
+ }
597
+ if (style.widthKeyword || style.minWidthKeyword || style.maxWidthKeyword) {
598
+ // an intrinsic size is the item's content's, measured here and handed
599
+ // over as a length: `w-fit` in a column is not stretched across it,
600
+ // and `min-w-max` in a row does not shrink below its content
601
+ const room = Math.max(
602
+ 0,
603
+ containingWidth - box.marginLeft - box.marginRight,
604
+ );
605
+ const size = (keyword: ContentSize): number =>
606
+ contentSizedWidth(box, ctx, keyword, room, containingWidth);
607
+ if (style.widthKeyword) {
608
+ laid.set = size(style.widthKeyword);
609
+ node.setWidth(laid.set);
610
+ }
611
+ if (style.minWidthKeyword) node.setMinWidth(size(style.minWidthKeyword));
612
+ if (style.maxWidthKeyword) node.setMaxWidth(size(style.maxWidthKeyword));
177
613
  }
178
614
  const minHeight = resolveOrNull(style.minHeight, NaN);
179
- if (minHeight !== null) node.setMinHeight(minHeight);
615
+ if (minHeight !== null) node.setMinHeight(minHeight + down);
180
616
  if (style.maxHeight !== 'none') {
181
617
  const maxHeight = resolveOrNull(style.maxHeight, NaN);
182
- if (maxHeight !== null) node.setMaxHeight(maxHeight);
618
+ if (maxHeight !== null) node.setMaxHeight(maxHeight + down);
183
619
  }
184
620
 
185
- if (style.flexBasis === 'content') node.setFlexBasisAuto();
186
- else if (style.flexBasis === AUTO) node.setFlexBasisAuto();
187
- else if (isPct(style.flexBasis))
188
- node.setFlexBasisPercent(style.flexBasis.pct);
189
- else node.setFlexBasis(style.flexBasis);
621
+ const row = box.parent?.style.flexDirection.startsWith('row') ?? true;
622
+ // Yoga takes a length for a basis only where the flex box's main size is
623
+ // definite, and else the item's own size along it: down a column of no
624
+ // height of its own it read `flex: 0 0 3rem` as the item's height, or
625
+ // its content's. There the basis is handed over as that height, which is
626
+ // what the item's own is to a basis anyway — no more than its start
627
+ const setBasis = (px: number): void => {
628
+ if (row || tall) node.setFlexBasis(px);
629
+ else node.setHeight(px);
630
+ };
631
+ // down a column, an item with a ratio and a width is as tall as that
632
+ // makes it, for a basis of its content or of its own `auto` height (CSS
633
+ // Flexbox 9.2.3, B) — where Yoga measured it, and its block layout held
634
+ // it to its content (CSS Sizing 4, 5.2), which only its automatic
635
+ // minimum does here (`autoMinimums`)
636
+ const columnBasis =
637
+ !row &&
638
+ (style.flexBasis === 'content' ||
639
+ (style.flexBasis === AUTO && style.height === AUTO))
640
+ ? ratioHeightBasis(box, containingWidth)
641
+ : null;
642
+ if (style.flexBasis === 'content' && row) {
643
+ // the content's size along a row, whatever the item's own width says
644
+ // (CSS Flexbox 7.2.3), which Yoga reads as `auto` and takes the width
645
+ // for; along a column, Yoga's measure is the content's
646
+ node.setFlexBasis(contentBasis(box, ctx, containingWidth));
647
+ } else if (columnBasis !== null) {
648
+ // but a height of its own hides it from Yoga, and an item with a ratio
649
+ // and a width is as tall as that makes it
650
+ setBasis(columnBasis);
651
+ } else if (style.flexBasis === 'content' || style.flexBasis === AUTO) {
652
+ // Yoga's own
653
+ } else if (isPct(style.flexBasis)) {
654
+ // a percentage of the main size, which is known across a row
655
+ const basis = style.flexBasis;
656
+ if (!basis.px && !basis.of) node.setFlexBasisPercent(basis.pct);
657
+ else if (row && Number.isFinite(containingWidth)) {
658
+ node.setFlexBasis(resolve(basis, containingWidth));
659
+ } else if (basis.of) node.setFlexBasisAuto();
660
+ else node.setFlexBasisPercent(basis.pct);
661
+ } else setBasis(style.flexBasis + (row ? across : down));
190
662
 
191
663
  // The item's padding and border belong to Yoga so it can size the item,
192
664
  // and to this engine so it can paint it. Both read the same numbers.
193
- node.setPadding(Y.EDGE_TOP, box.padTop);
194
- node.setPadding(Y.EDGE_RIGHT, box.padRight);
195
- node.setPadding(Y.EDGE_BOTTOM, box.padBottom);
196
- node.setPadding(Y.EDGE_LEFT, box.padLeft);
197
- node.setBorder(Y.EDGE_TOP, box.borderTop);
198
- node.setBorder(Y.EDGE_RIGHT, box.borderRight);
199
- node.setBorder(Y.EDGE_BOTTOM, box.borderBottom);
200
- node.setBorder(Y.EDGE_LEFT, box.borderLeft);
665
+ if (box.padTop) node.setPadding(Y.EDGE_TOP, box.padTop);
666
+ if (box.padRight) node.setPadding(Y.EDGE_RIGHT, box.padRight);
667
+ if (box.padBottom) node.setPadding(Y.EDGE_BOTTOM, box.padBottom);
668
+ if (box.padLeft) node.setPadding(Y.EDGE_LEFT, box.padLeft);
669
+ if (box.borderTop) node.setBorder(Y.EDGE_TOP, box.borderTop);
670
+ if (box.borderRight) node.setBorder(Y.EDGE_RIGHT, box.borderRight);
671
+ if (box.borderBottom) node.setBorder(Y.EDGE_BOTTOM, box.borderBottom);
672
+ if (box.borderLeft) node.setBorder(Y.EDGE_LEFT, box.borderLeft);
201
673
 
202
674
  // Yoga asks; this engine answers. That is the whole of the bridge, and it
203
675
  // is what lets a paragraph be a flex item without flex knowing what a
204
676
  // paragraph is.
677
+ // Its max-content width is the same at every width Yoga asks at, and at
678
+ // every layout the box has, so it is taken once in the box's life, as a
679
+ // table cell's is: taken per layout of the container, a flex box in a
680
+ // flex box in a flex box laid its innermost out three times a level,
681
+ // and twelve levels took two seconds.
682
+ const alongRow = box.parent?.style.flexDirection.startsWith('row') ?? true;
683
+ const content = (): number => {
684
+ // a replaced element's is the width it has with no limit — its
685
+ // natural one, or what its ratio makes of a height of its own — which
686
+ // its image, loading, may change, so it is not kept; taken as its
687
+ // content's, it was none, and Yoga measured an image as nothing wide
688
+ if (box.kind === 'replaced') {
689
+ ctx.layoutSubtree(box, Infinity);
690
+ return Math.max(0, box.width - box.horizontalExtra);
691
+ }
692
+ // an item with a ratio and a definite height is that height through
693
+ // its ratio wide: its flex base size along a row (CSS Flexbox 9.2.3)
694
+ const fromRatio =
695
+ alongRow && style.width === AUTO && !style.widthKeyword
696
+ ? ratioBasis(box)
697
+ : null;
698
+ if (fromRatio !== null) return Math.max(0, fromRatio - box.horizontalExtra);
699
+ let width = MAX_CONTENT.get(box);
700
+ if (width === undefined) {
701
+ width = measureIntrinsicWidth(box, ctx, Infinity) - box.horizontalExtra;
702
+ MAX_CONTENT.set(box, width);
703
+ }
704
+ // within what its least and greatest heights make of widths through
705
+ // its ratio: its size before it is flexed, and not after
706
+ const extra = box.horizontalExtra;
707
+ return Math.max(0, transferredWidth(box, width + extra) - extra);
708
+ };
709
+ // An item with a ratio is as wide, across a column, as the height it
710
+ // was given makes it through the ratio, where its width is its own to
711
+ // find (CSS Flexbox 9.4, its hypothetical cross size from its used main
712
+ // size); and a replaced one is as tall, along a row, as the width it was
713
+ // given makes it, where its height is — which a replaced element's
714
+ // layout, sized by its own style, does not know.
715
+ const ratio = box.kind === 'replaced' ? replacedRatio(box) : 0;
716
+ const widthThrough =
717
+ !alongRow && style.width === AUTO && !style.widthKeyword
718
+ ? (height: number): number | null =>
719
+ box.kind === 'replaced'
720
+ ? ratio > 0
721
+ ? height * ratio
722
+ : null
723
+ : (() => {
724
+ const width = widthFromHeight(box, height + box.verticalExtra);
725
+ return width === null
726
+ ? null
727
+ : Math.max(0, width - box.horizontalExtra);
728
+ })()
729
+ : null;
730
+ // and an answer Yoga asks for twice is the layout the item already has
731
+ const answers = new Map<number, { width: number; height: number }>();
205
732
  node.setMeasureFunc((w, wm, h, hm) => {
206
- void h;
207
- void hm;
208
- const available =
209
- wm === Y.MEASURE_MODE_UNDEFINED || !Number.isFinite(w) ? Infinity : w;
210
- return measureBox(box, ctx, available);
733
+ // the width Yoga gave, as this engine meant it (`meant`)
734
+ const extra = box.horizontalExtra;
735
+ const width = meant(w, laid.set - extra, laid.stretch - extra);
736
+ const given = hm === Y.MEASURE_MODE_EXACTLY && Number.isFinite(h);
737
+ const exact = wm === Y.MEASURE_MODE_EXACTLY && Number.isFinite(width);
738
+ const through = widthThrough && given && !exact ? widthThrough(h) : null;
739
+ // along a row, a replaced element is its own width wherever there is
740
+ // room for less — its flex base size is not fitted to the room (9.2)
741
+ // — and across a column it is fitted, as any item is
742
+ const inner =
743
+ through !== null
744
+ ? through
745
+ : box.kind === 'replaced' && alongRow && !exact
746
+ ? content()
747
+ : innerWidth(width, wm, content);
748
+ if (
749
+ box.kind === 'replaced' &&
750
+ exact &&
751
+ ratio > 0 &&
752
+ style.height === AUTO
753
+ ) {
754
+ return { width: inner, height: inner / ratio };
755
+ }
756
+ let answer = answers.get(inner);
757
+ if (answer === undefined) {
758
+ answer = measureBox(box, ctx, inner);
759
+ answers.set(inner, answer);
760
+ laid.width = box.width;
761
+ laid.height = box.height;
762
+ }
763
+ return answer;
211
764
  });
212
765
  }
213
766
 
767
+ /** How wide an item's content is as the box is laid out: its max-content
768
+ * width, measured the once (`applyItem`). Keyed by the box, whose lifetime
769
+ * is the cache's: any change to what is in it rebuilds it. */
770
+ const MAX_CONTENT = new WeakMap<Box, number>();
771
+
772
+ /** The width and height of the layout an item was last given, its border
773
+ * box's: what the final pass keeps where the width is the same. */
774
+ interface Laid {
775
+ width: number;
776
+ height: number;
777
+ /** The border-box width this engine set on the item's node — a length,
778
+ * or the content's for `fit-content` and its kin — or NaN. */
779
+ set: number;
780
+ /** Its border-box width stretched across its container: the container's
781
+ * content width, less its margins. */
782
+ stretch: number;
783
+ }
784
+
785
+ /**
786
+ * Whether two widths are the same to a float32's precision. Yoga keeps
787
+ * every length as a float32, a few of its own operations deep, and hands
788
+ * back a width this engine meant rounded — down as often as up.
789
+ */
790
+ function nearly(a: number, b: number): boolean {
791
+ return Math.abs(a - b) <= Math.max(Math.abs(a), Math.abs(b)) * 2 ** -20;
792
+ }
793
+
794
+ /**
795
+ * Yoga's width for an item, as this engine meant it: the first of
796
+ * `intended` it is the float32 of, or its own where it is none of them. A
797
+ * box exactly as wide as its text — `width: fit-content` in a column, an
798
+ * item as wide as its content in a row, a flex box sized to what it holds —
799
+ * came back a hair narrower than the text, and laid out there its last word
800
+ * wrapped: meetup.com's "About us" and "Related topics" were two lines.
801
+ */
802
+ function meant(width: number, ...intended: number[]): number {
803
+ for (const w of intended) {
804
+ if (Number.isFinite(w) && nearly(width, w)) return w;
805
+ }
806
+ return width;
807
+ }
808
+
809
+ /** Set a length on the node; the points it set, or NaN where it set a
810
+ * percentage, which Yoga resolves, or nothing. */
214
811
  function setLength(
812
+ node: YogaNode,
813
+ across: boolean,
215
814
  len: ComputedStyle['width'],
216
815
  base: number,
217
- setPx: (v: number) => void,
218
- setPercent: (v: number) => void,
219
- setAuto: () => void,
220
- ): void {
221
- if (len === AUTO) {
222
- setAuto();
223
- return;
224
- }
816
+ /** Padding and border a `content-box` length goes without. */
817
+ extra: number,
818
+ ): number {
819
+ const px = (v: number) => {
820
+ if (across) node.setWidth(v);
821
+ else node.setHeight(v);
822
+ return v;
823
+ };
824
+ const percent = (v: number) => {
825
+ if (across) node.setWidthPercent(v);
826
+ else node.setHeightPercent(v);
827
+ return NaN;
828
+ };
829
+ if (len === AUTO) return NaN;
225
830
  if (isPct(len)) {
226
- setPercent(len.pct);
227
- return;
831
+ // Yoga takes a percentage or points, not both: `calc(100% - 20px)`
832
+ // resolves here where its base is known, and so does a percentage with
833
+ // padding to add, and a percentage is kept alone where it is not
834
+ if (!len.px && !len.of && !extra) return percent(len.pct);
835
+ if (Number.isFinite(base)) return px(resolve(len, base) + extra);
836
+ if (len.of) return NaN;
837
+ return percent(len.pct);
228
838
  }
229
- void base;
230
- setPx(len);
839
+ return px(len + extra);
231
840
  }
232
841
 
233
842
  /**
234
- * Lay a box out at a width and report the size it came to — the measure
235
- * function's body, and also how a settled item is finally laid out. The two
236
- * are the same call on purpose: an element that reports one size and then
237
- * draws another is the bug this shape makes impossible.
843
+ * The size of an item's content, the measure function's answer. Yoga holds
844
+ * the item's padding and border and adds them itself, so this answers
845
+ * inside them: a border box here was an item its padding's height taller
846
+ * than a browser draws it. Asked for a width it may take up to, or none,
847
+ * an item is as wide as its content, its max-content width (CSS Flexbox
848
+ * 9.2, `flex-basis: auto`), rather than as wide as the row; asked for one
849
+ * exactly, it is that wide. Its height is its content's at that width.
238
850
  */
239
851
  function measureBox(
240
852
  box: Box,
241
853
  ctx: LayoutContext,
242
- available: number,
854
+ inner: number,
243
855
  ): { width: number; height: number } {
244
- ctx.layoutSubtree(box, available);
245
- return { width: box.width, height: box.height };
856
+ ctx.layoutSubtree(box, inner + box.horizontalExtra);
857
+ return {
858
+ width: inner,
859
+ height: Math.max(0, box.height - box.verticalExtra),
860
+ };
861
+ }
862
+
863
+ /** The width an item's content is measured at: the width Yoga gives it
864
+ * exactly, or its max-content width, no wider than any it may take up to
865
+ * (CSS Flexbox 9.2). */
866
+ function innerWidth(
867
+ width: number,
868
+ mode: number,
869
+ maxContent: () => number,
870
+ ): number {
871
+ if (mode === Y.MEASURE_MODE_EXACTLY && Number.isFinite(width)) {
872
+ return Math.max(0, width);
873
+ }
874
+ const content = maxContent();
875
+ if (mode !== Y.MEASURE_MODE_AT_MOST || !Number.isFinite(width)) {
876
+ return content;
877
+ }
878
+ // a room exactly as wide as the content, as Yoga holds it, is room for it
879
+ return content <= width || nearly(content, width)
880
+ ? content
881
+ : Math.max(0, width);
246
882
  }
247
883
 
884
+ /**
885
+ * An item's automatic minimum (CSS Flexbox 4.5): with `min-width: auto` in
886
+ * a row, or `min-height: auto` in a column, an item its content sizes is no
887
+ * smaller along the row than its content comes to — its min-content width,
888
+ * or its content's height at its width.
889
+ * Yoga has no such minimum, and shrank an item under a long word or a
890
+ * column's content, which ran out over the next one; `min-w-0` is what
891
+ * lets an item shrink past it, and so `auto` is kept apart from 0.
892
+ *
893
+ * Asked of an item only where its content overflows it at the size Yoga
894
+ * gave it, laid out there as the final pass would lay it out and keeps
895
+ * (`Laid`), so a row with room pays for nothing. True where some item
896
+ * was given a minimum and the row has to be laid out again.
897
+ */
898
+ function autoMinimums(
899
+ items: { box: Box; node: YogaNode; laid: Laid }[],
900
+ row: boolean,
901
+ ctx: LayoutContext,
902
+ containingWidth: number,
903
+ ): boolean {
904
+ let changed = false;
905
+ for (const { box, node, laid } of items) {
906
+ if (box.kind === 'text' || box.kind === 'break') continue;
907
+ const style = box.style;
908
+ // a box that scrolls or clips has none, but for one that asks for its
909
+ // content's height
910
+ const asked = !row && style.minHeightKeyword !== null;
911
+ if (!asked && scrolls(style)) {
912
+ continue;
913
+ }
914
+ const width = meant(
915
+ node.getComputedWidth(),
916
+ laid.set,
917
+ laid.stretch,
918
+ laid.width,
919
+ );
920
+ // a replaced item's content along a row is its natural width
921
+ if (row && box.kind === 'replaced') {
922
+ if (style.minWidth !== AUTO || style.minWidthKeyword) continue;
923
+ const least = replacedMinimum(box, containingWidth);
924
+ if (least === null || width >= least - 0.01) continue;
925
+ node.setMinWidth(least);
926
+ changed = true;
927
+ continue;
928
+ }
929
+ // An item with a ratio and a definite height is along a row as wide
930
+ // as that height makes it, or as its content at its narrowest where
931
+ // that is wider (4.5's content size suggestion, its min-content size
932
+ // through the ratio, and CSS Sizing 4, 5.2) — and no wider for it
933
+ // than a width of its own
934
+ if (
935
+ row &&
936
+ box.kind !== 'replaced' &&
937
+ style.minWidth === AUTO &&
938
+ !style.minWidthKeyword
939
+ ) {
940
+ const through = ratioBasis(box);
941
+ if (through !== null) {
942
+ let least = Math.max(through, minContentOf(box, ctx, laid));
943
+ const own = resolveOrNull(style.width, containingWidth);
944
+ const extra =
945
+ style.boxSizing === 'border-box' ? 0 : box.horizontalExtra;
946
+ if (own !== null) least = Math.min(least, own + extra);
947
+ if (style.maxWidth !== 'none') {
948
+ const most = resolveOrNull(style.maxWidth, containingWidth);
949
+ if (most !== null) least = Math.min(least, most + extra);
950
+ }
951
+ if (width >= least - 0.01) continue;
952
+ node.setMinWidth(least);
953
+ changed = true;
954
+ continue;
955
+ }
956
+ }
957
+ if (
958
+ row
959
+ ? style.minWidth !== AUTO || style.minWidthKeyword || style.widthKeyword
960
+ : style.minHeight !== AUTO && !asked
961
+ ) {
962
+ continue;
963
+ }
964
+ // One with a width of its own is no narrower along a row than the
965
+ // lesser of that width and its content at its narrowest (4.5's
966
+ // specified and content size suggestions): a `width: 250px` sidebar
967
+ // with `flex-basis: 0` is 250 wide beside the item that takes the
968
+ // rest, and one holding a longer word is still no wider than 250
969
+ if (row && style.width !== AUTO) {
970
+ const own = resolveOrNull(style.width, containingWidth);
971
+ if (own === null) continue;
972
+ const extra = style.boxSizing === 'border-box' ? 0 : box.horizontalExtra;
973
+ let least = own + extra;
974
+ if (style.maxWidth !== 'none') {
975
+ const most = resolveOrNull(style.maxWidth, containingWidth);
976
+ if (most !== null) least = Math.min(least, most + extra);
977
+ }
978
+ if (width >= least - 0.01) continue;
979
+ least = Math.min(least, minContentOf(box, ctx, laid));
980
+ if (node.getComputedWidth() >= least - 0.01) continue;
981
+ node.setMinWidth(least);
982
+ changed = true;
983
+ continue;
984
+ }
985
+ // no narrower than its content at its widest, where Yoga measured that
986
+ // — and than what a ratio makes of its least height, which a content
987
+ // no wider may still be held to
988
+ const widest = row ? MAX_CONTENT.get(box) : undefined;
989
+ if (
990
+ widest !== undefined &&
991
+ transferredWidth(box, widest + box.horizontalExtra) <= width + 0.5
992
+ ) {
993
+ continue;
994
+ }
995
+ if (!(Math.abs(laid.width - width) <= 0.01)) {
996
+ ctx.layoutSubtree(box, width);
997
+ laid.width = box.width;
998
+ laid.height = box.height;
999
+ }
1000
+ let least: number;
1001
+ if (row) {
1002
+ // or than what it drew at the width it has: nothing overflows it
1003
+ const drawn = intrinsicWidth(box) + box.horizontalExtra;
1004
+ if (transferredWidth(box, drawn) <= width + 0.5) continue;
1005
+ // within what a ratio makes of its least and greatest heights (4.5's
1006
+ // content size suggestion)
1007
+ least = transferredWidth(box, minContentOf(box, ctx, laid));
1008
+ const extra = style.boxSizing === 'border-box' ? 0 : box.horizontalExtra;
1009
+ if (style.maxWidth !== 'none') {
1010
+ const most = resolveOrNull(style.maxWidth, containingWidth);
1011
+ if (most !== null) least = Math.min(least, most + extra);
1012
+ }
1013
+ if (node.getComputedWidth() >= least - 0.01) continue;
1014
+ node.setMinWidth(least);
1015
+ } else {
1016
+ // its height, or where it has one of its own and its content comes to
1017
+ // less, its content's: the lesser of the two (4.5)
1018
+ let content: number;
1019
+ if (box.kind === 'replaced') content = laid.height;
1020
+ else if (style.height !== AUTO && percentHeightsIn(box)) {
1021
+ // what its content comes to where it has no height to take
1022
+ // percentages of, as an intrinsic size is measured: laid out so
1023
+ // apart, and the final pass lays it out again
1024
+ FLEXED_HEIGHT.set(box, NaN);
1025
+ try {
1026
+ ctx.layoutSubtree(box, width);
1027
+ } finally {
1028
+ FLEXED_HEIGHT.delete(box);
1029
+ }
1030
+ content = contentBottom(box) + box.verticalExtra;
1031
+ laid.width = NaN;
1032
+ } else content = contentBottom(box) + box.verticalExtra;
1033
+ // and a ratio's content is at least its width through the ratio,
1034
+ // height of its own or not (CSS Sizing 4, 5.1)
1035
+ const aspect = style.aspectRatio;
1036
+ if (aspect && box.kind !== 'replaced') {
1037
+ content = Math.max(
1038
+ content,
1039
+ style.boxSizing === 'border-box'
1040
+ ? box.width / aspect.ratio
1041
+ : box.contentWidth / aspect.ratio + box.verticalExtra,
1042
+ );
1043
+ }
1044
+ // within what the ratio makes of its least and greatest widths
1045
+ if (box.kind !== 'replaced') {
1046
+ content = transferredHeight(box, content, containingWidth);
1047
+ }
1048
+ least = Math.min(laid.height, content);
1049
+ const extra = style.boxSizing === 'border-box' ? 0 : box.verticalExtra;
1050
+ if (style.maxHeight !== 'none') {
1051
+ const most = resolveOrNull(style.maxHeight, NaN);
1052
+ if (most !== null) least = Math.min(least, most + extra);
1053
+ }
1054
+ if (node.getComputedHeight() >= least - 0.01) continue;
1055
+ node.setMinHeight(least);
1056
+ }
1057
+ changed = true;
1058
+ }
1059
+ return changed;
1060
+ }
1061
+
1062
+ /** An item's min-content width, its border box's, taken the once: its
1063
+ * content's, whatever width it has of its own (`keywordWidth`'s too). */
1064
+ function minContentOf(box: Box, ctx: LayoutContext, laid: Laid): number {
1065
+ if (box.intrinsicMinContent < 0) {
1066
+ const exact = ctx.fonts ? exactMinContent(box, ctx.fonts) : null;
1067
+ box.intrinsicMinContent =
1068
+ exact ?? measureIntrinsicWidth(box, ctx, MIN_CONTENT_PROBE, true);
1069
+ // a probe lays the box out where the kept layout was
1070
+ if (exact === null) laid.width = NaN;
1071
+ }
1072
+ return box.intrinsicMinContent;
1073
+ }
1074
+
1075
+ /** How far down a laid-out box's content reaches inside its content box:
1076
+ * its lines and its children, floats included, with their margins. */
1077
+ function contentBottom(box: Box): number {
1078
+ const top = box.contentY;
1079
+ let bottom = 0;
1080
+ for (const line of box.lines ?? []) {
1081
+ bottom = Math.max(bottom, line.y + line.height - top);
1082
+ }
1083
+ for (const child of box.children) {
1084
+ if (child.outOfFlow || child.kind === 'text' || child.kind === 'break') {
1085
+ continue;
1086
+ }
1087
+ if (child.kind === 'inline') continue;
1088
+ bottom = Math.max(
1089
+ bottom,
1090
+ child.y + child.height + child.marginBottom - top,
1091
+ );
1092
+ }
1093
+ return bottom;
1094
+ }
1095
+
1096
+ /**
1097
+ * A row's items aligned by their baselines (CSS Flexbox 8.3, 9.4 step 8),
1098
+ * which Yoga cannot see: an item is a leaf there, and a leaf's baseline is
1099
+ * its bottom edge, so it lined them up by their bottoms. With the items laid
1100
+ * out, each line's, and for each the top margin that sets it at the line's
1101
+ * start with its first baseline where the lowest-reaching one's is — or
1102
+ * null where no line has two to align.
1103
+ */
1104
+ function baselineLines<T extends { box: Box }>(
1105
+ style: ComputedStyle,
1106
+ items: readonly T[],
1107
+ ): (T[] & { margins: number[] })[] | null {
1108
+ // a line that grows from its end is aligned from there, and left to Yoga
1109
+ if (style.flexWrap === 'wrap-reverse') return null;
1110
+ const wraps = style.flexWrap !== 'nowrap';
1111
+ // along a line the items go the way the main axis does, and the next
1112
+ // line starts where one does not
1113
+ const back =
1114
+ (style.flexDirection === 'row-reverse') !== (style.direction === 'rtl');
1115
+ const out: (T[] & { margins: number[] })[] = [];
1116
+ let line: T[] = [];
1117
+ let last = NaN;
1118
+ let several = false;
1119
+ const close = (): void => {
1120
+ if (!line.length) return;
1121
+ if (line.length > 1) several = true;
1122
+ let reach = -Infinity;
1123
+ const ascents = line.map(({ box }) => {
1124
+ const ascent = box.marginTop + itemBaseline(box);
1125
+ reach = Math.max(reach, ascent);
1126
+ return ascent;
1127
+ });
1128
+ const margins = line.map(
1129
+ ({ box }, i) => box.marginTop + reach - ascents[i],
1130
+ );
1131
+ out.push(Object.assign(line, { margins }));
1132
+ };
1133
+ for (const item of items) {
1134
+ const box = item.box;
1135
+ if (wraps && line.length && (back ? box.x >= last : box.x <= last)) {
1136
+ close();
1137
+ line = [];
1138
+ }
1139
+ last = box.x;
1140
+ const own = box.style;
1141
+ const aligned = own.alignSelf === AUTO ? style.alignItems : own.alignSelf;
1142
+ // an `auto` margin across the line takes it over alignment
1143
+ if (
1144
+ aligned === 'baseline' &&
1145
+ own.marginTop !== AUTO &&
1146
+ own.marginBottom !== AUTO
1147
+ ) {
1148
+ line.push(item);
1149
+ }
1150
+ }
1151
+ close();
1152
+ // one alone on its line is at its start already
1153
+ return several ? out : null;
1154
+ }
1155
+
1156
+ /**
1157
+ * How far an item is from where it belongs across its line, where Yoga
1158
+ * (3.2.1) aligned the lines in the pass it takes for a box that wraps or
1159
+ * aligns by baselines: it sets an item aligned to its line's start there
1160
+ * as though it had no margin at that side, and one centred as though it had
1161
+ * none at either — `items-start` in a wrapping row put every card's top
1162
+ * margin under it. By the margin at the start of the line's cross axis, and
1163
+ * by half what it exceeds the one at the end by, as Yoga holds them: for an
1164
+ * item set at its line's start (`started`), its baseline's. A column's,
1165
+ * whose cross axis runs right to left, and a box that wraps in reverse are
1166
+ * left as Yoga has them.
1167
+ */
1168
+ function lineMarginFix(
1169
+ container: ComputedStyle,
1170
+ item: Box,
1171
+ node: YogaNode,
1172
+ row: boolean,
1173
+ started = false,
1174
+ ): number {
1175
+ if (container.flexWrap === 'wrap-reverse') return 0;
1176
+ if (!row && container.direction === 'rtl') return 0;
1177
+ const style = item.style;
1178
+ // a margin that is `auto` takes the item over its alignment
1179
+ const lead = row ? style.marginTop : style.marginLeft;
1180
+ const trail = row ? style.marginBottom : style.marginRight;
1181
+ if (lead === AUTO || trail === AUTO) return 0;
1182
+ const align = started
1183
+ ? 'flex-start'
1184
+ : style.alignSelf === AUTO
1185
+ ? container.alignItems
1186
+ : style.alignSelf;
1187
+ if (align !== 'flex-start' && align !== 'center') return 0;
1188
+ const leading = node.getComputedMargin(row ? Y.EDGE_TOP : Y.EDGE_LEFT);
1189
+ if (align === 'flex-start') return leading;
1190
+ const trailing = node.getComputedMargin(row ? Y.EDGE_BOTTOM : Y.EDGE_RIGHT);
1191
+ return (leading - trailing) / 2;
1192
+ }
1193
+
1194
+ /** An item's first baseline, down from its border edge: its content's
1195
+ * first line's, or where it has none, or is replaced, one synthesized
1196
+ * from its border box — its bottom edge. */
1197
+ function itemBaseline(item: Box): number {
1198
+ if (item.kind !== 'replaced') {
1199
+ const found = firstBaselineIn(item);
1200
+ if (found !== null) return Math.min(found - item.y, item.height);
1201
+ }
1202
+ return item.height;
1203
+ }
1204
+
1205
+ /** Whether an item is stretched across its line: `stretch`, its own or its
1206
+ * container's, with no height of its own and no `auto` margin across. */
1207
+ function stretches(
1208
+ box: Box,
1209
+ container: ComputedStyle,
1210
+ /** Whether the line is a row's, across which the item's height is
1211
+ * stretched; a column's stretches its width. */
1212
+ row = true,
1213
+ ): boolean {
1214
+ const style = box.style;
1215
+ const align =
1216
+ style.alignSelf === AUTO ? container.alignItems : style.alignSelf;
1217
+ if (align !== 'stretch') return false;
1218
+ return row
1219
+ ? style.height === AUTO &&
1220
+ style.marginTop !== AUTO &&
1221
+ style.marginBottom !== AUTO
1222
+ : style.width === AUTO &&
1223
+ style.marginLeft !== AUTO &&
1224
+ style.marginRight !== AUTO;
1225
+ }
1226
+
1227
+ /** How deep flex boxes are laid out by Yoga, one inside another's measure
1228
+ * (`layoutFlex`). */
1229
+ const FLEX_DEPTH = 64;
1230
+
248
1231
  /** No Yoga assembly: stack the items instead of dropping them. */
249
1232
  function layoutAsBlockFallback(
250
1233
  box: Box,
@@ -253,9 +1236,9 @@ function layoutAsBlockFallback(
253
1236
  ): number {
254
1237
  let y = box.contentY;
255
1238
  for (const child of box.children) {
256
- if (child.kind === 'text' && !child.text.trim()) continue;
1239
+ if (child.kind === 'text' && isBlank(child.text)) continue;
257
1240
  if (child.outOfFlow) {
258
- ctx.positioned.push({ box: child, containing: box });
1241
+ positionOutOfFlow(child, box, ctx, true);
259
1242
  continue;
260
1243
  }
261
1244
  resolveEdges(child, contentWidth);
@@ -277,6 +1260,32 @@ const WRAP: Record<string, number> = {
277
1260
  wrap: Y?.WRAP_WRAP,
278
1261
  'wrap-reverse': Y?.WRAP_WRAP_REVERSE,
279
1262
  };
1263
+ /**
1264
+ * A `justify-content` as the main axis takes it (CSS Box Alignment 3,
1265
+ * 6.1): `start` and `end` are the writing mode's, the main axis's own ends
1266
+ * turned round in a reversed direction; `left` and `right` are the page's
1267
+ * along a row, and `start` along a column, which has neither.
1268
+ */
1269
+ function mainJustify(style: ComputedStyle): string {
1270
+ const justify = style.justifyContent;
1271
+ if (
1272
+ justify !== 'start' &&
1273
+ justify !== 'end' &&
1274
+ justify !== 'left' &&
1275
+ justify !== 'right'
1276
+ ) {
1277
+ return justify;
1278
+ }
1279
+ const reverse = style.flexDirection.endsWith('-reverse');
1280
+ const row = style.flexDirection.startsWith('row');
1281
+ let start: boolean;
1282
+ if (justify === 'start') start = true;
1283
+ else if (justify === 'end') start = false;
1284
+ else if (!row) start = true;
1285
+ else start = (justify === 'left') === (style.direction !== 'rtl');
1286
+ return start !== reverse ? 'flex-start' : 'flex-end';
1287
+ }
1288
+
280
1289
  const JUSTIFY: Record<string, number> = {
281
1290
  'flex-start': Y?.JUSTIFY_FLEX_START,
282
1291
  'flex-end': Y?.JUSTIFY_FLEX_END,