@shopify/cli-kit 3.47.5 → 3.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/cli-ruby/lib/project_types/extension/messages/messages.rb +18 -1
- package/assets/cli-ruby/lib/shopify_cli/constants.rb +1 -0
- package/assets/cli-ruby/lib/shopify_cli/environment.rb +7 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/extension/dev_server.rb +8 -2
- package/dist/private/node/ui/alert.js +3 -1
- package/dist/private/node/ui/alert.js.map +1 -1
- package/dist/private/node/ui/components/Alert.d.ts +1 -1
- package/dist/private/node/ui/components/Alert.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.d.ts +7 -2
- package/dist/private/node/ui/components/AutocompletePrompt.js +28 -91
- package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.test.js +317 -257
- package/dist/private/node/ui/components/AutocompletePrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.d.ts +1 -0
- package/dist/private/node/ui/components/ConcurrentOutput.js +59 -32
- package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.test.js +62 -22
- package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.d.ts +12 -0
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.js +77 -0
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.js.map +1 -0
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.test.js +101 -0
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.test.js.map +1 -0
- package/dist/private/node/ui/components/List.d.ts +1 -0
- package/dist/private/node/ui/components/List.js +2 -2
- package/dist/private/node/ui/components/List.js.map +1 -1
- package/dist/private/node/ui/components/{GitDiff.d.ts → Prompts/GitDiff.d.ts} +4 -2
- package/dist/private/node/ui/components/{GitDiff.js → Prompts/GitDiff.js} +3 -2
- package/dist/private/node/ui/components/Prompts/GitDiff.js.map +1 -0
- package/dist/private/node/ui/components/Prompts/GitDiff.test.d.ts +1 -0
- package/dist/private/node/ui/components/{GitDiff.test.js → Prompts/GitDiff.test.js} +50 -28
- package/dist/private/node/ui/components/Prompts/GitDiff.test.js.map +1 -0
- package/dist/private/node/ui/components/Prompts/InfoMessage.d.ts +14 -0
- package/dist/private/node/ui/components/Prompts/InfoMessage.js +11 -0
- package/dist/private/node/ui/components/Prompts/InfoMessage.js.map +1 -0
- package/dist/private/node/ui/components/Prompts/InfoMessage.test.d.ts +1 -0
- package/dist/private/node/ui/components/Prompts/InfoMessage.test.js +21 -0
- package/dist/private/node/ui/components/Prompts/InfoMessage.test.js.map +1 -0
- package/dist/private/node/ui/components/Prompts/InfoTable.d.ts +1 -0
- package/dist/private/node/ui/components/Prompts/InfoTable.js +11 -7
- package/dist/private/node/ui/components/Prompts/InfoTable.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/InfoTable.test.js +6 -4
- package/dist/private/node/ui/components/Prompts/InfoTable.test.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.d.ts +21 -0
- package/dist/private/node/ui/components/Prompts/PromptLayout.js +73 -0
- package/dist/private/node/ui/components/Prompts/PromptLayout.js.map +1 -0
- package/dist/private/node/ui/components/Prompts/PromptLayout.test.d.ts +1 -0
- package/dist/private/node/ui/components/Prompts/PromptLayout.test.js +129 -0
- package/dist/private/node/ui/components/Prompts/PromptLayout.test.js.map +1 -0
- package/dist/private/node/ui/components/Scrollbar.d.ts +10 -0
- package/dist/private/node/ui/components/Scrollbar.js +44 -0
- package/dist/private/node/ui/components/Scrollbar.js.map +1 -0
- package/dist/private/node/ui/components/Scrollbar.test.d.ts +1 -0
- package/dist/private/node/ui/components/Scrollbar.test.js +96 -0
- package/dist/private/node/ui/components/Scrollbar.test.js.map +1 -0
- package/dist/private/node/ui/components/SelectInput.d.ts +3 -6
- package/dist/private/node/ui/components/SelectInput.js +57 -41
- package/dist/private/node/ui/components/SelectInput.js.map +1 -1
- package/dist/private/node/ui/components/SelectInput.test.js +120 -192
- package/dist/private/node/ui/components/SelectInput.test.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.d.ts +7 -6
- package/dist/private/node/ui/components/SelectPrompt.js +11 -68
- package/dist/private/node/ui/components/SelectPrompt.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.test.js +135 -65
- package/dist/private/node/ui/components/SelectPrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/Table/Row.js +2 -1
- package/dist/private/node/ui/components/Table/Row.js.map +1 -1
- package/dist/private/node/ui/components/Table/Table.js +2 -1
- package/dist/private/node/ui/components/Table/Table.js.map +1 -1
- package/dist/private/node/ui/components/Tasks.js +1 -8
- package/dist/private/node/ui/components/Tasks.js.map +1 -1
- package/dist/private/node/ui/components/TextInput.d.ts +1 -0
- package/dist/private/node/ui/components/TextInput.js +10 -4
- package/dist/private/node/ui/components/TextInput.js.map +1 -1
- package/dist/private/node/ui/components/TextInput.test.js +27 -18
- package/dist/private/node/ui/components/TextInput.test.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.d.ts +2 -3
- package/dist/private/node/ui/components/TextPrompt.js +18 -16
- package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.test.js +25 -11
- package/dist/private/node/ui/components/TextPrompt.test.js.map +1 -1
- package/dist/private/node/ui/hooks/use-prompt.d.ts +18 -0
- package/dist/private/node/ui/hooks/use-prompt.js +20 -0
- package/dist/private/node/ui/hooks/use-prompt.js.map +1 -0
- package/dist/private/node/ui/hooks/use-select-state.d.ts +4 -4
- package/dist/private/node/ui/hooks/use-select-state.js +9 -9
- package/dist/private/node/ui/hooks/use-select-state.js.map +1 -1
- package/dist/public/common/object.d.ts +16 -0
- package/dist/public/common/object.js +26 -0
- package/dist/public/common/object.js.map +1 -1
- package/dist/public/common/string.d.ts +16 -0
- package/dist/public/common/string.js +30 -0
- package/dist/public/common/string.js.map +1 -1
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/analytics.js +3 -1
- package/dist/public/node/analytics.js.map +1 -1
- package/dist/public/node/base-command.d.ts +1 -0
- package/dist/public/node/base-command.js +21 -1
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/figures.d.ts +2 -0
- package/dist/public/node/figures.js +3 -0
- package/dist/public/node/figures.js.map +1 -0
- package/dist/public/node/metadata.d.ts +2 -1
- package/dist/public/node/metadata.js +5 -2
- package/dist/public/node/metadata.js.map +1 -1
- package/dist/public/node/monorail.d.ts +22 -1
- package/dist/public/node/monorail.js +1 -1
- package/dist/public/node/monorail.js.map +1 -1
- package/dist/public/node/output.d.ts +1 -1
- package/dist/public/node/output.js +1 -1
- package/dist/public/node/output.js.map +1 -1
- package/dist/public/node/ruby.d.ts +1 -0
- package/dist/public/node/ruby.js +1 -0
- package/dist/public/node/ruby.js.map +1 -1
- package/dist/public/node/system.js +2 -2
- package/dist/public/node/system.js.map +1 -1
- package/dist/public/node/themes/models/theme.d.ts +2 -1
- package/dist/public/node/themes/models/theme.js +2 -1
- package/dist/public/node/themes/models/theme.js.map +1 -1
- package/dist/public/node/themes/theme-urls.d.ts +1 -0
- package/dist/public/node/themes/theme-urls.js +4 -0
- package/dist/public/node/themes/theme-urls.js.map +1 -1
- package/dist/public/node/themes/themes-api.d.ts +9 -1
- package/dist/public/node/themes/themes-api.js +14 -3
- package/dist/public/node/themes/themes-api.js.map +1 -1
- package/dist/public/node/toml.d.ts +3 -2
- package/dist/public/node/toml.js +5 -2
- package/dist/public/node/toml.js.map +1 -1
- package/dist/public/node/ui.d.ts +82 -27
- package/dist/public/node/ui.js +97 -32
- package/dist/public/node/ui.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -14
- package/dist/private/node/ui/components/GitDiff.js.map +0 -1
- package/dist/private/node/ui/components/GitDiff.test.js.map +0 -1
- /package/dist/private/node/ui/components/{GitDiff.test.d.ts → DangerousConfirmationPrompt.test.d.ts} +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { InfoMessage } from './InfoMessage.js';
|
|
2
|
+
import { render } from '../../../testing/ui.js';
|
|
3
|
+
import { describe, expect, test } from 'vitest';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
describe('InfoMessage', async () => {
|
|
6
|
+
test('renders a message with title and body', async () => {
|
|
7
|
+
const { lastFrame } = render(React.createElement(InfoMessage, { message: {
|
|
8
|
+
title: {
|
|
9
|
+
color: 'red',
|
|
10
|
+
text: "This can't be undone.",
|
|
11
|
+
},
|
|
12
|
+
body: "Once you upgrade this app, you can't go back to the old way of deploying extensions",
|
|
13
|
+
} }));
|
|
14
|
+
expect(lastFrame()).toMatchInlineSnapshot(`
|
|
15
|
+
"[31mThis can't be undone.[39m
|
|
16
|
+
|
|
17
|
+
Once you upgrade this app, you can't go back to the old way of deploying extensions"
|
|
18
|
+
`);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=InfoMessage.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InfoMessage.test.js","sourceRoot":"","sources":["../../../../../../src/private/node/ui/components/Prompts/InfoMessage.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAC,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAC,MAAM,EAAC,MAAM,wBAAwB,CAAA;AAC7C,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,QAAQ,CAAC,aAAa,EAAE,KAAK,IAAI,EAAE;IACjC,IAAI,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CACxB,oBAAC,WAAW,IACV,OAAO,EAAE;gBACP,KAAK,EAAE;oBACL,KAAK,EAAE,KAAK;oBACZ,IAAI,EAAE,uBAAuB;iBAC9B;gBACD,IAAI,EAAE,qFAAqF;aAC5F,GACD,CACH,CAAA;QAED,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,qBAAqB,CAAC;;;;KAIzC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {InfoMessage} from './InfoMessage.js'\nimport {render} from '../../../testing/ui.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\n\ndescribe('InfoMessage', async () => {\n test('renders a message with title and body', async () => {\n const {lastFrame} = render(\n <InfoMessage\n message={{\n title: {\n color: 'red',\n text: \"This can't be undone.\",\n },\n body: \"Once you upgrade this app, you can't go back to the old way of deploying extensions\",\n }}\n />,\n )\n\n expect(lastFrame()).toMatchInlineSnapshot(`\n \"\u001b[31mThis can't be undone.\u001b[39m\n\n Once you upgrade this app, you can't go back to the old way of deploying extensions\"\n `)\n })\n})\n"]}
|
|
@@ -5,19 +5,23 @@ import React from 'react';
|
|
|
5
5
|
const InfoTable = ({ table }) => {
|
|
6
6
|
const sections = Array.isArray(table)
|
|
7
7
|
? table
|
|
8
|
-
: Object.keys(table).map((header) => ({
|
|
8
|
+
: Object.keys(table).map((header) => ({
|
|
9
|
+
header,
|
|
10
|
+
items: table[header],
|
|
11
|
+
color: undefined,
|
|
12
|
+
helperText: undefined,
|
|
13
|
+
bullet: undefined,
|
|
14
|
+
}));
|
|
9
15
|
const headerColumnWidth = Math.max(...sections.map((section) => {
|
|
10
16
|
return Math.max(...section.header.split('\n').map((line) => {
|
|
11
17
|
return line.length;
|
|
12
18
|
}));
|
|
13
19
|
}));
|
|
14
|
-
return (React.createElement(Box, { flexDirection: "column" }, sections.map((section, index) => (React.createElement(Box, { key: index, marginBottom: index === sections.length - 1 ? 0 : 1 },
|
|
20
|
+
return (React.createElement(Box, { flexDirection: "column" }, sections.map((section, index) => (React.createElement(Box, { key: index, marginBottom: index === sections.length - 1 ? 0 : 1, flexDirection: "column" },
|
|
15
21
|
section.header.length > 0 && (React.createElement(Box, { width: headerColumnWidth + 1 },
|
|
16
|
-
React.createElement(Text, { color: section.color },
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
React.createElement(Box, { marginLeft: section.header.length > 0 ? 2 : 0, flexGrow: 1, flexDirection: "column", gap: 1 },
|
|
20
|
-
React.createElement(List, { margin: false, items: section.items, color: section.color }),
|
|
22
|
+
React.createElement(Text, { color: section.color, bold: true }, capitalize(section.header)))),
|
|
23
|
+
React.createElement(Box, { flexGrow: 1, flexDirection: "column", gap: 1 },
|
|
24
|
+
React.createElement(List, { margin: false, items: section.items, color: section.color, bullet: section.bullet }),
|
|
21
25
|
section.helperText ? React.createElement(Text, { color: section.color }, section.helperText) : null))))));
|
|
22
26
|
};
|
|
23
27
|
export { InfoTable };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfoTable.js","sourceRoot":"","sources":["../../../../../../src/private/node/ui/components/Prompts/InfoTable.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,YAAY,CAAA;AAC/B,OAAO,EAAC,UAAU,EAAC,MAAM,wCAAwC,CAAA;AAEjE,OAAO,EAAC,GAAG,EAAE,IAAI,EAAY,MAAM,KAAK,CAAA;AACxC,OAAO,KAA0B,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"InfoTable.js","sourceRoot":"","sources":["../../../../../../src/private/node/ui/components/Prompts/InfoTable.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,YAAY,CAAA;AAC/B,OAAO,EAAC,UAAU,EAAC,MAAM,wCAAwC,CAAA;AAEjE,OAAO,EAAC,GAAG,EAAE,IAAI,EAAY,MAAM,KAAK,CAAA;AACxC,OAAO,KAA0B,MAAM,OAAO,CAAA;AAoB9C,MAAM,SAAS,GAAsC,CAAC,EAAC,KAAK,EAAC,EAAE,EAAE;IAC/D,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACnC,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAClC,MAAM;YACN,KAAK,EAAE,KAAK,CAAC,MAAM,CAAE;YACrB,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,SAAS;YACrB,MAAM,EAAE,SAAS;SAClB,CAAC,CAAC,CAAA;IAEP,MAAM,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAChC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAC1B,OAAO,IAAI,CAAC,GAAG,CACb,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACzC,OAAO,IAAI,CAAC,MAAM,CAAA;QACpB,CAAC,CAAC,CACH,CAAA;IACH,CAAC,CAAC,CACH,CAAA;IAED,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,IACxB,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CAChC,oBAAC,GAAG,IAAC,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,aAAa,EAAC,QAAQ;QACzF,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAC5B,oBAAC,GAAG,IAAC,KAAK,EAAE,iBAAiB,GAAG,CAAC;YAC/B,oBAAC,IAAI,IAAC,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,UAC7B,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CACtB,CACH,CACP;QACD,oBAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,EAAC,GAAG,EAAE,CAAC;YAC7C,oBAAC,IAAI,IAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,GAAI;YAC1F,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAG,OAAO,CAAC,UAAU,CAAQ,CAAC,CAAC,CAAC,IAAI,CAChF,CACF,CACP,CAAC,CACE,CACP,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,SAAS,EAAC,CAAA","sourcesContent":["import {List} from '../List.js'\nimport {capitalize} from '../../../../../public/common/string.js'\nimport {InlineToken, TokenItem} from '../TokenizedText.js'\nimport {Box, Text, TextProps} from 'ink'\nimport React, {FunctionComponent} from 'react'\n\ntype Items = TokenItem<InlineToken>[]\n\nexport interface InfoTableSection {\n color?: TextProps['color']\n header: string\n bullet?: string\n helperText?: string\n items: Items\n}\n\nexport interface InfoTableProps {\n table:\n | {\n [header: string]: Items\n }\n | InfoTableSection[]\n}\n\nconst InfoTable: FunctionComponent<InfoTableProps> = ({table}) => {\n const sections = Array.isArray(table)\n ? table\n : Object.keys(table).map((header) => ({\n header,\n items: table[header]!,\n color: undefined,\n helperText: undefined,\n bullet: undefined,\n }))\n\n const headerColumnWidth = Math.max(\n ...sections.map((section) => {\n return Math.max(\n ...section.header.split('\\n').map((line) => {\n return line.length\n }),\n )\n }),\n )\n\n return (\n <Box flexDirection=\"column\">\n {sections.map((section, index) => (\n <Box key={index} marginBottom={index === sections.length - 1 ? 0 : 1} flexDirection=\"column\">\n {section.header.length > 0 && (\n <Box width={headerColumnWidth + 1}>\n <Text color={section.color} bold>\n {capitalize(section.header)}\n </Text>\n </Box>\n )}\n <Box flexGrow={1} flexDirection=\"column\" gap={1}>\n <List margin={false} items={section.items} color={section.color} bullet={section.bullet} />\n {section.helperText ? <Text color={section.color}>{section.helperText}</Text> : null}\n </Box>\n </Box>\n ))}\n </Box>\n )\n}\n\nexport {InfoTable}\n"]}
|
|
@@ -10,11 +10,13 @@ describe('InfoTable', async () => {
|
|
|
10
10
|
'header 2\nlonger text here': [['one item', { link: { label: 'Shopify', url: 'https://shopify.com' } }]],
|
|
11
11
|
} }));
|
|
12
12
|
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
13
|
-
"Header 1
|
|
14
|
-
|
|
13
|
+
"Header 1
|
|
14
|
+
• some
|
|
15
|
+
• items
|
|
15
16
|
|
|
16
|
-
Header 2
|
|
17
|
-
longer text here
|
|
17
|
+
Header 2
|
|
18
|
+
longer text here
|
|
19
|
+
• one item Shopify ( https://shopify.com )"
|
|
18
20
|
`);
|
|
19
21
|
});
|
|
20
22
|
test('supports an empty header value', async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfoTable.test.js","sourceRoot":"","sources":["../../../../../../src/private/node/ui/components/Prompts/InfoTable.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAC,QAAQ,EAAC,MAAM,sCAAsC,CAAA;AAC7D,OAAO,EAAC,MAAM,EAAC,MAAM,wBAAwB,CAAA;AAC7C,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,QAAQ,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE;IAC/B,IAAI,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CACxB,oBAAC,SAAS,IACR,KAAK,EAAE;gBACL,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;gBAC7B,4BAA4B,EAAE,CAAC,CAAC,UAAU,EAAE,EAAC,IAAI,EAAE,EAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,qBAAqB,EAAC,EAAC,CAAC,CAAC;aACrG,GACD,CACH,CAAA;QAED,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC
|
|
1
|
+
{"version":3,"file":"InfoTable.test.js","sourceRoot":"","sources":["../../../../../../src/private/node/ui/components/Prompts/InfoTable.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAC,QAAQ,EAAC,MAAM,sCAAsC,CAAA;AAC7D,OAAO,EAAC,MAAM,EAAC,MAAM,wBAAwB,CAAA;AAC7C,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,QAAQ,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE;IAC/B,IAAI,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CACxB,oBAAC,SAAS,IACR,KAAK,EAAE;gBACL,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;gBAC7B,4BAA4B,EAAE,CAAC,CAAC,UAAU,EAAE,EAAC,IAAI,EAAE,EAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,qBAAqB,EAAC,EAAC,CAAC,CAAC;aACrG,GACD,CACH,CAAA;QAED,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;KAQpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CACxB,oBAAC,SAAS,IACR,KAAK,EAAE;gBACL,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;aACtB,GACD,CACH,CAAA;QAED,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;KAGpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {InfoTable} from './InfoTable.js'\nimport {unstyled} from '../../../../../public/node/output.js'\nimport {render} from '../../../testing/ui.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\n\ndescribe('InfoTable', async () => {\n test('renders a horizontal table with bullet points', async () => {\n const {lastFrame} = render(\n <InfoTable\n table={{\n 'header 1': ['some', 'items'],\n 'header 2\\nlonger text here': [['one item', {link: {label: 'Shopify', url: 'https://shopify.com'}}]],\n }}\n />,\n )\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"Header 1\n • some\n • items\n\n Header 2\n longer text here\n • one item Shopify ( https://shopify.com )\"\n `)\n })\n\n test('supports an empty header value', async () => {\n const {lastFrame} = render(\n <InfoTable\n table={{\n '': ['some', 'items'],\n }}\n />,\n )\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"• some\n • items\"\n `)\n })\n})\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { GitDiffProps } from './GitDiff.js';
|
|
2
|
+
import { InfoMessageProps } from './InfoMessage.js';
|
|
3
|
+
import { InfoTableProps } from './InfoTable.js';
|
|
4
|
+
import { InlineToken, LinkToken, TokenItem } from '../TokenizedText.js';
|
|
5
|
+
import { AbortSignal } from '../../../../../public/node/abort.js';
|
|
6
|
+
import { PromptState } from '../../hooks/use-prompt.js';
|
|
7
|
+
import { ReactElement } from 'react';
|
|
8
|
+
export type Message = TokenItem<Exclude<InlineToken, LinkToken>>;
|
|
9
|
+
export interface PromptLayoutProps {
|
|
10
|
+
message: Message;
|
|
11
|
+
infoTable?: InfoTableProps['table'];
|
|
12
|
+
abortSignal?: AbortSignal;
|
|
13
|
+
infoMessage?: InfoMessageProps['message'];
|
|
14
|
+
gitDiff?: GitDiffProps['gitDiff'];
|
|
15
|
+
header?: ReactElement | null;
|
|
16
|
+
state: PromptState;
|
|
17
|
+
submittedAnswerLabel?: string;
|
|
18
|
+
input: ReactElement;
|
|
19
|
+
}
|
|
20
|
+
declare const PromptLayout: ({ message, infoTable, abortSignal, infoMessage, gitDiff, header, state, input, submittedAnswerLabel, }: PromptLayoutProps) => ReactElement | null;
|
|
21
|
+
export { PromptLayout };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { GitDiff } from './GitDiff.js';
|
|
2
|
+
import { InfoMessage } from './InfoMessage.js';
|
|
3
|
+
import { InfoTable } from './InfoTable.js';
|
|
4
|
+
import { TokenizedText } from '../TokenizedText.js';
|
|
5
|
+
import { messageWithPunctuation } from '../../utilities.js';
|
|
6
|
+
import useAbortSignal from '../../hooks/use-abort-signal.js';
|
|
7
|
+
import { PromptState } from '../../hooks/use-prompt.js';
|
|
8
|
+
import React, { cloneElement, useCallback, useLayoutEffect, useState } from 'react';
|
|
9
|
+
import { Box, measureElement, Text, useStdout } from 'ink';
|
|
10
|
+
import figures from 'figures';
|
|
11
|
+
const PromptLayout = ({ message, infoTable, abortSignal, infoMessage, gitDiff, header, state, input, submittedAnswerLabel, }) => {
|
|
12
|
+
const { stdout } = useStdout();
|
|
13
|
+
const [wrapperHeight, setWrapperHeight] = useState(0);
|
|
14
|
+
const [promptAreaHeight, setPromptAreaHeight] = useState(0);
|
|
15
|
+
const [inputFixedAreaHeight, setInputFixedAreaHeight] = useState(0);
|
|
16
|
+
const currentAvailableLines = stdout.rows - promptAreaHeight - inputFixedAreaHeight;
|
|
17
|
+
const [availableLines, setAvailableLines] = useState(currentAvailableLines);
|
|
18
|
+
const wrapperRef = useCallback((node) => {
|
|
19
|
+
if (node !== null) {
|
|
20
|
+
const { height } = measureElement(node);
|
|
21
|
+
if (wrapperHeight !== height) {
|
|
22
|
+
setWrapperHeight(height);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}, [wrapperHeight]);
|
|
26
|
+
const promptAreaRef = useCallback((node) => {
|
|
27
|
+
if (node !== null) {
|
|
28
|
+
const { height } = measureElement(node);
|
|
29
|
+
setPromptAreaHeight(height);
|
|
30
|
+
}
|
|
31
|
+
}, []);
|
|
32
|
+
const inputFixedAreaRef = useCallback((node) => {
|
|
33
|
+
if (node !== null) {
|
|
34
|
+
const { height } = measureElement(node);
|
|
35
|
+
// + 3 accounts for the margins inside the input elements and the last empty line of the terminal
|
|
36
|
+
setInputFixedAreaHeight(height + 3);
|
|
37
|
+
}
|
|
38
|
+
}, []);
|
|
39
|
+
const inputComponent = cloneElement(input, { availableLines, inputFixedAreaRef });
|
|
40
|
+
useLayoutEffect(() => {
|
|
41
|
+
function onResize() {
|
|
42
|
+
const newAvailableLines = stdout.rows - promptAreaHeight - inputFixedAreaHeight;
|
|
43
|
+
if (newAvailableLines !== availableLines) {
|
|
44
|
+
setAvailableLines(newAvailableLines);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
onResize();
|
|
48
|
+
stdout.on('resize', onResize);
|
|
49
|
+
return () => {
|
|
50
|
+
stdout.off('resize', onResize);
|
|
51
|
+
};
|
|
52
|
+
}, [wrapperHeight, promptAreaHeight, stdout, availableLines, inputFixedAreaHeight]);
|
|
53
|
+
const { isAborted } = useAbortSignal(abortSignal);
|
|
54
|
+
// Object.keys on an array returns the indices as strings
|
|
55
|
+
const showInfoTable = infoTable && Object.keys(infoTable).length > 0;
|
|
56
|
+
return isAborted ? null : (React.createElement(Box, { flexDirection: "column", marginBottom: 1, ref: wrapperRef },
|
|
57
|
+
React.createElement(Box, { ref: promptAreaRef, flexDirection: "column" },
|
|
58
|
+
React.createElement(Box, null,
|
|
59
|
+
React.createElement(Box, { marginRight: 2 },
|
|
60
|
+
React.createElement(Text, null, "?")),
|
|
61
|
+
React.createElement(TokenizedText, { item: messageWithPunctuation(message) }),
|
|
62
|
+
header),
|
|
63
|
+
(showInfoTable || infoMessage || gitDiff) && state !== PromptState.Submitted ? (React.createElement(Box, { marginTop: 1, marginLeft: 3, paddingLeft: 2, borderStyle: "bold", borderLeft: true, borderRight: false, borderTop: false, borderBottom: false, flexDirection: "column", gap: 1 },
|
|
64
|
+
infoMessage ? React.createElement(InfoMessage, { message: infoMessage }) : null,
|
|
65
|
+
showInfoTable ? React.createElement(InfoTable, { table: infoTable }) : null,
|
|
66
|
+
gitDiff ? React.createElement(GitDiff, { gitDiff: gitDiff }) : null)) : null),
|
|
67
|
+
state === PromptState.Submitted && submittedAnswerLabel ? (React.createElement(Box, null,
|
|
68
|
+
React.createElement(Box, { marginRight: 2 },
|
|
69
|
+
React.createElement(Text, { color: "cyan" }, figures.tick)),
|
|
70
|
+
React.createElement(Text, { color: "cyan" }, submittedAnswerLabel))) : (React.createElement(Box, { marginTop: 1 }, inputComponent))));
|
|
71
|
+
};
|
|
72
|
+
export { PromptLayout };
|
|
73
|
+
//# sourceMappingURL=PromptLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptLayout.js","sourceRoot":"","sources":["../../../../../../src/private/node/ui/components/Prompts/PromptLayout.tsx"],"names":[],"mappings":"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","sourcesContent":["import {GitDiff, GitDiffProps} from './GitDiff.js'\nimport {InfoMessage, InfoMessageProps} from './InfoMessage.js'\nimport {InfoTable, InfoTableProps} from './InfoTable.js'\nimport {InlineToken, LinkToken, TokenItem, TokenizedText} from '../TokenizedText.js'\nimport {messageWithPunctuation} from '../../utilities.js'\nimport {AbortSignal} from '../../../../../public/node/abort.js'\nimport useAbortSignal from '../../hooks/use-abort-signal.js'\nimport {PromptState} from '../../hooks/use-prompt.js'\nimport React, {ReactElement, cloneElement, useCallback, useLayoutEffect, useState} from 'react'\nimport {Box, measureElement, Text, useStdout} from 'ink'\nimport figures from 'figures'\n\nexport type Message = TokenItem<Exclude<InlineToken, LinkToken>>\n\nexport interface PromptLayoutProps {\n message: Message\n infoTable?: InfoTableProps['table']\n abortSignal?: AbortSignal\n infoMessage?: InfoMessageProps['message']\n gitDiff?: GitDiffProps['gitDiff']\n header?: ReactElement | null\n state: PromptState\n submittedAnswerLabel?: string\n input: ReactElement\n}\n\nconst PromptLayout = ({\n message,\n infoTable,\n abortSignal,\n infoMessage,\n gitDiff,\n header,\n state,\n input,\n submittedAnswerLabel,\n}: PromptLayoutProps): ReactElement | null => {\n const {stdout} = useStdout()\n const [wrapperHeight, setWrapperHeight] = useState(0)\n const [promptAreaHeight, setPromptAreaHeight] = useState(0)\n const [inputFixedAreaHeight, setInputFixedAreaHeight] = useState(0)\n const currentAvailableLines = stdout.rows - promptAreaHeight - inputFixedAreaHeight\n const [availableLines, setAvailableLines] = useState(currentAvailableLines)\n\n const wrapperRef = useCallback(\n (node) => {\n if (node !== null) {\n const {height} = measureElement(node)\n if (wrapperHeight !== height) {\n setWrapperHeight(height)\n }\n }\n },\n [wrapperHeight],\n )\n\n const promptAreaRef = useCallback((node) => {\n if (node !== null) {\n const {height} = measureElement(node)\n setPromptAreaHeight(height)\n }\n }, [])\n\n const inputFixedAreaRef = useCallback((node) => {\n if (node !== null) {\n const {height} = measureElement(node)\n // + 3 accounts for the margins inside the input elements and the last empty line of the terminal\n setInputFixedAreaHeight(height + 3)\n }\n }, [])\n\n const inputComponent = cloneElement(input, {availableLines, inputFixedAreaRef})\n\n useLayoutEffect(() => {\n function onResize() {\n const newAvailableLines = stdout.rows - promptAreaHeight - inputFixedAreaHeight\n if (newAvailableLines !== availableLines) {\n setAvailableLines(newAvailableLines)\n }\n }\n\n onResize()\n\n stdout.on('resize', onResize)\n return () => {\n stdout.off('resize', onResize)\n }\n }, [wrapperHeight, promptAreaHeight, stdout, availableLines, inputFixedAreaHeight])\n\n const {isAborted} = useAbortSignal(abortSignal)\n // Object.keys on an array returns the indices as strings\n const showInfoTable = infoTable && Object.keys(infoTable).length > 0\n\n return isAborted ? null : (\n <Box flexDirection=\"column\" marginBottom={1} ref={wrapperRef}>\n <Box ref={promptAreaRef} flexDirection=\"column\">\n <Box>\n <Box marginRight={2}>\n <Text>?</Text>\n </Box>\n <TokenizedText item={messageWithPunctuation(message)} />\n {header}\n </Box>\n\n {(showInfoTable || infoMessage || gitDiff) && state !== PromptState.Submitted ? (\n <Box\n marginTop={1}\n marginLeft={3}\n paddingLeft={2}\n borderStyle=\"bold\"\n borderLeft\n borderRight={false}\n borderTop={false}\n borderBottom={false}\n flexDirection=\"column\"\n gap={1}\n >\n {infoMessage ? <InfoMessage message={infoMessage} /> : null}\n {showInfoTable ? <InfoTable table={infoTable} /> : null}\n {gitDiff ? <GitDiff gitDiff={gitDiff} /> : null}\n </Box>\n ) : null}\n </Box>\n\n {state === PromptState.Submitted && submittedAnswerLabel ? (\n <Box>\n <Box marginRight={2}>\n <Text color=\"cyan\">{figures.tick}</Text>\n </Box>\n\n <Text color=\"cyan\">{submittedAnswerLabel}</Text>\n </Box>\n ) : (\n <Box marginTop={1}>{inputComponent}</Box>\n )}\n </Box>\n )\n}\n\nexport {PromptLayout}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { PromptLayout } from './PromptLayout.js';
|
|
2
|
+
import { render } from '../../../testing/ui.js';
|
|
3
|
+
import { PromptState } from '../../hooks/use-prompt.js';
|
|
4
|
+
import { describe, expect, test } from 'vitest';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { Box, Text } from 'ink';
|
|
7
|
+
describe('PromptLayout', async () => {
|
|
8
|
+
test("doesn't add unnecessary margins when infoTable is an empty array", async () => {
|
|
9
|
+
const items = [
|
|
10
|
+
{ label: 'first', value: 'first' },
|
|
11
|
+
{ label: 'second', value: 'second' },
|
|
12
|
+
{ label: 'third', value: 'third' },
|
|
13
|
+
{ label: 'fourth', value: 'fourth' },
|
|
14
|
+
];
|
|
15
|
+
const renderInstance = render(React.createElement(PromptLayout, { message: "Associate your project with the org Castile Ventures?", infoTable: [], state: PromptState.Idle, input: React.createElement(Box, { flexDirection: "column" }, items.map((item) => (React.createElement(Text, { key: item.value }, item.label)))) }));
|
|
16
|
+
expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`
|
|
17
|
+
"? Associate your project with the org Castile Ventures?
|
|
18
|
+
|
|
19
|
+
first
|
|
20
|
+
second
|
|
21
|
+
third
|
|
22
|
+
fourth
|
|
23
|
+
"
|
|
24
|
+
`);
|
|
25
|
+
});
|
|
26
|
+
test("doesn't add unnecessary margins when infoTable is an empty object", async () => {
|
|
27
|
+
const items = [
|
|
28
|
+
{ label: 'first', value: 'first' },
|
|
29
|
+
{ label: 'second', value: 'second' },
|
|
30
|
+
{ label: 'third', value: 'third' },
|
|
31
|
+
{ label: 'fourth', value: 'fourth' },
|
|
32
|
+
];
|
|
33
|
+
const renderInstance = render(React.createElement(PromptLayout, { message: "Associate your project with the org Castile Ventures?", infoTable: {}, state: PromptState.Idle, input: React.createElement(Box, { flexDirection: "column" }, items.map((item) => (React.createElement(Text, { key: item.value }, item.label)))) }));
|
|
34
|
+
expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`
|
|
35
|
+
"? Associate your project with the org Castile Ventures?
|
|
36
|
+
|
|
37
|
+
first
|
|
38
|
+
second
|
|
39
|
+
third
|
|
40
|
+
fourth
|
|
41
|
+
"
|
|
42
|
+
`);
|
|
43
|
+
});
|
|
44
|
+
test("doesn't add unnecessary margins when infoTable is empty and there are other elements in the header", async () => {
|
|
45
|
+
const items = [
|
|
46
|
+
{ label: 'first', value: 'first' },
|
|
47
|
+
{ label: 'second', value: 'second' },
|
|
48
|
+
{ label: 'third', value: 'third' },
|
|
49
|
+
{ label: 'fourth', value: 'fourth' },
|
|
50
|
+
];
|
|
51
|
+
const gitDiff = {
|
|
52
|
+
baselineContent: 'hello',
|
|
53
|
+
updatedContent: 'hello',
|
|
54
|
+
};
|
|
55
|
+
const infoMessage = {
|
|
56
|
+
title: { text: 'some title' },
|
|
57
|
+
body: 'some body',
|
|
58
|
+
};
|
|
59
|
+
const renderInstance = render(React.createElement(PromptLayout, { message: "Associate your project with the org Castile Ventures?", infoTable: [], infoMessage: infoMessage, gitDiff: gitDiff, state: PromptState.Idle, input: React.createElement(Box, { flexDirection: "column" }, items.map((item) => (React.createElement(Text, { key: item.value }, item.label)))) }));
|
|
60
|
+
expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`
|
|
61
|
+
"? Associate your project with the org Castile Ventures?
|
|
62
|
+
|
|
63
|
+
┃ some title
|
|
64
|
+
┃
|
|
65
|
+
┃ some body
|
|
66
|
+
┃
|
|
67
|
+
┃ No changes.
|
|
68
|
+
|
|
69
|
+
first
|
|
70
|
+
second
|
|
71
|
+
third
|
|
72
|
+
fourth
|
|
73
|
+
"
|
|
74
|
+
`);
|
|
75
|
+
});
|
|
76
|
+
test('can have all elements visible in the header at the same time', async () => {
|
|
77
|
+
const items = [
|
|
78
|
+
{ label: 'first', value: 'first' },
|
|
79
|
+
{ label: 'second', value: 'second' },
|
|
80
|
+
{ label: 'third', value: 'third' },
|
|
81
|
+
{ label: 'fourth', value: 'fourth' },
|
|
82
|
+
];
|
|
83
|
+
const gitDiff = {
|
|
84
|
+
baselineContent: 'hello',
|
|
85
|
+
updatedContent: 'hello',
|
|
86
|
+
};
|
|
87
|
+
const infoMessage = {
|
|
88
|
+
title: { text: 'some title' },
|
|
89
|
+
body: 'some body',
|
|
90
|
+
};
|
|
91
|
+
const infoTable = {
|
|
92
|
+
header1: ['item 1', 'item 2', 'item 3'],
|
|
93
|
+
header2: ['item 4', 'item 5', 'item 6'],
|
|
94
|
+
header3: ['item 7', 'item 8', 'item 9'],
|
|
95
|
+
};
|
|
96
|
+
const renderInstance = render(React.createElement(PromptLayout, { message: "Associate your project with the org Castile Ventures?", infoTable: infoTable, infoMessage: infoMessage, gitDiff: gitDiff, state: PromptState.Idle, input: React.createElement(Box, { flexDirection: "column" }, items.map((item) => (React.createElement(Text, { key: item.value }, item.label)))) }));
|
|
97
|
+
expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`
|
|
98
|
+
"? Associate your project with the org Castile Ventures?
|
|
99
|
+
|
|
100
|
+
┃ some title
|
|
101
|
+
┃
|
|
102
|
+
┃ some body
|
|
103
|
+
┃
|
|
104
|
+
┃ [1mHeader1[22m
|
|
105
|
+
┃ • item 1
|
|
106
|
+
┃ • item 2
|
|
107
|
+
┃ • item 3
|
|
108
|
+
┃
|
|
109
|
+
┃ [1mHeader2[22m
|
|
110
|
+
┃ • item 4
|
|
111
|
+
┃ • item 5
|
|
112
|
+
┃ • item 6
|
|
113
|
+
┃
|
|
114
|
+
┃ [1mHeader3[22m
|
|
115
|
+
┃ • item 7
|
|
116
|
+
┃ • item 8
|
|
117
|
+
┃ • item 9
|
|
118
|
+
┃
|
|
119
|
+
┃ No changes.
|
|
120
|
+
|
|
121
|
+
first
|
|
122
|
+
second
|
|
123
|
+
third
|
|
124
|
+
fourth
|
|
125
|
+
"
|
|
126
|
+
`);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=PromptLayout.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptLayout.test.js","sourceRoot":"","sources":["../../../../../../src/private/node/ui/components/Prompts/PromptLayout.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {PromptLayout} from './PromptLayout.js'\nimport {render} from '../../../testing/ui.js'\nimport {PromptState} from '../../hooks/use-prompt.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\nimport {Box, Text} from 'ink'\n\ndescribe('PromptLayout', async () => {\n test(\"doesn't add unnecessary margins when infoTable is an empty array\", async () => {\n const items = [\n {label: 'first', value: 'first'},\n {label: 'second', value: 'second'},\n {label: 'third', value: 'third'},\n {label: 'fourth', value: 'fourth'},\n ]\n\n const renderInstance = render(\n <PromptLayout\n message=\"Associate your project with the org Castile Ventures?\"\n infoTable={[]}\n state={PromptState.Idle}\n input={\n <Box flexDirection=\"column\">\n {items.map((item) => (\n <Text key={item.value}>{item.label}</Text>\n ))}\n </Box>\n }\n />,\n )\n\n expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`\n \"? Associate your project with the org Castile Ventures?\n\n first\n second\n third\n fourth\n \"\n `)\n })\n\n test(\"doesn't add unnecessary margins when infoTable is an empty object\", async () => {\n const items = [\n {label: 'first', value: 'first'},\n {label: 'second', value: 'second'},\n {label: 'third', value: 'third'},\n {label: 'fourth', value: 'fourth'},\n ]\n\n const renderInstance = render(\n <PromptLayout\n message=\"Associate your project with the org Castile Ventures?\"\n infoTable={{}}\n state={PromptState.Idle}\n input={\n <Box flexDirection=\"column\">\n {items.map((item) => (\n <Text key={item.value}>{item.label}</Text>\n ))}\n </Box>\n }\n />,\n )\n\n expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`\n \"? Associate your project with the org Castile Ventures?\n\n first\n second\n third\n fourth\n \"\n `)\n })\n\n test(\"doesn't add unnecessary margins when infoTable is empty and there are other elements in the header\", async () => {\n const items = [\n {label: 'first', value: 'first'},\n {label: 'second', value: 'second'},\n {label: 'third', value: 'third'},\n {label: 'fourth', value: 'fourth'},\n ]\n\n const gitDiff = {\n baselineContent: 'hello',\n updatedContent: 'hello',\n }\n\n const infoMessage = {\n title: {text: 'some title'},\n body: 'some body',\n }\n\n const renderInstance = render(\n <PromptLayout\n message=\"Associate your project with the org Castile Ventures?\"\n infoTable={[]}\n infoMessage={infoMessage}\n gitDiff={gitDiff}\n state={PromptState.Idle}\n input={\n <Box flexDirection=\"column\">\n {items.map((item) => (\n <Text key={item.value}>{item.label}</Text>\n ))}\n </Box>\n }\n />,\n )\n\n expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`\n \"? Associate your project with the org Castile Ventures?\n\n ┃ some title\n ┃\n ┃ some body\n ┃\n ┃ No changes.\n\n first\n second\n third\n fourth\n \"\n `)\n })\n\n test('can have all elements visible in the header at the same time', async () => {\n const items = [\n {label: 'first', value: 'first'},\n {label: 'second', value: 'second'},\n {label: 'third', value: 'third'},\n {label: 'fourth', value: 'fourth'},\n ]\n\n const gitDiff = {\n baselineContent: 'hello',\n updatedContent: 'hello',\n }\n\n const infoMessage = {\n title: {text: 'some title'},\n body: 'some body',\n }\n\n const infoTable = {\n header1: ['item 1', 'item 2', 'item 3'],\n header2: ['item 4', 'item 5', 'item 6'],\n header3: ['item 7', 'item 8', 'item 9'],\n }\n\n const renderInstance = render(\n <PromptLayout\n message=\"Associate your project with the org Castile Ventures?\"\n infoTable={infoTable}\n infoMessage={infoMessage}\n gitDiff={gitDiff}\n state={PromptState.Idle}\n input={\n <Box flexDirection=\"column\">\n {items.map((item) => (\n <Text key={item.value}>{item.label}</Text>\n ))}\n </Box>\n }\n />,\n )\n\n expect(renderInstance.lastFrame()).toMatchInlineSnapshot(`\n \"? Associate your project with the org Castile Ventures?\n\n ┃ some title\n ┃\n ┃ some body\n ┃\n ┃ \u001b[1mHeader1\u001b[22m\n ┃ • item 1\n ┃ • item 2\n ┃ • item 3\n ┃\n ┃ \u001b[1mHeader2\u001b[22m\n ┃ • item 4\n ┃ • item 5\n ┃ • item 6\n ┃\n ┃ \u001b[1mHeader3\u001b[22m\n ┃ • item 7\n ┃ • item 8\n ┃ • item 9\n ┃\n ┃ No changes.\n\n first\n second\n third\n fourth\n \"\n `)\n })\n})\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FunctionComponent } from 'react';
|
|
2
|
+
export interface ScrollbarProps {
|
|
3
|
+
containerHeight: number;
|
|
4
|
+
visibleListSectionLength: number;
|
|
5
|
+
fullListLength: number;
|
|
6
|
+
visibleFromIndex: number;
|
|
7
|
+
noColor?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare const Scrollbar: FunctionComponent<ScrollbarProps>;
|
|
10
|
+
export { Scrollbar };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { shouldDisplayColors } from '../../../../public/node/output.js';
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
const BACKGROUND_CHAR = '│';
|
|
5
|
+
const SCROLLBOX_CHAR = '║';
|
|
6
|
+
const Scrollbar = ({ containerHeight, visibleListSectionLength, fullListLength, visibleFromIndex, noColor = !shouldDisplayColors(), }) => {
|
|
7
|
+
const displayArrows = containerHeight >= 4 && noColor;
|
|
8
|
+
const visibleToIndex = visibleFromIndex + visibleListSectionLength - 1;
|
|
9
|
+
// Leave 2 rows for top/bottom arrows when there is vertical room for them.
|
|
10
|
+
const fullHeight = displayArrows ? containerHeight - 2 : containerHeight;
|
|
11
|
+
const scrollboxHeight = Math.min(fullHeight - 1, Math.ceil(Math.min(1, visibleListSectionLength / fullListLength) * fullHeight));
|
|
12
|
+
let topBuffer;
|
|
13
|
+
// Ensure it scrolls all the way to the bottom when we hit the bottom
|
|
14
|
+
if (visibleToIndex >= fullListLength - 1) {
|
|
15
|
+
topBuffer = fullHeight - scrollboxHeight;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
// This is the actual number of rows available for the scrollbar to go up and down
|
|
19
|
+
const scrollingLength = fullHeight - scrollboxHeight;
|
|
20
|
+
// This is the number of times the screen itself can scroll down
|
|
21
|
+
const scrollableIncrements = fullListLength - visibleListSectionLength;
|
|
22
|
+
topBuffer = Math.max(
|
|
23
|
+
// Never go negative, that causes errors!
|
|
24
|
+
0, Math.min(
|
|
25
|
+
// Never have more buffer than filling in all spaces above the scrollbox
|
|
26
|
+
fullHeight - scrollboxHeight, Math.round((visibleFromIndex / scrollableIncrements) * scrollingLength)));
|
|
27
|
+
}
|
|
28
|
+
const bottomBuffer = fullHeight - scrollboxHeight - topBuffer;
|
|
29
|
+
const backgroundChar = noColor ? BACKGROUND_CHAR : ' ';
|
|
30
|
+
const scrollboxChar = noColor ? SCROLLBOX_CHAR : ' ';
|
|
31
|
+
const bgColor = noColor ? undefined : 'gray';
|
|
32
|
+
const scrollboxColor = noColor ? undefined : 'cyan';
|
|
33
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
34
|
+
displayArrows ? React.createElement(Text, null, "\u25B3") : null,
|
|
35
|
+
React.createElement(Box, { width: 1 },
|
|
36
|
+
React.createElement(Text, { backgroundColor: bgColor }, backgroundChar.repeat(topBuffer))),
|
|
37
|
+
React.createElement(Box, { width: 1 },
|
|
38
|
+
React.createElement(Text, { backgroundColor: scrollboxColor }, scrollboxChar.repeat(scrollboxHeight))),
|
|
39
|
+
React.createElement(Box, { width: 1 },
|
|
40
|
+
React.createElement(Text, { backgroundColor: bgColor }, backgroundChar.repeat(bottomBuffer))),
|
|
41
|
+
displayArrows ? React.createElement(Text, null, "\u25BD") : null));
|
|
42
|
+
};
|
|
43
|
+
export { Scrollbar };
|
|
44
|
+
//# sourceMappingURL=Scrollbar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Scrollbar.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Scrollbar.tsx"],"names":[],"mappings":"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","sourcesContent":["import {shouldDisplayColors} from '../../../../public/node/output.js'\nimport {Box, Text} from 'ink'\nimport React, {FunctionComponent} from 'react'\n\nexport interface ScrollbarProps {\n containerHeight: number\n visibleListSectionLength: number\n fullListLength: number\n visibleFromIndex: number\n noColor?: boolean\n}\n\nconst BACKGROUND_CHAR = '│'\nconst SCROLLBOX_CHAR = '║'\n\nconst Scrollbar: FunctionComponent<ScrollbarProps> = ({\n containerHeight,\n visibleListSectionLength,\n fullListLength,\n visibleFromIndex,\n noColor = !shouldDisplayColors(),\n}) => {\n const displayArrows = containerHeight >= 4 && noColor\n const visibleToIndex = visibleFromIndex + visibleListSectionLength - 1\n\n // Leave 2 rows for top/bottom arrows when there is vertical room for them.\n const fullHeight = displayArrows ? containerHeight - 2 : containerHeight\n const scrollboxHeight = Math.min(\n fullHeight - 1,\n Math.ceil(Math.min(1, visibleListSectionLength / fullListLength) * fullHeight),\n )\n\n let topBuffer: number\n // Ensure it scrolls all the way to the bottom when we hit the bottom\n if (visibleToIndex >= fullListLength - 1) {\n topBuffer = fullHeight - scrollboxHeight\n } else {\n // This is the actual number of rows available for the scrollbar to go up and down\n const scrollingLength = fullHeight - scrollboxHeight\n // This is the number of times the screen itself can scroll down\n const scrollableIncrements = fullListLength - visibleListSectionLength\n\n topBuffer = Math.max(\n // Never go negative, that causes errors!\n 0,\n Math.min(\n // Never have more buffer than filling in all spaces above the scrollbox\n fullHeight - scrollboxHeight,\n Math.round((visibleFromIndex / scrollableIncrements) * scrollingLength),\n ),\n )\n }\n const bottomBuffer = fullHeight - scrollboxHeight - topBuffer\n\n const backgroundChar = noColor ? BACKGROUND_CHAR : ' '\n const scrollboxChar = noColor ? SCROLLBOX_CHAR : ' '\n const bgColor = noColor ? undefined : 'gray'\n const scrollboxColor = noColor ? undefined : 'cyan'\n\n return (\n <Box flexDirection=\"column\">\n {displayArrows ? <Text>△</Text> : null}\n\n <Box width={1}>\n <Text backgroundColor={bgColor}>{backgroundChar.repeat(topBuffer)}</Text>\n </Box>\n <Box width={1}>\n <Text backgroundColor={scrollboxColor}>{scrollboxChar.repeat(scrollboxHeight)}</Text>\n </Box>\n <Box width={1}>\n <Text backgroundColor={bgColor}>{backgroundChar.repeat(bottomBuffer)}</Text>\n </Box>\n\n {displayArrows ? <Text>▽</Text> : null}\n </Box>\n )\n}\n\nexport {Scrollbar}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Scrollbar } from './Scrollbar.js';
|
|
2
|
+
import { render } from '../../testing/ui.js';
|
|
3
|
+
import { describe, expect, test } from 'vitest';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
describe('Scrollbar', async () => {
|
|
6
|
+
test('renders correctly when at the top of the list', async () => {
|
|
7
|
+
const options = {
|
|
8
|
+
containerHeight: 10,
|
|
9
|
+
visibleListSectionLength: 10,
|
|
10
|
+
fullListLength: 50,
|
|
11
|
+
visibleFromIndex: 0,
|
|
12
|
+
};
|
|
13
|
+
const { lastFrame } = render(React.createElement(Scrollbar, { ...options }));
|
|
14
|
+
// First 2 are colored in
|
|
15
|
+
expect(lastFrame()).toMatchInlineSnapshot(`
|
|
16
|
+
"\u001b[46m \u001b[49m
|
|
17
|
+
\u001b[46m \u001b[49m
|
|
18
|
+
\u001b[100m \u001b[49m
|
|
19
|
+
\u001b[100m \u001b[49m
|
|
20
|
+
\u001b[100m \u001b[49m
|
|
21
|
+
\u001b[100m \u001b[49m
|
|
22
|
+
\u001b[100m \u001b[49m
|
|
23
|
+
\u001b[100m \u001b[49m
|
|
24
|
+
\u001b[100m \u001b[49m
|
|
25
|
+
\u001b[100m \u001b[49m"
|
|
26
|
+
`);
|
|
27
|
+
});
|
|
28
|
+
test('renders correctly when in the middle of the list', async () => {
|
|
29
|
+
const options = {
|
|
30
|
+
containerHeight: 10,
|
|
31
|
+
visibleListSectionLength: 10,
|
|
32
|
+
fullListLength: 50,
|
|
33
|
+
visibleFromIndex: 20,
|
|
34
|
+
};
|
|
35
|
+
const { lastFrame } = render(React.createElement(Scrollbar, { ...options }));
|
|
36
|
+
// Scrollbar is in the middle
|
|
37
|
+
expect(lastFrame()).toMatchInlineSnapshot(`
|
|
38
|
+
"\u001b[100m \u001b[49m
|
|
39
|
+
\u001b[100m \u001b[49m
|
|
40
|
+
\u001b[100m \u001b[49m
|
|
41
|
+
\u001b[100m \u001b[49m
|
|
42
|
+
\u001b[46m \u001b[49m
|
|
43
|
+
\u001b[46m \u001b[49m
|
|
44
|
+
\u001b[100m \u001b[49m
|
|
45
|
+
\u001b[100m \u001b[49m
|
|
46
|
+
\u001b[100m \u001b[49m
|
|
47
|
+
\u001b[100m \u001b[49m"
|
|
48
|
+
`);
|
|
49
|
+
});
|
|
50
|
+
test('renders correctly when at the bottom of the list', async () => {
|
|
51
|
+
const options = {
|
|
52
|
+
containerHeight: 10,
|
|
53
|
+
visibleListSectionLength: 10,
|
|
54
|
+
fullListLength: 50,
|
|
55
|
+
visibleFromIndex: 40,
|
|
56
|
+
};
|
|
57
|
+
const { lastFrame } = render(React.createElement(Scrollbar, { ...options }));
|
|
58
|
+
// Last 2 are colored in
|
|
59
|
+
expect(lastFrame()).toMatchInlineSnapshot(`
|
|
60
|
+
"\u001b[100m \u001b[49m
|
|
61
|
+
\u001b[100m \u001b[49m
|
|
62
|
+
\u001b[100m \u001b[49m
|
|
63
|
+
\u001b[100m \u001b[49m
|
|
64
|
+
\u001b[100m \u001b[49m
|
|
65
|
+
\u001b[100m \u001b[49m
|
|
66
|
+
\u001b[100m \u001b[49m
|
|
67
|
+
\u001b[100m \u001b[49m
|
|
68
|
+
\u001b[46m \u001b[49m
|
|
69
|
+
\u001b[46m \u001b[49m"
|
|
70
|
+
`);
|
|
71
|
+
});
|
|
72
|
+
test('renders correctly in the middle of the list in no-color mode', async () => {
|
|
73
|
+
const options = {
|
|
74
|
+
containerHeight: 10,
|
|
75
|
+
visibleListSectionLength: 10,
|
|
76
|
+
fullListLength: 50,
|
|
77
|
+
visibleFromIndex: 20,
|
|
78
|
+
noColor: true,
|
|
79
|
+
};
|
|
80
|
+
const { lastFrame } = render(React.createElement(Scrollbar, { ...options }));
|
|
81
|
+
// Scrollbar is in the middle
|
|
82
|
+
expect(lastFrame()).toMatchInlineSnapshot(`
|
|
83
|
+
"△
|
|
84
|
+
│
|
|
85
|
+
│
|
|
86
|
+
│
|
|
87
|
+
║
|
|
88
|
+
║
|
|
89
|
+
│
|
|
90
|
+
│
|
|
91
|
+
│
|
|
92
|
+
▽"
|
|
93
|
+
`);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=Scrollbar.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Scrollbar.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Scrollbar.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,QAAQ,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE;IAC/B,IAAI,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,OAAO,GAAG;YACd,eAAe,EAAE,EAAE;YACnB,wBAAwB,EAAE,EAAE;YAC5B,cAAc,EAAE,EAAE;YAClB,gBAAgB,EAAE,CAAC;SACpB,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,SAAS,OAAK,OAAO,GAAI,CAAC,CAAA;QAEtD,yBAAyB;QACzB,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;KAWzC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,OAAO,GAAG;YACd,eAAe,EAAE,EAAE;YACnB,wBAAwB,EAAE,EAAE;YAC5B,cAAc,EAAE,EAAE;YAClB,gBAAgB,EAAE,EAAE;SACrB,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,SAAS,OAAK,OAAO,GAAI,CAAC,CAAA;QAEtD,6BAA6B;QAC7B,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;KAWzC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,OAAO,GAAG;YACd,eAAe,EAAE,EAAE;YACnB,wBAAwB,EAAE,EAAE;YAC5B,cAAc,EAAE,EAAE;YAClB,gBAAgB,EAAE,EAAE;SACrB,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,SAAS,OAAK,OAAO,GAAI,CAAC,CAAA;QAEtD,wBAAwB;QACxB,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;KAWzC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,OAAO,GAAG;YACd,eAAe,EAAE,EAAE;YACnB,wBAAwB,EAAE,EAAE;YAC5B,cAAc,EAAE,EAAE;YAClB,gBAAgB,EAAE,EAAE;YACpB,OAAO,EAAE,IAAI;SACd,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,SAAS,OAAK,OAAO,GAAI,CAAC,CAAA;QACtD,6BAA6B;QAC7B,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;KAWzC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {Scrollbar} from './Scrollbar.js'\nimport {render} from '../../testing/ui.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\n\ndescribe('Scrollbar', async () => {\n test('renders correctly when at the top of the list', async () => {\n const options = {\n containerHeight: 10,\n visibleListSectionLength: 10,\n fullListLength: 50,\n visibleFromIndex: 0,\n }\n\n const {lastFrame} = render(<Scrollbar {...options} />)\n\n // First 2 are colored in\n expect(lastFrame()).toMatchInlineSnapshot(`\n \"\\u001b[46m \\u001b[49m\n \\u001b[46m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\"\n `)\n })\n\n test('renders correctly when in the middle of the list', async () => {\n const options = {\n containerHeight: 10,\n visibleListSectionLength: 10,\n fullListLength: 50,\n visibleFromIndex: 20,\n }\n\n const {lastFrame} = render(<Scrollbar {...options} />)\n\n // Scrollbar is in the middle\n expect(lastFrame()).toMatchInlineSnapshot(`\n \"\\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[46m \\u001b[49m\n \\u001b[46m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\"\n `)\n })\n\n test('renders correctly when at the bottom of the list', async () => {\n const options = {\n containerHeight: 10,\n visibleListSectionLength: 10,\n fullListLength: 50,\n visibleFromIndex: 40,\n }\n\n const {lastFrame} = render(<Scrollbar {...options} />)\n\n // Last 2 are colored in\n expect(lastFrame()).toMatchInlineSnapshot(`\n \"\\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[100m \\u001b[49m\n \\u001b[46m \\u001b[49m\n \\u001b[46m \\u001b[49m\"\n `)\n })\n\n test('renders correctly in the middle of the list in no-color mode', async () => {\n const options = {\n containerHeight: 10,\n visibleListSectionLength: 10,\n fullListLength: 50,\n visibleFromIndex: 20,\n noColor: true,\n }\n\n const {lastFrame} = render(<Scrollbar {...options} />)\n // Scrollbar is in the middle\n expect(lastFrame()).toMatchInlineSnapshot(`\n \"△\n │\n │\n │\n ║\n ║\n │\n │\n │\n ▽\"\n `)\n })\n})\n"]}
|
|
@@ -5,6 +5,7 @@ declare module 'react' {
|
|
|
5
5
|
}
|
|
6
6
|
export interface SelectInputProps<T> {
|
|
7
7
|
items: Item<T>[];
|
|
8
|
+
initialItems?: Item<T>[];
|
|
8
9
|
onChange?: (item: Item<T> | undefined) => void;
|
|
9
10
|
enableShortcuts?: boolean;
|
|
10
11
|
focus?: boolean;
|
|
@@ -15,10 +16,9 @@ export interface SelectInputProps<T> {
|
|
|
15
16
|
errorMessage?: string;
|
|
16
17
|
hasMorePages?: boolean;
|
|
17
18
|
morePagesMessage?: string;
|
|
18
|
-
|
|
19
|
-
limit?: number;
|
|
20
|
-
submitWithShortcuts?: boolean;
|
|
19
|
+
availableLines?: number;
|
|
21
20
|
onSubmit?: (item: Item<T>) => void;
|
|
21
|
+
inputFixedAreaRef?: React.RefObject<DOMElement>;
|
|
22
22
|
}
|
|
23
23
|
export interface Item<T> {
|
|
24
24
|
label: string;
|
|
@@ -28,7 +28,4 @@ export interface Item<T> {
|
|
|
28
28
|
helperText?: string;
|
|
29
29
|
disabled?: boolean;
|
|
30
30
|
}
|
|
31
|
-
export interface ItemWithKey<T> extends Item<T> {
|
|
32
|
-
key: string;
|
|
33
|
-
}
|
|
34
31
|
export declare const SelectInput: <T>(props: SelectInputProps<T> & React.RefAttributes<DOMElement>) => JSX.Element | null;
|