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
package/readme.md
CHANGED
|
@@ -69,13 +69,11 @@ render(<Counter />);
|
|
|
69
69
|
|
|
70
70
|
<img src="media/demo.svg" width="600">
|
|
71
71
|
|
|
72
|
-
Feel free to play around with the code and fork this Repl at [https://repl.it/@vadimdemedes/ink-counter-demo](https://repl.it/@vadimdemedes/ink-counter-demo).
|
|
73
|
-
|
|
74
72
|
## Who's Using Ink?
|
|
75
73
|
|
|
76
74
|
- [Claude Code](https://github.com/anthropics/claude-code) - An agentic coding tool made by Anthropic.
|
|
77
75
|
- [Gemini CLI](https://github.com/google-gemini/gemini-cli) - An agentic coding tool made by Google.
|
|
78
|
-
- [GitHub Copilot
|
|
76
|
+
- [GitHub Copilot CLI](https://github.com/features/copilot/cli) - Just say what you want the shell to do.
|
|
79
77
|
- [Canva CLI](https://www.canva.dev/docs/apps/canva-cli/) - CLI for creating and managing Canva Apps.
|
|
80
78
|
- [Cloudflare's Wrangler](https://github.com/cloudflare/wrangler2) - The CLI for Cloudflare Workers.
|
|
81
79
|
- [Linear](https://linear.app) - Linear built an internal CLI for managing deployments, configs, and other housekeeping tasks.
|
|
@@ -123,15 +121,18 @@ Feel free to play around with the code and fork this Repl at [https://repl.it/@v
|
|
|
123
121
|
- [argonaut](https://github.com/darksworm/argonaut) - Manage Argo CD resources.
|
|
124
122
|
- [Qodo Command](https://github.com/qodo-ai/command) - Build, run, and manage AI agents.
|
|
125
123
|
- [Nanocoder](https://github.com/nano-collective/nanocoder) - A community-built, local-first AI coding agent with multi-provider support.
|
|
124
|
+
- [dev3000](https://github.com/vercel-labs/dev3000) - An AI agent MCP orchestrator and developer browser.
|
|
126
125
|
- [Neovate Code](https://github.com/neovateai/neovate-code) - An agentic coding tool made by AntGroup.
|
|
127
126
|
- [instagram-cli](https://github.com/supreme-gg-gg/instagram-cli) - Instagram client.
|
|
128
127
|
- [ElevenLabs CLI](https://github.com/elevenlabs/cli) - ElevenLabs agents client.
|
|
128
|
+
- [SSH AI Chat](https://github.com/miantiao-me/ssh-ai-chat) - Chat with AI over SSH.
|
|
129
129
|
|
|
130
130
|
*(PRs welcome. Append new entries at the end. Repos must have 100+ stars and showcase Ink beyond a basic list picker.)*
|
|
131
131
|
|
|
132
132
|
## Contents
|
|
133
133
|
|
|
134
134
|
- [Getting Started](#getting-started)
|
|
135
|
+
- [App Lifecycle](#app-lifecycle)
|
|
135
136
|
- [Components](#components)
|
|
136
137
|
- [`<Text>`](#text)
|
|
137
138
|
- [`<Box>`](#box)
|
|
@@ -147,13 +148,16 @@ Feel free to play around with the code and fork this Repl at [https://repl.it/@v
|
|
|
147
148
|
- [`useStderr`](#usestderr)
|
|
148
149
|
- [`useFocus`](#usefocusoptions)
|
|
149
150
|
- [`useFocusManager`](#usefocusmanager)
|
|
151
|
+
- [`useCursor`](#usecursor)
|
|
150
152
|
- [API](#api)
|
|
151
153
|
- [Testing](#testing)
|
|
152
154
|
- [Using React Devtools](#using-react-devtools)
|
|
153
155
|
- [Screen Reader Support](#screen-reader-support)
|
|
154
156
|
- [Useful Components](#useful-components)
|
|
155
157
|
- [Useful Hooks](#useful-hooks)
|
|
158
|
+
- [Recipes](#recipes)
|
|
156
159
|
- [Examples](#examples)
|
|
160
|
+
- [Continuous Integration](#continuous-integration)
|
|
157
161
|
|
|
158
162
|
## Getting Started
|
|
159
163
|
|
|
@@ -220,6 +224,22 @@ Think of it as if every `<div>` in the browser had `display: flex`.
|
|
|
220
224
|
See [`<Box>`](#box) built-in component below for documentation on how to use Flexbox layouts in Ink.
|
|
221
225
|
Note that all text must be wrapped in a [`<Text>`](#text) component.
|
|
222
226
|
|
|
227
|
+
## App Lifecycle
|
|
228
|
+
|
|
229
|
+
An Ink app is a Node.js process, so it stays alive only while there is active work in the event loop (timers, pending promises, [`useInput`](#useinputinputhandler-options) listening on `stdin`, etc.). If your component tree has no async work, the app will render once and exit immediately.
|
|
230
|
+
|
|
231
|
+
To exit the app, press **Ctrl+C** (enabled by default via [`exitOnCtrlC`](#exitonctrlc)), call [`exit()`](#exiterrororresult) from [`useApp`](#useapp) inside a component, or call [`unmount()`](#unmount) on the object returned by [`render()`](#rendertree-options).
|
|
232
|
+
|
|
233
|
+
Use [`waitUntilExit()`](#waituntilexit) to run code after the app is unmounted:
|
|
234
|
+
|
|
235
|
+
```jsx
|
|
236
|
+
const {waitUntilExit} = render(<MyApp />);
|
|
237
|
+
|
|
238
|
+
await waitUntilExit();
|
|
239
|
+
|
|
240
|
+
console.log('App exited');
|
|
241
|
+
```
|
|
242
|
+
|
|
223
243
|
## Components
|
|
224
244
|
|
|
225
245
|
### `<Text>`
|
|
@@ -1417,12 +1437,11 @@ For example, to implement a hanging indent component, you can indent all the lin
|
|
|
1417
1437
|
```jsx
|
|
1418
1438
|
import {render, Transform} from 'ink';
|
|
1419
1439
|
|
|
1420
|
-
const HangingIndent = ({
|
|
1440
|
+
const HangingIndent = ({indent = 4, children}) => (
|
|
1421
1441
|
<Transform
|
|
1422
1442
|
transform={(line, index) =>
|
|
1423
1443
|
index === 0 ? line : ' '.repeat(indent) + line
|
|
1424
1444
|
}
|
|
1425
|
-
{...props}
|
|
1426
1445
|
>
|
|
1427
1446
|
{children}
|
|
1428
1447
|
</Transform>
|
|
@@ -1436,9 +1455,8 @@ const text =
|
|
|
1436
1455
|
'of my hands only. I lived there two years and two months. At ' +
|
|
1437
1456
|
'present I am a sojourner in civilized life again.';
|
|
1438
1457
|
|
|
1439
|
-
// Other text properties are allowed as well
|
|
1440
1458
|
render(
|
|
1441
|
-
<HangingIndent
|
|
1459
|
+
<HangingIndent indent={4}>
|
|
1442
1460
|
{text}
|
|
1443
1461
|
</HangingIndent>
|
|
1444
1462
|
);
|
|
@@ -1582,6 +1600,16 @@ Default: `false`
|
|
|
1582
1600
|
If the Page Up or Page Down key was pressed, the corresponding property will be `true`.
|
|
1583
1601
|
For example, if the user presses Page Down, `key.pageDown` equals `true`.
|
|
1584
1602
|
|
|
1603
|
+
###### key.home
|
|
1604
|
+
|
|
1605
|
+
###### key.end
|
|
1606
|
+
|
|
1607
|
+
Type: `boolean`\
|
|
1608
|
+
Default: `false`
|
|
1609
|
+
|
|
1610
|
+
If the Home or End key was pressed, the corresponding property will be `true`.
|
|
1611
|
+
For example, if the user presses End, `key.end` equals `true`.
|
|
1612
|
+
|
|
1585
1613
|
###### key.meta
|
|
1586
1614
|
|
|
1587
1615
|
Type: `boolean`\
|
|
@@ -1589,6 +1617,41 @@ Default: `false`
|
|
|
1589
1617
|
|
|
1590
1618
|
[Meta key](https://en.wikipedia.org/wiki/Meta_key) was pressed.
|
|
1591
1619
|
|
|
1620
|
+
###### key.super
|
|
1621
|
+
|
|
1622
|
+
Type: `boolean`\
|
|
1623
|
+
Default: `false`
|
|
1624
|
+
|
|
1625
|
+
Super key (Cmd on macOS, Win on Windows) was pressed. Requires [kitty keyboard protocol](#kittykeyboard).
|
|
1626
|
+
|
|
1627
|
+
###### key.hyper
|
|
1628
|
+
|
|
1629
|
+
Type: `boolean`\
|
|
1630
|
+
Default: `false`
|
|
1631
|
+
|
|
1632
|
+
Hyper key was pressed. Requires [kitty keyboard protocol](#kittykeyboard).
|
|
1633
|
+
|
|
1634
|
+
###### key.capsLock
|
|
1635
|
+
|
|
1636
|
+
Type: `boolean`\
|
|
1637
|
+
Default: `false`
|
|
1638
|
+
|
|
1639
|
+
Caps Lock was active. Requires [kitty keyboard protocol](#kittykeyboard).
|
|
1640
|
+
|
|
1641
|
+
###### key.numLock
|
|
1642
|
+
|
|
1643
|
+
Type: `boolean`\
|
|
1644
|
+
Default: `false`
|
|
1645
|
+
|
|
1646
|
+
Num Lock was active. Requires [kitty keyboard protocol](#kittykeyboard).
|
|
1647
|
+
|
|
1648
|
+
###### key.eventType
|
|
1649
|
+
|
|
1650
|
+
Type: `'press' | 'repeat' | 'release'`\
|
|
1651
|
+
Default: `undefined`
|
|
1652
|
+
|
|
1653
|
+
The type of key event. Only available with [kitty keyboard protocol](#kittykeyboard). Without the protocol, this property is `undefined`.
|
|
1654
|
+
|
|
1592
1655
|
#### options
|
|
1593
1656
|
|
|
1594
1657
|
Type: `object`
|
|
@@ -1605,17 +1668,20 @@ Useful when there are multiple `useInput` hooks used at once to avoid handling t
|
|
|
1605
1668
|
|
|
1606
1669
|
`useApp` is a React hook that exposes a method to manually exit the app (unmount).
|
|
1607
1670
|
|
|
1608
|
-
#### exit(
|
|
1671
|
+
#### exit(errorOrResult?)
|
|
1609
1672
|
|
|
1610
1673
|
Type: `Function`
|
|
1611
1674
|
|
|
1612
1675
|
Exit (unmount) the whole Ink app.
|
|
1613
1676
|
|
|
1614
|
-
#####
|
|
1677
|
+
##### errorOrResult
|
|
1615
1678
|
|
|
1616
|
-
Type: `Error`
|
|
1679
|
+
Type: `Error | unknown`
|
|
1617
1680
|
|
|
1618
|
-
Optional
|
|
1681
|
+
Optional value that controls how [`waitUntilExit`](waituntilexit) settles:
|
|
1682
|
+
- `exit()` resolves with `undefined`.
|
|
1683
|
+
- `exit(error)` rejects when `error` is an `Error`.
|
|
1684
|
+
- `exit(value)` resolves with `value`.
|
|
1619
1685
|
|
|
1620
1686
|
```js
|
|
1621
1687
|
import {useApp} from 'ink';
|
|
@@ -1962,6 +2028,55 @@ const Example = () => {
|
|
|
1962
2028
|
};
|
|
1963
2029
|
```
|
|
1964
2030
|
|
|
2031
|
+
### useCursor()
|
|
2032
|
+
|
|
2033
|
+
`useCursor` lets you control the terminal cursor position after each render. This is essential for IME (Input Method Editor) support, where the composing character is displayed at the cursor location.
|
|
2034
|
+
|
|
2035
|
+
```jsx
|
|
2036
|
+
import {useState} from 'react';
|
|
2037
|
+
import {Box, Text, useCursor} from 'ink';
|
|
2038
|
+
import stringWidth from 'string-width';
|
|
2039
|
+
|
|
2040
|
+
const TextInput = () => {
|
|
2041
|
+
const [text, setText] = useState('');
|
|
2042
|
+
const {setCursorPosition} = useCursor();
|
|
2043
|
+
|
|
2044
|
+
const prompt = '> ';
|
|
2045
|
+
setCursorPosition({x: stringWidth(prompt + text), y: 1});
|
|
2046
|
+
|
|
2047
|
+
return (
|
|
2048
|
+
<Box flexDirection="column">
|
|
2049
|
+
<Text>Type here:</Text>
|
|
2050
|
+
<Text>{prompt}{text}</Text>
|
|
2051
|
+
</Box>
|
|
2052
|
+
);
|
|
2053
|
+
};
|
|
2054
|
+
```
|
|
2055
|
+
|
|
2056
|
+
#### setCursorPosition(position)
|
|
2057
|
+
|
|
2058
|
+
Set the cursor position relative to the Ink output. Pass `undefined` to hide the cursor.
|
|
2059
|
+
|
|
2060
|
+
##### position
|
|
2061
|
+
|
|
2062
|
+
Type: `object | undefined`
|
|
2063
|
+
|
|
2064
|
+
Use [`string-width`](https://github.com/sindresorhus/string-width) to calculate `x` for strings containing wide characters (CJK, emoji).
|
|
2065
|
+
|
|
2066
|
+
See a full example at [examples/cursor-ime](examples/cursor-ime/cursor-ime.tsx).
|
|
2067
|
+
|
|
2068
|
+
###### x
|
|
2069
|
+
|
|
2070
|
+
Type: `number`
|
|
2071
|
+
|
|
2072
|
+
Column position (0-based).
|
|
2073
|
+
|
|
2074
|
+
###### y
|
|
2075
|
+
|
|
2076
|
+
Type: `number`
|
|
2077
|
+
|
|
2078
|
+
Row position from the top of the Ink output (0 = first line).
|
|
2079
|
+
|
|
1965
2080
|
### useIsScreenReaderEnabled()
|
|
1966
2081
|
|
|
1967
2082
|
Returns whether a screen reader is enabled. This is useful when you want to render different output for screen readers.
|
|
@@ -1992,7 +2107,7 @@ Mount a component and render the output.
|
|
|
1992
2107
|
|
|
1993
2108
|
##### tree
|
|
1994
2109
|
|
|
1995
|
-
Type: `
|
|
2110
|
+
Type: `ReactNode`
|
|
1996
2111
|
|
|
1997
2112
|
##### options
|
|
1998
2113
|
|
|
@@ -2045,6 +2160,13 @@ Default: `undefined`
|
|
|
2045
2160
|
|
|
2046
2161
|
Runs the given callback after each render and re-render with a metrics object.
|
|
2047
2162
|
|
|
2163
|
+
###### isScreenReaderEnabled
|
|
2164
|
+
|
|
2165
|
+
Type: `boolean`\
|
|
2166
|
+
Default: `process.env['INK_SCREEN_READER'] === 'true'`
|
|
2167
|
+
|
|
2168
|
+
Enable screen reader support. See [Screen Reader Support](#screen-reader-support).
|
|
2169
|
+
|
|
2048
2170
|
###### debug
|
|
2049
2171
|
|
|
2050
2172
|
Type: `boolean`\
|
|
@@ -2070,6 +2192,133 @@ Default: `false`
|
|
|
2070
2192
|
Enable incremental rendering mode which only updates changed lines instead of redrawing the entire output.
|
|
2071
2193
|
This can reduce flickering and improve performance for frequently updating UIs.
|
|
2072
2194
|
|
|
2195
|
+
###### concurrent
|
|
2196
|
+
|
|
2197
|
+
Type: `boolean`\
|
|
2198
|
+
Default: `false`
|
|
2199
|
+
|
|
2200
|
+
Enable React Concurrent Rendering mode.
|
|
2201
|
+
|
|
2202
|
+
When enabled:
|
|
2203
|
+
- Suspense boundaries work correctly with async data fetching
|
|
2204
|
+
- `useTransition` and `useDeferredValue` hooks are fully functional
|
|
2205
|
+
- Updates can be interrupted for higher priority work
|
|
2206
|
+
|
|
2207
|
+
```jsx
|
|
2208
|
+
render(<MyApp />, {concurrent: true});
|
|
2209
|
+
```
|
|
2210
|
+
|
|
2211
|
+
**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.
|
|
2212
|
+
|
|
2213
|
+
###### kittyKeyboard
|
|
2214
|
+
|
|
2215
|
+
Type: `object`\
|
|
2216
|
+
Default: `undefined`
|
|
2217
|
+
|
|
2218
|
+
Enable the [kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/) for enhanced keyboard input handling. When enabled, terminals that support the protocol will report additional key information including `super`, `hyper`, `capsLock`, `numLock` modifiers and `eventType` (press/repeat/release).
|
|
2219
|
+
|
|
2220
|
+
```jsx
|
|
2221
|
+
import {render} from 'ink';
|
|
2222
|
+
|
|
2223
|
+
render(<MyApp />, {kittyKeyboard: {mode: 'auto'}});
|
|
2224
|
+
```
|
|
2225
|
+
|
|
2226
|
+
```jsx
|
|
2227
|
+
import {render} from 'ink';
|
|
2228
|
+
|
|
2229
|
+
render(<MyApp />, {
|
|
2230
|
+
kittyKeyboard: {
|
|
2231
|
+
mode: 'enabled',
|
|
2232
|
+
flags: ['disambiguateEscapeCodes', 'reportEventTypes'],
|
|
2233
|
+
},
|
|
2234
|
+
});
|
|
2235
|
+
```
|
|
2236
|
+
|
|
2237
|
+
**kittyKeyboard.mode**
|
|
2238
|
+
|
|
2239
|
+
Type: `'auto' | 'enabled' | 'disabled'`\
|
|
2240
|
+
Default: `'auto'`
|
|
2241
|
+
|
|
2242
|
+
- `'auto'`: Detect terminal support using a heuristic precheck (known terminals like kitty, WezTerm, Ghostty) followed by a protocol query confirmation (`CSI ? u`). The protocol is only enabled if the terminal responds to the query within a short timeout.
|
|
2243
|
+
- `'enabled'`: Force enable the protocol. Both stdin and stdout must be TTYs.
|
|
2244
|
+
- `'disabled'`: Never enable the protocol.
|
|
2245
|
+
|
|
2246
|
+
**kittyKeyboard.flags**
|
|
2247
|
+
|
|
2248
|
+
Type: `string[]`\
|
|
2249
|
+
Default: `['disambiguateEscapeCodes']`
|
|
2250
|
+
|
|
2251
|
+
Protocol flags to request from the terminal. Pass an array of flag name strings.
|
|
2252
|
+
|
|
2253
|
+
Available flags:
|
|
2254
|
+
- `'disambiguateEscapeCodes'` - Disambiguate escape codes
|
|
2255
|
+
- `'reportEventTypes'` - Report key press, repeat, and release events
|
|
2256
|
+
- `'reportAlternateKeys'` - Report alternate key encodings
|
|
2257
|
+
- `'reportAllKeysAsEscapeCodes'` - Report all keys as escape codes
|
|
2258
|
+
- `'reportAssociatedText'` - Report associated text with key events
|
|
2259
|
+
|
|
2260
|
+
**Behavior notes**
|
|
2261
|
+
|
|
2262
|
+
When the kitty keyboard protocol is enabled, input handling changes in several ways:
|
|
2263
|
+
|
|
2264
|
+
- **Non-printable keys produce empty input.** Keys like function keys (F1-F35), modifier-only keys (Shift, Control, Super), media keys, Caps Lock, Print Screen, and similar keys will not produce any text in the `input` parameter of `useInput`. They can still be detected via the `key` object properties.
|
|
2265
|
+
- **Ctrl+letter shortcuts work as expected.** When the terminal sends `Ctrl+letter` as codepoint 1-26 (the kitty CSI-u alternate form), `input` is set to the letter name (e.g. `'c'` for `Ctrl+C`) and `key.ctrl` is `true`. This ensures `exitOnCtrlC` and custom `Ctrl+letter` handlers continue to work regardless of which codepoint form the terminal uses.
|
|
2266
|
+
- **Key disambiguation.** The protocol allows the terminal to distinguish between keys that normally produce the same escape sequence. For example:
|
|
2267
|
+
- `Ctrl+I` vs `Tab` - without the protocol, both produce the same byte (`\x09`). With the protocol, they are reported as distinct keys.
|
|
2268
|
+
- `Shift+Enter` vs `Enter` - the shift modifier is correctly reported.
|
|
2269
|
+
- `Escape` key vs `Ctrl+[` - these are disambiguated.
|
|
2270
|
+
- **Event types.** With the `reportEventTypes` flag, key press, repeat, and release events are distinguished via `key.eventType`.
|
|
2271
|
+
|
|
2272
|
+
#### renderToString(tree, options?)
|
|
2273
|
+
|
|
2274
|
+
Returns: `string`
|
|
2275
|
+
|
|
2276
|
+
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.
|
|
2277
|
+
|
|
2278
|
+
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.
|
|
2279
|
+
|
|
2280
|
+
```jsx
|
|
2281
|
+
import {renderToString, Text, Box} from 'ink';
|
|
2282
|
+
|
|
2283
|
+
const output = renderToString(
|
|
2284
|
+
<Box padding={1}>
|
|
2285
|
+
<Text color="green">Hello World</Text>
|
|
2286
|
+
</Box>,
|
|
2287
|
+
);
|
|
2288
|
+
|
|
2289
|
+
console.log(output);
|
|
2290
|
+
```
|
|
2291
|
+
|
|
2292
|
+
**Notes:**
|
|
2293
|
+
|
|
2294
|
+
- 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.
|
|
2295
|
+
- `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.
|
|
2296
|
+
- `useLayoutEffect` callbacks fire synchronously during commit, so state updates they trigger **will** be reflected in the output.
|
|
2297
|
+
- The `<Static>` component is supported — its output is prepended to the dynamic output.
|
|
2298
|
+
- If a component throws during rendering, the error is propagated to the caller after cleanup.
|
|
2299
|
+
|
|
2300
|
+
##### tree
|
|
2301
|
+
|
|
2302
|
+
Type: `ReactNode`
|
|
2303
|
+
|
|
2304
|
+
##### options
|
|
2305
|
+
|
|
2306
|
+
Type: `object`
|
|
2307
|
+
|
|
2308
|
+
###### columns
|
|
2309
|
+
|
|
2310
|
+
Type: `number`\
|
|
2311
|
+
Default: `80`
|
|
2312
|
+
|
|
2313
|
+
Width of the virtual terminal in columns. Controls where text wrapping occurs.
|
|
2314
|
+
|
|
2315
|
+
```jsx
|
|
2316
|
+
const output = renderToString(<Text>{'A'.repeat(100)}</Text>, {
|
|
2317
|
+
columns: 40,
|
|
2318
|
+
});
|
|
2319
|
+
// Text wraps at 40 columns
|
|
2320
|
+
```
|
|
2321
|
+
|
|
2073
2322
|
#### Instance
|
|
2074
2323
|
|
|
2075
2324
|
This is the object that `render()` returns.
|
|
@@ -2080,7 +2329,7 @@ Replace the previous root node with a new one or update the props of the current
|
|
|
2080
2329
|
|
|
2081
2330
|
###### tree
|
|
2082
2331
|
|
|
2083
|
-
Type: `
|
|
2332
|
+
Type: `ReactNode`
|
|
2084
2333
|
|
|
2085
2334
|
```jsx
|
|
2086
2335
|
// Update props of the root node
|
|
@@ -2103,7 +2352,9 @@ unmount();
|
|
|
2103
2352
|
|
|
2104
2353
|
##### waitUntilExit()
|
|
2105
2354
|
|
|
2106
|
-
Returns a promise that
|
|
2355
|
+
Returns a promise that settles when the app is unmounted.
|
|
2356
|
+
|
|
2357
|
+
It resolves with the value passed to `exit(value)` and rejects with the error passed to `exit(error)`.
|
|
2107
2358
|
|
|
2108
2359
|
```jsx
|
|
2109
2360
|
const {unmount, waitUntilExit} = render(<MyApp />);
|
|
@@ -2113,6 +2364,12 @@ setTimeout(unmount, 1000);
|
|
|
2113
2364
|
await waitUntilExit(); // resolves after `unmount()` is called
|
|
2114
2365
|
```
|
|
2115
2366
|
|
|
2367
|
+
##### cleanup()
|
|
2368
|
+
|
|
2369
|
+
Delete the internal Ink instance associated with the current `stdout`.
|
|
2370
|
+
This is mostly useful for advanced cases (for example, tests) where you need `render()` to create a fresh instance for the same stream.
|
|
2371
|
+
This does not unmount the current app.
|
|
2372
|
+
|
|
2116
2373
|
##### clear()
|
|
2117
2374
|
|
|
2118
2375
|
Clear output.
|
|
@@ -2325,11 +2582,18 @@ For a practical example of building an accessible component, see the [ARIA examp
|
|
|
2325
2582
|
- [ink-chart](https://github.com/pppp606/ink-chart) - Sparkline and bar chart.
|
|
2326
2583
|
- [ink-scroll-view](https://github.com/ByteLandTechnology/ink-scroll-view) - Scroll container.
|
|
2327
2584
|
- [ink-scroll-list](https://github.com/ByteLandTechnology/ink-scroll-list) - Scrollable list.
|
|
2585
|
+
- [ink-stepper](https://github.com/archcorsair/ink-stepper) - Step-by-step wizard.
|
|
2586
|
+
- [ink-virtual-list](https://github.com/archcorsair/ink-virtual-list) - Virtualized list that renders only visible items for performance.
|
|
2587
|
+
- [ink-color-picker](https://github.com/sina-byn/ink-color-picker) - Color picker.
|
|
2328
2588
|
|
|
2329
2589
|
## Useful Hooks
|
|
2330
2590
|
|
|
2331
2591
|
- [ink-use-stdout-dimensions](https://github.com/cameronhunter/ink-monorepo/tree/master/packages/ink-use-stdout-dimensions) - Subscribe to stdout dimensions.
|
|
2332
2592
|
|
|
2593
|
+
## Recipes
|
|
2594
|
+
|
|
2595
|
+
- [Routing with React Router](recipes/routing.md) - Navigate between routes using `MemoryRouter`.
|
|
2596
|
+
|
|
2333
2597
|
## Examples
|
|
2334
2598
|
|
|
2335
2599
|
The [`examples`](/examples) directory contains a set of real examples. You can run them with:
|
|
@@ -2351,6 +2615,20 @@ npm run example examples/[example name]
|
|
|
2351
2615
|
- [Write to stderr](examples/use-stderr/use-stderr.tsx) - Write to stderr, bypassing main Ink output.
|
|
2352
2616
|
- [Static](examples/static/static.tsx) - Use the `<Static>` component to render permanent output.
|
|
2353
2617
|
- [Child process](examples/subprocess-output) - Renders output from a child process.
|
|
2618
|
+
- [Router](examples/router/router.tsx) - Navigate between routes using React Router's `MemoryRouter`.
|
|
2619
|
+
|
|
2620
|
+
## Continuous Integration
|
|
2621
|
+
|
|
2622
|
+
When running on CI (detected via the `CI` environment variable), Ink adapts its rendering:
|
|
2623
|
+
|
|
2624
|
+
- Only the last frame is rendered on exit, instead of continuously updating the terminal. This is because most CI environments don't support the ANSI escape sequences used to overwrite previous output.
|
|
2625
|
+
- Terminal resize events are not listened to.
|
|
2626
|
+
|
|
2627
|
+
If your CI environment supports full terminal rendering and you want to opt out of this behavior, set `CI=false`:
|
|
2628
|
+
|
|
2629
|
+
```sh
|
|
2630
|
+
CI=false node my-cli.js
|
|
2631
|
+
```
|
|
2354
2632
|
|
|
2355
2633
|
## Maintainers
|
|
2356
2634
|
|