UNPKG

aura-ai

Version:

AI-powered marketing strategist CLI tool for developers

154 lines (143 loc) 4.24 kB
import React, { useState, useEffect, useRef } from 'react' import { Box, Text, useInput, Newline } from 'ink' import TextInput from 'ink-text-input' import SelectInput from 'ink-select-input' /** * Simplified composite input component - show menu OR text input, not both */ const CompositeInput = ({ options = [], onSubmit, placeholder = 'Type your answer...', initialValue = '', onBack = null, isReview = false, onPrevious = null, showTypeYourAnswer = true, directSubmitValues = [], }) => { const [mode, setMode] = useState(options.length > 0 ? 'select' : 'text') const [inputValue, setInputValue] = useState('') const [exitPrompt, setExitPrompt] = useState(false) const lastCtrlC = useRef(0) // Handle Ctrl+C to exit init and return to main menu useInput((input, key) => { if (key.ctrl && input === 'c') { const now = Date.now() if (now - lastCtrlC.current < 2000) { // Double Ctrl+C within 2 seconds - exit to main menu if (onBack) onBack() } else { setExitPrompt(true) lastCtrlC.current = now setTimeout(() => { setExitPrompt(false) }, 2000) } } }) // Reset when options or initial value changes useEffect(() => { setMode(options.length > 0 ? 'select' : 'text') setInputValue(initialValue) setExitPrompt(false) }, [options, initialValue]) // Prepare select items with optional "Type your answer..." as last option const selectItems = options.length > 0 ? [ ...options.map(opt => ({ label: opt.label, value: opt.value, })), ...(showTypeYourAnswer ? [ { label: 'Type your answer...', value: '__custom_input__', }, ] : []), ] : [] // Handle selection from menu const handleSelect = item => { if (item.value === '__custom_input__') { // For "Type your answer..." option, switch to text mode setMode('text') setInputValue('') } else if (directSubmitValues.includes(item.value)) { // For direct submit values, submit immediately without text mode onSubmit(item.value) } else { // For other options, switch to text mode and pre-fill setMode('text') setInputValue(item.label) } } // Handle text input submission const handleTextSubmit = value => { if (value.trim()) { // Handle /back command to go to previous question if (value.toLowerCase() === '/back' && !isReview && onPrevious) { onPrevious() return } onSubmit(value) } } return ( <Box flexDirection='column'> {/* Show either select menu or text input */} <Box flexDirection='column'> {mode === 'select' && options.length > 0 ? ( <Box paddingX={1} paddingY={0} borderColor='whiteBright' borderStyle='round' width={'100%'} > <SelectInput items={selectItems} onSelect={handleSelect} /> </Box> ) : ( <Box paddingX={1} paddingY={0} borderColor='whiteBright' borderStyle='round' width={'100%'} > <Text color='blue'>{'> '}</Text> <TextInput value={inputValue} onChange={setInputValue} onSubmit={handleTextSubmit} placeholder={placeholder} focus={true} /> </Box> )} </Box> {/* Help text */} <Box marginTop={1}> <Text dimColor fontSize={12}> {mode === 'select' ? ( <>Use ↑↓ to navigate, Enter to select</> ) : isReview ? ( <>Use /1, /2, etc. to jump to specific questions</> ) : ( <>Use /back to go to previous question</> )} </Text> </Box> {/* Exit prompt */} {exitPrompt && ( <Box marginTop={1}> <Text color='yellow'>Press Ctrl+C again to return to main menu</Text> </Box> )} </Box> ) } export default CompositeInput