@fairyhunter13/opentui-core 0.1.89 → 0.1.91

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 (571) hide show
  1. package/README.md +2 -2
  2. package/dev/keypress-debug-renderer.ts +148 -0
  3. package/dev/keypress-debug.ts +43 -0
  4. package/dev/print-env-vars.ts +32 -0
  5. package/dev/test-tmux-graphics-334.sh +68 -0
  6. package/dev/thai-debug-test.ts +68 -0
  7. package/docs/development.md +141 -0
  8. package/docs/env-vars.md +140 -0
  9. package/docs/getting-started.md +353 -0
  10. package/docs/renderables-vs-constructs.md +159 -0
  11. package/docs/tree-sitter.md +311 -0
  12. package/package.json +61 -52
  13. package/scripts/build.ts +400 -0
  14. package/scripts/publish.ts +60 -0
  15. package/src/3d/SpriteResourceManager.ts +286 -0
  16. package/src/3d/SpriteUtils.ts +71 -0
  17. package/src/3d/TextureUtils.ts +196 -0
  18. package/src/3d/ThreeRenderable.ts +197 -0
  19. package/src/3d/WGPURenderer.ts +294 -0
  20. package/src/3d/animation/ExplodingSpriteEffect.ts +513 -0
  21. package/src/3d/animation/PhysicsExplodingSpriteEffect.ts +429 -0
  22. package/src/3d/animation/SpriteAnimator.ts +633 -0
  23. package/src/3d/animation/SpriteParticleGenerator.ts +435 -0
  24. package/src/3d/canvas.ts +464 -0
  25. package/src/3d/index.ts +12 -0
  26. package/src/3d/physics/PlanckPhysicsAdapter.ts +72 -0
  27. package/src/3d/physics/RapierPhysicsAdapter.ts +66 -0
  28. package/src/3d/physics/physics-interface.ts +31 -0
  29. package/src/3d/shaders/supersampling.wgsl +201 -0
  30. package/src/3d.ts +3 -0
  31. package/src/NativeSpanFeed.ts +300 -0
  32. package/src/Renderable.ts +1698 -0
  33. package/src/__snapshots__/buffer.test.ts.snap +28 -0
  34. package/src/animation/Timeline.test.ts +2709 -0
  35. package/src/animation/Timeline.ts +598 -0
  36. package/src/ansi.ts +18 -0
  37. package/src/benchmark/latest-all-bench-run.json +707 -0
  38. package/src/benchmark/latest-async-bench-run.json +336 -0
  39. package/src/benchmark/latest-default-bench-run.json +657 -0
  40. package/src/benchmark/latest-large-bench-run.json +707 -0
  41. package/src/benchmark/latest-quick-bench-run.json +207 -0
  42. package/src/benchmark/markdown-benchmark.ts +1804 -0
  43. package/src/benchmark/native-span-feed-async-benchmark.ts +355 -0
  44. package/src/benchmark/native-span-feed-benchmark.md +56 -0
  45. package/src/benchmark/native-span-feed-benchmark.ts +596 -0
  46. package/src/benchmark/native-span-feed-compare.ts +280 -0
  47. package/src/benchmark/renderer-benchmark.ts +754 -0
  48. package/src/benchmark/text-table-benchmark.ts +947 -0
  49. package/src/buffer.test.ts +291 -0
  50. package/src/buffer.ts +519 -0
  51. package/src/console.test.ts +612 -0
  52. package/src/console.ts +1255 -0
  53. package/src/edit-buffer.test.ts +1769 -0
  54. package/src/edit-buffer.ts +411 -0
  55. package/src/editor-view.test.ts +1032 -0
  56. package/src/editor-view.ts +284 -0
  57. package/src/examples/ascii-font-selection-demo.ts +245 -0
  58. package/src/examples/assets/Water_2_M_Normal.jpg +0 -0
  59. package/src/examples/assets/concrete.png +0 -0
  60. package/src/examples/assets/crate.png +0 -0
  61. package/src/examples/assets/crate_emissive.png +0 -0
  62. package/src/examples/assets/forrest_background.png +0 -0
  63. package/src/examples/assets/hast-example.json +1018 -0
  64. package/src/examples/assets/heart.png +0 -0
  65. package/src/examples/assets/main_char_heavy_attack.png +0 -0
  66. package/src/examples/assets/main_char_idle.png +0 -0
  67. package/src/examples/assets/main_char_jump_end.png +0 -0
  68. package/src/examples/assets/main_char_jump_landing.png +0 -0
  69. package/src/examples/assets/main_char_jump_start.png +0 -0
  70. package/src/examples/assets/main_char_run_loop.png +0 -0
  71. package/src/examples/assets/roughness_map.jpg +0 -0
  72. package/src/examples/build.ts +115 -0
  73. package/src/examples/code-demo.ts +584 -0
  74. package/src/examples/console-demo.ts +358 -0
  75. package/src/examples/core-plugin-slots-demo.ts +759 -0
  76. package/src/examples/diff-demo.ts +699 -0
  77. package/src/examples/draggable-three-demo.ts +259 -0
  78. package/src/examples/editor-demo.ts +322 -0
  79. package/src/examples/extmarks-demo.ts +204 -0
  80. package/src/examples/focus-restore-demo.ts +310 -0
  81. package/src/examples/fonts.ts +245 -0
  82. package/src/examples/fractal-shader-demo.ts +268 -0
  83. package/src/examples/framebuffer-demo.ts +674 -0
  84. package/src/examples/full-unicode-demo.ts +181 -0
  85. package/src/examples/golden-star-demo.ts +933 -0
  86. package/src/examples/grayscale-buffer-demo.ts +249 -0
  87. package/src/examples/hast-syntax-highlighting-demo.ts +129 -0
  88. package/src/examples/index.ts +925 -0
  89. package/src/examples/input-demo.ts +377 -0
  90. package/src/examples/input-select-layout-demo.ts +425 -0
  91. package/src/examples/install.sh +143 -0
  92. package/src/examples/keypress-debug-demo.ts +452 -0
  93. package/src/examples/lib/HexList.ts +122 -0
  94. package/src/examples/lib/PaletteGrid.ts +125 -0
  95. package/src/examples/lib/standalone-keys.ts +25 -0
  96. package/src/examples/lib/tab-controller.ts +243 -0
  97. package/src/examples/lights-phong-demo.ts +290 -0
  98. package/src/examples/link-demo.ts +220 -0
  99. package/src/examples/live-state-demo.ts +480 -0
  100. package/src/examples/markdown-demo.ts +620 -0
  101. package/src/examples/mouse-interaction-demo.ts +428 -0
  102. package/src/examples/nested-zindex-demo.ts +357 -0
  103. package/src/examples/opacity-example.ts +235 -0
  104. package/src/examples/opentui-demo.ts +1057 -0
  105. package/src/examples/physx-planck-2d-demo.ts +507 -0
  106. package/src/examples/physx-rapier-2d-demo.ts +526 -0
  107. package/src/examples/relative-positioning-demo.ts +323 -0
  108. package/src/examples/scroll-example.ts +214 -0
  109. package/src/examples/scrollbox-mouse-test.ts +112 -0
  110. package/src/examples/scrollbox-overlay-hit-test.ts +206 -0
  111. package/src/examples/select-demo.ts +237 -0
  112. package/src/examples/shader-cube-demo.ts +772 -0
  113. package/src/examples/simple-layout-example.ts +591 -0
  114. package/src/examples/slider-demo.ts +617 -0
  115. package/src/examples/split-mode-demo.ts +445 -0
  116. package/src/examples/sprite-animation-demo.ts +443 -0
  117. package/src/examples/sprite-particle-generator-demo.ts +486 -0
  118. package/src/examples/static-sprite-demo.ts +193 -0
  119. package/src/examples/sticky-scroll-example.ts +308 -0
  120. package/src/examples/styled-text-demo.ts +282 -0
  121. package/src/examples/tab-select-demo.ts +219 -0
  122. package/src/examples/terminal-title.ts +29 -0
  123. package/src/examples/terminal.ts +305 -0
  124. package/src/examples/text-node-demo.ts +416 -0
  125. package/src/examples/text-selection-demo.ts +377 -0
  126. package/src/examples/text-table-demo.ts +503 -0
  127. package/src/examples/text-truncation-demo.ts +481 -0
  128. package/src/examples/text-wrap.ts +757 -0
  129. package/src/examples/texture-loading-demo.ts +259 -0
  130. package/src/examples/timeline-example.ts +670 -0
  131. package/src/examples/transparency-demo.ts +241 -0
  132. package/src/examples/vnode-composition-demo.ts +404 -0
  133. package/src/index.ts +22 -0
  134. package/src/lib/KeyHandler.integration.test.ts +292 -0
  135. package/src/lib/KeyHandler.stopPropagation.test.ts +289 -0
  136. package/src/lib/KeyHandler.test.ts +662 -0
  137. package/src/lib/KeyHandler.ts +222 -0
  138. package/src/lib/RGBA.test.ts +984 -0
  139. package/src/lib/RGBA.ts +204 -0
  140. package/src/lib/ascii.font.ts +330 -0
  141. package/src/lib/border.test.ts +83 -0
  142. package/src/lib/border.ts +168 -0
  143. package/src/lib/bunfs.test.ts +27 -0
  144. package/src/lib/bunfs.ts +18 -0
  145. package/src/lib/clipboard.test.ts +41 -0
  146. package/src/lib/clipboard.ts +47 -0
  147. package/src/lib/clock.ts +31 -0
  148. package/src/lib/data-paths.test.ts +133 -0
  149. package/src/lib/data-paths.ts +109 -0
  150. package/src/lib/debounce.ts +106 -0
  151. package/src/lib/detect-links.test.ts +98 -0
  152. package/src/lib/detect-links.ts +56 -0
  153. package/src/lib/env.test.ts +228 -0
  154. package/src/lib/env.ts +209 -0
  155. package/src/lib/extmarks-history.ts +51 -0
  156. package/src/lib/extmarks-multiwidth.test.ts +322 -0
  157. package/src/lib/extmarks.test.ts +3457 -0
  158. package/src/lib/extmarks.ts +843 -0
  159. package/src/lib/fonts/block.json +405 -0
  160. package/src/lib/fonts/grid.json +265 -0
  161. package/src/lib/fonts/huge.json +741 -0
  162. package/src/lib/fonts/pallet.json +314 -0
  163. package/src/lib/fonts/shade.json +591 -0
  164. package/src/lib/fonts/slick.json +321 -0
  165. package/src/lib/fonts/tiny.json +69 -0
  166. package/src/lib/hast-styled-text.ts +59 -0
  167. package/src/lib/index.ts +21 -0
  168. package/src/lib/keymapping.test.ts +280 -0
  169. package/src/lib/keymapping.ts +87 -0
  170. package/src/lib/objects-in-viewport.test.ts +787 -0
  171. package/src/lib/objects-in-viewport.ts +153 -0
  172. package/src/lib/output.capture.ts +58 -0
  173. package/src/lib/parse.keypress-kitty.protocol.test.ts +340 -0
  174. package/src/lib/parse.keypress-kitty.test.ts +663 -0
  175. package/src/lib/parse.keypress-kitty.ts +439 -0
  176. package/src/lib/parse.keypress.test.ts +1849 -0
  177. package/src/lib/parse.keypress.ts +397 -0
  178. package/src/lib/parse.mouse.test.ts +552 -0
  179. package/src/lib/parse.mouse.ts +232 -0
  180. package/src/lib/paste.ts +16 -0
  181. package/src/lib/queue.ts +65 -0
  182. package/src/lib/renderable.validations.test.ts +87 -0
  183. package/src/lib/renderable.validations.ts +83 -0
  184. package/src/lib/scroll-acceleration.ts +98 -0
  185. package/src/lib/selection.ts +240 -0
  186. package/src/lib/singleton.ts +28 -0
  187. package/src/lib/stdin-parser.test.ts +1676 -0
  188. package/src/lib/stdin-parser.ts +1248 -0
  189. package/src/lib/styled-text.ts +178 -0
  190. package/src/lib/terminal-capability-detection.test.ts +202 -0
  191. package/src/lib/terminal-capability-detection.ts +79 -0
  192. package/src/lib/terminal-palette.test.ts +878 -0
  193. package/src/lib/terminal-palette.ts +383 -0
  194. package/src/lib/tree-sitter/assets/README.md +118 -0
  195. package/src/lib/tree-sitter/assets/update.ts +331 -0
  196. package/src/lib/tree-sitter/assets.d.ts +9 -0
  197. package/src/lib/tree-sitter/cache.test.ts +270 -0
  198. package/src/lib/tree-sitter/client.test.ts +1061 -0
  199. package/src/lib/tree-sitter/client.ts +615 -0
  200. package/src/lib/tree-sitter/default-parsers.ts +80 -0
  201. package/src/lib/tree-sitter/download-utils.ts +148 -0
  202. package/src/lib/tree-sitter/index.ts +28 -0
  203. package/src/lib/tree-sitter/parser.worker.ts +1001 -0
  204. package/src/lib/tree-sitter/parsers-config.ts +75 -0
  205. package/src/lib/tree-sitter/resolve-ft.ts +62 -0
  206. package/src/lib/tree-sitter/types.ts +81 -0
  207. package/src/lib/tree-sitter-styled-text.test.ts +1253 -0
  208. package/src/lib/tree-sitter-styled-text.ts +306 -0
  209. package/src/lib/validate-dir-name.ts +55 -0
  210. package/src/lib/yoga.options.test.ts +628 -0
  211. package/src/lib/yoga.options.ts +346 -0
  212. package/src/plugins/core-slot.ts +579 -0
  213. package/src/plugins/registry.ts +377 -0
  214. package/src/plugins/types.ts +46 -0
  215. package/src/post/filters.ts +888 -0
  216. package/src/renderables/ASCIIFont.ts +219 -0
  217. package/src/renderables/Box.test.ts +160 -0
  218. package/src/renderables/Box.ts +295 -0
  219. package/src/renderables/Code.test.ts +2062 -0
  220. package/src/renderables/Code.ts +357 -0
  221. package/src/renderables/Diff.regression.test.ts +226 -0
  222. package/src/renderables/Diff.test.ts +3027 -0
  223. package/src/renderables/Diff.ts +1209 -0
  224. package/src/renderables/EditBufferRenderable.ts +764 -0
  225. package/src/renderables/FrameBuffer.ts +47 -0
  226. package/src/renderables/Input.test.ts +1228 -0
  227. package/src/renderables/Input.ts +245 -0
  228. package/src/renderables/LineNumberRenderable.ts +675 -0
  229. package/src/renderables/Markdown.ts +1106 -0
  230. package/src/renderables/ScrollBar.ts +422 -0
  231. package/src/renderables/ScrollBox.ts +883 -0
  232. package/src/renderables/Select.test.ts +1010 -0
  233. package/src/renderables/Select.ts +523 -0
  234. package/src/renderables/Slider.test.ts +456 -0
  235. package/src/renderables/Slider.ts +347 -0
  236. package/src/renderables/TabSelect.test.ts +197 -0
  237. package/src/renderables/TabSelect.ts +455 -0
  238. package/src/renderables/Text.selection-buffer.test.ts +123 -0
  239. package/src/renderables/Text.test.ts +2660 -0
  240. package/src/renderables/Text.ts +147 -0
  241. package/src/renderables/TextBufferRenderable.ts +518 -0
  242. package/src/renderables/TextNode.test.ts +1058 -0
  243. package/src/renderables/TextNode.ts +325 -0
  244. package/src/renderables/TextTable.test.ts +1421 -0
  245. package/src/renderables/TextTable.ts +1344 -0
  246. package/src/renderables/Textarea.ts +732 -0
  247. package/src/renderables/TimeToFirstDraw.ts +89 -0
  248. package/src/renderables/__snapshots__/Code.test.ts.snap +13 -0
  249. package/src/renderables/__snapshots__/Diff.test.ts.snap +785 -0
  250. package/src/renderables/__snapshots__/Text.test.ts.snap +421 -0
  251. package/src/renderables/__snapshots__/TextTable.test.ts.snap +215 -0
  252. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
  253. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +816 -0
  254. package/src/renderables/__tests__/LineNumberRenderable.test.ts +1787 -0
  255. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
  256. package/src/renderables/__tests__/Markdown.test.ts +2287 -0
  257. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
  258. package/src/renderables/__tests__/Textarea.buffer.test.ts +682 -0
  259. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
  260. package/src/renderables/__tests__/Textarea.editing.test.ts +2041 -0
  261. package/src/renderables/__tests__/Textarea.error-handling.test.ts +35 -0
  262. package/src/renderables/__tests__/Textarea.events.test.ts +738 -0
  263. package/src/renderables/__tests__/Textarea.highlights.test.ts +590 -0
  264. package/src/renderables/__tests__/Textarea.keybinding.test.ts +3149 -0
  265. package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
  266. package/src/renderables/__tests__/Textarea.rendering.test.ts +1864 -0
  267. package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
  268. package/src/renderables/__tests__/Textarea.selection.test.ts +1590 -0
  269. package/src/renderables/__tests__/Textarea.stress.test.ts +670 -0
  270. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +383 -0
  271. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +310 -0
  272. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +221 -0
  273. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +89 -0
  274. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +457 -0
  275. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +158 -0
  276. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +387 -0
  277. package/src/renderables/__tests__/markdown-parser.test.ts +217 -0
  278. package/src/renderables/__tests__/renderable-test-utils.ts +60 -0
  279. package/src/renderables/composition/README.md +8 -0
  280. package/src/renderables/composition/VRenderable.ts +32 -0
  281. package/src/renderables/composition/constructs.ts +127 -0
  282. package/src/renderables/composition/vnode.ts +289 -0
  283. package/src/renderables/index.ts +22 -0
  284. package/src/renderables/markdown-parser.ts +66 -0
  285. package/src/renderer.ts +2363 -0
  286. package/src/runtime-plugin-support.ts +39 -0
  287. package/src/runtime-plugin.ts +144 -0
  288. package/src/syntax-style.test.ts +841 -0
  289. package/src/syntax-style.ts +264 -0
  290. package/src/testing/README.md +210 -0
  291. package/src/testing/capture-spans.test.ts +194 -0
  292. package/src/testing/integration.test.ts +276 -0
  293. package/src/testing/manual-clock.ts +106 -0
  294. package/src/testing/mock-keys.test.ts +1356 -0
  295. package/src/testing/mock-keys.ts +449 -0
  296. package/src/testing/mock-mouse.test.ts +218 -0
  297. package/src/testing/mock-mouse.ts +247 -0
  298. package/src/testing/mock-tree-sitter-client.ts +73 -0
  299. package/src/testing/spy.ts +13 -0
  300. package/src/testing/test-recorder.test.ts +415 -0
  301. package/src/testing/test-recorder.ts +145 -0
  302. package/src/testing/test-renderer.ts +116 -0
  303. package/src/testing.ts +7 -0
  304. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +481 -0
  305. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +19 -0
  306. package/src/tests/__snapshots__/scrollbox.test.ts.snap +29 -0
  307. package/src/tests/absolute-positioning.snapshot.test.ts +638 -0
  308. package/src/tests/allocator-stats.test.ts +38 -0
  309. package/src/tests/destroy-during-render.test.ts +200 -0
  310. package/src/tests/hover-cursor.test.ts +98 -0
  311. package/src/tests/native-span-feed-async.test.ts +173 -0
  312. package/src/tests/native-span-feed-close.test.ts +120 -0
  313. package/src/tests/native-span-feed-coverage.test.ts +227 -0
  314. package/src/tests/native-span-feed-edge-cases.test.ts +352 -0
  315. package/src/tests/native-span-feed-use-after-free.test.ts +45 -0
  316. package/src/tests/opacity.test.ts +123 -0
  317. package/src/tests/renderable.snapshot.test.ts +524 -0
  318. package/src/tests/renderable.test.ts +1281 -0
  319. package/src/tests/renderer.console-startup.test.ts +65 -0
  320. package/src/tests/renderer.control.test.ts +364 -0
  321. package/src/tests/renderer.core-slot-binding.test.ts +952 -0
  322. package/src/tests/renderer.cursor.test.ts +26 -0
  323. package/src/tests/renderer.destroy-during-render.test.ts +110 -0
  324. package/src/tests/renderer.focus-restore.test.ts +228 -0
  325. package/src/tests/renderer.focus.test.ts +251 -0
  326. package/src/tests/renderer.idle.test.ts +219 -0
  327. package/src/tests/renderer.input.test.ts +2145 -0
  328. package/src/tests/renderer.kitty-flags.test.ts +195 -0
  329. package/src/tests/renderer.mouse.test.ts +1269 -0
  330. package/src/tests/renderer.palette.test.ts +629 -0
  331. package/src/tests/renderer.selection.test.ts +49 -0
  332. package/src/tests/renderer.slot-registry.test.ts +649 -0
  333. package/src/tests/renderer.useMouse.test.ts +50 -0
  334. package/src/tests/runtime-plugin-support.fixture.ts +11 -0
  335. package/src/tests/runtime-plugin-support.test.ts +28 -0
  336. package/src/tests/runtime-plugin.fixture.ts +40 -0
  337. package/src/tests/runtime-plugin.test.ts +190 -0
  338. package/src/tests/scrollbox-culling-bug.test.ts +114 -0
  339. package/src/tests/scrollbox-hitgrid-resize.test.ts +136 -0
  340. package/src/tests/scrollbox-hitgrid.test.ts +909 -0
  341. package/src/tests/scrollbox.test.ts +1530 -0
  342. package/src/tests/wrap-resize-perf.test.ts +229 -0
  343. package/src/tests/yoga-setters.test.ts +921 -0
  344. package/src/text-buffer-view.test.ts +705 -0
  345. package/src/text-buffer-view.ts +189 -0
  346. package/src/text-buffer.test.ts +347 -0
  347. package/src/text-buffer.ts +250 -0
  348. package/src/types.ts +152 -0
  349. package/src/utils.ts +88 -0
  350. package/src/zig/ansi.zig +268 -0
  351. package/src/zig/bench/README.md +50 -0
  352. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +887 -0
  353. package/src/zig/bench/edit-buffer_bench.zig +476 -0
  354. package/src/zig/bench/native-span-feed_bench.zig +100 -0
  355. package/src/zig/bench/rope-markers_bench.zig +713 -0
  356. package/src/zig/bench/rope_bench.zig +514 -0
  357. package/src/zig/bench/styled-text_bench.zig +470 -0
  358. package/src/zig/bench/text-buffer-coords_bench.zig +362 -0
  359. package/src/zig/bench/text-buffer-view_bench.zig +459 -0
  360. package/src/zig/bench/text-chunk-graphemes_bench.zig +273 -0
  361. package/src/zig/bench/utf8_bench.zig +799 -0
  362. package/src/zig/bench-utils.zig +431 -0
  363. package/src/zig/bench.zig +217 -0
  364. package/src/zig/buffer.zig +2223 -0
  365. package/src/zig/build.zig +289 -0
  366. package/src/zig/build.zig.zon +16 -0
  367. package/src/zig/edit-buffer.zig +825 -0
  368. package/src/zig/editor-view.zig +802 -0
  369. package/src/zig/event-bus.zig +13 -0
  370. package/src/zig/event-emitter.zig +65 -0
  371. package/src/zig/file-logger.zig +92 -0
  372. package/src/zig/grapheme.zig +599 -0
  373. package/src/zig/lib.zig +1834 -0
  374. package/src/zig/link.zig +333 -0
  375. package/src/zig/logger.zig +43 -0
  376. package/src/zig/mem-registry.zig +125 -0
  377. package/src/zig/native-span-feed-bench-lib.zig +7 -0
  378. package/src/zig/native-span-feed.zig +708 -0
  379. package/src/zig/renderer.zig +1386 -0
  380. package/src/zig/rope.zig +1220 -0
  381. package/src/zig/syntax-style.zig +161 -0
  382. package/src/zig/terminal.zig +975 -0
  383. package/src/zig/test.zig +70 -0
  384. package/src/zig/tests/README.md +18 -0
  385. package/src/zig/tests/buffer_test.zig +2526 -0
  386. package/src/zig/tests/edit-buffer-history_test.zig +271 -0
  387. package/src/zig/tests/edit-buffer_test.zig +1689 -0
  388. package/src/zig/tests/editor-view_test.zig +3299 -0
  389. package/src/zig/tests/event-emitter_test.zig +249 -0
  390. package/src/zig/tests/grapheme_test.zig +1304 -0
  391. package/src/zig/tests/link_test.zig +190 -0
  392. package/src/zig/tests/mem-registry_test.zig +473 -0
  393. package/src/zig/tests/memory_leak_regression_test.zig +159 -0
  394. package/src/zig/tests/native-span-feed_test.zig +1264 -0
  395. package/src/zig/tests/renderer_test.zig +1010 -0
  396. package/src/zig/tests/rope-nested_test.zig +712 -0
  397. package/src/zig/tests/rope_fuzz_test.zig +238 -0
  398. package/src/zig/tests/rope_test.zig +2362 -0
  399. package/src/zig/tests/segment-merge.test.zig +148 -0
  400. package/src/zig/tests/syntax-style_test.zig +557 -0
  401. package/src/zig/tests/terminal_test.zig +719 -0
  402. package/src/zig/tests/text-buffer-drawing_test.zig +3237 -0
  403. package/src/zig/tests/text-buffer-highlights_test.zig +666 -0
  404. package/src/zig/tests/text-buffer-iterators_test.zig +776 -0
  405. package/src/zig/tests/text-buffer-segment_test.zig +320 -0
  406. package/src/zig/tests/text-buffer-selection_test.zig +1035 -0
  407. package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
  408. package/src/zig/tests/text-buffer-view_test.zig +3649 -0
  409. package/src/zig/tests/text-buffer_test.zig +2191 -0
  410. package/src/zig/tests/unicode-width-map.zon +3909 -0
  411. package/src/zig/tests/utf8_no_zwj_test.zig +260 -0
  412. package/src/zig/tests/utf8_test.zig +4057 -0
  413. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +267 -0
  414. package/src/zig/tests/utf8_wcwidth_test.zig +357 -0
  415. package/src/zig/tests/word-wrap-editing_test.zig +498 -0
  416. package/src/zig/tests/wrap-cache-perf_test.zig +113 -0
  417. package/src/zig/text-buffer-iterators.zig +499 -0
  418. package/src/zig/text-buffer-segment.zig +404 -0
  419. package/src/zig/text-buffer-view.zig +1371 -0
  420. package/src/zig/text-buffer.zig +1180 -0
  421. package/src/zig/utf8.zig +1948 -0
  422. package/src/zig/utils.zig +9 -0
  423. package/src/zig-structs.ts +261 -0
  424. package/src/zig.ts +3843 -0
  425. package/tsconfig.build.json +22 -0
  426. package/tsconfig.json +28 -0
  427. package/3d/SpriteResourceManager.d.ts +0 -74
  428. package/3d/SpriteUtils.d.ts +0 -13
  429. package/3d/TextureUtils.d.ts +0 -24
  430. package/3d/ThreeRenderable.d.ts +0 -40
  431. package/3d/WGPURenderer.d.ts +0 -61
  432. package/3d/animation/ExplodingSpriteEffect.d.ts +0 -71
  433. package/3d/animation/PhysicsExplodingSpriteEffect.d.ts +0 -76
  434. package/3d/animation/SpriteAnimator.d.ts +0 -124
  435. package/3d/animation/SpriteParticleGenerator.d.ts +0 -62
  436. package/3d/canvas.d.ts +0 -44
  437. package/3d/index.d.ts +0 -12
  438. package/3d/physics/PlanckPhysicsAdapter.d.ts +0 -19
  439. package/3d/physics/RapierPhysicsAdapter.d.ts +0 -19
  440. package/3d/physics/physics-interface.d.ts +0 -27
  441. package/3d.d.ts +0 -2
  442. package/3d.js +0 -34042
  443. package/3d.js.map +0 -155
  444. package/LICENSE +0 -21
  445. package/NativeSpanFeed.d.ts +0 -41
  446. package/Renderable.d.ts +0 -334
  447. package/animation/Timeline.d.ts +0 -126
  448. package/ansi.d.ts +0 -13
  449. package/buffer.d.ts +0 -107
  450. package/console.d.ts +0 -143
  451. package/edit-buffer.d.ts +0 -98
  452. package/editor-view.d.ts +0 -73
  453. package/index-e4hzc2j2.js +0 -113
  454. package/index-e4hzc2j2.js.map +0 -10
  455. package/index-nkrr8a4c.js +0 -18415
  456. package/index-nkrr8a4c.js.map +0 -64
  457. package/index-nyw5p3ep.js +0 -12619
  458. package/index-nyw5p3ep.js.map +0 -43
  459. package/index.d.ts +0 -21
  460. package/index.js +0 -430
  461. package/index.js.map +0 -9
  462. package/lib/KeyHandler.d.ts +0 -61
  463. package/lib/RGBA.d.ts +0 -25
  464. package/lib/ascii.font.d.ts +0 -508
  465. package/lib/border.d.ts +0 -49
  466. package/lib/bunfs.d.ts +0 -7
  467. package/lib/clipboard.d.ts +0 -17
  468. package/lib/clock.d.ts +0 -15
  469. package/lib/data-paths.d.ts +0 -26
  470. package/lib/debounce.d.ts +0 -42
  471. package/lib/detect-links.d.ts +0 -6
  472. package/lib/env.d.ts +0 -42
  473. package/lib/extmarks-history.d.ts +0 -17
  474. package/lib/extmarks.d.ts +0 -89
  475. package/lib/hast-styled-text.d.ts +0 -17
  476. package/lib/index.d.ts +0 -21
  477. package/lib/keymapping.d.ts +0 -25
  478. package/lib/objects-in-viewport.d.ts +0 -24
  479. package/lib/output.capture.d.ts +0 -24
  480. package/lib/parse.keypress-kitty.d.ts +0 -2
  481. package/lib/parse.keypress.d.ts +0 -26
  482. package/lib/parse.mouse.d.ts +0 -30
  483. package/lib/paste.d.ts +0 -7
  484. package/lib/queue.d.ts +0 -15
  485. package/lib/renderable.validations.d.ts +0 -12
  486. package/lib/scroll-acceleration.d.ts +0 -43
  487. package/lib/selection.d.ts +0 -63
  488. package/lib/singleton.d.ts +0 -7
  489. package/lib/stdin-parser.d.ts +0 -76
  490. package/lib/styled-text.d.ts +0 -63
  491. package/lib/terminal-capability-detection.d.ts +0 -30
  492. package/lib/terminal-palette.d.ts +0 -50
  493. package/lib/tree-sitter/assets/update.d.ts +0 -11
  494. package/lib/tree-sitter/client.d.ts +0 -47
  495. package/lib/tree-sitter/default-parsers.d.ts +0 -2
  496. package/lib/tree-sitter/download-utils.d.ts +0 -21
  497. package/lib/tree-sitter/index.d.ts +0 -8
  498. package/lib/tree-sitter/parser.worker.d.ts +0 -1
  499. package/lib/tree-sitter/parsers-config.d.ts +0 -38
  500. package/lib/tree-sitter/resolve-ft.d.ts +0 -2
  501. package/lib/tree-sitter/types.d.ts +0 -81
  502. package/lib/tree-sitter-styled-text.d.ts +0 -14
  503. package/lib/validate-dir-name.d.ts +0 -1
  504. package/lib/yoga.options.d.ts +0 -32
  505. package/parser.worker.js +0 -869
  506. package/parser.worker.js.map +0 -12
  507. package/plugins/core-slot.d.ts +0 -72
  508. package/plugins/registry.d.ts +0 -38
  509. package/plugins/types.d.ts +0 -34
  510. package/post/filters.d.ts +0 -105
  511. package/renderables/ASCIIFont.d.ts +0 -52
  512. package/renderables/Box.d.ts +0 -72
  513. package/renderables/Code.d.ts +0 -78
  514. package/renderables/Diff.d.ts +0 -142
  515. package/renderables/EditBufferRenderable.d.ts +0 -162
  516. package/renderables/FrameBuffer.d.ts +0 -16
  517. package/renderables/Input.d.ts +0 -67
  518. package/renderables/LineNumberRenderable.d.ts +0 -74
  519. package/renderables/Markdown.d.ts +0 -173
  520. package/renderables/ScrollBar.d.ts +0 -77
  521. package/renderables/ScrollBox.d.ts +0 -124
  522. package/renderables/Select.d.ts +0 -115
  523. package/renderables/Slider.d.ts +0 -44
  524. package/renderables/TabSelect.d.ts +0 -96
  525. package/renderables/Text.d.ts +0 -36
  526. package/renderables/TextBufferRenderable.d.ts +0 -105
  527. package/renderables/TextNode.d.ts +0 -91
  528. package/renderables/TextTable.d.ts +0 -140
  529. package/renderables/Textarea.d.ts +0 -114
  530. package/renderables/TimeToFirstDraw.d.ts +0 -24
  531. package/renderables/__tests__/renderable-test-utils.d.ts +0 -12
  532. package/renderables/composition/VRenderable.d.ts +0 -16
  533. package/renderables/composition/constructs.d.ts +0 -35
  534. package/renderables/composition/vnode.d.ts +0 -46
  535. package/renderables/index.d.ts +0 -22
  536. package/renderables/markdown-parser.d.ts +0 -10
  537. package/renderer.d.ts +0 -388
  538. package/runtime-plugin-support.d.ts +0 -3
  539. package/runtime-plugin-support.js +0 -29
  540. package/runtime-plugin-support.js.map +0 -10
  541. package/runtime-plugin.d.ts +0 -11
  542. package/runtime-plugin.js +0 -16
  543. package/runtime-plugin.js.map +0 -9
  544. package/syntax-style.d.ts +0 -54
  545. package/testing/manual-clock.d.ts +0 -16
  546. package/testing/mock-keys.d.ts +0 -81
  547. package/testing/mock-mouse.d.ts +0 -38
  548. package/testing/mock-tree-sitter-client.d.ts +0 -23
  549. package/testing/spy.d.ts +0 -7
  550. package/testing/test-recorder.d.ts +0 -61
  551. package/testing/test-renderer.d.ts +0 -23
  552. package/testing.d.ts +0 -6
  553. package/testing.js +0 -675
  554. package/testing.js.map +0 -15
  555. package/text-buffer-view.d.ts +0 -42
  556. package/text-buffer.d.ts +0 -67
  557. package/types.d.ts +0 -131
  558. package/utils.d.ts +0 -14
  559. package/zig-structs.d.ts +0 -155
  560. package/zig.d.ts +0 -351
  561. /package/{assets → src/lib/tree-sitter/assets}/javascript/highlights.scm +0 -0
  562. /package/{assets → src/lib/tree-sitter/assets}/javascript/tree-sitter-javascript.wasm +0 -0
  563. /package/{assets → src/lib/tree-sitter/assets}/markdown/highlights.scm +0 -0
  564. /package/{assets → src/lib/tree-sitter/assets}/markdown/injections.scm +0 -0
  565. /package/{assets → src/lib/tree-sitter/assets}/markdown/tree-sitter-markdown.wasm +0 -0
  566. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/highlights.scm +0 -0
  567. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  568. /package/{assets → src/lib/tree-sitter/assets}/typescript/highlights.scm +0 -0
  569. /package/{assets → src/lib/tree-sitter/assets}/typescript/tree-sitter-typescript.wasm +0 -0
  570. /package/{assets → src/lib/tree-sitter/assets}/zig/highlights.scm +0 -0
  571. /package/{assets → src/lib/tree-sitter/assets}/zig/tree-sitter-zig.wasm +0 -0
@@ -0,0 +1,123 @@
1
+ import { test, expect, beforeEach, afterEach, describe } from "bun:test"
2
+ import { Renderable, type RenderableOptions } from "../Renderable.js"
3
+ import { createTestRenderer, type TestRenderer } from "../testing/test-renderer.js"
4
+ import type { RenderContext } from "../types.js"
5
+
6
+ class TestRenderable extends Renderable {
7
+ constructor(ctx: RenderContext, options: RenderableOptions) {
8
+ super(ctx, options)
9
+ }
10
+ }
11
+
12
+ let testRenderer: TestRenderer
13
+ let renderOnce: () => Promise<void>
14
+
15
+ beforeEach(async () => {
16
+ ;({ renderer: testRenderer, renderOnce } = await createTestRenderer({}))
17
+ })
18
+
19
+ afterEach(() => {
20
+ testRenderer.destroy()
21
+ })
22
+
23
+ describe("Renderable - Opacity", () => {
24
+ test("defaults to 1.0", () => {
25
+ const renderable = new TestRenderable(testRenderer, { id: "test-opacity" })
26
+ expect(renderable.opacity).toBe(1.0)
27
+ })
28
+
29
+ test("accepts opacity in constructor options", () => {
30
+ const renderable = new TestRenderable(testRenderer, {
31
+ id: "test-opacity-options",
32
+ opacity: 0.5,
33
+ })
34
+ expect(renderable.opacity).toBe(0.5)
35
+ })
36
+
37
+ test("clamps opacity to 0-1 range via setter", () => {
38
+ const renderable = new TestRenderable(testRenderer, { id: "test-clamp" })
39
+
40
+ renderable.opacity = 1.5
41
+ expect(renderable.opacity).toBe(1.0)
42
+
43
+ renderable.opacity = -0.5
44
+ expect(renderable.opacity).toBe(0.0)
45
+
46
+ renderable.opacity = 0.7
47
+ expect(renderable.opacity).toBe(0.7)
48
+ })
49
+
50
+ test("clamps opacity from constructor options", () => {
51
+ const r1 = new TestRenderable(testRenderer, {
52
+ id: "test-clamp-high",
53
+ opacity: 2.0,
54
+ })
55
+ expect(r1.opacity).toBe(1.0)
56
+
57
+ const r2 = new TestRenderable(testRenderer, {
58
+ id: "test-clamp-low",
59
+ opacity: -1,
60
+ })
61
+ expect(r2.opacity).toBe(0.0)
62
+ })
63
+
64
+ test("handles opacity of 0 (fully transparent)", async () => {
65
+ const renderable = new TestRenderable(testRenderer, {
66
+ id: "invisible",
67
+ width: 10,
68
+ height: 5,
69
+ opacity: 0,
70
+ })
71
+ testRenderer.root.add(renderable)
72
+
73
+ expect(renderable.opacity).toBe(0)
74
+
75
+ // Render should not crash with zero opacity
76
+ await renderOnce()
77
+ })
78
+
79
+ test("nested renderables maintain independent opacity values", async () => {
80
+ const parent = new TestRenderable(testRenderer, {
81
+ id: "parent",
82
+ width: 20,
83
+ height: 10,
84
+ opacity: 0.5,
85
+ })
86
+
87
+ const child = new TestRenderable(testRenderer, {
88
+ id: "child",
89
+ width: 10,
90
+ height: 5,
91
+ opacity: 0.8,
92
+ })
93
+
94
+ parent.add(child)
95
+ testRenderer.root.add(parent)
96
+ await renderOnce()
97
+
98
+ expect(parent.opacity).toBe(0.5)
99
+ expect(child.opacity).toBe(0.8)
100
+ })
101
+
102
+ test("opacity changes trigger render request", () => {
103
+ const renderable = new TestRenderable(testRenderer, { id: "test-render" })
104
+ testRenderer.root.add(renderable)
105
+
106
+ const initialOpacity = renderable.opacity
107
+ renderable.opacity = 0.3
108
+
109
+ expect(renderable.opacity).not.toBe(initialOpacity)
110
+ expect(renderable.opacity).toBe(0.3)
111
+ })
112
+
113
+ test("setting same opacity value does not update", () => {
114
+ const renderable = new TestRenderable(testRenderer, {
115
+ id: "test-same",
116
+ opacity: 0.5,
117
+ })
118
+
119
+ // Set to same value - should not trigger change
120
+ renderable.opacity = 0.5
121
+ expect(renderable.opacity).toBe(0.5)
122
+ })
123
+ })
@@ -0,0 +1,524 @@
1
+ import { test, expect, beforeEach, afterEach, describe } from "bun:test"
2
+ import { createTestRenderer, type TestRenderer } from "../testing/test-renderer.js"
3
+ import { BoxRenderable } from "../renderables/Box.js"
4
+ import { TextRenderable } from "../renderables/Text.js"
5
+
6
+ let testRenderer: TestRenderer
7
+ let renderOnce: () => Promise<void>
8
+ let captureFrame: () => string
9
+
10
+ beforeEach(async () => {
11
+ ;({
12
+ renderer: testRenderer,
13
+ renderOnce,
14
+ captureCharFrame: captureFrame,
15
+ } = await createTestRenderer({
16
+ width: 10,
17
+ height: 5,
18
+ }))
19
+ })
20
+
21
+ afterEach(() => {
22
+ testRenderer.destroy()
23
+ })
24
+
25
+ describe("Renderable - insertBefore", () => {
26
+ test("reproduces insertBefore behavior with state change after timeout", async () => {
27
+ const container = new BoxRenderable(testRenderer, {
28
+ id: "container",
29
+ width: 10,
30
+ height: 5,
31
+ })
32
+
33
+ const bananaText = new TextRenderable(testRenderer, {
34
+ id: "banana",
35
+ content: "banana",
36
+ })
37
+
38
+ const appleText = new TextRenderable(testRenderer, {
39
+ id: "apple",
40
+ content: "apple",
41
+ })
42
+
43
+ const pearText = new TextRenderable(testRenderer, {
44
+ id: "pear",
45
+ content: "pear",
46
+ })
47
+
48
+ const separator = new BoxRenderable(testRenderer, {
49
+ id: "separator",
50
+ width: 20,
51
+ height: 1,
52
+ })
53
+
54
+ container.add(bananaText)
55
+ container.add(appleText)
56
+ container.add(pearText)
57
+ container.add(separator)
58
+
59
+ testRenderer.root.add(container)
60
+ await renderOnce()
61
+
62
+ const initialFrame = captureFrame()
63
+ expect(initialFrame).toMatchSnapshot("insertBefore initial state")
64
+
65
+ await new Promise((resolve) => setTimeout(resolve, 100))
66
+
67
+ container.insertBefore(appleText, separator)
68
+
69
+ await renderOnce()
70
+
71
+ const reorderedFrame = captureFrame()
72
+ expect(reorderedFrame).toMatchSnapshot("insertBefore reordered state")
73
+ })
74
+
75
+ test("ensure .add with index works correctly", async () => {
76
+ const container = new BoxRenderable(testRenderer, {
77
+ id: "container",
78
+ width: 20,
79
+ height: 10,
80
+ })
81
+
82
+ // Create 5 text renderables in order
83
+ const items = [
84
+ new TextRenderable(testRenderer, { id: "order-1", content: "First" }),
85
+ new TextRenderable(testRenderer, { id: "order-2", content: "Second" }),
86
+ new TextRenderable(testRenderer, { id: "order-3", content: "Third" }),
87
+ new TextRenderable(testRenderer, { id: "order-4", content: "Fourth" }),
88
+ new TextRenderable(testRenderer, { id: "order-5", content: "Fifth" }),
89
+ ]
90
+
91
+ // Add items in initial order [1, 2, 3, 4, 5]
92
+ for (const item of items) {
93
+ container.add(item)
94
+ }
95
+
96
+ testRenderer.root.add(container)
97
+ await renderOnce()
98
+
99
+ let children = container.getChildren()
100
+
101
+ expect(children.length).toBe(5)
102
+ expect(children[0]?.id).toBe("order-1")
103
+ expect(children[1]?.id).toBe("order-2")
104
+ expect(children[2]?.id).toBe("order-3")
105
+ expect(children[3]?.id).toBe("order-4")
106
+ expect(children[4]?.id).toBe("order-5")
107
+
108
+ // Reproduce the EXACT sequence from SolidJS reconciler output:
109
+ container.add(items[4]!, 1) // order-5 at index 1
110
+ container.add(items[0]!) // order-1 at index undefined
111
+ container.add(items[3]!, 2) // order-4 at index 2
112
+ container.add(items[1]!, 4) // order-2 at index 4
113
+
114
+ await renderOnce()
115
+
116
+ children = container.getChildren()
117
+
118
+ // Expected: [5, 4, 3, 2, 1]
119
+ expect(children.length).toBe(5)
120
+ expect(children[0]?.id).toBe("order-5")
121
+ expect(children[1]?.id).toBe("order-4")
122
+ expect(children[2]?.id).toBe("order-3")
123
+ expect(children[3]?.id).toBe("order-2")
124
+ expect(children[4]?.id).toBe("order-1")
125
+ })
126
+ })
127
+
128
+ describe("Renderable - add method", () => {
129
+ test("basic add appends to end", async () => {
130
+ const container = new BoxRenderable(testRenderer, {
131
+ id: "container",
132
+ width: 10,
133
+ height: 10,
134
+ })
135
+
136
+ const item1 = new TextRenderable(testRenderer, { id: "item-1", content: "A" })
137
+ const item2 = new TextRenderable(testRenderer, { id: "item-2", content: "B" })
138
+ const item3 = new TextRenderable(testRenderer, { id: "item-3", content: "C" })
139
+
140
+ container.add(item1)
141
+ container.add(item2)
142
+ container.add(item3)
143
+
144
+ const children = container.getChildren()
145
+ expect(children.length).toBe(3)
146
+ expect(children[0]?.id).toBe("item-1")
147
+ expect(children[1]?.id).toBe("item-2")
148
+ expect(children[2]?.id).toBe("item-3")
149
+ })
150
+
151
+ test("add with index 0 inserts at beginning", async () => {
152
+ const container = new BoxRenderable(testRenderer, {
153
+ id: "container",
154
+ width: 10,
155
+ height: 10,
156
+ })
157
+
158
+ const item1 = new TextRenderable(testRenderer, { id: "item-1", content: "A" })
159
+ const item2 = new TextRenderable(testRenderer, { id: "item-2", content: "B" })
160
+ const item3 = new TextRenderable(testRenderer, { id: "item-3", content: "C" })
161
+
162
+ container.add(item1)
163
+ container.add(item2)
164
+ container.add(item3, 0) // Insert at beginning
165
+
166
+ const children = container.getChildren()
167
+ expect(children.length).toBe(3)
168
+ expect(children[0]?.id).toBe("item-3")
169
+ expect(children[1]?.id).toBe("item-1")
170
+ expect(children[2]?.id).toBe("item-2")
171
+ })
172
+
173
+ test("add with middle index inserts correctly", async () => {
174
+ const container = new BoxRenderable(testRenderer, {
175
+ id: "container",
176
+ width: 10,
177
+ height: 10,
178
+ })
179
+
180
+ const item1 = new TextRenderable(testRenderer, { id: "item-1", content: "A" })
181
+ const item2 = new TextRenderable(testRenderer, { id: "item-2", content: "B" })
182
+ const item3 = new TextRenderable(testRenderer, { id: "item-3", content: "C" })
183
+
184
+ container.add(item1)
185
+ container.add(item2)
186
+ container.add(item3, 1) // Insert in middle
187
+
188
+ const children = container.getChildren()
189
+ expect(children.length).toBe(3)
190
+ expect(children[0]?.id).toBe("item-1")
191
+ expect(children[1]?.id).toBe("item-3")
192
+ expect(children[2]?.id).toBe("item-2")
193
+ })
194
+
195
+ test("add with large index appends to end", async () => {
196
+ const container = new BoxRenderable(testRenderer, {
197
+ id: "container",
198
+ width: 10,
199
+ height: 10,
200
+ })
201
+
202
+ const item1 = new TextRenderable(testRenderer, { id: "item-1", content: "A" })
203
+ const item2 = new TextRenderable(testRenderer, { id: "item-2", content: "B" })
204
+ const item3 = new TextRenderable(testRenderer, { id: "item-3", content: "C" })
205
+
206
+ container.add(item1)
207
+ container.add(item2)
208
+ container.add(item3, 999) // Out of bounds index
209
+
210
+ const children = container.getChildren()
211
+ expect(children.length).toBe(3)
212
+ expect(children[0]?.id).toBe("item-1")
213
+ expect(children[1]?.id).toBe("item-2")
214
+ expect(children[2]?.id).toBe("item-3")
215
+ })
216
+
217
+ test("add returns correct index", async () => {
218
+ const container = new BoxRenderable(testRenderer, {
219
+ id: "container",
220
+ width: 10,
221
+ height: 10,
222
+ })
223
+
224
+ const item1 = new TextRenderable(testRenderer, { id: "item-1", content: "A" })
225
+ const item2 = new TextRenderable(testRenderer, { id: "item-2", content: "B" })
226
+ const item3 = new TextRenderable(testRenderer, { id: "item-3", content: "C" })
227
+
228
+ const idx1 = container.add(item1)
229
+ const idx2 = container.add(item2)
230
+ const idx3 = container.add(item3, 1)
231
+
232
+ expect(idx1).toBe(0)
233
+ expect(idx2).toBe(1)
234
+ expect(idx3).toBe(1) // Inserted at index 1
235
+ })
236
+
237
+ test("add null/undefined returns -1", async () => {
238
+ const container = new BoxRenderable(testRenderer, {
239
+ id: "container",
240
+ width: 10,
241
+ height: 10,
242
+ })
243
+
244
+ const idx1 = container.add(null as any)
245
+ const idx2 = container.add(undefined as any)
246
+
247
+ expect(idx1).toBe(-1)
248
+ expect(idx2).toBe(-1)
249
+ expect(container.getChildrenCount()).toBe(0)
250
+ })
251
+
252
+ test("re-adding existing child moves it", async () => {
253
+ const container = new BoxRenderable(testRenderer, {
254
+ id: "container",
255
+ width: 10,
256
+ height: 10,
257
+ })
258
+
259
+ const item1 = new TextRenderable(testRenderer, { id: "item-1", content: "A" })
260
+ const item2 = new TextRenderable(testRenderer, { id: "item-2", content: "B" })
261
+ const item3 = new TextRenderable(testRenderer, { id: "item-3", content: "C" })
262
+
263
+ container.add(item1)
264
+ container.add(item2)
265
+ container.add(item3)
266
+
267
+ // Re-add item1 to end
268
+ container.add(item1)
269
+
270
+ let children = container.getChildren()
271
+ expect(children.length).toBe(3)
272
+ expect(children[0]?.id).toBe("item-2")
273
+ expect(children[1]?.id).toBe("item-3")
274
+ expect(children[2]?.id).toBe("item-1")
275
+
276
+ // Re-add item3 to beginning
277
+ container.add(item3, 0)
278
+
279
+ children = container.getChildren()
280
+ expect(children.length).toBe(3)
281
+ expect(children[0]?.id).toBe("item-3")
282
+ expect(children[1]?.id).toBe("item-2")
283
+ expect(children[2]?.id).toBe("item-1")
284
+ })
285
+
286
+ test("adding child from another parent removes it from old parent", async () => {
287
+ const container1 = new BoxRenderable(testRenderer, {
288
+ id: "container-1",
289
+ width: 10,
290
+ height: 10,
291
+ })
292
+
293
+ const container2 = new BoxRenderable(testRenderer, {
294
+ id: "container-2",
295
+ width: 10,
296
+ height: 10,
297
+ })
298
+
299
+ const item = new TextRenderable(testRenderer, { id: "item", content: "A" })
300
+
301
+ container1.add(item)
302
+ expect(container1.getChildrenCount()).toBe(1)
303
+ expect(item.parent).toBe(container1)
304
+
305
+ container2.add(item)
306
+ expect(container1.getChildrenCount()).toBe(0)
307
+ expect(container2.getChildrenCount()).toBe(1)
308
+ expect(item.parent).toBe(container2)
309
+ })
310
+ })
311
+
312
+ describe("Renderable - insertBefore method", () => {
313
+ test("insertBefore with null anchor appends to end", async () => {
314
+ const container = new BoxRenderable(testRenderer, {
315
+ id: "container",
316
+ width: 10,
317
+ height: 10,
318
+ })
319
+
320
+ const item1 = new TextRenderable(testRenderer, { id: "item-1", content: "A" })
321
+ const item2 = new TextRenderable(testRenderer, { id: "item-2", content: "B" })
322
+ const item3 = new TextRenderable(testRenderer, { id: "item-3", content: "C" })
323
+
324
+ container.add(item1)
325
+ container.add(item2)
326
+ container.insertBefore(item3, null as any)
327
+
328
+ const children = container.getChildren()
329
+ expect(children.length).toBe(3)
330
+ expect(children[2]?.id).toBe("item-3")
331
+ })
332
+
333
+ test("insertBefore inserts at correct position", async () => {
334
+ const container = new BoxRenderable(testRenderer, {
335
+ id: "container",
336
+ width: 10,
337
+ height: 10,
338
+ })
339
+
340
+ const item1 = new TextRenderable(testRenderer, { id: "item-1", content: "A" })
341
+ const item2 = new TextRenderable(testRenderer, { id: "item-2", content: "B" })
342
+ const item3 = new TextRenderable(testRenderer, { id: "item-3", content: "C" })
343
+
344
+ container.add(item1)
345
+ container.add(item3)
346
+ container.insertBefore(item2, item3) // Insert item2 before item3
347
+
348
+ const children = container.getChildren()
349
+ expect(children.length).toBe(3)
350
+ expect(children[0]?.id).toBe("item-1")
351
+ expect(children[1]?.id).toBe("item-2")
352
+ expect(children[2]?.id).toBe("item-3")
353
+ })
354
+
355
+ test("insertBefore at beginning", async () => {
356
+ const container = new BoxRenderable(testRenderer, {
357
+ id: "container",
358
+ width: 10,
359
+ height: 10,
360
+ })
361
+
362
+ const item1 = new TextRenderable(testRenderer, { id: "item-1", content: "A" })
363
+ const item2 = new TextRenderable(testRenderer, { id: "item-2", content: "B" })
364
+ const item3 = new TextRenderable(testRenderer, { id: "item-3", content: "C" })
365
+
366
+ container.add(item1)
367
+ container.add(item2)
368
+ container.insertBefore(item3, item1) // Insert before first item
369
+
370
+ const children = container.getChildren()
371
+ expect(children.length).toBe(3)
372
+ expect(children[0]?.id).toBe("item-3")
373
+ expect(children[1]?.id).toBe("item-1")
374
+ expect(children[2]?.id).toBe("item-2")
375
+ })
376
+
377
+ test("insertBefore moves existing child", async () => {
378
+ const container = new BoxRenderable(testRenderer, {
379
+ id: "container",
380
+ width: 10,
381
+ height: 10,
382
+ })
383
+
384
+ const item1 = new TextRenderable(testRenderer, { id: "item-1", content: "A" })
385
+ const item2 = new TextRenderable(testRenderer, { id: "item-2", content: "B" })
386
+ const item3 = new TextRenderable(testRenderer, { id: "item-3", content: "C" })
387
+
388
+ container.add(item1)
389
+ container.add(item2)
390
+ container.add(item3)
391
+
392
+ // Move item3 before item1
393
+ container.insertBefore(item3, item1)
394
+
395
+ let children = container.getChildren()
396
+ expect(children.length).toBe(3)
397
+ expect(children[0]?.id).toBe("item-3")
398
+ expect(children[1]?.id).toBe("item-1")
399
+ expect(children[2]?.id).toBe("item-2")
400
+
401
+ // Move item1 before item2
402
+ container.insertBefore(item1, item2)
403
+
404
+ children = container.getChildren()
405
+ expect(children.length).toBe(3)
406
+ expect(children[0]?.id).toBe("item-3")
407
+ expect(children[1]?.id).toBe("item-1")
408
+ expect(children[2]?.id).toBe("item-2")
409
+ })
410
+
411
+ test("insertBefore with invalid anchor returns -1", async () => {
412
+ const container = new BoxRenderable(testRenderer, {
413
+ id: "container",
414
+ width: 10,
415
+ height: 10,
416
+ })
417
+
418
+ const item1 = new TextRenderable(testRenderer, { id: "item-1", content: "A" })
419
+ const item2 = new TextRenderable(testRenderer, { id: "item-2", content: "B" })
420
+ const notAChild = new TextRenderable(testRenderer, { id: "not-child", content: "X" })
421
+
422
+ container.add(item1)
423
+
424
+ expect(container.insertBefore(item2, notAChild)).toBe(-1)
425
+ })
426
+
427
+ test("insertBefore returns correct index", async () => {
428
+ const container = new BoxRenderable(testRenderer, {
429
+ id: "container",
430
+ width: 10,
431
+ height: 10,
432
+ })
433
+
434
+ const item1 = new TextRenderable(testRenderer, { id: "item-1", content: "A" })
435
+ const item2 = new TextRenderable(testRenderer, { id: "item-2", content: "B" })
436
+ const item3 = new TextRenderable(testRenderer, { id: "item-3", content: "C" })
437
+
438
+ container.add(item1)
439
+ container.add(item3)
440
+
441
+ const idx = container.insertBefore(item2, item3)
442
+ expect(idx).toBe(1)
443
+ })
444
+
445
+ test("insertBefore with null object returns -1", async () => {
446
+ const container = new BoxRenderable(testRenderer, {
447
+ id: "container",
448
+ width: 10,
449
+ height: 10,
450
+ })
451
+
452
+ const anchor = new TextRenderable(testRenderer, { id: "anchor", content: "A" })
453
+ container.add(anchor)
454
+
455
+ const idx = container.insertBefore(null as any, anchor)
456
+ expect(idx).toBe(-1)
457
+ })
458
+
459
+ test("complex reordering scenario", async () => {
460
+ const container = new BoxRenderable(testRenderer, {
461
+ id: "container",
462
+ width: 10,
463
+ height: 10,
464
+ })
465
+
466
+ const items = [
467
+ new TextRenderable(testRenderer, { id: "A", content: "A" }),
468
+ new TextRenderable(testRenderer, { id: "B", content: "B" }),
469
+ new TextRenderable(testRenderer, { id: "C", content: "C" }),
470
+ new TextRenderable(testRenderer, { id: "D", content: "D" }),
471
+ new TextRenderable(testRenderer, { id: "E", content: "E" }),
472
+ ]
473
+
474
+ // Initial: A, B, C, D, E
475
+ items.forEach((item) => container.add(item))
476
+
477
+ let children = container.getChildren()
478
+ expect(children.map((c) => c.id)).toEqual(["A", "B", "C", "D", "E"])
479
+
480
+ // Move E before B: A, E, B, C, D
481
+ container.insertBefore(items[4]!, items[1]!)
482
+ children = container.getChildren()
483
+ expect(children.map((c) => c.id)).toEqual(["A", "E", "B", "C", "D"])
484
+
485
+ // Move A before D: E, B, C, A, D
486
+ container.insertBefore(items[0]!, items[3]!)
487
+ children = container.getChildren()
488
+ expect(children.map((c) => c.id)).toEqual(["E", "B", "C", "A", "D"])
489
+
490
+ // Move C before E: C, E, B, A, D
491
+ container.insertBefore(items[2]!, items[4]!)
492
+ children = container.getChildren()
493
+ expect(children.map((c) => c.id)).toEqual(["C", "E", "B", "A", "D"])
494
+ })
495
+
496
+ test("multiple sequential adds and inserts", async () => {
497
+ const container = new BoxRenderable(testRenderer, {
498
+ id: "container",
499
+ width: 10,
500
+ height: 10,
501
+ })
502
+
503
+ const items = [
504
+ new TextRenderable(testRenderer, { id: "1", content: "1" }),
505
+ new TextRenderable(testRenderer, { id: "2", content: "2" }),
506
+ new TextRenderable(testRenderer, { id: "3", content: "3" }),
507
+ new TextRenderable(testRenderer, { id: "4", content: "4" }),
508
+ ]
509
+
510
+ container.add(items[0]!)
511
+ container.add(items[1]!)
512
+ expect(container.getChildren().map((c) => c.id)).toEqual(["1", "2"])
513
+
514
+ container.insertBefore(items[2]!, items[1]!)
515
+ expect(container.getChildren().map((c) => c.id)).toEqual(["1", "3", "2"])
516
+
517
+ container.add(items[3]!, 0)
518
+ expect(container.getChildren().map((c) => c.id)).toEqual(["4", "1", "3", "2"])
519
+
520
+ // Move "2" before "4"
521
+ container.insertBefore(items[1]!, items[3]!)
522
+ expect(container.getChildren().map((c) => c.id)).toEqual(["2", "4", "1", "3"])
523
+ })
524
+ })