UNPKG

aura-ai

Version:

AI-powered marketing strategist CLI tool for developers

146 lines (135 loc) 4.32 kB
import React, { useState, useEffect } from 'react' import { Box, Newline, Spacer, Text, useInput } from 'ink' import TextInput from 'ink-text-input' /** * Command input component with autocomplete suggestions like Claude Code */ const CommandInput = ({ value, onChange, onSubmit, placeholder = 'Type a command or message...', commands = [], exitPrompt = false, onClearInput = null, onExit = null, }) => { const [suggestions, setSuggestions] = useState([]) const [showSuggestions, setShowSuggestions] = useState(false) const [selectedIndex, setSelectedIndex] = useState(0) // Handle keyboard input for autocomplete and Ctrl+C useInput((input, key) => { // Handle Ctrl+C if (key.ctrl && input === 'c') { if (value.length > 0 && onClearInput) { onClearInput() return } if (onExit) { onExit() return } } // Handle autocomplete when suggestions are shown if (showSuggestions && suggestions.length > 0) { if (key.upArrow) { setSelectedIndex(prev => Math.max(0, prev - 1)) return } if (key.downArrow) { setSelectedIndex(prev => Math.min(suggestions.length - 1, prev + 1)) return } if (key.tab) { // Auto-complete with selected suggestion const selectedCmd = suggestions[selectedIndex] if (selectedCmd) { onChange(`/${selectedCmd.name}`) setShowSuggestions(false) } return } } }) // Update suggestions when input value changes useEffect(() => { if (value.startsWith('/')) { const query = value.substring(1).toLowerCase() const filteredCommands = commands.filter( cmd => cmd.name.toLowerCase().includes(query) || cmd.description.toLowerCase().includes(query) ) setSuggestions(filteredCommands) setShowSuggestions(filteredCommands.length > 0) setSelectedIndex(0) // Reset selection } else { setSuggestions([]) setShowSuggestions(false) setSelectedIndex(0) } }, [value, commands]) const handleSubmit = inputValue => { // If there are suggestions showing and user presses Enter, // auto-complete with the selected suggestion if (showSuggestions && suggestions.length > 0) { const selectedCmd = suggestions[selectedIndex] if (selectedCmd) { setShowSuggestions(false) onSubmit(`/${selectedCmd.name}`) return } } // Normal submit setShowSuggestions(false) onSubmit(inputValue) } return ( <Box flexDirection='column' width='100%'> {/* Input field */} <Box paddingX={1} paddingY={0} borderColor='whiteBright' borderStyle='round' width={'100%'}> <Text color='blue'>{'> '}</Text> <TextInput value={value} onChange={onChange} onSubmit={handleSubmit} placeholder={placeholder} focus={true} /> </Box> {/* Autocomplete suggestions */} {showSuggestions && suggestions.length > 0 && ( <Box flexDirection='column' marginTop={1} marginBottom={1} paddingLeft={2}> {suggestions.map((cmd, index) => ( <Box flexDirection='row' flexWrap='wrap' key={index}> <Box width={16}> <Text color={index === selectedIndex ? 'blueBright' : 'gray'}> <Text color={index === selectedIndex ? 'blueBright' : 'gray'}>/{cmd.name}</Text> </Text> </Box> <Box paddingLeft={3}> <Text color={index === selectedIndex ? 'blueBright' : 'gray'}> {cmd.description} </Text> </Box> </Box> ))} </Box> )} {/* Help text with integrated Ctrl+C status */} <Box width='100%'> <Text dimColor> {exitPrompt ? ( <Text color='yellow'>Press Ctrl+C again to exit</Text> ) : value.startsWith('/') ? ( <>Press Enter to continue</> ) : ( <>Type / for commands</> )} </Text> <Spacer /> <Text dimColor>{!exitPrompt && <> Ctrl+C to {value ? 'clear input' : 'exit'}</>}</Text> </Box> </Box> ) } export default CommandInput