UNPKG

@shopify/cli-kit

Version:

A set of utilities, interfaces, and models that are common across all the platform features

80 lines 4.24 kB
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