@xincli/opentui-core 0.4.6
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 +63 -0
- 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/test-tmux-theme-queries.sh +151 -0
- package/dev/thai-debug-test.ts +68 -0
- package/dev/theme-mode.ts +290 -0
- package/docs/development.md +144 -0
- package/package.json +102 -0
- package/prebuilt/aarch64-android/libopentui.so +0 -0
- package/scripts/build-android.ts +226 -0
- package/scripts/build-native-termux.sh +525 -0
- package/scripts/build.ts +530 -0
- package/scripts/dist-test.ts +312 -0
- package/scripts/package-prebuilt.ts +110 -0
- package/scripts/publish.ts +60 -0
- package/scripts/test-node-hook.mjs +16 -0
- package/scripts/test-node.ts +241 -0
- package/scripts/vendor-deps.sh +73 -0
- package/src/NativeSpanFeed.ts +375 -0
- package/src/Renderable.ts +1878 -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 +22 -0
- package/src/audio.ts +479 -0
- package/src/benchmark/attenuation-benchmark.ts +81 -0
- package/src/benchmark/audio-playback-benchmark.ts +344 -0
- package/src/benchmark/box-draw-benchmark.ts +1042 -0
- package/src/benchmark/colormatrix-benchmark.ts +123 -0
- package/src/benchmark/gain-benchmark.ts +80 -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/layout-benchmark.ts +2547 -0
- package/src/benchmark/markdown-benchmark.ts +1796 -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/render-traversal-benchmark.ts +928 -0
- package/src/benchmark/text-buffer-render-benchmark.ts +874 -0
- package/src/benchmark/text-table-benchmark.ts +948 -0
- package/src/buffer.test.ts +292 -0
- package/src/buffer.ts +564 -0
- package/src/console.test.ts +629 -0
- package/src/console.ts +1253 -0
- package/src/edit-buffer.test.ts +1852 -0
- package/src/edit-buffer.ts +417 -0
- package/src/editor-view.test.ts +1056 -0
- package/src/editor-view.ts +290 -0
- package/src/index.ts +25 -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 +60 -0
- package/src/lib/RGBA.ts +343 -0
- package/src/lib/ascii.font.ts +330 -0
- package/src/lib/border.test.ts +83 -0
- package/src/lib/border.ts +170 -0
- package/src/lib/bunfs.test.ts +27 -0
- package/src/lib/bunfs.ts +18 -0
- package/src/lib/clipboard.test.ts +63 -0
- package/src/lib/clipboard.ts +41 -0
- package/src/lib/clock.ts +35 -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 +324 -0
- package/src/lib/extmarks.test.ts +3547 -0
- package/src/lib/extmarks.ts +861 -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 +22 -0
- package/src/lib/keybinding.internal.test.ts +342 -0
- package/src/lib/keybinding.internal.ts +182 -0
- package/src/lib/objects-in-viewport.test.ts +789 -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 +347 -0
- package/src/lib/parse.keypress-kitty.test.ts +712 -0
- package/src/lib/parse.keypress-kitty.ts +470 -0
- package/src/lib/parse.keypress.test.ts +2020 -0
- package/src/lib/parse.keypress.ts +480 -0
- package/src/lib/parse.mouse.test.ts +552 -0
- package/src/lib/parse.mouse.ts +232 -0
- package/src/lib/paste.ts +18 -0
- package/src/lib/queue.ts +65 -0
- package/src/lib/render-geometry.ts +36 -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 +261 -0
- package/src/lib/singleton.ts +34 -0
- package/src/lib/stdin-parser.test.ts +2439 -0
- package/src/lib/stdin-parser.ts +2007 -0
- package/src/lib/styled-text.ts +178 -0
- package/src/lib/terminal-capability-detection.test.ts +226 -0
- package/src/lib/terminal-capability-detection.ts +98 -0
- package/src/lib/terminal-palette.test.ts +954 -0
- package/src/lib/terminal-palette.ts +441 -0
- package/src/lib/tree-sitter/assets/README.md +119 -0
- package/src/lib/tree-sitter/assets/javascript/highlights.scm +205 -0
- package/src/lib/tree-sitter/assets/javascript/tree-sitter-javascript.wasm +0 -0
- package/src/lib/tree-sitter/assets/markdown/highlights.scm +150 -0
- package/src/lib/tree-sitter/assets/markdown/injections.scm +27 -0
- package/src/lib/tree-sitter/assets/markdown/tree-sitter-markdown.wasm +0 -0
- package/src/lib/tree-sitter/assets/markdown_inline/highlights.scm +115 -0
- package/src/lib/tree-sitter/assets/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
- package/src/lib/tree-sitter/assets/typescript/highlights.scm +604 -0
- package/src/lib/tree-sitter/assets/typescript/tree-sitter-typescript.wasm +0 -0
- package/src/lib/tree-sitter/assets/update.ts +360 -0
- package/src/lib/tree-sitter/assets/zig/highlights.scm +284 -0
- package/src/lib/tree-sitter/assets/zig/tree-sitter-zig.wasm +0 -0
- package/src/lib/tree-sitter/assets.d.ts +9 -0
- package/src/lib/tree-sitter/cache.test.ts +291 -0
- package/src/lib/tree-sitter/client.test.ts +1434 -0
- package/src/lib/tree-sitter/client.ts +847 -0
- package/src/lib/tree-sitter/default-parsers.ts +133 -0
- package/src/lib/tree-sitter/download-utils.ts +148 -0
- package/src/lib/tree-sitter/index.ts +75 -0
- package/src/lib/tree-sitter/parser.worker.ts +1098 -0
- package/src/lib/tree-sitter/parsers-config.ts +81 -0
- package/src/lib/tree-sitter/resolve-ft.test.ts +55 -0
- package/src/lib/tree-sitter/resolve-ft.ts +189 -0
- package/src/lib/tree-sitter/types.ts +132 -0
- package/src/lib/tree-sitter/update-assets.ts +10 -0
- package/src/lib/tree-sitter-styled-text.test.ts +1253 -0
- package/src/lib/tree-sitter-styled-text.ts +314 -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/native-event-worker-repro.test.ts +48 -0
- package/src/native-event-worker-repro.worker.ts +9 -0
- package/src/native-handle.test.ts +221 -0
- package/src/platform/ffi.test.ts +516 -0
- package/src/platform/ffi.ts +653 -0
- package/src/platform/runtime.test.ts +52 -0
- package/src/platform/runtime.ts +121 -0
- package/src/platform/test.ts +45 -0
- package/src/platform/worker-handler-cleanup.fixture.ts +12 -0
- package/src/platform/worker-onmessage-startup.fixture.ts +10 -0
- package/src/platform/worker-startup.fixture.ts +9 -0
- package/src/platform/worker.node-test.ts +153 -0
- package/src/platform/worker.ts +425 -0
- package/src/plugins/core-slot.ts +579 -0
- package/src/plugins/registry.ts +402 -0
- package/src/plugins/types.ts +46 -0
- package/src/post/effects.ts +948 -0
- package/src/post/filters.ts +512 -0
- package/src/post/matrices.ts +288 -0
- package/src/renderables/ASCIIFont.ts +219 -0
- package/src/renderables/Box.test.ts +474 -0
- package/src/renderables/Box.ts +353 -0
- package/src/renderables/Code.test.ts +2388 -0
- package/src/renderables/Code.ts +555 -0
- package/src/renderables/Diff.regression.test.ts +381 -0
- package/src/renderables/Diff.test.ts +3212 -0
- package/src/renderables/Diff.ts +1278 -0
- package/src/renderables/EditBufferRenderable.test.ts +288 -0
- package/src/renderables/EditBufferRenderable.ts +1152 -0
- package/src/renderables/FrameBuffer.ts +47 -0
- package/src/renderables/Input.test.ts +1310 -0
- package/src/renderables/Input.ts +273 -0
- package/src/renderables/LineNumberRenderable.ts +725 -0
- package/src/renderables/Markdown.ts +2144 -0
- package/src/renderables/ScrollBar.ts +423 -0
- package/src/renderables/ScrollBox.ts +903 -0
- package/src/renderables/Select.test.ts +1134 -0
- package/src/renderables/Select.ts +535 -0
- package/src/renderables/Slider.test.ts +456 -0
- package/src/renderables/Slider.ts +342 -0
- package/src/renderables/TabSelect.test.ts +238 -0
- package/src/renderables/TabSelect.ts +447 -0
- package/src/renderables/Text.selection-buffer.test.ts +118 -0
- package/src/renderables/Text.test.ts +2662 -0
- package/src/renderables/Text.ts +147 -0
- package/src/renderables/TextBufferRenderable.ts +504 -0
- package/src/renderables/TextNode.test.ts +1137 -0
- package/src/renderables/TextNode.ts +379 -0
- package/src/renderables/TextTable.test.ts +1411 -0
- package/src/renderables/TextTable.ts +1434 -0
- package/src/renderables/Textarea.ts +425 -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__/Code.test.ts +55 -0
- package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
- package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +827 -0
- package/src/renderables/__tests__/LineNumberRenderable.test.ts +1906 -0
- package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
- package/src/renderables/__tests__/Markdown.code-colors.test.ts +288 -0
- package/src/renderables/__tests__/Markdown.test.ts +4175 -0
- package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
- package/src/renderables/__tests__/Textarea.buffer.test.ts +683 -0
- package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
- package/src/renderables/__tests__/Textarea.editing.test.ts +2120 -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 +3275 -0
- package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
- package/src/renderables/__tests__/Textarea.rendering.test.ts +1927 -0
- package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
- package/src/renderables/__tests__/Textarea.selection.test.ts +1589 -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 +241 -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 +277 -0
- package/src/renderables/index.ts +23 -0
- package/src/renderables/markdown-parser.ts +79 -0
- package/src/renderer-theme-mode.ts +199 -0
- package/src/renderer.ts +4975 -0
- package/src/runtime-plugin-support-configure.ts +63 -0
- package/src/runtime-plugin-support.ts +13 -0
- package/src/runtime-plugin.ts +626 -0
- package/src/specs/terminal-startup.md +64 -0
- package/src/syntax-style.test.ts +841 -0
- package/src/syntax-style.ts +274 -0
- package/src/testing/README.md +219 -0
- package/src/testing/bun-test-node.ts +880 -0
- package/src/testing/capture-spans.test.ts +216 -0
- package/src/testing/integration.test.ts +276 -0
- package/src/testing/manual-clock.ts +117 -0
- package/src/testing/mock-keys.test.ts +1378 -0
- package/src/testing/mock-keys.ts +457 -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 +81 -0
- package/src/testing/spy.ts +13 -0
- package/src/testing/terminal-capabilities.ts +47 -0
- package/src/testing/test-recorder.test.ts +410 -0
- package/src/testing/test-recorder.ts +133 -0
- package/src/testing/test-renderer.ts +375 -0
- package/src/testing/test-renderer.wait.test.ts +278 -0
- package/src/testing/test-streams.ts +31 -0
- package/src/testing.ts +9 -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 +53 -0
- package/src/tests/audio.test.ts +303 -0
- package/src/tests/destroy-during-render.test.ts +200 -0
- package/src/tests/destroy-on-exit.fixture.ts +36 -0
- package/src/tests/destroy-on-exit.test.ts +62 -0
- package/src/tests/ffi-borrowed-pointer-callsites.test.ts +153 -0
- package/src/tests/hover-cursor.test.ts +98 -0
- package/src/tests/native-backed-measurement-lifecycle.test.ts +133 -0
- package/src/tests/native-backed-measurement-parity.test.ts +322 -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 +384 -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 +1851 -0
- package/src/tests/renderer.clock.test.ts +270 -0
- package/src/tests/renderer.console-startup.test.ts +2151 -0
- package/src/tests/renderer.control.test.ts +458 -0
- package/src/tests/renderer.core-slot-binding.test.ts +962 -0
- package/src/tests/renderer.cursor.test.ts +26 -0
- package/src/tests/renderer.custom-stdout.test.ts +1112 -0
- package/src/tests/renderer.destroy-during-render.test.ts +147 -0
- package/src/tests/renderer.focus-restore.test.ts +257 -0
- package/src/tests/renderer.focus.test.ts +329 -0
- package/src/tests/renderer.idle.test.ts +219 -0
- package/src/tests/renderer.input.test.ts +2615 -0
- package/src/tests/renderer.kitty-flags.test.ts +195 -0
- package/src/tests/renderer.lifecycle.test.ts +34 -0
- package/src/tests/renderer.mouse.test.ts +1315 -0
- package/src/tests/renderer.notifications.test.ts +27 -0
- package/src/tests/renderer.palette.test.ts +1199 -0
- package/src/tests/renderer.remote.test.ts +247 -0
- package/src/tests/renderer.render-stats.test.ts +146 -0
- package/src/tests/renderer.scrollback-surface.test.ts +474 -0
- package/src/tests/renderer.selection.test.ts +138 -0
- package/src/tests/renderer.slot-registry.test.ts +684 -0
- package/src/tests/renderer.tracker.test.ts +202 -0
- package/src/tests/renderer.useMouse.test.ts +83 -0
- package/src/tests/runtime-plugin-node-modules-cycle.fixture.ts +76 -0
- package/src/tests/runtime-plugin-node-modules-import-like-string.fixture.ts +48 -0
- package/src/tests/runtime-plugin-node-modules-mjs.fixture.ts +43 -0
- package/src/tests/runtime-plugin-node-modules-no-bare-rewrite.fixture.ts +67 -0
- package/src/tests/runtime-plugin-node-modules-package-type-cache.fixture.ts +72 -0
- package/src/tests/runtime-plugin-node-modules-runtime-specifier.fixture.ts +44 -0
- package/src/tests/runtime-plugin-node-modules-scoped-package-bare-rewrite.fixture.ts +85 -0
- package/src/tests/runtime-plugin-path-alias.fixture.ts +43 -0
- package/src/tests/runtime-plugin-resolve-roots.fixture.ts +65 -0
- package/src/tests/runtime-plugin-support-configure.fixture.ts +31 -0
- package/src/tests/runtime-plugin-support-late-addition.fixture.ts +17 -0
- package/src/tests/runtime-plugin-support.fixture.ts +11 -0
- package/src/tests/runtime-plugin-support.test.ts +54 -0
- package/src/tests/runtime-plugin-windows-file-url.fixture.ts +30 -0
- package/src/tests/runtime-plugin.fixture.ts +40 -0
- package/src/tests/runtime-plugin.test.ts +369 -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 +1895 -0
- package/src/tests/wrap-resize-perf.test.ts +276 -0
- package/src/tests/yoga-api-coverage.test.ts +409 -0
- package/src/tests/yoga-callback-stress.test.ts +122 -0
- package/src/tests/yoga-ffi.test.ts +117 -0
- package/src/tests/yoga-setters.test.ts +921 -0
- package/src/tests/yoga-upstream/YGAlignBaselineTest.test.ts +124 -0
- package/src/tests/yoga-upstream/YGComputedBorderTest.test.ts +27 -0
- package/src/tests/yoga-upstream/YGComputedMarginTest.test.ts +27 -0
- package/src/tests/yoga-upstream/YGComputedPaddingTest.test.ts +27 -0
- package/src/tests/yoga-upstream/YGDirtiedTest.test.ts +157 -0
- package/src/tests/yoga-upstream/YGErrataTest.test.ts +40 -0
- package/src/tests/yoga-upstream/YGFlexBasisAuto.test.ts +23 -0
- package/src/tests/yoga-upstream/YGHasNewLayout.test.ts +81 -0
- package/src/tests/yoga-upstream/YGMeasureCacheTest.test.ts +31 -0
- package/src/tests/yoga-upstream/YGMeasureTest.test.ts +70 -0
- package/src/tests/yoga-upstream/generated/YGAbsolutePositionTest.test.ts +1864 -0
- package/src/tests/yoga-upstream/generated/YGAlignContentTest.test.ts +5829 -0
- package/src/tests/yoga-upstream/generated/YGAlignItemsTest.test.ts +2444 -0
- package/src/tests/yoga-upstream/generated/YGAlignSelfTest.test.ts +293 -0
- package/src/tests/yoga-upstream/generated/YGAndroidNewsFeed.test.ts +315 -0
- package/src/tests/yoga-upstream/generated/YGAspectRatioTest.test.ts +231 -0
- package/src/tests/yoga-upstream/generated/YGAutoTest.test.ts +347 -0
- package/src/tests/yoga-upstream/generated/YGBorderTest.test.ts +256 -0
- package/src/tests/yoga-upstream/generated/YGBoxSizingTest.test.ts +2747 -0
- package/src/tests/yoga-upstream/generated/YGDimensionTest.test.ts +129 -0
- package/src/tests/yoga-upstream/generated/YGDisplayContentsTest.test.ts +109 -0
- package/src/tests/yoga-upstream/generated/YGDisplayTest.test.ts +1097 -0
- package/src/tests/yoga-upstream/generated/YGFlexDirectionTest.test.ts +4562 -0
- package/src/tests/yoga-upstream/generated/YGFlexTest.test.ts +677 -0
- package/src/tests/yoga-upstream/generated/YGFlexWrapTest.test.ts +2071 -0
- package/src/tests/yoga-upstream/generated/YGGapTest.test.ts +3303 -0
- package/src/tests/yoga-upstream/generated/YGIntrinsicSizeTest.test.ts +582 -0
- package/src/tests/yoga-upstream/generated/YGJustifyContentTest.test.ts +2150 -0
- package/src/tests/yoga-upstream/generated/YGMarginTest.test.ts +1963 -0
- package/src/tests/yoga-upstream/generated/YGMinMaxDimensionTest.test.ts +1446 -0
- package/src/tests/yoga-upstream/generated/YGPaddingTest.test.ts +354 -0
- package/src/tests/yoga-upstream/generated/YGPercentageTest.test.ts +1760 -0
- package/src/tests/yoga-upstream/generated/YGRoundingTest.test.ts +1161 -0
- package/src/tests/yoga-upstream/generated/YGSizeOverflowTest.test.ts +207 -0
- package/src/tests/yoga-upstream/generated/YGStaticPositionTest.test.ts +6338 -0
- package/src/tests/yoga-upstream/tools/MeasureCounter.ts +54 -0
- package/src/tests/yoga-upstream/tools/utils.ts +81 -0
- package/src/text-buffer-view.test.ts +722 -0
- package/src/text-buffer-view.ts +193 -0
- package/src/text-buffer.test.ts +512 -0
- package/src/text-buffer.ts +250 -0
- package/src/types.ts +199 -0
- package/src/utils.ts +88 -0
- package/src/yoga.ts +1146 -0
- package/src/zig/ansi.zig +502 -0
- package/src/zig/audio.zig +1206 -0
- package/src/zig/bench/README.md +50 -0
- package/src/zig/bench/buffer-color-blending_bench.zig +350 -0
- package/src/zig/bench/buffer-draw-box_bench.zig +786 -0
- package/src/zig/bench/buffer-draw-text-buffer_bench.zig +894 -0
- package/src/zig/bench/edit-buffer_bench.zig +476 -0
- package/src/zig/bench/editor-view_bench.zig +169 -0
- package/src/zig/bench/native-span-feed_bench.zig +107 -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 +476 -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 +272 -0
- package/src/zig/bench/utf8_bench.zig +799 -0
- package/src/zig/bench-utils.zig +431 -0
- package/src/zig/bench.zig +223 -0
- package/src/zig/buffer-methods.zig +215 -0
- package/src/zig/buffer.zig +2515 -0
- package/src/zig/build.zig +700 -0
- package/src/zig/build.zig.zon +19 -0
- package/src/zig/edit-buffer.zig +900 -0
- package/src/zig/editor-view.zig +812 -0
- package/src/zig/event-bus.zig +28 -0
- package/src/zig/event-emitter.zig +65 -0
- package/src/zig/file-logger.zig +92 -0
- package/src/zig/grapheme.zig +838 -0
- package/src/zig/handles.zig +267 -0
- package/src/zig/lib.zig +2813 -0
- package/src/zig/link.zig +349 -0
- package/src/zig/logger.zig +43 -0
- package/src/zig/mem-registry.zig +126 -0
- package/src/zig/miniaudio_shim.c +21 -0
- package/src/zig/native-renderable.zig +112 -0
- package/src/zig/native-span-feed-bench-lib.zig +7 -0
- package/src/zig/native-span-feed.zig +747 -0
- package/src/zig/renderer-output.zig +677 -0
- package/src/zig/renderer.zig +2106 -0
- package/src/zig/rope.zig +1220 -0
- package/src/zig/split-scrollback.zig +88 -0
- package/src/zig/syntax-style.zig +174 -0
- package/src/zig/terminal.zig +1652 -0
- package/src/zig/test.zig +82 -0
- package/src/zig/tests/README.md +18 -0
- package/src/zig/tests/ansi_test.zig +18 -0
- package/src/zig/tests/audio_test.zig +439 -0
- package/src/zig/tests/buffer-methods_test.zig +1111 -0
- package/src/zig/tests/buffer_test.zig +2926 -0
- package/src/zig/tests/edit-buffer-history_test.zig +299 -0
- package/src/zig/tests/edit-buffer_test.zig +1688 -0
- package/src/zig/tests/editor-view_test.zig +3454 -0
- package/src/zig/tests/event-emitter_test.zig +249 -0
- package/src/zig/tests/grapheme_test.zig +1329 -0
- package/src/zig/tests/handles_test.zig +123 -0
- package/src/zig/tests/link_test.zig +220 -0
- package/src/zig/tests/mem-registry_test.zig +473 -0
- package/src/zig/tests/memory_leak_regression_test.zig +234 -0
- package/src/zig/tests/native-renderable_test.zig +16 -0
- package/src/zig/tests/native-span-feed_test.zig +1266 -0
- package/src/zig/tests/renderer_test.zig +2604 -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/split-scrollback_test.zig +70 -0
- package/src/zig/tests/syntax-style_test.zig +558 -0
- package/src/zig/tests/terminal_test.zig +1489 -0
- package/src/zig/tests/test-renderer.zig +126 -0
- package/src/zig/tests/text-buffer-drawing_test.zig +3291 -0
- package/src/zig/tests/text-buffer-highlights_test.zig +706 -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 +1056 -0
- package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
- package/src/zig/tests/text-buffer-view_test.zig +3672 -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 +4060 -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/tests/yoga_test.zig +65 -0
- package/src/zig/text-buffer-iterators.zig +496 -0
- package/src/zig/text-buffer-segment.zig +403 -0
- package/src/zig/text-buffer-view.zig +1428 -0
- package/src/zig/text-buffer.zig +1272 -0
- package/src/zig/utf8.zig +1954 -0
- package/src/zig/utils.zig +12 -0
- package/src/zig/uucode-stub.zig +76 -0
- package/src/zig/vendor/miniaudio/miniaudio.h +93468 -0
- package/src/zig/yoga.zig +658 -0
- package/src/zig-structs.ts +381 -0
- package/src/zig.ts +5260 -0
- package/tsconfig.build.json +17 -0
- package/tsconfig.json +27 -0
- package/tsconfig.node-test.json +138 -0
|
@@ -0,0 +1,909 @@
|
|
|
1
|
+
import { test, expect, beforeEach, afterEach } from "bun:test"
|
|
2
|
+
import { createTestRenderer, MouseButtons, type MockMouse, type TestRenderer } from "../testing.js"
|
|
3
|
+
import { ScrollBoxRenderable } from "../renderables/ScrollBox.js"
|
|
4
|
+
import { BoxRenderable } from "../renderables/Box.js"
|
|
5
|
+
import { Renderable } from "../Renderable.js"
|
|
6
|
+
|
|
7
|
+
let testRenderer: TestRenderer
|
|
8
|
+
let mockMouse: MockMouse
|
|
9
|
+
|
|
10
|
+
class MovingBoxRenderable extends BoxRenderable {
|
|
11
|
+
public shouldMove = false
|
|
12
|
+
|
|
13
|
+
protected onUpdate(_deltaTime: number): void {
|
|
14
|
+
if (this.shouldMove) {
|
|
15
|
+
this.shouldMove = false
|
|
16
|
+
this.translateY = 3
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
beforeEach(async () => {
|
|
22
|
+
;({ renderer: testRenderer, mockMouse } = await createTestRenderer({
|
|
23
|
+
width: 50,
|
|
24
|
+
height: 30,
|
|
25
|
+
}))
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
testRenderer.destroy()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test("hit grid updates after render when scrollbox scrolls", async () => {
|
|
33
|
+
const scrollBox = new ScrollBoxRenderable(testRenderer, {
|
|
34
|
+
width: 40,
|
|
35
|
+
height: 20,
|
|
36
|
+
scrollY: true,
|
|
37
|
+
})
|
|
38
|
+
testRenderer.root.add(scrollBox)
|
|
39
|
+
|
|
40
|
+
const items: BoxRenderable[] = []
|
|
41
|
+
for (let i = 0; i < 30; i++) {
|
|
42
|
+
const item = new BoxRenderable(testRenderer, {
|
|
43
|
+
id: `item-${i}`,
|
|
44
|
+
height: 2,
|
|
45
|
+
backgroundColor: i % 2 === 0 ? "red" : "blue",
|
|
46
|
+
})
|
|
47
|
+
items.push(item)
|
|
48
|
+
scrollBox.add(item)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
await testRenderer.idle()
|
|
52
|
+
|
|
53
|
+
const item0 = items[0]
|
|
54
|
+
const item4 = items[4]
|
|
55
|
+
|
|
56
|
+
expect(item0.y).toBe(0)
|
|
57
|
+
expect(item4.y).toBe(8)
|
|
58
|
+
|
|
59
|
+
const checkHitAt = (x: number, y: number): Renderable | undefined => {
|
|
60
|
+
const renderableId = testRenderer.hitTest(x, y)
|
|
61
|
+
return Renderable.renderablesByNumber.get(renderableId)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let hitAtItem0 = checkHitAt(5, item0.y)
|
|
65
|
+
expect(hitAtItem0?.id).toBe("item-0")
|
|
66
|
+
|
|
67
|
+
let hitAtItem4 = checkHitAt(5, item4.y)
|
|
68
|
+
expect(hitAtItem4?.id).toBe("item-4")
|
|
69
|
+
|
|
70
|
+
scrollBox.scrollTop = 10
|
|
71
|
+
|
|
72
|
+
expect(item0.y).toBe(-10)
|
|
73
|
+
expect(item4.y).toBe(-2)
|
|
74
|
+
|
|
75
|
+
const item5 = items[5]
|
|
76
|
+
const item9 = items[9]
|
|
77
|
+
|
|
78
|
+
expect(item5.y).toBe(0)
|
|
79
|
+
expect(item9.y).toBe(8)
|
|
80
|
+
|
|
81
|
+
// Hit grid updates after render
|
|
82
|
+
await testRenderer.idle()
|
|
83
|
+
|
|
84
|
+
const hitAtItem5 = checkHitAt(5, item5.y)
|
|
85
|
+
expect(hitAtItem5?.id).toBe("item-5")
|
|
86
|
+
|
|
87
|
+
const hitAtItem9 = checkHitAt(5, item9.y)
|
|
88
|
+
expect(hitAtItem9?.id).toBe("item-9")
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
test("hover updates after scroll when pointer moves", async () => {
|
|
92
|
+
const scrollBox = new ScrollBoxRenderable(testRenderer, {
|
|
93
|
+
width: 20,
|
|
94
|
+
height: 6,
|
|
95
|
+
scrollY: true,
|
|
96
|
+
})
|
|
97
|
+
testRenderer.root.add(scrollBox)
|
|
98
|
+
|
|
99
|
+
const hoverEvents: string[] = []
|
|
100
|
+
let hoveredId: string | null = null
|
|
101
|
+
|
|
102
|
+
const items: BoxRenderable[] = []
|
|
103
|
+
for (let i = 0; i < 5; i++) {
|
|
104
|
+
const itemId = `item-${i}`
|
|
105
|
+
const item = new BoxRenderable(testRenderer, {
|
|
106
|
+
id: itemId,
|
|
107
|
+
width: "100%",
|
|
108
|
+
height: 2,
|
|
109
|
+
onMouseOver: () => {
|
|
110
|
+
hoveredId = itemId
|
|
111
|
+
hoverEvents.push(`over:${itemId}`)
|
|
112
|
+
},
|
|
113
|
+
onMouseOut: () => {
|
|
114
|
+
if (hoveredId === itemId) {
|
|
115
|
+
hoveredId = null
|
|
116
|
+
}
|
|
117
|
+
hoverEvents.push(`out:${itemId}`)
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
items.push(item)
|
|
121
|
+
scrollBox.add(item)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
await testRenderer.idle()
|
|
125
|
+
|
|
126
|
+
const pointerX = items[0].x + 1
|
|
127
|
+
const pointerY = items[0].y + 1
|
|
128
|
+
|
|
129
|
+
await mockMouse.moveTo(pointerX, pointerY)
|
|
130
|
+
expect(hoveredId!).toBe("item-0")
|
|
131
|
+
expect(hoverEvents).toEqual(["over:item-0"])
|
|
132
|
+
|
|
133
|
+
scrollBox.scrollTop = 2
|
|
134
|
+
await testRenderer.idle()
|
|
135
|
+
|
|
136
|
+
// Hover updates when pointer moves after scroll and render
|
|
137
|
+
await mockMouse.moveTo(pointerX, pointerY)
|
|
138
|
+
expect(hoveredId!).toBe("item-1")
|
|
139
|
+
expect(hoverEvents).toEqual(["over:item-0", "out:item-0", "over:item-1"])
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
test("hover updates after scroll without pointer movement", async () => {
|
|
143
|
+
const scrollBox = new ScrollBoxRenderable(testRenderer, {
|
|
144
|
+
width: 20,
|
|
145
|
+
height: 6,
|
|
146
|
+
scrollY: true,
|
|
147
|
+
})
|
|
148
|
+
testRenderer.root.add(scrollBox)
|
|
149
|
+
|
|
150
|
+
const hoverEvents: string[] = []
|
|
151
|
+
let hoveredId: string | null = null
|
|
152
|
+
|
|
153
|
+
const items: BoxRenderable[] = []
|
|
154
|
+
for (let i = 0; i < 5; i++) {
|
|
155
|
+
const itemId = `item-${i}`
|
|
156
|
+
const item = new BoxRenderable(testRenderer, {
|
|
157
|
+
id: itemId,
|
|
158
|
+
width: "100%",
|
|
159
|
+
height: 2,
|
|
160
|
+
onMouseOver: () => {
|
|
161
|
+
hoveredId = itemId
|
|
162
|
+
hoverEvents.push(`over:${itemId}`)
|
|
163
|
+
},
|
|
164
|
+
onMouseOut: () => {
|
|
165
|
+
if (hoveredId === itemId) {
|
|
166
|
+
hoveredId = null
|
|
167
|
+
}
|
|
168
|
+
hoverEvents.push(`out:${itemId}`)
|
|
169
|
+
},
|
|
170
|
+
})
|
|
171
|
+
items.push(item)
|
|
172
|
+
scrollBox.add(item)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
await testRenderer.idle()
|
|
176
|
+
|
|
177
|
+
const pointerX = items[0].x + 1
|
|
178
|
+
const pointerY = items[0].y + 1
|
|
179
|
+
|
|
180
|
+
await mockMouse.moveTo(pointerX, pointerY)
|
|
181
|
+
expect(hoveredId!).toBe("item-0")
|
|
182
|
+
expect(hoverEvents).toEqual(["over:item-0"])
|
|
183
|
+
|
|
184
|
+
scrollBox.scrollTop = 2
|
|
185
|
+
await testRenderer.idle()
|
|
186
|
+
|
|
187
|
+
expect(hoveredId!).toBe("item-1")
|
|
188
|
+
expect(hoverEvents).toEqual(["over:item-0", "out:item-0", "over:item-1"])
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
test("hover recheck uses neutral button and modifiers", async () => {
|
|
192
|
+
const scrollBox = new ScrollBoxRenderable(testRenderer, {
|
|
193
|
+
width: 20,
|
|
194
|
+
height: 6,
|
|
195
|
+
scrollY: true,
|
|
196
|
+
})
|
|
197
|
+
testRenderer.root.add(scrollBox)
|
|
198
|
+
|
|
199
|
+
const hoverEvents: Array<{
|
|
200
|
+
type: "over" | "out"
|
|
201
|
+
button: number
|
|
202
|
+
modifiers: { shift: boolean; alt: boolean; ctrl: boolean }
|
|
203
|
+
}> = []
|
|
204
|
+
let hoveredId: string | null = null
|
|
205
|
+
|
|
206
|
+
const items: BoxRenderable[] = []
|
|
207
|
+
for (let i = 0; i < 5; i++) {
|
|
208
|
+
const itemId = `item-${i}`
|
|
209
|
+
const item = new BoxRenderable(testRenderer, {
|
|
210
|
+
id: itemId,
|
|
211
|
+
width: "100%",
|
|
212
|
+
height: 2,
|
|
213
|
+
onMouseOver: (event) => {
|
|
214
|
+
hoveredId = itemId
|
|
215
|
+
hoverEvents.push({
|
|
216
|
+
type: "over",
|
|
217
|
+
button: event.button,
|
|
218
|
+
modifiers: { ...event.modifiers },
|
|
219
|
+
})
|
|
220
|
+
},
|
|
221
|
+
onMouseOut: (event) => {
|
|
222
|
+
if (hoveredId === itemId) {
|
|
223
|
+
hoveredId = null
|
|
224
|
+
}
|
|
225
|
+
hoverEvents.push({
|
|
226
|
+
type: "out",
|
|
227
|
+
button: event.button,
|
|
228
|
+
modifiers: { ...event.modifiers },
|
|
229
|
+
})
|
|
230
|
+
},
|
|
231
|
+
})
|
|
232
|
+
items.push(item)
|
|
233
|
+
scrollBox.add(item)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
await testRenderer.idle()
|
|
237
|
+
|
|
238
|
+
const pointerX = items[0].x + 1
|
|
239
|
+
const pointerY = items[0].y + 1
|
|
240
|
+
|
|
241
|
+
await mockMouse.moveTo(pointerX, pointerY, { modifiers: { shift: true } })
|
|
242
|
+
expect(hoveredId!).toBe("item-0")
|
|
243
|
+
|
|
244
|
+
await mockMouse.pressDown(pointerX, pointerY, MouseButtons.RIGHT, { modifiers: { shift: true } })
|
|
245
|
+
|
|
246
|
+
scrollBox.scrollTop = 2
|
|
247
|
+
await testRenderer.idle()
|
|
248
|
+
|
|
249
|
+
expect(hoveredId!).toBe("item-1")
|
|
250
|
+
expect(hoverEvents).toHaveLength(3)
|
|
251
|
+
const outEvent = hoverEvents[1]
|
|
252
|
+
const overEvent = hoverEvents[2]
|
|
253
|
+
// Synthetic hover recheck uses neutral button but preserves last known modifiers
|
|
254
|
+
expect(outEvent.button).toBe(0)
|
|
255
|
+
expect(outEvent.modifiers).toEqual({ shift: true, alt: false, ctrl: false })
|
|
256
|
+
expect(overEvent.button).toBe(0)
|
|
257
|
+
expect(overEvent.modifiers).toEqual({ shift: true, alt: false, ctrl: false })
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
test("hover recheck over event has no source when not dragging", async () => {
|
|
261
|
+
const scrollBox = new ScrollBoxRenderable(testRenderer, {
|
|
262
|
+
width: 20,
|
|
263
|
+
height: 6,
|
|
264
|
+
scrollY: true,
|
|
265
|
+
})
|
|
266
|
+
testRenderer.root.add(scrollBox)
|
|
267
|
+
|
|
268
|
+
const hoverEvents: Array<{
|
|
269
|
+
type: "over" | "out"
|
|
270
|
+
source: Renderable | undefined
|
|
271
|
+
}> = []
|
|
272
|
+
|
|
273
|
+
const items: BoxRenderable[] = []
|
|
274
|
+
for (let i = 0; i < 5; i++) {
|
|
275
|
+
const itemId = `item-${i}`
|
|
276
|
+
const item = new BoxRenderable(testRenderer, {
|
|
277
|
+
id: itemId,
|
|
278
|
+
width: "100%",
|
|
279
|
+
height: 2,
|
|
280
|
+
onMouseOver: (event) => {
|
|
281
|
+
hoverEvents.push({
|
|
282
|
+
type: "over",
|
|
283
|
+
source: event.source,
|
|
284
|
+
})
|
|
285
|
+
},
|
|
286
|
+
onMouseOut: (event) => {
|
|
287
|
+
hoverEvents.push({
|
|
288
|
+
type: "out",
|
|
289
|
+
source: event.source,
|
|
290
|
+
})
|
|
291
|
+
},
|
|
292
|
+
})
|
|
293
|
+
items.push(item)
|
|
294
|
+
scrollBox.add(item)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
await testRenderer.idle()
|
|
298
|
+
|
|
299
|
+
const pointerX = items[0].x + 1
|
|
300
|
+
const pointerY = items[0].y + 1
|
|
301
|
+
|
|
302
|
+
// Move to item-0 (not dragging)
|
|
303
|
+
await mockMouse.moveTo(pointerX, pointerY)
|
|
304
|
+
expect(hoverEvents).toHaveLength(1)
|
|
305
|
+
expect(hoverEvents[0].type).toBe("over")
|
|
306
|
+
expect(hoverEvents[0].source).toBeUndefined()
|
|
307
|
+
|
|
308
|
+
// Scroll to trigger hover recheck - should have no source since we're not dragging
|
|
309
|
+
scrollBox.scrollTop = 2
|
|
310
|
+
await testRenderer.idle()
|
|
311
|
+
|
|
312
|
+
expect(hoverEvents).toHaveLength(3)
|
|
313
|
+
// out event from item-0
|
|
314
|
+
expect(hoverEvents[1].type).toBe("out")
|
|
315
|
+
expect(hoverEvents[1].source).toBeUndefined()
|
|
316
|
+
// over event to item-1 - source should be undefined (not dragging)
|
|
317
|
+
expect(hoverEvents[2].type).toBe("over")
|
|
318
|
+
expect(hoverEvents[2].source).toBeUndefined()
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
test("hover updates on multiple scroll changes", async () => {
|
|
322
|
+
const scrollBox = new ScrollBoxRenderable(testRenderer, {
|
|
323
|
+
width: 20,
|
|
324
|
+
height: 6,
|
|
325
|
+
scrollY: true,
|
|
326
|
+
})
|
|
327
|
+
testRenderer.root.add(scrollBox)
|
|
328
|
+
|
|
329
|
+
const hoverEvents: string[] = []
|
|
330
|
+
let hoveredId: string | null = null
|
|
331
|
+
|
|
332
|
+
const items: BoxRenderable[] = []
|
|
333
|
+
for (let i = 0; i < 5; i++) {
|
|
334
|
+
const itemId = `item-${i}`
|
|
335
|
+
const item = new BoxRenderable(testRenderer, {
|
|
336
|
+
id: itemId,
|
|
337
|
+
width: "100%",
|
|
338
|
+
height: 2,
|
|
339
|
+
onMouseOver: () => {
|
|
340
|
+
hoveredId = itemId
|
|
341
|
+
hoverEvents.push(`over:${itemId}`)
|
|
342
|
+
},
|
|
343
|
+
onMouseOut: () => {
|
|
344
|
+
if (hoveredId === itemId) {
|
|
345
|
+
hoveredId = null
|
|
346
|
+
}
|
|
347
|
+
hoverEvents.push(`out:${itemId}`)
|
|
348
|
+
},
|
|
349
|
+
})
|
|
350
|
+
items.push(item)
|
|
351
|
+
scrollBox.add(item)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
await testRenderer.idle()
|
|
355
|
+
|
|
356
|
+
const pointerX = items[0].x + 1
|
|
357
|
+
const pointerY = items[0].y + 1
|
|
358
|
+
|
|
359
|
+
await mockMouse.moveTo(pointerX, pointerY)
|
|
360
|
+
expect(hoveredId!).toBe("item-0")
|
|
361
|
+
expect(hoverEvents).toEqual(["over:item-0"])
|
|
362
|
+
|
|
363
|
+
// First scroll - hover recheck happens immediately after render
|
|
364
|
+
scrollBox.scrollTop = 2
|
|
365
|
+
await testRenderer.idle()
|
|
366
|
+
expect(hoveredId!).toBe("item-1")
|
|
367
|
+
|
|
368
|
+
// Second scroll - another immediate hover recheck
|
|
369
|
+
scrollBox.scrollTop = 4
|
|
370
|
+
await testRenderer.idle()
|
|
371
|
+
|
|
372
|
+
expect(hoveredId!).toBe("item-2")
|
|
373
|
+
// Each render triggers immediate hover recheck, so we see all transitions
|
|
374
|
+
expect(hoverEvents).toEqual(["over:item-0", "out:item-0", "over:item-1", "out:item-1", "over:item-2"])
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
test("mouse move during scroll triggers normal hover", async () => {
|
|
378
|
+
const scrollBox = new ScrollBoxRenderable(testRenderer, {
|
|
379
|
+
width: 20,
|
|
380
|
+
height: 6,
|
|
381
|
+
scrollY: true,
|
|
382
|
+
})
|
|
383
|
+
testRenderer.root.add(scrollBox)
|
|
384
|
+
|
|
385
|
+
const hoverEvents: string[] = []
|
|
386
|
+
let hoveredId: string | null = null
|
|
387
|
+
|
|
388
|
+
const items: BoxRenderable[] = []
|
|
389
|
+
for (let i = 0; i < 5; i++) {
|
|
390
|
+
const itemId = `item-${i}`
|
|
391
|
+
const item = new BoxRenderable(testRenderer, {
|
|
392
|
+
id: itemId,
|
|
393
|
+
width: "100%",
|
|
394
|
+
height: 2,
|
|
395
|
+
onMouseOver: () => {
|
|
396
|
+
hoveredId = itemId
|
|
397
|
+
hoverEvents.push(`over:${itemId}`)
|
|
398
|
+
},
|
|
399
|
+
onMouseOut: () => {
|
|
400
|
+
if (hoveredId === itemId) {
|
|
401
|
+
hoveredId = null
|
|
402
|
+
}
|
|
403
|
+
hoverEvents.push(`out:${itemId}`)
|
|
404
|
+
},
|
|
405
|
+
})
|
|
406
|
+
items.push(item)
|
|
407
|
+
scrollBox.add(item)
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
await testRenderer.idle()
|
|
411
|
+
|
|
412
|
+
const pointerX = items[0].x + 1
|
|
413
|
+
const pointerY = items[0].y + 1
|
|
414
|
+
|
|
415
|
+
await mockMouse.moveTo(pointerX, pointerY)
|
|
416
|
+
expect(hoveredId!).toBe("item-0")
|
|
417
|
+
expect(hoverEvents).toEqual(["over:item-0"])
|
|
418
|
+
|
|
419
|
+
// Scroll triggers render which triggers immediate hover recheck
|
|
420
|
+
scrollBox.scrollTop = 2
|
|
421
|
+
await testRenderer.idle()
|
|
422
|
+
expect(hoveredId!).toBe("item-1")
|
|
423
|
+
expect(hoverEvents).toEqual(["over:item-0", "out:item-0", "over:item-1"])
|
|
424
|
+
|
|
425
|
+
// Mouse move also works and doesn't duplicate events since we're already on item-1
|
|
426
|
+
await mockMouse.moveTo(pointerX, pointerY)
|
|
427
|
+
expect(hoveredId!).toBe("item-1")
|
|
428
|
+
expect(hoverEvents).toEqual(["over:item-0", "out:item-0", "over:item-1"])
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
test("hover updates immediately after render", async () => {
|
|
432
|
+
const scrollBox = new ScrollBoxRenderable(testRenderer, {
|
|
433
|
+
width: 20,
|
|
434
|
+
height: 6,
|
|
435
|
+
scrollY: true,
|
|
436
|
+
})
|
|
437
|
+
testRenderer.root.add(scrollBox)
|
|
438
|
+
|
|
439
|
+
let hoveredId: string | null = null
|
|
440
|
+
|
|
441
|
+
const items: BoxRenderable[] = []
|
|
442
|
+
for (let i = 0; i < 5; i++) {
|
|
443
|
+
const itemId = `item-${i}`
|
|
444
|
+
const item = new BoxRenderable(testRenderer, {
|
|
445
|
+
id: itemId,
|
|
446
|
+
width: "100%",
|
|
447
|
+
height: 2,
|
|
448
|
+
onMouseOver: () => {
|
|
449
|
+
hoveredId = itemId
|
|
450
|
+
},
|
|
451
|
+
onMouseOut: () => {
|
|
452
|
+
if (hoveredId === itemId) {
|
|
453
|
+
hoveredId = null
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
})
|
|
457
|
+
items.push(item)
|
|
458
|
+
scrollBox.add(item)
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
await testRenderer.idle()
|
|
462
|
+
|
|
463
|
+
const pointerX = items[0].x + 1
|
|
464
|
+
const pointerY = items[0].y + 1
|
|
465
|
+
|
|
466
|
+
await mockMouse.moveTo(pointerX, pointerY)
|
|
467
|
+
expect(hoveredId!).toBe("item-0")
|
|
468
|
+
|
|
469
|
+
// Hover updates immediately after render - no delay needed
|
|
470
|
+
scrollBox.scrollTop = 2
|
|
471
|
+
await testRenderer.idle()
|
|
472
|
+
expect(hoveredId!).toBe("item-1")
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
test("hit grid handles multiple scroll operations correctly", async () => {
|
|
476
|
+
const scrollBox = new ScrollBoxRenderable(testRenderer, {
|
|
477
|
+
width: 40,
|
|
478
|
+
height: 20,
|
|
479
|
+
scrollY: true,
|
|
480
|
+
})
|
|
481
|
+
testRenderer.root.add(scrollBox)
|
|
482
|
+
|
|
483
|
+
const items: BoxRenderable[] = []
|
|
484
|
+
for (let i = 0; i < 40; i++) {
|
|
485
|
+
const item = new BoxRenderable(testRenderer, {
|
|
486
|
+
id: `item-${i}`,
|
|
487
|
+
height: 2,
|
|
488
|
+
})
|
|
489
|
+
items.push(item)
|
|
490
|
+
scrollBox.add(item)
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
await testRenderer.idle()
|
|
494
|
+
|
|
495
|
+
const checkHitAt = (x: number, y: number): Renderable | undefined => {
|
|
496
|
+
const renderableId = testRenderer.hitTest(x, y)
|
|
497
|
+
return Renderable.renderablesByNumber.get(renderableId)
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
scrollBox.scrollTop = 20
|
|
501
|
+
expect(items[10].y).toBe(0)
|
|
502
|
+
await testRenderer.idle()
|
|
503
|
+
let hit = checkHitAt(5, items[10].y)
|
|
504
|
+
expect(hit?.id).toBe("item-10")
|
|
505
|
+
|
|
506
|
+
scrollBox.scrollTop = 40
|
|
507
|
+
expect(items[20].y).toBe(0)
|
|
508
|
+
await testRenderer.idle()
|
|
509
|
+
hit = checkHitAt(5, items[20].y)
|
|
510
|
+
expect(hit?.id).toBe("item-20")
|
|
511
|
+
|
|
512
|
+
scrollBox.scrollTop = 0
|
|
513
|
+
expect(items[0].y).toBe(0)
|
|
514
|
+
await testRenderer.idle()
|
|
515
|
+
hit = checkHitAt(5, items[0].y)
|
|
516
|
+
expect(hit?.id).toBe("item-0")
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
test("hit grid respects scrollbox viewport clipping when offset", async () => {
|
|
520
|
+
const container = new BoxRenderable(testRenderer, {
|
|
521
|
+
flexDirection: "column",
|
|
522
|
+
width: "100%",
|
|
523
|
+
height: "100%",
|
|
524
|
+
})
|
|
525
|
+
testRenderer.root.add(container)
|
|
526
|
+
|
|
527
|
+
const header = new BoxRenderable(testRenderer, {
|
|
528
|
+
id: "header",
|
|
529
|
+
height: 5,
|
|
530
|
+
width: "100%",
|
|
531
|
+
})
|
|
532
|
+
container.add(header)
|
|
533
|
+
|
|
534
|
+
const scrollBox = new ScrollBoxRenderable(testRenderer, {
|
|
535
|
+
width: 40,
|
|
536
|
+
height: 10,
|
|
537
|
+
scrollY: true,
|
|
538
|
+
})
|
|
539
|
+
container.add(scrollBox)
|
|
540
|
+
|
|
541
|
+
const items: BoxRenderable[] = []
|
|
542
|
+
for (let i = 0; i < 10; i++) {
|
|
543
|
+
const item = new BoxRenderable(testRenderer, {
|
|
544
|
+
id: `item-${i}`,
|
|
545
|
+
height: 2,
|
|
546
|
+
})
|
|
547
|
+
items.push(item)
|
|
548
|
+
scrollBox.add(item)
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
await testRenderer.idle()
|
|
552
|
+
|
|
553
|
+
const checkHitAt = (x: number, y: number): Renderable | undefined => {
|
|
554
|
+
const renderableId = testRenderer.hitTest(x, y)
|
|
555
|
+
return Renderable.renderablesByNumber.get(renderableId)
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const headerHit = checkHitAt(2, header.y + 1)
|
|
559
|
+
expect(headerHit?.id).toBe("header")
|
|
560
|
+
|
|
561
|
+
scrollBox.scrollTop = 4
|
|
562
|
+
await testRenderer.idle()
|
|
563
|
+
|
|
564
|
+
const headerHitAfterScroll = checkHitAt(2, header.y + 1)
|
|
565
|
+
expect(headerHitAfterScroll?.id).toBe("header")
|
|
566
|
+
|
|
567
|
+
const viewportHit = checkHitAt(2, scrollBox.viewport.y + 1)
|
|
568
|
+
expect(viewportHit?.id).toBe("item-2")
|
|
569
|
+
})
|
|
570
|
+
|
|
571
|
+
test("hover recheck skips while dragging captured renderable", async () => {
|
|
572
|
+
const scrollBox = new ScrollBoxRenderable(testRenderer, {
|
|
573
|
+
width: 20,
|
|
574
|
+
height: 6,
|
|
575
|
+
scrollY: true,
|
|
576
|
+
})
|
|
577
|
+
testRenderer.root.add(scrollBox)
|
|
578
|
+
|
|
579
|
+
const hoverEvents: string[] = []
|
|
580
|
+
|
|
581
|
+
const items: BoxRenderable[] = []
|
|
582
|
+
for (let i = 0; i < 5; i++) {
|
|
583
|
+
const itemId = `item-${i}`
|
|
584
|
+
const item = new BoxRenderable(testRenderer, {
|
|
585
|
+
id: itemId,
|
|
586
|
+
width: "100%",
|
|
587
|
+
height: 2,
|
|
588
|
+
onMouseOver: () => {
|
|
589
|
+
hoverEvents.push(`over:${itemId}`)
|
|
590
|
+
},
|
|
591
|
+
onMouseOut: () => {
|
|
592
|
+
hoverEvents.push(`out:${itemId}`)
|
|
593
|
+
},
|
|
594
|
+
})
|
|
595
|
+
items.push(item)
|
|
596
|
+
scrollBox.add(item)
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
await testRenderer.idle()
|
|
600
|
+
|
|
601
|
+
const pointerX = items[0].x + 1
|
|
602
|
+
const pointerY = items[0].y + 1
|
|
603
|
+
|
|
604
|
+
await mockMouse.moveTo(pointerX, pointerY)
|
|
605
|
+
await mockMouse.pressDown(pointerX, pointerY)
|
|
606
|
+
await mockMouse.moveTo(pointerX, pointerY)
|
|
607
|
+
|
|
608
|
+
scrollBox.scrollTop = 2
|
|
609
|
+
await testRenderer.idle()
|
|
610
|
+
|
|
611
|
+
// Hover recheck is skipped when there's a captured renderable (during drag)
|
|
612
|
+
expect(hoverEvents).toEqual(["over:item-0"])
|
|
613
|
+
})
|
|
614
|
+
|
|
615
|
+
test("captured renderable is not in hit grid during scroll", async () => {
|
|
616
|
+
const scrollBox = new ScrollBoxRenderable(testRenderer, {
|
|
617
|
+
width: 40,
|
|
618
|
+
height: 10,
|
|
619
|
+
scrollY: true,
|
|
620
|
+
})
|
|
621
|
+
testRenderer.root.add(scrollBox)
|
|
622
|
+
|
|
623
|
+
const items: BoxRenderable[] = []
|
|
624
|
+
for (let i = 0; i < 20; i++) {
|
|
625
|
+
const item = new BoxRenderable(testRenderer, {
|
|
626
|
+
id: `item-${i}`,
|
|
627
|
+
height: 2,
|
|
628
|
+
})
|
|
629
|
+
items.push(item)
|
|
630
|
+
scrollBox.add(item)
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
await testRenderer.idle()
|
|
634
|
+
|
|
635
|
+
const pointerX = 2
|
|
636
|
+
const pointerY = scrollBox.viewport.y + 1
|
|
637
|
+
|
|
638
|
+
await mockMouse.pressDown(pointerX, pointerY)
|
|
639
|
+
await mockMouse.moveTo(pointerX, pointerY + 1)
|
|
640
|
+
|
|
641
|
+
scrollBox.scrollTop = 4
|
|
642
|
+
await testRenderer.idle()
|
|
643
|
+
|
|
644
|
+
const renderableId = testRenderer.hitTest(pointerX, pointerY)
|
|
645
|
+
const hit = Renderable.renderablesByNumber.get(renderableId)
|
|
646
|
+
expect(hit?.id).toBe("item-2")
|
|
647
|
+
})
|
|
648
|
+
|
|
649
|
+
test("hit grid stays clipped after render", async () => {
|
|
650
|
+
const container = new BoxRenderable(testRenderer, {
|
|
651
|
+
id: "container",
|
|
652
|
+
width: 10,
|
|
653
|
+
height: 4,
|
|
654
|
+
overflow: "hidden",
|
|
655
|
+
})
|
|
656
|
+
testRenderer.root.add(container)
|
|
657
|
+
|
|
658
|
+
const child = new BoxRenderable(testRenderer, {
|
|
659
|
+
id: "child",
|
|
660
|
+
width: 20,
|
|
661
|
+
height: 4,
|
|
662
|
+
})
|
|
663
|
+
container.add(child)
|
|
664
|
+
|
|
665
|
+
await testRenderer.idle()
|
|
666
|
+
|
|
667
|
+
const insideHitId = testRenderer.hitTest(container.x + 1, container.y + 1)
|
|
668
|
+
const insideHit = Renderable.renderablesByNumber.get(insideHitId)
|
|
669
|
+
expect(insideHit?.id).toBe("child")
|
|
670
|
+
|
|
671
|
+
const outsideHitId = testRenderer.hitTest(container.x + container.width + 1, container.y + 1)
|
|
672
|
+
expect(outsideHitId).toBe(0)
|
|
673
|
+
})
|
|
674
|
+
|
|
675
|
+
test("buffered overflow scissor uses screen coordinates for hit grid", async () => {
|
|
676
|
+
const container = new BoxRenderable(testRenderer, {
|
|
677
|
+
id: "buffered-container",
|
|
678
|
+
width: 10,
|
|
679
|
+
height: 4,
|
|
680
|
+
overflow: "hidden",
|
|
681
|
+
buffered: true,
|
|
682
|
+
position: "absolute",
|
|
683
|
+
left: 10,
|
|
684
|
+
top: 5,
|
|
685
|
+
})
|
|
686
|
+
testRenderer.root.add(container)
|
|
687
|
+
|
|
688
|
+
const child = new BoxRenderable(testRenderer, {
|
|
689
|
+
id: "buffered-child",
|
|
690
|
+
width: 10,
|
|
691
|
+
height: 4,
|
|
692
|
+
})
|
|
693
|
+
container.add(child)
|
|
694
|
+
|
|
695
|
+
await testRenderer.idle()
|
|
696
|
+
|
|
697
|
+
const hitId = testRenderer.hitTest(container.x + 1, container.y + 1)
|
|
698
|
+
const hit = Renderable.renderablesByNumber.get(hitId)
|
|
699
|
+
expect(hit?.id).toBe("buffered-child")
|
|
700
|
+
})
|
|
701
|
+
|
|
702
|
+
test("hover updates after translate animation", async () => {
|
|
703
|
+
const hoverEvents: string[] = []
|
|
704
|
+
let hoveredId: string | null = null
|
|
705
|
+
|
|
706
|
+
const under = new BoxRenderable(testRenderer, {
|
|
707
|
+
id: "under",
|
|
708
|
+
position: "absolute",
|
|
709
|
+
left: 2,
|
|
710
|
+
top: 2,
|
|
711
|
+
width: 6,
|
|
712
|
+
height: 2,
|
|
713
|
+
zIndex: 0,
|
|
714
|
+
onMouseOver: () => {
|
|
715
|
+
hoveredId = "under"
|
|
716
|
+
hoverEvents.push("over:under")
|
|
717
|
+
},
|
|
718
|
+
onMouseOut: () => {
|
|
719
|
+
if (hoveredId === "under") {
|
|
720
|
+
hoveredId = null
|
|
721
|
+
}
|
|
722
|
+
hoverEvents.push("out:under")
|
|
723
|
+
},
|
|
724
|
+
})
|
|
725
|
+
testRenderer.root.add(under)
|
|
726
|
+
|
|
727
|
+
const moving = new MovingBoxRenderable(testRenderer, {
|
|
728
|
+
id: "moving",
|
|
729
|
+
position: "absolute",
|
|
730
|
+
left: 2,
|
|
731
|
+
top: 2,
|
|
732
|
+
width: 6,
|
|
733
|
+
height: 2,
|
|
734
|
+
zIndex: 1,
|
|
735
|
+
onMouseOver: () => {
|
|
736
|
+
hoveredId = "moving"
|
|
737
|
+
hoverEvents.push("over:moving")
|
|
738
|
+
},
|
|
739
|
+
onMouseOut: () => {
|
|
740
|
+
if (hoveredId === "moving") {
|
|
741
|
+
hoveredId = null
|
|
742
|
+
}
|
|
743
|
+
hoverEvents.push("out:moving")
|
|
744
|
+
},
|
|
745
|
+
})
|
|
746
|
+
testRenderer.root.add(moving)
|
|
747
|
+
|
|
748
|
+
await testRenderer.idle()
|
|
749
|
+
|
|
750
|
+
const pointerX = moving.x + 1
|
|
751
|
+
const pointerY = moving.y + 1
|
|
752
|
+
|
|
753
|
+
await mockMouse.moveTo(pointerX, pointerY)
|
|
754
|
+
expect(hoveredId!).toBe("moving")
|
|
755
|
+
expect(hoverEvents).toEqual(["over:moving"])
|
|
756
|
+
|
|
757
|
+
moving.shouldMove = true
|
|
758
|
+
moving.requestRender()
|
|
759
|
+
await testRenderer.idle()
|
|
760
|
+
|
|
761
|
+
expect(hoveredId!).toBe("under")
|
|
762
|
+
expect(hoverEvents).toEqual(["over:moving", "out:moving", "over:under"])
|
|
763
|
+
})
|
|
764
|
+
|
|
765
|
+
test("hover updates after z-index change", async () => {
|
|
766
|
+
const hoverEvents: string[] = []
|
|
767
|
+
let hoveredId: string | null = null
|
|
768
|
+
|
|
769
|
+
const back = new BoxRenderable(testRenderer, {
|
|
770
|
+
id: "back",
|
|
771
|
+
position: "absolute",
|
|
772
|
+
left: 2,
|
|
773
|
+
top: 2,
|
|
774
|
+
width: 6,
|
|
775
|
+
height: 2,
|
|
776
|
+
zIndex: 0,
|
|
777
|
+
onMouseOver: () => {
|
|
778
|
+
hoveredId = "back"
|
|
779
|
+
hoverEvents.push("over:back")
|
|
780
|
+
},
|
|
781
|
+
onMouseOut: () => {
|
|
782
|
+
if (hoveredId === "back") {
|
|
783
|
+
hoveredId = null
|
|
784
|
+
}
|
|
785
|
+
hoverEvents.push("out:back")
|
|
786
|
+
},
|
|
787
|
+
})
|
|
788
|
+
testRenderer.root.add(back)
|
|
789
|
+
|
|
790
|
+
const front = new BoxRenderable(testRenderer, {
|
|
791
|
+
id: "front",
|
|
792
|
+
position: "absolute",
|
|
793
|
+
left: 2,
|
|
794
|
+
top: 2,
|
|
795
|
+
width: 6,
|
|
796
|
+
height: 2,
|
|
797
|
+
zIndex: 1,
|
|
798
|
+
onMouseOver: () => {
|
|
799
|
+
hoveredId = "front"
|
|
800
|
+
hoverEvents.push("over:front")
|
|
801
|
+
},
|
|
802
|
+
onMouseOut: () => {
|
|
803
|
+
if (hoveredId === "front") {
|
|
804
|
+
hoveredId = null
|
|
805
|
+
}
|
|
806
|
+
hoverEvents.push("out:front")
|
|
807
|
+
},
|
|
808
|
+
})
|
|
809
|
+
testRenderer.root.add(front)
|
|
810
|
+
|
|
811
|
+
await testRenderer.idle()
|
|
812
|
+
|
|
813
|
+
const pointerX = front.x + 1
|
|
814
|
+
const pointerY = front.y + 1
|
|
815
|
+
|
|
816
|
+
await mockMouse.moveTo(pointerX, pointerY)
|
|
817
|
+
expect(hoveredId!).toBe("front")
|
|
818
|
+
expect(hoverEvents).toEqual(["over:front"])
|
|
819
|
+
|
|
820
|
+
back.zIndex = 2
|
|
821
|
+
await testRenderer.idle()
|
|
822
|
+
|
|
823
|
+
expect(hoveredId!).toBe("back")
|
|
824
|
+
expect(hoverEvents).toEqual(["over:front", "out:front", "over:back"])
|
|
825
|
+
})
|
|
826
|
+
|
|
827
|
+
test("scrolling does not steal clicks outside the list", async () => {
|
|
828
|
+
let lastClick = "none"
|
|
829
|
+
|
|
830
|
+
const overlay = new BoxRenderable(testRenderer, {
|
|
831
|
+
id: "overlay",
|
|
832
|
+
position: "absolute",
|
|
833
|
+
left: 0,
|
|
834
|
+
top: 0,
|
|
835
|
+
width: "100%",
|
|
836
|
+
height: "100%",
|
|
837
|
+
zIndex: 100,
|
|
838
|
+
onMouseDown: () => {
|
|
839
|
+
lastClick = "overlay"
|
|
840
|
+
},
|
|
841
|
+
})
|
|
842
|
+
testRenderer.root.add(overlay)
|
|
843
|
+
|
|
844
|
+
const dialog = new BoxRenderable(testRenderer, {
|
|
845
|
+
id: "dialog",
|
|
846
|
+
position: "absolute",
|
|
847
|
+
left: 5,
|
|
848
|
+
top: 4,
|
|
849
|
+
width: 30,
|
|
850
|
+
height: 14,
|
|
851
|
+
flexDirection: "column",
|
|
852
|
+
padding: 1,
|
|
853
|
+
gap: 1,
|
|
854
|
+
onMouseDown: (event) => {
|
|
855
|
+
lastClick = "dialog"
|
|
856
|
+
event.stopPropagation()
|
|
857
|
+
},
|
|
858
|
+
})
|
|
859
|
+
overlay.add(dialog)
|
|
860
|
+
|
|
861
|
+
const header = new BoxRenderable(testRenderer, {
|
|
862
|
+
id: "dialog-header",
|
|
863
|
+
width: "100%",
|
|
864
|
+
height: 2,
|
|
865
|
+
onMouseDown: (event) => {
|
|
866
|
+
lastClick = "header"
|
|
867
|
+
event.stopPropagation()
|
|
868
|
+
},
|
|
869
|
+
})
|
|
870
|
+
dialog.add(header)
|
|
871
|
+
|
|
872
|
+
const scrollBox = new ScrollBoxRenderable(testRenderer, {
|
|
873
|
+
id: "dialog-scrollbox",
|
|
874
|
+
width: "100%",
|
|
875
|
+
height: 7,
|
|
876
|
+
scrollY: true,
|
|
877
|
+
onMouseDown: (event) => {
|
|
878
|
+
lastClick = "scrollbox"
|
|
879
|
+
event.stopPropagation()
|
|
880
|
+
},
|
|
881
|
+
})
|
|
882
|
+
dialog.add(scrollBox)
|
|
883
|
+
|
|
884
|
+
for (let i = 0; i < 20; i++) {
|
|
885
|
+
const item = new BoxRenderable(testRenderer, {
|
|
886
|
+
id: `line-${i}`,
|
|
887
|
+
width: "100%",
|
|
888
|
+
height: 1,
|
|
889
|
+
})
|
|
890
|
+
scrollBox.add(item)
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
await testRenderer.idle()
|
|
894
|
+
|
|
895
|
+
await mockMouse.click(scrollBox.viewport.x + 1, scrollBox.viewport.y + 1)
|
|
896
|
+
expect(lastClick).toBe("scrollbox")
|
|
897
|
+
|
|
898
|
+
const headerClickY = header.y + 1
|
|
899
|
+
const targetScrollTop = Math.max(1, scrollBox.viewport.y - headerClickY)
|
|
900
|
+
scrollBox.scrollTop = targetScrollTop
|
|
901
|
+
|
|
902
|
+
await mockMouse.click(header.x + 1, headerClickY)
|
|
903
|
+
expect(lastClick).toBe("header")
|
|
904
|
+
|
|
905
|
+
await mockMouse.click(dialog.x + 1, dialog.y - 1)
|
|
906
|
+
expect(lastClick).toBe("overlay")
|
|
907
|
+
|
|
908
|
+
await testRenderer.idle()
|
|
909
|
+
})
|