@effect-tui/react 0.1.1 → 0.1.4
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/dist/jsx-runtime.d.ts +13 -0
- package/dist/jsx-runtime.d.ts.map +1 -1
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/src/codeblock.d.ts.map +1 -1
- package/dist/src/codeblock.js.map +1 -1
- package/dist/src/components/Divider.d.ts +18 -0
- package/dist/src/components/Divider.d.ts.map +1 -0
- package/dist/src/components/Divider.js +17 -0
- package/dist/src/components/Divider.js.map +1 -0
- package/dist/src/components/Markdown.d.ts +66 -0
- package/dist/src/components/Markdown.d.ts.map +1 -0
- package/dist/src/components/Markdown.js +226 -0
- package/dist/src/components/Markdown.js.map +1 -0
- package/dist/src/components/MultilineTextInput.d.ts +65 -0
- package/dist/src/components/MultilineTextInput.d.ts.map +1 -0
- package/dist/src/components/MultilineTextInput.js +607 -0
- package/dist/src/components/MultilineTextInput.js.map +1 -0
- package/dist/src/components/Overlay.d.ts +46 -0
- package/dist/src/components/Overlay.d.ts.map +1 -0
- package/dist/src/components/Overlay.js +11 -0
- package/dist/src/components/Overlay.js.map +1 -0
- package/dist/src/components/Static.d.ts +44 -0
- package/dist/src/components/Static.d.ts.map +1 -0
- package/dist/src/components/Static.js +53 -0
- package/dist/src/components/Static.js.map +1 -0
- package/dist/src/components/TextInput.d.ts +53 -0
- package/dist/src/components/TextInput.d.ts.map +1 -0
- package/dist/src/components/TextInput.js +210 -0
- package/dist/src/components/TextInput.js.map +1 -0
- package/dist/src/components/index.d.ts +7 -0
- package/dist/src/components/index.d.ts.map +1 -0
- package/dist/src/components/index.js +7 -0
- package/dist/src/components/index.js.map +1 -0
- package/dist/src/components/text-editing.d.ts +62 -0
- package/dist/src/components/text-editing.d.ts.map +1 -0
- package/dist/src/components/text-editing.js +385 -0
- package/dist/src/components/text-editing.js.map +1 -0
- package/dist/src/console/ConsoleCapture.d.ts +36 -0
- package/dist/src/console/ConsoleCapture.d.ts.map +1 -0
- package/dist/src/console/ConsoleCapture.js +210 -0
- package/dist/src/console/ConsoleCapture.js.map +1 -0
- package/dist/src/console/ConsolePopover.d.ts +18 -0
- package/dist/src/console/ConsolePopover.d.ts.map +1 -0
- package/dist/src/console/ConsolePopover.js +324 -0
- package/dist/src/console/ConsolePopover.js.map +1 -0
- package/dist/src/console/clipboard.d.ts +10 -0
- package/dist/src/console/clipboard.d.ts.map +1 -0
- package/dist/src/console/clipboard.js +74 -0
- package/dist/src/console/clipboard.js.map +1 -0
- package/dist/src/console/index.d.ts +5 -0
- package/dist/src/console/index.d.ts.map +1 -0
- package/dist/src/console/index.js +33 -0
- package/dist/src/console/index.js.map +1 -0
- package/dist/src/console/useConsole.d.ts +44 -0
- package/dist/src/console/useConsole.d.ts.map +1 -0
- package/dist/src/console/useConsole.js +91 -0
- package/dist/src/console/useConsole.js.map +1 -0
- package/dist/src/debug/DebugOverlay.d.ts +49 -0
- package/dist/src/debug/DebugOverlay.d.ts.map +1 -0
- package/dist/src/debug/DebugOverlay.js +438 -0
- package/dist/src/debug/DebugOverlay.js.map +1 -0
- package/dist/src/debug/DiagnosticsPanel.d.ts.map +1 -1
- package/dist/src/debug/DiagnosticsPanel.js.map +1 -1
- package/dist/src/dev/Toast.d.ts +19 -0
- package/dist/src/dev/Toast.d.ts.map +1 -0
- package/dist/src/dev/Toast.js +72 -0
- package/dist/src/dev/Toast.js.map +1 -0
- package/dist/src/dev/index.d.ts +2 -0
- package/dist/src/dev/index.d.ts.map +1 -0
- package/dist/src/dev/index.js +3 -0
- package/dist/src/dev/index.js.map +1 -0
- package/dist/src/dev.d.ts +114 -0
- package/dist/src/dev.d.ts.map +1 -0
- package/dist/src/dev.js +373 -0
- package/dist/src/dev.js.map +1 -0
- package/dist/src/highlight.d.ts +3 -3
- package/dist/src/highlight.d.ts.map +1 -1
- package/dist/src/highlight.js.map +1 -1
- package/dist/src/hmr-plugin.d.ts +2 -0
- package/dist/src/hmr-plugin.d.ts.map +1 -0
- package/dist/src/hmr-plugin.js +53 -0
- package/dist/src/hmr-plugin.js.map +1 -0
- package/dist/src/hooks/index.d.ts +4 -0
- package/dist/src/hooks/index.d.ts.map +1 -1
- package/dist/src/hooks/index.js +2 -0
- package/dist/src/hooks/index.js.map +1 -1
- package/dist/src/hooks/use-keyboard.d.ts +11 -0
- package/dist/src/hooks/use-keyboard.d.ts.map +1 -1
- package/dist/src/hooks/use-keyboard.js +22 -4
- package/dist/src/hooks/use-keyboard.js.map +1 -1
- package/dist/src/hooks/use-mouse.d.ts +24 -0
- package/dist/src/hooks/use-mouse.d.ts.map +1 -0
- package/dist/src/hooks/use-mouse.js +41 -0
- package/dist/src/hooks/use-mouse.js.map +1 -0
- package/dist/src/hooks/use-paste.d.ts +11 -0
- package/dist/src/hooks/use-paste.d.ts.map +1 -1
- package/dist/src/hooks/use-paste.js +17 -3
- package/dist/src/hooks/use-paste.js.map +1 -1
- package/dist/src/hooks/use-scroll.d.ts +79 -0
- package/dist/src/hooks/use-scroll.d.ts.map +1 -0
- package/dist/src/hooks/use-scroll.js +239 -0
- package/dist/src/hooks/use-scroll.js.map +1 -0
- package/dist/src/hooks/useFrameStats.js.map +1 -1
- package/dist/src/hosts/base.d.ts +62 -1
- package/dist/src/hosts/base.d.ts.map +1 -1
- package/dist/src/hosts/base.js +118 -5
- package/dist/src/hosts/base.js.map +1 -1
- package/dist/src/hosts/box.d.ts +7 -7
- package/dist/src/hosts/box.d.ts.map +1 -1
- package/dist/src/hosts/box.js +31 -26
- package/dist/src/hosts/box.js.map +1 -1
- package/dist/src/hosts/canvas.d.ts +8 -8
- package/dist/src/hosts/canvas.d.ts.map +1 -1
- package/dist/src/hosts/canvas.js +13 -22
- package/dist/src/hosts/canvas.js.map +1 -1
- package/dist/src/hosts/codeblock.d.ts +7 -7
- package/dist/src/hosts/codeblock.d.ts.map +1 -1
- package/dist/src/hosts/codeblock.js +11 -20
- package/dist/src/hosts/codeblock.js.map +1 -1
- package/dist/src/hosts/flex-container.d.ts +45 -0
- package/dist/src/hosts/flex-container.d.ts.map +1 -0
- package/dist/src/hosts/flex-container.js +90 -0
- package/dist/src/hosts/flex-container.js.map +1 -0
- package/dist/src/hosts/hstack.d.ts +6 -11
- package/dist/src/hosts/hstack.d.ts.map +1 -1
- package/dist/src/hosts/hstack.js +6 -41
- package/dist/src/hosts/hstack.js.map +1 -1
- package/dist/src/hosts/index.d.ts +4 -0
- package/dist/src/hosts/index.d.ts.map +1 -1
- package/dist/src/hosts/index.js +10 -0
- package/dist/src/hosts/index.js.map +1 -1
- package/dist/src/hosts/overlay-item.d.ts +32 -0
- package/dist/src/hosts/overlay-item.d.ts.map +1 -0
- package/dist/src/hosts/overlay-item.js +54 -0
- package/dist/src/hosts/overlay-item.js.map +1 -0
- package/dist/src/hosts/overlay.d.ts +30 -0
- package/dist/src/hosts/overlay.d.ts.map +1 -0
- package/dist/src/hosts/overlay.js +105 -0
- package/dist/src/hosts/overlay.js.map +1 -0
- package/dist/src/hosts/scroll.d.ts +56 -0
- package/dist/src/hosts/scroll.d.ts.map +1 -0
- package/dist/src/hosts/scroll.js +204 -0
- package/dist/src/hosts/scroll.js.map +1 -0
- package/dist/src/hosts/single-child.d.ts +16 -0
- package/dist/src/hosts/single-child.d.ts.map +1 -0
- package/dist/src/hosts/single-child.js +45 -0
- package/dist/src/hosts/single-child.js.map +1 -0
- package/dist/src/hosts/spacer.d.ts.map +1 -1
- package/dist/src/hosts/spacer.js +7 -3
- package/dist/src/hosts/spacer.js.map +1 -1
- package/dist/src/hosts/text.d.ts +9 -6
- package/dist/src/hosts/text.d.ts.map +1 -1
- package/dist/src/hosts/text.js +49 -22
- package/dist/src/hosts/text.js.map +1 -1
- package/dist/src/hosts/vstack.d.ts +6 -11
- package/dist/src/hosts/vstack.d.ts.map +1 -1
- package/dist/src/hosts/vstack.js +6 -41
- package/dist/src/hosts/vstack.js.map +1 -1
- package/dist/src/hosts/zstack.d.ts.map +1 -1
- package/dist/src/hosts/zstack.js +16 -5
- package/dist/src/hosts/zstack.js.map +1 -1
- package/dist/src/index.d.ts +9 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +10 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/inline/index.d.ts.map +1 -1
- package/dist/src/inline/index.js.map +1 -1
- package/dist/src/motion/color-motion-value.d.ts.map +1 -1
- package/dist/src/motion/color-motion-value.js.map +1 -1
- package/dist/src/motion/color.d.ts +1 -29
- package/dist/src/motion/color.d.ts.map +1 -1
- package/dist/src/motion/color.js +2 -170
- package/dist/src/motion/color.js.map +1 -1
- package/dist/src/motion/color.test.js.map +1 -1
- package/dist/src/motion/event-emitter.d.ts.map +1 -1
- package/dist/src/motion/event-emitter.js.map +1 -1
- package/dist/src/motion/frame.js.map +1 -1
- package/dist/src/motion/hooks.d.ts.map +1 -1
- package/dist/src/motion/hooks.js +8 -3
- package/dist/src/motion/hooks.js.map +1 -1
- package/dist/src/motion/index.d.ts.map +1 -1
- package/dist/src/motion/index.js.map +1 -1
- package/dist/src/motion/motion-value.d.ts.map +1 -1
- package/dist/src/motion/motion-value.js.map +1 -1
- package/dist/src/motion/motion-value.test.js.map +1 -1
- package/dist/src/motion/spring-math.d.ts +6 -1
- package/dist/src/motion/spring-math.d.ts.map +1 -1
- package/dist/src/motion/spring-math.js +6 -1
- package/dist/src/motion/spring-math.js.map +1 -1
- package/dist/src/motion/types.d.ts.map +1 -1
- package/dist/src/motion/types.js.map +1 -1
- package/dist/src/profiler.js.map +1 -1
- package/dist/src/reconciler/host-config.d.ts +5 -5
- package/dist/src/reconciler/host-config.d.ts.map +1 -1
- package/dist/src/reconciler/host-config.js +43 -51
- package/dist/src/reconciler/host-config.js.map +1 -1
- package/dist/src/reconciler/noop-methods.d.ts +29 -0
- package/dist/src/reconciler/noop-methods.d.ts.map +1 -0
- package/dist/src/reconciler/noop-methods.js +43 -0
- package/dist/src/reconciler/noop-methods.js.map +1 -0
- package/dist/src/reconciler/types.d.ts +68 -14
- package/dist/src/reconciler/types.d.ts.map +1 -1
- package/dist/src/remote/Procedures.d.ts +22 -0
- package/dist/src/remote/Procedures.d.ts.map +1 -0
- package/dist/src/remote/Procedures.js +42 -0
- package/dist/src/remote/Procedures.js.map +1 -0
- package/dist/src/remote/Router.d.ts +20 -0
- package/dist/src/remote/Router.d.ts.map +1 -0
- package/dist/src/remote/Router.js +26 -0
- package/dist/src/remote/Router.js.map +1 -0
- package/dist/src/remote/Server.d.ts +6 -0
- package/dist/src/remote/Server.d.ts.map +1 -0
- package/dist/src/remote/Server.js +53 -0
- package/dist/src/remote/Server.js.map +1 -0
- package/dist/src/remote/index.d.ts +18 -0
- package/dist/src/remote/index.d.ts.map +1 -0
- package/dist/src/remote/index.js +74 -0
- package/dist/src/remote/index.js.map +1 -0
- package/dist/src/renderer/core/FrameBuilder.d.ts +18 -0
- package/dist/src/renderer/core/FrameBuilder.d.ts.map +1 -0
- package/dist/src/renderer/core/FrameBuilder.js +38 -0
- package/dist/src/renderer/core/FrameBuilder.js.map +1 -0
- package/dist/src/renderer/core/RendererState.d.ts +41 -0
- package/dist/src/renderer/core/RendererState.d.ts.map +1 -0
- package/dist/src/renderer/core/RendererState.js +70 -0
- package/dist/src/renderer/core/RendererState.js.map +1 -0
- package/dist/src/renderer/core/index.d.ts +3 -0
- package/dist/src/renderer/core/index.d.ts.map +1 -0
- package/dist/src/renderer/core/index.js +3 -0
- package/dist/src/renderer/core/index.js.map +1 -0
- package/dist/src/renderer/input/InputProcessor.d.ts +25 -0
- package/dist/src/renderer/input/InputProcessor.d.ts.map +1 -0
- package/dist/src/renderer/input/InputProcessor.js +81 -0
- package/dist/src/renderer/input/InputProcessor.js.map +1 -0
- package/dist/src/renderer/input/index.d.ts +2 -0
- package/dist/src/renderer/input/index.d.ts.map +1 -0
- package/dist/src/renderer/input/index.js +2 -0
- package/dist/src/renderer/input/index.js.map +1 -0
- package/dist/src/renderer/lifecycle/EventBus.d.ts +41 -0
- package/dist/src/renderer/lifecycle/EventBus.d.ts.map +1 -0
- package/dist/src/renderer/lifecycle/EventBus.js +78 -0
- package/dist/src/renderer/lifecycle/EventBus.js.map +1 -0
- package/dist/src/renderer/lifecycle/ResizeManager.d.ts +34 -0
- package/dist/src/renderer/lifecycle/ResizeManager.d.ts.map +1 -0
- package/dist/src/renderer/lifecycle/ResizeManager.js +47 -0
- package/dist/src/renderer/lifecycle/ResizeManager.js.map +1 -0
- package/dist/src/renderer/lifecycle/TerminalSetup.d.ts +36 -0
- package/dist/src/renderer/lifecycle/TerminalSetup.d.ts.map +1 -0
- package/dist/src/renderer/lifecycle/TerminalSetup.js +82 -0
- package/dist/src/renderer/lifecycle/TerminalSetup.js.map +1 -0
- package/dist/src/renderer/lifecycle/index.d.ts +4 -0
- package/dist/src/renderer/lifecycle/index.d.ts.map +1 -0
- package/dist/src/renderer/lifecycle/index.js +4 -0
- package/dist/src/renderer/lifecycle/index.js.map +1 -0
- package/dist/src/renderer/modes/FullscreenRenderer.d.ts +12 -0
- package/dist/src/renderer/modes/FullscreenRenderer.d.ts.map +1 -0
- package/dist/src/renderer/modes/FullscreenRenderer.js +52 -0
- package/dist/src/renderer/modes/FullscreenRenderer.js.map +1 -0
- package/dist/src/renderer/modes/InlineRenderer.d.ts +22 -0
- package/dist/src/renderer/modes/InlineRenderer.d.ts.map +1 -0
- package/dist/src/renderer/modes/InlineRenderer.js +154 -0
- package/dist/src/renderer/modes/InlineRenderer.js.map +1 -0
- package/dist/src/renderer/modes/RendererMode.d.ts +42 -0
- package/dist/src/renderer/modes/RendererMode.d.ts.map +1 -0
- package/dist/src/renderer/modes/RendererMode.js +2 -0
- package/dist/src/renderer/modes/RendererMode.js.map +1 -0
- package/dist/src/renderer/modes/StaticContentRenderer.d.ts +25 -0
- package/dist/src/renderer/modes/StaticContentRenderer.d.ts.map +1 -0
- package/dist/src/renderer/modes/StaticContentRenderer.js +47 -0
- package/dist/src/renderer/modes/StaticContentRenderer.js.map +1 -0
- package/dist/src/renderer/modes/index.d.ts +5 -0
- package/dist/src/renderer/modes/index.d.ts.map +1 -0
- package/dist/src/renderer/modes/index.js +4 -0
- package/dist/src/renderer/modes/index.js.map +1 -0
- package/dist/src/renderer-context.d.ts +9 -0
- package/dist/src/renderer-context.d.ts.map +1 -0
- package/dist/src/renderer-context.js +22 -0
- package/dist/src/renderer-context.js.map +1 -0
- package/dist/src/renderer-types.d.ts +103 -0
- package/dist/src/renderer-types.d.ts.map +1 -0
- package/dist/src/renderer-types.js +2 -0
- package/dist/src/renderer-types.js.map +1 -0
- package/dist/src/renderer.d.ts +4 -86
- package/dist/src/renderer.d.ts.map +1 -1
- package/dist/src/renderer.js +213 -384
- package/dist/src/renderer.js.map +1 -1
- package/dist/src/test/index.d.ts.map +1 -1
- package/dist/src/test/index.js.map +1 -1
- package/dist/src/test/mock-streams.d.ts.map +1 -1
- package/dist/src/test/mock-streams.js.map +1 -1
- package/dist/src/test/render-tui.d.ts.map +1 -1
- package/dist/src/test/render-tui.js +2 -5
- package/dist/src/test/render-tui.js.map +1 -1
- package/dist/src/trace/SpanTree.d.ts.map +1 -1
- package/dist/src/trace/SpanTree.js +21 -11
- package/dist/src/trace/SpanTree.js.map +1 -1
- package/dist/src/trace/format-value.d.ts +15 -0
- package/dist/src/trace/format-value.d.ts.map +1 -0
- package/dist/src/trace/format-value.js +77 -0
- package/dist/src/trace/format-value.js.map +1 -0
- package/dist/src/trace/index.d.ts.map +1 -1
- package/dist/src/trace/index.js.map +1 -1
- package/dist/src/trace/location.js +1 -1
- package/dist/src/trace/location.js.map +1 -1
- package/dist/src/trace/span-processor.d.ts.map +1 -1
- package/dist/src/trace/span-processor.js.map +1 -1
- package/dist/src/trace/span-state.d.ts +19 -2
- package/dist/src/trace/span-state.d.ts.map +1 -1
- package/dist/src/trace/span-state.js +62 -31
- package/dist/src/trace/span-state.js.map +1 -1
- package/dist/src/trace/tui-logger.js.map +1 -1
- package/dist/src/utils/border.d.ts +1 -1
- package/dist/src/utils/border.d.ts.map +1 -1
- package/dist/src/utils/border.js +6 -0
- package/dist/src/utils/border.js.map +1 -1
- package/dist/src/utils/flex-layout.d.ts +2 -1
- package/dist/src/utils/flex-layout.d.ts.map +1 -1
- package/dist/src/utils/flex-layout.js +22 -33
- package/dist/src/utils/flex-layout.js.map +1 -1
- package/dist/src/utils/index.d.ts +1 -1
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +1 -1
- package/dist/src/utils/index.js.map +1 -1
- package/dist/src/utils/padding.d.ts.map +1 -1
- package/dist/src/utils/padding.js.map +1 -1
- package/dist/src/utils/styles.d.ts +20 -1
- package/dist/src/utils/styles.d.ts.map +1 -1
- package/dist/src/utils/styles.js +36 -1
- package/dist/src/utils/styles.js.map +1 -1
- package/dist/src/visualize/index.d.ts +8 -19
- package/dist/src/visualize/index.d.ts.map +1 -1
- package/dist/src/visualize/index.js +11 -25
- package/dist/src/visualize/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/jsx-dev-runtime.ts +5 -0
- package/jsx-runtime.ts +54 -0
- package/package.json +124 -92
- package/src/codeblock.tsx +34 -34
- package/src/components/Divider.tsx +23 -0
- package/src/components/Markdown.tsx +380 -0
- package/src/components/MultilineTextInput.tsx +749 -0
- package/src/components/Overlay.tsx +56 -0
- package/src/components/Static.tsx +68 -0
- package/src/components/TextInput.tsx +285 -0
- package/src/components/index.ts +6 -0
- package/src/components/text-editing.ts +464 -0
- package/src/console/ConsoleCapture.ts +272 -0
- package/src/console/ConsolePopover.tsx +487 -0
- package/src/console/clipboard.ts +81 -0
- package/src/console/index.ts +42 -0
- package/src/console/useConsole.ts +129 -0
- package/src/debug/DebugOverlay.ts +557 -0
- package/src/debug/DiagnosticsPanel.tsx +27 -27
- package/src/dev/Toast.tsx +117 -0
- package/src/dev/index.ts +2 -0
- package/src/dev.tsx +489 -0
- package/src/highlight.ts +46 -46
- package/src/hmr-plugin.ts +61 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/use-keyboard.ts +44 -24
- package/src/hooks/use-mouse.ts +51 -0
- package/src/hooks/use-paste.ts +21 -6
- package/src/hooks/use-scroll.ts +386 -0
- package/src/hooks/useFrameStats.ts +17 -17
- package/src/hosts/base.ts +180 -59
- package/src/hosts/box.ts +117 -96
- package/src/hosts/canvas.ts +137 -141
- package/src/hosts/codeblock.ts +117 -133
- package/src/hosts/flex-container.ts +124 -0
- package/src/hosts/hstack.ts +11 -59
- package/src/hosts/index.ts +24 -14
- package/src/hosts/overlay-item.ts +72 -0
- package/src/hosts/overlay.ts +125 -0
- package/src/hosts/scroll.ts +255 -0
- package/src/hosts/single-child.ts +52 -0
- package/src/hosts/spacer.ts +30 -26
- package/src/hosts/text.ts +198 -164
- package/src/hosts/vstack.ts +11 -59
- package/src/hosts/zstack.ts +79 -67
- package/src/index.ts +44 -19
- package/src/inline/index.tsx +123 -123
- package/src/motion/color-motion-value.ts +67 -67
- package/src/motion/color.test.ts +107 -107
- package/src/motion/color.ts +9 -190
- package/src/motion/event-emitter.ts +20 -20
- package/src/motion/frame.ts +35 -35
- package/src/motion/hooks.ts +144 -139
- package/src/motion/index.ts +10 -10
- package/src/motion/motion-value.test.ts +207 -207
- package/src/motion/motion-value.ts +112 -112
- package/src/motion/spring-math.ts +88 -83
- package/src/motion/types.ts +25 -25
- package/src/profiler.ts +50 -50
- package/src/reconciler/host-config.ts +152 -174
- package/src/reconciler/noop-methods.ts +55 -0
- package/src/reconciler/types.ts +112 -46
- package/src/remote/Procedures.ts +52 -0
- package/src/remote/Router.ts +58 -0
- package/src/remote/Server.ts +76 -0
- package/src/remote/index.ts +90 -0
- package/src/renderer/core/FrameBuilder.ts +49 -0
- package/src/renderer/core/RendererState.ts +80 -0
- package/src/renderer/core/index.ts +2 -0
- package/src/renderer/input/InputProcessor.ts +94 -0
- package/src/renderer/input/index.ts +1 -0
- package/src/renderer/lifecycle/EventBus.ts +90 -0
- package/src/renderer/lifecycle/ResizeManager.ts +65 -0
- package/src/renderer/lifecycle/TerminalSetup.ts +105 -0
- package/src/renderer/lifecycle/index.ts +3 -0
- package/src/renderer/modes/FullscreenRenderer.ts +53 -0
- package/src/renderer/modes/InlineRenderer.ts +178 -0
- package/src/renderer/modes/RendererMode.ts +46 -0
- package/src/renderer/modes/StaticContentRenderer.ts +56 -0
- package/src/renderer/modes/index.ts +4 -0
- package/src/renderer-context.ts +27 -0
- package/src/renderer-types.ts +109 -0
- package/src/renderer.ts +391 -642
- package/src/test/index.ts +5 -5
- package/src/test/mock-streams.ts +115 -115
- package/src/test/render-tui.ts +84 -87
- package/src/utils/border.ts +79 -73
- package/src/utils/flex-layout.ts +80 -93
- package/src/utils/index.ts +1 -1
- package/src/utils/padding.ts +27 -27
- package/src/utils/styles.ts +50 -7
- package/src/visualize/index.tsx +225 -240
- package/dist/src/output.d.ts +0 -47
- package/dist/src/output.d.ts.map +0 -1
- package/dist/src/output.js +0 -125
- package/dist/src/output.js.map +0 -1
- package/dist/src/terminal.d.ts +0 -37
- package/dist/src/terminal.d.ts.map +0 -1
- package/dist/src/terminal.js +0 -65
- package/dist/src/terminal.js.map +0 -1
- package/src/output.ts +0 -156
- package/src/terminal.ts +0 -67
- package/src/trace/SpanTree.tsx +0 -195
- package/src/trace/index.tsx +0 -205
- package/src/trace/location.ts +0 -90
- package/src/trace/span-processor.ts +0 -65
- package/src/trace/span-state.ts +0 -286
- package/src/trace/tui-logger.ts +0 -72
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { ANSI, Terminal } from "@effect-tui/core"
|
|
2
|
+
import type { TuiWriteStream, TuiReadStream } from "../../renderer-types.js"
|
|
3
|
+
|
|
4
|
+
export interface TerminalSetupConfig {
|
|
5
|
+
mode: "fullscreen" | "inline"
|
|
6
|
+
enablePaste: boolean
|
|
7
|
+
enableMouse: boolean
|
|
8
|
+
skipTerminalSetup: boolean
|
|
9
|
+
/**
|
|
10
|
+
* Enable Kitty keyboard protocol for enhanced modifier detection.
|
|
11
|
+
* When enabled, Ctrl+Shift+C can be distinguished from Ctrl+C.
|
|
12
|
+
* Supported by: Kitty, iTerm2 3.5+, WezTerm, Ghostty, foot, Contour, rio.
|
|
13
|
+
* Gracefully ignored by terminals that don't support it.
|
|
14
|
+
* @default true
|
|
15
|
+
*/
|
|
16
|
+
enableKittyKeyboard?: boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Manages terminal setup and teardown sequences.
|
|
21
|
+
* Handles fullscreen mode, cursor visibility, paste bracketing, mouse tracking, and raw mode.
|
|
22
|
+
*/
|
|
23
|
+
export class TerminalSetup {
|
|
24
|
+
constructor(
|
|
25
|
+
private stdout: TuiWriteStream,
|
|
26
|
+
private stdin: TuiReadStream,
|
|
27
|
+
private config: TerminalSetupConfig,
|
|
28
|
+
) {}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Set up terminal for rendering.
|
|
32
|
+
* Call this before starting the render loop.
|
|
33
|
+
*/
|
|
34
|
+
setup(): void {
|
|
35
|
+
if (this.config.skipTerminalSetup) return
|
|
36
|
+
|
|
37
|
+
if (this.config.mode === "fullscreen") {
|
|
38
|
+
this.stdout.write(Terminal.enterFullscreen)
|
|
39
|
+
} else {
|
|
40
|
+
// Inline mode: try to disable reflow (DEC mode 2028)
|
|
41
|
+
// Supported by Contour, some others. Ignored by unsupported terminals.
|
|
42
|
+
this.stdout.write(ANSI.reflow.disable)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Hide cursor during rendering (both modes)
|
|
46
|
+
this.stdout.write(Terminal.hideCursor)
|
|
47
|
+
|
|
48
|
+
if (this.config.enablePaste) {
|
|
49
|
+
this.stdout.write(ANSI.paste.enable)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (this.config.enableMouse) {
|
|
53
|
+
this.stdout.write(ANSI.mouse.enable)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Enable enhanced keyboard protocols for modifier detection
|
|
57
|
+
// This allows distinguishing Ctrl+Shift+C from Ctrl+C on supported terminals
|
|
58
|
+
// NOTE: Many terminals intercept Ctrl+Shift+C for their own copy function!
|
|
59
|
+
if (this.config.enableKittyKeyboard !== false) {
|
|
60
|
+
this.stdout.write(ANSI.keyboard.enable(1)) // Kitty protocol (flag 1 = disambiguate)
|
|
61
|
+
this.stdout.write(ANSI.modifyOtherKeys.enable) // xterm protocol (mode 2)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (this.stdin.isTTY && this.stdin.setRawMode) {
|
|
65
|
+
this.stdin.setRawMode(true)
|
|
66
|
+
this.stdin.resume?.()
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Restore terminal to normal state.
|
|
72
|
+
* Call this when stopping the renderer.
|
|
73
|
+
*/
|
|
74
|
+
teardown(): void {
|
|
75
|
+
if (this.config.skipTerminalSetup) return
|
|
76
|
+
|
|
77
|
+
if (this.config.mode === "fullscreen") {
|
|
78
|
+
this.stdout.write(Terminal.exitFullscreen)
|
|
79
|
+
} else {
|
|
80
|
+
// Re-enable reflow on exit
|
|
81
|
+
this.stdout.write(ANSI.reflow.enable)
|
|
82
|
+
this.stdout.write("\r\n")
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (this.config.enablePaste) {
|
|
86
|
+
this.stdout.write(ANSI.paste.disable)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (this.config.enableMouse) {
|
|
90
|
+
this.stdout.write(ANSI.mouse.disable)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Disable enhanced keyboard protocols
|
|
94
|
+
if (this.config.enableKittyKeyboard !== false) {
|
|
95
|
+
this.stdout.write(ANSI.keyboard.disable)
|
|
96
|
+
this.stdout.write(ANSI.modifyOtherKeys.disable)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.stdout.write(Terminal.showCursor)
|
|
100
|
+
|
|
101
|
+
if (this.stdin.isTTY && this.stdin.setRawMode) {
|
|
102
|
+
this.stdin.setRawMode(false)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ANSI, emitRowWithReset, findChangeWindow } from "@effect-tui/core"
|
|
2
|
+
import type { RendererMode, RenderContext, RenderOutput } from "./RendererMode.js"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fullscreen rendering mode using alternate buffer.
|
|
6
|
+
* Supports line-by-line diffing for efficient updates.
|
|
7
|
+
*/
|
|
8
|
+
export class FullscreenRenderer implements RendererMode {
|
|
9
|
+
private needsFullClear = false
|
|
10
|
+
|
|
11
|
+
generateOutput(ctx: RenderContext): RenderOutput {
|
|
12
|
+
const { nextBuffer, prevBuffer, palette, frameWidth, frameHeight, enableDiff } = ctx
|
|
13
|
+
let output = ""
|
|
14
|
+
|
|
15
|
+
// If a full clear was requested (e.g., on resize), prepend it to output
|
|
16
|
+
// so clear + content are written atomically (no visible flash)
|
|
17
|
+
if (this.needsFullClear) {
|
|
18
|
+
output += ANSI.cursor.to(1, 1)
|
|
19
|
+
this.needsFullClear = false
|
|
20
|
+
// After clear, we must redraw everything - can't rely on diff
|
|
21
|
+
for (let y = 0; y < frameHeight; y++) {
|
|
22
|
+
if (y > 0) output += ANSI.cursor.to(1, y + 1)
|
|
23
|
+
output += emitRowWithReset(nextBuffer, palette, y, frameWidth)
|
|
24
|
+
}
|
|
25
|
+
} else if (enableDiff && prevBuffer) {
|
|
26
|
+
// Diff per line for minimal writes
|
|
27
|
+
for (let y = 0; y < frameHeight; y++) {
|
|
28
|
+
const change = findChangeWindow(prevBuffer, nextBuffer, y, frameWidth)
|
|
29
|
+
if (!change) continue
|
|
30
|
+
output += ANSI.cursor.to(change.left + 1, y + 1)
|
|
31
|
+
output += emitRowWithReset(nextBuffer, palette, y, frameWidth, change.left, change.right + 1)
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
// Full redraw (tests/manual mode)
|
|
35
|
+
output += ANSI.cursor.to(1, 1) + palette.sgr(0)
|
|
36
|
+
for (let y = 0; y < frameHeight; y++) {
|
|
37
|
+
output += emitRowWithReset(nextBuffer, palette, y, frameWidth)
|
|
38
|
+
if (y < frameHeight - 1) output += "\r\n"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return { output, contentHeight: frameHeight }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
handleResize(_newWidth: number, _newHeight: number, _prevWidth: number): void {
|
|
46
|
+
// Defer clear to generateOutput so it's written atomically with content
|
|
47
|
+
this.needsFullClear = true
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
reset(): void {
|
|
51
|
+
// Nothing to reset for fullscreen mode
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { ANSI, emitRowWithReset, rowContentWidth, findChangeWindow } from "@effect-tui/core"
|
|
2
|
+
import type { RendererMode, RenderContext, RenderOutput } from "./RendererMode.js"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Inline rendering mode that renders in-place without alternate buffer.
|
|
6
|
+
* When content exceeds terminal height, shows the bottom portion (bottom-aligned truncation).
|
|
7
|
+
*/
|
|
8
|
+
export class InlineRenderer implements RendererMode {
|
|
9
|
+
private previousHeight = 0
|
|
10
|
+
private previousStartRow = 0 // Track which row we started from (for truncation)
|
|
11
|
+
private _needsFullRerender = false
|
|
12
|
+
private printedWidths: number[] = []
|
|
13
|
+
|
|
14
|
+
generateOutput(ctx: RenderContext): RenderOutput {
|
|
15
|
+
const { prevBuffer, frameHeight, contentHeight } = ctx
|
|
16
|
+
let output = ""
|
|
17
|
+
|
|
18
|
+
// Calculate visible region (bottom-aligned when overflowing)
|
|
19
|
+
const isOverflowing = contentHeight > frameHeight
|
|
20
|
+
const visibleHeight = Math.min(contentHeight, frameHeight)
|
|
21
|
+
const startRow = isOverflowing ? contentHeight - frameHeight : 0
|
|
22
|
+
|
|
23
|
+
// Detect if viewport shifted (content grew/shrank affecting visible region)
|
|
24
|
+
const startRowChanged = startRow !== this.previousStartRow
|
|
25
|
+
const needsFullRedraw = this.previousHeight >= frameHeight || startRowChanged
|
|
26
|
+
|
|
27
|
+
// Need full redraw if: at terminal limit, or viewport shifted
|
|
28
|
+
if (needsFullRedraw) {
|
|
29
|
+
// Clear visible area and redraw (prepend to output for atomic write)
|
|
30
|
+
if (this.previousHeight > 0) {
|
|
31
|
+
output += ANSI.cursor.up(this.previousHeight)
|
|
32
|
+
}
|
|
33
|
+
output += ANSI.cursor.startOfLine
|
|
34
|
+
this.previousStartRow = startRow
|
|
35
|
+
this.printedWidths = []
|
|
36
|
+
} else if (this.previousHeight > 0) {
|
|
37
|
+
// Normal case: move cursor up to start of previous output
|
|
38
|
+
output += ANSI.cursor.up(this.previousHeight)
|
|
39
|
+
output += ANSI.cursor.startOfLine
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Generate output for visible region
|
|
43
|
+
if (prevBuffer && !needsFullRedraw) {
|
|
44
|
+
output += this.generateDiffOutput(ctx, visibleHeight, startRow)
|
|
45
|
+
} else {
|
|
46
|
+
output += this.generateFullOutput(ctx, visibleHeight, startRow, startRow + visibleHeight)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
this.previousHeight = visibleHeight
|
|
50
|
+
this.previousStartRow = startRow
|
|
51
|
+
return { output, contentHeight: visibleHeight }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private generateDiffOutput(ctx: RenderContext, visibleHeight: number, startRow: number): string {
|
|
55
|
+
const { nextBuffer, prevBuffer, palette, frameWidth } = ctx
|
|
56
|
+
if (!prevBuffer) return ""
|
|
57
|
+
|
|
58
|
+
let output = ""
|
|
59
|
+
const rowsToProcess = Math.max(visibleHeight, this.previousHeight)
|
|
60
|
+
let cursorRow = 0
|
|
61
|
+
|
|
62
|
+
const moveToRow = (targetRow: number) => {
|
|
63
|
+
const delta = targetRow - cursorRow
|
|
64
|
+
if (delta > 0) {
|
|
65
|
+
output += ANSI.cursor.down(delta)
|
|
66
|
+
} else if (delta < 0) {
|
|
67
|
+
output += ANSI.cursor.up(-delta)
|
|
68
|
+
}
|
|
69
|
+
cursorRow = targetRow
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for (let screenY = 0; screenY < rowsToProcess; screenY++) {
|
|
73
|
+
const bufferY = startRow + screenY
|
|
74
|
+
|
|
75
|
+
// Rows beyond visible height: clear if previously printed
|
|
76
|
+
if (screenY >= visibleHeight) {
|
|
77
|
+
const prevW = this.printedWidths[screenY] ?? 0
|
|
78
|
+
if (prevW > 0) {
|
|
79
|
+
moveToRow(screenY)
|
|
80
|
+
output += ANSI.cursor.toCol(1) + palette.sgr(0) + " ".repeat(prevW)
|
|
81
|
+
this.printedWidths[screenY] = 0
|
|
82
|
+
}
|
|
83
|
+
continue
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const change = findChangeWindow(prevBuffer, nextBuffer, bufferY, frameWidth)
|
|
87
|
+
const newW = rowContentWidth(nextBuffer, bufferY, frameWidth)
|
|
88
|
+
const prevW = this.printedWidths[screenY] ?? 0
|
|
89
|
+
|
|
90
|
+
if (!change) {
|
|
91
|
+
// No change; maybe need to clear tail if content shrunk
|
|
92
|
+
if (prevW > newW) {
|
|
93
|
+
moveToRow(screenY)
|
|
94
|
+
output += ANSI.cursor.toCol(newW + 1) + palette.sgr(0) + " ".repeat(prevW - newW)
|
|
95
|
+
this.printedWidths[screenY] = newW
|
|
96
|
+
}
|
|
97
|
+
continue
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Emit changed region [left..right]
|
|
101
|
+
moveToRow(screenY)
|
|
102
|
+
output += ANSI.cursor.toCol(change.left + 1)
|
|
103
|
+
output += emitRowWithReset(nextBuffer, palette, bufferY, frameWidth, change.left, change.right + 1)
|
|
104
|
+
|
|
105
|
+
// Clear tail if shrunk
|
|
106
|
+
const effectiveW = Math.max(newW, change.right + 1)
|
|
107
|
+
if (prevW > effectiveW) {
|
|
108
|
+
output += ANSI.cursor.toCol(effectiveW + 1) + palette.sgr(0) + " ".repeat(prevW - effectiveW)
|
|
109
|
+
}
|
|
110
|
+
this.printedWidths[screenY] = newW
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Ensure cursor ends just after the dynamic block for next frame positioning
|
|
114
|
+
moveToRow(visibleHeight)
|
|
115
|
+
output += ANSI.cursor.toCol(1)
|
|
116
|
+
|
|
117
|
+
return output
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private generateFullOutput(ctx: RenderContext, rowCount: number, startRow: number, endRow: number): string {
|
|
121
|
+
const { nextBuffer, palette, frameWidth } = ctx
|
|
122
|
+
let output = ""
|
|
123
|
+
|
|
124
|
+
// Full redraw inline: clear each line first, then emit content
|
|
125
|
+
for (let bufferY = startRow; bufferY < endRow; bufferY++) {
|
|
126
|
+
const screenY = bufferY - startRow
|
|
127
|
+
const trimmedWidth = rowContentWidth(nextBuffer, bufferY, frameWidth)
|
|
128
|
+
// Full-width emit avoids reliance on line clears.
|
|
129
|
+
output += emitRowWithReset(nextBuffer, palette, bufferY, frameWidth, 0, frameWidth)
|
|
130
|
+
output += "\r\n"
|
|
131
|
+
// Track line widths for resize reflow calculation
|
|
132
|
+
this.printedWidths[screenY] = trimmedWidth
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Clear any extra lines if content shrank
|
|
136
|
+
for (let screenY = rowCount; screenY < this.previousHeight; screenY++) {
|
|
137
|
+
output += palette.sgr(0) + " ".repeat(frameWidth) + "\r\n"
|
|
138
|
+
this.printedWidths[screenY] = 0
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Move cursor back up to end of content
|
|
142
|
+
if (this.previousHeight > rowCount) {
|
|
143
|
+
output += ANSI.cursor.up(this.previousHeight - rowCount)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return output
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
handleResize(newWidth: number, _newHeight: number, prevWidth: number): void {
|
|
150
|
+
// Any width change triggers full rerender (Ink-style: clear + replay static)
|
|
151
|
+
if (newWidth !== prevWidth) {
|
|
152
|
+
this._needsFullRerender = true
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Check if full rerender is needed (clear screen + replay static) */
|
|
157
|
+
needsFullRerender(): boolean {
|
|
158
|
+
return this._needsFullRerender
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Clear the full rerender flag after handling */
|
|
162
|
+
clearFullRerenderFlag(): void {
|
|
163
|
+
this._needsFullRerender = false
|
|
164
|
+
this.previousHeight = 0
|
|
165
|
+
this.previousStartRow = 0
|
|
166
|
+
this.printedWidths = []
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
reset(): void {
|
|
170
|
+
this.previousHeight = 0
|
|
171
|
+
this.previousStartRow = 0
|
|
172
|
+
this.printedWidths = []
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
getPreviousHeight(): number {
|
|
176
|
+
return this.previousHeight
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { CellBuffer, Palette } from "@effect-tui/core"
|
|
2
|
+
import type { TuiWriteStream } from "../../renderer-types.js"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Context passed to render mode output generation.
|
|
6
|
+
*/
|
|
7
|
+
export interface RenderContext {
|
|
8
|
+
nextBuffer: CellBuffer
|
|
9
|
+
prevBuffer: CellBuffer | null
|
|
10
|
+
palette: Palette
|
|
11
|
+
frameWidth: number
|
|
12
|
+
/** Terminal height (viewport) */
|
|
13
|
+
frameHeight: number
|
|
14
|
+
/** Actual content height (may exceed frameHeight in inline mode) */
|
|
15
|
+
contentHeight: number
|
|
16
|
+
enableDiff: boolean
|
|
17
|
+
stdout: TuiWriteStream
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Result of generating output for a frame.
|
|
22
|
+
*/
|
|
23
|
+
export interface RenderOutput {
|
|
24
|
+
output: string
|
|
25
|
+
contentHeight: number
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Interface for render mode implementations.
|
|
30
|
+
*/
|
|
31
|
+
export interface RendererMode {
|
|
32
|
+
/**
|
|
33
|
+
* Generate ANSI output for the current frame.
|
|
34
|
+
*/
|
|
35
|
+
generateOutput(ctx: RenderContext): RenderOutput
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Handle a resize event. Returns true if a full clear is needed.
|
|
39
|
+
*/
|
|
40
|
+
handleResize(newWidth: number, newHeight: number, prevWidth: number): void
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Reset any mode-specific state (e.g., after static content flush).
|
|
44
|
+
*/
|
|
45
|
+
reset(): void
|
|
46
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { CellBuffer, emitRowWithReset, rowContentWidth, type Palette } from "@effect-tui/core"
|
|
2
|
+
import type { HostInstance } from "../../reconciler/types.js"
|
|
3
|
+
import type { TuiWriteStream } from "../../renderer-types.js"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Renders static content to scrollback (inline mode only).
|
|
7
|
+
* Static content is rendered once and doesn't update with the dynamic section.
|
|
8
|
+
* Caches all output for replay on resize (Ink-style).
|
|
9
|
+
*/
|
|
10
|
+
export class StaticContentRenderer {
|
|
11
|
+
private cachedOutput = "" // Accumulates all static content for replay
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
_stdout: TuiWriteStream, // Kept for API compatibility, not used (writes are atomic in renderer.ts)
|
|
15
|
+
private palette: Palette,
|
|
16
|
+
) {}
|
|
17
|
+
|
|
18
|
+
/** Get all cached static output for replay on resize */
|
|
19
|
+
getCachedOutput(): string {
|
|
20
|
+
return this.cachedOutput
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Clear the cache (call after full terminal clear + replay) */
|
|
24
|
+
clearCache(): void {
|
|
25
|
+
this.cachedOutput = ""
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Render a static node and return the output string.
|
|
30
|
+
* Static content is append-only - no cursor positioning needed.
|
|
31
|
+
* Caller clears dynamic area first, then appends this output.
|
|
32
|
+
*/
|
|
33
|
+
render(staticNode: HostInstance, frameWidth: number): string {
|
|
34
|
+
// Measure and layout static content
|
|
35
|
+
const staticSize = staticNode.measure(frameWidth, Number.MAX_SAFE_INTEGER)
|
|
36
|
+
staticNode.layout({ x: 0, y: 0, w: frameWidth, h: staticSize.h })
|
|
37
|
+
|
|
38
|
+
// Render to a temporary buffer
|
|
39
|
+
const staticBuffer = new CellBuffer(frameWidth, staticSize.h)
|
|
40
|
+
staticBuffer.clear(0)
|
|
41
|
+
staticNode.render(staticBuffer, this.palette)
|
|
42
|
+
|
|
43
|
+
// Build content lines - append-only, no cursor movement
|
|
44
|
+
let contentLines = ""
|
|
45
|
+
for (let y = 0; y < staticSize.h; y++) {
|
|
46
|
+
const trimmedWidth = rowContentWidth(staticBuffer, y, frameWidth)
|
|
47
|
+
const line = emitRowWithReset(staticBuffer, this.palette, y, frameWidth, 0, trimmedWidth)
|
|
48
|
+
contentLines += line + "\n"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Cache the content for replay on resize
|
|
52
|
+
this.cachedOutput += contentLines
|
|
53
|
+
|
|
54
|
+
return contentLines
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createContext, useContext, useState, useEffect } from "react"
|
|
2
|
+
import type { TuiRenderer } from "./renderer-types.js"
|
|
3
|
+
|
|
4
|
+
// Context for accessing renderer in components
|
|
5
|
+
export const RendererContext = createContext<TuiRenderer | null>(null)
|
|
6
|
+
|
|
7
|
+
export function useRenderer(): TuiRenderer {
|
|
8
|
+
const renderer = useContext(RendererContext)
|
|
9
|
+
if (!renderer) {
|
|
10
|
+
throw new Error("useRenderer must be used within a TUI renderer")
|
|
11
|
+
}
|
|
12
|
+
return renderer
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Hook that returns terminal size and re-renders on resize */
|
|
16
|
+
export function useTerminalSize(): { width: number; height: number } {
|
|
17
|
+
const renderer = useRenderer()
|
|
18
|
+
const [size, setSize] = useState({ width: renderer.width, height: renderer.height })
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
return renderer.onResize((width, height) => {
|
|
22
|
+
setSize({ width, height })
|
|
23
|
+
})
|
|
24
|
+
}, [renderer])
|
|
25
|
+
|
|
26
|
+
return size
|
|
27
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { KeyMsg, MouseMsg } from "@effect-tui/core"
|
|
2
|
+
import type { HostInstance, HostContext } from "./reconciler/types.js"
|
|
3
|
+
|
|
4
|
+
/** Minimal write stream interface for renderer output */
|
|
5
|
+
export interface TuiWriteStream {
|
|
6
|
+
write(s: string): void
|
|
7
|
+
columns: number
|
|
8
|
+
rows: number
|
|
9
|
+
on(event: string, cb: () => void): void
|
|
10
|
+
removeListener(event: string, cb: () => void): void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Minimal read stream interface for renderer input */
|
|
14
|
+
export interface TuiReadStream {
|
|
15
|
+
isTTY?: boolean
|
|
16
|
+
setRawMode?(mode: boolean): void
|
|
17
|
+
resume?(): void
|
|
18
|
+
on(event: string, cb: (data: Buffer) => void): void
|
|
19
|
+
removeListener(event: string, cb: (data: Buffer) => void): void
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface TuiRenderer {
|
|
23
|
+
/** Terminal width */
|
|
24
|
+
width: number
|
|
25
|
+
/** Terminal height */
|
|
26
|
+
height: number
|
|
27
|
+
/** Request a re-render */
|
|
28
|
+
requestRender(): void
|
|
29
|
+
/** Subscribe to per-frame stats (if enabled). */
|
|
30
|
+
onFrameStats?(handler: (stats: FrameStats) => void): () => void
|
|
31
|
+
/** Subscribe to keyboard events */
|
|
32
|
+
onKey(handler: (key: KeyMsg) => void): () => void
|
|
33
|
+
/** Subscribe to mouse events (clicks, scroll, etc.) */
|
|
34
|
+
onMouse(handler: (mouse: MouseMsg) => void): () => void
|
|
35
|
+
/** Subscribe to paste events (bracketed paste mode). */
|
|
36
|
+
onPaste?(handler: (text: string) => void): () => void
|
|
37
|
+
/** Subscribe to resize events */
|
|
38
|
+
onResize(handler: (width: number, height: number) => void): () => void
|
|
39
|
+
/** Stop the renderer */
|
|
40
|
+
stop(): void
|
|
41
|
+
/** Manually trigger one render frame (only in manualMode) */
|
|
42
|
+
flush(): void
|
|
43
|
+
/**
|
|
44
|
+
* Get the current screen as ANSI string (for screenshots/debugging).
|
|
45
|
+
* Returns the last rendered frame with all ANSI color codes intact.
|
|
46
|
+
*/
|
|
47
|
+
getScreenshot(): string
|
|
48
|
+
/** Dispatch a key event (for remote control) */
|
|
49
|
+
dispatchKey?(key: KeyMsg): void
|
|
50
|
+
/** Dispatch a paste event (for remote control) */
|
|
51
|
+
dispatchPaste?(text: string): void
|
|
52
|
+
/** Dispatch a resize event (for remote control) */
|
|
53
|
+
dispatchResize?(width: number, height: number): void
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Internal renderer type with container reference */
|
|
57
|
+
export interface TuiRendererInternal extends TuiRenderer {
|
|
58
|
+
_container: Container | null
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface Container {
|
|
62
|
+
root: HostInstance | null
|
|
63
|
+
ctx: HostContext
|
|
64
|
+
/** @internal Static content root node (for Static component) */
|
|
65
|
+
staticRoot?: HostInstance | null
|
|
66
|
+
/** @internal Flag indicating static content needs flushing */
|
|
67
|
+
staticDirty?: boolean
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface RendererOptions {
|
|
71
|
+
fps?: number
|
|
72
|
+
stdout?: NodeJS.WriteStream | TuiWriteStream
|
|
73
|
+
stdin?: NodeJS.ReadStream | TuiReadStream
|
|
74
|
+
/** Render mode: "fullscreen" uses alternate buffer, "inline" renders in-place */
|
|
75
|
+
mode?: "fullscreen" | "inline"
|
|
76
|
+
/** Exit the process on Ctrl+C unless preventDefault was called. Defaults to true. */
|
|
77
|
+
exitOnCtrlC?: boolean
|
|
78
|
+
/** Enable diffed rendering (per-line). Defaults to true in runtime, false in manualMode (tests). */
|
|
79
|
+
diff?: boolean
|
|
80
|
+
/** Skip automatic render loop. Call flush() manually to render frames. */
|
|
81
|
+
manualMode?: boolean
|
|
82
|
+
/** Skip fullscreen/raw mode setup (for testing) */
|
|
83
|
+
skipTerminalSetup?: boolean
|
|
84
|
+
/** Enable bracketed paste (default true). */
|
|
85
|
+
enablePaste?: boolean
|
|
86
|
+
/** Enable mouse mode for scroll wheel events (default true in fullscreen). */
|
|
87
|
+
enableMouse?: boolean
|
|
88
|
+
/** Optional per-frame diagnostics hook. Called after each frame is written. */
|
|
89
|
+
debug?: {
|
|
90
|
+
onFrame?: (stats: FrameStats) => void
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface FrameStats {
|
|
95
|
+
mode: "fullscreen" | "inline"
|
|
96
|
+
width: number
|
|
97
|
+
height: number
|
|
98
|
+
contentHeight: number
|
|
99
|
+
bytes: number
|
|
100
|
+
frameMs: number
|
|
101
|
+
phases: {
|
|
102
|
+
clear: number
|
|
103
|
+
layout: number
|
|
104
|
+
render: number
|
|
105
|
+
diffAnsi: number
|
|
106
|
+
write: number
|
|
107
|
+
}
|
|
108
|
+
timestamp: number
|
|
109
|
+
}
|