ink 6.6.0 → 6.7.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.
Files changed (43) hide show
  1. package/build/components/App.d.ts +7 -48
  2. package/build/components/App.js +259 -225
  3. package/build/components/App.js.map +1 -1
  4. package/build/components/CursorContext.d.ts +11 -0
  5. package/build/components/CursorContext.js +8 -0
  6. package/build/components/CursorContext.js.map +1 -0
  7. package/build/components/ErrorBoundary.d.ts +18 -0
  8. package/build/components/ErrorBoundary.js +23 -0
  9. package/build/components/ErrorBoundary.js.map +1 -0
  10. package/build/cursor-helpers.d.ts +38 -0
  11. package/build/cursor-helpers.js +56 -0
  12. package/build/cursor-helpers.js.map +1 -0
  13. package/build/hooks/use-cursor.d.ts +12 -0
  14. package/build/hooks/use-cursor.js +29 -0
  15. package/build/hooks/use-cursor.js.map +1 -0
  16. package/build/hooks/use-input.d.ts +30 -0
  17. package/build/hooks/use-input.js +31 -2
  18. package/build/hooks/use-input.js.map +1 -1
  19. package/build/index.d.ts +4 -0
  20. package/build/index.js +2 -0
  21. package/build/index.js.map +1 -1
  22. package/build/ink.d.ts +32 -0
  23. package/build/ink.js +258 -31
  24. package/build/ink.js.map +1 -1
  25. package/build/kitty-keyboard.d.ts +23 -0
  26. package/build/kitty-keyboard.js +32 -0
  27. package/build/kitty-keyboard.js.map +1 -0
  28. package/build/log-update.d.ts +6 -1
  29. package/build/log-update.js +163 -40
  30. package/build/log-update.js.map +1 -1
  31. package/build/parse-keypress.d.ts +8 -0
  32. package/build/parse-keypress.js +270 -2
  33. package/build/parse-keypress.js.map +1 -1
  34. package/build/reconciler.js +11 -1
  35. package/build/reconciler.js.map +1 -1
  36. package/build/render.d.ts +22 -0
  37. package/build/render.js +7 -2
  38. package/build/render.js.map +1 -1
  39. package/build/write-synchronized.d.ts +4 -0
  40. package/build/write-synchronized.js +7 -0
  41. package/build/write-synchronized.js.map +1 -0
  42. package/package.json +18 -15
  43. package/readme.md +167 -1
@@ -0,0 +1,11 @@
1
+ import { type CursorPosition } from '../log-update.js';
2
+ export type Props = {
3
+ /**
4
+ Set the cursor position relative to the Ink output.
5
+
6
+ Pass `undefined` to hide the cursor.
7
+ */
8
+ readonly setCursorPosition: (position: CursorPosition | undefined) => void;
9
+ };
10
+ declare const CursorContext: import("react").Context<Props>;
11
+ export default CursorContext;
@@ -0,0 +1,8 @@
1
+ import { createContext } from 'react';
2
+ // eslint-disable-next-line @typescript-eslint/naming-convention
3
+ const CursorContext = createContext({
4
+ setCursorPosition() { },
5
+ });
6
+ CursorContext.displayName = 'InternalCursorContext';
7
+ export default CursorContext;
8
+ //# sourceMappingURL=CursorContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CursorContext.js","sourceRoot":"","sources":["../../src/components/CursorContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,OAAO,CAAC;AAYpC,gEAAgE;AAChE,MAAM,aAAa,GAAG,aAAa,CAAQ;IAC1C,iBAAiB,KAAI,CAAC;CACtB,CAAC,CAAC;AAEH,aAAa,CAAC,WAAW,GAAG,uBAAuB,CAAC;AAEpD,eAAe,aAAa,CAAC"}
@@ -0,0 +1,18 @@
1
+ import React, { PureComponent, type ReactNode } from 'react';
2
+ type Props = {
3
+ readonly children: ReactNode;
4
+ readonly onError: (error: Error) => void;
5
+ };
6
+ type State = {
7
+ readonly error?: Error;
8
+ };
9
+ export default class ErrorBoundary extends PureComponent<Props, State> {
10
+ static displayName: string;
11
+ static getDerivedStateFromError(error: Error): {
12
+ error: Error;
13
+ };
14
+ state: State;
15
+ componentDidCatch(error: Error): void;
16
+ render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
17
+ }
18
+ export {};
@@ -0,0 +1,23 @@
1
+ import React, { PureComponent } from 'react';
2
+ import ErrorOverview from './ErrorOverview.js';
3
+ // Error boundary must be a class component since getDerivedStateFromError
4
+ // and componentDidCatch are not available as hooks
5
+ export default class ErrorBoundary extends PureComponent {
6
+ static displayName = 'InternalErrorBoundary';
7
+ static getDerivedStateFromError(error) {
8
+ return { error };
9
+ }
10
+ state = {
11
+ error: undefined,
12
+ };
13
+ componentDidCatch(error) {
14
+ this.props.onError(error);
15
+ }
16
+ render() {
17
+ if (this.state.error) {
18
+ return React.createElement(ErrorOverview, { error: this.state.error });
19
+ }
20
+ return this.props.children;
21
+ }
22
+ }
23
+ //# sourceMappingURL=ErrorBoundary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorBoundary.js","sourceRoot":"","sources":["../../src/components/ErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAC,aAAa,EAAiB,MAAM,OAAO,CAAC;AAC3D,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAW/C,0EAA0E;AAC1E,mDAAmD;AACnD,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,aAA2B;IACrE,MAAM,CAAC,WAAW,GAAG,uBAAuB,CAAC;IAE7C,MAAM,CAAC,wBAAwB,CAAC,KAAY;QAC3C,OAAO,EAAC,KAAK,EAAC,CAAC;IAChB,CAAC;IAEQ,KAAK,GAAU;QACvB,KAAK,EAAE,SAAS;KAChB,CAAC;IAEO,iBAAiB,CAAC,KAAY;QACtC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAEQ,MAAM;QACd,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,oBAAC,aAAa,IAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAI,CAAC;QACnD,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;IAC5B,CAAC"}
@@ -0,0 +1,38 @@
1
+ export type CursorPosition = {
2
+ x: number;
3
+ y: number;
4
+ };
5
+ declare const showCursorEscape = "\u001B[?25h";
6
+ declare const hideCursorEscape = "\u001B[?25l";
7
+ export { showCursorEscape, hideCursorEscape };
8
+ /**
9
+ Compare two cursor positions. Returns true if they differ.
10
+ */
11
+ export declare const cursorPositionChanged: (a: CursorPosition | undefined, b: CursorPosition | undefined) => boolean;
12
+ /**
13
+ Build escape sequence to move cursor from bottom of output to the target position and show it.
14
+ Assumes cursor is at (col 0, line visibleLineCount) — i.e. just after the last output line.
15
+ */
16
+ export declare const buildCursorSuffix: (visibleLineCount: number, cursorPosition: CursorPosition | undefined) => string;
17
+ /**
18
+ Build escape sequence to move cursor from previousCursorPosition back to the bottom of output.
19
+ This must be done before eraseLines or any operation that assumes cursor is at the bottom.
20
+ */
21
+ export declare const buildReturnToBottom: (previousLineCount: number, previousCursorPosition: CursorPosition | undefined) => string;
22
+ export type CursorOnlyInput = {
23
+ cursorWasShown: boolean;
24
+ previousLineCount: number;
25
+ previousCursorPosition: CursorPosition | undefined;
26
+ visibleLineCount: number;
27
+ cursorPosition: CursorPosition | undefined;
28
+ };
29
+ /**
30
+ Build the escape sequence for cursor-only updates (output unchanged, cursor moved).
31
+ Hides cursor if it was previously shown, returns to bottom, then repositions.
32
+ */
33
+ export declare const buildCursorOnlySequence: (input: CursorOnlyInput) => string;
34
+ /**
35
+ Build the prefix that hides cursor and returns to bottom before erasing or rewriting.
36
+ Returns empty string if cursor was not shown.
37
+ */
38
+ export declare const buildReturnToBottomPrefix: (cursorWasShown: boolean, previousLineCount: number, previousCursorPosition: CursorPosition | undefined) => string;
@@ -0,0 +1,56 @@
1
+ import ansiEscapes from 'ansi-escapes';
2
+ const showCursorEscape = '\u001B[?25h';
3
+ const hideCursorEscape = '\u001B[?25l';
4
+ export { showCursorEscape, hideCursorEscape };
5
+ /**
6
+ Compare two cursor positions. Returns true if they differ.
7
+ */
8
+ export const cursorPositionChanged = (a, b) => a?.x !== b?.x || a?.y !== b?.y;
9
+ /**
10
+ Build escape sequence to move cursor from bottom of output to the target position and show it.
11
+ Assumes cursor is at (col 0, line visibleLineCount) — i.e. just after the last output line.
12
+ */
13
+ export const buildCursorSuffix = (visibleLineCount, cursorPosition) => {
14
+ if (!cursorPosition) {
15
+ return '';
16
+ }
17
+ const moveUp = visibleLineCount - cursorPosition.y;
18
+ return ((moveUp > 0 ? ansiEscapes.cursorUp(moveUp) : '') +
19
+ ansiEscapes.cursorTo(cursorPosition.x) +
20
+ showCursorEscape);
21
+ };
22
+ /**
23
+ Build escape sequence to move cursor from previousCursorPosition back to the bottom of output.
24
+ This must be done before eraseLines or any operation that assumes cursor is at the bottom.
25
+ */
26
+ export const buildReturnToBottom = (previousLineCount, previousCursorPosition) => {
27
+ if (!previousCursorPosition) {
28
+ return '';
29
+ }
30
+ // PreviousLineCount includes trailing newline, so visible lines = previousLineCount - 1
31
+ // cursor is at previousCursorPosition.y, need to go to line (previousLineCount - 1)
32
+ const down = previousLineCount - 1 - previousCursorPosition.y;
33
+ return ((down > 0 ? ansiEscapes.cursorDown(down) : '') + ansiEscapes.cursorTo(0));
34
+ };
35
+ /**
36
+ Build the escape sequence for cursor-only updates (output unchanged, cursor moved).
37
+ Hides cursor if it was previously shown, returns to bottom, then repositions.
38
+ */
39
+ export const buildCursorOnlySequence = (input) => {
40
+ const hidePrefix = input.cursorWasShown ? hideCursorEscape : '';
41
+ const returnToBottom = buildReturnToBottom(input.previousLineCount, input.previousCursorPosition);
42
+ const cursorSuffix = buildCursorSuffix(input.visibleLineCount, input.cursorPosition);
43
+ return hidePrefix + returnToBottom + cursorSuffix;
44
+ };
45
+ /**
46
+ Build the prefix that hides cursor and returns to bottom before erasing or rewriting.
47
+ Returns empty string if cursor was not shown.
48
+ */
49
+ export const buildReturnToBottomPrefix = (cursorWasShown, previousLineCount, previousCursorPosition) => {
50
+ if (!cursorWasShown) {
51
+ return '';
52
+ }
53
+ return (hideCursorEscape +
54
+ buildReturnToBottom(previousLineCount, previousCursorPosition));
55
+ };
56
+ //# sourceMappingURL=cursor-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-helpers.js","sourceRoot":"","sources":["../src/cursor-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,cAAc,CAAC;AAOvC,MAAM,gBAAgB,GAAG,aAAa,CAAC;AACvC,MAAM,gBAAgB,GAAG,aAAa,CAAC;AAEvC,OAAO,EAAC,gBAAgB,EAAE,gBAAgB,EAAC,CAAC;AAE5C;;EAEE;AACF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACpC,CAA6B,EAC7B,CAA6B,EACnB,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAE7C;;;EAGE;AACF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAChC,gBAAwB,EACxB,cAA0C,EACjC,EAAE;IACX,IAAI,CAAC,cAAc,EAAE,CAAC;QACrB,OAAO,EAAE,CAAC;IACX,CAAC;IAED,MAAM,MAAM,GAAG,gBAAgB,GAAG,cAAc,CAAC,CAAC,CAAC;IACnD,OAAO,CACN,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC;QACtC,gBAAgB,CAChB,CAAC;AACH,CAAC,CAAC;AAEF;;;EAGE;AACF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAClC,iBAAyB,EACzB,sBAAkD,EACzC,EAAE;IACX,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC;IACX,CAAC;IAED,wFAAwF;IACxF,oFAAoF;IACpF,MAAM,IAAI,GAAG,iBAAiB,GAAG,CAAC,GAAG,sBAAsB,CAAC,CAAC,CAAC;IAC9D,OAAO,CACN,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CACxE,CAAC;AACH,CAAC,CAAC;AAUF;;;EAGE;AACF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,KAAsB,EAAU,EAAE;IACzE,MAAM,UAAU,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;IAChE,MAAM,cAAc,GAAG,mBAAmB,CACzC,KAAK,CAAC,iBAAiB,EACvB,KAAK,CAAC,sBAAsB,CAC5B,CAAC;IACF,MAAM,YAAY,GAAG,iBAAiB,CACrC,KAAK,CAAC,gBAAgB,EACtB,KAAK,CAAC,cAAc,CACpB,CAAC;IACF,OAAO,UAAU,GAAG,cAAc,GAAG,YAAY,CAAC;AACnD,CAAC,CAAC;AAEF;;;EAGE;AACF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACxC,cAAuB,EACvB,iBAAyB,EACzB,sBAAkD,EACzC,EAAE;IACX,IAAI,CAAC,cAAc,EAAE,CAAC;QACrB,OAAO,EAAE,CAAC;IACX,CAAC;IAED,OAAO,CACN,gBAAgB;QAChB,mBAAmB,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,CAC9D,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { type CursorPosition } from '../log-update.js';
2
+ /**
3
+ `useCursor` is a React hook that lets you control the terminal cursor position.
4
+
5
+ Setting a cursor position makes the cursor visible at the specified coordinates (relative to the Ink output origin). This is useful for IME (Input Method Editor) support, where the composing character is displayed at the cursor location.
6
+
7
+ Pass `undefined` to hide the cursor.
8
+ */
9
+ declare const useCursor: () => {
10
+ setCursorPosition: (position: CursorPosition | undefined) => void;
11
+ };
12
+ export default useCursor;
@@ -0,0 +1,29 @@
1
+ import { useContext, useRef, useCallback, useInsertionEffect } from 'react';
2
+ import CursorContext from '../components/CursorContext.js';
3
+ /**
4
+ `useCursor` is a React hook that lets you control the terminal cursor position.
5
+
6
+ Setting a cursor position makes the cursor visible at the specified coordinates (relative to the Ink output origin). This is useful for IME (Input Method Editor) support, where the composing character is displayed at the cursor location.
7
+
8
+ Pass `undefined` to hide the cursor.
9
+ */
10
+ const useCursor = () => {
11
+ const context = useContext(CursorContext);
12
+ const positionRef = useRef(undefined);
13
+ const setCursorPosition = useCallback((position) => {
14
+ positionRef.current = position;
15
+ }, []);
16
+ // Propagate cursor position to log-update only during commit phase.
17
+ // useInsertionEffect runs before resetAfterCommit (which triggers onRender),
18
+ // and does NOT run for abandoned concurrent renders (e.g. suspended components).
19
+ // This prevents cursor state from leaking across render boundaries.
20
+ useInsertionEffect(() => {
21
+ context.setCursorPosition(positionRef.current);
22
+ return () => {
23
+ context.setCursorPosition(undefined);
24
+ };
25
+ });
26
+ return { setCursorPosition };
27
+ };
28
+ export default useCursor;
29
+ //# sourceMappingURL=use-cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-cursor.js","sourceRoot":"","sources":["../../src/hooks/use-cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAAC,MAAM,OAAO,CAAC;AAC1E,OAAO,aAAa,MAAM,gCAAgC,CAAC;AAG3D;;;;;;EAME;AACF,MAAM,SAAS,GAAG,GAAG,EAAE;IACtB,MAAM,OAAO,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,MAAM,CAA6B,SAAS,CAAC,CAAC;IAElE,MAAM,iBAAiB,GAAG,WAAW,CACpC,CAAC,QAAoC,EAAE,EAAE;QACxC,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAC;IAChC,CAAC,EACD,EAAE,CACF,CAAC;IAEF,oEAAoE;IACpE,6EAA6E;IAC7E,iFAAiF;IACjF,oEAAoE;IACpE,kBAAkB,CAAC,GAAG,EAAE;QACvB,OAAO,CAAC,iBAAiB,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC/C,OAAO,GAAG,EAAE;YACX,OAAO,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QACtC,CAAC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,EAAC,iBAAiB,EAAC,CAAC;AAC5B,CAAC,CAAC;AAEF,eAAe,SAAS,CAAC"}
@@ -66,6 +66,36 @@ export type Key = {
66
66
  [Meta key](https://en.wikipedia.org/wiki/Meta_key) was pressed.
67
67
  */
68
68
  meta: boolean;
69
+ /**
70
+ Super key (Cmd on Mac, Win on Windows) was pressed.
71
+
72
+ Only available with kitty keyboard protocol.
73
+ */
74
+ super: boolean;
75
+ /**
76
+ Hyper key was pressed.
77
+
78
+ Only available with kitty keyboard protocol.
79
+ */
80
+ hyper: boolean;
81
+ /**
82
+ Caps Lock is active.
83
+
84
+ Only available with kitty keyboard protocol.
85
+ */
86
+ capsLock: boolean;
87
+ /**
88
+ Num Lock is active.
89
+
90
+ Only available with kitty keyboard protocol.
91
+ */
92
+ numLock: boolean;
93
+ /**
94
+ Event type for key events.
95
+
96
+ Only available with kitty keyboard protocol.
97
+ */
98
+ eventType?: 'press' | 'repeat' | 'release';
69
99
  };
70
100
  type Handler = (input: string, key: Key) => void;
71
101
  type Options = {
@@ -62,9 +62,38 @@ const useInput = (inputHandler, options = {}) => {
62
62
  // to avoid breaking changes in Ink.
63
63
  // TODO(vadimdemedes): consider removing this in the next major version.
64
64
  meta: keypress.meta || keypress.name === 'escape' || keypress.option,
65
+ // Kitty keyboard protocol modifiers
66
+ super: keypress.super ?? false,
67
+ hyper: keypress.hyper ?? false,
68
+ capsLock: keypress.capsLock ?? false,
69
+ numLock: keypress.numLock ?? false,
70
+ eventType: keypress.eventType,
65
71
  };
66
- let input = keypress.ctrl ? keypress.name : keypress.sequence;
67
- if (nonAlphanumericKeys.includes(keypress.name)) {
72
+ let input;
73
+ if (keypress.isKittyProtocol) {
74
+ // Use text-as-codepoints field for printable keys (needed when
75
+ // reportAllKeysAsEscapeCodes flag is enabled), suppress non-printable
76
+ if (keypress.isPrintable) {
77
+ input = keypress.text ?? keypress.name;
78
+ }
79
+ else if (keypress.ctrl && keypress.name.length === 1) {
80
+ // Ctrl+letter via codepoint 1-26 form: not printable text, but
81
+ // the letter name must flow through so handlers (e.g. exitOnCtrlC
82
+ // checking `input === 'c' && key.ctrl`) still work.
83
+ input = keypress.name;
84
+ }
85
+ else {
86
+ input = '';
87
+ }
88
+ }
89
+ else if (keypress.ctrl) {
90
+ input = keypress.name;
91
+ }
92
+ else {
93
+ input = keypress.sequence;
94
+ }
95
+ if (!keypress.isKittyProtocol &&
96
+ nonAlphanumericKeys.includes(keypress.name)) {
68
97
  input = '';
69
98
  }
70
99
  // Strip meta if it's still remaining after `parseKeypress`
@@ -1 +1 @@
1
- {"version":3,"file":"use-input.js","sourceRoot":"","sources":["../../src/hooks/use-input.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-input.js","sourceRoot":"","sources":["../../src/hooks/use-input.ts"],"names":[],"mappings":"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"}
package/build/index.d.ts CHANGED
@@ -24,5 +24,9 @@ export { default as useStderr } from './hooks/use-stderr.js';
24
24
  export { default as useFocus } from './hooks/use-focus.js';
25
25
  export { default as useFocusManager } from './hooks/use-focus-manager.js';
26
26
  export { default as useIsScreenReaderEnabled } from './hooks/use-is-screen-reader-enabled.js';
27
+ export { default as useCursor } from './hooks/use-cursor.js';
28
+ export type { CursorPosition } from './log-update.js';
27
29
  export { default as measureElement } from './measure-element.js';
28
30
  export type { DOMElement } from './dom.js';
31
+ export { kittyFlags, kittyModifiers } from './kitty-keyboard.js';
32
+ export type { KittyKeyboardOptions, KittyFlagName } from './kitty-keyboard.js';
package/build/index.js CHANGED
@@ -13,5 +13,7 @@ export { default as useStderr } from './hooks/use-stderr.js';
13
13
  export { default as useFocus } from './hooks/use-focus.js';
14
14
  export { default as useFocusManager } from './hooks/use-focus-manager.js';
15
15
  export { default as useIsScreenReaderEnabled } from './hooks/use-is-screen-reader-enabled.js';
16
+ export { default as useCursor } from './hooks/use-cursor.js';
16
17
  export { default as measureElement } from './measure-element.js';
18
+ export { kittyFlags, kittyModifiers } from './kitty-keyboard.js';
17
19
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAC,OAAO,IAAI,GAAG,EAAC,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAC,OAAO,IAAI,IAAI,EAAC,MAAM,sBAAsB,CAAC;AAMrD,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAC,OAAO,IAAI,OAAO,EAAC,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,eAAe,EAAC,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAC,OAAO,IAAI,wBAAwB,EAAC,MAAM,yCAAyC,CAAC;AAC5F,OAAO,EAAC,OAAO,IAAI,cAAc,EAAC,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAC,OAAO,IAAI,GAAG,EAAC,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAC,OAAO,IAAI,IAAI,EAAC,MAAM,sBAAsB,CAAC;AAMrD,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAC,OAAO,IAAI,OAAO,EAAC,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,MAAM,EAAC,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAC,OAAO,IAAI,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,IAAI,eAAe,EAAC,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAC,OAAO,IAAI,wBAAwB,EAAC,MAAM,yCAAyC,CAAC;AAC5F,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAC,OAAO,IAAI,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAC,UAAU,EAAE,cAAc,EAAC,MAAM,qBAAqB,CAAC"}
package/build/ink.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { type ReactNode } from 'react';
2
+ import { type CursorPosition } from './log-update.js';
3
+ import { type KittyKeyboardOptions } from './kitty-keyboard.js';
2
4
  /**
3
5
  Performance metrics for a render operation.
4
6
  */
@@ -20,28 +22,55 @@ export type Options = {
20
22
  waitUntilExit?: () => Promise<void>;
21
23
  maxFps?: number;
22
24
  incrementalRendering?: boolean;
25
+ /**
26
+ Enable React Concurrent Rendering mode.
27
+
28
+ When enabled:
29
+ - Suspense boundaries work correctly with async data
30
+ - `useTransition` and `useDeferredValue` are fully functional
31
+ - Updates can be interrupted for higher priority work
32
+
33
+ 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.
34
+
35
+ @default false
36
+ @experimental
37
+ */
38
+ concurrent?: boolean;
39
+ kittyKeyboard?: KittyKeyboardOptions;
23
40
  };
24
41
  export default class Ink {
42
+ /**
43
+ Whether this instance is using concurrent rendering mode.
44
+ */
45
+ readonly isConcurrent: boolean;
25
46
  private readonly options;
26
47
  private readonly log;
48
+ private cursorPosition;
27
49
  private readonly throttledLog;
28
50
  private readonly isScreenReaderEnabled;
29
51
  private isUnmounted;
30
52
  private lastOutput;
53
+ private lastOutputToRender;
31
54
  private lastOutputHeight;
32
55
  private lastTerminalWidth;
33
56
  private readonly container;
34
57
  private readonly rootNode;
35
58
  private fullStaticOutput;
36
59
  private exitPromise?;
60
+ private beforeExitHandler?;
37
61
  private restoreConsole?;
38
62
  private readonly unsubscribeResize?;
63
+ private readonly throttledOnRender?;
64
+ private kittyProtocolEnabled;
65
+ private cancelKittyDetection?;
39
66
  constructor(options: Options);
40
67
  getTerminalWidth: () => number;
41
68
  resized: () => void;
42
69
  resolveExitPromise: () => void;
43
70
  rejectExitPromise: (reason?: Error) => void;
44
71
  unsubscribeExit: () => void;
72
+ setCursorPosition: (position: CursorPosition | undefined) => void;
73
+ restoreLastOutput: () => void;
45
74
  calculateLayout: () => void;
46
75
  onRender: () => void;
47
76
  render(node: ReactNode): void;
@@ -51,4 +80,7 @@ export default class Ink {
51
80
  waitUntilExit(): Promise<void>;
52
81
  clear(): void;
53
82
  patchConsole(): void;
83
+ private initKittyKeyboard;
84
+ private confirmKittySupport;
85
+ private enableKittyProtocol;
54
86
  }