@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.
- package/README.md +2 -2
- package/dev/keypress-debug-renderer.ts +148 -0
- package/dev/keypress-debug.ts +43 -0
- package/dev/print-env-vars.ts +32 -0
- package/dev/test-tmux-graphics-334.sh +68 -0
- package/dev/thai-debug-test.ts +68 -0
- package/docs/development.md +141 -0
- package/docs/env-vars.md +140 -0
- package/docs/getting-started.md +353 -0
- package/docs/renderables-vs-constructs.md +159 -0
- package/docs/tree-sitter.md +311 -0
- package/package.json +61 -52
- package/scripts/build.ts +400 -0
- package/scripts/publish.ts +60 -0
- package/src/3d/SpriteResourceManager.ts +286 -0
- package/src/3d/SpriteUtils.ts +71 -0
- package/src/3d/TextureUtils.ts +196 -0
- package/src/3d/ThreeRenderable.ts +197 -0
- package/src/3d/WGPURenderer.ts +294 -0
- package/src/3d/animation/ExplodingSpriteEffect.ts +513 -0
- package/src/3d/animation/PhysicsExplodingSpriteEffect.ts +429 -0
- package/src/3d/animation/SpriteAnimator.ts +633 -0
- package/src/3d/animation/SpriteParticleGenerator.ts +435 -0
- package/src/3d/canvas.ts +464 -0
- package/src/3d/index.ts +12 -0
- package/src/3d/physics/PlanckPhysicsAdapter.ts +72 -0
- package/src/3d/physics/RapierPhysicsAdapter.ts +66 -0
- package/src/3d/physics/physics-interface.ts +31 -0
- package/src/3d/shaders/supersampling.wgsl +201 -0
- package/src/3d.ts +3 -0
- package/src/NativeSpanFeed.ts +300 -0
- package/src/Renderable.ts +1698 -0
- package/src/__snapshots__/buffer.test.ts.snap +28 -0
- package/src/animation/Timeline.test.ts +2709 -0
- package/src/animation/Timeline.ts +598 -0
- package/src/ansi.ts +18 -0
- package/src/benchmark/latest-all-bench-run.json +707 -0
- package/src/benchmark/latest-async-bench-run.json +336 -0
- package/src/benchmark/latest-default-bench-run.json +657 -0
- package/src/benchmark/latest-large-bench-run.json +707 -0
- package/src/benchmark/latest-quick-bench-run.json +207 -0
- package/src/benchmark/markdown-benchmark.ts +1804 -0
- package/src/benchmark/native-span-feed-async-benchmark.ts +355 -0
- package/src/benchmark/native-span-feed-benchmark.md +56 -0
- package/src/benchmark/native-span-feed-benchmark.ts +596 -0
- package/src/benchmark/native-span-feed-compare.ts +280 -0
- package/src/benchmark/renderer-benchmark.ts +754 -0
- package/src/benchmark/text-table-benchmark.ts +947 -0
- package/src/buffer.test.ts +291 -0
- package/src/buffer.ts +519 -0
- package/src/console.test.ts +612 -0
- package/src/console.ts +1255 -0
- package/src/edit-buffer.test.ts +1769 -0
- package/src/edit-buffer.ts +411 -0
- package/src/editor-view.test.ts +1032 -0
- package/src/editor-view.ts +284 -0
- package/src/examples/ascii-font-selection-demo.ts +245 -0
- package/src/examples/assets/Water_2_M_Normal.jpg +0 -0
- package/src/examples/assets/concrete.png +0 -0
- package/src/examples/assets/crate.png +0 -0
- package/src/examples/assets/crate_emissive.png +0 -0
- package/src/examples/assets/forrest_background.png +0 -0
- package/src/examples/assets/hast-example.json +1018 -0
- package/src/examples/assets/heart.png +0 -0
- package/src/examples/assets/main_char_heavy_attack.png +0 -0
- package/src/examples/assets/main_char_idle.png +0 -0
- package/src/examples/assets/main_char_jump_end.png +0 -0
- package/src/examples/assets/main_char_jump_landing.png +0 -0
- package/src/examples/assets/main_char_jump_start.png +0 -0
- package/src/examples/assets/main_char_run_loop.png +0 -0
- package/src/examples/assets/roughness_map.jpg +0 -0
- package/src/examples/build.ts +115 -0
- package/src/examples/code-demo.ts +584 -0
- package/src/examples/console-demo.ts +358 -0
- package/src/examples/core-plugin-slots-demo.ts +759 -0
- package/src/examples/diff-demo.ts +699 -0
- package/src/examples/draggable-three-demo.ts +259 -0
- package/src/examples/editor-demo.ts +322 -0
- package/src/examples/extmarks-demo.ts +204 -0
- package/src/examples/focus-restore-demo.ts +310 -0
- package/src/examples/fonts.ts +245 -0
- package/src/examples/fractal-shader-demo.ts +268 -0
- package/src/examples/framebuffer-demo.ts +674 -0
- package/src/examples/full-unicode-demo.ts +181 -0
- package/src/examples/golden-star-demo.ts +933 -0
- package/src/examples/grayscale-buffer-demo.ts +249 -0
- package/src/examples/hast-syntax-highlighting-demo.ts +129 -0
- package/src/examples/index.ts +925 -0
- package/src/examples/input-demo.ts +377 -0
- package/src/examples/input-select-layout-demo.ts +425 -0
- package/src/examples/install.sh +143 -0
- package/src/examples/keypress-debug-demo.ts +452 -0
- package/src/examples/lib/HexList.ts +122 -0
- package/src/examples/lib/PaletteGrid.ts +125 -0
- package/src/examples/lib/standalone-keys.ts +25 -0
- package/src/examples/lib/tab-controller.ts +243 -0
- package/src/examples/lights-phong-demo.ts +290 -0
- package/src/examples/link-demo.ts +220 -0
- package/src/examples/live-state-demo.ts +480 -0
- package/src/examples/markdown-demo.ts +620 -0
- package/src/examples/mouse-interaction-demo.ts +428 -0
- package/src/examples/nested-zindex-demo.ts +357 -0
- package/src/examples/opacity-example.ts +235 -0
- package/src/examples/opentui-demo.ts +1057 -0
- package/src/examples/physx-planck-2d-demo.ts +507 -0
- package/src/examples/physx-rapier-2d-demo.ts +526 -0
- package/src/examples/relative-positioning-demo.ts +323 -0
- package/src/examples/scroll-example.ts +214 -0
- package/src/examples/scrollbox-mouse-test.ts +112 -0
- package/src/examples/scrollbox-overlay-hit-test.ts +206 -0
- package/src/examples/select-demo.ts +237 -0
- package/src/examples/shader-cube-demo.ts +772 -0
- package/src/examples/simple-layout-example.ts +591 -0
- package/src/examples/slider-demo.ts +617 -0
- package/src/examples/split-mode-demo.ts +445 -0
- package/src/examples/sprite-animation-demo.ts +443 -0
- package/src/examples/sprite-particle-generator-demo.ts +486 -0
- package/src/examples/static-sprite-demo.ts +193 -0
- package/src/examples/sticky-scroll-example.ts +308 -0
- package/src/examples/styled-text-demo.ts +282 -0
- package/src/examples/tab-select-demo.ts +219 -0
- package/src/examples/terminal-title.ts +29 -0
- package/src/examples/terminal.ts +305 -0
- package/src/examples/text-node-demo.ts +416 -0
- package/src/examples/text-selection-demo.ts +377 -0
- package/src/examples/text-table-demo.ts +503 -0
- package/src/examples/text-truncation-demo.ts +481 -0
- package/src/examples/text-wrap.ts +757 -0
- package/src/examples/texture-loading-demo.ts +259 -0
- package/src/examples/timeline-example.ts +670 -0
- package/src/examples/transparency-demo.ts +241 -0
- package/src/examples/vnode-composition-demo.ts +404 -0
- package/src/index.ts +22 -0
- package/src/lib/KeyHandler.integration.test.ts +292 -0
- package/src/lib/KeyHandler.stopPropagation.test.ts +289 -0
- package/src/lib/KeyHandler.test.ts +662 -0
- package/src/lib/KeyHandler.ts +222 -0
- package/src/lib/RGBA.test.ts +984 -0
- package/src/lib/RGBA.ts +204 -0
- package/src/lib/ascii.font.ts +330 -0
- package/src/lib/border.test.ts +83 -0
- package/src/lib/border.ts +168 -0
- package/src/lib/bunfs.test.ts +27 -0
- package/src/lib/bunfs.ts +18 -0
- package/src/lib/clipboard.test.ts +41 -0
- package/src/lib/clipboard.ts +47 -0
- package/src/lib/clock.ts +31 -0
- package/src/lib/data-paths.test.ts +133 -0
- package/src/lib/data-paths.ts +109 -0
- package/src/lib/debounce.ts +106 -0
- package/src/lib/detect-links.test.ts +98 -0
- package/src/lib/detect-links.ts +56 -0
- package/src/lib/env.test.ts +228 -0
- package/src/lib/env.ts +209 -0
- package/src/lib/extmarks-history.ts +51 -0
- package/src/lib/extmarks-multiwidth.test.ts +322 -0
- package/src/lib/extmarks.test.ts +3457 -0
- package/src/lib/extmarks.ts +843 -0
- package/src/lib/fonts/block.json +405 -0
- package/src/lib/fonts/grid.json +265 -0
- package/src/lib/fonts/huge.json +741 -0
- package/src/lib/fonts/pallet.json +314 -0
- package/src/lib/fonts/shade.json +591 -0
- package/src/lib/fonts/slick.json +321 -0
- package/src/lib/fonts/tiny.json +69 -0
- package/src/lib/hast-styled-text.ts +59 -0
- package/src/lib/index.ts +21 -0
- package/src/lib/keymapping.test.ts +280 -0
- package/src/lib/keymapping.ts +87 -0
- package/src/lib/objects-in-viewport.test.ts +787 -0
- package/src/lib/objects-in-viewport.ts +153 -0
- package/src/lib/output.capture.ts +58 -0
- package/src/lib/parse.keypress-kitty.protocol.test.ts +340 -0
- package/src/lib/parse.keypress-kitty.test.ts +663 -0
- package/src/lib/parse.keypress-kitty.ts +439 -0
- package/src/lib/parse.keypress.test.ts +1849 -0
- package/src/lib/parse.keypress.ts +397 -0
- package/src/lib/parse.mouse.test.ts +552 -0
- package/src/lib/parse.mouse.ts +232 -0
- package/src/lib/paste.ts +16 -0
- package/src/lib/queue.ts +65 -0
- package/src/lib/renderable.validations.test.ts +87 -0
- package/src/lib/renderable.validations.ts +83 -0
- package/src/lib/scroll-acceleration.ts +98 -0
- package/src/lib/selection.ts +240 -0
- package/src/lib/singleton.ts +28 -0
- package/src/lib/stdin-parser.test.ts +1676 -0
- package/src/lib/stdin-parser.ts +1248 -0
- package/src/lib/styled-text.ts +178 -0
- package/src/lib/terminal-capability-detection.test.ts +202 -0
- package/src/lib/terminal-capability-detection.ts +79 -0
- package/src/lib/terminal-palette.test.ts +878 -0
- package/src/lib/terminal-palette.ts +383 -0
- package/src/lib/tree-sitter/assets/README.md +118 -0
- package/src/lib/tree-sitter/assets/update.ts +331 -0
- package/src/lib/tree-sitter/assets.d.ts +9 -0
- package/src/lib/tree-sitter/cache.test.ts +270 -0
- package/src/lib/tree-sitter/client.test.ts +1061 -0
- package/src/lib/tree-sitter/client.ts +615 -0
- package/src/lib/tree-sitter/default-parsers.ts +80 -0
- package/src/lib/tree-sitter/download-utils.ts +148 -0
- package/src/lib/tree-sitter/index.ts +28 -0
- package/src/lib/tree-sitter/parser.worker.ts +1001 -0
- package/src/lib/tree-sitter/parsers-config.ts +75 -0
- package/src/lib/tree-sitter/resolve-ft.ts +62 -0
- package/src/lib/tree-sitter/types.ts +81 -0
- package/src/lib/tree-sitter-styled-text.test.ts +1253 -0
- package/src/lib/tree-sitter-styled-text.ts +306 -0
- package/src/lib/validate-dir-name.ts +55 -0
- package/src/lib/yoga.options.test.ts +628 -0
- package/src/lib/yoga.options.ts +346 -0
- package/src/plugins/core-slot.ts +579 -0
- package/src/plugins/registry.ts +377 -0
- package/src/plugins/types.ts +46 -0
- package/src/post/filters.ts +888 -0
- package/src/renderables/ASCIIFont.ts +219 -0
- package/src/renderables/Box.test.ts +160 -0
- package/src/renderables/Box.ts +295 -0
- package/src/renderables/Code.test.ts +2062 -0
- package/src/renderables/Code.ts +357 -0
- package/src/renderables/Diff.regression.test.ts +226 -0
- package/src/renderables/Diff.test.ts +3027 -0
- package/src/renderables/Diff.ts +1209 -0
- package/src/renderables/EditBufferRenderable.ts +764 -0
- package/src/renderables/FrameBuffer.ts +47 -0
- package/src/renderables/Input.test.ts +1228 -0
- package/src/renderables/Input.ts +245 -0
- package/src/renderables/LineNumberRenderable.ts +675 -0
- package/src/renderables/Markdown.ts +1106 -0
- package/src/renderables/ScrollBar.ts +422 -0
- package/src/renderables/ScrollBox.ts +883 -0
- package/src/renderables/Select.test.ts +1010 -0
- package/src/renderables/Select.ts +523 -0
- package/src/renderables/Slider.test.ts +456 -0
- package/src/renderables/Slider.ts +347 -0
- package/src/renderables/TabSelect.test.ts +197 -0
- package/src/renderables/TabSelect.ts +455 -0
- package/src/renderables/Text.selection-buffer.test.ts +123 -0
- package/src/renderables/Text.test.ts +2660 -0
- package/src/renderables/Text.ts +147 -0
- package/src/renderables/TextBufferRenderable.ts +518 -0
- package/src/renderables/TextNode.test.ts +1058 -0
- package/src/renderables/TextNode.ts +325 -0
- package/src/renderables/TextTable.test.ts +1421 -0
- package/src/renderables/TextTable.ts +1344 -0
- package/src/renderables/Textarea.ts +732 -0
- package/src/renderables/TimeToFirstDraw.ts +89 -0
- package/src/renderables/__snapshots__/Code.test.ts.snap +13 -0
- package/src/renderables/__snapshots__/Diff.test.ts.snap +785 -0
- package/src/renderables/__snapshots__/Text.test.ts.snap +421 -0
- package/src/renderables/__snapshots__/TextTable.test.ts.snap +215 -0
- package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
- package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +816 -0
- package/src/renderables/__tests__/LineNumberRenderable.test.ts +1787 -0
- package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
- package/src/renderables/__tests__/Markdown.test.ts +2287 -0
- package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
- package/src/renderables/__tests__/Textarea.buffer.test.ts +682 -0
- package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
- package/src/renderables/__tests__/Textarea.editing.test.ts +2041 -0
- package/src/renderables/__tests__/Textarea.error-handling.test.ts +35 -0
- package/src/renderables/__tests__/Textarea.events.test.ts +738 -0
- package/src/renderables/__tests__/Textarea.highlights.test.ts +590 -0
- package/src/renderables/__tests__/Textarea.keybinding.test.ts +3149 -0
- package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
- package/src/renderables/__tests__/Textarea.rendering.test.ts +1864 -0
- package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
- package/src/renderables/__tests__/Textarea.selection.test.ts +1590 -0
- package/src/renderables/__tests__/Textarea.stress.test.ts +670 -0
- package/src/renderables/__tests__/Textarea.undo-redo.test.ts +383 -0
- package/src/renderables/__tests__/Textarea.visual-lines.test.ts +310 -0
- package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +221 -0
- package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +89 -0
- package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +457 -0
- package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +158 -0
- package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +387 -0
- package/src/renderables/__tests__/markdown-parser.test.ts +217 -0
- package/src/renderables/__tests__/renderable-test-utils.ts +60 -0
- package/src/renderables/composition/README.md +8 -0
- package/src/renderables/composition/VRenderable.ts +32 -0
- package/src/renderables/composition/constructs.ts +127 -0
- package/src/renderables/composition/vnode.ts +289 -0
- package/src/renderables/index.ts +22 -0
- package/src/renderables/markdown-parser.ts +66 -0
- package/src/renderer.ts +2363 -0
- package/src/runtime-plugin-support.ts +39 -0
- package/src/runtime-plugin.ts +144 -0
- package/src/syntax-style.test.ts +841 -0
- package/src/syntax-style.ts +264 -0
- package/src/testing/README.md +210 -0
- package/src/testing/capture-spans.test.ts +194 -0
- package/src/testing/integration.test.ts +276 -0
- package/src/testing/manual-clock.ts +106 -0
- package/src/testing/mock-keys.test.ts +1356 -0
- package/src/testing/mock-keys.ts +449 -0
- package/src/testing/mock-mouse.test.ts +218 -0
- package/src/testing/mock-mouse.ts +247 -0
- package/src/testing/mock-tree-sitter-client.ts +73 -0
- package/src/testing/spy.ts +13 -0
- package/src/testing/test-recorder.test.ts +415 -0
- package/src/testing/test-recorder.ts +145 -0
- package/src/testing/test-renderer.ts +116 -0
- package/src/testing.ts +7 -0
- package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +481 -0
- package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +19 -0
- package/src/tests/__snapshots__/scrollbox.test.ts.snap +29 -0
- package/src/tests/absolute-positioning.snapshot.test.ts +638 -0
- package/src/tests/allocator-stats.test.ts +38 -0
- package/src/tests/destroy-during-render.test.ts +200 -0
- package/src/tests/hover-cursor.test.ts +98 -0
- package/src/tests/native-span-feed-async.test.ts +173 -0
- package/src/tests/native-span-feed-close.test.ts +120 -0
- package/src/tests/native-span-feed-coverage.test.ts +227 -0
- package/src/tests/native-span-feed-edge-cases.test.ts +352 -0
- package/src/tests/native-span-feed-use-after-free.test.ts +45 -0
- package/src/tests/opacity.test.ts +123 -0
- package/src/tests/renderable.snapshot.test.ts +524 -0
- package/src/tests/renderable.test.ts +1281 -0
- package/src/tests/renderer.console-startup.test.ts +65 -0
- package/src/tests/renderer.control.test.ts +364 -0
- package/src/tests/renderer.core-slot-binding.test.ts +952 -0
- package/src/tests/renderer.cursor.test.ts +26 -0
- package/src/tests/renderer.destroy-during-render.test.ts +110 -0
- package/src/tests/renderer.focus-restore.test.ts +228 -0
- package/src/tests/renderer.focus.test.ts +251 -0
- package/src/tests/renderer.idle.test.ts +219 -0
- package/src/tests/renderer.input.test.ts +2145 -0
- package/src/tests/renderer.kitty-flags.test.ts +195 -0
- package/src/tests/renderer.mouse.test.ts +1269 -0
- package/src/tests/renderer.palette.test.ts +629 -0
- package/src/tests/renderer.selection.test.ts +49 -0
- package/src/tests/renderer.slot-registry.test.ts +649 -0
- package/src/tests/renderer.useMouse.test.ts +50 -0
- package/src/tests/runtime-plugin-support.fixture.ts +11 -0
- package/src/tests/runtime-plugin-support.test.ts +28 -0
- package/src/tests/runtime-plugin.fixture.ts +40 -0
- package/src/tests/runtime-plugin.test.ts +190 -0
- package/src/tests/scrollbox-culling-bug.test.ts +114 -0
- package/src/tests/scrollbox-hitgrid-resize.test.ts +136 -0
- package/src/tests/scrollbox-hitgrid.test.ts +909 -0
- package/src/tests/scrollbox.test.ts +1530 -0
- package/src/tests/wrap-resize-perf.test.ts +229 -0
- package/src/tests/yoga-setters.test.ts +921 -0
- package/src/text-buffer-view.test.ts +705 -0
- package/src/text-buffer-view.ts +189 -0
- package/src/text-buffer.test.ts +347 -0
- package/src/text-buffer.ts +250 -0
- package/src/types.ts +152 -0
- package/src/utils.ts +88 -0
- package/src/zig/ansi.zig +268 -0
- package/src/zig/bench/README.md +50 -0
- package/src/zig/bench/buffer-draw-text-buffer_bench.zig +887 -0
- package/src/zig/bench/edit-buffer_bench.zig +476 -0
- package/src/zig/bench/native-span-feed_bench.zig +100 -0
- package/src/zig/bench/rope-markers_bench.zig +713 -0
- package/src/zig/bench/rope_bench.zig +514 -0
- package/src/zig/bench/styled-text_bench.zig +470 -0
- package/src/zig/bench/text-buffer-coords_bench.zig +362 -0
- package/src/zig/bench/text-buffer-view_bench.zig +459 -0
- package/src/zig/bench/text-chunk-graphemes_bench.zig +273 -0
- package/src/zig/bench/utf8_bench.zig +799 -0
- package/src/zig/bench-utils.zig +431 -0
- package/src/zig/bench.zig +217 -0
- package/src/zig/buffer.zig +2223 -0
- package/src/zig/build.zig +289 -0
- package/src/zig/build.zig.zon +16 -0
- package/src/zig/edit-buffer.zig +825 -0
- package/src/zig/editor-view.zig +802 -0
- package/src/zig/event-bus.zig +13 -0
- package/src/zig/event-emitter.zig +65 -0
- package/src/zig/file-logger.zig +92 -0
- package/src/zig/grapheme.zig +599 -0
- package/src/zig/lib.zig +1834 -0
- package/src/zig/link.zig +333 -0
- package/src/zig/logger.zig +43 -0
- package/src/zig/mem-registry.zig +125 -0
- package/src/zig/native-span-feed-bench-lib.zig +7 -0
- package/src/zig/native-span-feed.zig +708 -0
- package/src/zig/renderer.zig +1386 -0
- package/src/zig/rope.zig +1220 -0
- package/src/zig/syntax-style.zig +161 -0
- package/src/zig/terminal.zig +975 -0
- package/src/zig/test.zig +70 -0
- package/src/zig/tests/README.md +18 -0
- package/src/zig/tests/buffer_test.zig +2526 -0
- package/src/zig/tests/edit-buffer-history_test.zig +271 -0
- package/src/zig/tests/edit-buffer_test.zig +1689 -0
- package/src/zig/tests/editor-view_test.zig +3299 -0
- package/src/zig/tests/event-emitter_test.zig +249 -0
- package/src/zig/tests/grapheme_test.zig +1304 -0
- package/src/zig/tests/link_test.zig +190 -0
- package/src/zig/tests/mem-registry_test.zig +473 -0
- package/src/zig/tests/memory_leak_regression_test.zig +159 -0
- package/src/zig/tests/native-span-feed_test.zig +1264 -0
- package/src/zig/tests/renderer_test.zig +1010 -0
- package/src/zig/tests/rope-nested_test.zig +712 -0
- package/src/zig/tests/rope_fuzz_test.zig +238 -0
- package/src/zig/tests/rope_test.zig +2362 -0
- package/src/zig/tests/segment-merge.test.zig +148 -0
- package/src/zig/tests/syntax-style_test.zig +557 -0
- package/src/zig/tests/terminal_test.zig +719 -0
- package/src/zig/tests/text-buffer-drawing_test.zig +3237 -0
- package/src/zig/tests/text-buffer-highlights_test.zig +666 -0
- package/src/zig/tests/text-buffer-iterators_test.zig +776 -0
- package/src/zig/tests/text-buffer-segment_test.zig +320 -0
- package/src/zig/tests/text-buffer-selection_test.zig +1035 -0
- package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
- package/src/zig/tests/text-buffer-view_test.zig +3649 -0
- package/src/zig/tests/text-buffer_test.zig +2191 -0
- package/src/zig/tests/unicode-width-map.zon +3909 -0
- package/src/zig/tests/utf8_no_zwj_test.zig +260 -0
- package/src/zig/tests/utf8_test.zig +4057 -0
- package/src/zig/tests/utf8_wcwidth_cursor_test.zig +267 -0
- package/src/zig/tests/utf8_wcwidth_test.zig +357 -0
- package/src/zig/tests/word-wrap-editing_test.zig +498 -0
- package/src/zig/tests/wrap-cache-perf_test.zig +113 -0
- package/src/zig/text-buffer-iterators.zig +499 -0
- package/src/zig/text-buffer-segment.zig +404 -0
- package/src/zig/text-buffer-view.zig +1371 -0
- package/src/zig/text-buffer.zig +1180 -0
- package/src/zig/utf8.zig +1948 -0
- package/src/zig/utils.zig +9 -0
- package/src/zig-structs.ts +261 -0
- package/src/zig.ts +3843 -0
- package/tsconfig.build.json +22 -0
- package/tsconfig.json +28 -0
- package/3d/SpriteResourceManager.d.ts +0 -74
- package/3d/SpriteUtils.d.ts +0 -13
- package/3d/TextureUtils.d.ts +0 -24
- package/3d/ThreeRenderable.d.ts +0 -40
- package/3d/WGPURenderer.d.ts +0 -61
- package/3d/animation/ExplodingSpriteEffect.d.ts +0 -71
- package/3d/animation/PhysicsExplodingSpriteEffect.d.ts +0 -76
- package/3d/animation/SpriteAnimator.d.ts +0 -124
- package/3d/animation/SpriteParticleGenerator.d.ts +0 -62
- package/3d/canvas.d.ts +0 -44
- package/3d/index.d.ts +0 -12
- package/3d/physics/PlanckPhysicsAdapter.d.ts +0 -19
- package/3d/physics/RapierPhysicsAdapter.d.ts +0 -19
- package/3d/physics/physics-interface.d.ts +0 -27
- package/3d.d.ts +0 -2
- package/3d.js +0 -34042
- package/3d.js.map +0 -155
- package/LICENSE +0 -21
- package/NativeSpanFeed.d.ts +0 -41
- package/Renderable.d.ts +0 -334
- package/animation/Timeline.d.ts +0 -126
- package/ansi.d.ts +0 -13
- package/buffer.d.ts +0 -107
- package/console.d.ts +0 -143
- package/edit-buffer.d.ts +0 -98
- package/editor-view.d.ts +0 -73
- package/index-e4hzc2j2.js +0 -113
- package/index-e4hzc2j2.js.map +0 -10
- package/index-nkrr8a4c.js +0 -18415
- package/index-nkrr8a4c.js.map +0 -64
- package/index-nyw5p3ep.js +0 -12619
- package/index-nyw5p3ep.js.map +0 -43
- package/index.d.ts +0 -21
- package/index.js +0 -430
- package/index.js.map +0 -9
- package/lib/KeyHandler.d.ts +0 -61
- package/lib/RGBA.d.ts +0 -25
- package/lib/ascii.font.d.ts +0 -508
- package/lib/border.d.ts +0 -49
- package/lib/bunfs.d.ts +0 -7
- package/lib/clipboard.d.ts +0 -17
- package/lib/clock.d.ts +0 -15
- package/lib/data-paths.d.ts +0 -26
- package/lib/debounce.d.ts +0 -42
- package/lib/detect-links.d.ts +0 -6
- package/lib/env.d.ts +0 -42
- package/lib/extmarks-history.d.ts +0 -17
- package/lib/extmarks.d.ts +0 -89
- package/lib/hast-styled-text.d.ts +0 -17
- package/lib/index.d.ts +0 -21
- package/lib/keymapping.d.ts +0 -25
- package/lib/objects-in-viewport.d.ts +0 -24
- package/lib/output.capture.d.ts +0 -24
- package/lib/parse.keypress-kitty.d.ts +0 -2
- package/lib/parse.keypress.d.ts +0 -26
- package/lib/parse.mouse.d.ts +0 -30
- package/lib/paste.d.ts +0 -7
- package/lib/queue.d.ts +0 -15
- package/lib/renderable.validations.d.ts +0 -12
- package/lib/scroll-acceleration.d.ts +0 -43
- package/lib/selection.d.ts +0 -63
- package/lib/singleton.d.ts +0 -7
- package/lib/stdin-parser.d.ts +0 -76
- package/lib/styled-text.d.ts +0 -63
- package/lib/terminal-capability-detection.d.ts +0 -30
- package/lib/terminal-palette.d.ts +0 -50
- package/lib/tree-sitter/assets/update.d.ts +0 -11
- package/lib/tree-sitter/client.d.ts +0 -47
- package/lib/tree-sitter/default-parsers.d.ts +0 -2
- package/lib/tree-sitter/download-utils.d.ts +0 -21
- package/lib/tree-sitter/index.d.ts +0 -8
- package/lib/tree-sitter/parser.worker.d.ts +0 -1
- package/lib/tree-sitter/parsers-config.d.ts +0 -38
- package/lib/tree-sitter/resolve-ft.d.ts +0 -2
- package/lib/tree-sitter/types.d.ts +0 -81
- package/lib/tree-sitter-styled-text.d.ts +0 -14
- package/lib/validate-dir-name.d.ts +0 -1
- package/lib/yoga.options.d.ts +0 -32
- package/parser.worker.js +0 -869
- package/parser.worker.js.map +0 -12
- package/plugins/core-slot.d.ts +0 -72
- package/plugins/registry.d.ts +0 -38
- package/plugins/types.d.ts +0 -34
- package/post/filters.d.ts +0 -105
- package/renderables/ASCIIFont.d.ts +0 -52
- package/renderables/Box.d.ts +0 -72
- package/renderables/Code.d.ts +0 -78
- package/renderables/Diff.d.ts +0 -142
- package/renderables/EditBufferRenderable.d.ts +0 -162
- package/renderables/FrameBuffer.d.ts +0 -16
- package/renderables/Input.d.ts +0 -67
- package/renderables/LineNumberRenderable.d.ts +0 -74
- package/renderables/Markdown.d.ts +0 -173
- package/renderables/ScrollBar.d.ts +0 -77
- package/renderables/ScrollBox.d.ts +0 -124
- package/renderables/Select.d.ts +0 -115
- package/renderables/Slider.d.ts +0 -44
- package/renderables/TabSelect.d.ts +0 -96
- package/renderables/Text.d.ts +0 -36
- package/renderables/TextBufferRenderable.d.ts +0 -105
- package/renderables/TextNode.d.ts +0 -91
- package/renderables/TextTable.d.ts +0 -140
- package/renderables/Textarea.d.ts +0 -114
- package/renderables/TimeToFirstDraw.d.ts +0 -24
- package/renderables/__tests__/renderable-test-utils.d.ts +0 -12
- package/renderables/composition/VRenderable.d.ts +0 -16
- package/renderables/composition/constructs.d.ts +0 -35
- package/renderables/composition/vnode.d.ts +0 -46
- package/renderables/index.d.ts +0 -22
- package/renderables/markdown-parser.d.ts +0 -10
- package/renderer.d.ts +0 -388
- package/runtime-plugin-support.d.ts +0 -3
- package/runtime-plugin-support.js +0 -29
- package/runtime-plugin-support.js.map +0 -10
- package/runtime-plugin.d.ts +0 -11
- package/runtime-plugin.js +0 -16
- package/runtime-plugin.js.map +0 -9
- package/syntax-style.d.ts +0 -54
- package/testing/manual-clock.d.ts +0 -16
- package/testing/mock-keys.d.ts +0 -81
- package/testing/mock-mouse.d.ts +0 -38
- package/testing/mock-tree-sitter-client.d.ts +0 -23
- package/testing/spy.d.ts +0 -7
- package/testing/test-recorder.d.ts +0 -61
- package/testing/test-renderer.d.ts +0 -23
- package/testing.d.ts +0 -6
- package/testing.js +0 -675
- package/testing.js.map +0 -15
- package/text-buffer-view.d.ts +0 -42
- package/text-buffer.d.ts +0 -67
- package/types.d.ts +0 -131
- package/utils.d.ts +0 -14
- package/zig-structs.d.ts +0 -155
- package/zig.d.ts +0 -351
- /package/{assets → src/lib/tree-sitter/assets}/javascript/highlights.scm +0 -0
- /package/{assets → src/lib/tree-sitter/assets}/javascript/tree-sitter-javascript.wasm +0 -0
- /package/{assets → src/lib/tree-sitter/assets}/markdown/highlights.scm +0 -0
- /package/{assets → src/lib/tree-sitter/assets}/markdown/injections.scm +0 -0
- /package/{assets → src/lib/tree-sitter/assets}/markdown/tree-sitter-markdown.wasm +0 -0
- /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/highlights.scm +0 -0
- /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
- /package/{assets → src/lib/tree-sitter/assets}/typescript/highlights.scm +0 -0
- /package/{assets → src/lib/tree-sitter/assets}/typescript/tree-sitter-typescript.wasm +0 -0
- /package/{assets → src/lib/tree-sitter/assets}/zig/highlights.scm +0 -0
- /package/{assets → src/lib/tree-sitter/assets}/zig/tree-sitter-zig.wasm +0 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
# Getting Started with OpenTUI
|
|
2
|
+
|
|
3
|
+
OpenTUI is a native terminal UI core written in Zig with TypeScript bindings. The native core exposes a C ABI and can be used from any language. OpenTUI powers OpenCode in production today and will also power terminal.shop. It is an extensible core with a focus on correctness, stability, and high performance. It provides a component-based architecture with flexible layout capabilities, allowing you to create complex terminal applications.
|
|
4
|
+
|
|
5
|
+
## Core Concepts
|
|
6
|
+
|
|
7
|
+
### Renderer
|
|
8
|
+
|
|
9
|
+
The `CliRenderer` is the heart of OpenTUI. It manages the terminal output, handles input events, and orchestrates the rendering loop. Think of it as the canvas that draws your interface to the terminal. It can run in a "live" mode, when calling `renderer.start()`, which runs a loop capped at the specified target FPS. It also just works without calling `renderer.start()`, which will only re-render when the renderable tree or layout changes.
|
|
10
|
+
|
|
11
|
+
By default, left-clicking auto-focuses the closest focusable renderable. Disable this with `createCliRenderer({ autoFocus: false })` if you need manual focus control.
|
|
12
|
+
|
|
13
|
+
### Theme Mode
|
|
14
|
+
|
|
15
|
+
OpenTUI can detect the terminal's preferred color scheme (dark or light) when the terminal supports DEC mode 2031 color scheme updates. Read the current mode via `renderer.themeMode` and subscribe to `theme_mode` to react to changes. Possible values are `"dark"`, `"light"`, or `null` when unsupported, and no events fire in the unsupported case.
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { type ThemeMode } from "@fairyhunter13/opentui-core"
|
|
19
|
+
|
|
20
|
+
const mode = renderer.themeMode
|
|
21
|
+
|
|
22
|
+
renderer.on("theme_mode", (nextMode: ThemeMode) => {
|
|
23
|
+
console.log("Theme mode changed:", nextMode)
|
|
24
|
+
})
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### FrameBuffer (OptimizedBuffer)
|
|
28
|
+
|
|
29
|
+
The `FrameBuffer` is a low-level rendering surface for custom graphics and complex visual effects. It is a 2D array of cells that can be drawn to using the `setCell`, `setCellWithAlphaBlending`, `drawText`, `fillRect`, and `drawFrameBuffer` methods. It is optimized for performance and memory usage. It allows for transparent cells and alpha blending, down to the viewport framebuffer.
|
|
30
|
+
|
|
31
|
+
### Renderables
|
|
32
|
+
|
|
33
|
+
Renderables are the building blocks of your UI - hierarchical objects that can be positioned, styled, and nested within each other. Each Renderable represents a visual element (like text, boxes, or input fields) and uses the Yoga layout engine for flexible positioning and sizing.
|
|
34
|
+
|
|
35
|
+
### Constructs (Components)
|
|
36
|
+
|
|
37
|
+
Constructs look just like React or Solid components, but are not render functions. You can think of them as constructors, a way to create new renderables by composing existing ones. They provide a more declarative way to build your UI. See a comparison on [this page](./renderables-vs-constructs.md).
|
|
38
|
+
|
|
39
|
+
### Console
|
|
40
|
+
|
|
41
|
+
OpenTUI includes a built-in console overlay that captures all `console.log`, `console.info`, `console.warn`, `console.error`, and `console.debug` calls. The console appears as a visual overlay that can be positioned at any edge of the terminal, with scrolling and focus management. It's particularly useful for debugging TUI applications without disrupting the main interface.
|
|
42
|
+
|
|
43
|
+
## Basic Setup
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { createCliRenderer, TextRenderable, Text } from "@fairyhunter13/opentui-core"
|
|
47
|
+
|
|
48
|
+
const renderer = await createCliRenderer()
|
|
49
|
+
|
|
50
|
+
// Raw Renderable
|
|
51
|
+
const greeting = new TextRenderable(renderer, {
|
|
52
|
+
id: "greeting",
|
|
53
|
+
content: "Hello, OpenTUI!",
|
|
54
|
+
fg: "#00FF00",
|
|
55
|
+
position: "absolute",
|
|
56
|
+
left: 10,
|
|
57
|
+
top: 5,
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
renderer.root.add(greeting)
|
|
61
|
+
|
|
62
|
+
// Construct/Component (VNode)
|
|
63
|
+
const greeting2 = Text({
|
|
64
|
+
content: "Hello, OpenTUI!",
|
|
65
|
+
fg: "#00FF00",
|
|
66
|
+
position: "absolute",
|
|
67
|
+
left: 10,
|
|
68
|
+
top: 5,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
renderer.root.add(greeting)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Console
|
|
75
|
+
|
|
76
|
+
When focused, you can use your arrow keys to scroll through the console. `renderer.console.toggle()` will toggle the console overlay, when open but not focused, it will focus the console. `+` and `-` will increase and decrease the size of the console.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { createCliRenderer, ConsolePosition } from "@fairyhunter13/opentui-core"
|
|
80
|
+
|
|
81
|
+
const renderer = await createCliRenderer({
|
|
82
|
+
consoleOptions: {
|
|
83
|
+
position: ConsolePosition.BOTTOM,
|
|
84
|
+
sizePercent: 30,
|
|
85
|
+
colorInfo: "#00FFFF",
|
|
86
|
+
colorWarn: "#FFFF00",
|
|
87
|
+
colorError: "#FF0000",
|
|
88
|
+
startInDebugMode: false,
|
|
89
|
+
},
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
console.log("This appears in the overlay")
|
|
93
|
+
console.error("Errors are color-coded red")
|
|
94
|
+
console.warn("Warnings appear in yellow")
|
|
95
|
+
|
|
96
|
+
renderer.console.toggle()
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Colors: RGBA
|
|
100
|
+
|
|
101
|
+
OpenTUI uses the `RGBA` class for consistent color representation throughout the library. Colors are internally stored as normalized float values (0.0-1.0) for efficient processing, but the class provides convenient methods for working with different color formats.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { RGBA } from "@fairyhunter13/opentui-core"
|
|
105
|
+
|
|
106
|
+
const redFromInts = RGBA.fromInts(255, 0, 0, 255) // RGB integers (0-255)
|
|
107
|
+
const blueFromValues = RGBA.fromValues(0.0, 0.0, 1.0, 1.0) // Float values (0.0-1.0)
|
|
108
|
+
const greenFromHex = RGBA.fromHex("#00FF00") // Hex strings
|
|
109
|
+
const transparent = RGBA.fromValues(1.0, 1.0, 1.0, 0.5) // Semi-transparent white
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The `parseColor()` utility function accepts both RGBA objects and color strings (hex, CSS color names, "transparent") for flexible color input throughout the API.
|
|
113
|
+
|
|
114
|
+
## Keyboard
|
|
115
|
+
|
|
116
|
+
OpenTUI provides a keyboard handler that parses terminal input and provides structured key events. Get the handler via `renderer.keyInput`, an EventEmitter that emits `keypress` and `paste` events with detailed key information.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { type KeyEvent } from "@fairyhunter13/opentui-core"
|
|
120
|
+
|
|
121
|
+
const keyHandler = renderer.keyInput
|
|
122
|
+
|
|
123
|
+
keyHandler.on("keypress", (key: KeyEvent) => {
|
|
124
|
+
console.log("Key name:", key.name)
|
|
125
|
+
console.log("Sequence:", key.sequence)
|
|
126
|
+
console.log("Ctrl pressed:", key.ctrl)
|
|
127
|
+
console.log("Shift pressed:", key.shift)
|
|
128
|
+
console.log("Alt pressed:", key.meta)
|
|
129
|
+
console.log("Option pressed:", key.option)
|
|
130
|
+
|
|
131
|
+
if (key.name === "escape") {
|
|
132
|
+
console.log("Escape pressed!")
|
|
133
|
+
} else if (key.ctrl && key.name === "c") {
|
|
134
|
+
console.log("Ctrl+C pressed!")
|
|
135
|
+
} else if (key.shift && key.name === "f1") {
|
|
136
|
+
console.log("Shift+F1 pressed!")
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Available Renderables
|
|
142
|
+
|
|
143
|
+
OpenTUI provides several primitive components that you can use to build your interfaces:
|
|
144
|
+
|
|
145
|
+
### Text
|
|
146
|
+
|
|
147
|
+
Display styled text content with support for colors, attributes, and text selection.
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import { TextRenderable, TextAttributes, t, bold, underline, fg } from "@fairyhunter13/opentui-core"
|
|
151
|
+
|
|
152
|
+
const plainText = new TextRenderable(renderer, {
|
|
153
|
+
id: "plain-text",
|
|
154
|
+
content: "Important Message",
|
|
155
|
+
fg: "#FFFF00",
|
|
156
|
+
attributes: TextAttributes.BOLD | TextAttributes.UNDERLINE, // bitwise OR to combine attributes
|
|
157
|
+
position: "absolute",
|
|
158
|
+
left: 5,
|
|
159
|
+
top: 2,
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
// You can also use the `t` template literal to create more complex styled text:
|
|
163
|
+
const styledTextRenderable = new TextRenderable(renderer, {
|
|
164
|
+
id: "styled-text",
|
|
165
|
+
content: t`${bold("Important Message")} ${fg("#FF0000")(underline("Important Message"))}`,
|
|
166
|
+
position: "absolute",
|
|
167
|
+
left: 5,
|
|
168
|
+
top: 3,
|
|
169
|
+
})
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Box
|
|
173
|
+
|
|
174
|
+
A container component with borders, background colors, and layout capabilities. Perfect for creating panels, frames, and organized sections.
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
import { BoxRenderable } from "@fairyhunter13/opentui-core"
|
|
178
|
+
|
|
179
|
+
const panel = new BoxRenderable(renderer, {
|
|
180
|
+
id: "panel",
|
|
181
|
+
width: 30,
|
|
182
|
+
height: 10,
|
|
183
|
+
backgroundColor: "#333366",
|
|
184
|
+
borderStyle: "double",
|
|
185
|
+
borderColor: "#FFFFFF",
|
|
186
|
+
title: "Settings Panel",
|
|
187
|
+
titleAlignment: "center",
|
|
188
|
+
position: "absolute",
|
|
189
|
+
left: 10,
|
|
190
|
+
top: 5,
|
|
191
|
+
})
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Input
|
|
195
|
+
|
|
196
|
+
Text input field with cursor support, placeholder text, and focus states for user interaction.
|
|
197
|
+
Has to be focused to receive input.
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
import { InputRenderable, InputRenderableEvents } from "@fairyhunter13/opentui-core"
|
|
201
|
+
|
|
202
|
+
const nameInput = new InputRenderable(renderer, {
|
|
203
|
+
id: "name-input",
|
|
204
|
+
width: 25,
|
|
205
|
+
placeholder: "Enter your name...",
|
|
206
|
+
focusedBackgroundColor: "#1a1a1a",
|
|
207
|
+
position: "absolute",
|
|
208
|
+
left: 10,
|
|
209
|
+
top: 8,
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
// The change event is currently emitted when pressing return or enter. (this will be fixed in the future)
|
|
213
|
+
nameInput.on(InputRenderableEvents.CHANGE, (value) => {
|
|
214
|
+
console.log("Input changed:", value)
|
|
215
|
+
})
|
|
216
|
+
nameInput.focus()
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Select
|
|
220
|
+
|
|
221
|
+
A list selection component for choosing from multiple options.
|
|
222
|
+
Has to be focused to receive input. Default keybindings are `up/k` and `down/j` to navigate the list, `enter` to select.
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
import { SelectRenderable, SelectRenderableEvents } from "@fairyhunter13/opentui-core"
|
|
226
|
+
|
|
227
|
+
const menu = new SelectRenderable(renderer, {
|
|
228
|
+
id: "menu",
|
|
229
|
+
width: 30,
|
|
230
|
+
height: 8,
|
|
231
|
+
options: [
|
|
232
|
+
{ name: "New File", description: "Create a new file" },
|
|
233
|
+
{ name: "Open File", description: "Open an existing file" },
|
|
234
|
+
{ name: "Save", description: "Save current file" },
|
|
235
|
+
{ name: "Exit", description: "Exit the application" },
|
|
236
|
+
],
|
|
237
|
+
position: "absolute",
|
|
238
|
+
left: 5,
|
|
239
|
+
top: 3,
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
menu.on(SelectRenderableEvents.ITEM_SELECTED, (index, option) => {
|
|
243
|
+
console.log("Selected:", option.name)
|
|
244
|
+
})
|
|
245
|
+
menu.focus()
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### TabSelect
|
|
249
|
+
|
|
250
|
+
Horizontal tab-based selection component with descriptions and scroll support.
|
|
251
|
+
Has to be focused to receive input. Default keybindings are `left/[` and `right/]` to navigate the tabs, `enter` to select.
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
import { TabSelectRenderable, TabSelectRenderableEvents } from "@fairyhunter13/opentui-core"
|
|
255
|
+
|
|
256
|
+
const tabs = new TabSelectRenderable(renderer, {
|
|
257
|
+
id: "tabs",
|
|
258
|
+
width: 60,
|
|
259
|
+
options: [
|
|
260
|
+
{ name: "Home", description: "Dashboard and overview" },
|
|
261
|
+
{ name: "Files", description: "File management" },
|
|
262
|
+
{ name: "Settings", description: "Application settings" },
|
|
263
|
+
],
|
|
264
|
+
tabWidth: 20,
|
|
265
|
+
position: "absolute",
|
|
266
|
+
left: 2,
|
|
267
|
+
top: 1,
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
tabs.on(TabSelectRenderableEvents.ITEM_SELECTED, (index, option) => {
|
|
271
|
+
console.log("Selected:", option.name)
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
tabs.focus()
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### ASCIIFont
|
|
278
|
+
|
|
279
|
+
Display text using ASCII art fonts with multiple font styles available.
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
import { ASCIIFontRenderable, RGBA } from "@fairyhunter13/opentui-core"
|
|
283
|
+
|
|
284
|
+
const title = new ASCIIFontRenderable(renderer, {
|
|
285
|
+
id: "title",
|
|
286
|
+
text: "OPENTUI",
|
|
287
|
+
font: "tiny",
|
|
288
|
+
color: RGBA.fromInts(255, 255, 255, 255),
|
|
289
|
+
position: "absolute",
|
|
290
|
+
left: 10,
|
|
291
|
+
top: 2,
|
|
292
|
+
})
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### FrameBuffer
|
|
296
|
+
|
|
297
|
+
A low-level rendering surface for custom graphics and complex visual effects.
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
import { FrameBufferRenderable, RGBA } from "@fairyhunter13/opentui-core"
|
|
301
|
+
|
|
302
|
+
const canvas = new FrameBufferRenderable(renderer, {
|
|
303
|
+
id: "canvas",
|
|
304
|
+
width: 50,
|
|
305
|
+
height: 20,
|
|
306
|
+
position: "absolute",
|
|
307
|
+
left: 5,
|
|
308
|
+
top: 5,
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
// Custom rendering in the frame buffer
|
|
312
|
+
canvas.frameBuffer.fillRect(10, 5, 20, 8, RGBA.fromHex("#FF0000"))
|
|
313
|
+
canvas.frameBuffer.drawText("Custom Graphics", 12, 7, RGBA.fromHex("#FFFFFF"))
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Layout System
|
|
317
|
+
|
|
318
|
+
OpenTUI uses the Yoga layout engine, providing CSS Flexbox-like capabilities for responsive layouts:
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
import { BoxRenderable } from "@fairyhunter13/opentui-core"
|
|
322
|
+
|
|
323
|
+
const container = new BoxRenderable(renderer, {
|
|
324
|
+
id: "container",
|
|
325
|
+
flexDirection: "row",
|
|
326
|
+
justifyContent: "space-between",
|
|
327
|
+
alignItems: "center",
|
|
328
|
+
width: "100%",
|
|
329
|
+
height: 10,
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
const leftPanel = new BoxRenderable(renderer, {
|
|
333
|
+
id: "left",
|
|
334
|
+
flexGrow: 1,
|
|
335
|
+
height: 10,
|
|
336
|
+
backgroundColor: "#444",
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
const rightPanel = new BoxRenderable(renderer, {
|
|
340
|
+
id: "right",
|
|
341
|
+
width: 20,
|
|
342
|
+
height: 10,
|
|
343
|
+
backgroundColor: "#666",
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
container.add(leftPanel)
|
|
347
|
+
container.add(rightPanel)
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## Next Steps
|
|
351
|
+
|
|
352
|
+
- Explore the [examples](../src/examples) directory for more complex use cases
|
|
353
|
+
- Check out the React and Solid integrations for declarative UI development
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Renderables vs Constructs
|
|
2
|
+
|
|
3
|
+
Lets look at two ways of composing Renderables, imperative and declarative.
|
|
4
|
+
Assume we want to create a simple "login" form with a username and password input.
|
|
5
|
+
|
|
6
|
+
## Imperative
|
|
7
|
+
|
|
8
|
+
Creates concrete `Renderable` instances with a `RenderContext` and composes via `add()`. State/behavior are mutated directly on instances (setters/methods), with mouse/key events bubbling upward through `processMouseEvent` for example.
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
import { BoxRenderable, TextRenderable, InputRenderable, createCliRenderer, type RenderContext } from "@fairyhunter13/opentui-core"
|
|
12
|
+
|
|
13
|
+
const renderer = await createCliRenderer()
|
|
14
|
+
|
|
15
|
+
const loginForm = new BoxRenderable(renderer, {
|
|
16
|
+
id: "login-form",
|
|
17
|
+
width: 20,
|
|
18
|
+
height: 10,
|
|
19
|
+
padding: 1,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// Compose renderables to a single renderable.
|
|
23
|
+
// Needs a RendererContext at creation time.
|
|
24
|
+
function createLabeledInput(renderer: RenderContext, props: { label: string; placeholder: string; id: string }) {
|
|
25
|
+
const labeledInput = new BoxRenderable(renderer, {
|
|
26
|
+
id: `${props.id}-labeled-input`,
|
|
27
|
+
flexDirection: "row",
|
|
28
|
+
backgroundColor: "gray",
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
labeledInput.add(
|
|
32
|
+
new TextRenderable(renderer, {
|
|
33
|
+
id: `${props.id}-label`,
|
|
34
|
+
content: props.label + " ",
|
|
35
|
+
}),
|
|
36
|
+
)
|
|
37
|
+
labeledInput.add(
|
|
38
|
+
new InputRenderable(renderer, {
|
|
39
|
+
id: `${props.id}-input`,
|
|
40
|
+
placeholder: props.placeholder,
|
|
41
|
+
backgroundColor: "white",
|
|
42
|
+
textColor: "black",
|
|
43
|
+
cursorColor: "blue",
|
|
44
|
+
focusedBackgroundColor: "orange",
|
|
45
|
+
width: 20,
|
|
46
|
+
}),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return labeledInput
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const labeledUsername = createLabeledInput(renderer, {
|
|
53
|
+
id: "username",
|
|
54
|
+
label: "Username:",
|
|
55
|
+
placeholder: "Enter your username...",
|
|
56
|
+
})
|
|
57
|
+
loginForm.add(labeledUsername)
|
|
58
|
+
|
|
59
|
+
// Now it becomse difficult to focus. because it is in a container.
|
|
60
|
+
// This does not work:
|
|
61
|
+
labeledUsername.focus()
|
|
62
|
+
|
|
63
|
+
// Needs to be:
|
|
64
|
+
labeledUsername.getRenderable("username-input")?.focus()
|
|
65
|
+
|
|
66
|
+
const labeledPassword = createLabeledInput(renderer, {
|
|
67
|
+
id: "password",
|
|
68
|
+
label: "Password:",
|
|
69
|
+
placeholder: "Enter your password...",
|
|
70
|
+
})
|
|
71
|
+
loginForm.add(labeledPassword)
|
|
72
|
+
|
|
73
|
+
// Compose a button component
|
|
74
|
+
function createButton(props: { content: string; onClick: () => void; id: string }) {
|
|
75
|
+
const box = new BoxRenderable(renderer, {
|
|
76
|
+
id: `${props.id}-button`,
|
|
77
|
+
border: true,
|
|
78
|
+
backgroundColor: "gray",
|
|
79
|
+
onMouseDown: props.onClick,
|
|
80
|
+
})
|
|
81
|
+
const text = new TextRenderable(renderer, {
|
|
82
|
+
id: `${props.id}-button-text`,
|
|
83
|
+
content: props.content,
|
|
84
|
+
selectable: false,
|
|
85
|
+
})
|
|
86
|
+
box.add(text)
|
|
87
|
+
return box
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const buttons = new BoxRenderable(renderer, {
|
|
91
|
+
id: "buttons",
|
|
92
|
+
flexDirection: "row",
|
|
93
|
+
padding: 1,
|
|
94
|
+
width: 20,
|
|
95
|
+
})
|
|
96
|
+
buttons.add(createButton({ id: "register", content: "Register", onClick: () => {} }))
|
|
97
|
+
buttons.add(createButton({ id: "login", content: "Login", onClick: () => {} }))
|
|
98
|
+
loginForm.add(buttons)
|
|
99
|
+
|
|
100
|
+
renderer.root.add(loginForm)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Declarative
|
|
104
|
+
|
|
105
|
+
Builds an allegedly lightweight VNode graph using functional constructs that return VNodes; no instances exist until `instantiate(ctx, vnode)` is called. During instantiation, children are flattened, renderables are created and added, and any chained method/property calls made on VNodes are replayed on the created instance. `delegate(mapping, vnode)` can annotate the VNode so selected APIs (e.g., `focus`, `add`) are later routed to a specific descendant when the instance is created.
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { Text, Input, Box, createCliRenderer, delegate, instantiate } from "@fairyhunter13/opentui-core"
|
|
109
|
+
|
|
110
|
+
const renderer = await createCliRenderer()
|
|
111
|
+
|
|
112
|
+
function LabeledInput(props: { id: string; label: string; placeholder: string }) {
|
|
113
|
+
return delegate(
|
|
114
|
+
{
|
|
115
|
+
focus: `${props.id}-input`,
|
|
116
|
+
},
|
|
117
|
+
Box(
|
|
118
|
+
{ flexDirection: "row" },
|
|
119
|
+
Text({ content: props.label + " " }),
|
|
120
|
+
Input({
|
|
121
|
+
id: `${props.id}-input`,
|
|
122
|
+
placeholder: props.placeholder,
|
|
123
|
+
width: 20,
|
|
124
|
+
backgroundColor: "white",
|
|
125
|
+
textColor: "black",
|
|
126
|
+
cursorColor: "blue",
|
|
127
|
+
focusedBackgroundColor: "orange",
|
|
128
|
+
}),
|
|
129
|
+
),
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function Button(props: { id: string; content: string; onClick: () => void }) {
|
|
134
|
+
return Box(
|
|
135
|
+
{
|
|
136
|
+
border: true,
|
|
137
|
+
backgroundColor: "gray",
|
|
138
|
+
onMouseDown: props.onClick,
|
|
139
|
+
},
|
|
140
|
+
Text({ content: props.content, selectable: false }),
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const usernameInput = LabeledInput({ id: "username", label: "Username:", placeholder: "Enter your username..." })
|
|
145
|
+
usernameInput.focus()
|
|
146
|
+
|
|
147
|
+
const loginForm = Box(
|
|
148
|
+
{ width: 20, height: 10, padding: 1 },
|
|
149
|
+
usernameInput,
|
|
150
|
+
LabeledInput({ id: "password", label: "Password:", placeholder: "Enter your password..." }),
|
|
151
|
+
Box(
|
|
152
|
+
{ flexDirection: "row", padding: 1, width: 20 },
|
|
153
|
+
Button({ id: "login", content: "Login", onClick: () => {} }),
|
|
154
|
+
Button({ id: "register", content: "Register", onClick: () => {} }),
|
|
155
|
+
),
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
renderer.root.add(loginForm)
|
|
159
|
+
```
|