@effect-tui/react 0.1.3 → 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 +30 -23
- 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 -94
- 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,386 @@
|
|
|
1
|
+
// use-scroll.ts — Hook for managing scroll state with keyboard/mouse input
|
|
2
|
+
import { useState, useCallback, useRef, useMemo, useLayoutEffect } from "react"
|
|
3
|
+
import type { KeyMsg } from "@effect-tui/core"
|
|
4
|
+
import { useKeyboard } from "./use-keyboard.js"
|
|
5
|
+
import { useTerminalSize } from "../renderer.js"
|
|
6
|
+
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Scroll Acceleration (macOS-style)
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
interface ScrollAcceleration {
|
|
12
|
+
tick(now?: number): number
|
|
13
|
+
reset(): void
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* macOS-inspired scroll acceleration.
|
|
18
|
+
* Tracks velocity via moving window of tick intervals.
|
|
19
|
+
* Fast scrolling gets progressively faster.
|
|
20
|
+
*/
|
|
21
|
+
class MacOSScrollAccel implements ScrollAcceleration {
|
|
22
|
+
private lastTickTime = 0
|
|
23
|
+
private velocityHistory: number[] = []
|
|
24
|
+
private readonly historySize = 3
|
|
25
|
+
private readonly streakTimeout = 150
|
|
26
|
+
// Some terminals send duplicate ticks ~4ms apart (Ghostty workaround)
|
|
27
|
+
private readonly minTickInterval = 6
|
|
28
|
+
|
|
29
|
+
constructor(
|
|
30
|
+
private opts: {
|
|
31
|
+
A?: number // Amplitude (default 0.8)
|
|
32
|
+
tau?: number // Time constant (default 3)
|
|
33
|
+
maxMultiplier?: number // Cap (default 6)
|
|
34
|
+
} = {},
|
|
35
|
+
) {}
|
|
36
|
+
|
|
37
|
+
tick(now = Date.now()): number {
|
|
38
|
+
const A = this.opts.A ?? 0.8
|
|
39
|
+
const tau = this.opts.tau ?? 3
|
|
40
|
+
const maxMultiplier = this.opts.maxMultiplier ?? 6
|
|
41
|
+
|
|
42
|
+
const dt = this.lastTickTime ? now - this.lastTickTime : Infinity
|
|
43
|
+
|
|
44
|
+
// Reset if too much time passed
|
|
45
|
+
if (dt === Infinity || dt > this.streakTimeout) {
|
|
46
|
+
this.lastTickTime = now
|
|
47
|
+
this.velocityHistory = []
|
|
48
|
+
return 1
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Ignore duplicate ticks (terminal quirks)
|
|
52
|
+
if (dt < this.minTickInterval) {
|
|
53
|
+
return 1
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.lastTickTime = now
|
|
57
|
+
this.velocityHistory.push(dt)
|
|
58
|
+
if (this.velocityHistory.length > this.historySize) {
|
|
59
|
+
this.velocityHistory.shift()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Calculate average interval (lower = faster scrolling)
|
|
63
|
+
const avgInterval = this.velocityHistory.reduce((a, b) => a + b, 0) / this.velocityHistory.length
|
|
64
|
+
|
|
65
|
+
// Convert to velocity: faster ticks = higher velocity
|
|
66
|
+
const referenceInterval = 100
|
|
67
|
+
const velocity = referenceInterval / avgInterval
|
|
68
|
+
|
|
69
|
+
// Apply exponential curve
|
|
70
|
+
const x = velocity / tau
|
|
71
|
+
const multiplier = 1 + A * (Math.exp(x) - 1)
|
|
72
|
+
|
|
73
|
+
return Math.min(multiplier, maxMultiplier)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
reset(): void {
|
|
77
|
+
this.lastTickTime = 0
|
|
78
|
+
this.velocityHistory = []
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ============================================================================
|
|
83
|
+
// Scroll State
|
|
84
|
+
// ============================================================================
|
|
85
|
+
|
|
86
|
+
export interface ScrollState {
|
|
87
|
+
/** Current scroll offset (pixels from start) */
|
|
88
|
+
offset: number
|
|
89
|
+
/** Maximum scroll offset */
|
|
90
|
+
maxOffset: number
|
|
91
|
+
/** Viewport height (or width for horizontal) */
|
|
92
|
+
viewportSize: number
|
|
93
|
+
/** Total content size */
|
|
94
|
+
contentSize: number
|
|
95
|
+
/** Whether we're at the start edge */
|
|
96
|
+
atStart: boolean
|
|
97
|
+
/** Whether we're at the end edge */
|
|
98
|
+
atEnd: boolean
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface UseScrollOptions {
|
|
102
|
+
/** Scroll axis: "vertical" (default) or "horizontal" */
|
|
103
|
+
axis?: "vertical" | "horizontal"
|
|
104
|
+
/** Initial scroll offset */
|
|
105
|
+
initialOffset?: number
|
|
106
|
+
/** Enable keyboard navigation (default: true) */
|
|
107
|
+
enableKeyboard?: boolean
|
|
108
|
+
/** Enable mouse wheel (default: true) */
|
|
109
|
+
enableMouseWheel?: boolean
|
|
110
|
+
/** Enable scroll acceleration (default: true) */
|
|
111
|
+
enableAcceleration?: boolean
|
|
112
|
+
/** Sticky scroll - auto-scroll to end when content grows (default: false) */
|
|
113
|
+
sticky?: boolean
|
|
114
|
+
/** Scroll speed for arrow keys (pixels, default: 1) */
|
|
115
|
+
arrowSpeed?: number
|
|
116
|
+
/** Scroll speed for page up/down (fraction of viewport, default: 0.5) */
|
|
117
|
+
pageSpeed?: number
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface UseScrollReturn {
|
|
121
|
+
/** Current scroll state */
|
|
122
|
+
state: ScrollState
|
|
123
|
+
/** Set scroll offset directly */
|
|
124
|
+
setOffset: (offset: number) => void
|
|
125
|
+
/** Scroll by delta pixels */
|
|
126
|
+
scrollBy: (delta: number) => void
|
|
127
|
+
/** Scroll to start */
|
|
128
|
+
scrollToStart: () => void
|
|
129
|
+
/** Scroll to end */
|
|
130
|
+
scrollToEnd: () => void
|
|
131
|
+
/**
|
|
132
|
+
* Scroll to make a position visible in the viewport.
|
|
133
|
+
* Useful for keeping a selected item in view.
|
|
134
|
+
* @param position - The position (row/col index or pixel offset)
|
|
135
|
+
* @param itemSize - Size of each item (default: 1 for row-based lists)
|
|
136
|
+
* @param padding - Extra padding around the item (default: 0)
|
|
137
|
+
*/
|
|
138
|
+
scrollToVisible: (position: number, itemSize?: number, padding?: number) => void
|
|
139
|
+
/** Props to spread on <scroll> element */
|
|
140
|
+
scrollProps: {
|
|
141
|
+
offset: number
|
|
142
|
+
axis: "vertical" | "horizontal"
|
|
143
|
+
onContentSize: (width: number, height: number) => void
|
|
144
|
+
onViewportSize: (width: number, height: number) => void
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Hook for managing scroll state with keyboard/mouse input.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```tsx
|
|
153
|
+
* function ScrollableList({ items }) {
|
|
154
|
+
* const { state, scrollProps } = useScroll({ sticky: true })
|
|
155
|
+
*
|
|
156
|
+
* return (
|
|
157
|
+
* <scroll {...scrollProps}>
|
|
158
|
+
* <vstack>
|
|
159
|
+
* {items.map(item => <text key={item.id}>{item.text}</text>)}
|
|
160
|
+
* </vstack>
|
|
161
|
+
* </scroll>
|
|
162
|
+
* )
|
|
163
|
+
* }
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
export function useScroll(options: UseScrollOptions = {}): UseScrollReturn {
|
|
167
|
+
const {
|
|
168
|
+
axis = "vertical",
|
|
169
|
+
initialOffset = 0,
|
|
170
|
+
enableKeyboard = true,
|
|
171
|
+
enableMouseWheel = true,
|
|
172
|
+
enableAcceleration = true,
|
|
173
|
+
sticky = false,
|
|
174
|
+
arrowSpeed = 1,
|
|
175
|
+
pageSpeed = 0.5,
|
|
176
|
+
} = options
|
|
177
|
+
|
|
178
|
+
const { width: termWidth, height: termHeight } = useTerminalSize()
|
|
179
|
+
|
|
180
|
+
// Scroll state
|
|
181
|
+
const [offset, setOffsetRaw] = useState(initialOffset)
|
|
182
|
+
const [contentSize, setContentSize] = useState(0)
|
|
183
|
+
// Use terminal size as initial estimate, but scroll component will report actual size
|
|
184
|
+
const [viewportSize, setViewportSize] = useState(axis === "vertical" ? termHeight : termWidth)
|
|
185
|
+
|
|
186
|
+
// Refs for sticky scroll behavior
|
|
187
|
+
const wasAtEndRef = useRef(sticky)
|
|
188
|
+
const prevContentSizeRef = useRef(0)
|
|
189
|
+
|
|
190
|
+
// Scroll acceleration
|
|
191
|
+
const accel = useMemo(
|
|
192
|
+
() => (enableAcceleration ? new MacOSScrollAccel() : { tick: () => 1, reset: () => {} }),
|
|
193
|
+
[enableAcceleration],
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
// Fractional accumulator for smooth sub-pixel scrolling
|
|
197
|
+
const accumulatorRef = useRef(0)
|
|
198
|
+
|
|
199
|
+
// Ref for scrollToVisible so it doesn't change on every scroll
|
|
200
|
+
const offsetRef = useRef(offset)
|
|
201
|
+
offsetRef.current = offset
|
|
202
|
+
|
|
203
|
+
// Calculate derived state
|
|
204
|
+
const maxOffset = Math.max(0, contentSize - viewportSize)
|
|
205
|
+
const atStart = offset <= 0
|
|
206
|
+
const atEnd = offset >= maxOffset
|
|
207
|
+
|
|
208
|
+
// Clamp and set offset
|
|
209
|
+
const setOffset = useCallback(
|
|
210
|
+
(newOffset: number) => {
|
|
211
|
+
const clamped = Math.max(0, Math.min(maxOffset, newOffset))
|
|
212
|
+
setOffsetRaw(clamped)
|
|
213
|
+
// Track if we're at end for sticky behavior
|
|
214
|
+
wasAtEndRef.current = clamped >= maxOffset - 1
|
|
215
|
+
},
|
|
216
|
+
[maxOffset],
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
// Scroll by delta with accumulator for fractional scrolling
|
|
220
|
+
const scrollBy = useCallback(
|
|
221
|
+
(delta: number) => {
|
|
222
|
+
accumulatorRef.current += delta
|
|
223
|
+
const integerDelta = Math.trunc(accumulatorRef.current)
|
|
224
|
+
if (integerDelta !== 0) {
|
|
225
|
+
setOffset(offset + integerDelta)
|
|
226
|
+
accumulatorRef.current -= integerDelta
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
[offset, setOffset],
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
const scrollToStart = useCallback(() => {
|
|
233
|
+
setOffset(0)
|
|
234
|
+
accumulatorRef.current = 0
|
|
235
|
+
accel.reset()
|
|
236
|
+
}, [setOffset, accel])
|
|
237
|
+
|
|
238
|
+
const scrollToEnd = useCallback(() => {
|
|
239
|
+
setOffset(maxOffset)
|
|
240
|
+
accumulatorRef.current = 0
|
|
241
|
+
accel.reset()
|
|
242
|
+
}, [setOffset, maxOffset, accel])
|
|
243
|
+
|
|
244
|
+
// Handle content size changes (for sticky scroll)
|
|
245
|
+
const handleContentSize = useCallback(
|
|
246
|
+
(width: number, height: number) => {
|
|
247
|
+
const newSize = axis === "vertical" ? height : width
|
|
248
|
+
setContentSize(newSize)
|
|
249
|
+
prevContentSizeRef.current = newSize
|
|
250
|
+
},
|
|
251
|
+
[axis],
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
// Synchronous sticky scroll: snap to end when content grows
|
|
255
|
+
// useLayoutEffect runs synchronously after React commit but before paint
|
|
256
|
+
useLayoutEffect(() => {
|
|
257
|
+
if (!sticky) return
|
|
258
|
+
const newMaxOffset = Math.max(0, contentSize - viewportSize)
|
|
259
|
+
if (wasAtEndRef.current && contentSize > 0) {
|
|
260
|
+
setOffsetRaw(newMaxOffset)
|
|
261
|
+
}
|
|
262
|
+
}, [sticky, contentSize, viewportSize])
|
|
263
|
+
|
|
264
|
+
// Handle viewport size changes (reported by scroll component)
|
|
265
|
+
const handleViewportSize = useCallback(
|
|
266
|
+
(width: number, height: number) => {
|
|
267
|
+
const newSize = axis === "vertical" ? height : width
|
|
268
|
+
setViewportSize(newSize)
|
|
269
|
+
},
|
|
270
|
+
[axis],
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
// Keyboard handler
|
|
274
|
+
const handleKey = useCallback(
|
|
275
|
+
(key: KeyMsg) => {
|
|
276
|
+
// Mouse wheel comes as pageup/pagedown with meta=true
|
|
277
|
+
// Handle separately from keyboard since enableKeyboard shouldn't disable mouse
|
|
278
|
+
if (key.meta && enableMouseWheel && (key.name === "pageup" || key.name === "pagedown")) {
|
|
279
|
+
const multiplier = accel.tick()
|
|
280
|
+
const delta = Math.ceil(arrowSpeed * multiplier)
|
|
281
|
+
scrollBy(key.name === "pageup" ? -delta : delta)
|
|
282
|
+
return
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (!enableKeyboard) return
|
|
286
|
+
|
|
287
|
+
const isVertical = axis === "vertical"
|
|
288
|
+
const upKey = isVertical ? "up" : "left"
|
|
289
|
+
const downKey = isVertical ? "down" : "right"
|
|
290
|
+
|
|
291
|
+
switch (key.name) {
|
|
292
|
+
case upKey:
|
|
293
|
+
scrollBy(-arrowSpeed)
|
|
294
|
+
break
|
|
295
|
+
case downKey:
|
|
296
|
+
scrollBy(arrowSpeed)
|
|
297
|
+
break
|
|
298
|
+
case "pageup":
|
|
299
|
+
scrollBy(-Math.floor(viewportSize * pageSpeed))
|
|
300
|
+
break
|
|
301
|
+
case "pagedown":
|
|
302
|
+
scrollBy(Math.floor(viewportSize * pageSpeed))
|
|
303
|
+
break
|
|
304
|
+
case "home":
|
|
305
|
+
scrollToStart()
|
|
306
|
+
break
|
|
307
|
+
case "end":
|
|
308
|
+
scrollToEnd()
|
|
309
|
+
break
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
[
|
|
313
|
+
enableKeyboard,
|
|
314
|
+
axis,
|
|
315
|
+
arrowSpeed,
|
|
316
|
+
pageSpeed,
|
|
317
|
+
viewportSize,
|
|
318
|
+
enableMouseWheel,
|
|
319
|
+
accel,
|
|
320
|
+
scrollBy,
|
|
321
|
+
scrollToStart,
|
|
322
|
+
scrollToEnd,
|
|
323
|
+
],
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
useKeyboard(handleKey)
|
|
327
|
+
|
|
328
|
+
// Scroll to make a position visible (for keeping selection in view)
|
|
329
|
+
// Uses refs to avoid changing on every scroll - only triggers when selection changes
|
|
330
|
+
const scrollToVisible = useCallback(
|
|
331
|
+
(position: number, itemSize = 1, padding = 0) => {
|
|
332
|
+
const currentOffset = offsetRef.current
|
|
333
|
+
const itemStart = position * itemSize
|
|
334
|
+
const itemEnd = itemStart + itemSize
|
|
335
|
+
|
|
336
|
+
// If item is above viewport, scroll up to show it
|
|
337
|
+
if (itemStart < currentOffset + padding) {
|
|
338
|
+
setOffset(Math.max(0, itemStart - padding))
|
|
339
|
+
}
|
|
340
|
+
// If item is below viewport, scroll down to show it
|
|
341
|
+
else if (itemEnd > currentOffset + viewportSize - padding) {
|
|
342
|
+
const currentMaxOffset = Math.max(0, contentSize - viewportSize)
|
|
343
|
+
setOffset(Math.min(currentMaxOffset, itemEnd - viewportSize + padding))
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
[viewportSize, contentSize, setOffset],
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
const state: ScrollState = {
|
|
350
|
+
offset,
|
|
351
|
+
maxOffset,
|
|
352
|
+
viewportSize,
|
|
353
|
+
contentSize,
|
|
354
|
+
atStart,
|
|
355
|
+
atEnd,
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Handle effective offset sync from host (when sticky adjusts the offset)
|
|
359
|
+
const handleEffectiveOffset = useCallback(
|
|
360
|
+
(effectiveOffset: number) => {
|
|
361
|
+
// Sync the ref so scrollToVisible uses the actual rendered position
|
|
362
|
+
offsetRef.current = effectiveOffset
|
|
363
|
+
// Also update state to keep in sync (but don't trigger wasAtEnd change)
|
|
364
|
+
setOffsetRaw(effectiveOffset)
|
|
365
|
+
},
|
|
366
|
+
[],
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
const scrollProps = {
|
|
370
|
+
offset,
|
|
371
|
+
axis,
|
|
372
|
+
onContentSize: handleContentSize,
|
|
373
|
+
onViewportSize: handleViewportSize,
|
|
374
|
+
onEffectiveOffset: handleEffectiveOffset,
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return {
|
|
378
|
+
state,
|
|
379
|
+
setOffset,
|
|
380
|
+
scrollBy,
|
|
381
|
+
scrollToStart,
|
|
382
|
+
scrollToEnd,
|
|
383
|
+
scrollToVisible,
|
|
384
|
+
scrollProps,
|
|
385
|
+
}
|
|
386
|
+
}
|
|
@@ -7,26 +7,26 @@ import type { FrameStats } from "../renderer.js"
|
|
|
7
7
|
* Falls back to null when the renderer does not support onFrameStats.
|
|
8
8
|
*/
|
|
9
9
|
export function useFrameStats(sampleMs = 200): FrameStats | null {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const renderer = useRenderer()
|
|
11
|
+
const [stats, setStats] = useState<FrameStats | null>(null)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (!renderer.onFrameStats) return
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
let last: FrameStats | null = null
|
|
17
|
+
const unsub = renderer.onFrameStats((s) => {
|
|
18
|
+
last = s
|
|
19
|
+
})
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
const id = setInterval(() => {
|
|
22
|
+
if (last) setStats(last)
|
|
23
|
+
}, sampleMs)
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
return () => {
|
|
26
|
+
clearInterval(id)
|
|
27
|
+
unsub?.()
|
|
28
|
+
}
|
|
29
|
+
}, [renderer, sampleMs])
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
return stats
|
|
32
32
|
}
|
package/src/hosts/base.ts
CHANGED
|
@@ -1,65 +1,186 @@
|
|
|
1
|
-
import type { CellBuffer, Palette } from "@effect-tui/core"
|
|
1
|
+
import type { CellBuffer, Palette, Color } from "@effect-tui/core"
|
|
2
2
|
import type { HostInstance, Rect, Size, HostContext, CommonProps } from "../reconciler/types.js"
|
|
3
3
|
|
|
4
|
+
/** Host that may have a background color (e.g., BoxHost) */
|
|
5
|
+
export interface HostWithBg extends HostInstance {
|
|
6
|
+
bg?: Color
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Type guard for hosts with bg property */
|
|
10
|
+
function hasBackground(host: HostInstance): host is HostWithBg {
|
|
11
|
+
return "bg" in host
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Walk up parent chain to find inherited background color */
|
|
15
|
+
export function getInheritedBg(startParent: HostInstance | null): Color | undefined {
|
|
16
|
+
let p: HostInstance | null = startParent
|
|
17
|
+
while (p) {
|
|
18
|
+
if (hasBackground(p) && p.bg !== undefined) {
|
|
19
|
+
return p.bg
|
|
20
|
+
}
|
|
21
|
+
p = p.parent
|
|
22
|
+
}
|
|
23
|
+
return undefined
|
|
24
|
+
}
|
|
25
|
+
|
|
4
26
|
let idCounter = 0
|
|
5
27
|
|
|
6
28
|
export abstract class BaseHost implements HostInstance {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
29
|
+
id: string
|
|
30
|
+
type: string
|
|
31
|
+
parent: HostInstance | null = null
|
|
32
|
+
children: HostInstance[] = []
|
|
33
|
+
rect: Rect | null = null
|
|
34
|
+
|
|
35
|
+
// Common flex props
|
|
36
|
+
flexGrow = 0
|
|
37
|
+
flexShrink = 1
|
|
38
|
+
|
|
39
|
+
// ─────────────────────────────────────────────────────────────
|
|
40
|
+
// Frame constraints (like SwiftUI's .frame modifier)
|
|
41
|
+
// See CommonProps for detailed documentation
|
|
42
|
+
// ─────────────────────────────────────────────────────────────
|
|
43
|
+
frameWidth?: number
|
|
44
|
+
frameHeight?: number
|
|
45
|
+
frameMinWidth?: number
|
|
46
|
+
frameMaxWidth?: number
|
|
47
|
+
frameMinHeight?: number
|
|
48
|
+
frameMaxHeight?: number
|
|
49
|
+
|
|
50
|
+
/** @internal Marks this node as static content (for Static component) */
|
|
51
|
+
__static?: boolean
|
|
52
|
+
|
|
53
|
+
protected ctx: HostContext
|
|
54
|
+
|
|
55
|
+
constructor(type: string, props: CommonProps, ctx: HostContext) {
|
|
56
|
+
this.id = `${type}-${idCounter++}`
|
|
57
|
+
this.type = type
|
|
58
|
+
this.ctx = ctx
|
|
59
|
+
// NOTE: Subclasses must call this.updateProps(props) after super()
|
|
60
|
+
// because JavaScript field initializers run AFTER parent constructor,
|
|
61
|
+
// which would overwrite any values set here.
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
abstract measure(maxW: number, maxH: number): Size
|
|
65
|
+
abstract render(buffer: CellBuffer, palette: Palette): void
|
|
66
|
+
|
|
67
|
+
layout(rect: Rect): void {
|
|
68
|
+
this.rect = rect
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Apply frame constraints to a proposed size before passing to children.
|
|
73
|
+
*
|
|
74
|
+
* This is the first half of SwiftUI-style frame semantics. When a parent
|
|
75
|
+
* proposes a size to us, we modify it based on our constraints before
|
|
76
|
+
* passing it down to our children.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```
|
|
80
|
+
* Parent proposes: 100x100
|
|
81
|
+
* Our height constraint: 10
|
|
82
|
+
* We propose to children: 100x10
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* This prevents greedy children (like scroll) from measuring larger than
|
|
86
|
+
* our constrained size.
|
|
87
|
+
*
|
|
88
|
+
* @param maxW - Width proposed by parent
|
|
89
|
+
* @param maxH - Height proposed by parent
|
|
90
|
+
* @returns Constrained size to propose to children
|
|
91
|
+
*/
|
|
92
|
+
protected constrainProposal(maxW: number, maxH: number): { w: number; h: number } {
|
|
93
|
+
let w = maxW
|
|
94
|
+
let h = maxH
|
|
95
|
+
|
|
96
|
+
// Fixed width/height override everything
|
|
97
|
+
if (this.frameWidth !== undefined) w = this.frameWidth
|
|
98
|
+
if (this.frameHeight !== undefined) h = this.frameHeight
|
|
99
|
+
|
|
100
|
+
// Apply min/max clamps
|
|
101
|
+
if (this.frameMinWidth !== undefined) w = Math.max(this.frameMinWidth, w)
|
|
102
|
+
if (this.frameMaxWidth !== undefined) w = Math.min(this.frameMaxWidth, w)
|
|
103
|
+
if (this.frameMinHeight !== undefined) h = Math.max(this.frameMinHeight, h)
|
|
104
|
+
if (this.frameMaxHeight !== undefined) h = Math.min(this.frameMaxHeight, h)
|
|
105
|
+
|
|
106
|
+
return { w, h }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Apply frame constraints to our measured size before returning to parent.
|
|
111
|
+
*
|
|
112
|
+
* This is the second half of SwiftUI-style frame semantics. After measuring
|
|
113
|
+
* our children, we modify our reported size based on our constraints before
|
|
114
|
+
* returning it to our parent.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```
|
|
118
|
+
* Children measured: 5x1 (small content)
|
|
119
|
+
* Our height constraint: 10
|
|
120
|
+
* We report to parent: 5x10
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* This ensures we report our constrained size regardless of children's
|
|
124
|
+
* natural size, which is essential for layout composition (e.g., spacer
|
|
125
|
+
* needs to know our fixed size to calculate remaining space).
|
|
126
|
+
*
|
|
127
|
+
* @param size - Natural size from measuring children
|
|
128
|
+
* @returns Constrained size to report to parent
|
|
129
|
+
*/
|
|
130
|
+
protected constrainResult(size: Size): Size {
|
|
131
|
+
let { w, h } = size
|
|
132
|
+
|
|
133
|
+
// Fixed width/height override the measured size
|
|
134
|
+
if (this.frameWidth !== undefined) w = this.frameWidth
|
|
135
|
+
if (this.frameHeight !== undefined) h = this.frameHeight
|
|
136
|
+
|
|
137
|
+
// Apply min/max clamps
|
|
138
|
+
if (this.frameMinWidth !== undefined) w = Math.max(this.frameMinWidth, w)
|
|
139
|
+
if (this.frameMaxWidth !== undefined) w = Math.min(this.frameMaxWidth, w)
|
|
140
|
+
if (this.frameMinHeight !== undefined) h = Math.max(this.frameMinHeight, h)
|
|
141
|
+
if (this.frameMaxHeight !== undefined) h = Math.min(this.frameMaxHeight, h)
|
|
142
|
+
|
|
143
|
+
return { w, h }
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
updateProps(props: Record<string, unknown>): void {
|
|
147
|
+
this.flexGrow = (props.flexGrow as number | undefined) ?? 0
|
|
148
|
+
this.flexShrink = (props.flexShrink as number | undefined) ?? 1
|
|
149
|
+
|
|
150
|
+
// Frame constraints
|
|
151
|
+
this.frameWidth = props.width as number | undefined
|
|
152
|
+
this.frameHeight = props.height as number | undefined
|
|
153
|
+
this.frameMinWidth = props.minWidth as number | undefined
|
|
154
|
+
this.frameMaxWidth = props.maxWidth as number | undefined
|
|
155
|
+
this.frameMinHeight = props.minHeight as number | undefined
|
|
156
|
+
this.frameMaxHeight = props.maxHeight as number | undefined
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
destroy(): void {
|
|
160
|
+
// Override in subclasses if cleanup needed
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Child management helpers
|
|
164
|
+
appendChild(child: HostInstance): void {
|
|
165
|
+
this.children.push(child)
|
|
166
|
+
child.parent = this
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
removeChild(child: HostInstance): void {
|
|
170
|
+
const idx = this.children.indexOf(child)
|
|
171
|
+
if (idx >= 0) {
|
|
172
|
+
this.children.splice(idx, 1)
|
|
173
|
+
child.parent = null
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
insertBefore(child: HostInstance, before: HostInstance): void {
|
|
178
|
+
const idx = this.children.indexOf(before)
|
|
179
|
+
if (idx >= 0) {
|
|
180
|
+
this.children.splice(idx, 0, child)
|
|
181
|
+
} else {
|
|
182
|
+
this.children.push(child)
|
|
183
|
+
}
|
|
184
|
+
child.parent = this
|
|
185
|
+
}
|
|
65
186
|
}
|