@jakubmazanec/cli 0.3.4 → 0.3.5-unstable.91147a2
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/ui/Failure.d.ts +2 -2
- package/build/ui/Failure.js +3 -3
- package/build/ui/Failure.js.map +2 -2
- package/build/ui/Header.d.ts +2 -2
- package/build/ui/Header.js.map +1 -1
- package/build/ui/Help.d.ts +2 -2
- package/build/ui/Help.js +1 -1
- package/build/ui/Help.js.map +2 -2
- package/build/ui/form/Form.d.ts +2 -2
- package/build/ui/form/FormProps.d.ts +3 -3
- package/build/ui/form/FormRow.d.ts +2 -2
- package/build/ui/form/FormRow.js +16 -12
- package/build/ui/form/FormRow.js.map +2 -2
- package/build/ui/form/SelectInput.d.ts +2 -2
- package/build/ui/form/SelectInput.js.map +1 -1
- package/build/ui/form/TextInput.d.ts +2 -2
- package/build/ui/form/TextInput.js +2 -2
- package/build/ui/form/TextInput.js.map +2 -2
- package/build/ui/form/createForm.js +3 -3
- package/build/ui/form/createForm.js.map +2 -2
- package/build/ui/form.d.ts +9 -9
- package/build/ui/form.js +0 -9
- package/build/ui/form.js.map +2 -2
- package/build/ui/getErrorDetail.js.map +2 -2
- package/build/ui/internals/Wrapper.js +3 -3
- package/build/ui/internals/Wrapper.js.map +2 -2
- package/build/ui/useProgram.js.map +2 -2
- package/package.json +7 -7
- package/source/ui/Failure.tsx +5 -5
- package/source/ui/Header.tsx +2 -2
- package/source/ui/Help.tsx +3 -3
- package/source/ui/form/Form.ts +1 -1
- package/source/ui/form/FormProps.ts +4 -4
- package/source/ui/form/FormRow.tsx +22 -17
- package/source/ui/form/SelectInput.tsx +2 -2
- package/source/ui/form/TextInput.tsx +4 -6
- package/source/ui/form/createForm.tsx +4 -4
- package/source/ui/form.ts +9 -9
- package/source/ui/getErrorDetail.ts +2 -0
- package/source/ui/internals/Wrapper.tsx +3 -3
- package/source/ui/useProgram.ts +2 -0
package/build/ui/Failure.d.ts
CHANGED
|
@@ -3,12 +3,12 @@ import { type ErrorDetail } from './ErrorDetail.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* {@link Failure} component props.
|
|
5
5
|
*/
|
|
6
|
-
export type FailureProps =
|
|
6
|
+
export type FailureProps = {
|
|
7
7
|
/** 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. */
|
|
8
8
|
error: Error;
|
|
9
9
|
/** Information about the failure state. Overrides information retireved from `error` prop. */
|
|
10
10
|
errorDetail?: ErrorDetail;
|
|
11
|
-
};
|
|
11
|
+
} & BoxProps;
|
|
12
12
|
/**
|
|
13
13
|
* A component that renders a failure state.
|
|
14
14
|
*/
|
package/build/ui/Failure.js
CHANGED
|
@@ -10,10 +10,10 @@ export function Failure({ error, errorDetail, ...boxProps }) {
|
|
|
10
10
|
return /* @__PURE__ */ jsxs(Box, { ...boxProps, flexDirection: "column", children: [
|
|
11
11
|
/* @__PURE__ */ jsx(Header, { icon: icons.error, children: /* @__PURE__ */ jsx(Text, { color: colors.highlighted, children: label }) }),
|
|
12
12
|
description ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: colors.failure, children: description }) }) : null,
|
|
13
|
-
stack ? /* @__PURE__ */ jsx(Box, { flexDirection: "column",
|
|
13
|
+
stack ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.muted, children: stack }) }) : null,
|
|
14
14
|
cause ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
15
|
-
/* @__PURE__ */ jsx(Box, { flexDirection: "column",
|
|
16
|
-
cause.stack ? /* @__PURE__ */ jsx(Box, { flexDirection: "column",
|
|
15
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.muted, children: cause.description }) }),
|
|
16
|
+
cause.stack ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.muted, children: cause.stack }) }) : null
|
|
17
17
|
] }) : null
|
|
18
18
|
] });
|
|
19
19
|
}
|
package/build/ui/Failure.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../source/ui/Failure.tsx"],
|
|
4
|
-
"sourcesContent": ["import {Box, type BoxProps, Text} from 'ink';\n\nimport * as colors from './colors.js';\nimport {type ErrorDetail} from './ErrorDetail.js';\nimport {getErrorDetail} from './getErrorDetail.js';\nimport {Header} from './Header.js';\nimport * as icons from './icons.js';\n\n/**\n * {@link Failure} component props.\n */\nexport type FailureProps =
|
|
5
|
-
"mappings": ";AA4BQ,SAgBA,UAhBA,KAgBA,YAhBA;AA5BR,SAAQ,KAAoB,YAAW;AAEvC,YAAY,YAAY;AAExB,SAAQ,sBAAqB;AAC7B,SAAQ,cAAa;AACrB,YAAY,WAAW;AAgBhB,gBAAS,QAAQ,EAAC,OAAO,aAAa,GAAG,SAAQ,GAAiB;AACvE,MAAI,EAAC,OAAO,aAAa,OAAO,MAAK,IAAI,eAAe,eAAe,KAAK;AAE5E,SACE,qBAAC,OAAK,GAAG,UAAU,eAAc,UAC/B;AAAA,wBAAC,UAAO,MAAM,MAAM,OAClB,8BAAC,QAAK,OAAO,OAAO,aAAc,iBAAM,GAC1C;AAAA,IAEC,cACC,oBAAC,OAAI,eAAc,UAAS,YAAY,GACtC,8BAAC,QAAK,OAAO,OAAO,SAAU,uBAAY,GAC5C,IACA;AAAA,IAED,QACC,oBAAC,OAAI,eAAc,UAAS,
|
|
4
|
+
"sourcesContent": ["import {Box, type BoxProps, Text} from 'ink';\n\nimport * as colors from './colors.js';\nimport {type ErrorDetail} from './ErrorDetail.js';\nimport {getErrorDetail} from './getErrorDetail.js';\nimport {Header} from './Header.js';\nimport * as icons from './icons.js';\n\n/**\n * {@link Failure} component props.\n */\nexport type FailureProps = {\n /** 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. */\n error: Error;\n\n /** Information about the failure state. Overrides information retireved from `error` prop. */\n errorDetail?: ErrorDetail;\n} & BoxProps;\n\n/**\n * A component that renders a failure state.\n */\nexport function Failure({error, errorDetail, ...boxProps}: FailureProps) {\n let {label, description, stack, cause} = errorDetail ?? getErrorDetail(error);\n\n return (\n <Box {...boxProps} flexDirection=\"column\">\n <Header icon={icons.error}>\n <Text color={colors.highlighted}>{label}</Text>\n </Header>\n\n {description ?\n <Box flexDirection=\"column\" marginLeft={2}>\n <Text color={colors.failure}>{description}</Text>\n </Box>\n : null}\n\n {stack ?\n <Box flexDirection=\"column\" marginLeft={2} marginTop={1}>\n <Text color={colors.muted}>{stack}</Text>\n </Box>\n : null}\n\n {cause ?\n <>\n <Box flexDirection=\"column\" marginLeft={2} marginTop={1}>\n <Text color={colors.muted}>{cause.description}</Text>\n </Box>\n\n {cause.stack ?\n <Box flexDirection=\"column\" marginLeft={2} marginTop={1}>\n <Text color={colors.muted}>{cause.stack}</Text>\n </Box>\n : null}\n </>\n : null}\n </Box>\n );\n}\n"],
|
|
5
|
+
"mappings": ";AA4BQ,SAgBA,UAhBA,KAgBA,YAhBA;AA5BR,SAAQ,KAAoB,YAAW;AAEvC,YAAY,YAAY;AAExB,SAAQ,sBAAqB;AAC7B,SAAQ,cAAa;AACrB,YAAY,WAAW;AAgBhB,gBAAS,QAAQ,EAAC,OAAO,aAAa,GAAG,SAAQ,GAAiB;AACvE,MAAI,EAAC,OAAO,aAAa,OAAO,MAAK,IAAI,eAAe,eAAe,KAAK;AAE5E,SACE,qBAAC,OAAK,GAAG,UAAU,eAAc,UAC/B;AAAA,wBAAC,UAAO,MAAM,MAAM,OAClB,8BAAC,QAAK,OAAO,OAAO,aAAc,iBAAM,GAC1C;AAAA,IAEC,cACC,oBAAC,OAAI,eAAc,UAAS,YAAY,GACtC,8BAAC,QAAK,OAAO,OAAO,SAAU,uBAAY,GAC5C,IACA;AAAA,IAED,QACC,oBAAC,OAAI,eAAc,UAAS,YAAY,GAAG,WAAW,GACpD,8BAAC,QAAK,OAAO,OAAO,OAAQ,iBAAM,GACpC,IACA;AAAA,IAED,QACC,iCACE;AAAA,0BAAC,OAAI,eAAc,UAAS,YAAY,GAAG,WAAW,GACpD,8BAAC,QAAK,OAAO,OAAO,OAAQ,gBAAM,aAAY,GAChD;AAAA,MAEC,MAAM,QACL,oBAAC,OAAI,eAAc,UAAS,YAAY,GAAG,WAAW,GACpD,8BAAC,QAAK,OAAO,OAAO,OAAQ,gBAAM,OAAM,GAC1C,IACA;AAAA,OACJ,IACA;AAAA,KACJ;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/ui/Header.d.ts
CHANGED
|
@@ -3,12 +3,12 @@ import { type PropsWithChildren } from 'react';
|
|
|
3
3
|
/**
|
|
4
4
|
* {@link Header} component props.
|
|
5
5
|
*/
|
|
6
|
-
export type HeaderProps =
|
|
6
|
+
export type HeaderProps = {
|
|
7
7
|
/** Icon (recommended is 1 character) to render before the header itself. */
|
|
8
8
|
icon?: string;
|
|
9
9
|
/** Show spinner instead of the icon. */
|
|
10
10
|
showSpinner?: boolean;
|
|
11
|
-
};
|
|
11
|
+
} & BoxProps;
|
|
12
12
|
/**
|
|
13
13
|
* Header component.
|
|
14
14
|
*/
|
package/build/ui/Header.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../source/ui/Header.tsx"],
|
|
4
|
-
"sourcesContent": ["import {Box, type BoxProps, Text} from 'ink';\nimport {type PropsWithChildren} from 'react';\n\nimport {Spinner} from './Spinner.js';\n\n/**\n * {@link Header} component props.\n */\nexport type HeaderProps =
|
|
4
|
+
"sourcesContent": ["import {Box, type BoxProps, Text} from 'ink';\nimport {type PropsWithChildren} from 'react';\n\nimport {Spinner} from './Spinner.js';\n\n/**\n * {@link Header} component props.\n */\nexport type HeaderProps = {\n /** Icon (recommended is 1 character) to render before the header itself. */\n icon?: string;\n\n /** Show spinner instead of the icon. */\n showSpinner?: boolean;\n} & BoxProps;\n\n/**\n * Header component.\n */\nexport function Header({\n children,\n icon,\n showSpinner = false,\n ...boxProps\n}: PropsWithChildren<HeaderProps>) {\n return (\n <Box {...boxProps}>\n {icon || showSpinner ?\n <Box marginRight={1}>\n {showSpinner ?\n <Spinner />\n : null}\n {!showSpinner && icon ?\n <Text>{icon}</Text>\n : null}\n </Box>\n : null}\n <Box>{children}</Box>\n </Box>\n );\n}\n"],
|
|
5
5
|
"mappings": ";AA4BQ,SAEI,KAFJ;AA5BR,SAAQ,KAAoB,YAAW;AAGvC,SAAQ,eAAc;AAgBf,gBAAS,OAAO;AAAA,EACrB;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,GAAG;AACL,GAAmC;AACjC,SACE,qBAAC,OAAK,GAAG,UACN;AAAA,YAAQ,cACP,qBAAC,OAAI,aAAa,GACf;AAAA,oBACC,oBAAC,WAAQ,IACT;AAAA,MACD,CAAC,eAAe,OACf,oBAAC,QAAM,gBAAK,IACZ;AAAA,OACJ,IACA;AAAA,IACF,oBAAC,OAAK,UAAS;AAAA,KACjB;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/ui/Help.d.ts
CHANGED
|
@@ -3,10 +3,10 @@ import { type Program } from '../program.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* {@link Help} component props.
|
|
5
5
|
*/
|
|
6
|
-
export type HelpProps =
|
|
6
|
+
export type HelpProps = {
|
|
7
7
|
/** {@link Program} instance. */
|
|
8
8
|
program: Program;
|
|
9
|
-
};
|
|
9
|
+
} & BoxProps;
|
|
10
10
|
/**
|
|
11
11
|
* A component that renders help information.
|
|
12
12
|
*/
|
package/build/ui/Help.js
CHANGED
|
@@ -30,7 +30,7 @@ export function Help({ program, ...boxProps }) {
|
|
|
30
30
|
if (command.description) {
|
|
31
31
|
line += ` ${command.description}`;
|
|
32
32
|
}
|
|
33
|
-
return /* @__PURE__ */ jsx(Box, {
|
|
33
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { children: line }) }, command.name);
|
|
34
34
|
})
|
|
35
35
|
] }) : null
|
|
36
36
|
] });
|
package/build/ui/Help.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../source/ui/Help.tsx"],
|
|
4
|
-
"sourcesContent": ["import chalk from 'chalk';\nimport {Box, type BoxProps, Text} from 'ink';\n\nimport {type Program} from '../program.js';\nimport * as colors from './colors.js';\nimport {Header} from './Header.js';\nimport * as icons from './icons.js';\n\n/**\n * {@link Help} component props.\n */\nexport type HelpProps =
|
|
5
|
-
"mappings": ";AAsBM,SAME,UANF,KAME,YANF;AAtBN,OAAO,WAAW;AAClB,SAAQ,KAAoB,YAAW;AAGvC,YAAY,YAAY;AACxB,SAAQ,cAAa;AACrB,YAAY,WAAW;AAahB,gBAAS,KAAK,EAAC,SAAS,GAAG,SAAQ,GAAc;AACtD,SACE,qBAAC,OAAK,GAAG,UAAU,eAAc,UAC/B;AAAA,wBAAC,QAAM,aAAG,MAAM,OAAO,MAAM,EAAE,QAAQ,eAAe,QAAQ,QAAQ,GAAG,CAAC,IAAI,MAC5E,OAAO,KACT,EAAE,QAAQ,WAAW,GAAG,CAAC,IAAG;AAAA,IAC5B,oBAAC,QAAK,OAAO,OAAO,MAAO,kBAAQ,aAAY;AAAA,IAE9C,QAAQ,SAAS,SAChB,iCACE;AAAA,0BAAC,UAAO,MAAM,MAAM,MAAM,WAAW,GACnC,8BAAC,QAAK,OAAO,OAAO,aAAa,mBAAK,GACxC;AAAA,MACC,QAAQ,SAAS,IAAI,CAAC,YAAY;AACjC,YAAI,OAAO,GAAG,MAAM,OAAO,KAAK,EAAE,QAAQ,OAAO,GAAG,CAAC,IAAI,QAAQ,IAAI;AAErE,YAAI,QAAQ,YAAY;AACtB,cAAI,QAAQ,WAAW,KAAK,CAAC,oBAAoB,CAAC,CAAC,gBAAgB,QAAQ,GAAG;AAC5E,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,cAAc,CAAC;AAAA,UACjD,OAAO;AACL,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,gBAAgB,CAAC;AAAA,UACnD;AAAA,QACF;AAEA,YAAI,QAAQ,SAAS;AACnB,cACE,OAAO,QAAQ,QAAQ,OAAO,EAAE,KAAK,CAAC,CAAC,EAAE,YAAY,MAAM,CAAC,CAAC,aAAa,QAAQ,GAClF;AACA,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,WAAW,CAAC;AAAA,UAC9C,OAAO;AACL,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,aAAa,CAAC;AAAA,UAChD;AAAA,QACF;AAEA,YAAI,QAAQ,aAAa;AACvB,kBAAQ,IAAI,QAAQ,WAAW;AAAA,QACjC;AAEA,eACE,oBAAC,OAAuB,
|
|
4
|
+
"sourcesContent": ["import chalk from 'chalk';\nimport {Box, type BoxProps, Text} from 'ink';\n\nimport {type Program} from '../program.js';\nimport * as colors from './colors.js';\nimport {Header} from './Header.js';\nimport * as icons from './icons.js';\n\n/**\n * {@link Help} component props.\n */\nexport type HelpProps = {\n /** {@link Program} instance. */\n program: Program;\n} & BoxProps;\n\n/**\n * A component that renders help information.\n */\nexport function Help({program, ...boxProps}: HelpProps) {\n return (\n <Box {...boxProps} flexDirection=\"column\">\n <Text>{`${chalk[colors.notice](program.displayName ?? program.name ?? '?')} ${chalk[\n colors.muted\n ](program.version ?? '?')}`}</Text>\n <Text color={colors.body}>{program.description}</Text>\n\n {program.commands.length ?\n <>\n <Header icon={icons.info} marginTop={1}>\n <Text color={colors.highlighted}>Usage</Text>\n </Header>\n {program.commands.map((command) => {\n let line = `${chalk[colors.muted](program.bin ?? '?')} ${command.name}`;\n\n if (command.parameters) {\n if (command.parameters.some((parameterConfig) => !!parameterConfig.required)) {\n line += ` ${chalk[colors.muted]('<parameters>')}`;\n } else {\n line += ` ${chalk[colors.muted]('[<parameters>]')}`;\n }\n }\n\n if (command.options) {\n if (\n Object.entries(command.options).some(([, optionConfig]) => !!optionConfig.required)\n ) {\n line += ` ${chalk[colors.muted]('<options>')}`;\n } else {\n line += ` ${chalk[colors.muted]('[<options>]')}`;\n }\n }\n\n if (command.description) {\n line += ` ${command.description}`;\n }\n\n return (\n <Box key={command.name} flexDirection=\"column\" marginLeft={2}>\n <Text>{line}</Text>\n </Box>\n );\n })}\n </>\n : null}\n </Box>\n );\n}\n"],
|
|
5
|
+
"mappings": ";AAsBM,SAME,UANF,KAME,YANF;AAtBN,OAAO,WAAW;AAClB,SAAQ,KAAoB,YAAW;AAGvC,YAAY,YAAY;AACxB,SAAQ,cAAa;AACrB,YAAY,WAAW;AAahB,gBAAS,KAAK,EAAC,SAAS,GAAG,SAAQ,GAAc;AACtD,SACE,qBAAC,OAAK,GAAG,UAAU,eAAc,UAC/B;AAAA,wBAAC,QAAM,aAAG,MAAM,OAAO,MAAM,EAAE,QAAQ,eAAe,QAAQ,QAAQ,GAAG,CAAC,IAAI,MAC5E,OAAO,KACT,EAAE,QAAQ,WAAW,GAAG,CAAC,IAAG;AAAA,IAC5B,oBAAC,QAAK,OAAO,OAAO,MAAO,kBAAQ,aAAY;AAAA,IAE9C,QAAQ,SAAS,SAChB,iCACE;AAAA,0BAAC,UAAO,MAAM,MAAM,MAAM,WAAW,GACnC,8BAAC,QAAK,OAAO,OAAO,aAAa,mBAAK,GACxC;AAAA,MACC,QAAQ,SAAS,IAAI,CAAC,YAAY;AACjC,YAAI,OAAO,GAAG,MAAM,OAAO,KAAK,EAAE,QAAQ,OAAO,GAAG,CAAC,IAAI,QAAQ,IAAI;AAErE,YAAI,QAAQ,YAAY;AACtB,cAAI,QAAQ,WAAW,KAAK,CAAC,oBAAoB,CAAC,CAAC,gBAAgB,QAAQ,GAAG;AAC5E,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,cAAc,CAAC;AAAA,UACjD,OAAO;AACL,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,gBAAgB,CAAC;AAAA,UACnD;AAAA,QACF;AAEA,YAAI,QAAQ,SAAS;AACnB,cACE,OAAO,QAAQ,QAAQ,OAAO,EAAE,KAAK,CAAC,CAAC,EAAE,YAAY,MAAM,CAAC,CAAC,aAAa,QAAQ,GAClF;AACA,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,WAAW,CAAC;AAAA,UAC9C,OAAO;AACL,oBAAQ,IAAI,MAAM,OAAO,KAAK,EAAE,aAAa,CAAC;AAAA,UAChD;AAAA,QACF;AAEA,YAAI,QAAQ,aAAa;AACvB,kBAAQ,IAAI,QAAQ,WAAW;AAAA,QACjC;AAEA,eACE,oBAAC,OAAuB,eAAc,UAAS,YAAY,GACzD,8BAAC,QAAM,gBAAK,KADJ,QAAQ,IAElB;AAAA,MAEJ,CAAC;AAAA,OACH,IACA;AAAA,KACJ;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/ui/form/Form.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ type FormPropsRows<C extends FormConfig> = Pick<{
|
|
|
18
18
|
/**
|
|
19
19
|
* Form component props.
|
|
20
20
|
*/
|
|
21
|
-
export type FormProps<C extends FormConfig> = FormPropsRows<C> extends Record<number | string | symbol, never> ?
|
|
21
|
+
export type FormProps<C extends FormConfig> = FormPropsRows<C> extends Record<number | string | symbol, never> ? {
|
|
22
22
|
/** Props for each row. */
|
|
23
23
|
rows?: null | undefined;
|
|
24
24
|
/** Form values */
|
|
@@ -27,7 +27,7 @@ export type FormProps<C extends FormConfig> = FormPropsRows<C> extends Record<nu
|
|
|
27
27
|
onChange?: ((formResult: FormValues<C>) => void) | undefined;
|
|
28
28
|
/** Handler function that is called when the value is accepted. */
|
|
29
29
|
onComplete: (formResult: FormValues<C>) => void;
|
|
30
|
-
}
|
|
30
|
+
} & BoxProps : {
|
|
31
31
|
/** Props for each row. */
|
|
32
32
|
rows: FormPropsRows<C>;
|
|
33
33
|
/** Form values */
|
|
@@ -36,5 +36,5 @@ export type FormProps<C extends FormConfig> = FormPropsRows<C> extends Record<nu
|
|
|
36
36
|
onChange?: ((formResult: FormValues<C>) => void) | undefined;
|
|
37
37
|
/** Handler function that is called when the value is accepted. */
|
|
38
38
|
onComplete: (formResult: FormValues<C>) => void;
|
|
39
|
-
};
|
|
39
|
+
} & BoxProps;
|
|
40
40
|
export {};
|
|
@@ -5,7 +5,7 @@ import { type FormRowConfig } from './FormRowConfig.js';
|
|
|
5
5
|
/**
|
|
6
6
|
* Form row component props.
|
|
7
7
|
*/
|
|
8
|
-
type FormRowProps<C extends FormConfig> =
|
|
8
|
+
type FormRowProps<C extends FormConfig> = {
|
|
9
9
|
/** Form row configuration. */
|
|
10
10
|
config: FormRowConfig;
|
|
11
11
|
/** Props of all form rows. */
|
|
@@ -22,7 +22,7 @@ type FormRowProps<C extends FormConfig> = BoxProps & {
|
|
|
22
22
|
onComplete: (value: unknown, inputName: keyof C['rows']) => void;
|
|
23
23
|
/** Indicates whether value has been accepted. Component in the row then doesn't accept more input. */
|
|
24
24
|
isComplete: boolean;
|
|
25
|
-
};
|
|
25
|
+
} & BoxProps;
|
|
26
26
|
/**
|
|
27
27
|
* Form row component.
|
|
28
28
|
*/
|
package/build/ui/form/FormRow.js
CHANGED
|
@@ -33,37 +33,41 @@ export function FormRow({
|
|
|
33
33
|
[rowName, onComplete]
|
|
34
34
|
);
|
|
35
35
|
switch (config.type) {
|
|
36
|
-
case "
|
|
36
|
+
case "confirm": {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
case "select": {
|
|
37
40
|
return /* @__PURE__ */ jsx(
|
|
38
|
-
|
|
41
|
+
SelectInput,
|
|
39
42
|
{
|
|
40
|
-
|
|
41
|
-
validate: config.validate,
|
|
42
|
-
value,
|
|
43
|
+
items: rows ? rows[rowName].choices : [],
|
|
43
44
|
focus,
|
|
44
45
|
isComplete,
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
label: config.label ?? "",
|
|
47
|
+
onSelect: handleSelectFinish,
|
|
47
48
|
...boxProps
|
|
48
49
|
},
|
|
49
50
|
String(rowName)
|
|
50
51
|
);
|
|
51
52
|
}
|
|
52
|
-
case "
|
|
53
|
+
case "text": {
|
|
53
54
|
return /* @__PURE__ */ jsx(
|
|
54
|
-
|
|
55
|
+
TextInput,
|
|
55
56
|
{
|
|
56
|
-
label: config.label ?? "",
|
|
57
|
-
items: rows ? rows[rowName].choices : [],
|
|
58
57
|
focus,
|
|
59
58
|
isComplete,
|
|
60
|
-
|
|
59
|
+
label: config.label ?? "",
|
|
60
|
+
validate: config.validate,
|
|
61
|
+
value,
|
|
62
|
+
onChange: handleChange,
|
|
63
|
+
onSubmit: handleFinish,
|
|
61
64
|
...boxProps
|
|
62
65
|
},
|
|
63
66
|
String(rowName)
|
|
64
67
|
);
|
|
65
68
|
}
|
|
66
69
|
default: {
|
|
70
|
+
config;
|
|
67
71
|
return null;
|
|
68
72
|
}
|
|
69
73
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../source/ui/form/FormRow.tsx"],
|
|
4
|
-
"sourcesContent": ["import {type BoxProps} from 'ink';\nimport {useCallback} from 'react';\n\nimport {type FormConfig} from './FormConfig.js';\nimport {type FormProps} from './FormProps.js';\nimport {type FormRowConfig} from './FormRowConfig.js';\nimport {SelectInput} from './SelectInput.js';\nimport {TextInput} from './TextInput.js';\n\n/**\n * Form row component props.\n */\ntype FormRowProps<C extends FormConfig> =
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["import {type BoxProps} from 'ink';\nimport {useCallback} from 'react';\n\nimport {type FormConfig} from './FormConfig.js';\nimport {type FormProps} from './FormProps.js';\nimport {type FormRowConfig} from './FormRowConfig.js';\nimport {SelectInput} from './SelectInput.js';\nimport {TextInput} from './TextInput.js';\n\n/**\n * Form row component props.\n */\ntype FormRowProps<C extends FormConfig> = {\n /** Form row configuration. */\n config: FormRowConfig;\n\n // TODO: Should all rows props be passed to each row?\n /** Props of all form rows. */\n rows: FormProps<C>['rows'] | null;\n\n /** Row name. */\n rowName: keyof C['rows'];\n\n /** Value. */\n value: unknown;\n\n /** 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 \"routed\" to a specific component. */\n focus: boolean;\n\n /** Handler function that is called when value changes. */\n onChange: (value: unknown, inputName: keyof C['rows']) => void;\n\n /** Handler function that is called when the value is accepted. */\n onComplete: (value: unknown, inputName: keyof C['rows']) => void;\n\n /** Indicates whether value has been accepted. Component in the row then doesn't accept more input. */\n isComplete: boolean;\n} & BoxProps;\n\n/**\n * Form row component.\n */\nexport function FormRow<C extends FormConfig>({\n rowName,\n config,\n rows,\n value,\n focus,\n isComplete,\n onChange,\n onComplete,\n ...boxProps\n}: FormRowProps<C>) {\n // TODO: Each input component handles values and events differently; the APIs should be adjusted.\n let handleChange = useCallback(\n (newValue: unknown) => {\n onChange(newValue, rowName);\n },\n [rowName, onChange],\n );\n\n let handleFinish = useCallback(\n (newValue: unknown) => {\n onComplete(newValue, rowName);\n },\n [rowName, onComplete],\n );\n\n let handleSelectFinish = useCallback(\n (item: {value: unknown}) => {\n onComplete(item.value, rowName);\n },\n [rowName, onComplete],\n );\n\n switch (config.type) {\n case 'confirm': {\n return null;\n }\n case 'select': {\n return (\n <SelectInput\n key={String(rowName)}\n items={\n rows ?\n (\n (\n rows as {\n [key: string]: unknown;\n }\n )[rowName as string] as {choices: Array<{value: string; label: string}>}\n ).choices\n : []\n }\n focus={focus}\n isComplete={isComplete}\n label={config.label ?? ''}\n onSelect={handleSelectFinish}\n {...boxProps}\n />\n );\n }\n case 'text': {\n return (\n <TextInput\n key={String(rowName)}\n focus={focus}\n isComplete={isComplete}\n label={config.label ?? ''}\n validate={config.validate}\n value={value as string}\n onChange={handleChange}\n onSubmit={handleFinish}\n {...boxProps}\n />\n );\n }\n default: {\n config satisfies never;\n\n return null;\n }\n }\n}\n"],
|
|
5
|
+
"mappings": ";AAiFQ;AAhFR,SAAQ,mBAAkB;AAK1B,SAAQ,mBAAkB;AAC1B,SAAQ,iBAAgB;AAmCjB,gBAAS,QAA8B;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAoB;AAElB,MAAI,eAAe;AAAA,IACjB,CAAC,aAAsB;AACrB,eAAS,UAAU,OAAO;AAAA,IAC5B;AAAA,IACA,CAAC,SAAS,QAAQ;AAAA,EACpB;AAEA,MAAI,eAAe;AAAA,IACjB,CAAC,aAAsB;AACrB,iBAAW,UAAU,OAAO;AAAA,IAC9B;AAAA,IACA,CAAC,SAAS,UAAU;AAAA,EACtB;AAEA,MAAI,qBAAqB;AAAA,IACvB,CAAC,SAA2B;AAC1B,iBAAW,KAAK,OAAO,OAAO;AAAA,IAChC;AAAA,IACA,CAAC,SAAS,UAAU;AAAA,EACtB;AAEA,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK,WAAW;AACd,aAAO;AAAA,IACT;AAAA,IACA,KAAK,UAAU;AACb,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,OACE,OAGM,KAGA,OAAiB,EACnB,UACF,CAAC;AAAA,UAEL;AAAA,UACA;AAAA,UACA,OAAO,OAAO,SAAS;AAAA,UACvB,UAAU;AAAA,UACT,GAAG;AAAA;AAAA,QAhBC,OAAO,OAAO;AAAA,MAiBrB;AAAA,IAEJ;AAAA,IACA,KAAK,QAAQ;AACX,aACE;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA;AAAA,UACA,OAAO,OAAO,SAAS;AAAA,UACvB,UAAU,OAAO;AAAA,UACjB;AAAA,UACA,UAAU;AAAA,UACV,UAAU;AAAA,UACT,GAAG;AAAA;AAAA,QARC,OAAO,OAAO;AAAA,MASrB;AAAA,IAEJ;AAAA,IACA,SAAS;AACP;AAEA,aAAO;AAAA,IACT;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,7 +3,7 @@ import { type SelectInputItem } from './SelectInputItem.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* {@linkcode SelectInput} component props.
|
|
5
5
|
*/
|
|
6
|
-
type SelectInputProps =
|
|
6
|
+
type SelectInputProps = {
|
|
7
7
|
/** Text to display as a label. */
|
|
8
8
|
label: string;
|
|
9
9
|
/** Items to display in a list. */
|
|
@@ -20,7 +20,7 @@ type SelectInputProps = BoxProps & {
|
|
|
20
20
|
onHighlight?: ((item: SelectInputItem) => void) | undefined;
|
|
21
21
|
/** Indicates whether value has been accepted. Component then doesn't accept more input. */
|
|
22
22
|
isComplete?: boolean | undefined;
|
|
23
|
-
};
|
|
23
|
+
} & BoxProps;
|
|
24
24
|
/**
|
|
25
25
|
* Select input component.
|
|
26
26
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../source/ui/form/SelectInput.tsx"],
|
|
4
|
-
"sourcesContent": ["import {Box, type BoxProps, type Key, Text, useInput} from 'ink';\nimport _ from 'lodash';\nimport {useEffect, useRef, useState} from 'react';\n\nimport * as colors from '../colors.js';\nimport * as icons from '../icons.js';\nimport {rotate} from '../internals.js';\nimport {type SelectInputItem} from './SelectInputItem.js';\n\n/**\n * {@linkcode SelectInput} component props.\n */\ntype SelectInputProps =
|
|
4
|
+
"sourcesContent": ["import {Box, type BoxProps, type Key, Text, useInput} from 'ink';\nimport _ from 'lodash';\nimport {useEffect, useRef, useState} from 'react';\n\nimport * as colors from '../colors.js';\nimport * as icons from '../icons.js';\nimport {rotate} from '../internals.js';\nimport {type SelectInputItem} from './SelectInputItem.js';\n\n/**\n * {@linkcode SelectInput} component props.\n */\ntype SelectInputProps = {\n /** Text to display as a label. */\n label: string;\n\n /** Items to display in a list. */\n items: SelectInputItem[];\n\n /** 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. */\n focus?: boolean | undefined;\n\n /** Index of initially selected item. */\n initialIndex?: number | undefined;\n\n /** Number of items to display. */\n limit?: number | undefined;\n\n /** Handler function that is called when item is selected. */\n onSelect?: ((item: SelectInputItem) => void) | undefined;\n\n /** Handler function that is called when item is highlighted. */\n onHighlight?: ((item: SelectInputItem) => void) | undefined;\n\n /** Indicates whether value has been accepted. Component then doesn't accept more input. */\n isComplete?: boolean | undefined;\n} & BoxProps;\n\n/**\n * Select input component.\n */\nexport function SelectInput({\n label,\n items,\n focus = true,\n initialIndex = 0,\n limit: userDefinedLimit,\n onSelect,\n onHighlight,\n isComplete,\n ...boxProps\n}: SelectInputProps): JSX.Element {\n let [rotatedIndex, setRotatedIndex] = useState(0);\n let [selectedIndex, setSelectedIndex] = useState(initialIndex);\n let hasLimit = typeof userDefinedLimit === 'number' && items.length > userDefinedLimit;\n let limit = hasLimit ? Math.min(userDefinedLimit as number, items.length) : items.length;\n let previousItems = useRef<SelectInputItem[]>(items);\n\n useEffect(() => {\n if (\n !_.isEqual(\n previousItems.current.map((item) => item.value),\n items.map((item) => item.value),\n )\n ) {\n setRotatedIndex(0);\n setSelectedIndex(0);\n }\n\n previousItems.current = items;\n }, [items]);\n\n useInput(\n (input: string, key: Key) => {\n if (input === 'k' || key.upArrow) {\n let lastIndex = (hasLimit ? limit : items.length) - 1;\n let isAtFirstIndex = selectedIndex === 0;\n let nextIndex = hasLimit ? selectedIndex : lastIndex;\n let nextRotatedIndex = isAtFirstIndex ? rotatedIndex + 1 : rotatedIndex;\n let nextSelectedIndex = isAtFirstIndex ? nextIndex : selectedIndex - 1;\n\n setRotatedIndex(nextRotatedIndex);\n setSelectedIndex(nextSelectedIndex);\n\n let slicedItems = hasLimit ? rotate(items, nextRotatedIndex).slice(0, limit) : items;\n\n if (typeof onHighlight === 'function') {\n onHighlight(slicedItems[nextSelectedIndex] as SelectInputItem);\n }\n }\n\n if (input === 'j' || key.downArrow) {\n let isAtLastIndex = selectedIndex === (hasLimit ? limit : items.length) - 1;\n let nextIndex = hasLimit ? selectedIndex : 0;\n let nextRotatedIndex = isAtLastIndex ? rotatedIndex - 1 : rotatedIndex;\n let nextSelectedIndex = isAtLastIndex ? nextIndex : selectedIndex + 1;\n\n setRotatedIndex(nextRotatedIndex);\n setSelectedIndex(nextSelectedIndex);\n\n let slicedItems = hasLimit ? rotate(items, nextRotatedIndex).slice(0, limit) : items;\n\n if (typeof onHighlight === 'function') {\n onHighlight(slicedItems[nextSelectedIndex] as SelectInputItem);\n }\n }\n\n if (key.return) {\n let slicedItems = hasLimit ? rotate(items, rotatedIndex).slice(0, limit) : items;\n\n if (typeof onSelect === 'function') {\n onSelect(slicedItems[selectedIndex] as SelectInputItem);\n }\n }\n },\n {isActive: focus},\n );\n\n let visibleItems: SelectInputItem[] =\n hasLimit ? rotate(items, rotatedIndex).slice(0, limit) : items;\n\n return (\n <Box {...boxProps}>\n <Box marginRight={1}>\n <Text>{isComplete ? icons.success : icons.question}</Text>\n </Box>\n\n <Box flexDirection=\"column\">\n <Box marginRight={1}>\n <Text color={colors.highlighted}>{label}</Text>\n </Box>\n {isComplete ?\n <Text color={colors.body}>\n {items[selectedIndex]?.label ?? String(items[selectedIndex]?.value)}\n </Text>\n : <Box flexDirection=\"column\">\n {visibleItems.map((item, index) => {\n let isSelected = index === selectedIndex;\n\n return (\n <Box key={item.value}>\n <Box marginRight={1}>\n {isSelected ?\n <Text color={colors.selected}>{icons.selectedCircle}</Text>\n : <Text color={colors.unselected}>{icons.unselectedCircle}</Text>}\n </Box>\n <Text color={isSelected ? colors.highlighted : colors.muted}>{item.label}</Text>\n </Box>\n );\n })}\n </Box>\n }\n </Box>\n </Box>\n );\n}\n\n// partially based on https://github.com/vadimdemedes/ink-select-input/tree/309497ca641f55d8df0083ec2d07264f101358e4 (see https://github.com/vadimdemedes/ink-select-input/blob/309497ca641f55d8df0083ec2d07264f101358e4/license for license)\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,7 +2,7 @@ import { type BoxProps } from 'ink';
|
|
|
2
2
|
/**
|
|
3
3
|
* Text input component props.
|
|
4
4
|
*/
|
|
5
|
-
export type TextInputProps =
|
|
5
|
+
export type TextInputProps = {
|
|
6
6
|
/** Text to display as a label. */
|
|
7
7
|
label: string;
|
|
8
8
|
/** Text to display when `value` is empty. */
|
|
@@ -23,7 +23,7 @@ export type TextInputProps = BoxProps & {
|
|
|
23
23
|
onSubmit?: ((value: string) => void) | undefined;
|
|
24
24
|
/** Indicates whether value has been accepted. Component then doesn't accept more input. */
|
|
25
25
|
isComplete?: boolean | undefined;
|
|
26
|
-
};
|
|
26
|
+
} & BoxProps;
|
|
27
27
|
/**
|
|
28
28
|
* Text input component.
|
|
29
29
|
*/
|
|
@@ -91,11 +91,11 @@ export function TextInput({
|
|
|
91
91
|
}
|
|
92
92
|
} else if (key.backspace || key.delete) {
|
|
93
93
|
if (state.cursorOffset > 0) {
|
|
94
|
-
nextValue = originalValue.slice(0, state.cursorOffset - 1) + originalValue.slice(state.cursorOffset
|
|
94
|
+
nextValue = originalValue.slice(0, state.cursorOffset - 1) + originalValue.slice(state.cursorOffset);
|
|
95
95
|
nextCursorOffset -= 1;
|
|
96
96
|
}
|
|
97
97
|
} else {
|
|
98
|
-
nextValue = originalValue.slice(0, state.cursorOffset) + input + originalValue.slice(state.cursorOffset
|
|
98
|
+
nextValue = originalValue.slice(0, state.cursorOffset) + input + originalValue.slice(state.cursorOffset);
|
|
99
99
|
nextCursorOffset += input.length;
|
|
100
100
|
if (input.length > 1) {
|
|
101
101
|
nextCursorWidth = input.length;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../source/ui/form/TextInput.tsx"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["import chalk from 'chalk';\nimport {Box, type BoxProps, Text, useInput} from 'ink';\nimport {useEffect, useState} from 'react';\n\nimport * as colors from '../colors.js';\nimport * as icons from '../icons.js';\n\n/**\n * Text input component props.\n */\nexport type TextInputProps = {\n /** Text to display as a label. */\n label: string;\n\n /** Text to display when `value` is empty. */\n placeholder?: string | undefined;\n\n /** Value. */\n value: string;\n\n /** 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. */\n focus?: boolean | undefined;\n\n /** Replace all chars and mask the value. Useful for password inputs. */\n mask?: string | undefined;\n\n /** Show cursor and allow navigation using arrow keys. */\n showCursor?: boolean | undefined;\n\n /** Validation function that is called when value changes. If this function throws an error*/\n validate?: ((value: string) => void) | undefined;\n\n /** Handler function that is called when value changes. */\n onChange: (value: string) => void;\n\n /** Handler function that is called when enter is pressed. */\n onSubmit?: ((value: string) => void) | undefined;\n\n /** Indicates whether value has been accepted. Component then doesn't accept more input. */\n isComplete?: boolean | undefined;\n} & BoxProps;\n\n/**\n * Text input component.\n */\nexport function TextInput({\n label,\n validate,\n isComplete,\n value: originalValue,\n placeholder = '',\n focus = true,\n mask,\n showCursor = true,\n onChange,\n onSubmit,\n ...boxProps\n}: TextInputProps) {\n let [validationError, setValidationError] = useState('');\n let [state, setState] = useState({\n cursorOffset: (originalValue || '').length,\n cursorWidth: 0,\n });\n\n useEffect(() => {\n setState((previousState) => {\n if (!focus || !showCursor) {\n return previousState;\n }\n\n let newValue = originalValue || '';\n\n if (previousState.cursorOffset > newValue.length - 1) {\n return {\n cursorOffset: newValue.length,\n cursorWidth: 0,\n };\n }\n\n return previousState;\n });\n }, [originalValue, focus, showCursor]);\n\n let value = mask ? mask.repeat(originalValue.length) : originalValue;\n let renderedValue = value;\n let renderedPlaceholder = placeholder ? chalk[colors.muted](placeholder) : undefined;\n\n if (showCursor && focus) {\n renderedPlaceholder =\n placeholder.length > 0 ?\n chalk.inverse(placeholder[0]) + chalk[colors.muted](placeholder.slice(1))\n : chalk.inverse(' ');\n\n renderedValue = value.length > 0 ? '' : chalk.inverse(' ');\n\n for (let [i, character] of Object.entries(value)) {\n if (Number(i) >= state.cursorOffset && Number(i) <= state.cursorOffset) {\n renderedValue += chalk.inverse(character);\n } else {\n renderedValue += character;\n }\n }\n\n if (value.length > 0 && state.cursorOffset === value.length) {\n renderedValue += chalk.inverse(' ');\n }\n }\n\n useInput(\n (input, key) => {\n if (\n key.upArrow ||\n key.downArrow ||\n (key.ctrl && input === 'c') ||\n (key.shift && key.tab) ||\n key.tab\n ) {\n return;\n }\n\n if (key.return) {\n if (onSubmit) {\n if (validate) {\n try {\n validate(originalValue);\n } catch (error: unknown) {\n setValidationError((error as Error).message);\n\n return;\n }\n }\n\n if (validationError) {\n setValidationError('');\n } else {\n onSubmit(originalValue);\n }\n }\n\n return;\n }\n\n let nextCursorOffset = state.cursorOffset;\n let nextValue = originalValue;\n let nextCursorWidth = 0;\n\n if (key.leftArrow) {\n if (showCursor) {\n nextCursorOffset -= 1;\n }\n } else if (key.rightArrow) {\n if (showCursor) {\n nextCursorOffset += 1;\n }\n } else if (key.backspace || key.delete) {\n if (state.cursorOffset > 0) {\n nextValue =\n originalValue.slice(0, state.cursorOffset - 1) +\n originalValue.slice(state.cursorOffset);\n\n nextCursorOffset -= 1;\n }\n } else {\n nextValue =\n originalValue.slice(0, state.cursorOffset) +\n input +\n originalValue.slice(state.cursorOffset);\n\n nextCursorOffset += input.length;\n\n if (input.length > 1) {\n nextCursorWidth = input.length;\n }\n }\n\n if (state.cursorOffset < 0) {\n nextCursorOffset = 0;\n }\n\n if (state.cursorOffset > originalValue.length) {\n nextCursorOffset = originalValue.length;\n }\n\n setState({\n cursorOffset: nextCursorOffset,\n cursorWidth: nextCursorWidth,\n });\n\n if (nextValue !== originalValue) {\n onChange(nextValue);\n }\n },\n {isActive: focus},\n );\n\n return (\n <Box {...boxProps}>\n <Box marginRight={1}>\n <Text>{isComplete ? icons.success : icons.question}</Text>\n </Box>\n\n <Box flexDirection=\"column\">\n <Box marginRight={1}>\n <Text color={colors.highlighted}>{label}</Text>\n </Box>\n {isComplete ?\n <Text color={colors.body}>{value}</Text>\n : <Text color={colors.highlighted}>\n {placeholder ?\n value.length > 0 ?\n renderedValue\n : renderedPlaceholder\n : renderedValue}\n </Text>\n }\n {validationError ?\n <Box marginTop={0}>\n <Text color={colors.warning}>{validationError}</Text>\n </Box>\n : null}\n </Box>\n </Box>\n );\n}\n\n// partially based on https://github.com/vadimdemedes/ink-text-input/tree/0787c505415f0d059801d80600e4ccb0651385f3 (see https://github.com/vadimdemedes/ink-text-input/blob/0787c505415f0d059801d80600e4ccb0651385f3/license for license)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -51,12 +51,12 @@ export function createForm(formConfig) {
|
|
|
51
51
|
/* @__PURE__ */ jsx(
|
|
52
52
|
FormRow,
|
|
53
53
|
{
|
|
54
|
-
|
|
54
|
+
config: input,
|
|
55
55
|
focus: rowName === activeInputName,
|
|
56
56
|
isComplete: results[rowName].isComplete,
|
|
57
|
-
|
|
58
|
-
rows,
|
|
57
|
+
marginTop: inputElements.length === 0 ? 0 : 1,
|
|
59
58
|
rowName,
|
|
59
|
+
rows,
|
|
60
60
|
value: results[rowName].value,
|
|
61
61
|
onChange: handleChange,
|
|
62
62
|
onComplete: handleFinish
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../source/ui/form/createForm.tsx"],
|
|
4
|
-
"sourcesContent": ["import {Box, type BoxProps} from 'ink';\nimport {useCallback} from 'react';\n\nimport {type Form} from './Form.js';\nimport {type FormConfig} from './FormConfig.js';\nimport {type FormProps} from './FormProps.js';\nimport {FormRow} from './FormRow.js';\n\n/**\n * Creates form component that contains individual rows with inputs based on the provided config.\n *\n * @param formConfig Form configuration.\n * @returns Form component.\n */\nexport function createForm<C extends FormConfig>(formConfig: C): Form<C> {\n let Form = ({\n rows,\n values: results,\n onChange,\n onComplete: onFinish,\n ...boxProps\n }: FormProps<C>) => {\n let handleChange = useCallback(\n (value: unknown, rowName: keyof C['rows']) => {\n if (onChange) {\n onChange({\n ...results,\n [rowName]: {\n ...results[rowName],\n value,\n },\n });\n }\n },\n [onChange, results],\n );\n\n let handleFinish = useCallback(\n (value: unknown, rowName: keyof C['rows']) => {\n onFinish({\n ...results,\n [rowName]: {\n value,\n isComplete: true,\n },\n });\n },\n [onFinish, results],\n );\n\n let inputElements = [];\n let activeInputName:
|
|
5
|
-
"mappings": ";AAgEU;AAhEV,SAAQ,WAAyB;AACjC,SAAQ,mBAAkB;AAK1B,SAAQ,eAAc;AAQf,gBAAS,WAAiC,YAAwB;AACvE,MAAI,OAAO,CAAC;AAAA,IACV;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA,YAAY;AAAA,IACZ,GAAG;AAAA,EACL,MAAoB;AAClB,QAAI,eAAe;AAAA,MACjB,CAAC,OAAgB,YAA6B;AAC5C,YAAI,UAAU;AACZ,mBAAS;AAAA,YACP,GAAG;AAAA,YACH,CAAC,OAAO,GAAG;AAAA,cACT,GAAG,QAAQ,OAAO;AAAA,cAClB;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,MACA,CAAC,UAAU,OAAO;AAAA,IACpB;AAEA,QAAI,eAAe;AAAA,MACjB,CAAC,OAAgB,YAA6B;AAC5C,iBAAS;AAAA,UACP,GAAG;AAAA,UACH,CAAC,OAAO,GAAG;AAAA,YACT;AAAA,YACA,YAAY;AAAA,UACd;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA,CAAC,UAAU,OAAO;AAAA,IACpB;AAEA,QAAI,gBAAgB,CAAC;AACrB,QAAI,kBAAiC;AAErC,aAAS,CAAC,OAAO,KAAK,OAAO,QAAQ,WAAW,IAAI,GAAG;AACrD,UAAI,CAAC,QAAQ,OAA0B,EAAE,YAAY;AACnD,0BAAkB,OAAO,OAAO;AAEhC;AAAA,MACF;AAAA,IACF;AAEA,aAAS,CAAC,SAAS,KAAK,KAAK,OAAO,QAAQ,WAAW,IAAI,GAAG;AAC5D,UAAI,QAAQ,OAA0B,EAAE,cAAc,YAAY,iBAAiB;AACjF,sBAAc;AAAA,UACZ;AAAA,YAAC;AAAA;AAAA,cAEC,
|
|
4
|
+
"sourcesContent": ["import {Box, type BoxProps} from 'ink';\nimport {useCallback} from 'react';\n\nimport {type Form} from './Form.js';\nimport {type FormConfig} from './FormConfig.js';\nimport {type FormProps} from './FormProps.js';\nimport {FormRow} from './FormRow.js';\n\n/**\n * Creates form component that contains individual rows with inputs based on the provided config.\n *\n * @param formConfig Form configuration.\n * @returns Form component.\n */\nexport function createForm<C extends FormConfig>(formConfig: C): Form<C> {\n let Form = ({\n rows,\n values: results,\n onChange,\n onComplete: onFinish,\n ...boxProps\n }: FormProps<C>) => {\n let handleChange = useCallback(\n (value: unknown, rowName: keyof C['rows']) => {\n if (onChange) {\n onChange({\n ...results,\n [rowName]: {\n ...results[rowName],\n value,\n },\n });\n }\n },\n [onChange, results],\n );\n\n let handleFinish = useCallback(\n (value: unknown, rowName: keyof C['rows']) => {\n onFinish({\n ...results,\n [rowName]: {\n value,\n isComplete: true,\n },\n });\n },\n [onFinish, results],\n );\n\n let inputElements = [];\n let activeInputName: null | string = null;\n\n for (let [rowName] of Object.entries(formConfig.rows)) {\n if (!results[rowName as keyof C['rows']].isComplete) {\n activeInputName = String(rowName);\n\n break;\n }\n }\n\n for (let [rowName, input] of Object.entries(formConfig.rows)) {\n if (results[rowName as keyof C['rows']].isComplete || rowName === activeInputName) {\n inputElements.push(\n <FormRow\n key={rowName}\n config={input}\n focus={rowName === activeInputName}\n isComplete={results[rowName as keyof C['rows']].isComplete}\n marginTop={inputElements.length === 0 ? 0 : 1}\n rowName={rowName}\n rows={rows}\n value={results[rowName as keyof C['rows']].value}\n onChange={handleChange}\n onComplete={handleFinish}\n />,\n );\n }\n }\n\n return (\n <Box {...(boxProps as BoxProps)} flexDirection=\"column\">\n {inputElements}\n </Box>\n );\n };\n\n return Object.assign(Form, {config: formConfig});\n}\n"],
|
|
5
|
+
"mappings": ";AAgEU;AAhEV,SAAQ,WAAyB;AACjC,SAAQ,mBAAkB;AAK1B,SAAQ,eAAc;AAQf,gBAAS,WAAiC,YAAwB;AACvE,MAAI,OAAO,CAAC;AAAA,IACV;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA,YAAY;AAAA,IACZ,GAAG;AAAA,EACL,MAAoB;AAClB,QAAI,eAAe;AAAA,MACjB,CAAC,OAAgB,YAA6B;AAC5C,YAAI,UAAU;AACZ,mBAAS;AAAA,YACP,GAAG;AAAA,YACH,CAAC,OAAO,GAAG;AAAA,cACT,GAAG,QAAQ,OAAO;AAAA,cAClB;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,MACA,CAAC,UAAU,OAAO;AAAA,IACpB;AAEA,QAAI,eAAe;AAAA,MACjB,CAAC,OAAgB,YAA6B;AAC5C,iBAAS;AAAA,UACP,GAAG;AAAA,UACH,CAAC,OAAO,GAAG;AAAA,YACT;AAAA,YACA,YAAY;AAAA,UACd;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA,CAAC,UAAU,OAAO;AAAA,IACpB;AAEA,QAAI,gBAAgB,CAAC;AACrB,QAAI,kBAAiC;AAErC,aAAS,CAAC,OAAO,KAAK,OAAO,QAAQ,WAAW,IAAI,GAAG;AACrD,UAAI,CAAC,QAAQ,OAA0B,EAAE,YAAY;AACnD,0BAAkB,OAAO,OAAO;AAEhC;AAAA,MACF;AAAA,IACF;AAEA,aAAS,CAAC,SAAS,KAAK,KAAK,OAAO,QAAQ,WAAW,IAAI,GAAG;AAC5D,UAAI,QAAQ,OAA0B,EAAE,cAAc,YAAY,iBAAiB;AACjF,sBAAc;AAAA,UACZ;AAAA,YAAC;AAAA;AAAA,cAEC,QAAQ;AAAA,cACR,OAAO,YAAY;AAAA,cACnB,YAAY,QAAQ,OAA0B,EAAE;AAAA,cAChD,WAAW,cAAc,WAAW,IAAI,IAAI;AAAA,cAC5C;AAAA,cACA;AAAA,cACA,OAAO,QAAQ,OAA0B,EAAE;AAAA,cAC3C,UAAU;AAAA,cACV,YAAY;AAAA;AAAA,YATP;AAAA,UAUP;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WACE,oBAAC,OAAK,GAAI,UAAuB,eAAc,UAC5C,yBACH;AAAA,EAEJ;AAEA,SAAO,OAAO,OAAO,MAAM,EAAC,QAAQ,WAAU,CAAC;AACjD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/ui/form.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export * from './form/createForm.js';
|
|
2
|
-
export * from './form/Form.js';
|
|
3
|
-
export * from './form/FormConfig.js';
|
|
4
|
-
export * from './form/FormProps.js';
|
|
5
|
-
export * from './form/FormResult.js';
|
|
2
|
+
export type * from './form/Form.js';
|
|
3
|
+
export type * from './form/FormConfig.js';
|
|
4
|
+
export type * from './form/FormProps.js';
|
|
5
|
+
export type * from './form/FormResult.js';
|
|
6
6
|
export * from './form/FormRow.js';
|
|
7
|
-
export * from './form/FormRowConfig.js';
|
|
8
|
-
export * from './form/FormRowsConfig.js';
|
|
9
|
-
export * from './form/FormValue.js';
|
|
10
|
-
export * from './form/FormValues.js';
|
|
7
|
+
export type * from './form/FormRowConfig.js';
|
|
8
|
+
export type * from './form/FormRowsConfig.js';
|
|
9
|
+
export type * from './form/FormValue.js';
|
|
10
|
+
export type * from './form/FormValues.js';
|
|
11
11
|
export * from './form/SelectInput.js';
|
|
12
|
-
export * from './form/SelectInputItem.js';
|
|
12
|
+
export type * from './form/SelectInputItem.js';
|
|
13
13
|
export * from './form/TextInput.js';
|
package/build/ui/form.js
CHANGED
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
export * from "./form/createForm.js";
|
|
3
|
-
export * from "./form/Form.js";
|
|
4
|
-
export * from "./form/FormConfig.js";
|
|
5
|
-
export * from "./form/FormProps.js";
|
|
6
|
-
export * from "./form/FormResult.js";
|
|
7
3
|
export * from "./form/FormRow.js";
|
|
8
|
-
export * from "./form/FormRowConfig.js";
|
|
9
|
-
export * from "./form/FormRowsConfig.js";
|
|
10
|
-
export * from "./form/FormValue.js";
|
|
11
|
-
export * from "./form/FormValues.js";
|
|
12
4
|
export * from "./form/SelectInput.js";
|
|
13
|
-
export * from "./form/SelectInputItem.js";
|
|
14
5
|
export * from "./form/TextInput.js";
|
|
15
6
|
//# sourceMappingURL=form.js.map
|
package/build/ui/form.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../source/ui/form.ts"],
|
|
4
|
-
"sourcesContent": ["export * from './form/createForm.js';\nexport * from './form/Form.js';\nexport * from './form/FormConfig.js';\nexport * from './form/FormProps.js';\nexport * from './form/FormResult.js';\nexport * from './form/FormRow.js';\nexport * from './form/FormRowConfig.js';\nexport * from './form/FormRowsConfig.js';\nexport * from './form/FormValue.js';\nexport * from './form/FormValues.js';\nexport * from './form/SelectInput.js';\nexport * from './form/SelectInputItem.js';\nexport * from './form/TextInput.js';\n"],
|
|
5
|
-
"mappings": ";AAAA,cAAc;
|
|
4
|
+
"sourcesContent": ["export * from './form/createForm.js';\nexport type * from './form/Form.js';\nexport type * from './form/FormConfig.js';\nexport type * from './form/FormProps.js';\nexport type * from './form/FormResult.js';\nexport * from './form/FormRow.js';\nexport type * from './form/FormRowConfig.js';\nexport type * from './form/FormRowsConfig.js';\nexport type * from './form/FormValue.js';\nexport type * from './form/FormValues.js';\nexport * from './form/SelectInput.js';\nexport type * from './form/SelectInputItem.js';\nexport * from './form/TextInput.js';\n"],
|
|
5
|
+
"mappings": ";AAAA,cAAc;AAKd,cAAc;AAKd,cAAc;AAEd,cAAc;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../source/ui/getErrorDetail.ts"],
|
|
4
|
-
"sourcesContent": ["import {ParsingError, ValidationError} from '@jakubmazanec/args';\nimport {zodIssuesToStrings} from '@jakubmazanec/zod-utils';\nimport {ZodError} from 'zod';\n\nimport {type ErrorDetail} from './ErrorDetail.js';\n\n/**\n * Creates detailed information about an error.\n */\nexport function getErrorDetail(error: unknown): ErrorDetail {\n // TODO: add all codes\n if (error instanceof ParsingError) {\n switch (error.code) {\n default: {\n return {\n label: 'Parsing error',\n description: error.message,\n };\n }\n }\n }\n\n // TODO: add all codes\n if (error instanceof ValidationError) {\n switch (error.code) {\n default: {\n return {\n label: 'Validation error',\n description: error.message,\n };\n }\n }\n }\n\n // TODO: add all built-in errors\n if (error instanceof ReferenceError) {\n let errorDetail: ErrorDetail = {\n label: 'Error',\n description: error.message,\n };\n\n if (error.stack) {\n errorDetail.stack = error.stack;\n }\n\n return errorDetail;\n }\n\n if (error instanceof ZodError) {\n let errorDetail: ErrorDetail = {\n label: 'Error',\n description: zodIssuesToStrings(error.issues).join('\\n'),\n };\n\n return errorDetail;\n }\n\n if (error instanceof Error) {\n let errorDetail: ErrorDetail = {\n label: 'Error',\n description: error.message,\n };\n\n if (error.stack) {\n errorDetail.stack = error.stack;\n }\n\n if (error.cause instanceof Error) {\n errorDetail.cause = {\n description: error.cause.message,\n };\n\n if (error.cause.stack) {\n errorDetail.cause.stack = error.cause.stack;\n }\n }\n\n return errorDetail;\n }\n\n return {\n label: 'Error',\n };\n}\n"],
|
|
5
|
-
"mappings": ";AAAA,SAAQ,cAAc,uBAAsB;AAC5C,SAAQ,0BAAyB;AACjC,SAAQ,gBAAe;AAOhB,gBAAS,eAAe,OAA6B;AAE1D,MAAI,iBAAiB,cAAc;
|
|
4
|
+
"sourcesContent": ["import {ParsingError, ValidationError} from '@jakubmazanec/args';\nimport {zodIssuesToStrings} from '@jakubmazanec/zod-utils';\nimport {ZodError} from 'zod';\n\nimport {type ErrorDetail} from './ErrorDetail.js';\n\n/**\n * Creates detailed information about an error.\n */\nexport function getErrorDetail(error: unknown): ErrorDetail {\n // TODO: add all codes\n if (error instanceof ParsingError) {\n // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- remove this when the TODO comment above is resolved\n switch (error.code) {\n default: {\n return {\n label: 'Parsing error',\n description: error.message,\n };\n }\n }\n }\n\n // TODO: add all codes\n if (error instanceof ValidationError) {\n // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- remove this when the TODO comment above is resolved\n switch (error.code) {\n default: {\n return {\n label: 'Validation error',\n description: error.message,\n };\n }\n }\n }\n\n // TODO: add all built-in errors\n if (error instanceof ReferenceError) {\n let errorDetail: ErrorDetail = {\n label: 'Error',\n description: error.message,\n };\n\n if (error.stack) {\n errorDetail.stack = error.stack;\n }\n\n return errorDetail;\n }\n\n if (error instanceof ZodError) {\n let errorDetail: ErrorDetail = {\n label: 'Error',\n description: zodIssuesToStrings(error.issues).join('\\n'),\n };\n\n return errorDetail;\n }\n\n if (error instanceof Error) {\n let errorDetail: ErrorDetail = {\n label: 'Error',\n description: error.message,\n };\n\n if (error.stack) {\n errorDetail.stack = error.stack;\n }\n\n if (error.cause instanceof Error) {\n errorDetail.cause = {\n description: error.cause.message,\n };\n\n if (error.cause.stack) {\n errorDetail.cause.stack = error.cause.stack;\n }\n }\n\n return errorDetail;\n }\n\n return {\n label: 'Error',\n };\n}\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAQ,cAAc,uBAAsB;AAC5C,SAAQ,0BAAyB;AACjC,SAAQ,gBAAe;AAOhB,gBAAS,eAAe,OAA6B;AAE1D,MAAI,iBAAiB,cAAc;AAEjC,YAAQ,MAAM,MAAM;AAAA,MAClB,SAAS;AACP,eAAO;AAAA,UACL,OAAO;AAAA,UACP,aAAa,MAAM;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,iBAAiB,iBAAiB;AAEpC,YAAQ,MAAM,MAAM;AAAA,MAClB,SAAS;AACP,eAAO;AAAA,UACL,OAAO;AAAA,UACP,aAAa,MAAM;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,iBAAiB,gBAAgB;AACnC,QAAI,cAA2B;AAAA,MAC7B,OAAO;AAAA,MACP,aAAa,MAAM;AAAA,IACrB;AAEA,QAAI,MAAM,OAAO;AACf,kBAAY,QAAQ,MAAM;AAAA,IAC5B;AAEA,WAAO;AAAA,EACT;AAEA,MAAI,iBAAiB,UAAU;AAC7B,QAAI,cAA2B;AAAA,MAC7B,OAAO;AAAA,MACP,aAAa,mBAAmB,MAAM,MAAM,EAAE,KAAK,IAAI;AAAA,IACzD;AAEA,WAAO;AAAA,EACT;AAEA,MAAI,iBAAiB,OAAO;AAC1B,QAAI,cAA2B;AAAA,MAC7B,OAAO;AAAA,MACP,aAAa,MAAM;AAAA,IACrB;AAEA,QAAI,MAAM,OAAO;AACf,kBAAY,QAAQ,MAAM;AAAA,IAC5B;AAEA,QAAI,MAAM,iBAAiB,OAAO;AAChC,kBAAY,QAAQ;AAAA,QAClB,aAAa,MAAM,MAAM;AAAA,MAC3B;AAEA,UAAI,MAAM,MAAM,OAAO;AACrB,oBAAY,MAAM,QAAQ,MAAM,MAAM;AAAA,MACxC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,EACT;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -18,14 +18,14 @@ export const Wrapper = ({ program, children }) => {
|
|
|
18
18
|
/* @__PURE__ */ jsxs(
|
|
19
19
|
Box,
|
|
20
20
|
{
|
|
21
|
-
flexDirection: "column",
|
|
22
21
|
borderColor: notice,
|
|
23
22
|
borderStyle: "round",
|
|
23
|
+
flexDirection: "column",
|
|
24
24
|
margin: 1,
|
|
25
|
-
paddingTop: 1,
|
|
26
|
-
paddingRight: 4,
|
|
27
25
|
paddingBottom: 1,
|
|
28
26
|
paddingLeft: 4,
|
|
27
|
+
paddingRight: 4,
|
|
28
|
+
paddingTop: 1,
|
|
29
29
|
children: [
|
|
30
30
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
31
31
|
"New version ",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../source/ui/internals/Wrapper.tsx"],
|
|
4
|
-
"sourcesContent": ["import {Box, Spacer, Text} from 'ink';\nimport {type FC, type PropsWithChildren, useMemo} from 'react';\nimport {ErrorBoundary} from 'react-error-boundary';\n\nimport {type Program} from '../../program.js';\nimport {highlighted, notice} from '../colors.js';\nimport {Failure} from '../Failure.js';\nimport {programContext} from './programContext.js';\n\n/**\n * {@link Wrapper} component props.\n */\nexport type WrapperProps = {\n program: Program;\n};\n\n/**\n * A component that wraps anything {@link Program} tries to render with an error boundary and all neccessary providers.\n */\nexport const Wrapper: FC<PropsWithChildren<WrapperProps>> = ({program, children}) => {\n let programContextValue = useMemo(\n () => ({\n program,\n }),\n [program],\n );\n\n return (\n <ErrorBoundary FallbackComponent={Failure}>\n <programContext.Provider value={programContextValue}>\n {program.latestVersion && program.latestVersion !== program.version ?\n <Box>\n <Box\n
|
|
5
|
-
"mappings": ";AA0Cc,SACc,KADd;AA1Cd,SAAQ,KAAK,QAAQ,YAAW;AAChC,SAAyC,eAAc;AACvD,SAAQ,qBAAoB;AAG5B,SAAQ,aAAa,cAAa;AAClC,SAAQ,eAAc;AACtB,SAAQ,sBAAqB;AAYtB,aAAM,UAA+C,CAAC,EAAC,SAAS,SAAQ,MAAM;AACnF,MAAI,sBAAsB;AAAA,IACxB,OAAO;AAAA,MACL;AAAA,IACF;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,SACE,oBAAC,iBAAc,mBAAmB,SAChC,+BAAC,eAAe,UAAf,EAAwB,OAAO,qBAC7B;AAAA,YAAQ,iBAAiB,QAAQ,kBAAkB,QAAQ,UAC1D,qBAAC,OACC;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,
|
|
4
|
+
"sourcesContent": ["import {Box, Spacer, Text} from 'ink';\nimport {type FC, type PropsWithChildren, useMemo} from 'react';\nimport {ErrorBoundary} from 'react-error-boundary';\n\nimport {type Program} from '../../program.js';\nimport {highlighted, notice} from '../colors.js';\nimport {Failure} from '../Failure.js';\nimport {programContext} from './programContext.js';\n\n/**\n * {@link Wrapper} component props.\n */\nexport type WrapperProps = {\n program: Program;\n};\n\n/**\n * A component that wraps anything {@link Program} tries to render with an error boundary and all neccessary providers.\n */\nexport const Wrapper: FC<PropsWithChildren<WrapperProps>> = ({program, children}) => {\n let programContextValue = useMemo(\n () => ({\n program,\n }),\n [program],\n );\n\n return (\n <ErrorBoundary FallbackComponent={Failure}>\n <programContext.Provider value={programContextValue}>\n {program.latestVersion && program.latestVersion !== program.version ?\n <Box>\n <Box\n borderColor={notice}\n borderStyle=\"round\"\n flexDirection=\"column\"\n margin={1}\n paddingBottom={1}\n paddingLeft={4}\n paddingRight={4}\n paddingTop={1}\n >\n <Text>\n New version <Text color={highlighted}>{program.latestVersion}</Text> is available!\n </Text>\n <Text>\n Run <Text color={highlighted}>{`npm install ${program.name} -D`}</Text> to update.\n </Text>\n </Box>\n <Spacer />\n </Box>\n : null}\n <Box>{children}</Box>\n </programContext.Provider>\n </ErrorBoundary>\n );\n};\n"],
|
|
5
|
+
"mappings": ";AA0Cc,SACc,KADd;AA1Cd,SAAQ,KAAK,QAAQ,YAAW;AAChC,SAAyC,eAAc;AACvD,SAAQ,qBAAoB;AAG5B,SAAQ,aAAa,cAAa;AAClC,SAAQ,eAAc;AACtB,SAAQ,sBAAqB;AAYtB,aAAM,UAA+C,CAAC,EAAC,SAAS,SAAQ,MAAM;AACnF,MAAI,sBAAsB;AAAA,IACxB,OAAO;AAAA,MACL;AAAA,IACF;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,SACE,oBAAC,iBAAc,mBAAmB,SAChC,+BAAC,eAAe,UAAf,EAAwB,OAAO,qBAC7B;AAAA,YAAQ,iBAAiB,QAAQ,kBAAkB,QAAQ,UAC1D,qBAAC,OACC;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,aAAa;AAAA,UACb,aAAY;AAAA,UACZ,eAAc;AAAA,UACd,QAAQ;AAAA,UACR,eAAe;AAAA,UACf,aAAa;AAAA,UACb,cAAc;AAAA,UACd,YAAY;AAAA,UAEZ;AAAA,iCAAC,QAAK;AAAA;AAAA,cACQ,oBAAC,QAAK,OAAO,aAAc,kBAAQ,eAAc;AAAA,cAAO;AAAA,eACtE;AAAA,YACA,qBAAC,QAAK;AAAA;AAAA,cACA,oBAAC,QAAK,OAAO,aAAc,yBAAe,QAAQ,IAAI,OAAM;AAAA,cAAO;AAAA,eACzE;AAAA;AAAA;AAAA,MACF;AAAA,MACA,oBAAC,UAAO;AAAA,OACV,IACA;AAAA,IACF,oBAAC,OAAK,UAAS;AAAA,KACjB,GACF;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../source/ui/useProgram.ts"],
|
|
4
|
-
"sourcesContent": ["import {useApp} from 'ink';\nimport {useCallback, useContext} from 'react';\nimport {useErrorBoundary} from 'react-error-boundary';\n\nimport {programContext} from './internals.js';\n\n/**\n * A React hook for accessing {@link Program} instance and `exit` function that is used for showing an error (via an error boundary) and exiting.\n */\nexport function useProgram() {\n let {showBoundary} = useErrorBoundary();\n let {exit: appExit} = useApp();\n let {program} = useContext(programContext);\n\n let exit = useCallback(\n (error: unknown) => {\n process.exitCode = 1;\n\n showBoundary(error);\n appExit(error as Error);\n },\n [appExit, showBoundary],\n );\n\n return {program, exit};\n}\n"],
|
|
5
|
-
"mappings": ";AAAA,SAAQ,cAAa;AACrB,SAAQ,aAAa,kBAAiB;AACtC,SAAQ,wBAAuB;AAE/B,SAAQ,sBAAqB;AAKtB,gBAAS,aAAa;AAC3B,MAAI,EAAC,aAAY,IAAI,iBAAiB;AACtC,MAAI,EAAC,MAAM,QAAO,IAAI,OAAO;AAC7B,MAAI,EAAC,QAAO,IAAI,WAAW,cAAc;AAEzC,MAAI,OAAO;AAAA,IACT,CAAC,UAAmB;
|
|
4
|
+
"sourcesContent": ["import {useApp} from 'ink';\nimport {useCallback, useContext} from 'react';\nimport {useErrorBoundary} from 'react-error-boundary';\n\nimport {programContext} from './internals.js';\n\n/**\n * A React hook for accessing {@link Program} instance and `exit` function that is used for showing an error (via an error boundary) and exiting.\n */\nexport function useProgram() {\n let {showBoundary} = useErrorBoundary();\n let {exit: appExit} = useApp();\n let {program} = useContext(programContext);\n\n let exit = useCallback(\n (error: unknown) => {\n // TODO: remove when this is fixed: https://github.com/facebook/react/issues/31544\n // eslint-disable-next-line react-compiler/react-compiler -- false positive\n process.exitCode = 1;\n\n showBoundary(error);\n appExit(error as Error);\n },\n [appExit, showBoundary],\n );\n\n return {program, exit};\n}\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAQ,cAAa;AACrB,SAAQ,aAAa,kBAAiB;AACtC,SAAQ,wBAAuB;AAE/B,SAAQ,sBAAqB;AAKtB,gBAAS,aAAa;AAC3B,MAAI,EAAC,aAAY,IAAI,iBAAiB;AACtC,MAAI,EAAC,MAAM,QAAO,IAAI,OAAO;AAC7B,MAAI,EAAC,QAAO,IAAI,WAAW,cAAc;AAEzC,MAAI,OAAO;AAAA,IACT,CAAC,UAAmB;AAGlB,cAAQ,WAAW;AAEnB,mBAAa,KAAK;AAClB,cAAQ,KAAc;AAAA,IACxB;AAAA,IACA,CAAC,SAAS,YAAY;AAAA,EACxB;AAEA,SAAO,EAAC,SAAS,KAAI;AACvB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jakubmazanec/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5-unstable.91147a2",
|
|
4
4
|
"description": "TypeScript-first library for building CLIs.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"typecheck": "tsc --project tsconfig.typecheck.json"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@jakubmazanec/args": "
|
|
31
|
-
"@jakubmazanec/error": "
|
|
32
|
-
"@jakubmazanec/ts-utils": "
|
|
33
|
-
"@jakubmazanec/zod-utils": "
|
|
30
|
+
"@jakubmazanec/args": "2.0.5-unstable.91147a2",
|
|
31
|
+
"@jakubmazanec/error": "3.0.5-unstable.91147a2",
|
|
32
|
+
"@jakubmazanec/ts-utils": "3.0.5-unstable.91147a2",
|
|
33
|
+
"@jakubmazanec/zod-utils": "2.0.5-unstable.91147a2",
|
|
34
34
|
"chalk": "^5.3.0",
|
|
35
35
|
"fs-extra": "^11.2.0",
|
|
36
36
|
"latest-version": "^9.0.0",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"zod": "^3.23.8"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@jakubmazanec/eslint-config": "
|
|
42
|
+
"@jakubmazanec/eslint-config": "4.0.0-unstable.91147a2",
|
|
43
43
|
"@types/fs-extra": "^11.0.4",
|
|
44
44
|
"@types/lodash": "^4.17.13",
|
|
45
45
|
"@types/node": "^22.9.0",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"cross-env": "^7.0.3",
|
|
50
50
|
"del-cli": "^6.0.0",
|
|
51
51
|
"esbuild": "^0.24.0",
|
|
52
|
-
"eslint": "^
|
|
52
|
+
"eslint": "^9.14.0",
|
|
53
53
|
"ink": "^5.0.1",
|
|
54
54
|
"ink-testing-library": "^4.0.0",
|
|
55
55
|
"lodash": "^4.17.21",
|
package/source/ui/Failure.tsx
CHANGED
|
@@ -9,13 +9,13 @@ import * as icons from './icons.js';
|
|
|
9
9
|
/**
|
|
10
10
|
* {@link Failure} component props.
|
|
11
11
|
*/
|
|
12
|
-
export type FailureProps =
|
|
12
|
+
export type FailureProps = {
|
|
13
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. */
|
|
17
17
|
errorDetail?: ErrorDetail;
|
|
18
|
-
};
|
|
18
|
+
} & BoxProps;
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* A component that renders a failure state.
|
|
@@ -36,19 +36,19 @@ export function Failure({error, errorDetail, ...boxProps}: FailureProps) {
|
|
|
36
36
|
: null}
|
|
37
37
|
|
|
38
38
|
{stack ?
|
|
39
|
-
<Box flexDirection="column"
|
|
39
|
+
<Box flexDirection="column" marginLeft={2} marginTop={1}>
|
|
40
40
|
<Text color={colors.muted}>{stack}</Text>
|
|
41
41
|
</Box>
|
|
42
42
|
: null}
|
|
43
43
|
|
|
44
44
|
{cause ?
|
|
45
45
|
<>
|
|
46
|
-
<Box flexDirection="column"
|
|
46
|
+
<Box flexDirection="column" marginLeft={2} marginTop={1}>
|
|
47
47
|
<Text color={colors.muted}>{cause.description}</Text>
|
|
48
48
|
</Box>
|
|
49
49
|
|
|
50
50
|
{cause.stack ?
|
|
51
|
-
<Box flexDirection="column"
|
|
51
|
+
<Box flexDirection="column" marginLeft={2} marginTop={1}>
|
|
52
52
|
<Text color={colors.muted}>{cause.stack}</Text>
|
|
53
53
|
</Box>
|
|
54
54
|
: null}
|
package/source/ui/Header.tsx
CHANGED
|
@@ -6,13 +6,13 @@ import {Spinner} from './Spinner.js';
|
|
|
6
6
|
/**
|
|
7
7
|
* {@link Header} component props.
|
|
8
8
|
*/
|
|
9
|
-
export type HeaderProps =
|
|
9
|
+
export type HeaderProps = {
|
|
10
10
|
/** Icon (recommended is 1 character) to render before the header itself. */
|
|
11
11
|
icon?: string;
|
|
12
12
|
|
|
13
13
|
/** Show spinner instead of the icon. */
|
|
14
14
|
showSpinner?: boolean;
|
|
15
|
-
};
|
|
15
|
+
} & BoxProps;
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Header component.
|
package/source/ui/Help.tsx
CHANGED
|
@@ -9,10 +9,10 @@ import * as icons from './icons.js';
|
|
|
9
9
|
/**
|
|
10
10
|
* {@link Help} component props.
|
|
11
11
|
*/
|
|
12
|
-
export type HelpProps =
|
|
12
|
+
export type HelpProps = {
|
|
13
13
|
/** {@link Program} instance. */
|
|
14
14
|
program: Program;
|
|
15
|
-
};
|
|
15
|
+
} & BoxProps;
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* A component that renders help information.
|
|
@@ -56,7 +56,7 @@ export function Help({program, ...boxProps}: HelpProps) {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
return (
|
|
59
|
-
<Box key={command.name} marginLeft={2}
|
|
59
|
+
<Box key={command.name} flexDirection="column" marginLeft={2}>
|
|
60
60
|
<Text>{line}</Text>
|
|
61
61
|
</Box>
|
|
62
62
|
);
|
package/source/ui/form/Form.ts
CHANGED
|
@@ -33,7 +33,7 @@ type FormPropsRows<C extends FormConfig> = Pick<
|
|
|
33
33
|
*/
|
|
34
34
|
export type FormProps<C extends FormConfig> =
|
|
35
35
|
FormPropsRows<C> extends Record<number | string | symbol, never> ?
|
|
36
|
-
|
|
36
|
+
{
|
|
37
37
|
/** Props for each row. */
|
|
38
38
|
rows?: null | undefined;
|
|
39
39
|
|
|
@@ -45,8 +45,8 @@ export type FormProps<C extends FormConfig> =
|
|
|
45
45
|
|
|
46
46
|
/** Handler function that is called when the value is accepted. */
|
|
47
47
|
onComplete: (formResult: FormValues<C>) => void;
|
|
48
|
-
}
|
|
49
|
-
:
|
|
48
|
+
} & BoxProps
|
|
49
|
+
: {
|
|
50
50
|
/** Props for each row. */
|
|
51
51
|
rows: FormPropsRows<C>;
|
|
52
52
|
|
|
@@ -58,4 +58,4 @@ export type FormProps<C extends FormConfig> =
|
|
|
58
58
|
|
|
59
59
|
/** Handler function that is called when the value is accepted. */
|
|
60
60
|
onComplete: (formResult: FormValues<C>) => void;
|
|
61
|
-
};
|
|
61
|
+
} & BoxProps;
|
|
@@ -10,7 +10,7 @@ import {TextInput} from './TextInput.js';
|
|
|
10
10
|
/**
|
|
11
11
|
* Form row component props.
|
|
12
12
|
*/
|
|
13
|
-
type FormRowProps<C extends FormConfig> =
|
|
13
|
+
type FormRowProps<C extends FormConfig> = {
|
|
14
14
|
/** Form row configuration. */
|
|
15
15
|
config: FormRowConfig;
|
|
16
16
|
|
|
@@ -35,7 +35,7 @@ type FormRowProps<C extends FormConfig> = BoxProps & {
|
|
|
35
35
|
|
|
36
36
|
/** Indicates whether value has been accepted. Component in the row then doesn't accept more input. */
|
|
37
37
|
isComplete: boolean;
|
|
38
|
-
};
|
|
38
|
+
} & BoxProps;
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Form row component.
|
|
@@ -74,26 +74,13 @@ export function FormRow<C extends FormConfig>({
|
|
|
74
74
|
);
|
|
75
75
|
|
|
76
76
|
switch (config.type) {
|
|
77
|
-
case '
|
|
78
|
-
return
|
|
79
|
-
<TextInput
|
|
80
|
-
key={String(rowName)}
|
|
81
|
-
label={config.label ?? ''}
|
|
82
|
-
validate={config.validate}
|
|
83
|
-
value={value as string}
|
|
84
|
-
focus={focus}
|
|
85
|
-
isComplete={isComplete}
|
|
86
|
-
onChange={handleChange}
|
|
87
|
-
onSubmit={handleFinish}
|
|
88
|
-
{...boxProps}
|
|
89
|
-
/>
|
|
90
|
-
);
|
|
77
|
+
case 'confirm': {
|
|
78
|
+
return null;
|
|
91
79
|
}
|
|
92
80
|
case 'select': {
|
|
93
81
|
return (
|
|
94
82
|
<SelectInput
|
|
95
83
|
key={String(rowName)}
|
|
96
|
-
label={config.label ?? ''}
|
|
97
84
|
items={
|
|
98
85
|
rows ?
|
|
99
86
|
(
|
|
@@ -107,12 +94,30 @@ export function FormRow<C extends FormConfig>({
|
|
|
107
94
|
}
|
|
108
95
|
focus={focus}
|
|
109
96
|
isComplete={isComplete}
|
|
97
|
+
label={config.label ?? ''}
|
|
110
98
|
onSelect={handleSelectFinish}
|
|
111
99
|
{...boxProps}
|
|
112
100
|
/>
|
|
113
101
|
);
|
|
114
102
|
}
|
|
103
|
+
case 'text': {
|
|
104
|
+
return (
|
|
105
|
+
<TextInput
|
|
106
|
+
key={String(rowName)}
|
|
107
|
+
focus={focus}
|
|
108
|
+
isComplete={isComplete}
|
|
109
|
+
label={config.label ?? ''}
|
|
110
|
+
validate={config.validate}
|
|
111
|
+
value={value as string}
|
|
112
|
+
onChange={handleChange}
|
|
113
|
+
onSubmit={handleFinish}
|
|
114
|
+
{...boxProps}
|
|
115
|
+
/>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
115
118
|
default: {
|
|
119
|
+
config satisfies never;
|
|
120
|
+
|
|
116
121
|
return null;
|
|
117
122
|
}
|
|
118
123
|
}
|
|
@@ -10,7 +10,7 @@ import {type SelectInputItem} from './SelectInputItem.js';
|
|
|
10
10
|
/**
|
|
11
11
|
* {@linkcode SelectInput} component props.
|
|
12
12
|
*/
|
|
13
|
-
type SelectInputProps =
|
|
13
|
+
type SelectInputProps = {
|
|
14
14
|
/** Text to display as a label. */
|
|
15
15
|
label: string;
|
|
16
16
|
|
|
@@ -34,7 +34,7 @@ type SelectInputProps = BoxProps & {
|
|
|
34
34
|
|
|
35
35
|
/** Indicates whether value has been accepted. Component then doesn't accept more input. */
|
|
36
36
|
isComplete?: boolean | undefined;
|
|
37
|
-
};
|
|
37
|
+
} & BoxProps;
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* Select input component.
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// TODO: resolve
|
|
2
|
-
/* eslint-disable complexity -- TODO */
|
|
3
1
|
import chalk from 'chalk';
|
|
4
2
|
import {Box, type BoxProps, Text, useInput} from 'ink';
|
|
5
3
|
import {useEffect, useState} from 'react';
|
|
@@ -10,7 +8,7 @@ import * as icons from '../icons.js';
|
|
|
10
8
|
/**
|
|
11
9
|
* Text input component props.
|
|
12
10
|
*/
|
|
13
|
-
export type TextInputProps =
|
|
11
|
+
export type TextInputProps = {
|
|
14
12
|
/** Text to display as a label. */
|
|
15
13
|
label: string;
|
|
16
14
|
|
|
@@ -40,7 +38,7 @@ export type TextInputProps = BoxProps & {
|
|
|
40
38
|
|
|
41
39
|
/** Indicates whether value has been accepted. Component then doesn't accept more input. */
|
|
42
40
|
isComplete?: boolean | undefined;
|
|
43
|
-
};
|
|
41
|
+
} & BoxProps;
|
|
44
42
|
|
|
45
43
|
/**
|
|
46
44
|
* Text input component.
|
|
@@ -158,7 +156,7 @@ export function TextInput({
|
|
|
158
156
|
if (state.cursorOffset > 0) {
|
|
159
157
|
nextValue =
|
|
160
158
|
originalValue.slice(0, state.cursorOffset - 1) +
|
|
161
|
-
originalValue.slice(state.cursorOffset
|
|
159
|
+
originalValue.slice(state.cursorOffset);
|
|
162
160
|
|
|
163
161
|
nextCursorOffset -= 1;
|
|
164
162
|
}
|
|
@@ -166,7 +164,7 @@ export function TextInput({
|
|
|
166
164
|
nextValue =
|
|
167
165
|
originalValue.slice(0, state.cursorOffset) +
|
|
168
166
|
input +
|
|
169
|
-
originalValue.slice(state.cursorOffset
|
|
167
|
+
originalValue.slice(state.cursorOffset);
|
|
170
168
|
|
|
171
169
|
nextCursorOffset += input.length;
|
|
172
170
|
|
|
@@ -49,7 +49,7 @@ export function createForm<C extends FormConfig>(formConfig: C): Form<C> {
|
|
|
49
49
|
);
|
|
50
50
|
|
|
51
51
|
let inputElements = [];
|
|
52
|
-
let activeInputName:
|
|
52
|
+
let activeInputName: null | string = null;
|
|
53
53
|
|
|
54
54
|
for (let [rowName] of Object.entries(formConfig.rows)) {
|
|
55
55
|
if (!results[rowName as keyof C['rows']].isComplete) {
|
|
@@ -64,12 +64,12 @@ export function createForm<C extends FormConfig>(formConfig: C): Form<C> {
|
|
|
64
64
|
inputElements.push(
|
|
65
65
|
<FormRow
|
|
66
66
|
key={rowName}
|
|
67
|
-
|
|
67
|
+
config={input}
|
|
68
68
|
focus={rowName === activeInputName}
|
|
69
69
|
isComplete={results[rowName as keyof C['rows']].isComplete}
|
|
70
|
-
|
|
71
|
-
rows={rows}
|
|
70
|
+
marginTop={inputElements.length === 0 ? 0 : 1}
|
|
72
71
|
rowName={rowName}
|
|
72
|
+
rows={rows}
|
|
73
73
|
value={results[rowName as keyof C['rows']].value}
|
|
74
74
|
onChange={handleChange}
|
|
75
75
|
onComplete={handleFinish}
|
package/source/ui/form.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export * from './form/createForm.js';
|
|
2
|
-
export * from './form/Form.js';
|
|
3
|
-
export * from './form/FormConfig.js';
|
|
4
|
-
export * from './form/FormProps.js';
|
|
5
|
-
export * from './form/FormResult.js';
|
|
2
|
+
export type * from './form/Form.js';
|
|
3
|
+
export type * from './form/FormConfig.js';
|
|
4
|
+
export type * from './form/FormProps.js';
|
|
5
|
+
export type * from './form/FormResult.js';
|
|
6
6
|
export * from './form/FormRow.js';
|
|
7
|
-
export * from './form/FormRowConfig.js';
|
|
8
|
-
export * from './form/FormRowsConfig.js';
|
|
9
|
-
export * from './form/FormValue.js';
|
|
10
|
-
export * from './form/FormValues.js';
|
|
7
|
+
export type * from './form/FormRowConfig.js';
|
|
8
|
+
export type * from './form/FormRowsConfig.js';
|
|
9
|
+
export type * from './form/FormValue.js';
|
|
10
|
+
export type * from './form/FormValues.js';
|
|
11
11
|
export * from './form/SelectInput.js';
|
|
12
|
-
export * from './form/SelectInputItem.js';
|
|
12
|
+
export type * from './form/SelectInputItem.js';
|
|
13
13
|
export * from './form/TextInput.js';
|
|
@@ -10,6 +10,7 @@ import {type ErrorDetail} from './ErrorDetail.js';
|
|
|
10
10
|
export function getErrorDetail(error: unknown): ErrorDetail {
|
|
11
11
|
// TODO: add all codes
|
|
12
12
|
if (error instanceof ParsingError) {
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- remove this when the TODO comment above is resolved
|
|
13
14
|
switch (error.code) {
|
|
14
15
|
default: {
|
|
15
16
|
return {
|
|
@@ -22,6 +23,7 @@ export function getErrorDetail(error: unknown): ErrorDetail {
|
|
|
22
23
|
|
|
23
24
|
// TODO: add all codes
|
|
24
25
|
if (error instanceof ValidationError) {
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- remove this when the TODO comment above is resolved
|
|
25
27
|
switch (error.code) {
|
|
26
28
|
default: {
|
|
27
29
|
return {
|
|
@@ -31,14 +31,14 @@ export const Wrapper: FC<PropsWithChildren<WrapperProps>> = ({program, children}
|
|
|
31
31
|
{program.latestVersion && program.latestVersion !== program.version ?
|
|
32
32
|
<Box>
|
|
33
33
|
<Box
|
|
34
|
-
flexDirection="column"
|
|
35
34
|
borderColor={notice}
|
|
36
35
|
borderStyle="round"
|
|
36
|
+
flexDirection="column"
|
|
37
37
|
margin={1}
|
|
38
|
-
paddingTop={1}
|
|
39
|
-
paddingRight={4}
|
|
40
38
|
paddingBottom={1}
|
|
41
39
|
paddingLeft={4}
|
|
40
|
+
paddingRight={4}
|
|
41
|
+
paddingTop={1}
|
|
42
42
|
>
|
|
43
43
|
<Text>
|
|
44
44
|
New version <Text color={highlighted}>{program.latestVersion}</Text> is available!
|
package/source/ui/useProgram.ts
CHANGED
|
@@ -14,6 +14,8 @@ export function useProgram() {
|
|
|
14
14
|
|
|
15
15
|
let exit = useCallback(
|
|
16
16
|
(error: unknown) => {
|
|
17
|
+
// TODO: remove when this is fixed: https://github.com/facebook/react/issues/31544
|
|
18
|
+
// eslint-disable-next-line react-compiler/react-compiler -- false positive
|
|
17
19
|
process.exitCode = 1;
|
|
18
20
|
|
|
19
21
|
showBoundary(error);
|