@jakubmazanec/cli 0.1.0-a500263 → 0.1.0-c2efc51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/program/Command.d.ts +2 -2
- package/dist/program/Command.js +4 -4
- package/dist/program/Command.js.map +1 -1
- package/dist/program/CommandOptions.d.ts +1 -1
- package/dist/program/CommandOptions.js.map +1 -1
- package/dist/program/Program.d.ts +8 -3
- package/dist/program/Program.js +32 -12
- package/dist/program/Program.js.map +1 -1
- package/dist/program/ProgramOptions.d.ts +5 -1
- package/dist/program/ProgramOptions.js +1 -3
- package/dist/program/ProgramOptions.js.map +1 -1
- package/dist/program/ProgramStreams.d.ts +1 -1
- package/dist/program/ProgramStreams.js +1 -1
- package/dist/program/ProgramStreams.js.map +1 -1
- package/dist/program/getProgramDetail.js.map +1 -1
- package/dist/ui/Failure.d.ts +2 -2
- package/dist/ui/Failure.js +2 -2
- package/dist/ui/Failure.js.map +1 -1
- package/dist/ui/Header.d.ts +1 -1
- package/dist/ui/Header.js +1 -1
- package/dist/ui/Header.js.map +1 -1
- package/dist/ui/Help.d.ts +2 -2
- package/dist/ui/Help.js +1 -1
- package/dist/ui/Help.js.map +1 -1
- package/dist/ui/Spinner.js.map +1 -1
- package/dist/ui/form/FormRow.js +1 -1
- package/dist/ui/form/FormRow.js.map +1 -1
- package/dist/ui/form/SelectInput.d.ts +3 -3
- package/dist/ui/form/SelectInput.js +20 -29
- package/dist/ui/form/SelectInput.js.map +1 -1
- package/dist/ui/form/TextInput.d.ts +1 -1
- package/dist/ui/form/TextInput.js +5 -8
- package/dist/ui/form/TextInput.js.map +1 -1
- package/dist/ui/form/createForm.js +1 -1
- package/dist/ui/form/createForm.js.map +1 -1
- package/dist/ui/getErrorDetail.js +9 -0
- package/dist/ui/getErrorDetail.js.map +1 -1
- package/dist/ui/icons.js.map +1 -1
- package/dist/ui/internals/Wrapper.d.ts +2 -2
- package/dist/ui/internals/Wrapper.js +4 -4
- package/dist/ui/internals/Wrapper.js.map +1 -1
- package/dist/ui/internals/programContext.d.ts +1 -1
- package/dist/ui/internals/programContext.js +1 -1
- package/dist/ui/internals/programContext.js.map +1 -1
- package/dist/ui/internals/rotate.js.map +1 -1
- package/dist/ui/useProgram.d.ts +1 -1
- package/dist/ui/useProgram.js +5 -5
- package/dist/ui/useProgram.js.map +1 -1
- package/package.json +8 -7
- package/src/program/Command.ts +2 -3
- package/src/program/CommandOptions.ts +1 -1
- package/src/program/Program.ts +38 -5
- package/src/program/ProgramOptions.ts +7 -1
- package/src/program/ProgramStreams.ts +1 -1
- package/src/ui/Failure.tsx +2 -2
- package/src/ui/Header.tsx +1 -1
- package/src/ui/Help.tsx +2 -2
- package/src/ui/form/SelectInput.tsx +23 -28
- package/src/ui/form/TextInput.tsx +5 -10
- package/src/ui/getErrorDetail.ts +11 -0
- package/src/ui/internals/Wrapper.tsx +5 -5
- package/src/ui/internals/programContext.ts +1 -1
- package/src/ui/useProgram.ts +3 -3
package/src/program/Program.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any -- needed */
|
|
2
2
|
import {type ParametersConfig, type Argv, type OptionsConfig} from '@jakubmazanec/args';
|
|
3
|
+
import {type ComponentType} from 'react';
|
|
4
|
+
import {type FallbackProps} from 'react-error-boundary';
|
|
3
5
|
|
|
4
6
|
import {type Command} from './Command.js';
|
|
5
7
|
import {ProgramError} from './ProgramError.js';
|
|
@@ -9,7 +11,7 @@ import {Wrapper} from '../ui/internals.js';
|
|
|
9
11
|
import {Failure, Help} from '../ui.js';
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
|
-
* Program manages and executes {@
|
|
14
|
+
* Program manages and executes {@link Command} instances attached to it based on parsing command line arguments.
|
|
13
15
|
*/
|
|
14
16
|
export class Program {
|
|
15
17
|
/** Program name. */
|
|
@@ -37,7 +39,10 @@ export class Program {
|
|
|
37
39
|
stdout: process.stdout,
|
|
38
40
|
};
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
/** Custom error boundary fallback component */
|
|
43
|
+
ErrorBoundaryFallbackComponent: ComponentType<FallbackProps>;
|
|
44
|
+
|
|
45
|
+
constructor({name, version, description, bin, ErrorBoundaryFallbackComponent}: ProgramOptions) {
|
|
41
46
|
if (name) {
|
|
42
47
|
this.name = name;
|
|
43
48
|
}
|
|
@@ -53,6 +58,12 @@ export class Program {
|
|
|
53
58
|
if (bin) {
|
|
54
59
|
this.bin = bin;
|
|
55
60
|
}
|
|
61
|
+
|
|
62
|
+
if (ErrorBoundaryFallbackComponent) {
|
|
63
|
+
this.ErrorBoundaryFallbackComponent = ErrorBoundaryFallbackComponent;
|
|
64
|
+
} else {
|
|
65
|
+
this.ErrorBoundaryFallbackComponent = Failure;
|
|
66
|
+
}
|
|
56
67
|
}
|
|
57
68
|
|
|
58
69
|
/**
|
|
@@ -70,6 +81,8 @@ export class Program {
|
|
|
70
81
|
|
|
71
82
|
/**
|
|
72
83
|
* Renders a React element using Ink and outputs to the configured streams.
|
|
84
|
+
*
|
|
85
|
+
* @param element The React element to render.
|
|
73
86
|
*/
|
|
74
87
|
async renderElement(element: React.ReactElement): Promise<void> {
|
|
75
88
|
if (this.isRendering) {
|
|
@@ -92,7 +105,9 @@ export class Program {
|
|
|
92
105
|
});
|
|
93
106
|
} catch (error: unknown) {
|
|
94
107
|
if (error instanceof Error) {
|
|
95
|
-
await this.renderElement(
|
|
108
|
+
await this.renderElement(
|
|
109
|
+
createElement(this.ErrorBoundaryFallbackComponent, {error, resetErrorBoundary: () => {}}),
|
|
110
|
+
);
|
|
96
111
|
}
|
|
97
112
|
} finally {
|
|
98
113
|
this.isRendering = false;
|
|
@@ -117,10 +132,28 @@ export class Program {
|
|
|
117
132
|
let {createElement} = await import('react');
|
|
118
133
|
|
|
119
134
|
for (let error of parsedArgs.errors) {
|
|
120
|
-
await this.renderElement(
|
|
135
|
+
await this.renderElement(
|
|
136
|
+
createElement(this.ErrorBoundaryFallbackComponent, {
|
|
137
|
+
error,
|
|
138
|
+
resetErrorBoundary: () => {},
|
|
139
|
+
}),
|
|
140
|
+
);
|
|
121
141
|
}
|
|
122
142
|
} else {
|
|
123
|
-
|
|
143
|
+
try {
|
|
144
|
+
await command.run(parsedArgs, this);
|
|
145
|
+
} catch (error: unknown) {
|
|
146
|
+
let {createElement} = await import('react');
|
|
147
|
+
|
|
148
|
+
if (error instanceof Error) {
|
|
149
|
+
await this.renderElement(
|
|
150
|
+
createElement(this.ErrorBoundaryFallbackComponent, {
|
|
151
|
+
error,
|
|
152
|
+
resetErrorBoundary: () => {},
|
|
153
|
+
}),
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
124
157
|
|
|
125
158
|
break;
|
|
126
159
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import {type ComponentType} from 'react';
|
|
2
|
+
import {type FallbackProps} from 'react-error-boundary';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
|
-
*
|
|
5
|
+
* {@link Project.constructor | Program constructor} options parameter.
|
|
3
6
|
*/
|
|
4
7
|
export type ProgramOptions = {
|
|
5
8
|
/** Program name. */
|
|
@@ -13,4 +16,7 @@ export type ProgramOptions = {
|
|
|
13
16
|
|
|
14
17
|
/** Program executable name. */
|
|
15
18
|
bin?: string | undefined;
|
|
19
|
+
|
|
20
|
+
/** Custom error boundary fallback component */
|
|
21
|
+
ErrorBoundaryFallbackComponent?: ComponentType<FallbackProps>;
|
|
16
22
|
};
|
package/src/ui/Failure.tsx
CHANGED
|
@@ -7,10 +7,10 @@ import {Header} from './Header.js';
|
|
|
7
7
|
import * as icons from './icons.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* {@
|
|
10
|
+
* {@link Failure} component props.
|
|
11
11
|
*/
|
|
12
12
|
export type FailureProps = BoxProps & {
|
|
13
|
-
/** Error that describes a failure state. Function {@
|
|
13
|
+
/** Error that describes a failure state. Function {@link getErrorDetail} is used for getting all the information from the error; you can use it to implement own retrieval logic and pass the result as `errorDetail` prop. */
|
|
14
14
|
error: Error;
|
|
15
15
|
|
|
16
16
|
/** Information about the failure state. Overrides information retireved from `error` prop. */
|
package/src/ui/Header.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import {type PropsWithChildren} from 'react';
|
|
|
4
4
|
import {Spinner} from './Spinner.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* {@
|
|
7
|
+
* {@link Header} component props.
|
|
8
8
|
*/
|
|
9
9
|
export type HeaderProps = BoxProps & {
|
|
10
10
|
/** Icon (recommended is 1 character) to render before the header itself. */
|
package/src/ui/Help.tsx
CHANGED
|
@@ -7,10 +7,10 @@ import * as icons from './icons.js';
|
|
|
7
7
|
import {type Program} from '../program.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* {@
|
|
10
|
+
* {@link Help} component props.
|
|
11
11
|
*/
|
|
12
12
|
export type HelpProps = BoxProps & {
|
|
13
|
-
/** {@
|
|
13
|
+
/** {@link Program} instance. */
|
|
14
14
|
program: Program;
|
|
15
15
|
};
|
|
16
16
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {Box, type BoxProps, Text, useInput, type Key} from 'ink';
|
|
2
2
|
import _ from 'lodash';
|
|
3
|
-
import {useState, useEffect, useRef
|
|
3
|
+
import {useState, useEffect, useRef} from 'react';
|
|
4
4
|
|
|
5
5
|
import {type SelectInputItem} from './SelectInputItem.js';
|
|
6
6
|
import * as colors from '../colors.js';
|
|
@@ -8,7 +8,7 @@ import * as icons from '../icons.js';
|
|
|
8
8
|
import {rotate} from '../internals.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* {@linkcode SelectInput} component props.
|
|
12
12
|
*/
|
|
13
13
|
type SelectInputProps = BoxProps & {
|
|
14
14
|
/** Text to display as a label. */
|
|
@@ -17,7 +17,7 @@ type SelectInputProps = BoxProps & {
|
|
|
17
17
|
/** Items to display in a list. */
|
|
18
18
|
items: SelectInputItem[];
|
|
19
19
|
|
|
20
|
-
/** Should component listen to
|
|
20
|
+
/** Should component listen to user's input? Useful in case there are multiple input components at the same time and input must be handled only by a specific component. */
|
|
21
21
|
focus?: boolean | undefined;
|
|
22
22
|
|
|
23
23
|
/** Index of initially selected item. */
|
|
@@ -44,17 +44,16 @@ export function SelectInput({
|
|
|
44
44
|
items = [],
|
|
45
45
|
focus = true,
|
|
46
46
|
initialIndex = 0,
|
|
47
|
-
limit:
|
|
47
|
+
limit: userDefinedLimit,
|
|
48
48
|
onSelect,
|
|
49
49
|
onHighlight,
|
|
50
|
-
marginTop = 0,
|
|
51
50
|
isComplete,
|
|
52
51
|
...boxProps
|
|
53
52
|
}: SelectInputProps): JSX.Element {
|
|
54
|
-
let [
|
|
53
|
+
let [rotatedIndex, setRotatedIndex] = useState(0);
|
|
55
54
|
let [selectedIndex, setSelectedIndex] = useState(initialIndex);
|
|
56
|
-
let hasLimit = typeof
|
|
57
|
-
let limit = hasLimit ? Math.min(
|
|
55
|
+
let hasLimit = typeof userDefinedLimit === 'number' && items.length > userDefinedLimit;
|
|
56
|
+
let limit = hasLimit ? Math.min(userDefinedLimit as number, items.length) : items.length;
|
|
58
57
|
let previousItems = useRef<SelectInputItem[]>(items);
|
|
59
58
|
|
|
60
59
|
useEffect(() => {
|
|
@@ -64,26 +63,26 @@ export function SelectInput({
|
|
|
64
63
|
items.map((item) => item.value),
|
|
65
64
|
)
|
|
66
65
|
) {
|
|
67
|
-
|
|
66
|
+
setRotatedIndex(0);
|
|
68
67
|
setSelectedIndex(0);
|
|
69
68
|
}
|
|
70
69
|
|
|
71
70
|
previousItems.current = items;
|
|
72
71
|
}, [items]);
|
|
73
72
|
|
|
74
|
-
|
|
73
|
+
useInput(
|
|
75
74
|
(input: string, key: Key) => {
|
|
76
75
|
if (input === 'k' || key.upArrow) {
|
|
77
76
|
let lastIndex = (hasLimit ? limit : items.length) - 1;
|
|
78
|
-
let
|
|
77
|
+
let isAtFirstIndex = selectedIndex === 0;
|
|
79
78
|
let nextIndex = hasLimit ? selectedIndex : lastIndex;
|
|
80
|
-
let
|
|
81
|
-
let nextSelectedIndex =
|
|
79
|
+
let nextRotatedIndex = isAtFirstIndex ? rotatedIndex + 1 : rotatedIndex;
|
|
80
|
+
let nextSelectedIndex = isAtFirstIndex ? nextIndex : selectedIndex - 1;
|
|
82
81
|
|
|
83
|
-
|
|
82
|
+
setRotatedIndex(nextRotatedIndex);
|
|
84
83
|
setSelectedIndex(nextSelectedIndex);
|
|
85
84
|
|
|
86
|
-
let slicedItems = hasLimit ? rotate(items,
|
|
85
|
+
let slicedItems = hasLimit ? rotate(items, nextRotatedIndex).slice(0, limit) : items;
|
|
87
86
|
|
|
88
87
|
if (typeof onHighlight === 'function') {
|
|
89
88
|
onHighlight(slicedItems[nextSelectedIndex] as SelectInputItem);
|
|
@@ -93,13 +92,13 @@ export function SelectInput({
|
|
|
93
92
|
if (input === 'j' || key.downArrow) {
|
|
94
93
|
let isAtLastIndex = selectedIndex === (hasLimit ? limit : items.length) - 1;
|
|
95
94
|
let nextIndex = hasLimit ? selectedIndex : 0;
|
|
96
|
-
let
|
|
95
|
+
let nextRotatedIndex = isAtLastIndex ? rotatedIndex - 1 : rotatedIndex;
|
|
97
96
|
let nextSelectedIndex = isAtLastIndex ? nextIndex : selectedIndex + 1;
|
|
98
97
|
|
|
99
|
-
|
|
98
|
+
setRotatedIndex(nextRotatedIndex);
|
|
100
99
|
setSelectedIndex(nextSelectedIndex);
|
|
101
100
|
|
|
102
|
-
let slicedItems = hasLimit ? rotate(items,
|
|
101
|
+
let slicedItems = hasLimit ? rotate(items, nextRotatedIndex).slice(0, limit) : items;
|
|
103
102
|
|
|
104
103
|
if (typeof onHighlight === 'function') {
|
|
105
104
|
onHighlight(slicedItems[nextSelectedIndex] as SelectInputItem);
|
|
@@ -107,20 +106,18 @@ export function SelectInput({
|
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
if (key.return) {
|
|
110
|
-
let slicedItems = hasLimit ? rotate(items,
|
|
109
|
+
let slicedItems = hasLimit ? rotate(items, rotatedIndex).slice(0, limit) : items;
|
|
111
110
|
|
|
112
111
|
if (typeof onSelect === 'function') {
|
|
113
112
|
onSelect(slicedItems[selectedIndex] as SelectInputItem);
|
|
114
113
|
}
|
|
115
114
|
}
|
|
116
115
|
},
|
|
117
|
-
|
|
116
|
+
{isActive: focus},
|
|
118
117
|
);
|
|
119
118
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
let visibleItem: SelectInputItem[] = hasLimit
|
|
123
|
-
? rotate(items, rotateIndex).slice(0, limit)
|
|
119
|
+
let visibleItems: SelectInputItem[] = hasLimit
|
|
120
|
+
? rotate(items, rotatedIndex).slice(0, limit)
|
|
124
121
|
: items;
|
|
125
122
|
|
|
126
123
|
return (
|
|
@@ -139,7 +136,7 @@ export function SelectInput({
|
|
|
139
136
|
</Text>
|
|
140
137
|
) : (
|
|
141
138
|
<Box flexDirection="column">
|
|
142
|
-
{
|
|
139
|
+
{visibleItems.map((item, index) => {
|
|
143
140
|
let isSelected = index === selectedIndex;
|
|
144
141
|
|
|
145
142
|
return (
|
|
@@ -151,9 +148,7 @@ export function SelectInput({
|
|
|
151
148
|
<Text color={colors.unselected}>{icons.unselectedCircle}</Text>
|
|
152
149
|
)}
|
|
153
150
|
</Box>
|
|
154
|
-
<Text
|
|
155
|
-
color={isSelected ? colors.highlighted : colors.muted}
|
|
156
|
-
>{`${item.label}`}</Text>
|
|
151
|
+
<Text color={isSelected ? colors.highlighted : colors.muted}>{item.label}</Text>
|
|
157
152
|
</Box>
|
|
158
153
|
);
|
|
159
154
|
})}
|
|
@@ -20,7 +20,7 @@ export type TextInputProps = BoxProps & {
|
|
|
20
20
|
/** Value. */
|
|
21
21
|
value: string;
|
|
22
22
|
|
|
23
|
-
/** Should component listen to Listen to user's input? Useful in case there are multiple input components at the same time and input must be
|
|
23
|
+
/** Should component listen to Listen to user's input? Useful in case there are multiple input components at the same time and input must be handled only by a specific component. */
|
|
24
24
|
focus?: boolean | undefined;
|
|
25
25
|
|
|
26
26
|
/** Replace all chars and mask the value. Useful for password inputs. */
|
|
@@ -87,7 +87,6 @@ export function TextInput({
|
|
|
87
87
|
let renderedValue = value;
|
|
88
88
|
let renderedPlaceholder = placeholder ? chalk[colors.muted](placeholder) : undefined;
|
|
89
89
|
|
|
90
|
-
// fake mouse cursor; dealing with with actual cursor and ANSI escape codes is inconvinient
|
|
91
90
|
if (showCursor && focus) {
|
|
92
91
|
renderedPlaceholder =
|
|
93
92
|
placeholder.length > 0
|
|
@@ -96,16 +95,12 @@ export function TextInput({
|
|
|
96
95
|
|
|
97
96
|
renderedValue = value.length > 0 ? '' : chalk.inverse(' ');
|
|
98
97
|
|
|
99
|
-
let i
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (i >= state.cursorOffset && i <= state.cursorOffset) {
|
|
103
|
-
renderedValue += chalk.inverse(char);
|
|
98
|
+
for (let [i, character] of Object.entries(value)) {
|
|
99
|
+
if (Number(i) >= state.cursorOffset && Number(i) <= state.cursorOffset) {
|
|
100
|
+
renderedValue += chalk.inverse(character);
|
|
104
101
|
} else {
|
|
105
|
-
renderedValue +=
|
|
102
|
+
renderedValue += character;
|
|
106
103
|
}
|
|
107
|
-
|
|
108
|
-
i += 1;
|
|
109
104
|
}
|
|
110
105
|
|
|
111
106
|
if (value.length > 0 && state.cursorOffset === value.length) {
|
package/src/ui/getErrorDetail.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {ValidationError, ParsingError} from '@jakubmazanec/args';
|
|
2
|
+
import {zodIssuesToStrings} from '@jakubmazanec/zod-utils';
|
|
3
|
+
import {ZodError} from 'zod';
|
|
2
4
|
|
|
3
5
|
import {type ErrorDetail} from './ErrorDetail.js';
|
|
4
6
|
|
|
@@ -44,6 +46,15 @@ export function getErrorDetail(error: unknown): ErrorDetail {
|
|
|
44
46
|
return errorDetail;
|
|
45
47
|
}
|
|
46
48
|
|
|
49
|
+
if (error instanceof ZodError) {
|
|
50
|
+
let errorDetail: ErrorDetail = {
|
|
51
|
+
label: 'Error',
|
|
52
|
+
description: zodIssuesToStrings(error.issues).join('\n'),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return errorDetail;
|
|
56
|
+
}
|
|
57
|
+
|
|
47
58
|
if (error instanceof Error) {
|
|
48
59
|
let errorDetail: ErrorDetail = {
|
|
49
60
|
label: 'Error',
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import {Box} from 'ink';
|
|
2
2
|
import {useMemo, type FC, type PropsWithChildren} from 'react';
|
|
3
|
-
import
|
|
3
|
+
import {ErrorBoundary} from 'react-error-boundary';
|
|
4
4
|
|
|
5
5
|
import {programContext} from './programContext.js';
|
|
6
6
|
import {type Program} from '../../program.js';
|
|
7
7
|
import {Failure} from '../Failure.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* {@
|
|
10
|
+
* {@link Wrapper} component props.
|
|
11
11
|
*/
|
|
12
12
|
export type WrapperProps = {
|
|
13
13
|
program: Program;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* A component that wraps anything {@
|
|
17
|
+
* A component that wraps anything {@link Program} tries to render with an error boundary and all neccessary providers.
|
|
18
18
|
*/
|
|
19
19
|
export const Wrapper: FC<PropsWithChildren<WrapperProps>> = ({program, children}) => {
|
|
20
20
|
let programContextValue = useMemo(
|
|
@@ -25,10 +25,10 @@ export const Wrapper: FC<PropsWithChildren<WrapperProps>> = ({program, children}
|
|
|
25
25
|
);
|
|
26
26
|
|
|
27
27
|
return (
|
|
28
|
-
<
|
|
28
|
+
<ErrorBoundary FallbackComponent={Failure}>
|
|
29
29
|
<programContext.Provider value={programContextValue}>
|
|
30
30
|
<Box>{children}</Box>
|
|
31
31
|
</programContext.Provider>
|
|
32
|
-
</
|
|
32
|
+
</ErrorBoundary>
|
|
33
33
|
);
|
|
34
34
|
};
|
package/src/ui/useProgram.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {useApp} from 'ink';
|
|
2
2
|
import {useCallback, useContext} from 'react';
|
|
3
|
-
import
|
|
3
|
+
import {useErrorBoundary} from 'react-error-boundary';
|
|
4
4
|
|
|
5
5
|
import {programContext} from './internals.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* A React hook for accessing {@
|
|
8
|
+
* A React hook for accessing {@link Program} instance and `exit` function that is used for showing an error (via an error boundary) and exiting.
|
|
9
9
|
*/
|
|
10
10
|
export function useProgram() {
|
|
11
|
-
let {showBoundary} =
|
|
11
|
+
let {showBoundary} = useErrorBoundary();
|
|
12
12
|
let {exit: appExit} = useApp();
|
|
13
13
|
let {program} = useContext(programContext);
|
|
14
14
|
|