@effect-tui/react 0.15.2 → 2.0.0
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 +11 -2
- package/dist/src/codeblock.d.ts +1 -1
- package/dist/src/codeblock.d.ts.map +1 -1
- package/dist/src/codeblock.js +2 -2
- package/dist/src/codeblock.js.map +1 -1
- package/dist/src/components/ListView.d.ts +4 -4
- package/dist/src/components/ListView.d.ts.map +1 -1
- package/dist/src/components/ListView.js +16 -17
- package/dist/src/components/ListView.js.map +1 -1
- package/dist/src/components/Markdown.js +3 -3
- package/dist/src/components/Markdown.js.map +1 -1
- package/dist/src/components/MultilineTextInput.d.ts.map +1 -1
- package/dist/src/components/MultilineTextInput.js +133 -305
- package/dist/src/components/MultilineTextInput.js.map +1 -1
- package/dist/src/components/TextInput.d.ts.map +1 -1
- package/dist/src/components/TextInput.js +51 -98
- package/dist/src/components/TextInput.js.map +1 -1
- package/dist/src/components/text-editing.d.ts +61 -0
- package/dist/src/components/text-editing.d.ts.map +1 -1
- package/dist/src/components/text-editing.js +131 -0
- package/dist/src/components/text-editing.js.map +1 -1
- package/dist/src/console/ConsolePopover.d.ts +7 -1
- package/dist/src/console/ConsolePopover.d.ts.map +1 -1
- package/dist/src/console/ConsolePopover.js +55 -74
- package/dist/src/console/ConsolePopover.js.map +1 -1
- package/dist/src/debug/DebugOverlay.d.ts.map +1 -1
- package/dist/src/debug/DebugOverlay.js +3 -57
- package/dist/src/debug/DebugOverlay.js.map +1 -1
- package/dist/src/debug/DiagnosticsPanel.js +1 -1
- package/dist/src/debug/DiagnosticsPanel.js.map +1 -1
- package/dist/src/dev.d.ts +5 -117
- package/dist/src/dev.d.ts.map +1 -1
- package/dist/src/dev.js +3 -333
- package/dist/src/dev.js.map +1 -1
- package/dist/src/hooks/use-scroll.d.ts +31 -35
- package/dist/src/hooks/use-scroll.d.ts.map +1 -1
- package/dist/src/hooks/use-scroll.js +51 -90
- package/dist/src/hooks/use-scroll.js.map +1 -1
- package/dist/src/hosts/base.d.ts +13 -2
- package/dist/src/hosts/base.d.ts.map +1 -1
- package/dist/src/hosts/base.js +74 -2
- package/dist/src/hosts/base.js.map +1 -1
- package/dist/src/hosts/box.d.ts +2 -2
- package/dist/src/hosts/box.d.ts.map +1 -1
- package/dist/src/hosts/box.js +29 -2
- package/dist/src/hosts/box.js.map +1 -1
- package/dist/src/hosts/canvas.d.ts +24 -4
- package/dist/src/hosts/canvas.d.ts.map +1 -1
- package/dist/src/hosts/canvas.js +107 -41
- package/dist/src/hosts/canvas.js.map +1 -1
- package/dist/src/hosts/codeblock.d.ts +10 -12
- package/dist/src/hosts/codeblock.d.ts.map +1 -1
- package/dist/src/hosts/codeblock.js +38 -35
- package/dist/src/hosts/codeblock.js.map +1 -1
- package/dist/src/hosts/flex-container.d.ts +3 -3
- package/dist/src/hosts/flex-container.d.ts.map +1 -1
- package/dist/src/hosts/flex-container.js +20 -5
- package/dist/src/hosts/flex-container.js.map +1 -1
- package/dist/src/hosts/index.d.ts +3 -2
- package/dist/src/hosts/index.d.ts.map +1 -1
- package/dist/src/hosts/index.js +2 -1
- package/dist/src/hosts/index.js.map +1 -1
- package/dist/src/hosts/layout-helpers.d.ts +10 -0
- package/dist/src/hosts/layout-helpers.d.ts.map +1 -0
- package/dist/src/hosts/layout-helpers.js +10 -0
- package/dist/src/hosts/layout-helpers.js.map +1 -0
- package/dist/src/hosts/leaf.d.ts +14 -0
- package/dist/src/hosts/leaf.d.ts.map +1 -0
- package/dist/src/hosts/leaf.js +31 -0
- package/dist/src/hosts/leaf.js.map +1 -0
- package/dist/src/hosts/overlay-item.d.ts +2 -2
- package/dist/src/hosts/overlay-item.d.ts.map +1 -1
- package/dist/src/hosts/overlay-item.js +7 -2
- package/dist/src/hosts/overlay-item.js.map +1 -1
- package/dist/src/hosts/overlay.d.ts +2 -2
- package/dist/src/hosts/overlay.d.ts.map +1 -1
- package/dist/src/hosts/overlay.js +6 -9
- package/dist/src/hosts/overlay.js.map +1 -1
- package/dist/src/hosts/scroll.d.ts +54 -26
- package/dist/src/hosts/scroll.d.ts.map +1 -1
- package/dist/src/hosts/scroll.js +185 -87
- package/dist/src/hosts/scroll.js.map +1 -1
- package/dist/src/hosts/single-child.d.ts.map +1 -1
- package/dist/src/hosts/single-child.js +2 -0
- package/dist/src/hosts/single-child.js.map +1 -1
- package/dist/src/hosts/spacer.d.ts +3 -3
- package/dist/src/hosts/spacer.d.ts.map +1 -1
- package/dist/src/hosts/spacer.js +8 -3
- package/dist/src/hosts/spacer.js.map +1 -1
- package/dist/src/hosts/text.d.ts +22 -18
- package/dist/src/hosts/text.d.ts.map +1 -1
- package/dist/src/hosts/text.js +108 -131
- package/dist/src/hosts/text.js.map +1 -1
- package/dist/src/hosts/vstack.js +1 -1
- package/dist/src/hosts/vstack.js.map +1 -1
- package/dist/src/hosts/zstack.d.ts +3 -3
- package/dist/src/hosts/zstack.d.ts.map +1 -1
- package/dist/src/hosts/zstack.js +13 -8
- package/dist/src/hosts/zstack.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/internal/dev/hmr.d.ts +20 -0
- package/dist/src/internal/dev/hmr.d.ts.map +1 -0
- package/dist/src/internal/dev/hmr.js +93 -0
- package/dist/src/internal/dev/hmr.js.map +1 -0
- package/dist/src/internal/dev/runtime.d.ts +24 -0
- package/dist/src/internal/dev/runtime.d.ts.map +1 -0
- package/dist/src/internal/dev/runtime.js +135 -0
- package/dist/src/internal/dev/runtime.js.map +1 -0
- package/dist/src/internal/dev/ui.d.ts +13 -0
- package/dist/src/internal/dev/ui.d.ts.map +1 -0
- package/dist/src/internal/dev/ui.js +51 -0
- package/dist/src/internal/dev/ui.js.map +1 -0
- package/dist/src/internal/renderer/context.d.ts +9 -0
- package/dist/src/internal/renderer/context.d.ts.map +1 -0
- package/dist/src/internal/renderer/context.js +22 -0
- package/dist/src/internal/renderer/context.js.map +1 -0
- package/dist/src/internal/renderer/core/FrameBuilder.d.ts +18 -0
- package/dist/src/internal/renderer/core/FrameBuilder.d.ts.map +1 -0
- package/dist/src/internal/renderer/core/FrameBuilder.js +40 -0
- package/dist/src/internal/renderer/core/FrameBuilder.js.map +1 -0
- package/dist/src/internal/renderer/core/RendererState.d.ts +41 -0
- package/dist/src/internal/renderer/core/RendererState.d.ts.map +1 -0
- package/dist/src/internal/renderer/core/RendererState.js +70 -0
- package/dist/src/internal/renderer/core/RendererState.js.map +1 -0
- package/dist/src/internal/renderer/core/index.d.ts +3 -0
- package/dist/src/internal/renderer/core/index.d.ts.map +1 -0
- package/dist/src/internal/renderer/core/index.js +3 -0
- package/dist/src/internal/renderer/core/index.js.map +1 -0
- package/dist/src/internal/renderer/index.d.ts +40 -0
- package/dist/src/internal/renderer/index.d.ts.map +1 -0
- package/dist/src/internal/renderer/index.js +543 -0
- package/dist/src/internal/renderer/index.js.map +1 -0
- package/dist/src/internal/renderer/input/InputProcessor.d.ts +30 -0
- package/dist/src/internal/renderer/input/InputProcessor.d.ts.map +1 -0
- package/dist/src/internal/renderer/input/InputProcessor.js +122 -0
- package/dist/src/internal/renderer/input/InputProcessor.js.map +1 -0
- package/dist/src/internal/renderer/input/index.d.ts +2 -0
- package/dist/src/internal/renderer/input/index.d.ts.map +1 -0
- package/dist/src/internal/renderer/input/index.js +2 -0
- package/dist/src/internal/renderer/input/index.js.map +1 -0
- package/dist/src/internal/renderer/lifecycle/EventBus.d.ts +42 -0
- package/dist/src/internal/renderer/lifecycle/EventBus.d.ts.map +1 -0
- package/dist/src/internal/renderer/lifecycle/EventBus.js +97 -0
- package/dist/src/internal/renderer/lifecycle/EventBus.js.map +1 -0
- package/dist/src/internal/renderer/lifecycle/ProcessLifecycle.d.ts +13 -0
- package/dist/src/internal/renderer/lifecycle/ProcessLifecycle.d.ts.map +1 -0
- package/dist/src/internal/renderer/lifecycle/ProcessLifecycle.js +111 -0
- package/dist/src/internal/renderer/lifecycle/ProcessLifecycle.js.map +1 -0
- package/dist/src/internal/renderer/lifecycle/RenderCache.d.ts +3 -0
- package/dist/src/internal/renderer/lifecycle/RenderCache.d.ts.map +1 -0
- package/dist/src/internal/renderer/lifecycle/RenderCache.js +9 -0
- package/dist/src/internal/renderer/lifecycle/RenderCache.js.map +1 -0
- package/dist/src/internal/renderer/lifecycle/index.d.ts +4 -0
- package/dist/src/internal/renderer/lifecycle/index.d.ts.map +1 -0
- package/dist/src/internal/renderer/lifecycle/index.js +4 -0
- package/dist/src/internal/renderer/lifecycle/index.js.map +1 -0
- package/dist/src/internal/renderer/modes/FullscreenRenderer.d.ts +12 -0
- package/dist/src/internal/renderer/modes/FullscreenRenderer.d.ts.map +1 -0
- package/dist/src/internal/renderer/modes/FullscreenRenderer.js +54 -0
- package/dist/src/internal/renderer/modes/FullscreenRenderer.js.map +1 -0
- package/dist/src/internal/renderer/modes/InlineRenderer.d.ts +25 -0
- package/dist/src/internal/renderer/modes/InlineRenderer.d.ts.map +1 -0
- package/dist/src/internal/renderer/modes/InlineRenderer.js +166 -0
- package/dist/src/internal/renderer/modes/InlineRenderer.js.map +1 -0
- package/dist/src/internal/renderer/modes/RendererMode.d.ts +42 -0
- package/dist/src/internal/renderer/modes/RendererMode.d.ts.map +1 -0
- package/dist/src/internal/renderer/modes/RendererMode.js +2 -0
- package/dist/src/internal/renderer/modes/RendererMode.js.map +1 -0
- package/dist/src/internal/renderer/modes/StaticContentRenderer.d.ts +25 -0
- package/dist/src/internal/renderer/modes/StaticContentRenderer.d.ts.map +1 -0
- package/dist/src/internal/renderer/modes/StaticContentRenderer.js +49 -0
- package/dist/src/internal/renderer/modes/StaticContentRenderer.js.map +1 -0
- package/dist/src/internal/renderer/modes/index.d.ts +5 -0
- package/dist/src/internal/renderer/modes/index.d.ts.map +1 -0
- package/dist/src/internal/renderer/modes/index.js +4 -0
- package/dist/src/internal/renderer/modes/index.js.map +1 -0
- package/dist/src/internal/renderer/terminal/KeyboardCapabilityProbe.d.ts +13 -0
- package/dist/src/internal/renderer/terminal/KeyboardCapabilityProbe.d.ts.map +1 -0
- package/dist/src/internal/renderer/terminal/KeyboardCapabilityProbe.js +75 -0
- package/dist/src/internal/renderer/terminal/KeyboardCapabilityProbe.js.map +1 -0
- package/dist/src/internal/renderer/terminal/TerminalSetup.d.ts +29 -0
- package/dist/src/internal/renderer/terminal/TerminalSetup.d.ts.map +1 -0
- package/dist/src/internal/renderer/terminal/TerminalSetup.js +82 -0
- package/dist/src/internal/renderer/terminal/TerminalSetup.js.map +1 -0
- package/dist/src/internal/renderer/terminal/index.d.ts +3 -0
- package/dist/src/internal/renderer/terminal/index.d.ts.map +1 -0
- package/dist/src/internal/renderer/terminal/index.js +3 -0
- package/dist/src/internal/renderer/terminal/index.js.map +1 -0
- package/dist/src/internal/renderer/types.d.ts +122 -0
- package/dist/src/internal/renderer/types.d.ts.map +1 -0
- package/dist/src/internal/renderer/types.js +2 -0
- package/dist/src/internal/renderer/types.js.map +1 -0
- package/dist/src/motion/hooks.d.ts +1 -1
- package/dist/src/motion/hooks.js +1 -1
- package/dist/src/reconciler/host-config.js +2 -2
- package/dist/src/reconciler/host-config.js.map +1 -1
- package/dist/src/reconciler/types.d.ts +5 -1
- package/dist/src/reconciler/types.d.ts.map +1 -1
- package/dist/src/renderer-context.d.ts +1 -8
- package/dist/src/renderer-context.d.ts.map +1 -1
- package/dist/src/renderer-context.js +1 -21
- package/dist/src/renderer-context.js.map +1 -1
- package/dist/src/renderer-types.d.ts +1 -115
- package/dist/src/renderer-types.d.ts.map +1 -1
- package/dist/src/renderer.d.ts +1 -31
- package/dist/src/renderer.d.ts.map +1 -1
- package/dist/src/renderer.js +1 -495
- package/dist/src/renderer.js.map +1 -1
- package/dist/src/test/render-tui.d.ts +3 -3
- package/dist/src/test/render-tui.d.ts.map +1 -1
- package/dist/src/test/render-tui.js +16 -9
- package/dist/src/test/render-tui.js.map +1 -1
- package/dist/src/utils/alignment.d.ts +1 -1
- package/dist/src/utils/alignment.d.ts.map +1 -1
- package/dist/src/utils/alignment.js +0 -2
- package/dist/src/utils/alignment.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 +2 -0
- package/dist/src/utils/border.js.map +1 -1
- package/dist/src/utils/console-helpers.d.ts +19 -0
- package/dist/src/utils/console-helpers.d.ts.map +1 -0
- package/dist/src/utils/console-helpers.js +61 -0
- package/dist/src/utils/console-helpers.js.map +1 -0
- package/dist/src/utils/index.d.ts +2 -1
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +2 -1
- package/dist/src/utils/index.js.map +1 -1
- package/dist/src/utils/styles.d.ts +8 -1
- package/dist/src/utils/styles.d.ts.map +1 -1
- package/dist/src/utils/styles.js +10 -8
- package/dist/src/utils/styles.js.map +1 -1
- package/dist/src/utils/text-layout.d.ts +22 -0
- package/dist/src/utils/text-layout.d.ts.map +1 -0
- package/dist/src/utils/text-layout.js +37 -0
- package/dist/src/utils/text-layout.js.map +1 -0
- package/dist/src/utils/text-wrap.d.ts +31 -1
- package/dist/src/utils/text-wrap.d.ts.map +1 -1
- package/dist/src/utils/text-wrap.js +205 -48
- package/dist/src/utils/text-wrap.js.map +1 -1
- package/dist/src/visualize/index.js +1 -1
- package/dist/src/visualize/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/codeblock.tsx +2 -2
- package/src/components/ListView.tsx +21 -23
- package/src/components/Markdown.tsx +3 -3
- package/src/components/MultilineTextInput.tsx +138 -344
- package/src/components/TextInput.tsx +54 -99
- package/src/components/text-editing.ts +180 -0
- package/src/console/ConsolePopover.tsx +124 -107
- package/src/debug/DebugOverlay.ts +15 -74
- package/src/debug/DiagnosticsPanel.tsx +1 -1
- package/src/dev.tsx +5 -458
- package/src/hooks/use-scroll.ts +85 -145
- package/src/hosts/base.ts +86 -3
- package/src/hosts/box.ts +37 -2
- package/src/hosts/canvas.ts +128 -42
- package/src/hosts/codeblock.ts +48 -35
- package/src/hosts/flex-container.ts +25 -6
- package/src/hosts/index.ts +11 -2
- package/src/hosts/layout-helpers.ts +20 -0
- package/src/hosts/leaf.ts +36 -0
- package/src/hosts/overlay-item.ts +8 -2
- package/src/hosts/overlay.ts +13 -11
- package/src/hosts/scroll.ts +228 -106
- package/src/hosts/single-child.ts +2 -0
- package/src/hosts/spacer.ts +8 -3
- package/src/hosts/text.ts +126 -132
- package/src/hosts/vstack.ts +1 -1
- package/src/hosts/zstack.ts +14 -9
- package/src/index.ts +2 -2
- package/src/internal/dev/hmr.ts +101 -0
- package/src/internal/dev/runtime.ts +170 -0
- package/src/internal/dev/ui.tsx +87 -0
- package/src/internal/renderer/context.ts +27 -0
- package/src/{renderer → internal/renderer}/core/FrameBuilder.ts +2 -2
- package/src/internal/renderer/index.ts +689 -0
- package/src/{renderer → internal/renderer}/input/InputProcessor.ts +10 -1
- package/src/{renderer → internal/renderer}/lifecycle/EventBus.ts +9 -1
- package/src/internal/renderer/lifecycle/ProcessLifecycle.ts +125 -0
- package/src/internal/renderer/lifecycle/index.ts +3 -0
- package/src/{renderer → internal/renderer}/modes/InlineRenderer.ts +5 -2
- package/src/{renderer → internal/renderer}/modes/RendererMode.ts +1 -1
- package/src/{renderer → internal/renderer}/modes/StaticContentRenderer.ts +5 -2
- package/src/internal/renderer/terminal/KeyboardCapabilityProbe.ts +91 -0
- package/src/{renderer/lifecycle → internal/renderer/terminal}/TerminalSetup.ts +4 -22
- package/src/internal/renderer/terminal/index.ts +2 -0
- package/src/internal/renderer/types.ts +129 -0
- package/src/motion/hooks.ts +1 -1
- package/src/reconciler/host-config.ts +2 -2
- package/src/reconciler/types.ts +7 -1
- package/src/renderer-context.ts +1 -27
- package/src/renderer-types.ts +10 -123
- package/src/renderer.ts +1 -619
- package/src/test/render-tui.ts +16 -10
- package/src/utils/alignment.ts +1 -3
- package/src/utils/border.ts +11 -1
- package/src/utils/console-helpers.ts +86 -0
- package/src/utils/index.ts +15 -1
- package/src/utils/styles.ts +16 -4
- package/src/utils/text-layout.ts +65 -0
- package/src/utils/text-wrap.ts +261 -48
- package/src/visualize/index.tsx +1 -1
- package/src/renderer/lifecycle/ResizeManager.ts +0 -65
- package/src/renderer/lifecycle/index.ts +0 -4
- /package/src/{renderer → internal/renderer}/core/RendererState.ts +0 -0
- /package/src/{renderer → internal/renderer}/core/index.ts +0 -0
- /package/src/{renderer → internal/renderer}/input/index.ts +0 -0
- /package/src/{renderer → internal/renderer}/lifecycle/RenderCache.ts +0 -0
- /package/src/{renderer → internal/renderer}/modes/FullscreenRenderer.ts +0 -0
- /package/src/{renderer → internal/renderer}/modes/index.ts +0 -0
package/src/hosts/canvas.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import type { CellBuffer, Color, Palette } from "@effect-tui/core"
|
|
2
|
-
import { Colors } from "@effect-tui/core"
|
|
2
|
+
import { Colors, displayWidth } from "@effect-tui/core"
|
|
3
3
|
import type { CommonProps, HostContext, Size } from "../reconciler/types.js"
|
|
4
|
+
import * as Prof from "../profiler.js"
|
|
4
5
|
import {
|
|
5
6
|
type BorderKind,
|
|
6
7
|
borderChars,
|
|
7
8
|
drawBorder,
|
|
9
|
+
fillRectWithInheritedBg,
|
|
8
10
|
resolveBgStyle,
|
|
9
|
-
resolveInheritedBgStyle,
|
|
10
11
|
styleIdFromProps,
|
|
11
12
|
toColorValue,
|
|
12
13
|
} from "../utils/index.js"
|
|
13
|
-
import {
|
|
14
|
+
import { LeafHost } from "./leaf.js"
|
|
14
15
|
|
|
15
16
|
export type { BorderKind }
|
|
16
17
|
|
|
@@ -20,6 +21,9 @@ export interface DrawContext {
|
|
|
20
21
|
/** Canvas height in cells */
|
|
21
22
|
height: number
|
|
22
23
|
|
|
24
|
+
/** Resolve a style id for reuse across many draw calls */
|
|
25
|
+
style(opts?: { fg?: Color; bg?: Color; bold?: boolean; italic?: boolean; underline?: boolean; inverse?: boolean }): number
|
|
26
|
+
|
|
23
27
|
/** Draw text at position */
|
|
24
28
|
text(
|
|
25
29
|
x: number,
|
|
@@ -29,7 +33,7 @@ export interface DrawContext {
|
|
|
29
33
|
): void
|
|
30
34
|
|
|
31
35
|
/** Fill rectangle with character */
|
|
32
|
-
|
|
36
|
+
fillRect(
|
|
33
37
|
x: number,
|
|
34
38
|
y: number,
|
|
35
39
|
w: number,
|
|
@@ -54,6 +58,20 @@ export interface DrawContext {
|
|
|
54
58
|
|
|
55
59
|
/** Clear entire canvas */
|
|
56
60
|
clear(): void
|
|
61
|
+
|
|
62
|
+
/** Draw a single cell with a codepoint */
|
|
63
|
+
cell(x: number, y: number, cp: number, style?: number, width?: number): void
|
|
64
|
+
|
|
65
|
+
/** Draw many single-cell codepoints efficiently */
|
|
66
|
+
cells(cells: Array<CanvasCell>): void
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface CanvasCell {
|
|
70
|
+
x: number
|
|
71
|
+
y: number
|
|
72
|
+
cp: number
|
|
73
|
+
style?: number
|
|
74
|
+
width?: number
|
|
57
75
|
}
|
|
58
76
|
|
|
59
77
|
export interface CanvasProps extends CommonProps {
|
|
@@ -67,7 +85,7 @@ export interface CanvasProps extends CommonProps {
|
|
|
67
85
|
inheritBg?: boolean
|
|
68
86
|
}
|
|
69
87
|
|
|
70
|
-
export class CanvasHost extends
|
|
88
|
+
export class CanvasHost extends LeafHost {
|
|
71
89
|
draw: CanvasProps["draw"] = () => {}
|
|
72
90
|
fixedWidth?: number
|
|
73
91
|
fixedHeight?: number
|
|
@@ -78,7 +96,7 @@ export class CanvasHost extends BaseHost {
|
|
|
78
96
|
this.updateProps(props as unknown as Record<string, unknown>)
|
|
79
97
|
}
|
|
80
98
|
|
|
81
|
-
|
|
99
|
+
protected measureSelf(maxW: number, maxH: number): Size {
|
|
82
100
|
const constrained = this.constrainProposal(maxW, maxH)
|
|
83
101
|
const size = {
|
|
84
102
|
w: this.fixedWidth ?? constrained.w,
|
|
@@ -91,26 +109,36 @@ export class CanvasHost extends BaseHost {
|
|
|
91
109
|
if (!this.rect) return
|
|
92
110
|
const { x: ox, y: oy, w, h } = this.rect
|
|
93
111
|
|
|
94
|
-
// Get inherited background for use in drawing functions
|
|
95
|
-
const { value: inheritedBgValue, styleId: inheritedBgStyleId } = this.inheritBg
|
|
96
|
-
? resolveInheritedBgStyle(palette, undefined, this.parent)
|
|
97
|
-
: { value: undefined, styleId: 0 }
|
|
98
|
-
|
|
99
112
|
// Pre-fill with inherited background if requested
|
|
100
|
-
|
|
101
|
-
buffer
|
|
102
|
-
|
|
113
|
+
const inheritedBgValue = this.inheritBg
|
|
114
|
+
? fillRectWithInheritedBg(buffer, palette, { x: ox, y: oy, w, h }, undefined, this.parent, {
|
|
115
|
+
skipWhenUndefined: true,
|
|
116
|
+
}).value
|
|
117
|
+
: undefined
|
|
103
118
|
|
|
104
119
|
// Create draw context
|
|
105
120
|
const ctx: DrawContext = {
|
|
106
121
|
width: w,
|
|
107
122
|
height: h,
|
|
108
123
|
|
|
124
|
+
style: (opts) => {
|
|
125
|
+
const effectiveBg = opts?.bg ?? (this.inheritBg ? inheritedBgValue : undefined)
|
|
126
|
+
return styleIdFromProps(palette, {
|
|
127
|
+
fg: opts?.fg,
|
|
128
|
+
bg: effectiveBg,
|
|
129
|
+
bold: opts?.bold,
|
|
130
|
+
italic: opts?.italic,
|
|
131
|
+
underline: opts?.underline,
|
|
132
|
+
inverse: opts?.inverse,
|
|
133
|
+
})
|
|
134
|
+
},
|
|
135
|
+
|
|
109
136
|
text: (x, y, str, opts) => {
|
|
110
137
|
const px = Math.round(ox + x)
|
|
111
138
|
const py = Math.round(oy + y)
|
|
112
139
|
// Use inherited bg when inheritBg is enabled and no explicit bg provided
|
|
113
140
|
const effectiveBg = opts?.bg ?? (this.inheritBg ? inheritedBgValue : undefined)
|
|
141
|
+
const styleT = Prof.startPhase()
|
|
114
142
|
const style = styleIdFromProps(palette, {
|
|
115
143
|
fg: opts?.fg,
|
|
116
144
|
bg: effectiveBg,
|
|
@@ -119,20 +147,40 @@ export class CanvasHost extends BaseHost {
|
|
|
119
147
|
underline: opts?.underline,
|
|
120
148
|
inverse: opts?.inverse,
|
|
121
149
|
})
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
150
|
+
Prof.endPhase("canvas.text.style", styleT)
|
|
151
|
+
const widthT = Prof.startPhase()
|
|
152
|
+
let textWidth = 0
|
|
153
|
+
let asciiCp: number | null = null
|
|
154
|
+
if (str.length === 1) {
|
|
155
|
+
const code = str.charCodeAt(0)
|
|
156
|
+
if (code >= 0x20 && code <= 0x7e) {
|
|
157
|
+
textWidth = 1
|
|
158
|
+
asciiCp = code
|
|
159
|
+
} else {
|
|
160
|
+
textWidth = displayWidth(str)
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
textWidth = displayWidth(str)
|
|
164
|
+
}
|
|
165
|
+
Prof.endPhase("canvas.text.width", widthT)
|
|
166
|
+
if (textWidth > 0) {
|
|
167
|
+
const drawT = Prof.startPhase()
|
|
168
|
+
if (asciiCp !== null) {
|
|
169
|
+
buffer.drawCP(px, py, asciiCp, style, 1)
|
|
170
|
+
} else {
|
|
171
|
+
buffer.drawText(px, py, str, style, textWidth)
|
|
172
|
+
}
|
|
173
|
+
Prof.endPhase("canvas.text.draw", drawT)
|
|
127
174
|
}
|
|
128
175
|
},
|
|
129
176
|
|
|
130
|
-
|
|
177
|
+
fillRect: (x, y, fw, fh, char = " ", opts) => {
|
|
131
178
|
const px = Math.round(ox + x)
|
|
132
179
|
const py = Math.round(oy + y)
|
|
133
|
-
const cp = char.codePointAt(0)!
|
|
180
|
+
const cp = char.length > 0 ? char.codePointAt(0)! : " ".codePointAt(0)!
|
|
134
181
|
// Use inherited bg when inheritBg is enabled and no explicit bg provided
|
|
135
182
|
const effectiveBg = opts?.bg ?? (this.inheritBg ? inheritedBgValue : undefined)
|
|
183
|
+
const styleT = Prof.startPhase()
|
|
136
184
|
const style = styleIdFromProps(palette, {
|
|
137
185
|
fg: opts?.fg,
|
|
138
186
|
bg: effectiveBg,
|
|
@@ -141,65 +189,103 @@ export class CanvasHost extends BaseHost {
|
|
|
141
189
|
underline: opts?.underline,
|
|
142
190
|
inverse: opts?.inverse,
|
|
143
191
|
})
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
192
|
+
Prof.endPhase("canvas.fillRect.style", styleT)
|
|
193
|
+
const fillW = Math.ceil(fw)
|
|
194
|
+
const fillH = Math.ceil(fh)
|
|
195
|
+
const drawT = Prof.startPhase()
|
|
196
|
+
buffer.fillRect(px, py, fillW, fillH, cp, style)
|
|
197
|
+
Prof.endPhase("canvas.fillRect.draw", drawT)
|
|
151
198
|
},
|
|
152
199
|
|
|
153
200
|
box: (x, y, bw, bh, opts) => {
|
|
154
201
|
const px = Math.round(ox + x)
|
|
155
202
|
const py = Math.round(oy + y)
|
|
203
|
+
const boxW = Math.ceil(bw)
|
|
204
|
+
const boxH = Math.ceil(bh)
|
|
156
205
|
const border = opts?.border ?? "none"
|
|
206
|
+
const bgStyleT = Prof.startPhase()
|
|
157
207
|
const { value: bgValue, styleId: bgStyleId } = resolveBgStyle(palette, opts?.bg)
|
|
208
|
+
Prof.endPhase("canvas.box.bg.style", bgStyleT)
|
|
158
209
|
|
|
159
210
|
// Fill background (with clipping)
|
|
160
211
|
if (bgValue !== undefined) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const xx = px + col
|
|
165
|
-
buffer.drawCP(xx, yy, " ".codePointAt(0)!, bgStyleId)
|
|
166
|
-
}
|
|
167
|
-
}
|
|
212
|
+
const bgDrawT = Prof.startPhase()
|
|
213
|
+
buffer.fillRect(px, py, boxW, boxH, " ".codePointAt(0)!, bgStyleId)
|
|
214
|
+
Prof.endPhase("canvas.box.bg.draw", bgDrawT)
|
|
168
215
|
}
|
|
169
216
|
|
|
170
217
|
// Draw border (with clipping)
|
|
171
|
-
if (border !== "none" &&
|
|
218
|
+
if (border !== "none" && boxW >= 2 && boxH >= 2) {
|
|
219
|
+
const borderStyleT = Prof.startPhase()
|
|
172
220
|
const chars = borderChars(border)
|
|
173
221
|
const borderFg = toColorValue(opts?.borderColor) ?? toColorValue(opts?.fg) ?? Colors.ansi.gray(8)
|
|
174
222
|
const borderStyle = palette.id({ fg: borderFg })
|
|
175
|
-
|
|
223
|
+
Prof.endPhase("canvas.box.border.style", borderStyleT)
|
|
224
|
+
const borderDrawT = Prof.startPhase()
|
|
225
|
+
drawBorder(buffer, px, py, boxW, boxH, chars, borderStyle, { ox, oy, w, h })
|
|
226
|
+
Prof.endPhase("canvas.box.border.draw", borderDrawT)
|
|
176
227
|
}
|
|
177
228
|
},
|
|
178
229
|
|
|
179
230
|
clear: () => {
|
|
231
|
+
const clearT = Prof.startPhase()
|
|
180
232
|
const style = palette.id({})
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
233
|
+
buffer.fillRect(ox, oy, w, h, " ".codePointAt(0)!, style)
|
|
234
|
+
Prof.endPhase("canvas.clear", clearT)
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
cell: (x, y, cp, style = 0, width) => {
|
|
238
|
+
const px = Math.round(ox + x)
|
|
239
|
+
const py = Math.round(oy + y)
|
|
240
|
+
const drawT = Prof.startPhase()
|
|
241
|
+
buffer.drawCP(px, py, cp, style, width)
|
|
242
|
+
Prof.endPhase("canvas.cell.draw", drawT)
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
cells: (cells) => {
|
|
246
|
+
const drawT = Prof.startPhase()
|
|
247
|
+
const baseX = ox
|
|
248
|
+
const baseY = oy
|
|
249
|
+
for (const cell of cells) {
|
|
250
|
+
const px = Math.round(baseX + cell.x)
|
|
251
|
+
const py = Math.round(baseY + cell.y)
|
|
252
|
+
buffer.drawCP(px, py, cell.cp, cell.style ?? 0, cell.width)
|
|
185
253
|
}
|
|
254
|
+
Prof.endPhase("canvas.cells.draw", drawT)
|
|
186
255
|
},
|
|
187
256
|
}
|
|
188
257
|
|
|
189
258
|
buffer.withClip(ox, oy, w, h, () => {
|
|
190
259
|
// Call user's draw function within the canvas clip region
|
|
260
|
+
const drawT = Prof.startPhase()
|
|
191
261
|
this.draw(ctx)
|
|
262
|
+
Prof.endPhase("canvas.draw", drawT)
|
|
192
263
|
})
|
|
193
264
|
}
|
|
194
265
|
|
|
195
266
|
override updateProps(props: Record<string, unknown>): void {
|
|
196
267
|
super.updateProps(props)
|
|
268
|
+
const prevDraw = this.draw
|
|
269
|
+
const prevWidth = this.fixedWidth
|
|
270
|
+
const prevHeight = this.fixedHeight
|
|
271
|
+
const prevInheritBg = this.inheritBg
|
|
272
|
+
|
|
197
273
|
if (props.draw !== undefined) {
|
|
198
274
|
this.draw = props.draw as CanvasProps["draw"]
|
|
199
|
-
this.ctx.requestRender() // trigger repaint when draw function changes
|
|
200
275
|
}
|
|
201
276
|
if (props.width !== undefined) this.fixedWidth = props.width as number
|
|
202
277
|
if (props.height !== undefined) this.fixedHeight = props.height as number
|
|
203
278
|
if (props.inheritBg !== undefined) this.inheritBg = props.inheritBg as boolean
|
|
279
|
+
|
|
280
|
+
const layoutChanged = prevWidth !== this.fixedWidth || prevHeight !== this.fixedHeight
|
|
281
|
+
if (layoutChanged) {
|
|
282
|
+
this.invalidateLayout()
|
|
283
|
+
return
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const renderChanged = prevDraw !== this.draw || prevInheritBg !== this.inheritBg
|
|
287
|
+
if (renderChanged) {
|
|
288
|
+
this.invalidateRender()
|
|
289
|
+
}
|
|
204
290
|
}
|
|
205
291
|
}
|
package/src/hosts/codeblock.ts
CHANGED
|
@@ -1,33 +1,35 @@
|
|
|
1
1
|
import { type CellBuffer, type Color, Colors, displayWidth, type Palette } from "@effect-tui/core"
|
|
2
2
|
import type { HighlightLine } from "../highlight.js"
|
|
3
3
|
import type { CommonProps, HostContext, Size } from "../reconciler/types.js"
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
type Padding,
|
|
6
|
+
type PaddingInput,
|
|
7
|
+
resolveBgStyle,
|
|
8
|
+
resolvePadding,
|
|
9
|
+
spansDisplayWidth,
|
|
10
|
+
styleIdFromProps,
|
|
11
|
+
} from "../utils/index.js"
|
|
12
|
+
import { LeafHost } from "./leaf.js"
|
|
6
13
|
|
|
7
14
|
export interface CodeBlockProps extends CommonProps {
|
|
8
15
|
lines: HighlightLine[]
|
|
9
16
|
lineNumbers?: boolean
|
|
10
17
|
padding?: PaddingInput
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
bg?: Color
|
|
19
|
+
lineNumberFg?: Color
|
|
20
|
+
lineNumberBg?: Color
|
|
14
21
|
}
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
return line.reduce((w, token) => w + displayWidth(token.text), 0)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export class CodeBlockHost extends BaseHost {
|
|
23
|
+
export class CodeBlockHost extends LeafHost {
|
|
21
24
|
lines: HighlightLine[] = [[]]
|
|
22
25
|
lineNumbers = false
|
|
23
26
|
padding: Padding = { top: 0, right: 0, bottom: 0, left: 0 }
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
bg?: Color
|
|
28
|
+
lineNumberFg?: Color
|
|
29
|
+
lineNumberBg?: Color
|
|
27
30
|
|
|
28
31
|
private cachedLineWidths: number[] = []
|
|
29
32
|
private gutterWidth = 0
|
|
30
|
-
private prepared = false
|
|
31
33
|
|
|
32
34
|
constructor(props: CodeBlockProps, ctx: HostContext) {
|
|
33
35
|
super("codeblock", props, ctx)
|
|
@@ -51,21 +53,15 @@ export class CodeBlockHost extends BaseHost {
|
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
private prepareMetrics(): void {
|
|
54
|
-
this.cachedLineWidths = this.lines.map((line) =>
|
|
56
|
+
this.cachedLineWidths = this.lines.map((line) => spansDisplayWidth(line))
|
|
55
57
|
this.gutterWidth = this.computeGutterWidth()
|
|
56
|
-
this.prepared = true
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
if (this.prepared) return
|
|
60
|
+
protected override prepareSelf(_layoutDirty: boolean, _renderDirty: boolean): void {
|
|
61
61
|
this.prepareMetrics()
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
protected
|
|
65
|
-
this.ensurePrepared()
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
measure(maxW: number, maxH: number): Size {
|
|
64
|
+
protected measureSelf(maxW: number, maxH: number): Size {
|
|
69
65
|
const constrained = this.constrainProposal(maxW, maxH)
|
|
70
66
|
this.ensurePrepared()
|
|
71
67
|
|
|
@@ -89,7 +85,7 @@ export class CodeBlockHost extends BaseHost {
|
|
|
89
85
|
const startX = x + this.padding.left + this.gutterWidth
|
|
90
86
|
const startY = y + this.padding.top
|
|
91
87
|
|
|
92
|
-
const { value: bgValue, styleId: bgStyleId } = resolveBgStyle(palette, this.
|
|
88
|
+
const { value: bgValue, styleId: bgStyleId } = resolveBgStyle(palette, this.bg)
|
|
93
89
|
if (bgValue !== undefined && w > 0 && h > 0) {
|
|
94
90
|
buffer.fillRect(x, y, w, h, " ".codePointAt(0)!, bgStyleId)
|
|
95
91
|
}
|
|
@@ -100,8 +96,8 @@ export class CodeBlockHost extends BaseHost {
|
|
|
100
96
|
|
|
101
97
|
if (this.lineNumbers) {
|
|
102
98
|
const gutterStyle = styleIdFromProps(palette, {
|
|
103
|
-
fg: this.
|
|
104
|
-
bg: this.
|
|
99
|
+
fg: this.lineNumberFg ?? Colors.ansi.gray(11),
|
|
100
|
+
bg: this.lineNumberBg ?? this.bg,
|
|
105
101
|
})
|
|
106
102
|
const digits = String(i + 1).padStart(this.gutterWidth - 1, " ")
|
|
107
103
|
buffer.drawText(x + this.padding.left, lineY, `${digits} `, gutterStyle, this.gutterWidth)
|
|
@@ -116,7 +112,7 @@ export class CodeBlockHost extends BaseHost {
|
|
|
116
112
|
const style = token.style ?? {}
|
|
117
113
|
const styleId = styleIdFromProps(palette, {
|
|
118
114
|
fg: style.fg,
|
|
119
|
-
bg: style.bg ?? this.
|
|
115
|
+
bg: style.bg ?? this.bg,
|
|
120
116
|
bold: style.bold,
|
|
121
117
|
italic: style.italic,
|
|
122
118
|
underline: style.underline,
|
|
@@ -131,19 +127,36 @@ export class CodeBlockHost extends BaseHost {
|
|
|
131
127
|
|
|
132
128
|
override updateProps(props: Record<string, unknown>): void {
|
|
133
129
|
super.updateProps(props)
|
|
134
|
-
let
|
|
130
|
+
let layoutChanged = false
|
|
131
|
+
let renderChanged = false
|
|
135
132
|
if (props.lines !== undefined) {
|
|
136
133
|
this.lines = props.lines as HighlightLine[]
|
|
137
|
-
|
|
134
|
+
layoutChanged = true
|
|
138
135
|
}
|
|
139
136
|
if (props.lineNumbers !== undefined) {
|
|
140
137
|
this.lineNumbers = !!props.lineNumbers
|
|
141
|
-
|
|
138
|
+
layoutChanged = true
|
|
139
|
+
}
|
|
140
|
+
if (props.padding !== undefined) {
|
|
141
|
+
this.padding = resolvePadding(props.padding as CodeBlockProps["padding"])
|
|
142
|
+
layoutChanged = true
|
|
143
|
+
}
|
|
144
|
+
if (props.bg !== undefined) {
|
|
145
|
+
this.bg = props.bg as Color
|
|
146
|
+
renderChanged = true
|
|
147
|
+
}
|
|
148
|
+
if (props.lineNumberFg !== undefined) {
|
|
149
|
+
this.lineNumberFg = props.lineNumberFg as Color
|
|
150
|
+
renderChanged = true
|
|
151
|
+
}
|
|
152
|
+
if (props.lineNumberBg !== undefined) {
|
|
153
|
+
this.lineNumberBg = props.lineNumberBg as Color
|
|
154
|
+
renderChanged = true
|
|
155
|
+
}
|
|
156
|
+
if (layoutChanged) {
|
|
157
|
+
this.invalidateLayout()
|
|
158
|
+
} else if (renderChanged) {
|
|
159
|
+
this.invalidateRender()
|
|
142
160
|
}
|
|
143
|
-
if (props.padding !== undefined) this.padding = resolvePadding(props.padding as CodeBlockProps["padding"])
|
|
144
|
-
if (props.background !== undefined) this.background = props.background as Color
|
|
145
|
-
if (props.lineNumberColor !== undefined) this.lineNumberColor = props.lineNumberColor as Color
|
|
146
|
-
if (props.lineNumberBackground !== undefined) this.lineNumberBackground = props.lineNumberBackground as Color
|
|
147
|
-
if (invalidate) this.prepared = false
|
|
148
161
|
}
|
|
149
162
|
}
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import { BaseHost } from "./base.js"
|
|
16
16
|
|
|
17
17
|
export type CrossAlignment<A extends FlexAxis> = A extends "vertical"
|
|
18
|
-
? "
|
|
18
|
+
? "left" | "center" | "right"
|
|
19
19
|
: "top" | "center" | "bottom"
|
|
20
20
|
|
|
21
21
|
export interface FlexContainerProps<A extends FlexAxis> extends CommonProps {
|
|
@@ -30,7 +30,7 @@ export interface FlexContainerProps<A extends FlexAxis> extends CommonProps {
|
|
|
30
30
|
function toFlexAlignment<A extends FlexAxis>(axis: A, alignment: CrossAlignment<A>): FlexAlignment {
|
|
31
31
|
if (alignment === "center") return "center"
|
|
32
32
|
if (axis === "vertical") {
|
|
33
|
-
return alignment === "
|
|
33
|
+
return alignment === "left" ? "start" : "end"
|
|
34
34
|
} else {
|
|
35
35
|
return alignment === "top" ? "start" : "end"
|
|
36
36
|
}
|
|
@@ -79,7 +79,7 @@ export class FlexContainerHost<A extends FlexAxis> extends BaseHost {
|
|
|
79
79
|
* </vstack>
|
|
80
80
|
* ```
|
|
81
81
|
*/
|
|
82
|
-
|
|
82
|
+
protected measureSelf(maxW: number, maxH: number): Size {
|
|
83
83
|
// Apply frame constraints to what we propose to children
|
|
84
84
|
const constrained = this.constrainProposal(maxW, maxH)
|
|
85
85
|
const insetX = this.padding.left + this.padding.right
|
|
@@ -102,9 +102,9 @@ export class FlexContainerHost<A extends FlexAxis> extends BaseHost {
|
|
|
102
102
|
return this.constrainResult(paddedSize)
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
override
|
|
105
|
+
protected override layoutSelf(rect: Rect): void {
|
|
106
106
|
const layoutRect = this.layoutWithConstraints(rect)
|
|
107
|
-
const stretchCross = this.axis === "vertical" ? this.alignment === "
|
|
107
|
+
const stretchCross = this.axis === "vertical" ? this.alignment === "left" : this.alignment === "top"
|
|
108
108
|
const insetX = this.padding.left + this.padding.right
|
|
109
109
|
const insetY = this.padding.top + this.padding.bottom
|
|
110
110
|
const innerRect: Rect = {
|
|
@@ -142,12 +142,31 @@ export class FlexContainerHost<A extends FlexAxis> extends BaseHost {
|
|
|
142
142
|
|
|
143
143
|
override updateProps(props: Record<string, unknown>): void {
|
|
144
144
|
super.updateProps(props)
|
|
145
|
+
const prevSpacing = this.spacing
|
|
146
|
+
const prevAlignment = this.alignment
|
|
147
|
+
const prevPadding = this.padding
|
|
148
|
+
const prevBg = this.bg
|
|
149
|
+
|
|
145
150
|
this.spacing = (props.spacing as number | undefined) ?? 0
|
|
146
151
|
// Reset to axis-specific default when undefined
|
|
147
152
|
this.alignment =
|
|
148
153
|
(props.alignment as CrossAlignment<A> | undefined) ??
|
|
149
|
-
((this.axis === "vertical" ? "
|
|
154
|
+
((this.axis === "vertical" ? "left" : "top") as CrossAlignment<A>)
|
|
150
155
|
this.padding = resolvePadding(props.padding as FlexContainerProps<A>["padding"])
|
|
151
156
|
this.bg = props.bg as Color | undefined
|
|
157
|
+
|
|
158
|
+
const paddingChanged =
|
|
159
|
+
prevPadding.top !== this.padding.top ||
|
|
160
|
+
prevPadding.right !== this.padding.right ||
|
|
161
|
+
prevPadding.bottom !== this.padding.bottom ||
|
|
162
|
+
prevPadding.left !== this.padding.left
|
|
163
|
+
|
|
164
|
+
const layoutChanged = prevSpacing !== this.spacing || prevAlignment !== this.alignment || paddingChanged
|
|
165
|
+
|
|
166
|
+
if (layoutChanged) {
|
|
167
|
+
this.invalidateLayout()
|
|
168
|
+
} else if (prevBg !== this.bg) {
|
|
169
|
+
this.invalidateRender()
|
|
170
|
+
}
|
|
152
171
|
}
|
|
153
172
|
}
|
package/src/hosts/index.ts
CHANGED
|
@@ -14,13 +14,22 @@ import { ZStackHost } from "./zstack.js"
|
|
|
14
14
|
|
|
15
15
|
export { BaseHost } from "./base.js"
|
|
16
16
|
export { BoxHost, type BoxProps } from "./box.js"
|
|
17
|
-
export { CanvasHost, type CanvasProps, type DrawContext } from "./canvas.js"
|
|
17
|
+
export { CanvasHost, type CanvasCell, type CanvasProps, type DrawContext } from "./canvas.js"
|
|
18
18
|
export { CodeBlockHost, type CodeBlockProps } from "./codeblock.js"
|
|
19
19
|
export { HStackHost, type HStackProps } from "./hstack.js"
|
|
20
20
|
export { OverlayHost, type OverlayProps } from "./overlay.js"
|
|
21
21
|
export { OverlayItemHost, type OverlayItemProps } from "./overlay-item.js"
|
|
22
|
-
export {
|
|
22
|
+
export {
|
|
23
|
+
ScrollHost,
|
|
24
|
+
type ScrollAlign,
|
|
25
|
+
type ScrollAlignX,
|
|
26
|
+
type ScrollAlignY,
|
|
27
|
+
type ScrollAxis,
|
|
28
|
+
type ScrollLayoutChange,
|
|
29
|
+
type ScrollProps,
|
|
30
|
+
} from "./scroll.js"
|
|
23
31
|
export { SingleChildHost } from "./single-child.js"
|
|
32
|
+
export { LeafHost } from "./leaf.js"
|
|
24
33
|
export { SpacerHost, type SpacerProps } from "./spacer.js"
|
|
25
34
|
export {
|
|
26
35
|
RawTextHost,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Rect, Size } from "../reconciler/types.js"
|
|
2
|
+
import type { HostInstance } from "../reconciler/types.js"
|
|
3
|
+
import { alignedChildRect, type HAlign, type VAlign } from "../utils/index.js"
|
|
4
|
+
|
|
5
|
+
type Alignment = { h?: HAlign; v?: VAlign }
|
|
6
|
+
|
|
7
|
+
export function layoutAlignedChildren(
|
|
8
|
+
layoutRect: Rect,
|
|
9
|
+
children: HostInstance[],
|
|
10
|
+
cachedSizes: Size[],
|
|
11
|
+
alignmentForChild: (child: HostInstance, index: number) => Alignment,
|
|
12
|
+
startIndex = 0,
|
|
13
|
+
): void {
|
|
14
|
+
for (let i = startIndex; i < children.length; i++) {
|
|
15
|
+
const child = children[i]
|
|
16
|
+
const size = cachedSizes[i] ?? child.measure(layoutRect.w, layoutRect.h)
|
|
17
|
+
const alignment = alignmentForChild(child, i)
|
|
18
|
+
child.layout(alignedChildRect(layoutRect, size, alignment.h ?? "center", alignment.v ?? "center"))
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { HostInstance } from "../reconciler/types.js"
|
|
2
|
+
import { BaseHost } from "./base.js"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Base host that rejects children.
|
|
6
|
+
* Any attempted child insertion is ignored with a warning (once).
|
|
7
|
+
*/
|
|
8
|
+
export abstract class LeafHost extends BaseHost {
|
|
9
|
+
private warned = false
|
|
10
|
+
|
|
11
|
+
override appendChild(child: HostInstance): void {
|
|
12
|
+
this.rejectChild(child)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
override insertBefore(child: HostInstance, _before: HostInstance): void {
|
|
16
|
+
this.rejectChild(child)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override removeChild(child: HostInstance): void {
|
|
20
|
+
const idx = this.children.indexOf(child)
|
|
21
|
+
if (idx >= 0) {
|
|
22
|
+
this.children.splice(idx, 1)
|
|
23
|
+
}
|
|
24
|
+
if (child.parent === this) {
|
|
25
|
+
child.parent = null
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private rejectChild(child: HostInstance): void {
|
|
30
|
+
if (!this.warned) {
|
|
31
|
+
console.warn(`[effect-tui] <${this.type}> does not support children; child ignored.`)
|
|
32
|
+
this.warned = true
|
|
33
|
+
}
|
|
34
|
+
child.parent = null
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -26,7 +26,7 @@ export class OverlayItemHost extends SingleChildHost {
|
|
|
26
26
|
this.updateProps(props as unknown as Record<string, unknown>)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
override
|
|
29
|
+
protected override measureSelf(maxW: number, maxH: number): Size {
|
|
30
30
|
const constrained = this.constrainProposal(maxW, maxH)
|
|
31
31
|
|
|
32
32
|
if (!this.child) {
|
|
@@ -37,7 +37,7 @@ export class OverlayItemHost extends SingleChildHost {
|
|
|
37
37
|
return this.constrainResult(childSize)
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
override
|
|
40
|
+
protected override layoutSelf(rect: Rect): void {
|
|
41
41
|
const layoutRect = this.layoutWithConstraints(rect)
|
|
42
42
|
this.child?.layout(layoutRect)
|
|
43
43
|
}
|
|
@@ -50,8 +50,14 @@ export class OverlayItemHost extends SingleChildHost {
|
|
|
50
50
|
|
|
51
51
|
override updateProps(props: Record<string, unknown>): void {
|
|
52
52
|
super.updateProps(props)
|
|
53
|
+
const prevAlignment = this.alignment
|
|
53
54
|
if (props.alignment !== undefined) {
|
|
54
55
|
this.alignment = props.alignment as { h?: HAlign; v?: VAlign }
|
|
55
56
|
}
|
|
57
|
+
const layoutChanged =
|
|
58
|
+
prevAlignment.h !== this.alignment.h || prevAlignment.v !== this.alignment.v
|
|
59
|
+
if (layoutChanged) {
|
|
60
|
+
this.invalidateLayout()
|
|
61
|
+
}
|
|
56
62
|
}
|
|
57
63
|
}
|
package/src/hosts/overlay.ts
CHANGED
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
|
|
19
19
|
import type { CellBuffer, Palette, Rect, Size } from "@effect-tui/core"
|
|
20
20
|
import type { CommonProps, HostContext } from "../reconciler/types.js"
|
|
21
|
-
import { alignedChildRect } from "../utils/index.js"
|
|
22
21
|
import { BaseHost } from "./base.js"
|
|
22
|
+
import { layoutAlignedChildren } from "./layout-helpers.js"
|
|
23
23
|
import type { OverlayItemHost } from "./overlay-item.js"
|
|
24
24
|
|
|
25
25
|
export interface OverlayProps extends CommonProps {}
|
|
@@ -32,7 +32,7 @@ export class OverlayHost extends BaseHost {
|
|
|
32
32
|
this.updateProps(props as unknown as Record<string, unknown>)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
override
|
|
35
|
+
protected override measureSelf(maxW: number, maxH: number): Size {
|
|
36
36
|
// Apply frame constraints to what we propose to children
|
|
37
37
|
const constrained = this.constrainProposal(maxW, maxH)
|
|
38
38
|
|
|
@@ -56,7 +56,7 @@ export class OverlayHost extends BaseHost {
|
|
|
56
56
|
return this.constrainResult(baseSize)
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
override
|
|
59
|
+
protected override layoutSelf(rect: Rect): void {
|
|
60
60
|
const layoutRect = this.layoutWithConstraints(rect)
|
|
61
61
|
|
|
62
62
|
// Layout base child to fill our rect
|
|
@@ -66,14 +66,16 @@ export class OverlayHost extends BaseHost {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
// Layout overlay children with their alignment
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
69
|
+
layoutAlignedChildren(
|
|
70
|
+
layoutRect,
|
|
71
|
+
this.children,
|
|
72
|
+
this.cachedSizes,
|
|
73
|
+
(child) => {
|
|
74
|
+
// Read alignment from OverlayItemHost (use type check, not instanceof, for bundler compatibility)
|
|
75
|
+
return child.type === "overlayItem" ? (child as OverlayItemHost).alignment : {}
|
|
76
|
+
},
|
|
77
|
+
1,
|
|
78
|
+
)
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
override render(buffer: CellBuffer, palette: Palette): void {
|