@alchemy.run/sigil 0.0.0-alpha.3 → 0.0.0-alpha.5
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 +23 -13
- package/THIRD_PARTY_NOTICES.md +70 -23
- package/dist/Text-D5HUf3Fj.d.ts +452 -0
- package/dist/ansi.d.ts +137 -143
- package/dist/ansi.js +87 -2
- package/dist/capabilities.d.ts +5 -0
- package/dist/capabilities.js +3 -0
- package/dist/cell-_ZVhbfl0.js +44 -0
- package/dist/color-CkbalRqK.js +2 -0
- package/dist/color-policy-BMzMwV7Q.d.ts +22 -0
- package/dist/color-policy-SVj1pYTA.js +560 -0
- package/dist/color-profile-DHhQHY55.js +36 -0
- package/dist/color-profile-u0Nhe9Nv.d.ts +97 -0
- package/dist/color.d.ts +21 -0
- package/dist/color.js +3 -0
- package/dist/cursor-position-D2LAkRG0.d.ts +7 -0
- package/dist/detect-Bh4yGP6w.d.ts +186 -0
- package/dist/detect-BuTXtY6e.js +373 -0
- package/dist/{devtools-BhYGjb7h.js → devtools-DbthxoD1.js} +22 -23
- package/dist/env-YVw64yZS.js +9 -0
- package/dist/escapes-CB_6CWOE.d.ts +72 -0
- package/dist/geometry-BxXOzJgo.d.ts +11 -0
- package/dist/index-Bmc2tRPk.d.ts +21 -0
- package/dist/index.d.ts +235 -754
- package/dist/index.js +1362 -3001
- package/dist/osc-CCH7xDoS.js +71 -0
- package/dist/osc-Cn0fw77g.d.ts +23 -0
- package/dist/paint-C19minOS.d.ts +81 -0
- package/dist/query-vaIeGOkH.d.ts +152 -0
- package/dist/router.d.ts +392 -0
- package/dist/router.js +709 -0
- package/dist/sample-Cqw1bjUL.js +445 -0
- package/dist/screen-BOh__-65.js +324 -0
- package/dist/screen-BReKIheE.d.ts +40 -0
- package/dist/screen.d.ts +5 -0
- package/dist/screen.js +5 -0
- package/dist/semantic-text-style-DIMzC7xt.js +91 -0
- package/dist/serialize-BTkAZgw1.js +79 -0
- package/dist/session-BJmzX2NJ.js +664 -0
- package/dist/sgr-BhwaWAJB.js +246 -0
- package/dist/store-CgrG9K4y.d.ts +72 -0
- package/dist/string-width-CijQwpIk.js +69 -0
- package/dist/strip-BvU4toXG.js +6 -0
- package/dist/terminal.d.ts +118 -0
- package/dist/terminal.js +2 -0
- package/dist/tokenize-AjqbvtiT.js +1242 -0
- package/dist/tokenize-Dx1y_l5H.d.ts +57 -0
- package/dist/truncate-D31fhU6i.js +562 -0
- package/dist/use-focus-C2sciZOo.js +1335 -0
- package/package.json +43 -17
- package/src/ansi/chalk.ts +12 -53
- package/src/ansi/cursor.ts +2 -4
- package/src/ansi/east-asian-width.ts +44 -0
- package/src/ansi/escapes.ts +18 -26
- package/src/ansi/graphemes.ts +8 -0
- package/src/ansi/hyperlink.ts +44 -0
- package/src/ansi/index.ts +14 -14
- package/src/ansi/osc.ts +77 -0
- package/src/ansi/sgr.ts +2 -5
- package/src/ansi/slice.ts +1 -1
- package/src/ansi/string-width.ts +91 -206
- package/src/ansi/strip.ts +13 -33
- package/src/ansi/tokenize.ts +96 -169
- package/src/ansi/truncate.ts +5 -3
- package/src/ansi/wrap.ts +13 -14
- package/src/ansi-tokenizer.ts +1 -1
- package/src/capabilities/color-policy.ts +34 -0
- package/src/capabilities/detect.ts +594 -0
- package/src/capabilities/index.ts +37 -0
- package/src/capabilities/query.ts +657 -0
- package/src/capabilities/store.ts +379 -0
- package/src/color/index.ts +3 -0
- package/src/color/paint.ts +169 -0
- package/src/color/palette.ts +48 -0
- package/src/color/sample.ts +323 -0
- package/src/color.ts +1 -0
- package/src/components/AnsiText.tsx +42 -0
- package/src/components/App.tsx +109 -22
- package/src/components/BackgroundContext.ts +2 -3
- package/src/components/Box.tsx +43 -60
- package/src/components/CursorContext.ts +1 -1
- package/src/components/ErrorBoundary.tsx +1 -1
- package/src/components/ErrorOverview.tsx +8 -7
- package/src/components/Hyperlink.tsx +56 -0
- package/src/components/Spacer.tsx +1 -1
- package/src/components/Static.tsx +1 -1
- package/src/components/StderrContext.ts +0 -2
- package/src/components/StdinContext.ts +0 -1
- package/src/components/StdoutContext.ts +1 -3
- package/src/components/TerminalOscContext.ts +25 -0
- package/src/components/Text.tsx +23 -46
- package/src/components/Transform.tsx +2 -2
- package/src/cursor-position.ts +1 -1
- package/src/devtools.ts +84 -24
- package/src/dom.ts +11 -8
- package/src/env.ts +12 -0
- package/src/get-max-width.ts +1 -1
- package/src/global.d.ts +6 -4
- package/src/{boxes.ts → glyphs.ts} +17 -18
- package/src/hooks/use-animation.ts +1 -1
- package/src/hooks/use-app.ts +1 -1
- package/src/hooks/use-box-metrics.ts +1 -1
- package/src/hooks/use-capabilities.ts +73 -0
- package/src/hooks/use-cursor.ts +3 -3
- package/src/hooks/use-focus-manager.ts +1 -1
- package/src/hooks/use-focus.ts +5 -6
- package/src/hooks/use-input.ts +4 -4
- package/src/hooks/use-is-screen-reader-enabled.ts +1 -1
- package/src/hooks/use-paste.ts +2 -2
- package/src/hooks/use-stderr.ts +1 -1
- package/src/hooks/use-stdin.ts +1 -1
- package/src/hooks/use-stdout.ts +1 -1
- package/src/hooks/use-terminal-osc.ts +59 -0
- package/src/hooks/use-window-size.ts +2 -2
- package/src/index.ts +88 -44
- package/src/ink.tsx +620 -745
- package/src/input-parser.ts +1 -1
- package/src/instances.ts +1 -1
- package/src/kitty-keyboard.ts +128 -0
- package/src/measure-element.ts +1 -1
- package/src/measure-text.ts +2 -2
- package/src/{render-node-to-output.ts → paint-tree.ts} +78 -53
- package/src/parse-keypress.ts +4 -5
- package/src/parse-stack-line.ts +0 -1
- package/src/patch-console.ts +44 -0
- package/src/reconciler.ts +36 -62
- package/src/render-background.ts +37 -16
- package/src/render-border.ts +97 -64
- package/src/render-frame.ts +83 -0
- package/src/render-to-string.ts +24 -9
- package/src/render.ts +24 -16
- package/src/router/components.tsx +343 -0
- package/src/router/context.ts +41 -0
- package/src/router/history.ts +194 -0
- package/src/router/hooks.tsx +391 -0
- package/src/router/index.ts +34 -0
- package/src/router/matcher.ts +571 -0
- package/src/sanitize-ansi.ts +1 -1
- package/src/screen/ansi.ts +184 -0
- package/src/screen/canvas.ts +137 -0
- package/src/screen/cell.ts +138 -0
- package/src/screen/color-profile.ts +47 -0
- package/src/screen/geometry.ts +9 -0
- package/src/screen/index.ts +6 -0
- package/src/screen/screen.ts +272 -0
- package/src/screen/serialize.ts +129 -0
- package/src/screen.ts +1 -0
- package/src/semantic-text-style.ts +118 -0
- package/src/signal-exit.ts +4 -5
- package/src/squash-text-nodes.ts +4 -7
- package/src/stream.ts +2 -4
- package/src/structured-text.ts +321 -0
- package/src/styles.ts +16 -17
- package/src/terminal/index.ts +2 -0
- package/src/terminal/inline-presenter.ts +120 -0
- package/src/terminal/input.ts +86 -0
- package/src/terminal/render-scheduler.ts +37 -0
- package/src/terminal/screen-presenter.ts +188 -0
- package/src/terminal/session.ts +407 -0
- package/src/terminal-size.ts +9 -8
- package/src/terminal.ts +1 -0
- package/src/testing/browser.ts +588 -0
- package/src/testing/emulators.ts +205 -0
- package/src/testing/explorer-app/index.html +12 -0
- package/src/testing/explorer-app/main.ts +381 -0
- package/src/testing/explorer-app/style.css +194 -0
- package/src/testing/explorer-app/tsconfig.json +15 -0
- package/src/testing/explorer-app/vite-env.d.ts +1 -0
- package/src/testing/index.ts +26 -0
- package/src/testing/keys.ts +56 -0
- package/src/testing/live.ts +85 -0
- package/src/testing/matchers.ts +70 -0
- package/src/testing/public.ts +94 -0
- package/src/testing/terminal.ts +349 -0
- package/src/testing/vitest.ts +157 -0
- package/src/transform-adapter.ts +14 -0
- package/src/types.ts +1 -6
- package/src/utils.ts +2 -2
- package/src/wrap-text.ts +4 -4
- package/src/yoga/config.ts +2 -2
- package/src/yoga/core/absoluteLayout.ts +15 -15
- package/src/yoga/core/baseline.ts +3 -3
- package/src/yoga/core/cache.ts +4 -4
- package/src/yoga/core/calculateLayout.ts +33 -27
- package/src/yoga/core/config.ts +1 -1
- package/src/yoga/core/flexLine.ts +3 -3
- package/src/yoga/core/helpers.ts +3 -3
- package/src/yoga/core/layoutResults.ts +4 -4
- package/src/yoga/core/node.ts +16 -16
- package/src/yoga/core/pixelGrid.ts +4 -4
- package/src/yoga/core/style.ts +11 -11
- package/src/yoga/core/types.ts +2 -2
- package/src/yoga/index.ts +6 -6
- package/src/yoga/node.ts +8 -8
- package/dist/sgr-CMfEpjSk.d.ts +0 -91
- package/dist/truncate-CBiyyZzw.js +0 -2156
- package/src/ansi/supports-color.ts +0 -213
- package/src/ansi/widest-line.ts +0 -12
- package/src/auto-bind.ts +0 -41
- package/src/colorize.ts +0 -60
- package/src/devtools-window-polyfill.ts +0 -73
- package/src/indent-string.ts +0 -16
- package/src/is-in-ci.ts +0 -7
- package/src/log-update.ts +0 -370
- package/src/output.ts +0 -308
- package/src/renderer.ts +0 -73
- package/src/write-synchronized.ts +0 -9
package/src/render-border.ts
CHANGED
|
@@ -1,26 +1,46 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import type
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
import { graphemes } from "#/ansi/graphemes.ts";
|
|
2
|
+
import { stringWidth } from "#/ansi/string-width.ts";
|
|
3
|
+
import type { Paint, PaintContext } from "#/color/paint.ts";
|
|
4
|
+
import { samplePaint } from "#/color/sample.ts";
|
|
5
|
+
import { type DOMNode } from "#/dom.ts";
|
|
6
|
+
import { BOXES } from "#/glyphs.ts";
|
|
7
|
+
import type { Canvas } from "#/screen/canvas.ts";
|
|
8
|
+
import type { Rect } from "#/screen/geometry.ts";
|
|
9
|
+
import { cellAttributes, createCell, type Cell } from "#/screen/index.ts";
|
|
10
|
+
|
|
11
|
+
const stylePiece = (
|
|
12
|
+
segment: string,
|
|
13
|
+
x: number,
|
|
14
|
+
y: number,
|
|
15
|
+
bounds: Rect,
|
|
16
|
+
context: PaintContext,
|
|
17
|
+
fg?: Paint,
|
|
18
|
+
bg?: Paint,
|
|
19
|
+
dim?: boolean,
|
|
20
|
+
): Cell[] => {
|
|
21
|
+
let column = x;
|
|
22
|
+
return [...graphemes(segment)].map((grapheme) => {
|
|
23
|
+
const foreground = fg ? samplePaint(fg, column, y, bounds, context) : undefined;
|
|
24
|
+
const background = bg ? samplePaint(bg, column, y, bounds, context) : undefined;
|
|
25
|
+
const width = Math.max(1, stringWidth(grapheme));
|
|
26
|
+
column += width;
|
|
27
|
+
return createCell(grapheme, width, {
|
|
28
|
+
...(foreground ? { foreground } : {}),
|
|
29
|
+
...(background ? { background } : {}),
|
|
30
|
+
underline: "none",
|
|
31
|
+
attributes: dim ? cellAttributes.faint : cellAttributes.none,
|
|
32
|
+
});
|
|
33
|
+
});
|
|
15
34
|
};
|
|
16
35
|
|
|
17
|
-
export const renderBorder = (x: number, y: number, node: DOMNode, output:
|
|
36
|
+
export const renderBorder = (x: number, y: number, node: DOMNode, output: Canvas): void => {
|
|
18
37
|
if (node.style.borderStyle) {
|
|
19
38
|
const width = node.yogaNode!.getComputedWidth();
|
|
20
39
|
const height = node.yogaNode!.getComputedHeight();
|
|
40
|
+
const bounds = { x, y, width, height };
|
|
21
41
|
const box =
|
|
22
42
|
typeof node.style.borderStyle === "string"
|
|
23
|
-
?
|
|
43
|
+
? BOXES[node.style.borderStyle]
|
|
24
44
|
: node.style.borderStyle;
|
|
25
45
|
|
|
26
46
|
const topBorderColor = node.style.borderTopColor ?? node.style.borderColor;
|
|
@@ -52,19 +72,12 @@ export const renderBorder = (x: number, y: number, node: DOMNode, output: Output
|
|
|
52
72
|
|
|
53
73
|
const contentWidth = width - (showLeftBorder ? 1 : 0) - (showRightBorder ? 1 : 0);
|
|
54
74
|
|
|
55
|
-
|
|
75
|
+
const topBorder = showTopBorder
|
|
56
76
|
? (showLeftBorder ? box.topLeft : "") +
|
|
57
77
|
box.top.repeat(contentWidth) +
|
|
58
78
|
(showRightBorder ? box.topRight : "")
|
|
59
79
|
: undefined;
|
|
60
80
|
|
|
61
|
-
topBorder &&= stylePiece(
|
|
62
|
-
topBorder,
|
|
63
|
-
topBorderColor,
|
|
64
|
-
topBorderBackgroundColor,
|
|
65
|
-
dimTopBorderColor,
|
|
66
|
-
);
|
|
67
|
-
|
|
68
81
|
let verticalBorderHeight = height;
|
|
69
82
|
|
|
70
83
|
if (showTopBorder) {
|
|
@@ -75,60 +88,80 @@ export const renderBorder = (x: number, y: number, node: DOMNode, output: Output
|
|
|
75
88
|
verticalBorderHeight -= 1;
|
|
76
89
|
}
|
|
77
90
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (showLeftBorder) {
|
|
81
|
-
const one = stylePiece(
|
|
82
|
-
box.left,
|
|
83
|
-
leftBorderColor,
|
|
84
|
-
leftBorderBackgroundColor,
|
|
85
|
-
dimLeftBorderColor,
|
|
86
|
-
);
|
|
87
|
-
leftBorder = (one + "\n").repeat(verticalBorderHeight);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
let rightBorder = "";
|
|
91
|
-
|
|
92
|
-
if (showRightBorder) {
|
|
93
|
-
const one = stylePiece(
|
|
94
|
-
box.right,
|
|
95
|
-
rightBorderColor,
|
|
96
|
-
rightBorderBackgroundColor,
|
|
97
|
-
dimRightBorderColor,
|
|
98
|
-
);
|
|
99
|
-
rightBorder = (one + "\n").repeat(verticalBorderHeight);
|
|
100
|
-
}
|
|
91
|
+
const offsetY = showTopBorder ? 1 : 0;
|
|
101
92
|
|
|
102
|
-
|
|
93
|
+
const bottomBorder = showBottomBorder
|
|
103
94
|
? (showLeftBorder ? box.bottomLeft : "") +
|
|
104
95
|
box.bottom.repeat(contentWidth) +
|
|
105
96
|
(showRightBorder ? box.bottomRight : "")
|
|
106
97
|
: undefined;
|
|
107
|
-
bottomBorder &&= stylePiece(
|
|
108
|
-
bottomBorder,
|
|
109
|
-
bottomBorderColor,
|
|
110
|
-
bottomBorderBackgroundColor,
|
|
111
|
-
dimBottomBorderColor,
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
const offsetY = showTopBorder ? 1 : 0;
|
|
115
98
|
|
|
116
99
|
if (topBorder) {
|
|
117
|
-
output.
|
|
100
|
+
output.writeCells(x, y, [
|
|
101
|
+
stylePiece(
|
|
102
|
+
topBorder,
|
|
103
|
+
x,
|
|
104
|
+
y,
|
|
105
|
+
bounds,
|
|
106
|
+
output.paintContext,
|
|
107
|
+
topBorderColor,
|
|
108
|
+
topBorderBackgroundColor,
|
|
109
|
+
dimTopBorderColor,
|
|
110
|
+
),
|
|
111
|
+
]);
|
|
118
112
|
}
|
|
119
113
|
|
|
120
|
-
if (
|
|
121
|
-
output.
|
|
114
|
+
if (showLeftBorder) {
|
|
115
|
+
output.writeCells(
|
|
116
|
+
x,
|
|
117
|
+
y + offsetY,
|
|
118
|
+
Array.from({ length: verticalBorderHeight }, (_, row) =>
|
|
119
|
+
stylePiece(
|
|
120
|
+
box.left,
|
|
121
|
+
x,
|
|
122
|
+
y + offsetY + row,
|
|
123
|
+
bounds,
|
|
124
|
+
output.paintContext,
|
|
125
|
+
leftBorderColor,
|
|
126
|
+
leftBorderBackgroundColor,
|
|
127
|
+
dimLeftBorderColor,
|
|
128
|
+
),
|
|
129
|
+
),
|
|
130
|
+
);
|
|
122
131
|
}
|
|
123
132
|
|
|
124
|
-
if (
|
|
125
|
-
output.
|
|
126
|
-
|
|
127
|
-
|
|
133
|
+
if (showRightBorder) {
|
|
134
|
+
output.writeCells(
|
|
135
|
+
x + width - 1,
|
|
136
|
+
y + offsetY,
|
|
137
|
+
Array.from({ length: verticalBorderHeight }, (_, row) =>
|
|
138
|
+
stylePiece(
|
|
139
|
+
box.right,
|
|
140
|
+
x + width - 1,
|
|
141
|
+
y + offsetY + row,
|
|
142
|
+
bounds,
|
|
143
|
+
output.paintContext,
|
|
144
|
+
rightBorderColor,
|
|
145
|
+
rightBorderBackgroundColor,
|
|
146
|
+
dimRightBorderColor,
|
|
147
|
+
),
|
|
148
|
+
),
|
|
149
|
+
);
|
|
128
150
|
}
|
|
129
151
|
|
|
130
152
|
if (bottomBorder) {
|
|
131
|
-
output.
|
|
153
|
+
output.writeCells(x, y + height - 1, [
|
|
154
|
+
stylePiece(
|
|
155
|
+
bottomBorder,
|
|
156
|
+
x,
|
|
157
|
+
y + height - 1,
|
|
158
|
+
bounds,
|
|
159
|
+
output.paintContext,
|
|
160
|
+
bottomBorderColor,
|
|
161
|
+
bottomBorderBackgroundColor,
|
|
162
|
+
dimBottomBorderColor,
|
|
163
|
+
),
|
|
164
|
+
]);
|
|
132
165
|
}
|
|
133
166
|
}
|
|
134
167
|
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { PaintContext } from "#/color/paint.ts";
|
|
2
|
+
import { type DOMElement } from "#/dom.ts";
|
|
3
|
+
import { paintTree, renderAccessibleText } from "#/paint-tree.ts";
|
|
4
|
+
import { Canvas } from "#/screen/canvas.ts";
|
|
5
|
+
import { type ColorProfile } from "#/screen/index.ts";
|
|
6
|
+
import type { Screen } from "#/screen/screen.ts";
|
|
7
|
+
|
|
8
|
+
type Result = {
|
|
9
|
+
screen?: Screen;
|
|
10
|
+
staticScreen?: Screen;
|
|
11
|
+
accessibleText?: string;
|
|
12
|
+
staticAccessibleText?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type RendererOptions = {
|
|
16
|
+
colorProfile?: ColorProfile;
|
|
17
|
+
paintContext?: PaintContext;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const renderDimension = (value: number): number =>
|
|
21
|
+
Number.isFinite(value) ? Math.max(0, Math.ceil(value)) : 0;
|
|
22
|
+
|
|
23
|
+
export const renderFrame = (
|
|
24
|
+
node: DOMElement,
|
|
25
|
+
isScreenReaderEnabled: boolean,
|
|
26
|
+
options: RendererOptions = {},
|
|
27
|
+
): Result => {
|
|
28
|
+
if (node.yogaNode) {
|
|
29
|
+
if (isScreenReaderEnabled) {
|
|
30
|
+
const output = renderAccessibleText(node, {
|
|
31
|
+
skipStaticElements: true,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
let staticOutput = "";
|
|
35
|
+
|
|
36
|
+
if (node.staticNode) {
|
|
37
|
+
staticOutput = renderAccessibleText(node.staticNode, {
|
|
38
|
+
skipStaticElements: false,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
accessibleText: output,
|
|
44
|
+
staticAccessibleText: staticOutput,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const output = new Canvas({
|
|
49
|
+
width: renderDimension(node.yogaNode.getComputedWidth()),
|
|
50
|
+
height: renderDimension(node.yogaNode.getComputedHeight()),
|
|
51
|
+
colorProfile: options.colorProfile,
|
|
52
|
+
paintContext: options.paintContext,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
paintTree(node, output, {
|
|
56
|
+
skipStaticElements: true,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
let staticOutput;
|
|
60
|
+
|
|
61
|
+
if (node.staticNode?.yogaNode) {
|
|
62
|
+
staticOutput = new Canvas({
|
|
63
|
+
width: renderDimension(node.staticNode.yogaNode.getComputedWidth()),
|
|
64
|
+
height: renderDimension(node.staticNode.yogaNode.getComputedHeight()),
|
|
65
|
+
colorProfile: options.colorProfile,
|
|
66
|
+
paintContext: options.paintContext,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
paintTree(node.staticNode, staticOutput, {
|
|
70
|
+
skipStaticElements: false,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
screen: output.finish(),
|
|
76
|
+
...(staticOutput ? { staticScreen: staticOutput.finish() } : {}),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
accessibleText: "",
|
|
82
|
+
};
|
|
83
|
+
};
|
package/src/render-to-string.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import { LegacyRoot } from "react-reconciler/constants.js";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
4
|
+
import { detectColorLevel } from "#/capabilities/detect.ts";
|
|
5
|
+
import { createNode, type DOMElement } from "#/dom.ts";
|
|
6
|
+
import { reconciler } from "#/reconciler.ts";
|
|
7
|
+
import { renderFrame } from "#/render-frame.ts";
|
|
8
|
+
import { colorProfileFromLevel, type ColorProfile } from "#/screen/index.ts";
|
|
9
|
+
import { serializeScreen } from "#/screen/serialize.ts";
|
|
10
|
+
import { Yoga } from "#/yoga/index.ts";
|
|
8
11
|
|
|
9
12
|
export type RenderToStringOptions = {
|
|
10
13
|
/**
|
|
@@ -13,6 +16,12 @@ export type RenderToStringOptions = {
|
|
|
13
16
|
@default 80
|
|
14
17
|
*/
|
|
15
18
|
columns?: number;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
Color profile used for deterministic serialization. By default this retains
|
|
22
|
+
the process color level for Ink compatibility.
|
|
23
|
+
*/
|
|
24
|
+
colorProfile?: ColorProfile;
|
|
16
25
|
};
|
|
17
26
|
|
|
18
27
|
/**
|
|
@@ -44,6 +53,7 @@ console.log(output);
|
|
|
44
53
|
*/
|
|
45
54
|
export const renderToString = (node: ReactNode, options?: RenderToStringOptions): string => {
|
|
46
55
|
const columns = options?.columns ?? 80;
|
|
56
|
+
const colorProfile = options?.colorProfile ?? colorProfileFromLevel(detectColorLevel());
|
|
47
57
|
|
|
48
58
|
// Create a standalone root node — no stdout, stdin, or terminal bindings
|
|
49
59
|
const rootNode: DOMElement = createNode("ink-root");
|
|
@@ -62,7 +72,10 @@ export const renderToString = (node: ReactNode, options?: RenderToStringOptions)
|
|
|
62
72
|
};
|
|
63
73
|
|
|
64
74
|
rootNode.onImmediateRender = () => {
|
|
65
|
-
const {
|
|
75
|
+
const { staticScreen } = renderFrame(rootNode, false, { colorProfile });
|
|
76
|
+
const staticOutput = staticScreen
|
|
77
|
+
? `${serializeScreen(staticScreen, { colorProfile, styles: colorProfile !== "none" })}\n`
|
|
78
|
+
: "";
|
|
66
79
|
if (staticOutput && staticOutput !== "\n") {
|
|
67
80
|
capturedStaticOutput += staticOutput;
|
|
68
81
|
}
|
|
@@ -99,7 +112,10 @@ export const renderToString = (node: ReactNode, options?: RenderToStringOptions)
|
|
|
99
112
|
|
|
100
113
|
// Yoga layout has already been calculated by onComputeLayout during commit.
|
|
101
114
|
// Render the DOM tree to a string — this captures the dynamic (non-static) output.
|
|
102
|
-
const {
|
|
115
|
+
const { screen } = renderFrame(rootNode, false, { colorProfile });
|
|
116
|
+
const output = screen
|
|
117
|
+
? serializeScreen(screen, { colorProfile, styles: colorProfile !== "none" })
|
|
118
|
+
: "";
|
|
103
119
|
|
|
104
120
|
// Tear down: unmount the tree so the reconciler cleans up child nodes
|
|
105
121
|
// and runs effect cleanup functions. The reconciler detaches removed
|
|
@@ -116,9 +132,8 @@ export const renderToString = (node: ReactNode, options?: RenderToStringOptions)
|
|
|
116
132
|
new Error(String(uncaughtError));
|
|
117
133
|
}
|
|
118
134
|
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
// so renderToString returns clean output.
|
|
135
|
+
// Static terminal output ends with a newline so dynamic output starts on a
|
|
136
|
+
// fresh line. Strip it here so renderToString returns clean output.
|
|
122
137
|
const normalizedStaticOutput = capturedStaticOutput.endsWith("\n")
|
|
123
138
|
? capturedStaticOutput.slice(0, -1)
|
|
124
139
|
: capturedStaticOutput;
|
package/src/render.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import process from "node:process";
|
|
2
1
|
import { Stream, type Writable } from "node:stream";
|
|
3
2
|
|
|
4
3
|
import type { ReactNode } from "react";
|
|
5
4
|
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
5
|
+
import type { ClipboardSelection, TerminalProgressState } from "#/ansi/osc.ts";
|
|
6
|
+
import { createInk, type Ink, type Options as InkOptions, type RenderMetrics } from "#/ink.tsx";
|
|
7
|
+
import { instances } from "#/instances.ts";
|
|
8
|
+
import { type KittyKeyboardOptions } from "#/kitty-keyboard.ts";
|
|
9
|
+
import { type ColorProfile } from "#/screen/color-profile.ts";
|
|
9
10
|
|
|
10
11
|
export type RenderOptions = {
|
|
11
12
|
/**
|
|
@@ -89,12 +90,12 @@ export type RenderOptions = {
|
|
|
89
90
|
maxFps?: number;
|
|
90
91
|
|
|
91
92
|
/**
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
Override the output color profile for this render instance. When omitted,
|
|
94
|
+
the profile follows the capabilities of `stdout` and capability upgrades
|
|
95
|
+
redraw the live frame. Static content already written to scrollback is not
|
|
96
|
+
replayed or recolored.
|
|
96
97
|
*/
|
|
97
|
-
|
|
98
|
+
colorProfile?: ColorProfile;
|
|
98
99
|
|
|
99
100
|
/**
|
|
100
101
|
Enable React Concurrent Rendering mode.
|
|
@@ -122,7 +123,7 @@ export type RenderOptions = {
|
|
|
122
123
|
/**
|
|
123
124
|
Override automatic interactive mode detection.
|
|
124
125
|
|
|
125
|
-
By default, Ink detects whether the environment is interactive based on CI detection (
|
|
126
|
+
By default, Ink detects whether the environment is interactive based on CI detection (the `CI` environment variable) and `stdout.isTTY`. Most users should not need to set this.
|
|
126
127
|
|
|
127
128
|
When non-interactive, Ink disables ANSI erase sequences, cursor manipulation, synchronized output, resize handling, and kitty keyboard auto-detection, writing only the final frame at unmount.
|
|
128
129
|
|
|
@@ -206,6 +207,12 @@ export type Instance = {
|
|
|
206
207
|
Clear output.
|
|
207
208
|
*/
|
|
208
209
|
clear: () => void;
|
|
210
|
+
|
|
211
|
+
/** Copy text through the renderer-owned terminal session. */
|
|
212
|
+
copyToClipboard: (text: string, selection?: ClipboardSelection) => boolean;
|
|
213
|
+
|
|
214
|
+
/** Update terminal-native progress through the renderer-owned session. */
|
|
215
|
+
setProgress: (state: TerminalProgressState, value?: number) => boolean;
|
|
209
216
|
};
|
|
210
217
|
|
|
211
218
|
/**
|
|
@@ -220,26 +227,27 @@ export const render = (node: ReactNode, options?: Writable | RenderOptions): Ins
|
|
|
220
227
|
exitOnCtrlC: true,
|
|
221
228
|
patchConsole: true,
|
|
222
229
|
maxFps: 30,
|
|
223
|
-
incrementalRendering: false,
|
|
224
230
|
concurrent: false,
|
|
225
231
|
alternateScreen: false,
|
|
226
232
|
...getOptions(options),
|
|
227
233
|
};
|
|
228
234
|
|
|
229
|
-
const instance: Ink = getInstance(inkOptions.stdout, () =>
|
|
235
|
+
const instance: Ink = getInstance(inkOptions.stdout, () => createInk(inkOptions));
|
|
230
236
|
instance.render(node);
|
|
231
237
|
|
|
232
238
|
return {
|
|
233
|
-
rerender: instance.render
|
|
239
|
+
rerender: instance.render,
|
|
234
240
|
unmount() {
|
|
235
241
|
instance.unmount();
|
|
236
242
|
},
|
|
237
|
-
waitUntilExit: instance.waitUntilExit
|
|
238
|
-
waitUntilRenderFlush: instance.waitUntilRenderFlush
|
|
243
|
+
waitUntilExit: instance.waitUntilExit,
|
|
244
|
+
waitUntilRenderFlush: instance.waitUntilRenderFlush,
|
|
239
245
|
cleanup() {
|
|
240
246
|
instance.unmount();
|
|
241
247
|
},
|
|
242
|
-
clear: instance.clear
|
|
248
|
+
clear: instance.clear,
|
|
249
|
+
copyToClipboard: instance.copyToClipboard,
|
|
250
|
+
setProgress: instance.setProgress,
|
|
243
251
|
};
|
|
244
252
|
};
|
|
245
253
|
|