UNPKG

askeroo

Version:

A modern CLI prompt library with flow control, history navigation, and conditional prompts

163 lines 7.83 kB
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useEffect } from "react"; import { Text, Box, useInput, Newline } from "ink"; import { createPrompt } from "../../core/registry.js"; import { useFieldReset } from "../../hooks/use-auto-submit.js"; import { TextInput } from "../../components/TextInput.js"; // Core text input plugin export const text = createPrompt({ type: "text", // autoSubmit: false (default) - Requires user interaction component: ({ node, options, events }) => { const initialValue = options.initialValue || ""; const [value, setValue] = useState(initialValue); const [submitted, setSubmitted] = useState(false); const [validationError, setValidationError] = useState(null); // Reset state when field becomes active const disabled = node.state === "disabled"; useFieldReset(disabled, submitted, setSubmitted); useEffect(() => { if (!disabled) { const initial = options.initialValue || ""; setValue(initial); } }, [options.initialValue, disabled]); // Validation helper const runValidation = async (val) => { if (!events.onValidate || node.state !== "active") { setValidationError(null); return true; } try { const result = await events.onValidate(val); setValidationError(result); return result === null; } catch { setValidationError("Validation error occurred"); return false; } }; // Hint management useEffect(() => { if (!events.onHintChange) return; // Only show hint if there's back navigation available const hasHint = node.state === "active" && !node.isFirstRootPrompt && node.allowBack; events.onHintChange(hasHint ? (_jsxs(_Fragment, { children: [_jsx(Newline, {}), _jsx(Text, { color: "yellow", children: "escape" }), " go back"] })) : null); }, [ node.state, node.isFirstRootPrompt, node.allowBack, events.onHintChange, ]); useInput(async (input, key) => { if (submitted || node.state !== "active") return; // Static group navigation if (node.flow === "static" && node.enableArrowNavigation) { if (key.downArrow && !node.isLastInGroup) { if (!(await runValidation(value))) return; setSubmitted(true); // Call user's onSubmit callback if provided and use return value if any let finalValue = value; if (options.onSubmit) { const result = options.onSubmit(value); if (result !== undefined) { finalValue = result; } } events.onSubmit?.(finalValue); return; } if (key.upArrow && !node.isFirstInGroup) { if (!(await runValidation(value))) return; setSubmitted(true); // Call user's onSubmit callback if provided and use return value if any let finalValue = value; if (options.onSubmit) { const result = options.onSubmit(value); if (result !== undefined) { finalValue = result; } } events.onSubmit?.({ __preserveAndBack: true, value: finalValue, }); return; } if (key.downArrow || key.upArrow) return; } // Escape handling if (key.escape) { if (node.flow === "static") { if (node.enableArrowNavigation && !node.isFirstInGroup) { if (!(await runValidation(value))) return; setSubmitted(true); // Call user's onSubmit callback if provided and use return value if any let finalValue = value; if (options.onSubmit) { const result = options.onSubmit(value); if (result !== undefined) { finalValue = result; } } events.onSubmit?.({ __preserveAndBack: true, value: finalValue, }); } else if (node.enableArrowNavigation && node.isFirstInGroup) { setSubmitted(true); // Note: For __clearGroupAndBack, we don't call user's onSubmit // as this is a special navigation case events.onSubmit?.({ __clearGroupAndBack: true }); } else if (node.allowBack && events.onBack) { events.onBack(); } } else if (node.allowBack && events.onBack) { events.onBack(); } return; } }, { isActive: node.state === "active" && !submitted }); const handleSubmit = async (val) => { if (!(await runValidation(val))) return; setSubmitted(true); // Call user's onSubmit callback if provided and use return value if any let finalValue = val; if (options.onSubmit) { const result = options.onSubmit(val); if (result !== undefined) { finalValue = result; } } events.onSubmit?.(finalValue); }; const handleEscape = () => { if (node.allowBack && events.onBack && node.flow !== "static") { events.onBack(); } }; if (node.state === "completed") { return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: options.label }), _jsx(Text, { color: "blue", children: node.completedValue || value })] })); } if (node.state === "disabled") { return (_jsxs(Box, { gap: 1, children: [_jsx(Box, { width: 14, children: _jsx(Text, { dimColor: true, children: options.shortLabel || options.label }) }), _jsx(Text, { dimColor: true, color: "gray", children: "..." })] })); } return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: node.flow === "static" ? "row" : "column", gap: node.flow === "static" ? 1 : 0, marginBottom: node.flow === "static" && !node.isLastInGroup ? 1 : 0, children: [_jsx(Box, { width: node.flow === "static" ? 14 : undefined, children: _jsx(Text, { children: options.label }) }), _jsx(TextInput, { value: value, onChange: setValue, onSubmit: handleSubmit, isActive: node.state === "active" && !submitted, color: "cyan", onEscape: handleEscape, disableArrowKeys: node.flow === "static" && node.enableArrowNavigation })] }), validationError && (_jsx(Box, { children: _jsx(Text, { color: "red", children: validationError }) }))] })); }, }); //# sourceMappingURL=index.js.map