ink 6.7.0 → 7.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/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/AnimationContext.d.ts +9 -0
- package/build/components/AnimationContext.js +13 -0
- package/build/components/AnimationContext.js.map +1 -0
- package/build/components/App.d.ts +5 -2
- package/build/components/App.js +192 -41
- package/build/components/App.js.map +1 -1
- package/build/components/AppContext.d.ts +33 -3
- package/build/components/AppContext.js +2 -1
- package/build/components/AppContext.js.map +1 -1
- package/build/components/Box.d.ts +16 -3
- package/build/components/ErrorBoundary.d.ts +2 -2
- package/build/components/ErrorOverview.js +6 -6
- package/build/components/ErrorOverview.js.map +1 -1
- package/build/components/Static.js.map +1 -1
- package/build/components/StdinContext.d.ts +7 -1
- package/build/components/StdinContext.js +1 -0
- package/build/components/StdinContext.js.map +1 -1
- package/build/components/Text.d.ts +1 -1
- package/build/components/Text.js +1 -1
- package/build/components/Text.js.map +1 -1
- package/build/components/Transform.d.ts +1 -1
- package/build/devtools-window-polyfill.js +7 -4
- package/build/devtools-window-polyfill.js.map +1 -1
- package/build/devtools.js +31 -6
- package/build/devtools.js.map +1 -1
- package/build/dom.d.ts +5 -1
- package/build/dom.js +25 -5
- package/build/dom.js.map +1 -1
- package/build/hooks/use-animation.d.ts +49 -0
- package/build/hooks/use-animation.js +87 -0
- package/build/hooks/use-animation.js.map +1 -0
- package/build/hooks/use-app.d.ts +5 -2
- package/build/hooks/use-app.js +1 -1
- package/build/hooks/use-box-metrics.d.ts +59 -0
- package/build/hooks/use-box-metrics.js +88 -0
- package/build/hooks/use-box-metrics.js.map +1 -0
- package/build/hooks/use-cursor.d.ts +1 -1
- package/build/hooks/use-cursor.js +1 -1
- package/build/hooks/use-focus-manager.d.ts +17 -2
- package/build/hooks/use-focus-manager.js +2 -1
- package/build/hooks/use-focus-manager.js.map +1 -1
- package/build/hooks/use-focus.d.ts +2 -1
- package/build/hooks/use-focus.js +5 -4
- package/build/hooks/use-focus.js.map +1 -1
- package/build/hooks/use-input.d.ts +2 -1
- package/build/hooks/use-input.js +82 -80
- package/build/hooks/use-input.js.map +1 -1
- package/build/hooks/use-is-screen-reader-enabled.d.ts +2 -1
- package/build/hooks/use-is-screen-reader-enabled.js +2 -1
- package/build/hooks/use-is-screen-reader-enabled.js.map +1 -1
- package/build/hooks/use-paste.d.ts +35 -0
- package/build/hooks/use-paste.js +62 -0
- package/build/hooks/use-paste.js.map +1 -0
- package/build/hooks/use-stderr.d.ts +1 -1
- package/build/hooks/use-stderr.js +1 -1
- package/build/hooks/use-stdin.d.ts +4 -2
- package/build/hooks/use-stdin.js +2 -1
- package/build/hooks/use-stdin.js.map +1 -1
- package/build/hooks/use-stdout.d.ts +1 -1
- package/build/hooks/use-stdout.js +1 -1
- package/build/hooks/use-window-size.d.ts +18 -0
- package/build/hooks/use-window-size.js +22 -0
- package/build/hooks/use-window-size.js.map +1 -0
- package/build/index.d.ts +10 -1
- package/build/index.js +5 -0
- package/build/index.js.map +1 -1
- package/build/ink.d.ts +55 -6
- package/build/ink.js +433 -162
- package/build/ink.js.map +1 -1
- package/build/input-parser.d.ts +10 -0
- package/build/input-parser.js +194 -0
- package/build/input-parser.js.map +1 -0
- package/build/log-update.d.ts +1 -0
- package/build/log-update.js +13 -1
- package/build/log-update.js.map +1 -1
- package/build/measure-element.d.ts +4 -0
- package/build/measure-element.js +4 -0
- package/build/measure-element.js.map +1 -1
- package/build/output.d.ts +1 -0
- package/build/output.js +63 -5
- package/build/output.js.map +1 -1
- package/build/parse-keypress.d.ts +1 -3
- package/build/parse-keypress.js +19 -17
- package/build/parse-keypress.js.map +1 -1
- package/build/reconciler.js +48 -19
- package/build/reconciler.js.map +1 -1
- package/build/render-border.js +29 -18
- package/build/render-border.js.map +1 -1
- package/build/render-to-string.d.ts +38 -0
- package/build/render-to-string.js +116 -0
- package/build/render-to-string.js.map +1 -0
- package/build/render.d.ts +69 -3
- package/build/render.js +18 -11
- 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/styles.d.ts +78 -16
- package/build/styles.js +102 -31
- package/build/styles.js.map +1 -1
- package/build/utils.d.ts +9 -0
- package/build/utils.js +19 -0
- package/build/utils.js.map +1 -0
- package/build/wrap-text.js +7 -0
- package/build/wrap-text.js.map +1 -1
- package/build/write-synchronized.d.ts +1 -1
- package/build/write-synchronized.js +4 -2
- package/build/write-synchronized.js.map +1 -1
- package/package.json +40 -101
- package/readme.md +674 -56
- package/build/apply-styles.js +0 -175
- package/build/build-layout.js +0 -77
- package/build/calculate-wrapped-text.js +0 -53
- package/build/components/Color.js +0 -62
- package/build/experimental/apply-style.js +0 -140
- package/build/experimental/dom.js +0 -123
- package/build/experimental/output.js +0 -91
- package/build/experimental/reconciler.js +0 -141
- package/build/experimental/renderer.js +0 -81
- package/build/hooks/useInput.js +0 -38
- package/build/instance.js +0 -205
- package/build/options.d.ts +0 -52
- package/build/options.js +0 -2
- package/build/options.js.map +0 -1
- package/build/screen-reader-update.d.ts +0 -13
- package/build/screen-reader-update.js +0 -38
- package/build/screen-reader-update.js.map +0 -1
package/readme.md
CHANGED
|
@@ -24,6 +24,8 @@ Since Ink is a React renderer, all features of React are supported.
|
|
|
24
24
|
Head over to the [React](https://reactjs.org) website for documentation on how to use it.
|
|
25
25
|
Only Ink's methods are documented in this readme.
|
|
26
26
|
|
|
27
|
+
**Fully AI-generated pull requests are not accepted. You can use AI, but should be verified and cleaned up by a human. Only Opus 4.6+ (high-effort) and Codex 5.4+ (extra high) are accepted models. Preferably created with Opus and verified by Codex.**
|
|
28
|
+
|
|
27
29
|
---
|
|
28
30
|
|
|
29
31
|
<div align="center">
|
|
@@ -42,6 +44,9 @@ Only Ink's methods are documented in this readme.
|
|
|
42
44
|
npm install ink react
|
|
43
45
|
```
|
|
44
46
|
|
|
47
|
+
> [!NOTE]
|
|
48
|
+
> This readme documents the upcoming version of Ink. For the latest stable release, see [Ink on npm](https://www.npmjs.com/package/ink).
|
|
49
|
+
|
|
45
50
|
## Usage
|
|
46
51
|
|
|
47
52
|
```jsx
|
|
@@ -69,8 +74,6 @@ render(<Counter />);
|
|
|
69
74
|
|
|
70
75
|
<img src="media/demo.svg" width="600">
|
|
71
76
|
|
|
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
77
|
## Who's Using Ink?
|
|
75
78
|
|
|
76
79
|
- [Claude Code](https://github.com/anthropics/claude-code) - An agentic coding tool made by Anthropic.
|
|
@@ -129,11 +132,12 @@ Feel free to play around with the code and fork this Repl at [https://repl.it/@v
|
|
|
129
132
|
- [ElevenLabs CLI](https://github.com/elevenlabs/cli) - ElevenLabs agents client.
|
|
130
133
|
- [SSH AI Chat](https://github.com/miantiao-me/ssh-ai-chat) - Chat with AI over SSH.
|
|
131
134
|
|
|
132
|
-
|
|
135
|
+
_(PRs welcome. Append new entries at the end. Repos must have 100+ stars and showcase Ink beyond a basic list picker.)_
|
|
133
136
|
|
|
134
137
|
## Contents
|
|
135
138
|
|
|
136
139
|
- [Getting Started](#getting-started)
|
|
140
|
+
- [App Lifecycle](#app-lifecycle)
|
|
137
141
|
- [Components](#components)
|
|
138
142
|
- [`<Text>`](#text)
|
|
139
143
|
- [`<Box>`](#box)
|
|
@@ -143,20 +147,26 @@ Feel free to play around with the code and fork this Repl at [https://repl.it/@v
|
|
|
143
147
|
- [`<Transform>`](#transform)
|
|
144
148
|
- [Hooks](#hooks)
|
|
145
149
|
- [`useInput`](#useinputinputhandler-options)
|
|
150
|
+
- [`usePaste`](#usepastehandler-options)
|
|
146
151
|
- [`useApp`](#useapp)
|
|
147
152
|
- [`useStdin`](#usestdin)
|
|
148
153
|
- [`useStdout`](#usestdout)
|
|
154
|
+
- [`useBoxMetrics`](#useboxmetricsref)
|
|
149
155
|
- [`useStderr`](#usestderr)
|
|
156
|
+
- [`useWindowSize`](#usewindowsize)
|
|
150
157
|
- [`useFocus`](#usefocusoptions)
|
|
151
158
|
- [`useFocusManager`](#usefocusmanager)
|
|
152
159
|
- [`useCursor`](#usecursor)
|
|
160
|
+
- [`useAnimation`](#useanimationoptions)
|
|
153
161
|
- [API](#api)
|
|
154
162
|
- [Testing](#testing)
|
|
155
163
|
- [Using React Devtools](#using-react-devtools)
|
|
156
164
|
- [Screen Reader Support](#screen-reader-support)
|
|
157
165
|
- [Useful Components](#useful-components)
|
|
158
166
|
- [Useful Hooks](#useful-hooks)
|
|
167
|
+
- [Recipes](#recipes)
|
|
159
168
|
- [Examples](#examples)
|
|
169
|
+
- [Continuous Integration](#continuous-integration)
|
|
160
170
|
|
|
161
171
|
## Getting Started
|
|
162
172
|
|
|
@@ -223,6 +233,22 @@ Think of it as if every `<div>` in the browser had `display: flex`.
|
|
|
223
233
|
See [`<Box>`](#box) built-in component below for documentation on how to use Flexbox layouts in Ink.
|
|
224
234
|
Note that all text must be wrapped in a [`<Text>`](#text) component.
|
|
225
235
|
|
|
236
|
+
## App Lifecycle
|
|
237
|
+
|
|
238
|
+
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.
|
|
239
|
+
|
|
240
|
+
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).
|
|
241
|
+
|
|
242
|
+
Use [`waitUntilExit()`](#waituntilexit) to run code after the app is unmounted:
|
|
243
|
+
|
|
244
|
+
```jsx
|
|
245
|
+
const {waitUntilExit} = render(<MyApp />);
|
|
246
|
+
|
|
247
|
+
await waitUntilExit();
|
|
248
|
+
|
|
249
|
+
console.log('App exited');
|
|
250
|
+
```
|
|
251
|
+
|
|
226
252
|
## Components
|
|
227
253
|
|
|
228
254
|
### `<Text>`
|
|
@@ -250,7 +276,8 @@ const Example = () => (
|
|
|
250
276
|
render(<Example />);
|
|
251
277
|
```
|
|
252
278
|
|
|
253
|
-
|
|
279
|
+
> [!NOTE]
|
|
280
|
+
> `<Text>` allows only text nodes and nested `<Text>` components inside of it. For example, `<Box>` component can't be used inside `<Text>`.
|
|
254
281
|
|
|
255
282
|
#### color
|
|
256
283
|
|
|
@@ -342,11 +369,12 @@ Invert background and foreground colors.
|
|
|
342
369
|
#### wrap
|
|
343
370
|
|
|
344
371
|
Type: `string`\
|
|
345
|
-
Allowed values: `wrap` `truncate` `truncate-start` `truncate-middle` `truncate-end`\
|
|
372
|
+
Allowed values: `wrap` `hard` `truncate` `truncate-start` `truncate-middle` `truncate-end`\
|
|
346
373
|
Default: `wrap`
|
|
347
374
|
|
|
348
375
|
This property tells Ink to wrap or truncate text if its width is larger than the container.
|
|
349
376
|
If `wrap` is passed (the default), Ink will wrap text and split it into multiple lines.
|
|
377
|
+
If `hard` is passed, Ink will fill each line to the full column width, breaking words as necessary.
|
|
350
378
|
If `truncate-*` is passed, Ink will truncate text instead, resulting in one line of text with the rest cut off.
|
|
351
379
|
|
|
352
380
|
```jsx
|
|
@@ -355,6 +383,11 @@ If `truncate-*` is passed, Ink will truncate text instead, resulting in one line
|
|
|
355
383
|
</Box>
|
|
356
384
|
//=> 'Hello\nWorld'
|
|
357
385
|
|
|
386
|
+
<Box width={7}>
|
|
387
|
+
<Text wrap="hard">Hello World</Text>
|
|
388
|
+
</Box>
|
|
389
|
+
//=> 'Hello W\norld'
|
|
390
|
+
|
|
358
391
|
// `truncate` is an alias to `truncate-end`
|
|
359
392
|
<Box width={7}>
|
|
360
393
|
<Text wrap="truncate">Hello World</Text>
|
|
@@ -448,11 +481,33 @@ Percentages aren't supported yet; see https://github.com/facebook/yoga/issues/87
|
|
|
448
481
|
|
|
449
482
|
##### minHeight
|
|
450
483
|
|
|
484
|
+
Type: `number` `string`
|
|
485
|
+
|
|
486
|
+
Sets a minimum height of the element in lines (rows).
|
|
487
|
+
You can also set it as a percentage, which will calculate the minimum height based on the height of the parent element.
|
|
488
|
+
|
|
489
|
+
##### maxWidth
|
|
490
|
+
|
|
451
491
|
Type: `number`
|
|
452
492
|
|
|
453
|
-
Sets a
|
|
493
|
+
Sets a maximum width of the element.
|
|
454
494
|
Percentages aren't supported yet; see https://github.com/facebook/yoga/issues/872.
|
|
455
495
|
|
|
496
|
+
##### maxHeight
|
|
497
|
+
|
|
498
|
+
Type: `number` `string`
|
|
499
|
+
|
|
500
|
+
Sets a maximum height of the element in lines (rows).
|
|
501
|
+
You can also set it as a percentage, which will calculate the maximum height based on the height of the parent element.
|
|
502
|
+
|
|
503
|
+
##### aspectRatio
|
|
504
|
+
|
|
505
|
+
Type: `number`
|
|
506
|
+
|
|
507
|
+
Defines the aspect ratio (width/height) for the element.
|
|
508
|
+
|
|
509
|
+
Use it with at least one size constraint (`width`, `height`, `minHeight`, or `maxHeight`) so Ink can derive the missing dimension.
|
|
510
|
+
|
|
456
511
|
#### Padding
|
|
457
512
|
|
|
458
513
|
##### paddingTop
|
|
@@ -757,7 +812,7 @@ See [flex-wrap](https://css-tricks.com/almanac/properties/f/flex-wrap/).
|
|
|
757
812
|
##### alignItems
|
|
758
813
|
|
|
759
814
|
Type: `string`\
|
|
760
|
-
Allowed values: `flex-start` `center` `flex-end`
|
|
815
|
+
Allowed values: `flex-start` `center` `flex-end` `stretch` `baseline`
|
|
761
816
|
|
|
762
817
|
See [align-items](https://css-tricks.com/almanac/properties/a/align-items/).
|
|
763
818
|
|
|
@@ -815,7 +870,7 @@ See [align-items](https://css-tricks.com/almanac/properties/a/align-items/).
|
|
|
815
870
|
|
|
816
871
|
Type: `string`\
|
|
817
872
|
Default: `auto`\
|
|
818
|
-
Allowed values: `auto` `flex-start` `center` `flex-end`
|
|
873
|
+
Allowed values: `auto` `flex-start` `center` `flex-end` `stretch` `baseline`
|
|
819
874
|
|
|
820
875
|
See [align-self](https://css-tricks.com/almanac/properties/a/align-self/).
|
|
821
876
|
|
|
@@ -848,6 +903,16 @@ See [align-self](https://css-tricks.com/almanac/properties/a/align-self/).
|
|
|
848
903
|
// X
|
|
849
904
|
```
|
|
850
905
|
|
|
906
|
+
##### alignContent
|
|
907
|
+
|
|
908
|
+
Type: `string`\
|
|
909
|
+
Default: `flex-start`\
|
|
910
|
+
Allowed values: `flex-start` `flex-end` `center` `stretch` `space-between` `space-around` `space-evenly`
|
|
911
|
+
|
|
912
|
+
Defines alignment between flex lines on the cross axis when `flexWrap` creates multiple lines.
|
|
913
|
+
See [align-content](https://css-tricks.com/almanac/properties/a/align-content/).
|
|
914
|
+
Unlike CSS (`stretch`), Ink defaults to `flex-start` so wrapped lines stay compact and fixed-height boxes don't gain unexpected empty rows unless you opt in to stretching.
|
|
915
|
+
|
|
851
916
|
##### justifyContent
|
|
852
917
|
|
|
853
918
|
Type: `string`\
|
|
@@ -890,6 +955,46 @@ See [justify-content](https://css-tricks.com/almanac/properties/j/justify-conten
|
|
|
890
955
|
// [ X Y ]
|
|
891
956
|
```
|
|
892
957
|
|
|
958
|
+
#### Position
|
|
959
|
+
|
|
960
|
+
##### position
|
|
961
|
+
|
|
962
|
+
Type: `string`\
|
|
963
|
+
Allowed values: `relative` `absolute` `static`\
|
|
964
|
+
Default: `relative`
|
|
965
|
+
|
|
966
|
+
Controls how the element is positioned.
|
|
967
|
+
|
|
968
|
+
When `position` is `static`, `top`, `right`, `bottom`, and `left` are ignored.
|
|
969
|
+
|
|
970
|
+
##### top
|
|
971
|
+
|
|
972
|
+
Type: `number` `string`
|
|
973
|
+
|
|
974
|
+
Top offset for positioned elements.
|
|
975
|
+
You can also set it as a percentage of the parent size.
|
|
976
|
+
|
|
977
|
+
##### right
|
|
978
|
+
|
|
979
|
+
Type: `number` `string`
|
|
980
|
+
|
|
981
|
+
Right offset for positioned elements.
|
|
982
|
+
You can also set it as a percentage of the parent size.
|
|
983
|
+
|
|
984
|
+
##### bottom
|
|
985
|
+
|
|
986
|
+
Type: `number` `string`
|
|
987
|
+
|
|
988
|
+
Bottom offset for positioned elements.
|
|
989
|
+
You can also set it as a percentage of the parent size.
|
|
990
|
+
|
|
991
|
+
##### left
|
|
992
|
+
|
|
993
|
+
Type: `number` `string`
|
|
994
|
+
|
|
995
|
+
Left offset for positioned elements.
|
|
996
|
+
You can also set it as a percentage of the parent size.
|
|
997
|
+
|
|
893
998
|
#### Visibility
|
|
894
999
|
|
|
895
1000
|
##### display
|
|
@@ -985,7 +1090,7 @@ Alternatively, pass a custom border style like so:
|
|
|
985
1090
|
bottomLeft: '↗',
|
|
986
1091
|
bottom: '↑',
|
|
987
1092
|
bottomRight: '↖',
|
|
988
|
-
right: '←'
|
|
1093
|
+
right: '←',
|
|
989
1094
|
}}
|
|
990
1095
|
>
|
|
991
1096
|
<Text>Custom</Text>
|
|
@@ -1127,6 +1232,76 @@ Dim the right border color.
|
|
|
1127
1232
|
</Box>
|
|
1128
1233
|
```
|
|
1129
1234
|
|
|
1235
|
+
##### borderBackgroundColor
|
|
1236
|
+
|
|
1237
|
+
Type: `string`
|
|
1238
|
+
|
|
1239
|
+
Change border background color.
|
|
1240
|
+
Accepts the same values as [`backgroundColor`](#backgroundcolor) in `<Text>` component.
|
|
1241
|
+
A shorthand for setting `borderTopBackgroundColor`, `borderRightBackgroundColor`, `borderBottomBackgroundColor`, and `borderLeftBackgroundColor`.
|
|
1242
|
+
|
|
1243
|
+
```jsx
|
|
1244
|
+
<Box borderStyle="round" borderColor="white" borderBackgroundColor="green">
|
|
1245
|
+
<Text>Hello world</Text>
|
|
1246
|
+
</Box>
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
##### borderTopBackgroundColor
|
|
1250
|
+
|
|
1251
|
+
Type: `string`
|
|
1252
|
+
|
|
1253
|
+
Change top border background color.
|
|
1254
|
+
Accepts the same values as [`backgroundColor`](#backgroundcolor) in `<Text>` component.
|
|
1255
|
+
Falls back to `borderBackgroundColor` if not specified.
|
|
1256
|
+
|
|
1257
|
+
```jsx
|
|
1258
|
+
<Box borderStyle="round" borderColor="white" borderTopBackgroundColor="green">
|
|
1259
|
+
<Text>Hello world</Text>
|
|
1260
|
+
</Box>
|
|
1261
|
+
```
|
|
1262
|
+
|
|
1263
|
+
##### borderBottomBackgroundColor
|
|
1264
|
+
|
|
1265
|
+
Type: `string`
|
|
1266
|
+
|
|
1267
|
+
Change bottom border background color.
|
|
1268
|
+
Accepts the same values as [`backgroundColor`](#backgroundcolor) in `<Text>` component.
|
|
1269
|
+
Falls back to `borderBackgroundColor` if not specified.
|
|
1270
|
+
|
|
1271
|
+
```jsx
|
|
1272
|
+
<Box borderStyle="round" borderColor="white" borderBottomBackgroundColor="green">
|
|
1273
|
+
<Text>Hello world</Text>
|
|
1274
|
+
</Box>
|
|
1275
|
+
```
|
|
1276
|
+
|
|
1277
|
+
##### borderRightBackgroundColor
|
|
1278
|
+
|
|
1279
|
+
Type: `string`
|
|
1280
|
+
|
|
1281
|
+
Change right border background color.
|
|
1282
|
+
Accepts the same values as [`backgroundColor`](#backgroundcolor) in `<Text>` component.
|
|
1283
|
+
Falls back to `borderBackgroundColor` if not specified.
|
|
1284
|
+
|
|
1285
|
+
```jsx
|
|
1286
|
+
<Box borderStyle="round" borderColor="white" borderRightBackgroundColor="green">
|
|
1287
|
+
<Text>Hello world</Text>
|
|
1288
|
+
</Box>
|
|
1289
|
+
```
|
|
1290
|
+
|
|
1291
|
+
##### borderLeftBackgroundColor
|
|
1292
|
+
|
|
1293
|
+
Type: `string`
|
|
1294
|
+
|
|
1295
|
+
Change left border background color.
|
|
1296
|
+
Accepts the same values as [`backgroundColor`](#backgroundcolor) in `<Text>` component.
|
|
1297
|
+
Falls back to `borderBackgroundColor` if not specified.
|
|
1298
|
+
|
|
1299
|
+
```jsx
|
|
1300
|
+
<Box borderStyle="round" borderColor="white" borderLeftBackgroundColor="green">
|
|
1301
|
+
<Text>Hello world</Text>
|
|
1302
|
+
</Box>
|
|
1303
|
+
```
|
|
1304
|
+
|
|
1130
1305
|
##### borderTop
|
|
1131
1306
|
|
|
1132
1307
|
Type: `boolean`\
|
|
@@ -1171,11 +1346,23 @@ Accepts the same values as [`color`](#color) in the `<Text>` component.
|
|
|
1171
1346
|
<Text>Red background</Text>
|
|
1172
1347
|
</Box>
|
|
1173
1348
|
|
|
1174
|
-
<Box
|
|
1349
|
+
<Box
|
|
1350
|
+
backgroundColor="#FF8800"
|
|
1351
|
+
width={20}
|
|
1352
|
+
height={3}
|
|
1353
|
+
marginTop={1}
|
|
1354
|
+
alignSelf="flex-start"
|
|
1355
|
+
>
|
|
1175
1356
|
<Text>Orange background</Text>
|
|
1176
1357
|
</Box>
|
|
1177
1358
|
|
|
1178
|
-
<Box
|
|
1359
|
+
<Box
|
|
1360
|
+
backgroundColor="rgb(0, 255, 0)"
|
|
1361
|
+
width={20}
|
|
1362
|
+
height={3}
|
|
1363
|
+
marginTop={1}
|
|
1364
|
+
alignSelf="flex-start"
|
|
1365
|
+
>
|
|
1179
1366
|
<Text>Green background</Text>
|
|
1180
1367
|
</Box>
|
|
1181
1368
|
</Box>
|
|
@@ -1194,7 +1381,12 @@ The background color fills the entire `<Box>` area and is inherited by child `<T
|
|
|
1194
1381
|
Background colors work with borders and padding:
|
|
1195
1382
|
|
|
1196
1383
|
```jsx
|
|
1197
|
-
<Box
|
|
1384
|
+
<Box
|
|
1385
|
+
backgroundColor="cyan"
|
|
1386
|
+
borderStyle="round"
|
|
1387
|
+
padding={1}
|
|
1388
|
+
alignSelf="flex-start"
|
|
1389
|
+
>
|
|
1198
1390
|
<Text>Background with border and padding</Text>
|
|
1199
1391
|
</Box>
|
|
1200
1392
|
```
|
|
@@ -1303,8 +1495,8 @@ const Example = () => {
|
|
|
1303
1495
|
...previousTests,
|
|
1304
1496
|
{
|
|
1305
1497
|
id: previousTests.length,
|
|
1306
|
-
title: `Test #${previousTests.length + 1}
|
|
1307
|
-
}
|
|
1498
|
+
title: `Test #${previousTests.length + 1}`,
|
|
1499
|
+
},
|
|
1308
1500
|
]);
|
|
1309
1501
|
|
|
1310
1502
|
timer = setTimeout(run, 100);
|
|
@@ -1340,9 +1532,8 @@ const Example = () => {
|
|
|
1340
1532
|
render(<Example />);
|
|
1341
1533
|
```
|
|
1342
1534
|
|
|
1343
|
-
|
|
1344
|
-
that were previously rendered. This means that when you add new items to the `items`
|
|
1345
|
-
array, changes you make to previous items will not trigger a rerender.
|
|
1535
|
+
> [!NOTE]
|
|
1536
|
+
> `<Static>` only renders new items in the `items` prop and ignores items that were previously rendered. This means that when you add new items to the `items` array, changes you make to previous items will not trigger a rerender.
|
|
1346
1537
|
|
|
1347
1538
|
See [examples/static](examples/static/static.tsx) for an example usage of `<Static>` component.
|
|
1348
1539
|
|
|
@@ -1397,7 +1588,11 @@ For example, you might want to apply a [gradient to text](https://github.com/sin
|
|
|
1397
1588
|
These use cases can't accept React nodes as input; they expect a string.
|
|
1398
1589
|
That's what the `<Transform>` component does: it gives you an output string of its child components and lets you transform it in any way.
|
|
1399
1590
|
|
|
1400
|
-
|
|
1591
|
+
> [!NOTE]
|
|
1592
|
+
> `<Transform>` must be applied only to `<Text>` children components and shouldn't change the dimensions of the output; otherwise, the layout will be incorrect.
|
|
1593
|
+
|
|
1594
|
+
> [!IMPORTANT]
|
|
1595
|
+
> When children use `<Text>` styling props (e.g. `color`, `bold`), the string passed to `transform` will contain [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code). If your transform manipulates whitespace or does string operations like `.trim()`, you may need to use ANSI-aware methods (e.g. from [`slice-ansi`](https://github.com/chalk/slice-ansi) or [`strip-ansi`](https://github.com/chalk/strip-ansi)).
|
|
1401
1596
|
|
|
1402
1597
|
```jsx
|
|
1403
1598
|
import {render, Transform} from 'ink';
|
|
@@ -1420,12 +1615,11 @@ For example, to implement a hanging indent component, you can indent all the lin
|
|
|
1420
1615
|
```jsx
|
|
1421
1616
|
import {render, Transform} from 'ink';
|
|
1422
1617
|
|
|
1423
|
-
const HangingIndent = ({
|
|
1618
|
+
const HangingIndent = ({indent = 4, children}) => (
|
|
1424
1619
|
<Transform
|
|
1425
1620
|
transform={(line, index) =>
|
|
1426
1621
|
index === 0 ? line : ' '.repeat(indent) + line
|
|
1427
1622
|
}
|
|
1428
|
-
{...props}
|
|
1429
1623
|
>
|
|
1430
1624
|
{children}
|
|
1431
1625
|
</Transform>
|
|
@@ -1439,12 +1633,7 @@ const text =
|
|
|
1439
1633
|
'of my hands only. I lived there two years and two months. At ' +
|
|
1440
1634
|
'present I am a sojourner in civilized life again.';
|
|
1441
1635
|
|
|
1442
|
-
|
|
1443
|
-
render(
|
|
1444
|
-
<HangingIndent bold dimColor indent={4}>
|
|
1445
|
-
{text}
|
|
1446
|
-
</HangingIndent>
|
|
1447
|
-
);
|
|
1636
|
+
render(<HangingIndent indent={4}>{text}</HangingIndent>);
|
|
1448
1637
|
```
|
|
1449
1638
|
|
|
1450
1639
|
#### transform(outputLine, index)
|
|
@@ -1470,7 +1659,7 @@ The zero-indexed line number of the line that's currently being transformed.
|
|
|
1470
1659
|
|
|
1471
1660
|
### useInput(inputHandler, options?)
|
|
1472
1661
|
|
|
1473
|
-
|
|
1662
|
+
A React hook that returns `void` and handles user input.
|
|
1474
1663
|
It's a more convenient alternative to using `useStdin` and listening for `data` events.
|
|
1475
1664
|
The callback you pass to `useInput` is called for each character when the user enters any input.
|
|
1476
1665
|
However, if the user pastes text and it's more than one character, the callback will be called only once, and the whole string will be passed as `input`.
|
|
@@ -1585,6 +1774,16 @@ Default: `false`
|
|
|
1585
1774
|
If the Page Up or Page Down key was pressed, the corresponding property will be `true`.
|
|
1586
1775
|
For example, if the user presses Page Down, `key.pageDown` equals `true`.
|
|
1587
1776
|
|
|
1777
|
+
###### key.home
|
|
1778
|
+
|
|
1779
|
+
###### key.end
|
|
1780
|
+
|
|
1781
|
+
Type: `boolean`\
|
|
1782
|
+
Default: `false`
|
|
1783
|
+
|
|
1784
|
+
If the Home or End key was pressed, the corresponding property will be `true`.
|
|
1785
|
+
For example, if the user presses End, `key.end` equals `true`.
|
|
1786
|
+
|
|
1588
1787
|
###### key.meta
|
|
1589
1788
|
|
|
1590
1789
|
Type: `boolean`\
|
|
@@ -1639,23 +1838,77 @@ Default: `true`
|
|
|
1639
1838
|
Enable or disable capturing of user input.
|
|
1640
1839
|
Useful when there are multiple `useInput` hooks used at once to avoid handling the same input several times.
|
|
1641
1840
|
|
|
1841
|
+
### usePaste(handler, options?)
|
|
1842
|
+
|
|
1843
|
+
A React hook that calls `handler` whenever the user pastes text. Bracketed paste mode (`\x1b[?2004h`) is automatically enabled while the hook is active, so pasted text arrives as a single string rather than being misinterpreted as individual key presses.
|
|
1844
|
+
|
|
1845
|
+
`usePaste` and `useInput` can be used together in the same component. They operate on separate event channels, so paste content is never forwarded to `useInput` handlers when `usePaste` is active.
|
|
1846
|
+
|
|
1847
|
+
```jsx
|
|
1848
|
+
import {useInput, usePaste} from 'ink';
|
|
1849
|
+
|
|
1850
|
+
const MyInput = () => {
|
|
1851
|
+
useInput((input, key) => {
|
|
1852
|
+
// Only receives typed characters and key events, not pasted text.
|
|
1853
|
+
if (key.return) {
|
|
1854
|
+
// Submit
|
|
1855
|
+
}
|
|
1856
|
+
});
|
|
1857
|
+
|
|
1858
|
+
usePaste((text) => {
|
|
1859
|
+
// Receives the full pasted string, including newlines.
|
|
1860
|
+
console.log('Pasted:', text);
|
|
1861
|
+
});
|
|
1862
|
+
|
|
1863
|
+
return …
|
|
1864
|
+
};
|
|
1865
|
+
```
|
|
1866
|
+
|
|
1867
|
+
#### handler(text)
|
|
1868
|
+
|
|
1869
|
+
Type: `Function`
|
|
1870
|
+
|
|
1871
|
+
Called with the full pasted string whenever the user pastes text. The string is delivered verbatim — newlines, escape sequences, and other special characters are preserved exactly as pasted.
|
|
1872
|
+
|
|
1873
|
+
##### text
|
|
1874
|
+
|
|
1875
|
+
Type: `string`
|
|
1876
|
+
|
|
1877
|
+
The pasted text.
|
|
1878
|
+
|
|
1879
|
+
#### options
|
|
1880
|
+
|
|
1881
|
+
Type: `object`
|
|
1882
|
+
|
|
1883
|
+
##### isActive
|
|
1884
|
+
|
|
1885
|
+
Type: `boolean`\
|
|
1886
|
+
Default: `true`
|
|
1887
|
+
|
|
1888
|
+
Enable or disable the paste handler. Useful when multiple components use `usePaste` and only one should be active at a time.
|
|
1889
|
+
|
|
1642
1890
|
### useApp()
|
|
1643
1891
|
|
|
1644
|
-
|
|
1892
|
+
A React hook that returns app lifecycle methods.
|
|
1645
1893
|
|
|
1646
|
-
#### exit(
|
|
1894
|
+
#### exit(errorOrResult?)
|
|
1647
1895
|
|
|
1648
1896
|
Type: `Function`
|
|
1649
1897
|
|
|
1650
1898
|
Exit (unmount) the whole Ink app.
|
|
1651
1899
|
|
|
1652
|
-
#####
|
|
1900
|
+
##### errorOrResult
|
|
1901
|
+
|
|
1902
|
+
Type: `Error | unknown`
|
|
1653
1903
|
|
|
1654
|
-
|
|
1904
|
+
Optional value that controls how [`waitUntilExit`](#waituntilexit) settles:
|
|
1655
1905
|
|
|
1656
|
-
|
|
1906
|
+
- `exit()` resolves with `undefined`.
|
|
1907
|
+
- `exit(error)` rejects when `error` is an `Error`.
|
|
1908
|
+
- `exit(value)` resolves with `value`.
|
|
1657
1909
|
|
|
1658
1910
|
```js
|
|
1911
|
+
import {useEffect} from 'react';
|
|
1659
1912
|
import {useApp} from 'ink';
|
|
1660
1913
|
|
|
1661
1914
|
const Example = () => {
|
|
@@ -1666,15 +1919,39 @@ const Example = () => {
|
|
|
1666
1919
|
setTimeout(() => {
|
|
1667
1920
|
exit();
|
|
1668
1921
|
}, 5000);
|
|
1669
|
-
}, []);
|
|
1922
|
+
}, [exit]);
|
|
1670
1923
|
|
|
1671
1924
|
return …
|
|
1672
1925
|
};
|
|
1673
1926
|
```
|
|
1674
1927
|
|
|
1928
|
+
#### waitUntilRenderFlush()
|
|
1929
|
+
|
|
1930
|
+
Type: `Function`
|
|
1931
|
+
|
|
1932
|
+
Returns a promise that settles after pending render output is flushed to stdout.
|
|
1933
|
+
|
|
1934
|
+
```js
|
|
1935
|
+
import {useEffect} from 'react';
|
|
1936
|
+
import {useApp} from 'ink';
|
|
1937
|
+
|
|
1938
|
+
const Example = () => {
|
|
1939
|
+
const {waitUntilRenderFlush} = useApp();
|
|
1940
|
+
|
|
1941
|
+
useEffect(() => {
|
|
1942
|
+
void (async () => {
|
|
1943
|
+
await waitUntilRenderFlush();
|
|
1944
|
+
runNextCommand();
|
|
1945
|
+
})();
|
|
1946
|
+
}, [waitUntilRenderFlush]);
|
|
1947
|
+
|
|
1948
|
+
return …;
|
|
1949
|
+
};
|
|
1950
|
+
```
|
|
1951
|
+
|
|
1675
1952
|
### useStdin()
|
|
1676
1953
|
|
|
1677
|
-
|
|
1954
|
+
A React hook that returns the stdin stream and stdin-related utilities.
|
|
1678
1955
|
|
|
1679
1956
|
#### stdin
|
|
1680
1957
|
|
|
@@ -1748,7 +2025,7 @@ const Example = () => {
|
|
|
1748
2025
|
|
|
1749
2026
|
### useStdout()
|
|
1750
2027
|
|
|
1751
|
-
|
|
2028
|
+
A React hook that returns the stdout stream where Ink renders your app and stdout-related utilities.
|
|
1752
2029
|
|
|
1753
2030
|
#### stdout
|
|
1754
2031
|
|
|
@@ -1794,9 +2071,73 @@ const Example = () => {
|
|
|
1794
2071
|
|
|
1795
2072
|
See additional usage example in [examples/use-stdout](examples/use-stdout/use-stdout.tsx).
|
|
1796
2073
|
|
|
2074
|
+
### useBoxMetrics(ref)
|
|
2075
|
+
|
|
2076
|
+
A React hook that returns the current layout metrics for a tracked box element.
|
|
2077
|
+
It updates when layout changes (for example terminal resize, sibling/content changes, or position changes).
|
|
2078
|
+
|
|
2079
|
+
Use `hasMeasured` to detect when the currently tracked element has been measured.
|
|
2080
|
+
|
|
2081
|
+
#### ref
|
|
2082
|
+
|
|
2083
|
+
Type: `React.RefObject<DOMElement>`
|
|
2084
|
+
|
|
2085
|
+
A ref to the `<Box>` element to track.
|
|
2086
|
+
|
|
2087
|
+
```jsx
|
|
2088
|
+
import {useRef} from 'react';
|
|
2089
|
+
import {Box, Text, useBoxMetrics} from 'ink';
|
|
2090
|
+
|
|
2091
|
+
const Example = () => {
|
|
2092
|
+
const ref = useRef(null);
|
|
2093
|
+
const {width, height, left, top, hasMeasured} = useBoxMetrics(ref);
|
|
2094
|
+
|
|
2095
|
+
return (
|
|
2096
|
+
<Box ref={ref}>
|
|
2097
|
+
<Text>
|
|
2098
|
+
{hasMeasured ? `${width}x${height} at ${left},${top}` : 'Measuring...'}
|
|
2099
|
+
</Text>
|
|
2100
|
+
</Box>
|
|
2101
|
+
);
|
|
2102
|
+
};
|
|
2103
|
+
```
|
|
2104
|
+
|
|
2105
|
+
#### width
|
|
2106
|
+
|
|
2107
|
+
Type: `number`
|
|
2108
|
+
|
|
2109
|
+
Element width.
|
|
2110
|
+
|
|
2111
|
+
#### height
|
|
2112
|
+
|
|
2113
|
+
Type: `number`
|
|
2114
|
+
|
|
2115
|
+
Element height.
|
|
2116
|
+
|
|
2117
|
+
#### left
|
|
2118
|
+
|
|
2119
|
+
Type: `number`
|
|
2120
|
+
|
|
2121
|
+
Distance from the left edge of the parent.
|
|
2122
|
+
|
|
2123
|
+
#### top
|
|
2124
|
+
|
|
2125
|
+
Type: `number`
|
|
2126
|
+
|
|
2127
|
+
Distance from the top edge of the parent.
|
|
2128
|
+
|
|
2129
|
+
#### hasMeasured
|
|
2130
|
+
|
|
2131
|
+
Type: `boolean`
|
|
2132
|
+
|
|
2133
|
+
Whether the currently tracked element has been measured.
|
|
2134
|
+
|
|
2135
|
+
> [!NOTE]
|
|
2136
|
+
> The hook returns `{width: 0, height: 0, left: 0, top: 0}` until the first layout pass completes. It also returns zeros when the tracked ref is detached.
|
|
2137
|
+
|
|
1797
2138
|
### useStderr()
|
|
1798
2139
|
|
|
1799
|
-
|
|
2140
|
+
A React hook that returns the stderr stream and stderr-related utilities.
|
|
1800
2141
|
|
|
1801
2142
|
#### stderr
|
|
1802
2143
|
|
|
@@ -1843,8 +2184,42 @@ const Example = () => {
|
|
|
1843
2184
|
};
|
|
1844
2185
|
```
|
|
1845
2186
|
|
|
2187
|
+
### useWindowSize()
|
|
2188
|
+
|
|
2189
|
+
A React hook that returns the current terminal dimensions and re-renders the component whenever the terminal is resized.
|
|
2190
|
+
|
|
2191
|
+
```js
|
|
2192
|
+
import {Text, useWindowSize} from 'ink';
|
|
2193
|
+
|
|
2194
|
+
const Example = () => {
|
|
2195
|
+
const {columns, rows} = useWindowSize();
|
|
2196
|
+
|
|
2197
|
+
return (
|
|
2198
|
+
<Text>
|
|
2199
|
+
{columns}x{rows}
|
|
2200
|
+
</Text>
|
|
2201
|
+
);
|
|
2202
|
+
};
|
|
2203
|
+
```
|
|
2204
|
+
|
|
2205
|
+
#### columns
|
|
2206
|
+
|
|
2207
|
+
Type: `number`
|
|
2208
|
+
|
|
2209
|
+
Number of columns (horizontal character cells).
|
|
2210
|
+
|
|
2211
|
+
#### rows
|
|
2212
|
+
|
|
2213
|
+
Type: `number`
|
|
2214
|
+
|
|
2215
|
+
Number of rows (vertical character cells).
|
|
2216
|
+
|
|
2217
|
+
> [!NOTE]
|
|
2218
|
+
> When the terminal is resized narrower, ghost lines may briefly appear depending on the terminal emulator's reflow behavior.
|
|
2219
|
+
|
|
1846
2220
|
### useFocus(options?)
|
|
1847
2221
|
|
|
2222
|
+
A React hook that returns focus state and focus controls for the current component.
|
|
1848
2223
|
A component that uses the `useFocus` hook becomes "focusable" to Ink, so when the user presses <kbd>Tab</kbd>, Ink will switch focus to this component.
|
|
1849
2224
|
If there are multiple components that execute the `useFocus` hook, focus will be given to them in the order in which these components are rendered.
|
|
1850
2225
|
This hook returns an object with an `isFocused` boolean property, which determines whether this component is focused.
|
|
@@ -1889,13 +2264,14 @@ See example in [examples/use-focus](examples/use-focus/use-focus.tsx) and [examp
|
|
|
1889
2264
|
|
|
1890
2265
|
### useFocusManager()
|
|
1891
2266
|
|
|
1892
|
-
|
|
2267
|
+
A React hook that returns methods to manage focus across focusable components.
|
|
1893
2268
|
|
|
1894
2269
|
#### enableFocus()
|
|
1895
2270
|
|
|
1896
2271
|
Enable focus management for all components.
|
|
1897
2272
|
|
|
1898
|
-
|
|
2273
|
+
> [!NOTE]
|
|
2274
|
+
> You don't need to call this method manually unless you've disabled focus management. Focus management is enabled by default.
|
|
1899
2275
|
|
|
1900
2276
|
```js
|
|
1901
2277
|
import {useFocusManager} from 'ink';
|
|
@@ -1936,7 +2312,8 @@ Switch focus to the next focusable component.
|
|
|
1936
2312
|
If there's no active component right now, focus will be given to the first focusable component.
|
|
1937
2313
|
If the active component is the last in the list of focusable components, focus will be switched to the first focusable component.
|
|
1938
2314
|
|
|
1939
|
-
|
|
2315
|
+
> [!NOTE]
|
|
2316
|
+
> Ink calls this method when user presses <kbd>Tab</kbd>.
|
|
1940
2317
|
|
|
1941
2318
|
```js
|
|
1942
2319
|
import {useFocusManager} from 'ink';
|
|
@@ -1958,7 +2335,8 @@ Switch focus to the previous focusable component.
|
|
|
1958
2335
|
If there's no active component right now, focus will be given to the first focusable component.
|
|
1959
2336
|
If the active component is the first in the list of focusable components, focus will be switched to the last focusable component.
|
|
1960
2337
|
|
|
1961
|
-
|
|
2338
|
+
> [!NOTE]
|
|
2339
|
+
> Ink calls this method when user presses <kbd>Shift</kbd>+<kbd>Tab</kbd>.
|
|
1962
2340
|
|
|
1963
2341
|
```js
|
|
1964
2342
|
import {useFocusManager} from 'ink';
|
|
@@ -1981,7 +2359,7 @@ const Example = () => {
|
|
|
1981
2359
|
Type: `string`
|
|
1982
2360
|
|
|
1983
2361
|
Switch focus to the component with the given [`id`](#id).
|
|
1984
|
-
If there's no component with that ID, focus
|
|
2362
|
+
If there's no component with that ID, focus is not changed.
|
|
1985
2363
|
|
|
1986
2364
|
```js
|
|
1987
2365
|
import {useFocusManager, useInput} from 'ink';
|
|
@@ -2000,9 +2378,26 @@ const Example = () => {
|
|
|
2000
2378
|
};
|
|
2001
2379
|
```
|
|
2002
2380
|
|
|
2381
|
+
#### activeId
|
|
2382
|
+
|
|
2383
|
+
Type: `string | undefined`
|
|
2384
|
+
|
|
2385
|
+
The ID of the currently focused component, or `undefined` if no component is focused.
|
|
2386
|
+
|
|
2387
|
+
```js
|
|
2388
|
+
import {Text, useFocusManager} from 'ink';
|
|
2389
|
+
|
|
2390
|
+
const Example = () => {
|
|
2391
|
+
const {activeId} = useFocusManager();
|
|
2392
|
+
|
|
2393
|
+
return <Text>Focused: {activeId ?? 'none'}</Text>;
|
|
2394
|
+
};
|
|
2395
|
+
```
|
|
2396
|
+
|
|
2003
2397
|
### useCursor()
|
|
2004
2398
|
|
|
2005
|
-
|
|
2399
|
+
A React hook that returns methods to control the terminal cursor position after each render.
|
|
2400
|
+
This is essential for IME (Input Method Editor) support, where the composing character is displayed at the cursor location.
|
|
2006
2401
|
|
|
2007
2402
|
```jsx
|
|
2008
2403
|
import {useState} from 'react';
|
|
@@ -2019,7 +2414,10 @@ const TextInput = () => {
|
|
|
2019
2414
|
return (
|
|
2020
2415
|
<Box flexDirection="column">
|
|
2021
2416
|
<Text>Type here:</Text>
|
|
2022
|
-
<Text>
|
|
2417
|
+
<Text>
|
|
2418
|
+
{prompt}
|
|
2419
|
+
{text}
|
|
2420
|
+
</Text>
|
|
2023
2421
|
</Box>
|
|
2024
2422
|
);
|
|
2025
2423
|
};
|
|
@@ -2051,7 +2449,8 @@ Row position from the top of the Ink output (0 = first line).
|
|
|
2051
2449
|
|
|
2052
2450
|
### useIsScreenReaderEnabled()
|
|
2053
2451
|
|
|
2054
|
-
|
|
2452
|
+
A React hook that returns whether a screen reader is enabled.
|
|
2453
|
+
This is useful when you want to render different output for screen readers.
|
|
2055
2454
|
|
|
2056
2455
|
```jsx
|
|
2057
2456
|
import {useIsScreenReaderEnabled, Text} from 'ink';
|
|
@@ -2069,6 +2468,65 @@ const Example = () => {
|
|
|
2069
2468
|
};
|
|
2070
2469
|
```
|
|
2071
2470
|
|
|
2471
|
+
### useAnimation(options?)
|
|
2472
|
+
|
|
2473
|
+
A React hook that drives animations. Returns a frame counter, elapsed time, frame delta, and a reset function. All animations share a single timer internally, so multiple animated components consolidate into one render cycle.
|
|
2474
|
+
|
|
2475
|
+
```jsx
|
|
2476
|
+
import {Text, useAnimation} from 'ink';
|
|
2477
|
+
|
|
2478
|
+
const Spinner = () => {
|
|
2479
|
+
const {frame} = useAnimation({interval: 80});
|
|
2480
|
+
const characters = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
2481
|
+
|
|
2482
|
+
return <Text>{characters[frame % characters.length]}</Text>;
|
|
2483
|
+
};
|
|
2484
|
+
```
|
|
2485
|
+
|
|
2486
|
+
#### options
|
|
2487
|
+
|
|
2488
|
+
Type: `object`
|
|
2489
|
+
|
|
2490
|
+
##### interval
|
|
2491
|
+
|
|
2492
|
+
Type: `number`\
|
|
2493
|
+
Default: `100`
|
|
2494
|
+
|
|
2495
|
+
Time between ticks in milliseconds.
|
|
2496
|
+
|
|
2497
|
+
##### isActive
|
|
2498
|
+
|
|
2499
|
+
Type: `boolean`\
|
|
2500
|
+
Default: `true`
|
|
2501
|
+
|
|
2502
|
+
Whether the animation is running. When set to `false`, the animation stops. When toggled back to `true`, all values reset to `0`.
|
|
2503
|
+
|
|
2504
|
+
#### Return value
|
|
2505
|
+
|
|
2506
|
+
##### frame
|
|
2507
|
+
|
|
2508
|
+
Type: `number`
|
|
2509
|
+
|
|
2510
|
+
Discrete counter that increments by 1 each interval. Useful for indexed sequences like spinner frames.
|
|
2511
|
+
|
|
2512
|
+
##### time
|
|
2513
|
+
|
|
2514
|
+
Type: `number`
|
|
2515
|
+
|
|
2516
|
+
Total elapsed time in milliseconds since the animation started or was last reset. Useful for continuous math-based animations like sine waves: `Math.sin(time / 1000 * Math.PI * 2)`.
|
|
2517
|
+
|
|
2518
|
+
##### delta
|
|
2519
|
+
|
|
2520
|
+
Type: `number`
|
|
2521
|
+
|
|
2522
|
+
Time in milliseconds since the previous rendered tick. Accounts for throttled renders. Useful for physics-based or velocity-driven motion: `position += speed * delta`.
|
|
2523
|
+
|
|
2524
|
+
##### reset
|
|
2525
|
+
|
|
2526
|
+
Type: `() => void`
|
|
2527
|
+
|
|
2528
|
+
Resets `frame`, `time`, and `delta` to `0` and restarts timing from the current moment. Useful for one-shot animations triggered by events.
|
|
2529
|
+
|
|
2072
2530
|
## API
|
|
2073
2531
|
|
|
2074
2532
|
#### render(tree, options?)
|
|
@@ -2079,7 +2537,7 @@ Mount a component and render the output.
|
|
|
2079
2537
|
|
|
2080
2538
|
##### tree
|
|
2081
2539
|
|
|
2082
|
-
Type: `
|
|
2540
|
+
Type: `ReactNode`
|
|
2083
2541
|
|
|
2084
2542
|
##### options
|
|
2085
2543
|
|
|
@@ -2123,6 +2581,8 @@ Patch console methods to ensure console output doesn't mix with Ink's output.
|
|
|
2123
2581
|
When any of the `console.*` methods are called (like `console.log()`), Ink intercepts their output, clears the main output, renders output from the console method, and then rerenders the main output again.
|
|
2124
2582
|
That way, both are visible and don't overlap each other.
|
|
2125
2583
|
|
|
2584
|
+
Once unmount starts, Ink restores the native console before React cleanup runs. Teardown-time `console.*` output then follows the normal console behavior instead of being rerouted through Ink.
|
|
2585
|
+
|
|
2126
2586
|
This functionality is powered by [patch-console](https://github.com/vadimdemedes/patch-console), so if you need to disable Ink's interception of output but want to build something custom, you can use that.
|
|
2127
2587
|
|
|
2128
2588
|
###### onRender
|
|
@@ -2130,7 +2590,16 @@ This functionality is powered by [patch-console](https://github.com/vadimdemedes
|
|
|
2130
2590
|
Type: `({renderTime: number}) => void`\
|
|
2131
2591
|
Default: `undefined`
|
|
2132
2592
|
|
|
2133
|
-
Runs the given callback after each render and re-render with
|
|
2593
|
+
Runs the given callback after each render and re-render with render metrics.
|
|
2594
|
+
This callback runs after Ink commits a frame, but it does not wait for `stdout`/`stderr` stream callbacks.
|
|
2595
|
+
To run code after output is flushed, use [`waitUntilRenderFlush()`](#waituntilrenderflush).
|
|
2596
|
+
|
|
2597
|
+
###### isScreenReaderEnabled
|
|
2598
|
+
|
|
2599
|
+
Type: `boolean`\
|
|
2600
|
+
Default: `process.env['INK_SCREEN_READER'] === 'true'`
|
|
2601
|
+
|
|
2602
|
+
Enable screen reader support. See [Screen Reader Support](#screen-reader-support).
|
|
2134
2603
|
|
|
2135
2604
|
###### debug
|
|
2136
2605
|
|
|
@@ -2165,6 +2634,7 @@ Default: `false`
|
|
|
2165
2634
|
Enable React Concurrent Rendering mode.
|
|
2166
2635
|
|
|
2167
2636
|
When enabled:
|
|
2637
|
+
|
|
2168
2638
|
- Suspense boundaries work correctly with async data fetching
|
|
2169
2639
|
- `useTransition` and `useDeferredValue` hooks are fully functional
|
|
2170
2640
|
- Updates can be interrupted for higher priority work
|
|
@@ -2173,7 +2643,48 @@ When enabled:
|
|
|
2173
2643
|
render(<MyApp />, {concurrent: true});
|
|
2174
2644
|
```
|
|
2175
2645
|
|
|
2176
|
-
|
|
2646
|
+
> [!NOTE]
|
|
2647
|
+
> Concurrent mode changes the timing of renders. Some tests may need to use `act()` to properly await updates. Reusing the same stdout across multiple `render()` calls without unmounting is unsupported. Call `unmount()` first if you need to change the rendering mode or create a fresh instance.
|
|
2648
|
+
|
|
2649
|
+
###### interactive
|
|
2650
|
+
|
|
2651
|
+
Type: `boolean`\
|
|
2652
|
+
Default: `true` (`false` if in CI (detected via [`is-in-ci`](https://github.com/sindresorhus/is-in-ci)) or `stdout.isTTY` is falsy)
|
|
2653
|
+
|
|
2654
|
+
Override automatic interactive mode detection.
|
|
2655
|
+
|
|
2656
|
+
By default, Ink detects whether the environment is interactive based on CI detection and `stdout.isTTY`. When non-interactive, Ink skips terminal-specific features like ANSI erase sequences, cursor manipulation, synchronized output, resize handling, and kitty keyboard auto-detection. Only the final frame of non-static output is written at unmount.
|
|
2657
|
+
|
|
2658
|
+
Most users should not need to set this option. Use it when you have your own "interactive" detection logic that differs from the built-in behavior.
|
|
2659
|
+
|
|
2660
|
+
> [!NOTE]
|
|
2661
|
+
> Reusing the same stdout across multiple `render()` calls without unmounting is unsupported. Call `unmount()` first if you need to change this option or create a fresh instance.
|
|
2662
|
+
|
|
2663
|
+
```jsx
|
|
2664
|
+
// Use your own detection logic
|
|
2665
|
+
const isInteractive = myCustomDetection();
|
|
2666
|
+
render(<MyApp />, {interactive: isInteractive});
|
|
2667
|
+
```
|
|
2668
|
+
|
|
2669
|
+
###### alternateScreen
|
|
2670
|
+
|
|
2671
|
+
Type: `boolean`\
|
|
2672
|
+
Default: `false`
|
|
2673
|
+
|
|
2674
|
+
Render the app in the terminal's alternate screen buffer. When enabled, the app renders on a separate screen, and the original terminal content is restored when the app exits. This is the same mechanism used by programs like vim, htop, and less.
|
|
2675
|
+
|
|
2676
|
+
Note: The terminal's scrollback buffer is not available while in the alternate screen. This is standard terminal behavior; programs like vim use the alternate screen specifically to avoid polluting the user's scrollback history.
|
|
2677
|
+
|
|
2678
|
+
Ink intentionally treats alternate-screen teardown output as disposable. It does not preserve or replay teardown-time frames, hook writes, or `console.*` output after restoring the primary screen.
|
|
2679
|
+
|
|
2680
|
+
Only works in interactive mode. Ignored when `interactive` is `false` or in a non-interactive environment (CI, piped stdout).
|
|
2681
|
+
|
|
2682
|
+
> [!NOTE]
|
|
2683
|
+
> Reusing the same stdout across multiple `render()` calls without unmounting is unsupported. Call `unmount()` first if you need to change this option or create a fresh instance.
|
|
2684
|
+
|
|
2685
|
+
```jsx
|
|
2686
|
+
render(<MyApp />, {alternateScreen: true});
|
|
2687
|
+
```
|
|
2177
2688
|
|
|
2178
2689
|
###### kittyKeyboard
|
|
2179
2690
|
|
|
@@ -2216,6 +2727,7 @@ Default: `['disambiguateEscapeCodes']`
|
|
|
2216
2727
|
Protocol flags to request from the terminal. Pass an array of flag name strings.
|
|
2217
2728
|
|
|
2218
2729
|
Available flags:
|
|
2730
|
+
|
|
2219
2731
|
- `'disambiguateEscapeCodes'` - Disambiguate escape codes
|
|
2220
2732
|
- `'reportEventTypes'` - Report key press, repeat, and release events
|
|
2221
2733
|
- `'reportAlternateKeys'` - Report alternate key encodings
|
|
@@ -2234,6 +2746,56 @@ When the kitty keyboard protocol is enabled, input handling changes in several w
|
|
|
2234
2746
|
- `Escape` key vs `Ctrl+[` - these are disambiguated.
|
|
2235
2747
|
- **Event types.** With the `reportEventTypes` flag, key press, repeat, and release events are distinguished via `key.eventType`.
|
|
2236
2748
|
|
|
2749
|
+
#### renderToString(tree, options?)
|
|
2750
|
+
|
|
2751
|
+
Returns: `string`
|
|
2752
|
+
|
|
2753
|
+
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.
|
|
2754
|
+
|
|
2755
|
+
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.
|
|
2756
|
+
|
|
2757
|
+
```jsx
|
|
2758
|
+
import {renderToString, Text, Box} from 'ink';
|
|
2759
|
+
|
|
2760
|
+
const output = renderToString(
|
|
2761
|
+
<Box padding={1}>
|
|
2762
|
+
<Text color="green">Hello World</Text>
|
|
2763
|
+
</Box>,
|
|
2764
|
+
);
|
|
2765
|
+
|
|
2766
|
+
console.log(output);
|
|
2767
|
+
```
|
|
2768
|
+
|
|
2769
|
+
**Notes:**
|
|
2770
|
+
|
|
2771
|
+
- Terminal-specific hooks (`useInput`, `useStdin`, `useStdout`, `useStderr`, `useWindowSize`, `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.
|
|
2772
|
+
- `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.
|
|
2773
|
+
- `useLayoutEffect` callbacks fire synchronously during commit, so state updates they trigger **will** be reflected in the output.
|
|
2774
|
+
- The `<Static>` component is supported — its output is prepended to the dynamic output.
|
|
2775
|
+
- If a component throws during rendering, the error is propagated to the caller after cleanup.
|
|
2776
|
+
|
|
2777
|
+
##### tree
|
|
2778
|
+
|
|
2779
|
+
Type: `ReactNode`
|
|
2780
|
+
|
|
2781
|
+
##### options
|
|
2782
|
+
|
|
2783
|
+
Type: `object`
|
|
2784
|
+
|
|
2785
|
+
###### columns
|
|
2786
|
+
|
|
2787
|
+
Type: `number`\
|
|
2788
|
+
Default: `80`
|
|
2789
|
+
|
|
2790
|
+
Width of the virtual terminal in columns. Controls where text wrapping occurs.
|
|
2791
|
+
|
|
2792
|
+
```jsx
|
|
2793
|
+
const output = renderToString(<Text>{'A'.repeat(100)}</Text>, {
|
|
2794
|
+
columns: 40,
|
|
2795
|
+
});
|
|
2796
|
+
// Text wraps at 40 columns
|
|
2797
|
+
```
|
|
2798
|
+
|
|
2237
2799
|
#### Instance
|
|
2238
2800
|
|
|
2239
2801
|
This is the object that `render()` returns.
|
|
@@ -2244,7 +2806,7 @@ Replace the previous root node with a new one or update the props of the current
|
|
|
2244
2806
|
|
|
2245
2807
|
###### tree
|
|
2246
2808
|
|
|
2247
|
-
Type: `
|
|
2809
|
+
Type: `ReactNode`
|
|
2248
2810
|
|
|
2249
2811
|
```jsx
|
|
2250
2812
|
// Update props of the root node
|
|
@@ -2267,7 +2829,10 @@ unmount();
|
|
|
2267
2829
|
|
|
2268
2830
|
##### waitUntilExit()
|
|
2269
2831
|
|
|
2270
|
-
Returns a promise that
|
|
2832
|
+
Returns a promise that settles when the app is unmounted.
|
|
2833
|
+
|
|
2834
|
+
It resolves with the value passed to `exit(value)` and rejects with the error passed to `exit(error)`.
|
|
2835
|
+
When `unmount()` is called manually, it settles after unmount-related stdout writes complete.
|
|
2271
2836
|
|
|
2272
2837
|
```jsx
|
|
2273
2838
|
const {unmount, waitUntilExit} = render(<MyApp />);
|
|
@@ -2277,6 +2842,27 @@ setTimeout(unmount, 1000);
|
|
|
2277
2842
|
await waitUntilExit(); // resolves after `unmount()` is called
|
|
2278
2843
|
```
|
|
2279
2844
|
|
|
2845
|
+
##### waitUntilRenderFlush()
|
|
2846
|
+
|
|
2847
|
+
Returns a promise that settles after pending render output is flushed to stdout.
|
|
2848
|
+
|
|
2849
|
+
Useful when you need to run code only after a frame is written:
|
|
2850
|
+
|
|
2851
|
+
```jsx
|
|
2852
|
+
const {rerender, waitUntilRenderFlush} = render(<MyApp step="loading" />);
|
|
2853
|
+
|
|
2854
|
+
rerender(<MyApp step="ready" />);
|
|
2855
|
+
await waitUntilRenderFlush(); // output for "ready" is flushed
|
|
2856
|
+
|
|
2857
|
+
runNextCommand();
|
|
2858
|
+
```
|
|
2859
|
+
|
|
2860
|
+
##### cleanup()
|
|
2861
|
+
|
|
2862
|
+
Unmount the current app and delete the internal Ink instance associated with the current `stdout`.
|
|
2863
|
+
This is mostly useful for advanced cases (for example, tests) where you need `render()` to create a fresh instance for the same stream.
|
|
2864
|
+
Unlike deleting the internal instance directly, this also tears down terminal state such as the alternate screen.
|
|
2865
|
+
|
|
2280
2866
|
##### clear()
|
|
2281
2867
|
|
|
2282
2868
|
Clear output.
|
|
@@ -2292,7 +2878,8 @@ Measure the dimensions of a particular `<Box>` element.
|
|
|
2292
2878
|
Returns an object with `width` and `height` properties.
|
|
2293
2879
|
This function is useful when your component needs to know the amount of available space it has. You can use it when you need to change the layout based on the length of its content.
|
|
2294
2880
|
|
|
2295
|
-
|
|
2881
|
+
> [!NOTE]
|
|
2882
|
+
> `measureElement()` returns `{width: 0, height: 0}` when called during render (before layout is calculated). Call it from post-render code, such as `useEffect`, `useLayoutEffect`, input handlers, or timer callbacks. When content changes, pass the relevant dependency to your effect so it re-measures after each update.
|
|
2296
2883
|
|
|
2297
2884
|
##### ref
|
|
2298
2885
|
|
|
@@ -2361,7 +2948,8 @@ npx react-devtools
|
|
|
2361
2948
|
After it starts, you should see the component tree of your CLI.
|
|
2362
2949
|
You can even inspect and change the props of components, and see the results immediately in the CLI, without restarting it.
|
|
2363
2950
|
|
|
2364
|
-
|
|
2951
|
+
> [!NOTE]
|
|
2952
|
+
> You must manually quit your CLI via <kbd>Ctrl</kbd>+<kbd>C</kbd> after you're done testing.
|
|
2365
2953
|
|
|
2366
2954
|
## Screen Reader Support
|
|
2367
2955
|
|
|
@@ -2417,38 +3005,49 @@ Default: `false`
|
|
|
2417
3005
|
|
|
2418
3006
|
Hide the element from screen readers.
|
|
2419
3007
|
|
|
2420
|
-
|
|
3008
|
+
### `aria-role`
|
|
2421
3009
|
|
|
2422
3010
|
Type: `string`
|
|
2423
3011
|
|
|
2424
3012
|
The role of the element.
|
|
2425
3013
|
|
|
2426
3014
|
Supported values:
|
|
3015
|
+
|
|
2427
3016
|
- `button`
|
|
2428
3017
|
- `checkbox`
|
|
2429
|
-
- `
|
|
2430
|
-
- `radiogroup`
|
|
3018
|
+
- `combobox`
|
|
2431
3019
|
- `list`
|
|
3020
|
+
- `listbox`
|
|
2432
3021
|
- `listitem`
|
|
2433
3022
|
- `menu`
|
|
2434
3023
|
- `menuitem`
|
|
3024
|
+
- `option`
|
|
2435
3025
|
- `progressbar`
|
|
3026
|
+
- `radio`
|
|
3027
|
+
- `radiogroup`
|
|
2436
3028
|
- `tab`
|
|
2437
3029
|
- `tablist`
|
|
3030
|
+
- `table`
|
|
3031
|
+
- `textbox`
|
|
2438
3032
|
- `timer`
|
|
2439
3033
|
- `toolbar`
|
|
2440
|
-
- `table`
|
|
2441
3034
|
|
|
2442
|
-
|
|
3035
|
+
### `aria-state`
|
|
2443
3036
|
|
|
2444
3037
|
Type: `object`
|
|
2445
3038
|
|
|
2446
3039
|
The state of the element.
|
|
2447
3040
|
|
|
2448
3041
|
Supported values:
|
|
3042
|
+
|
|
3043
|
+
- `busy` (boolean)
|
|
2449
3044
|
- `checked` (boolean)
|
|
2450
3045
|
- `disabled` (boolean)
|
|
2451
3046
|
- `expanded` (boolean)
|
|
3047
|
+
- `multiline` (boolean)
|
|
3048
|
+
- `multiselectable` (boolean)
|
|
3049
|
+
- `readonly` (boolean)
|
|
3050
|
+
- `required` (boolean)
|
|
2452
3051
|
- `selected` (boolean)
|
|
2453
3052
|
|
|
2454
3053
|
## Creating Components
|
|
@@ -2491,11 +3090,16 @@ For a practical example of building an accessible component, see the [ARIA examp
|
|
|
2491
3090
|
- [ink-scroll-list](https://github.com/ByteLandTechnology/ink-scroll-list) - Scrollable list.
|
|
2492
3091
|
- [ink-stepper](https://github.com/archcorsair/ink-stepper) - Step-by-step wizard.
|
|
2493
3092
|
- [ink-virtual-list](https://github.com/archcorsair/ink-virtual-list) - Virtualized list that renders only visible items for performance.
|
|
3093
|
+
- [ink-color-picker](https://github.com/sina-byn/ink-color-picker) - Color picker.
|
|
2494
3094
|
|
|
2495
3095
|
## Useful Hooks
|
|
2496
3096
|
|
|
2497
3097
|
- [ink-use-stdout-dimensions](https://github.com/cameronhunter/ink-monorepo/tree/master/packages/ink-use-stdout-dimensions) - Subscribe to stdout dimensions.
|
|
2498
3098
|
|
|
3099
|
+
## Recipes
|
|
3100
|
+
|
|
3101
|
+
- [Routing with React Router](recipes/routing.md) - Navigate between routes using `MemoryRouter`.
|
|
3102
|
+
|
|
2499
3103
|
## Examples
|
|
2500
3104
|
|
|
2501
3105
|
The [`examples`](/examples) directory contains a set of real examples. You can run them with:
|
|
@@ -2517,6 +3121,20 @@ npm run example examples/[example name]
|
|
|
2517
3121
|
- [Write to stderr](examples/use-stderr/use-stderr.tsx) - Write to stderr, bypassing main Ink output.
|
|
2518
3122
|
- [Static](examples/static/static.tsx) - Use the `<Static>` component to render permanent output.
|
|
2519
3123
|
- [Child process](examples/subprocess-output) - Renders output from a child process.
|
|
3124
|
+
- [Router](examples/router/router.tsx) - Navigate between routes using React Router's `MemoryRouter`.
|
|
3125
|
+
|
|
3126
|
+
## Continuous Integration
|
|
3127
|
+
|
|
3128
|
+
When running on CI (detected via the `CI` environment variable), Ink adapts its rendering:
|
|
3129
|
+
|
|
3130
|
+
- 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.
|
|
3131
|
+
- Terminal resize events are not listened to.
|
|
3132
|
+
|
|
3133
|
+
If your CI environment supports full terminal rendering and you want to opt out of this behavior, set `CI=false`:
|
|
3134
|
+
|
|
3135
|
+
```sh
|
|
3136
|
+
CI=false node my-cli.js
|
|
3137
|
+
```
|
|
2520
3138
|
|
|
2521
3139
|
## Maintainers
|
|
2522
3140
|
|