@shopify/cli-kit
Version:
A set of utilities, interfaces, and models that are common across all the platform features
80 lines • 4.24 kB
JavaScript
import { TextInput } from './TextInput.js';
import { TokenizedText } from './TokenizedText.js';
import { handleCtrlC } from '../../ui.js';
import useLayout from '../hooks/use-layout.js';
import { messageWithPunctuation } from '../utilities.js';
import useAbortSignal from '../hooks/use-abort-signal.js';
import usePrompt, { PromptState } from '../hooks/use-prompt.js';
import React, { useCallback, useEffect, useState } from 'react';
import { Box, useApp, useInput, Text } from 'ink';
import figures from 'figures';
const TextPrompt = ({ message, onSubmit, validate, defaultValue = '', password = false, allowEmpty = false, emptyDisplayedValue = '(empty)', abortSignal, preview, initialAnswer = '', }) => {
if (password && defaultValue) {
throw new Error("Can't use defaultValue with password");
}
const validateAnswer = useCallback((value) => {
if (validate) {
return validate(value);
}
if (value.length === 0 && !allowEmpty)
return 'Type an answer to the prompt.';
return undefined;
}, [allowEmpty, validate]);
const { oneThird } = useLayout();
const { promptState, setPromptState, answer, setAnswer } = usePrompt({
initialAnswer,
});
const answerOrDefault = answer.length > 0 ? answer : defaultValue;
const displayEmptyValue = answerOrDefault === '';
const displayedAnswer = displayEmptyValue ? emptyDisplayedValue : answerOrDefault;
const { exit: unmountInk } = useApp();
const [error, setError] = useState(undefined);
const color = promptState === PromptState.Error ? 'red' : 'cyan';
const underline = new Array(oneThird - 3).fill('▔');
const { isAborted } = useAbortSignal(abortSignal);
useInput((input, key) => {
handleCtrlC(input, key);
if (key.return) {
const error = validateAnswer(answerOrDefault);
if (error) {
setPromptState(PromptState.Error);
setError(error);
}
else {
setPromptState(PromptState.Submitted);
}
}
});
useEffect(() => {
if (promptState === PromptState.Submitted) {
onSubmit(answerOrDefault);
unmountInk();
}
}, [answerOrDefault, onSubmit, promptState, unmountInk]);
return isAborted ? null : (React.createElement(Box, { flexDirection: "column", marginBottom: 1, width: oneThird },
React.createElement(Box, null,
React.createElement(Box, { marginRight: 2 },
React.createElement(Text, null, "?")),
React.createElement(TokenizedText, { item: messageWithPunctuation(message) })),
promptState === PromptState.Submitted ? (React.createElement(Box, null,
React.createElement(Box, { width: 3 },
React.createElement(Text, { color: "cyan" }, figures.tick)),
React.createElement(Box, { flexGrow: 1 },
React.createElement(Text, { color: "cyan", dimColor: displayEmptyValue }, password ? '*'.repeat(answer.length) : displayedAnswer)))) : (React.createElement(Box, { flexDirection: "column" },
React.createElement(Box, null,
React.createElement(Box, { marginRight: 2 },
React.createElement(Text, { color: color }, `>`)),
React.createElement(Box, { flexGrow: 1 },
React.createElement(TextInput, { value: answer, onChange: (answer) => {
setAnswer(answer);
setPromptState(PromptState.Idle);
}, defaultValue: defaultValue, color: color, password: password }))),
React.createElement(Box, { marginLeft: 3 },
React.createElement(Text, { color: color }, underline)),
promptState === PromptState.Error ? (React.createElement(Box, { marginLeft: 3 },
React.createElement(Text, { color: color }, error))) : null,
promptState !== PromptState.Error && preview ? (React.createElement(Box, { marginLeft: 3 },
React.createElement(TokenizedText, { item: preview(answerOrDefault) }))) : null))));
};
export { TextPrompt };
//# sourceMappingURL=TextPrompt.js.map