ink 6.6.0 → 6.8.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/build/ansi-tokenizer.d.ts +38 -0
- package/build/ansi-tokenizer.js +316 -0
- package/build/ansi-tokenizer.js.map +1 -0
- package/build/components/App.d.ts +8 -49
- package/build/components/App.js +293 -228
- package/build/components/App.js.map +1 -1
- package/build/components/AppContext.d.ts +5 -1
- package/build/components/AppContext.js.map +1 -1
- package/build/components/Cursor.d.ts +83 -0
- package/build/components/Cursor.js +53 -0
- package/build/components/Cursor.js.map +1 -0
- package/build/components/CursorContext.d.ts +11 -0
- package/build/components/CursorContext.js +8 -0
- package/build/components/CursorContext.js.map +1 -0
- package/build/components/ErrorBoundary.d.ts +18 -0
- package/build/components/ErrorBoundary.js +23 -0
- package/build/components/ErrorBoundary.js.map +1 -0
- package/build/cursor-helpers.d.ts +38 -0
- package/build/cursor-helpers.js +56 -0
- package/build/cursor-helpers.js.map +1 -0
- package/build/dom.js +5 -4
- package/build/dom.js.map +1 -1
- package/build/hooks/use-cursor.d.ts +12 -0
- package/build/hooks/use-cursor.js +29 -0
- package/build/hooks/use-cursor.js.map +1 -0
- package/build/hooks/use-input.d.ts +30 -0
- package/build/hooks/use-input.js +31 -2
- package/build/hooks/use-input.js.map +1 -1
- package/build/index.d.ts +6 -0
- package/build/index.js +3 -0
- package/build/index.js.map +1 -1
- package/build/ink.d.ts +39 -3
- package/build/ink.js +377 -49
- package/build/ink.js.map +1 -1
- package/build/input-parser.d.ts +7 -0
- package/build/input-parser.js +154 -0
- package/build/input-parser.js.map +1 -0
- package/build/kitty-keyboard.d.ts +23 -0
- package/build/kitty-keyboard.js +32 -0
- package/build/kitty-keyboard.js.map +1 -0
- package/build/layout.d.ts +7 -0
- package/build/layout.js +33 -0
- package/build/layout.js.map +1 -0
- package/build/log-update.d.ts +6 -1
- package/build/log-update.js +163 -40
- package/build/log-update.js.map +1 -1
- package/build/output.d.ts +1 -0
- package/build/output.js +38 -5
- package/build/output.js.map +1 -1
- package/build/parse-keypress.d.ts +8 -0
- package/build/parse-keypress.js +270 -2
- package/build/parse-keypress.js.map +1 -1
- package/build/reconciler.js +23 -3
- package/build/reconciler.js.map +1 -1
- package/build/render-to-string.d.ts +38 -0
- package/build/render-to-string.js +115 -0
- package/build/render-to-string.js.map +1 -0
- package/build/render.d.ts +34 -1
- package/build/render.js +7 -2
- package/build/render.js.map +1 -1
- package/build/sanitize-ansi.d.ts +2 -0
- package/build/sanitize-ansi.js +27 -0
- package/build/sanitize-ansi.js.map +1 -0
- package/build/squash-text-nodes.js +2 -1
- package/build/squash-text-nodes.js.map +1 -1
- package/build/utils.d.ts +2 -0
- package/build/utils.js +4 -0
- package/build/utils.js.map +1 -0
- package/build/write-synchronized.d.ts +4 -0
- package/build/write-synchronized.js +7 -0
- package/build/write-synchronized.js.map +1 -0
- package/package.json +27 -21
- package/readme.md +292 -14
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import Yoga from 'yoga-layout';
|
|
2
|
+
import { LegacyRoot } from 'react-reconciler/constants.js';
|
|
3
|
+
import reconciler from './reconciler.js';
|
|
4
|
+
import renderer from './renderer.js';
|
|
5
|
+
import { createNode } from './dom.js';
|
|
6
|
+
/**
|
|
7
|
+
Render a React element to a string synchronously. Unlike `render()`, this function does not write to stdout, does not set up any terminal event listeners, and returns the rendered output as a string.
|
|
8
|
+
|
|
9
|
+
Useful for generating documentation, writing output to files, testing, or any scenario where you need the rendered output as a string without starting a persistent terminal application.
|
|
10
|
+
|
|
11
|
+
**Notes:**
|
|
12
|
+
|
|
13
|
+
- Terminal-specific hooks (`useInput`, `useStdin`, `useStdout`, `useStderr`, `useApp`, `useFocus`, `useFocusManager`) return default no-op values since there is no terminal session. They will not throw, but they will not function as in a live terminal.
|
|
14
|
+
- `useEffect` callbacks will execute during rendering (due to synchronous rendering mode), but state updates they trigger will not affect the returned output, which reflects the initial render.
|
|
15
|
+
- `useLayoutEffect` callbacks fire synchronously during commit, so state updates they trigger **will** be reflected in the output.
|
|
16
|
+
- The `<Static>` component is supported — its output is prepended to the dynamic output.
|
|
17
|
+
- If a component throws during rendering, the error is propagated to the caller after cleanup.
|
|
18
|
+
|
|
19
|
+
@example
|
|
20
|
+
```
|
|
21
|
+
import {renderToString, Text, Box} from 'ink';
|
|
22
|
+
|
|
23
|
+
const output = renderToString(
|
|
24
|
+
<Box padding={1}>
|
|
25
|
+
<Text color="green">Hello World</Text>
|
|
26
|
+
</Box>,
|
|
27
|
+
{columns: 40}
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
console.log(output);
|
|
31
|
+
```
|
|
32
|
+
*/
|
|
33
|
+
const renderToString = (node, options) => {
|
|
34
|
+
const columns = options?.columns ?? 80;
|
|
35
|
+
// Create a standalone root node — no stdout, stdin, or terminal bindings
|
|
36
|
+
const rootNode = createNode('ink-root');
|
|
37
|
+
// Capture static output from intermediate renders.
|
|
38
|
+
// The <Static> component uses useLayoutEffect to clear its children after
|
|
39
|
+
// the first commit. The reconciler's resetAfterCommit calls onImmediateRender
|
|
40
|
+
// when static content is dirty (and returns early, skipping the normal
|
|
41
|
+
// onRender callback), giving us a chance to capture it before it's cleared
|
|
42
|
+
// by the subsequent re-render.
|
|
43
|
+
let capturedStaticOutput = '';
|
|
44
|
+
rootNode.onComputeLayout = () => {
|
|
45
|
+
rootNode.yogaNode.setWidth(columns);
|
|
46
|
+
rootNode.yogaNode.calculateLayout(undefined, undefined, Yoga.DIRECTION_LTR);
|
|
47
|
+
};
|
|
48
|
+
rootNode.onImmediateRender = () => {
|
|
49
|
+
const { staticOutput } = renderer(rootNode, false);
|
|
50
|
+
if (staticOutput && staticOutput !== '\n') {
|
|
51
|
+
capturedStaticOutput += staticOutput;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
// Capture the first uncaught error so we can re-throw it after cleanup.
|
|
55
|
+
// React's reconciler catches component errors internally and reports them
|
|
56
|
+
// via onUncaughtError rather than letting them propagate. For a synchronous
|
|
57
|
+
// utility like renderToString, callers expect errors to throw.
|
|
58
|
+
let uncaughtError;
|
|
59
|
+
// Create a reconciler container in legacy (synchronous) mode.
|
|
60
|
+
// The four trailing callbacks are: onUncaughtError, onCaughtError,
|
|
61
|
+
// onRecoverableError, and onHostTransitionComplete.
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
63
|
+
const container = reconciler.createContainer(rootNode, LegacyRoot, null, false, null, 'render-to-string', (error) => {
|
|
64
|
+
uncaughtError ??= error;
|
|
65
|
+
}, () => { }, () => { }, () => { });
|
|
66
|
+
let teardownSucceeded = false;
|
|
67
|
+
try {
|
|
68
|
+
// Synchronously render the React tree into the container
|
|
69
|
+
reconciler.updateContainerSync(node, container, null, () => { });
|
|
70
|
+
reconciler.flushSyncWork();
|
|
71
|
+
// Yoga layout has already been calculated by onComputeLayout during commit.
|
|
72
|
+
// Render the DOM tree to a string — this captures the dynamic (non-static) output.
|
|
73
|
+
const { output } = renderer(rootNode, false);
|
|
74
|
+
// Tear down: unmount the tree so the reconciler cleans up child nodes
|
|
75
|
+
// and runs effect cleanup functions. Child Yoga nodes are freed by the
|
|
76
|
+
// reconciler's removeChildFromContainer → cleanupYogaNode → freeRecursive.
|
|
77
|
+
reconciler.updateContainerSync(null, container, null, () => { });
|
|
78
|
+
reconciler.flushSyncWork();
|
|
79
|
+
teardownSucceeded = true;
|
|
80
|
+
// Free the root yoga node itself (children already freed by reconciler)
|
|
81
|
+
rootNode.yogaNode.free();
|
|
82
|
+
// Re-throw after full cleanup so callers see the original error.
|
|
83
|
+
if (uncaughtError !== undefined) {
|
|
84
|
+
throw uncaughtError instanceof Error
|
|
85
|
+
? uncaughtError
|
|
86
|
+
: new Error(String(uncaughtError));
|
|
87
|
+
}
|
|
88
|
+
// The renderer appends a trailing newline to static output for terminal
|
|
89
|
+
// rendering (so dynamic output starts on a fresh line). Strip it here
|
|
90
|
+
// so renderToString returns clean output.
|
|
91
|
+
const normalizedStaticOutput = capturedStaticOutput.endsWith('\n')
|
|
92
|
+
? capturedStaticOutput.slice(0, -1)
|
|
93
|
+
: capturedStaticOutput;
|
|
94
|
+
if (normalizedStaticOutput && output) {
|
|
95
|
+
return normalizedStaticOutput + '\n' + output;
|
|
96
|
+
}
|
|
97
|
+
return normalizedStaticOutput || output;
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
// Ensure native Yoga memory is freed even if rendering or teardown threw.
|
|
101
|
+
// Yoga nodes are WASM-backed and not garbage collected.
|
|
102
|
+
if (!teardownSucceeded && rootNode.yogaNode) {
|
|
103
|
+
try {
|
|
104
|
+
// If reconciler teardown failed, some child nodes may not have been
|
|
105
|
+
// freed. Use freeRecursive to clean up the entire tree as best-effort.
|
|
106
|
+
rootNode.yogaNode.freeRecursive();
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Best-effort: node may already be partially freed
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
export default renderToString;
|
|
115
|
+
//# sourceMappingURL=render-to-string.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-to-string.js","sourceRoot":"","sources":["../src/render-to-string.ts"],"names":[],"mappings":"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"}
|
package/build/render.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import Ink, { type RenderMetrics } from './ink.js';
|
|
3
|
+
import { type KittyKeyboardOptions } from './kitty-keyboard.js';
|
|
3
4
|
export type RenderOptions = {
|
|
4
5
|
/**
|
|
5
6
|
Output stream where the app will be rendered.
|
|
@@ -61,6 +62,27 @@ export type RenderOptions = {
|
|
|
61
62
|
@default false
|
|
62
63
|
*/
|
|
63
64
|
incrementalRendering?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
Enable React Concurrent Rendering mode.
|
|
67
|
+
|
|
68
|
+
When enabled:
|
|
69
|
+
- Suspense boundaries work correctly with async data
|
|
70
|
+
- `useTransition` and `useDeferredValue` are fully functional
|
|
71
|
+
- Updates can be interrupted for higher priority work
|
|
72
|
+
|
|
73
|
+
Note: Concurrent mode changes the timing of renders. Some tests may need to use `act()` to properly await updates. The `concurrent` option only takes effect on the first render for a given stdout. If you need to change the rendering mode, call `unmount()` first.
|
|
74
|
+
|
|
75
|
+
@default false
|
|
76
|
+
*/
|
|
77
|
+
concurrent?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
Configure kitty keyboard protocol support for enhanced keyboard input.
|
|
80
|
+
Enables additional modifiers (super, hyper, capsLock, numLock) and
|
|
81
|
+
disambiguated key events in terminals that support the protocol.
|
|
82
|
+
|
|
83
|
+
@see https://sw.kovidgoyal.net/kitty/keyboard-protocol/
|
|
84
|
+
*/
|
|
85
|
+
kittyKeyboard?: KittyKeyboardOptions;
|
|
64
86
|
};
|
|
65
87
|
export type Instance = {
|
|
66
88
|
/**
|
|
@@ -72,7 +94,18 @@ export type Instance = {
|
|
|
72
94
|
*/
|
|
73
95
|
unmount: Ink['unmount'];
|
|
74
96
|
/**
|
|
75
|
-
Returns a promise that
|
|
97
|
+
Returns a promise that settles when the app is unmounted.
|
|
98
|
+
|
|
99
|
+
It resolves with the value passed to `exit(value)` and rejects with the error passed to `exit(error)`.
|
|
100
|
+
|
|
101
|
+
@example
|
|
102
|
+
```jsx
|
|
103
|
+
const {unmount, waitUntilExit} = render(<MyApp />);
|
|
104
|
+
|
|
105
|
+
setTimeout(unmount, 1000);
|
|
106
|
+
|
|
107
|
+
await waitUntilExit(); // resolves after `unmount()` is called
|
|
108
|
+
```
|
|
76
109
|
*/
|
|
77
110
|
waitUntilExit: Ink['waitUntilExit'];
|
|
78
111
|
cleanup: () => void;
|
package/build/render.js
CHANGED
|
@@ -15,9 +15,10 @@ const render = (node, options) => {
|
|
|
15
15
|
patchConsole: true,
|
|
16
16
|
maxFps: 30,
|
|
17
17
|
incrementalRendering: false,
|
|
18
|
+
concurrent: false,
|
|
18
19
|
...getOptions(options),
|
|
19
20
|
};
|
|
20
|
-
const instance = getInstance(inkOptions.stdout, () => new Ink(inkOptions));
|
|
21
|
+
const instance = getInstance(inkOptions.stdout, () => new Ink(inkOptions), inkOptions.concurrent ?? false);
|
|
21
22
|
instance.render(node);
|
|
22
23
|
return {
|
|
23
24
|
rerender: instance.render,
|
|
@@ -39,12 +40,16 @@ const getOptions = (stdout = {}) => {
|
|
|
39
40
|
}
|
|
40
41
|
return stdout;
|
|
41
42
|
};
|
|
42
|
-
const getInstance = (stdout, createInstance) => {
|
|
43
|
+
const getInstance = (stdout, createInstance, concurrent) => {
|
|
43
44
|
let instance = instances.get(stdout);
|
|
44
45
|
if (!instance) {
|
|
45
46
|
instance = createInstance();
|
|
46
47
|
instances.set(stdout, instance);
|
|
47
48
|
}
|
|
49
|
+
else if (instance.isConcurrent !== concurrent) {
|
|
50
|
+
console.warn(`Warning: render() was called with concurrent: ${concurrent}, but the existing instance for this stdout uses concurrent: ${instance.isConcurrent}. ` +
|
|
51
|
+
`The concurrent option only takes effect on the first render. Call unmount() first if you need to change the rendering mode.`);
|
|
52
|
+
}
|
|
48
53
|
return instance;
|
|
49
54
|
};
|
|
50
55
|
//# sourceMappingURL=render.js.map
|
package/build/render.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACnC,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,GAAqD,MAAM,UAAU,CAAC;AAC7E,OAAO,SAAS,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACnC,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,GAAqD,MAAM,UAAU,CAAC;AAC7E,OAAO,SAAS,MAAM,gBAAgB,CAAC;AAqIvC;;EAEE;AACF,MAAM,MAAM,GAAG,CACd,IAAe,EACf,OAA4C,EACjC,EAAE;IACb,MAAM,UAAU,GAAe;QAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,KAAK;QACZ,WAAW,EAAE,IAAI;QACjB,YAAY,EAAE,IAAI;QAClB,MAAM,EAAE,EAAE;QACV,oBAAoB,EAAE,KAAK;QAC3B,UAAU,EAAE,KAAK;QACjB,GAAG,UAAU,CAAC,OAAO,CAAC;KACtB,CAAC;IAEF,MAAM,QAAQ,GAAQ,WAAW,CAChC,UAAU,CAAC,MAAM,EACjB,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,EACzB,UAAU,CAAC,UAAU,IAAI,KAAK,CAC9B,CAAC;IAEF,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEtB,OAAO;QACN,QAAQ,EAAE,QAAQ,CAAC,MAAM;QACzB,OAAO;YACN,QAAQ,CAAC,OAAO,EAAE,CAAC;QACpB,CAAC;QACD,aAAa,EAAE,QAAQ,CAAC,aAAa;QACrC,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;QAClD,KAAK,EAAE,QAAQ,CAAC,KAAK;KACrB,CAAC;AACH,CAAC,CAAC;AAEF,eAAe,MAAM,CAAC;AAEtB,MAAM,UAAU,GAAG,CAClB,SAAyD,EAAE,EAC3C,EAAE;IAClB,IAAI,MAAM,YAAY,MAAM,EAAE,CAAC;QAC9B,OAAO;YACN,MAAM;YACN,KAAK,EAAE,OAAO,CAAC,KAAK;SACpB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CACnB,MAA0B,EAC1B,cAAyB,EACzB,UAAmB,EACb,EAAE;IACR,IAAI,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAErC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,QAAQ,GAAG,cAAc,EAAE,CAAC;QAC5B,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjC,CAAC;SAAM,IAAI,QAAQ,CAAC,YAAY,KAAK,UAAU,EAAE,CAAC;QACjD,OAAO,CAAC,IAAI,CACX,iDAAiD,UAAU,gEAAgE,QAAQ,CAAC,YAAY,IAAI;YACnJ,6HAA6H,CAC9H,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AACjB,CAAC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { hasAnsiControlCharacters, tokenizeAnsi } from './ansi-tokenizer.js';
|
|
2
|
+
const sgrParametersRegex = /^[\d:;]*$/;
|
|
3
|
+
// Strip ANSI escape sequences that would conflict with Ink's layout.
|
|
4
|
+
// Preserved: SGR sequences (colors, bold, etc. - end with 'm') and
|
|
5
|
+
// OSC sequences (hyperlinks, etc. - ESC ] or C1 OSC).
|
|
6
|
+
// Stripped: cursor movement, screen clearing, and other control sequences.
|
|
7
|
+
const sanitizeAnsi = (text) => {
|
|
8
|
+
if (!hasAnsiControlCharacters(text)) {
|
|
9
|
+
return text;
|
|
10
|
+
}
|
|
11
|
+
let output = '';
|
|
12
|
+
for (const token of tokenizeAnsi(text)) {
|
|
13
|
+
if (token.type === 'text' || token.type === 'osc') {
|
|
14
|
+
output += token.value;
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (token.type === 'csi' &&
|
|
18
|
+
token.finalCharacter === 'm' &&
|
|
19
|
+
token.intermediateString === '' &&
|
|
20
|
+
sgrParametersRegex.test(token.parameterString)) {
|
|
21
|
+
output += token.value;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return output;
|
|
25
|
+
};
|
|
26
|
+
export default sanitizeAnsi;
|
|
27
|
+
//# sourceMappingURL=sanitize-ansi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-ansi.js","sourceRoot":"","sources":["../src/sanitize-ansi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,wBAAwB,EAAE,YAAY,EAAC,MAAM,qBAAqB,CAAC;AAE3E,MAAM,kBAAkB,GAAG,WAAW,CAAC;AAEvC,qEAAqE;AACrE,mEAAmE;AACnE,sDAAsD;AACtD,2EAA2E;AAC3E,MAAM,YAAY,GAAG,CAAC,IAAY,EAAU,EAAE;IAC7C,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,MAAM,GAAG,EAAE,CAAC;IAEhB,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC;YACtB,SAAS;QACV,CAAC;QAED,IACC,KAAK,CAAC,IAAI,KAAK,KAAK;YACpB,KAAK,CAAC,cAAc,KAAK,GAAG;YAC5B,KAAK,CAAC,kBAAkB,KAAK,EAAE;YAC/B,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,EAC7C,CAAC;YACF,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC;QACvB,CAAC;IACF,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import sanitizeAnsi from './sanitize-ansi.js';
|
|
1
2
|
// Squashing text nodes allows to combine multiple text nodes into one and write
|
|
2
3
|
// to `Output` instance only once. For example, <Text>hello{' '}world</Text>
|
|
3
4
|
// is actually 3 text nodes, which would result 3 writes to `Output`.
|
|
@@ -29,7 +30,7 @@ const squashTextNodes = (node) => {
|
|
|
29
30
|
}
|
|
30
31
|
text += nodeText;
|
|
31
32
|
}
|
|
32
|
-
return text;
|
|
33
|
+
return sanitizeAnsi(text);
|
|
33
34
|
};
|
|
34
35
|
export default squashTextNodes;
|
|
35
36
|
//# sourceMappingURL=squash-text-nodes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"squash-text-nodes.js","sourceRoot":"","sources":["../src/squash-text-nodes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"squash-text-nodes.js","sourceRoot":"","sources":["../src/squash-text-nodes.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAE9C,gFAAgF;AAChF,4EAA4E;AAC5E,qEAAqE;AACrE,EAAE;AACF,kGAAkG;AAClG,wFAAwF;AACxF,MAAM,eAAe,GAAG,CAAC,IAAgB,EAAU,EAAE;IACpD,IAAI,IAAI,GAAG,EAAE,CAAC;IAEd,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAEzC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC7B,SAAS;QACV,CAAC;QAED,IAAI,QAAQ,GAAG,EAAE,CAAC;QAElB,IAAI,SAAS,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACpC,QAAQ,GAAG,SAAS,CAAC,SAAS,CAAC;QAChC,CAAC;aAAM,CAAC;YACP,IACC,SAAS,CAAC,QAAQ,KAAK,UAAU;gBACjC,SAAS,CAAC,QAAQ,KAAK,kBAAkB,EACxC,CAAC;gBACF,QAAQ,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;YACvC,CAAC;YAED,oFAAoF;YACpF,iFAAiF;YACjF,IACC,QAAQ,CAAC,MAAM,GAAG,CAAC;gBACnB,OAAO,SAAS,CAAC,kBAAkB,KAAK,UAAU,EACjD,CAAC;gBACF,QAAQ,GAAG,SAAS,CAAC,kBAAkB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAC1D,CAAC;QACF,CAAC;QAED,IAAI,IAAI,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
package/build/utils.d.ts
ADDED
package/build/utils.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC;AAElD,OAAO,EAAC,KAAK,EAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import isInCi from 'is-in-ci';
|
|
2
|
+
export const bsu = '\u001B[?2026h';
|
|
3
|
+
export const esu = '\u001B[?2026l';
|
|
4
|
+
export function shouldSynchronize(stream) {
|
|
5
|
+
return 'isTTY' in stream && stream.isTTY === true && !isInCi;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=write-synchronized.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-synchronized.js","sourceRoot":"","sources":["../src/write-synchronized.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,UAAU,CAAC;AAE9B,MAAM,CAAC,MAAM,GAAG,GAAG,eAAe,CAAC;AACnC,MAAM,CAAC,MAAM,GAAG,GAAG,eAAe,CAAC;AAEnC,MAAM,UAAU,iBAAiB,CAAC,MAAgB;IACjD,OAAO,OAAO,IAAI,MAAM,IAAK,MAAc,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC;AACvE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ink",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.8.0",
|
|
4
4
|
"description": "React for CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "vadimdemedes/ink",
|
|
@@ -22,8 +22,9 @@
|
|
|
22
22
|
"build": "tsc",
|
|
23
23
|
"prepare": "npm run build",
|
|
24
24
|
"test": "tsc --noEmit && xo && FORCE_COLOR=true ava",
|
|
25
|
-
"example": "NODE_NO_WARNINGS=1 node --
|
|
26
|
-
"benchmark": "NODE_NO_WARNINGS=1 node --
|
|
25
|
+
"example": "NODE_NO_WARNINGS=1 node --import=tsx",
|
|
26
|
+
"benchmark": "NODE_NO_WARNINGS=1 node --import=tsx",
|
|
27
|
+
"inspect": "react-devtools"
|
|
27
28
|
},
|
|
28
29
|
"files": [
|
|
29
30
|
"build"
|
|
@@ -43,8 +44,8 @@
|
|
|
43
44
|
"text"
|
|
44
45
|
],
|
|
45
46
|
"dependencies": {
|
|
46
|
-
"@alcalzone/ansi-tokenize": "^0.2.
|
|
47
|
-
"ansi-escapes": "^7.
|
|
47
|
+
"@alcalzone/ansi-tokenize": "^0.2.4",
|
|
48
|
+
"ansi-escapes": "^7.3.0",
|
|
48
49
|
"ansi-styles": "^6.2.1",
|
|
49
50
|
"auto-bind": "^5.0.1",
|
|
50
51
|
"chalk": "^5.6.0",
|
|
@@ -57,26 +58,29 @@
|
|
|
57
58
|
"is-in-ci": "^2.0.0",
|
|
58
59
|
"patch-console": "^2.0.0",
|
|
59
60
|
"react-reconciler": "^0.33.0",
|
|
61
|
+
"scheduler": "^0.27.0",
|
|
60
62
|
"signal-exit": "^3.0.7",
|
|
61
|
-
"slice-ansi": "^
|
|
63
|
+
"slice-ansi": "^8.0.0",
|
|
62
64
|
"stack-utils": "^2.0.6",
|
|
63
|
-
"string-width": "^8.1.
|
|
64
|
-
"
|
|
65
|
-
"
|
|
65
|
+
"string-width": "^8.1.1",
|
|
66
|
+
"terminal-size": "^4.0.1",
|
|
67
|
+
"type-fest": "^5.4.1",
|
|
68
|
+
"widest-line": "^6.0.0",
|
|
66
69
|
"wrap-ansi": "^9.0.0",
|
|
67
70
|
"ws": "^8.18.0",
|
|
68
71
|
"yoga-layout": "~3.2.1"
|
|
69
72
|
},
|
|
70
73
|
"devDependencies": {
|
|
71
|
-
"@faker-js/faker": "^
|
|
74
|
+
"@faker-js/faker": "^10.3.0",
|
|
72
75
|
"@sindresorhus/tsconfig": "^7.0.0",
|
|
73
|
-
"@sinonjs/fake-timers": "^
|
|
76
|
+
"@sinonjs/fake-timers": "^15.1.0",
|
|
74
77
|
"@types/ms": "^2.1.0",
|
|
75
|
-
"@types/node": "^
|
|
76
|
-
"@types/react": "^19.
|
|
77
|
-
"@types/react-reconciler": "^0.
|
|
78
|
+
"@types/node": "^25.0.10",
|
|
79
|
+
"@types/react": "^19.2.13",
|
|
80
|
+
"@types/react-reconciler": "^0.33.0",
|
|
81
|
+
"@types/scheduler": "^0.26.0",
|
|
78
82
|
"@types/signal-exit": "^3.0.0",
|
|
79
|
-
"@types/sinon": "^
|
|
83
|
+
"@types/sinon": "^21.0.0",
|
|
80
84
|
"@types/stack-utils": "^2.0.2",
|
|
81
85
|
"@types/ws": "^8.18.1",
|
|
82
86
|
"@vdemedes/prettier-config": "^2.0.1",
|
|
@@ -87,21 +91,23 @@
|
|
|
87
91
|
"eslint-plugin-react": "^7.37.5",
|
|
88
92
|
"eslint-plugin-react-hooks": "^5.0.0",
|
|
89
93
|
"ms": "^2.1.3",
|
|
90
|
-
"node-pty": "^1.0.
|
|
94
|
+
"node-pty": "^1.2.0-beta.10",
|
|
91
95
|
"p-queue": "^9.0.0",
|
|
92
|
-
"prettier": "^3.
|
|
93
|
-
"react": "^19.
|
|
96
|
+
"prettier": "^3.8.1",
|
|
97
|
+
"react": "^19.2.4",
|
|
94
98
|
"react-devtools-core": "^7.0.1",
|
|
99
|
+
"react-devtools": "^7.0.1",
|
|
100
|
+
"react-router": "^7.13.0",
|
|
95
101
|
"sinon": "^21.0.0",
|
|
96
102
|
"strip-ansi": "^7.1.0",
|
|
97
|
-
"
|
|
103
|
+
"tsx": "^4.21.0",
|
|
98
104
|
"typescript": "^5.8.3",
|
|
99
105
|
"xo": "^0.59.3"
|
|
100
106
|
},
|
|
101
107
|
"peerDependencies": {
|
|
102
108
|
"@types/react": ">=19.0.0",
|
|
103
109
|
"react": ">=19.0.0",
|
|
104
|
-
"react-devtools-core": "
|
|
110
|
+
"react-devtools-core": ">=6.1.2"
|
|
105
111
|
},
|
|
106
112
|
"peerDependenciesMeta": {
|
|
107
113
|
"@types/react": {
|
|
@@ -124,7 +130,7 @@
|
|
|
124
130
|
"tsx": "module"
|
|
125
131
|
},
|
|
126
132
|
"nodeArguments": [
|
|
127
|
-
"--
|
|
133
|
+
"--import=tsx"
|
|
128
134
|
]
|
|
129
135
|
},
|
|
130
136
|
"xo": {
|