@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,1698 @@
|
|
|
1
|
+
import { EventEmitter } from "events"
|
|
2
|
+
import Yoga, { Direction, Display, Edge, FlexDirection, type Config, type Node as YogaNode } from "yoga-layout"
|
|
3
|
+
import { OptimizedBuffer } from "./buffer.js"
|
|
4
|
+
import type { KeyEvent, PasteEvent } from "./lib/KeyHandler.js"
|
|
5
|
+
import type { MouseEventType } from "./lib/parse.mouse.js"
|
|
6
|
+
import type { Selection } from "./lib/selection.js"
|
|
7
|
+
import {
|
|
8
|
+
parseAlign,
|
|
9
|
+
parseAlignItems,
|
|
10
|
+
parseFlexDirection,
|
|
11
|
+
parseJustify,
|
|
12
|
+
parseOverflow,
|
|
13
|
+
parsePositionType,
|
|
14
|
+
parseWrap,
|
|
15
|
+
type AlignString,
|
|
16
|
+
type FlexDirectionString,
|
|
17
|
+
type JustifyString,
|
|
18
|
+
type OverflowString,
|
|
19
|
+
type PositionTypeString,
|
|
20
|
+
type WrapString,
|
|
21
|
+
} from "./lib/yoga.options.js"
|
|
22
|
+
import { maybeMakeRenderable, type VNode } from "./renderables/composition/vnode.js"
|
|
23
|
+
import type { MouseEvent } from "./renderer.js"
|
|
24
|
+
import type { RenderContext } from "./types.js"
|
|
25
|
+
import {
|
|
26
|
+
validateOptions,
|
|
27
|
+
isPositionType,
|
|
28
|
+
isDimensionType,
|
|
29
|
+
isFlexBasisType,
|
|
30
|
+
isSizeType,
|
|
31
|
+
isMarginType,
|
|
32
|
+
isPaddingType,
|
|
33
|
+
isPositionTypeType,
|
|
34
|
+
isOverflowType,
|
|
35
|
+
} from "./lib/renderable.validations.js"
|
|
36
|
+
|
|
37
|
+
const BrandedRenderable: unique symbol = Symbol.for("@fairyhunter13/opentui-core/Renderable")
|
|
38
|
+
|
|
39
|
+
export enum LayoutEvents {
|
|
40
|
+
LAYOUT_CHANGED = "layout-changed",
|
|
41
|
+
ADDED = "added",
|
|
42
|
+
REMOVED = "removed",
|
|
43
|
+
RESIZED = "resized",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export enum RenderableEvents {
|
|
47
|
+
FOCUSED = "focused",
|
|
48
|
+
BLURRED = "blurred",
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface Position {
|
|
52
|
+
top?: number | "auto" | `${number}%`
|
|
53
|
+
right?: number | "auto" | `${number}%`
|
|
54
|
+
bottom?: number | "auto" | `${number}%`
|
|
55
|
+
left?: number | "auto" | `${number}%`
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface BaseRenderableOptions {
|
|
59
|
+
id?: string
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface LayoutOptions extends BaseRenderableOptions {
|
|
63
|
+
flexGrow?: number
|
|
64
|
+
flexShrink?: number
|
|
65
|
+
flexDirection?: FlexDirectionString
|
|
66
|
+
flexWrap?: WrapString
|
|
67
|
+
alignItems?: AlignString
|
|
68
|
+
justifyContent?: JustifyString
|
|
69
|
+
alignSelf?: AlignString
|
|
70
|
+
flexBasis?: number | "auto" | undefined
|
|
71
|
+
position?: PositionTypeString
|
|
72
|
+
overflow?: OverflowString
|
|
73
|
+
top?: number | "auto" | `${number}%`
|
|
74
|
+
right?: number | "auto" | `${number}%`
|
|
75
|
+
bottom?: number | "auto" | `${number}%`
|
|
76
|
+
left?: number | "auto" | `${number}%`
|
|
77
|
+
minWidth?: number | "auto" | `${number}%`
|
|
78
|
+
minHeight?: number | "auto" | `${number}%`
|
|
79
|
+
maxWidth?: number | "auto" | `${number}%`
|
|
80
|
+
maxHeight?: number | "auto" | `${number}%`
|
|
81
|
+
margin?: number | "auto" | `${number}%`
|
|
82
|
+
marginX?: number | "auto" | `${number}%`
|
|
83
|
+
marginY?: number | "auto" | `${number}%`
|
|
84
|
+
marginTop?: number | "auto" | `${number}%`
|
|
85
|
+
marginRight?: number | "auto" | `${number}%`
|
|
86
|
+
marginBottom?: number | "auto" | `${number}%`
|
|
87
|
+
marginLeft?: number | "auto" | `${number}%`
|
|
88
|
+
padding?: number | `${number}%`
|
|
89
|
+
paddingX?: number | `${number}%`
|
|
90
|
+
paddingY?: number | `${number}%`
|
|
91
|
+
paddingTop?: number | `${number}%`
|
|
92
|
+
paddingRight?: number | `${number}%`
|
|
93
|
+
paddingBottom?: number | `${number}%`
|
|
94
|
+
paddingLeft?: number | `${number}%`
|
|
95
|
+
enableLayout?: boolean
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface RenderableOptions<T extends BaseRenderable = BaseRenderable> extends Partial<LayoutOptions> {
|
|
99
|
+
width?: number | "auto" | `${number}%`
|
|
100
|
+
height?: number | "auto" | `${number}%`
|
|
101
|
+
zIndex?: number
|
|
102
|
+
visible?: boolean
|
|
103
|
+
buffered?: boolean
|
|
104
|
+
live?: boolean
|
|
105
|
+
opacity?: number
|
|
106
|
+
|
|
107
|
+
// hooks for custom render logic
|
|
108
|
+
renderBefore?: (this: T, buffer: OptimizedBuffer, deltaTime: number) => void
|
|
109
|
+
renderAfter?: (this: T, buffer: OptimizedBuffer, deltaTime: number) => void
|
|
110
|
+
|
|
111
|
+
// catch all
|
|
112
|
+
onMouse?: (this: T, event: MouseEvent) => void
|
|
113
|
+
|
|
114
|
+
onMouseDown?: (this: T, event: MouseEvent) => void
|
|
115
|
+
onMouseUp?: (this: T, event: MouseEvent) => void
|
|
116
|
+
onMouseMove?: (this: T, event: MouseEvent) => void
|
|
117
|
+
onMouseDrag?: (this: T, event: MouseEvent) => void
|
|
118
|
+
onMouseDragEnd?: (this: T, event: MouseEvent) => void
|
|
119
|
+
onMouseDrop?: (this: T, event: MouseEvent) => void
|
|
120
|
+
onMouseOver?: (this: T, event: MouseEvent) => void
|
|
121
|
+
onMouseOut?: (this: T, event: MouseEvent) => void
|
|
122
|
+
onMouseScroll?: (this: T, event: MouseEvent) => void
|
|
123
|
+
|
|
124
|
+
onPaste?: (this: T, event: PasteEvent) => void
|
|
125
|
+
|
|
126
|
+
onKeyDown?: (key: KeyEvent) => void
|
|
127
|
+
|
|
128
|
+
onSizeChange?: (this: T) => void
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function isRenderable(obj: any): obj is Renderable {
|
|
132
|
+
return !!obj?.[BrandedRenderable]
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export abstract class BaseRenderable extends EventEmitter {
|
|
136
|
+
[BrandedRenderable] = true
|
|
137
|
+
|
|
138
|
+
private static renderableNumber = 1
|
|
139
|
+
protected _id: string
|
|
140
|
+
public readonly num: number
|
|
141
|
+
protected _dirty: boolean = false
|
|
142
|
+
public parent: BaseRenderable | null = null
|
|
143
|
+
protected _visible: boolean = true
|
|
144
|
+
|
|
145
|
+
constructor(options: BaseRenderableOptions) {
|
|
146
|
+
super()
|
|
147
|
+
this.num = BaseRenderable.renderableNumber++
|
|
148
|
+
this._id = options.id ?? `renderable-${this.num}`
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public abstract add(obj: BaseRenderable | unknown, index?: number): number
|
|
152
|
+
public abstract remove(id: string): void
|
|
153
|
+
public abstract insertBefore(obj: BaseRenderable | unknown, anchor: BaseRenderable | unknown): void
|
|
154
|
+
public abstract getChildren(): BaseRenderable[]
|
|
155
|
+
public abstract getChildrenCount(): number
|
|
156
|
+
public abstract getRenderable(id: string): BaseRenderable | undefined
|
|
157
|
+
public abstract requestRender(): void
|
|
158
|
+
public abstract findDescendantById(id: string): BaseRenderable | undefined
|
|
159
|
+
|
|
160
|
+
public get id(): string {
|
|
161
|
+
return this._id
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
public set id(value: string) {
|
|
165
|
+
this._id = value
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public get isDirty(): boolean {
|
|
169
|
+
return this._dirty
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
protected markClean(): void {
|
|
173
|
+
this._dirty = false
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
protected markDirty(): void {
|
|
177
|
+
this._dirty = true
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public destroy(): void {
|
|
181
|
+
// Default implementation: do nothing
|
|
182
|
+
// Override this method to provide custom removal logic
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
public destroyRecursively(): void {
|
|
186
|
+
// Default implementation: do nothing
|
|
187
|
+
// Override this method to provide custom destruction logic
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
public get visible(): boolean {
|
|
191
|
+
return this._visible
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public set visible(value: boolean) {
|
|
195
|
+
this._visible = value
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const yogaConfig: Config = Yoga.Config.create()
|
|
200
|
+
yogaConfig.setUseWebDefaults(false)
|
|
201
|
+
yogaConfig.setPointScaleFactor(1)
|
|
202
|
+
|
|
203
|
+
export abstract class Renderable extends BaseRenderable {
|
|
204
|
+
static renderablesByNumber: Map<number, Renderable> = new Map()
|
|
205
|
+
|
|
206
|
+
protected _isDestroyed: boolean = false
|
|
207
|
+
protected _ctx: RenderContext
|
|
208
|
+
protected _translateX: number = 0
|
|
209
|
+
protected _translateY: number = 0
|
|
210
|
+
protected _x: number = 0
|
|
211
|
+
protected _y: number = 0
|
|
212
|
+
protected _width: number | "auto" | `${number}%`
|
|
213
|
+
protected _height: number | "auto" | `${number}%`
|
|
214
|
+
protected _widthValue: number = 0
|
|
215
|
+
protected _heightValue: number = 0
|
|
216
|
+
private _zIndex: number
|
|
217
|
+
public selectable: boolean = false
|
|
218
|
+
protected buffered: boolean
|
|
219
|
+
protected frameBuffer: OptimizedBuffer | null = null
|
|
220
|
+
|
|
221
|
+
protected _focusable: boolean = false
|
|
222
|
+
protected _focused: boolean = false
|
|
223
|
+
protected keypressHandler: ((key: KeyEvent) => void) | null = null
|
|
224
|
+
protected pasteHandler: ((event: PasteEvent) => void) | null = null
|
|
225
|
+
|
|
226
|
+
private _live: boolean = false
|
|
227
|
+
protected _liveCount: number = 0
|
|
228
|
+
|
|
229
|
+
private _sizeChangeListener: (() => void) | undefined = undefined
|
|
230
|
+
private _mouseListener: ((event: MouseEvent) => void) | null = null
|
|
231
|
+
private _mouseListeners: Partial<Record<MouseEventType, (event: MouseEvent) => void>> = {}
|
|
232
|
+
private _pasteListener: ((event: PasteEvent) => void) | undefined = undefined
|
|
233
|
+
private _keyListeners: Partial<Record<"down", (key: KeyEvent) => void>> = {}
|
|
234
|
+
|
|
235
|
+
protected yogaNode: YogaNode
|
|
236
|
+
protected _positionType: PositionTypeString = "relative"
|
|
237
|
+
protected _overflow: OverflowString = "visible"
|
|
238
|
+
protected _position: Position = {}
|
|
239
|
+
protected _opacity: number = 1.0
|
|
240
|
+
private _flexShrink: number = 1
|
|
241
|
+
|
|
242
|
+
private renderableMapById: Map<string, Renderable> = new Map()
|
|
243
|
+
protected _childrenInLayoutOrder: Renderable[] = []
|
|
244
|
+
protected _childrenInZIndexOrder: Renderable[] = []
|
|
245
|
+
private needsZIndexSort: boolean = false
|
|
246
|
+
public override parent: Renderable | null = null
|
|
247
|
+
|
|
248
|
+
private childrenPrimarySortDirty: boolean = true
|
|
249
|
+
private childrenSortedByPrimaryAxis: Renderable[] = []
|
|
250
|
+
private _shouldUpdateBefore: Set<Renderable> = new Set()
|
|
251
|
+
|
|
252
|
+
public onLifecyclePass: (() => void) | null = null
|
|
253
|
+
|
|
254
|
+
public renderBefore?: (this: Renderable, buffer: OptimizedBuffer, deltaTime: number) => void
|
|
255
|
+
public renderAfter?: (this: Renderable, buffer: OptimizedBuffer, deltaTime: number) => void
|
|
256
|
+
|
|
257
|
+
constructor(ctx: RenderContext, options: RenderableOptions<any>) {
|
|
258
|
+
super(options)
|
|
259
|
+
|
|
260
|
+
this._ctx = ctx
|
|
261
|
+
Renderable.renderablesByNumber.set(this.num, this)
|
|
262
|
+
|
|
263
|
+
validateOptions(this.id, options)
|
|
264
|
+
|
|
265
|
+
this.renderBefore = options.renderBefore
|
|
266
|
+
this.renderAfter = options.renderAfter
|
|
267
|
+
|
|
268
|
+
this._width = options.width ?? "auto"
|
|
269
|
+
this._height = options.height ?? "auto"
|
|
270
|
+
|
|
271
|
+
if (typeof this._width === "number") {
|
|
272
|
+
this._widthValue = this._width
|
|
273
|
+
}
|
|
274
|
+
if (typeof this._height === "number") {
|
|
275
|
+
this._heightValue = this._height
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
this._zIndex = options.zIndex ?? 0
|
|
279
|
+
this._visible = options.visible !== false
|
|
280
|
+
this.buffered = options.buffered ?? false
|
|
281
|
+
this._live = options.live ?? false
|
|
282
|
+
this._liveCount = this._live && this._visible ? 1 : 0
|
|
283
|
+
this._opacity = options.opacity !== undefined ? Math.max(0, Math.min(1, options.opacity)) : 1.0
|
|
284
|
+
|
|
285
|
+
// TODO: use a global yoga config
|
|
286
|
+
this.yogaNode = Yoga.Node.create(yogaConfig)
|
|
287
|
+
this.yogaNode.setDisplay(this._visible ? Display.Flex : Display.None)
|
|
288
|
+
this.setupYogaProperties(options)
|
|
289
|
+
|
|
290
|
+
this.applyEventOptions(options)
|
|
291
|
+
|
|
292
|
+
if (this.buffered) {
|
|
293
|
+
this.createFrameBuffer()
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
public override get id() {
|
|
298
|
+
return this._id
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
public override set id(value: string) {
|
|
302
|
+
if (this.parent) {
|
|
303
|
+
this.parent.renderableMapById.delete(this.id)
|
|
304
|
+
this.parent.renderableMapById.set(value, this)
|
|
305
|
+
}
|
|
306
|
+
super.id = value
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
public get focusable(): boolean {
|
|
310
|
+
return this._focusable
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
public set focusable(value: boolean) {
|
|
314
|
+
this._focusable = value
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
public get ctx(): RenderContext {
|
|
318
|
+
return this._ctx
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
public override get visible(): boolean {
|
|
322
|
+
return this._visible
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
public get primaryAxis(): "row" | "column" {
|
|
326
|
+
const dir = this.yogaNode.getFlexDirection()
|
|
327
|
+
return dir === 2 || dir === 3 ? "row" : "column"
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
public override set visible(value: boolean) {
|
|
331
|
+
if (this._visible === value) return
|
|
332
|
+
|
|
333
|
+
const wasVisible = this._visible
|
|
334
|
+
this._visible = value
|
|
335
|
+
this.yogaNode.setDisplay(value ? Display.Flex : Display.None)
|
|
336
|
+
|
|
337
|
+
if (this._live) {
|
|
338
|
+
if (!wasVisible && value) {
|
|
339
|
+
this.propagateLiveCount(1)
|
|
340
|
+
} else if (wasVisible && !value) {
|
|
341
|
+
this.propagateLiveCount(-1)
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (this._focused) {
|
|
346
|
+
this.blur()
|
|
347
|
+
}
|
|
348
|
+
this.requestRender()
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
public get opacity(): number {
|
|
352
|
+
return this._opacity
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
public set opacity(value: number) {
|
|
356
|
+
const clamped = Math.max(0, Math.min(1, value))
|
|
357
|
+
if (this._opacity !== clamped) {
|
|
358
|
+
this._opacity = clamped
|
|
359
|
+
this.requestRender()
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
public hasSelection(): boolean {
|
|
364
|
+
return false
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
public onSelectionChanged(selection: Selection | null): boolean {
|
|
368
|
+
// Default implementation: do nothing
|
|
369
|
+
// Override this method to provide custom selection handling
|
|
370
|
+
return false
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
public getSelectedText(): string {
|
|
374
|
+
return ""
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
public shouldStartSelection(x: number, y: number): boolean {
|
|
378
|
+
return false
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
public focus(): void {
|
|
382
|
+
if (this._isDestroyed || this._focused || !this._focusable) return
|
|
383
|
+
|
|
384
|
+
this._ctx.focusRenderable(this)
|
|
385
|
+
this._focused = true
|
|
386
|
+
this.requestRender()
|
|
387
|
+
|
|
388
|
+
this.keypressHandler = (key: KeyEvent) => {
|
|
389
|
+
if (this._isDestroyed) return
|
|
390
|
+
this._keyListeners["down"]?.(key)
|
|
391
|
+
// Check again after user listener - it might have destroyed the renderable
|
|
392
|
+
if (this._isDestroyed) return
|
|
393
|
+
if (!key.defaultPrevented && this.handleKeyPress) {
|
|
394
|
+
this.handleKeyPress(key)
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
this.pasteHandler = (event: PasteEvent) => {
|
|
399
|
+
if (this._isDestroyed) return
|
|
400
|
+
this._pasteListener?.call(this, event)
|
|
401
|
+
// Check again after user listener - it might have destroyed the renderable
|
|
402
|
+
if (this._isDestroyed) return
|
|
403
|
+
if (!event.defaultPrevented && this.handlePaste) {
|
|
404
|
+
this.handlePaste(event)
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
this.ctx._internalKeyInput.onInternal("keypress", this.keypressHandler)
|
|
409
|
+
this.ctx._internalKeyInput.onInternal("paste", this.pasteHandler)
|
|
410
|
+
this.emit(RenderableEvents.FOCUSED)
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
public blur(): void {
|
|
414
|
+
if (!this._focused || !this._focusable) return
|
|
415
|
+
|
|
416
|
+
this._focused = false
|
|
417
|
+
this.requestRender()
|
|
418
|
+
|
|
419
|
+
if (this.keypressHandler) {
|
|
420
|
+
this.ctx._internalKeyInput.offInternal("keypress", this.keypressHandler)
|
|
421
|
+
this.keypressHandler = null
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (this.pasteHandler) {
|
|
425
|
+
this.ctx._internalKeyInput.offInternal("paste", this.pasteHandler)
|
|
426
|
+
this.pasteHandler = null
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
this.emit(RenderableEvents.BLURRED)
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
public get focused(): boolean {
|
|
433
|
+
return this._focused
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
public get live(): boolean {
|
|
437
|
+
return this._live
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
public get liveCount(): number {
|
|
441
|
+
return this._liveCount
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
public set live(value: boolean) {
|
|
445
|
+
if (this._live === value) return
|
|
446
|
+
|
|
447
|
+
this._live = value
|
|
448
|
+
|
|
449
|
+
if (this._visible) {
|
|
450
|
+
const delta = value ? 1 : -1
|
|
451
|
+
this.propagateLiveCount(delta)
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
protected propagateLiveCount(delta: number): void {
|
|
456
|
+
this._liveCount += delta
|
|
457
|
+
this.parent?.propagateLiveCount(delta)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
public handleKeyPress?(key: KeyEvent): boolean
|
|
461
|
+
public handlePaste?(event: PasteEvent): void
|
|
462
|
+
|
|
463
|
+
public override findDescendantById(id: string): Renderable | undefined {
|
|
464
|
+
for (const child of this._childrenInLayoutOrder) {
|
|
465
|
+
if (child.id === id) return child
|
|
466
|
+
if (isRenderable(child)) {
|
|
467
|
+
const found = child.findDescendantById(id)
|
|
468
|
+
if (found) return found
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return undefined
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
public override requestRender() {
|
|
475
|
+
this.markDirty()
|
|
476
|
+
this._ctx.requestRender()
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
public get translateX(): number {
|
|
480
|
+
return this._translateX
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
public set translateX(value: number) {
|
|
484
|
+
if (this._translateX === value) return
|
|
485
|
+
this._translateX = value
|
|
486
|
+
if (this.parent) this.parent.childrenPrimarySortDirty = true
|
|
487
|
+
this.requestRender()
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
public get translateY(): number {
|
|
491
|
+
return this._translateY
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
public set translateY(value: number) {
|
|
495
|
+
if (this._translateY === value) return
|
|
496
|
+
this._translateY = value
|
|
497
|
+
if (this.parent) this.parent.childrenPrimarySortDirty = true
|
|
498
|
+
this.requestRender()
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
public get x(): number {
|
|
502
|
+
if (this.parent) {
|
|
503
|
+
return this.parent.x + this._x + this._translateX
|
|
504
|
+
}
|
|
505
|
+
return this._x + this._translateX
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
public set x(value: number) {
|
|
509
|
+
this.left = value
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
public get top(): number | "auto" | `${number}%` | undefined {
|
|
513
|
+
return this._position.top
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
public set top(value: number | "auto" | `${number}%` | undefined) {
|
|
517
|
+
if (isPositionType(value) || value === undefined) {
|
|
518
|
+
this.setPosition({ top: value })
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
public get right(): number | "auto" | `${number}%` | undefined {
|
|
523
|
+
return this._position.right
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
public set right(value: number | "auto" | `${number}%` | undefined) {
|
|
527
|
+
if (isPositionType(value) || value === undefined) {
|
|
528
|
+
this.setPosition({ right: value })
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
public get bottom(): number | "auto" | `${number}%` | undefined {
|
|
533
|
+
return this._position.bottom
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
public set bottom(value: number | "auto" | `${number}%` | undefined) {
|
|
537
|
+
if (isPositionType(value) || value === undefined) {
|
|
538
|
+
this.setPosition({ bottom: value })
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
public get left(): number | "auto" | `${number}%` | undefined {
|
|
543
|
+
return this._position.left
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
public set left(value: number | "auto" | `${number}%` | undefined) {
|
|
547
|
+
if (isPositionType(value) || value === undefined) {
|
|
548
|
+
this.setPosition({ left: value })
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
public get y(): number {
|
|
553
|
+
if (this.parent) {
|
|
554
|
+
return this.parent.y + this._y + this._translateY
|
|
555
|
+
}
|
|
556
|
+
return this._y + this._translateY
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
public set y(value: number) {
|
|
560
|
+
this.top = value
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
public get width(): number {
|
|
564
|
+
return this._widthValue
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
public set width(value: number | "auto" | `${number}%`) {
|
|
568
|
+
if (isDimensionType(value)) {
|
|
569
|
+
this._width = value
|
|
570
|
+
this.yogaNode.setWidth(value)
|
|
571
|
+
|
|
572
|
+
if (typeof value === "number" && this._flexShrink === 1) {
|
|
573
|
+
this._flexShrink = 0
|
|
574
|
+
this.yogaNode.setFlexShrink(0)
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
this.requestRender()
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
public get height(): number {
|
|
582
|
+
return this._heightValue
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
public set height(value: number | "auto" | `${number}%`) {
|
|
586
|
+
if (isDimensionType(value)) {
|
|
587
|
+
this._height = value
|
|
588
|
+
this.yogaNode.setHeight(value)
|
|
589
|
+
|
|
590
|
+
if (typeof value === "number" && this._flexShrink === 1) {
|
|
591
|
+
this._flexShrink = 0
|
|
592
|
+
this.yogaNode.setFlexShrink(0)
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
this.requestRender()
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
public get zIndex(): number {
|
|
600
|
+
return this._zIndex
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
public set zIndex(value: number) {
|
|
604
|
+
if (this._zIndex !== value) {
|
|
605
|
+
this._zIndex = value
|
|
606
|
+
this.parent?.requestZIndexSort()
|
|
607
|
+
this.requestRender()
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
private requestZIndexSort(): void {
|
|
612
|
+
this.needsZIndexSort = true
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
private ensureZIndexSorted(): void {
|
|
616
|
+
if (this.needsZIndexSort) {
|
|
617
|
+
this._childrenInZIndexOrder.sort((a, b) => (a.zIndex > b.zIndex ? 1 : a.zIndex < b.zIndex ? -1 : 0))
|
|
618
|
+
this.needsZIndexSort = false
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
public getChildrenSortedByPrimaryAxis(): Renderable[] {
|
|
623
|
+
if (
|
|
624
|
+
!this.childrenPrimarySortDirty &&
|
|
625
|
+
this.childrenSortedByPrimaryAxis.length === this._childrenInLayoutOrder.length
|
|
626
|
+
) {
|
|
627
|
+
return this.childrenSortedByPrimaryAxis
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
const dir = this.yogaNode.getFlexDirection()
|
|
631
|
+
const axis: "x" | "y" = dir === 2 || dir === 3 ? "x" : "y"
|
|
632
|
+
|
|
633
|
+
const sorted = [...this._childrenInLayoutOrder]
|
|
634
|
+
sorted.sort((a, b) => {
|
|
635
|
+
const va = axis === "y" ? a.y : a.x
|
|
636
|
+
const vb = axis === "y" ? b.y : b.x
|
|
637
|
+
return va - vb
|
|
638
|
+
})
|
|
639
|
+
|
|
640
|
+
this.childrenSortedByPrimaryAxis = sorted
|
|
641
|
+
this.childrenPrimarySortDirty = false
|
|
642
|
+
return this.childrenSortedByPrimaryAxis
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
private setupYogaProperties(options: RenderableOptions<Renderable>): void {
|
|
646
|
+
const node = this.yogaNode
|
|
647
|
+
|
|
648
|
+
if (isFlexBasisType(options.flexBasis)) {
|
|
649
|
+
node.setFlexBasis(options.flexBasis)
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
if (isSizeType(options.minWidth)) {
|
|
653
|
+
node.setMinWidth(options.minWidth)
|
|
654
|
+
}
|
|
655
|
+
if (isSizeType(options.minHeight)) {
|
|
656
|
+
node.setMinHeight(options.minHeight)
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
if (options.flexGrow !== undefined) {
|
|
660
|
+
node.setFlexGrow(options.flexGrow)
|
|
661
|
+
} else {
|
|
662
|
+
node.setFlexGrow(0)
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
if (options.flexShrink !== undefined) {
|
|
666
|
+
this._flexShrink = options.flexShrink
|
|
667
|
+
node.setFlexShrink(options.flexShrink)
|
|
668
|
+
} else {
|
|
669
|
+
// If explicit numeric width is set, don't shrink by default
|
|
670
|
+
// Otherwise follow web default of 1
|
|
671
|
+
const hasExplicitWidth = typeof options.width === "number"
|
|
672
|
+
const hasExplicitHeight = typeof options.height === "number"
|
|
673
|
+
this._flexShrink = hasExplicitWidth || hasExplicitHeight ? 0 : 1
|
|
674
|
+
node.setFlexShrink(this._flexShrink)
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
node.setFlexDirection(parseFlexDirection(options.flexDirection))
|
|
678
|
+
node.setFlexWrap(parseWrap(options.flexWrap))
|
|
679
|
+
node.setAlignItems(parseAlignItems(options.alignItems))
|
|
680
|
+
node.setJustifyContent(parseJustify(options.justifyContent))
|
|
681
|
+
node.setAlignSelf(parseAlign(options.alignSelf))
|
|
682
|
+
|
|
683
|
+
if (isDimensionType(options.width)) {
|
|
684
|
+
this._width = options.width
|
|
685
|
+
this.yogaNode.setWidth(options.width)
|
|
686
|
+
}
|
|
687
|
+
if (isDimensionType(options.height)) {
|
|
688
|
+
this._height = options.height
|
|
689
|
+
this.yogaNode.setHeight(options.height)
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
this._positionType = options.position === "absolute" ? "absolute" : "relative"
|
|
693
|
+
if (this._positionType !== "relative") {
|
|
694
|
+
node.setPositionType(parsePositionType(this._positionType))
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
this._overflow = options.overflow === "hidden" ? "hidden" : options.overflow === "scroll" ? "scroll" : "visible"
|
|
698
|
+
if (this._overflow !== "visible") {
|
|
699
|
+
node.setOverflow(parseOverflow(this._overflow))
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// TODO: flatten position properties internally as well
|
|
703
|
+
const hasPositionProps =
|
|
704
|
+
options.top !== undefined ||
|
|
705
|
+
options.right !== undefined ||
|
|
706
|
+
options.bottom !== undefined ||
|
|
707
|
+
options.left !== undefined
|
|
708
|
+
if (hasPositionProps) {
|
|
709
|
+
this._position = {
|
|
710
|
+
top: options.top,
|
|
711
|
+
right: options.right,
|
|
712
|
+
bottom: options.bottom,
|
|
713
|
+
left: options.left,
|
|
714
|
+
}
|
|
715
|
+
this.updateYogaPosition(this._position)
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
if (isSizeType(options.maxWidth)) {
|
|
719
|
+
node.setMaxWidth(options.maxWidth)
|
|
720
|
+
}
|
|
721
|
+
if (isSizeType(options.maxHeight)) {
|
|
722
|
+
node.setMaxHeight(options.maxHeight)
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
this.setupMarginAndPadding(options)
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
private setupMarginAndPadding(options: RenderableOptions<Renderable>): void {
|
|
729
|
+
const node = this.yogaNode
|
|
730
|
+
|
|
731
|
+
if (isMarginType(options.margin)) {
|
|
732
|
+
node.setMargin(Edge.All, options.margin)
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
if (isMarginType(options.marginX)) {
|
|
736
|
+
node.setMargin(Edge.Horizontal, options.marginX)
|
|
737
|
+
}
|
|
738
|
+
if (isMarginType(options.marginY)) {
|
|
739
|
+
node.setMargin(Edge.Vertical, options.marginY)
|
|
740
|
+
}
|
|
741
|
+
if (isMarginType(options.marginTop)) {
|
|
742
|
+
node.setMargin(Edge.Top, options.marginTop)
|
|
743
|
+
}
|
|
744
|
+
if (isMarginType(options.marginRight)) {
|
|
745
|
+
node.setMargin(Edge.Right, options.marginRight)
|
|
746
|
+
}
|
|
747
|
+
if (isMarginType(options.marginBottom)) {
|
|
748
|
+
node.setMargin(Edge.Bottom, options.marginBottom)
|
|
749
|
+
}
|
|
750
|
+
if (isMarginType(options.marginLeft)) {
|
|
751
|
+
node.setMargin(Edge.Left, options.marginLeft)
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
if (isPaddingType(options.padding)) {
|
|
755
|
+
node.setPadding(Edge.All, options.padding)
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
if (isPaddingType(options.paddingX)) {
|
|
759
|
+
node.setPadding(Edge.Horizontal, options.paddingX)
|
|
760
|
+
}
|
|
761
|
+
if (isPaddingType(options.paddingY)) {
|
|
762
|
+
node.setPadding(Edge.Vertical, options.paddingY)
|
|
763
|
+
}
|
|
764
|
+
if (isPaddingType(options.paddingTop)) {
|
|
765
|
+
node.setPadding(Edge.Top, options.paddingTop)
|
|
766
|
+
}
|
|
767
|
+
if (isPaddingType(options.paddingRight)) {
|
|
768
|
+
node.setPadding(Edge.Right, options.paddingRight)
|
|
769
|
+
}
|
|
770
|
+
if (isPaddingType(options.paddingBottom)) {
|
|
771
|
+
node.setPadding(Edge.Bottom, options.paddingBottom)
|
|
772
|
+
}
|
|
773
|
+
if (isPaddingType(options.paddingLeft)) {
|
|
774
|
+
node.setPadding(Edge.Left, options.paddingLeft)
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
set position(positionType: PositionTypeString | null | undefined) {
|
|
779
|
+
if (!isPositionTypeType(positionType) || this._positionType === positionType) return
|
|
780
|
+
|
|
781
|
+
this._positionType = positionType
|
|
782
|
+
this.yogaNode.setPositionType(parsePositionType(positionType))
|
|
783
|
+
this.requestRender()
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
get overflow(): OverflowString {
|
|
787
|
+
return this._overflow
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
set overflow(overflow: OverflowString | null | undefined) {
|
|
791
|
+
if (!isOverflowType(overflow) || this._overflow === overflow) return
|
|
792
|
+
|
|
793
|
+
this._overflow = overflow
|
|
794
|
+
this.yogaNode.setOverflow(parseOverflow(overflow))
|
|
795
|
+
this.requestRender()
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
public setPosition(position: Position): void {
|
|
799
|
+
this._position = { ...this._position, ...position }
|
|
800
|
+
this.updateYogaPosition(position)
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
private updateYogaPosition(position: Position): void {
|
|
804
|
+
const node = this.yogaNode
|
|
805
|
+
const { top, right, bottom, left } = position
|
|
806
|
+
|
|
807
|
+
if (isPositionType(top)) {
|
|
808
|
+
if (top === "auto") {
|
|
809
|
+
node.setPositionAuto(Edge.Top)
|
|
810
|
+
} else {
|
|
811
|
+
node.setPosition(Edge.Top, top)
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
if (isPositionType(right)) {
|
|
815
|
+
if (right === "auto") {
|
|
816
|
+
node.setPositionAuto(Edge.Right)
|
|
817
|
+
} else {
|
|
818
|
+
node.setPosition(Edge.Right, right)
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
if (isPositionType(bottom)) {
|
|
822
|
+
if (bottom === "auto") {
|
|
823
|
+
node.setPositionAuto(Edge.Bottom)
|
|
824
|
+
} else {
|
|
825
|
+
node.setPosition(Edge.Bottom, bottom)
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
if (isPositionType(left)) {
|
|
829
|
+
if (left === "auto") {
|
|
830
|
+
node.setPositionAuto(Edge.Left)
|
|
831
|
+
} else {
|
|
832
|
+
node.setPosition(Edge.Left, left)
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
this.requestRender()
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
public set flexGrow(grow: number | null | undefined) {
|
|
839
|
+
if (grow == null) {
|
|
840
|
+
this.yogaNode.setFlexGrow(0)
|
|
841
|
+
} else {
|
|
842
|
+
this.yogaNode.setFlexGrow(grow)
|
|
843
|
+
}
|
|
844
|
+
this.requestRender()
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
public set flexShrink(shrink: number | null | undefined) {
|
|
848
|
+
const value = shrink == null ? 1 : shrink
|
|
849
|
+
this._flexShrink = value
|
|
850
|
+
this.yogaNode.setFlexShrink(value)
|
|
851
|
+
this.requestRender()
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
public set flexDirection(direction: FlexDirectionString | null | undefined) {
|
|
855
|
+
this.yogaNode.setFlexDirection(parseFlexDirection(direction))
|
|
856
|
+
this.requestRender()
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
public set flexWrap(wrap: WrapString | null | undefined) {
|
|
860
|
+
this.yogaNode.setFlexWrap(parseWrap(wrap))
|
|
861
|
+
this.requestRender()
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
public set alignItems(alignItems: AlignString | null | undefined) {
|
|
865
|
+
this.yogaNode.setAlignItems(parseAlignItems(alignItems))
|
|
866
|
+
this.requestRender()
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
public set justifyContent(justifyContent: JustifyString | null | undefined) {
|
|
870
|
+
this.yogaNode.setJustifyContent(parseJustify(justifyContent))
|
|
871
|
+
this.requestRender()
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
public set alignSelf(alignSelf: AlignString | null | undefined) {
|
|
875
|
+
this.yogaNode.setAlignSelf(parseAlign(alignSelf))
|
|
876
|
+
this.requestRender()
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
public set flexBasis(basis: number | "auto" | null | undefined) {
|
|
880
|
+
if (isFlexBasisType(basis)) {
|
|
881
|
+
this.yogaNode.setFlexBasis(basis)
|
|
882
|
+
this.requestRender()
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
public set minWidth(minWidth: number | `${number}%` | null | undefined) {
|
|
887
|
+
if (isSizeType(minWidth)) {
|
|
888
|
+
this.yogaNode.setMinWidth(minWidth)
|
|
889
|
+
this.requestRender()
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
public set maxWidth(maxWidth: number | `${number}%` | null | undefined) {
|
|
894
|
+
if (isSizeType(maxWidth)) {
|
|
895
|
+
this.yogaNode.setMaxWidth(maxWidth)
|
|
896
|
+
this.requestRender()
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
public set minHeight(minHeight: number | `${number}%` | null | undefined) {
|
|
901
|
+
if (isSizeType(minHeight)) {
|
|
902
|
+
this.yogaNode.setMinHeight(minHeight)
|
|
903
|
+
this.requestRender()
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
public set maxHeight(maxHeight: number | `${number}%` | null | undefined) {
|
|
908
|
+
if (isSizeType(maxHeight)) {
|
|
909
|
+
this.yogaNode.setMaxHeight(maxHeight)
|
|
910
|
+
this.requestRender()
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
public set margin(margin: number | "auto" | `${number}%` | null | undefined) {
|
|
915
|
+
if (isMarginType(margin)) {
|
|
916
|
+
this.yogaNode.setMargin(Edge.All, margin)
|
|
917
|
+
this.requestRender()
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
public set marginX(marginX: number | "auto" | `${number}%` | null | undefined) {
|
|
922
|
+
if (isMarginType(marginX)) {
|
|
923
|
+
this.yogaNode.setMargin(Edge.Horizontal, marginX)
|
|
924
|
+
this.requestRender()
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
public set marginY(marginY: number | "auto" | `${number}%` | null | undefined) {
|
|
929
|
+
if (isMarginType(marginY)) {
|
|
930
|
+
this.yogaNode.setMargin(Edge.Vertical, marginY)
|
|
931
|
+
this.requestRender()
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
public set marginTop(margin: number | "auto" | `${number}%` | null | undefined) {
|
|
936
|
+
if (isMarginType(margin)) {
|
|
937
|
+
this.yogaNode.setMargin(Edge.Top, margin)
|
|
938
|
+
this.requestRender()
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
public set marginRight(margin: number | "auto" | `${number}%` | null | undefined) {
|
|
943
|
+
if (isMarginType(margin)) {
|
|
944
|
+
this.yogaNode.setMargin(Edge.Right, margin)
|
|
945
|
+
this.requestRender()
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
public set marginBottom(margin: number | "auto" | `${number}%` | null | undefined) {
|
|
950
|
+
if (isMarginType(margin)) {
|
|
951
|
+
this.yogaNode.setMargin(Edge.Bottom, margin)
|
|
952
|
+
this.requestRender()
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
public set marginLeft(margin: number | "auto" | `${number}%` | null | undefined) {
|
|
957
|
+
if (isMarginType(margin)) {
|
|
958
|
+
this.yogaNode.setMargin(Edge.Left, margin)
|
|
959
|
+
this.requestRender()
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
public set padding(padding: number | `${number}%` | null | undefined) {
|
|
964
|
+
if (isPaddingType(padding)) {
|
|
965
|
+
this.yogaNode.setPadding(Edge.All, padding)
|
|
966
|
+
this.requestRender()
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
public set paddingX(paddingX: number | `${number}%` | null | undefined) {
|
|
971
|
+
if (isPaddingType(paddingX)) {
|
|
972
|
+
this.yogaNode.setPadding(Edge.Horizontal, paddingX)
|
|
973
|
+
this.requestRender()
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
public set paddingY(paddingY: number | `${number}%` | null | undefined) {
|
|
978
|
+
if (isPaddingType(paddingY)) {
|
|
979
|
+
this.yogaNode.setPadding(Edge.Vertical, paddingY)
|
|
980
|
+
this.requestRender()
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
public set paddingTop(padding: number | `${number}%` | null | undefined) {
|
|
985
|
+
if (isPaddingType(padding)) {
|
|
986
|
+
this.yogaNode.setPadding(Edge.Top, padding)
|
|
987
|
+
this.requestRender()
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
public set paddingRight(padding: number | `${number}%` | null | undefined) {
|
|
992
|
+
if (isPaddingType(padding)) {
|
|
993
|
+
this.yogaNode.setPadding(Edge.Right, padding)
|
|
994
|
+
this.requestRender()
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
public set paddingBottom(padding: number | `${number}%` | null | undefined) {
|
|
999
|
+
if (isPaddingType(padding)) {
|
|
1000
|
+
this.yogaNode.setPadding(Edge.Bottom, padding)
|
|
1001
|
+
this.requestRender()
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
public set paddingLeft(padding: number | `${number}%` | null | undefined) {
|
|
1006
|
+
if (isPaddingType(padding)) {
|
|
1007
|
+
this.yogaNode.setPadding(Edge.Left, padding)
|
|
1008
|
+
this.requestRender()
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
public getLayoutNode(): YogaNode {
|
|
1013
|
+
return this.yogaNode
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
public updateFromLayout(): void {
|
|
1017
|
+
const layout = this.yogaNode.getComputedLayout()
|
|
1018
|
+
|
|
1019
|
+
const oldX = this._x
|
|
1020
|
+
const oldY = this._y
|
|
1021
|
+
const oldWidth = this._widthValue
|
|
1022
|
+
const oldHeight = this._heightValue
|
|
1023
|
+
|
|
1024
|
+
this._x = layout.left
|
|
1025
|
+
this._y = layout.top
|
|
1026
|
+
|
|
1027
|
+
const newWidth = Math.max(layout.width, 1)
|
|
1028
|
+
const newHeight = Math.max(layout.height, 1)
|
|
1029
|
+
const sizeChanged = oldWidth !== newWidth || oldHeight !== newHeight
|
|
1030
|
+
|
|
1031
|
+
this._widthValue = newWidth
|
|
1032
|
+
this._heightValue = newHeight
|
|
1033
|
+
|
|
1034
|
+
if (sizeChanged) {
|
|
1035
|
+
this.onLayoutResize(newWidth, newHeight)
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
const positionChanged = oldX !== this._x || oldY !== this._y
|
|
1039
|
+
if (positionChanged) {
|
|
1040
|
+
if (this.parent) this.parent.childrenPrimarySortDirty = true
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
protected onLayoutResize(width: number, height: number): void {
|
|
1045
|
+
if (this._visible) {
|
|
1046
|
+
// TODO: Should probably .markDirty()
|
|
1047
|
+
this.handleFrameBufferResize(width, height)
|
|
1048
|
+
this.onResize(width, height)
|
|
1049
|
+
this.requestRender()
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
protected handleFrameBufferResize(width: number, height: number): void {
|
|
1054
|
+
if (!this.buffered) return
|
|
1055
|
+
|
|
1056
|
+
if (width <= 0 || height <= 0) {
|
|
1057
|
+
return
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
if (this.frameBuffer) {
|
|
1061
|
+
this.frameBuffer.resize(width, height)
|
|
1062
|
+
} else {
|
|
1063
|
+
this.createFrameBuffer()
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
protected createFrameBuffer(): void {
|
|
1068
|
+
const w = this.width
|
|
1069
|
+
const h = this.height
|
|
1070
|
+
|
|
1071
|
+
if (w <= 0 || h <= 0) {
|
|
1072
|
+
return
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
try {
|
|
1076
|
+
const widthMethod = this._ctx.widthMethod
|
|
1077
|
+
this.frameBuffer = OptimizedBuffer.create(w, h, widthMethod, { respectAlpha: true, id: `framebuffer-${this.id}` })
|
|
1078
|
+
} catch (error) {
|
|
1079
|
+
console.error(`Failed to create frame buffer for ${this.id}:`, error)
|
|
1080
|
+
this.frameBuffer = null
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
/**
|
|
1085
|
+
* This will be called during a render pass.
|
|
1086
|
+
* Requesting a render during a render pass will drop the requested render.
|
|
1087
|
+
* If you need to request a render during a render pass, use process.nextTick.
|
|
1088
|
+
*/
|
|
1089
|
+
protected onResize(width: number, height: number): void {
|
|
1090
|
+
this.onSizeChange?.()
|
|
1091
|
+
this.emit("resize")
|
|
1092
|
+
// Override in subclasses for additional resize logic
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
private replaceParent(obj: Renderable) {
|
|
1096
|
+
if (obj.parent) {
|
|
1097
|
+
obj.parent.remove(obj.id)
|
|
1098
|
+
}
|
|
1099
|
+
obj.parent = this
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
public override add(obj: Renderable | VNode<any, any[]> | unknown, index?: number): number {
|
|
1103
|
+
if (!obj) {
|
|
1104
|
+
return -1
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
const renderable = maybeMakeRenderable(this._ctx, obj)
|
|
1108
|
+
if (!renderable) {
|
|
1109
|
+
return -1
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
if (renderable.isDestroyed) {
|
|
1113
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1114
|
+
console.warn(`Renderable with id ${renderable.id} was already destroyed, skipping add`)
|
|
1115
|
+
}
|
|
1116
|
+
return -1
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
const anchorRenderable = index !== undefined ? this._childrenInLayoutOrder[index] : undefined
|
|
1120
|
+
|
|
1121
|
+
if (anchorRenderable) {
|
|
1122
|
+
return this.insertBefore(renderable, anchorRenderable)
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
if (renderable.parent === this) {
|
|
1126
|
+
this.yogaNode.removeChild(renderable.getLayoutNode())
|
|
1127
|
+
this._childrenInLayoutOrder.splice(this._childrenInLayoutOrder.indexOf(renderable), 1)
|
|
1128
|
+
} else {
|
|
1129
|
+
this.replaceParent(renderable)
|
|
1130
|
+
this.needsZIndexSort = true
|
|
1131
|
+
this.renderableMapById.set(renderable.id, renderable)
|
|
1132
|
+
this._childrenInZIndexOrder.push(renderable)
|
|
1133
|
+
|
|
1134
|
+
if (typeof renderable.onLifecyclePass === "function") {
|
|
1135
|
+
this._ctx.registerLifecyclePass(renderable)
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
if (renderable._liveCount > 0) {
|
|
1139
|
+
this.propagateLiveCount(renderable._liveCount)
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
const childLayoutNode = renderable.getLayoutNode()
|
|
1144
|
+
const insertedIndex = this._childrenInLayoutOrder.length
|
|
1145
|
+
this._childrenInLayoutOrder.push(renderable)
|
|
1146
|
+
this.yogaNode.insertChild(childLayoutNode, insertedIndex)
|
|
1147
|
+
|
|
1148
|
+
this.childrenPrimarySortDirty = true
|
|
1149
|
+
this._shouldUpdateBefore.add(renderable)
|
|
1150
|
+
|
|
1151
|
+
this.requestRender()
|
|
1152
|
+
|
|
1153
|
+
return insertedIndex
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
override insertBefore(obj: Renderable | VNode<any, any[]> | unknown, anchor?: Renderable | unknown): number {
|
|
1157
|
+
if (!anchor) {
|
|
1158
|
+
return this.add(obj)
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
if (!obj) {
|
|
1162
|
+
return -1
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
const renderable = maybeMakeRenderable(this._ctx, obj)
|
|
1166
|
+
if (!renderable) {
|
|
1167
|
+
return -1
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
if (renderable.isDestroyed) {
|
|
1171
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1172
|
+
console.warn(`Renderable with id ${renderable.id} was already destroyed, skipping insertBefore`)
|
|
1173
|
+
}
|
|
1174
|
+
return -1
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
if (!isRenderable(anchor)) {
|
|
1178
|
+
throw new Error("Anchor must be a Renderable")
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
if (anchor.isDestroyed) {
|
|
1182
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1183
|
+
console.warn(`Anchor with id ${anchor.id} was already destroyed, skipping insertBefore`)
|
|
1184
|
+
}
|
|
1185
|
+
return -1
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
if (!this.renderableMapById.has(anchor.id)) {
|
|
1189
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1190
|
+
console.warn(`Anchor with id ${anchor.id} does not exist within the parent ${this.id}, skipping insertBefore`)
|
|
1191
|
+
}
|
|
1192
|
+
return -1
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
if (renderable === anchor || renderable.id === anchor.id) {
|
|
1196
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1197
|
+
console.warn(`Anchor is the same as the node ${renderable.id} being inserted, skipping insertBefore`)
|
|
1198
|
+
}
|
|
1199
|
+
return -1
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
if (renderable.parent === this) {
|
|
1203
|
+
this.yogaNode.removeChild(renderable.getLayoutNode())
|
|
1204
|
+
this._childrenInLayoutOrder.splice(this._childrenInLayoutOrder.indexOf(renderable), 1)
|
|
1205
|
+
} else {
|
|
1206
|
+
this.replaceParent(renderable)
|
|
1207
|
+
this.needsZIndexSort = true
|
|
1208
|
+
this.renderableMapById.set(renderable.id, renderable)
|
|
1209
|
+
this._childrenInZIndexOrder.push(renderable)
|
|
1210
|
+
|
|
1211
|
+
if (typeof renderable.onLifecyclePass === "function") {
|
|
1212
|
+
this._ctx.registerLifecyclePass(renderable)
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
if (renderable._liveCount > 0) {
|
|
1216
|
+
this.propagateLiveCount(renderable._liveCount)
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
this.childrenPrimarySortDirty = true
|
|
1221
|
+
|
|
1222
|
+
const anchorIndex = this._childrenInLayoutOrder.indexOf(anchor)
|
|
1223
|
+
const insertedIndex = Math.max(0, Math.min(anchorIndex, this._childrenInLayoutOrder.length))
|
|
1224
|
+
|
|
1225
|
+
this._childrenInLayoutOrder.splice(insertedIndex, 0, renderable)
|
|
1226
|
+
this.yogaNode.insertChild(renderable.getLayoutNode(), insertedIndex)
|
|
1227
|
+
|
|
1228
|
+
this._shouldUpdateBefore.add(renderable)
|
|
1229
|
+
|
|
1230
|
+
this.requestRender()
|
|
1231
|
+
|
|
1232
|
+
return insertedIndex
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// TODO: that naming is meh
|
|
1236
|
+
public override getRenderable(id: string): Renderable | undefined {
|
|
1237
|
+
return this.renderableMapById.get(id)
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
public override remove(id: string): void {
|
|
1241
|
+
if (!id) {
|
|
1242
|
+
return
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
if (this.renderableMapById.has(id)) {
|
|
1246
|
+
const obj = this.renderableMapById.get(id)
|
|
1247
|
+
if (obj) {
|
|
1248
|
+
if (obj._liveCount > 0) {
|
|
1249
|
+
this.propagateLiveCount(-obj._liveCount)
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
const childLayoutNode = obj.getLayoutNode()
|
|
1253
|
+
this.yogaNode.removeChild(childLayoutNode)
|
|
1254
|
+
this.requestRender()
|
|
1255
|
+
|
|
1256
|
+
obj.onRemove()
|
|
1257
|
+
obj.parent = null
|
|
1258
|
+
this._ctx.unregisterLifecyclePass(obj)
|
|
1259
|
+
this.renderableMapById.delete(id)
|
|
1260
|
+
|
|
1261
|
+
const index = this._childrenInLayoutOrder.findIndex((obj) => obj.id === id)
|
|
1262
|
+
if (index !== -1) {
|
|
1263
|
+
this._childrenInLayoutOrder.splice(index, 1)
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
const zIndexIndex = this._childrenInZIndexOrder.findIndex((obj) => obj.id === id)
|
|
1267
|
+
if (zIndexIndex !== -1) {
|
|
1268
|
+
this._childrenInZIndexOrder.splice(zIndexIndex, 1)
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
this.childrenPrimarySortDirty = true
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
protected onRemove(): void {
|
|
1277
|
+
// Default implementation: do nothing
|
|
1278
|
+
// Override this method to provide custom removal logic
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
public override getChildren(): Renderable[] {
|
|
1282
|
+
return [...this._childrenInLayoutOrder]
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
public override getChildrenCount(): number {
|
|
1286
|
+
return this._childrenInLayoutOrder.length
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
public updateLayout(deltaTime: number, renderList: RenderCommand[] = []): void {
|
|
1290
|
+
if (!this.visible) return
|
|
1291
|
+
|
|
1292
|
+
this.onUpdate(deltaTime)
|
|
1293
|
+
|
|
1294
|
+
// If destroyed during onUpdate, don't add to render list
|
|
1295
|
+
if (this._isDestroyed) return
|
|
1296
|
+
|
|
1297
|
+
// NOTE: worst case updateFromLayout is called throughout the whole tree,
|
|
1298
|
+
// which currently still has yoga performance issues.
|
|
1299
|
+
// This can be mitigated at some point when the layout tree moved to native,
|
|
1300
|
+
// as in the native yoga tree we can use events during the calculateLayout phase,
|
|
1301
|
+
// and anctually know if a child has changed or not.
|
|
1302
|
+
// That would allow us to to generate optimised render commands,
|
|
1303
|
+
// including the layout updates, in one pass.
|
|
1304
|
+
this.updateFromLayout()
|
|
1305
|
+
|
|
1306
|
+
// Update newly added children before getting visible children
|
|
1307
|
+
// This ensures their positions are current when culling happens
|
|
1308
|
+
if (this._shouldUpdateBefore.size > 0) {
|
|
1309
|
+
for (const child of this._shouldUpdateBefore) {
|
|
1310
|
+
if (!child.isDestroyed) {
|
|
1311
|
+
child.updateFromLayout()
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
this._shouldUpdateBefore.clear()
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
// Check again after updateFromLayout, which calls onResize/onSizeChange
|
|
1318
|
+
if (this._isDestroyed) return
|
|
1319
|
+
|
|
1320
|
+
// Push opacity BEFORE rendering this element so it affects this element and all children
|
|
1321
|
+
const shouldPushOpacity = this._opacity < 1.0
|
|
1322
|
+
if (shouldPushOpacity) {
|
|
1323
|
+
renderList.push({ action: "pushOpacity", opacity: this._opacity })
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
renderList.push({ action: "render", renderable: this })
|
|
1327
|
+
|
|
1328
|
+
this.ensureZIndexSorted()
|
|
1329
|
+
|
|
1330
|
+
const shouldPushScissor = this._overflow !== "visible" && this.width > 0 && this.height > 0
|
|
1331
|
+
if (shouldPushScissor) {
|
|
1332
|
+
const scissorRect = this.getScissorRect()
|
|
1333
|
+
renderList.push({
|
|
1334
|
+
action: "pushScissorRect",
|
|
1335
|
+
x: scissorRect.x,
|
|
1336
|
+
y: scissorRect.y,
|
|
1337
|
+
width: scissorRect.width,
|
|
1338
|
+
height: scissorRect.height,
|
|
1339
|
+
screenX: this.x,
|
|
1340
|
+
screenY: this.y,
|
|
1341
|
+
})
|
|
1342
|
+
}
|
|
1343
|
+
const visibleChildren = this._getVisibleChildren()
|
|
1344
|
+
for (const child of this._childrenInZIndexOrder) {
|
|
1345
|
+
if (!visibleChildren.includes(child.num)) {
|
|
1346
|
+
child.updateFromLayout()
|
|
1347
|
+
continue
|
|
1348
|
+
}
|
|
1349
|
+
child.updateLayout(deltaTime, renderList)
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
if (shouldPushScissor) {
|
|
1353
|
+
renderList.push({ action: "popScissorRect" })
|
|
1354
|
+
}
|
|
1355
|
+
if (shouldPushOpacity) {
|
|
1356
|
+
renderList.push({ action: "popOpacity" })
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
public render(buffer: OptimizedBuffer, deltaTime: number): void {
|
|
1361
|
+
let renderBuffer = buffer
|
|
1362
|
+
if (this.buffered && this.frameBuffer) {
|
|
1363
|
+
renderBuffer = this.frameBuffer
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
if (this.renderBefore) {
|
|
1367
|
+
this.renderBefore.call(this, renderBuffer, deltaTime)
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
this.renderSelf(renderBuffer, deltaTime)
|
|
1371
|
+
|
|
1372
|
+
if (this.renderAfter) {
|
|
1373
|
+
this.renderAfter.call(this, renderBuffer, deltaTime)
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
this.markClean()
|
|
1377
|
+
this._ctx.addToHitGrid(this.x, this.y, this.width, this.height, this.num)
|
|
1378
|
+
|
|
1379
|
+
if (this.buffered && this.frameBuffer) {
|
|
1380
|
+
buffer.drawFrameBuffer(this.x, this.y, this.frameBuffer)
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
protected _getVisibleChildren(): number[] {
|
|
1385
|
+
return this._childrenInZIndexOrder.map((child) => child.num)
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
protected onUpdate(deltaTime: number): void {
|
|
1389
|
+
// Default implementation: do nothing
|
|
1390
|
+
// Override this method to provide custom rendering
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
protected getScissorRect(): { x: number; y: number; width: number; height: number } {
|
|
1394
|
+
return {
|
|
1395
|
+
x: this.buffered ? 0 : this.x,
|
|
1396
|
+
y: this.buffered ? 0 : this.y,
|
|
1397
|
+
width: this.width,
|
|
1398
|
+
height: this.height,
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
protected renderSelf(buffer: OptimizedBuffer, deltaTime: number): void {
|
|
1403
|
+
// Default implementation: do nothing
|
|
1404
|
+
// Override this method to provide custom rendering
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
public get isDestroyed(): boolean {
|
|
1408
|
+
return this._isDestroyed
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
public override destroy(): void {
|
|
1412
|
+
if (this._isDestroyed) {
|
|
1413
|
+
return
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
this._isDestroyed = true
|
|
1417
|
+
|
|
1418
|
+
if (this.parent) {
|
|
1419
|
+
this.parent.remove(this.id)
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
if (this.frameBuffer) {
|
|
1423
|
+
this.frameBuffer.destroy()
|
|
1424
|
+
this.frameBuffer = null
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
for (const child of this._childrenInLayoutOrder) {
|
|
1428
|
+
this.remove(child.id)
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
this._childrenInLayoutOrder = []
|
|
1432
|
+
this.renderableMapById.clear()
|
|
1433
|
+
Renderable.renderablesByNumber.delete(this.num)
|
|
1434
|
+
|
|
1435
|
+
this.blur()
|
|
1436
|
+
this.removeAllListeners()
|
|
1437
|
+
|
|
1438
|
+
this.destroySelf()
|
|
1439
|
+
|
|
1440
|
+
try {
|
|
1441
|
+
this.yogaNode.free()
|
|
1442
|
+
} catch (e) {
|
|
1443
|
+
// Might be already freed and will throw an error if we try to free it again
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
public override destroyRecursively(): void {
|
|
1448
|
+
// Destroy children first to ensure removal as destroy clears child array
|
|
1449
|
+
// Make a copy of the children array to avoid iteration issues when children are destroyed
|
|
1450
|
+
const children = [...this._childrenInLayoutOrder]
|
|
1451
|
+
for (const child of children) {
|
|
1452
|
+
child.destroyRecursively()
|
|
1453
|
+
}
|
|
1454
|
+
this.destroy()
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
protected destroySelf(): void {
|
|
1458
|
+
// Default implementation: do nothing else
|
|
1459
|
+
// Override this method to provide custom cleanup
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
public processMouseEvent(event: MouseEvent): void {
|
|
1463
|
+
this._mouseListener?.call(this, event)
|
|
1464
|
+
this._mouseListeners[event.type]?.call(this, event)
|
|
1465
|
+
this.onMouseEvent(event)
|
|
1466
|
+
|
|
1467
|
+
if (this.parent && !event.propagationStopped) {
|
|
1468
|
+
this.parent.processMouseEvent(event)
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
protected onMouseEvent(event: MouseEvent): void {
|
|
1473
|
+
// Default implementation: do nothing
|
|
1474
|
+
// Override this method to provide custom event handling
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
public set onMouse(handler: ((event: MouseEvent) => void) | undefined) {
|
|
1478
|
+
if (handler) this._mouseListener = handler
|
|
1479
|
+
else this._mouseListener = null
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
public set onMouseDown(handler: ((event: MouseEvent) => void) | undefined) {
|
|
1483
|
+
if (handler) this._mouseListeners["down"] = handler
|
|
1484
|
+
else delete this._mouseListeners["down"]
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
public set onMouseUp(handler: ((event: MouseEvent) => void) | undefined) {
|
|
1488
|
+
if (handler) this._mouseListeners["up"] = handler
|
|
1489
|
+
else delete this._mouseListeners["up"]
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
public set onMouseMove(handler: ((event: MouseEvent) => void) | undefined) {
|
|
1493
|
+
if (handler) this._mouseListeners["move"] = handler
|
|
1494
|
+
else delete this._mouseListeners["move"]
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
public set onMouseDrag(handler: ((event: MouseEvent) => void) | undefined) {
|
|
1498
|
+
if (handler) this._mouseListeners["drag"] = handler
|
|
1499
|
+
else delete this._mouseListeners["drag"]
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
public set onMouseDragEnd(handler: ((event: MouseEvent) => void) | undefined) {
|
|
1503
|
+
if (handler) this._mouseListeners["drag-end"] = handler
|
|
1504
|
+
else delete this._mouseListeners["drag-end"]
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
public set onMouseDrop(handler: ((event: MouseEvent) => void) | undefined) {
|
|
1508
|
+
if (handler) this._mouseListeners["drop"] = handler
|
|
1509
|
+
else delete this._mouseListeners["drop"]
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
public set onMouseOver(handler: ((event: MouseEvent) => void) | undefined) {
|
|
1513
|
+
if (handler) this._mouseListeners["over"] = handler
|
|
1514
|
+
else delete this._mouseListeners["over"]
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
public set onMouseOut(handler: ((event: MouseEvent) => void) | undefined) {
|
|
1518
|
+
if (handler) this._mouseListeners["out"] = handler
|
|
1519
|
+
else delete this._mouseListeners["out"]
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
public set onMouseScroll(handler: ((event: MouseEvent) => void) | undefined) {
|
|
1523
|
+
if (handler) this._mouseListeners["scroll"] = handler
|
|
1524
|
+
else delete this._mouseListeners["scroll"]
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
public set onPaste(handler: ((event: PasteEvent) => void) | undefined) {
|
|
1528
|
+
this._pasteListener = handler
|
|
1529
|
+
}
|
|
1530
|
+
public get onPaste(): ((event: PasteEvent) => void) | undefined {
|
|
1531
|
+
return this._pasteListener
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
public set onKeyDown(handler: ((key: KeyEvent) => void) | undefined) {
|
|
1535
|
+
if (handler) this._keyListeners["down"] = handler
|
|
1536
|
+
else delete this._keyListeners["down"]
|
|
1537
|
+
}
|
|
1538
|
+
public get onKeyDown(): ((key: KeyEvent) => void) | undefined {
|
|
1539
|
+
return this._keyListeners["down"]
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
public set onSizeChange(handler: (() => void) | undefined) {
|
|
1543
|
+
this._sizeChangeListener = handler
|
|
1544
|
+
}
|
|
1545
|
+
public get onSizeChange(): (() => void) | undefined {
|
|
1546
|
+
return this._sizeChangeListener
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
private applyEventOptions(options: RenderableOptions<Renderable>): void {
|
|
1550
|
+
this.onMouse = options.onMouse
|
|
1551
|
+
this.onMouseDown = options.onMouseDown
|
|
1552
|
+
this.onMouseUp = options.onMouseUp
|
|
1553
|
+
this.onMouseMove = options.onMouseMove
|
|
1554
|
+
this.onMouseDrag = options.onMouseDrag
|
|
1555
|
+
this.onMouseDragEnd = options.onMouseDragEnd
|
|
1556
|
+
this.onMouseDrop = options.onMouseDrop
|
|
1557
|
+
this.onMouseOver = options.onMouseOver
|
|
1558
|
+
this.onMouseOut = options.onMouseOut
|
|
1559
|
+
this.onMouseScroll = options.onMouseScroll
|
|
1560
|
+
this.onPaste = options.onPaste
|
|
1561
|
+
this.onKeyDown = options.onKeyDown
|
|
1562
|
+
this.onSizeChange = options.onSizeChange
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
interface RenderCommandBase {
|
|
1567
|
+
action: "render" | "pushScissorRect" | "popScissorRect" | "pushOpacity" | "popOpacity"
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
interface RenderCommandPushScissorRect extends RenderCommandBase {
|
|
1571
|
+
action: "pushScissorRect"
|
|
1572
|
+
x: number
|
|
1573
|
+
y: number
|
|
1574
|
+
width: number
|
|
1575
|
+
height: number
|
|
1576
|
+
screenX: number
|
|
1577
|
+
screenY: number
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
interface RenderCommandPopScissorRect extends RenderCommandBase {
|
|
1581
|
+
action: "popScissorRect"
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
interface RenderCommandRender extends RenderCommandBase {
|
|
1585
|
+
action: "render"
|
|
1586
|
+
renderable: Renderable
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
interface RenderCommandPushOpacity extends RenderCommandBase {
|
|
1590
|
+
action: "pushOpacity"
|
|
1591
|
+
opacity: number
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
interface RenderCommandPopOpacity extends RenderCommandBase {
|
|
1595
|
+
action: "popOpacity"
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
export type RenderCommand =
|
|
1599
|
+
| RenderCommandPushScissorRect
|
|
1600
|
+
| RenderCommandPopScissorRect
|
|
1601
|
+
| RenderCommandRender
|
|
1602
|
+
| RenderCommandPushOpacity
|
|
1603
|
+
| RenderCommandPopOpacity
|
|
1604
|
+
|
|
1605
|
+
export class RootRenderable extends Renderable {
|
|
1606
|
+
private renderList: RenderCommand[] = []
|
|
1607
|
+
|
|
1608
|
+
constructor(ctx: RenderContext) {
|
|
1609
|
+
super(ctx, { id: "__root__", zIndex: 0, visible: true, width: ctx.width, height: ctx.height, enableLayout: true })
|
|
1610
|
+
|
|
1611
|
+
if (this.yogaNode) {
|
|
1612
|
+
this.yogaNode.free()
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
this.yogaNode = Yoga.Node.create(yogaConfig)
|
|
1616
|
+
this.yogaNode.setWidth(ctx.width)
|
|
1617
|
+
this.yogaNode.setHeight(ctx.height)
|
|
1618
|
+
this.yogaNode.setFlexDirection(FlexDirection.Column)
|
|
1619
|
+
|
|
1620
|
+
this.calculateLayout()
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
public override render(buffer: OptimizedBuffer, deltaTime: number): void {
|
|
1624
|
+
if (!this.visible) return
|
|
1625
|
+
|
|
1626
|
+
// 0. Run lifecycle pass
|
|
1627
|
+
for (const renderable of this._ctx.getLifecyclePasses()) {
|
|
1628
|
+
renderable.onLifecyclePass?.call(renderable)
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
// NOTE: Strictly speaking, this is a 3-pass rendering process:
|
|
1632
|
+
// 1. Calculate layout from root
|
|
1633
|
+
// 2. Update layout throughout the tree and collect render list
|
|
1634
|
+
// 3. Render all collected renderables
|
|
1635
|
+
// Should be 2-pass by hooking into the calculateLayout phase,
|
|
1636
|
+
// but that's only possible if we move the layout tree to native.
|
|
1637
|
+
|
|
1638
|
+
// 1. Calculate layout from root
|
|
1639
|
+
if (this.yogaNode.isDirty()) {
|
|
1640
|
+
this.calculateLayout()
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
// 2. Update layout throughout the tree and collect render list
|
|
1644
|
+
this.renderList.length = 0
|
|
1645
|
+
this.updateLayout(deltaTime, this.renderList)
|
|
1646
|
+
|
|
1647
|
+
// 3. Render all collected renderables
|
|
1648
|
+
this._ctx.clearHitGridScissorRects()
|
|
1649
|
+
for (let i = 1; i < this.renderList.length; i++) {
|
|
1650
|
+
const command = this.renderList[i]
|
|
1651
|
+
switch (command.action) {
|
|
1652
|
+
case "render":
|
|
1653
|
+
// Skip if renderable was destroyed during a previous render callback
|
|
1654
|
+
if (!command.renderable.isDestroyed) {
|
|
1655
|
+
command.renderable.render(buffer, deltaTime)
|
|
1656
|
+
}
|
|
1657
|
+
break
|
|
1658
|
+
case "pushScissorRect":
|
|
1659
|
+
buffer.pushScissorRect(command.x, command.y, command.width, command.height)
|
|
1660
|
+
this._ctx.pushHitGridScissorRect(command.screenX, command.screenY, command.width, command.height)
|
|
1661
|
+
break
|
|
1662
|
+
case "popScissorRect":
|
|
1663
|
+
buffer.popScissorRect()
|
|
1664
|
+
this._ctx.popHitGridScissorRect()
|
|
1665
|
+
break
|
|
1666
|
+
case "pushOpacity":
|
|
1667
|
+
buffer.pushOpacity(command.opacity)
|
|
1668
|
+
break
|
|
1669
|
+
case "popOpacity":
|
|
1670
|
+
buffer.popOpacity()
|
|
1671
|
+
break
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
protected override propagateLiveCount(delta: number): void {
|
|
1677
|
+
const oldCount = this._liveCount
|
|
1678
|
+
this._liveCount += delta
|
|
1679
|
+
|
|
1680
|
+
if (oldCount === 0 && this._liveCount > 0) {
|
|
1681
|
+
this._ctx.requestLive()
|
|
1682
|
+
} else if (oldCount > 0 && this._liveCount === 0) {
|
|
1683
|
+
this._ctx.dropLive()
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
public calculateLayout(): void {
|
|
1688
|
+
this.yogaNode.calculateLayout(this.width, this.height, Direction.LTR)
|
|
1689
|
+
this.emit(LayoutEvents.LAYOUT_CHANGED)
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
public resize(width: number, height: number): void {
|
|
1693
|
+
this.width = width
|
|
1694
|
+
this.height = height
|
|
1695
|
+
|
|
1696
|
+
this.emit(LayoutEvents.RESIZED, { width, height })
|
|
1697
|
+
}
|
|
1698
|
+
}
|