feat: remove the disable state from chat input box (#1341)

This commit is contained in:
kang-square
2025-02-27 05:23:55 -05:00
committed by GitHub
parent b268316524
commit 234d55ea37
2 changed files with 26 additions and 30 deletions

View File

@@ -193,12 +193,7 @@ export default function ChatView({ setView }: { setView: (view: View) => void })
<div className="relative"> <div className="relative">
{isLoading && <LoadingGoose />} {isLoading && <LoadingGoose />}
<Input <Input handleSubmit={handleSubmit} isLoading={isLoading} onStop={onStopGoose} />
handleSubmit={handleSubmit}
disabled={isLoading}
isLoading={isLoading}
onStop={onStopGoose}
/>
<BottomMenu hasMessages={hasMessages} setView={setView} /> <BottomMenu hasMessages={hasMessages} setView={setView} />
</div> </div>
</Card> </Card>

View File

@@ -5,27 +5,21 @@ import { Attach, Send } from './icons';
interface InputProps { interface InputProps {
handleSubmit: (e: React.FormEvent) => void; handleSubmit: (e: React.FormEvent) => void;
disabled?: boolean;
isLoading?: boolean; isLoading?: boolean;
onStop?: () => void; onStop?: () => void;
} }
export default function Input({ export default function Input({ handleSubmit, isLoading = false, onStop }: InputProps) {
handleSubmit,
disabled = false,
isLoading = false,
onStop,
}: InputProps) {
const [value, setValue] = useState(''); const [value, setValue] = useState('');
// State to track if the IME is composing (i.e., in the middle of Japanese IME input) // State to track if the IME is composing (i.e., in the middle of Japanese IME input)
const [isComposing, setIsComposing] = useState(false); const [isComposing, setIsComposing] = useState(false);
const textAreaRef = useRef<HTMLTextAreaElement>(null); const textAreaRef = useRef<HTMLTextAreaElement>(null);
useEffect(() => { useEffect(() => {
if (textAreaRef.current && !disabled) { if (textAreaRef.current) {
textAreaRef.current.focus(); textAreaRef.current.focus();
} }
}, [disabled, value]); }, [value]);
const useAutosizeTextArea = (textAreaRef: HTMLTextAreaElement | null, value: string) => { const useAutosizeTextArea = (textAreaRef: HTMLTextAreaElement | null, value: string) => {
useEffect(() => { useEffect(() => {
@@ -57,10 +51,19 @@ export default function Input({
}; };
const handleKeyDown = (evt: React.KeyboardEvent<HTMLTextAreaElement>) => { const handleKeyDown = (evt: React.KeyboardEvent<HTMLTextAreaElement>) => {
// Only trigger submit on Enter if not composing (IME input in progress) and shift is not pressed if (evt.key === 'Enter') {
if (evt.key === 'Enter' && !evt.shiftKey && !isComposing) { // should not trigger submit on Enter if it's composing (IME input in progress) or shift is pressed
if (evt.shiftKey || isComposing) {
// Allow line break for Shift+Enter or during IME composition
return;
}
// Prevent default Enter behavior when loading or when not loading but has content
// So it won't trigger a new line
evt.preventDefault(); evt.preventDefault();
if (value.trim()) {
// Only submit if not loading and has content
if (!isLoading && value.trim()) {
handleSubmit(new CustomEvent('submit', { detail: { value } })); handleSubmit(new CustomEvent('submit', { detail: { value } }));
setValue(''); setValue('');
} }
@@ -69,7 +72,7 @@ export default function Input({
const onFormSubmit = (e: React.FormEvent) => { const onFormSubmit = (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
if (value.trim()) { if (value.trim() && !isLoading) {
handleSubmit(new CustomEvent('submit', { detail: { value } })); handleSubmit(new CustomEvent('submit', { detail: { value } }));
setValue(''); setValue('');
} }
@@ -97,7 +100,6 @@ export default function Input({
onCompositionStart={handleCompositionStart} onCompositionStart={handleCompositionStart}
onCompositionEnd={handleCompositionEnd} onCompositionEnd={handleCompositionEnd}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
disabled={disabled}
ref={textAreaRef} ref={textAreaRef}
rows={1} rows={1}
style={{ style={{
@@ -105,19 +107,14 @@ export default function Input({
maxHeight: `${maxHeight}px`, maxHeight: `${maxHeight}px`,
overflowY: 'auto', overflowY: 'auto',
}} }}
className={`w-full outline-none border-none focus:ring-0 bg-transparent p-0 text-base resize-none text-textStandard ${ className="w-full outline-none border-none focus:ring-0 bg-transparent p-0 text-base resize-none text-textStandard"
disabled ? 'cursor-not-allowed opacity-50' : ''
}`}
/> />
<Button <Button
type="button" type="button"
size="icon" size="icon"
variant="ghost" variant="ghost"
onClick={handleFileSelect} onClick={handleFileSelect}
disabled={disabled} className="absolute right-[40px] top-1/2 -translate-y-1/2 text-textSubtle hover:text-textStandard"
className={`absolute right-[40px] top-1/2 -translate-y-1/2 text-textSubtle hover:text-textStandard ${
disabled ? 'text-textSubtle cursor-not-allowed' : ''
}`}
> >
<Attach /> <Attach />
</Button> </Button>
@@ -126,7 +123,11 @@ export default function Input({
type="button" type="button"
size="icon" size="icon"
variant="ghost" variant="ghost"
onClick={onStop} onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onStop();
}}
className="absolute right-2 top-1/2 -translate-y-1/2 [&_svg]:size-5 text-textSubtle hover:text-textStandard" className="absolute right-2 top-1/2 -translate-y-1/2 [&_svg]:size-5 text-textSubtle hover:text-textStandard"
> >
<Stop size={24} /> <Stop size={24} />
@@ -136,9 +137,9 @@ export default function Input({
type="submit" type="submit"
size="icon" size="icon"
variant="ghost" variant="ghost"
disabled={disabled || !value.trim()} disabled={!value.trim()}
className={`absolute right-2 top-1/2 -translate-y-1/2 text-textSubtle hover:text-textStandard ${ className={`absolute right-2 top-1/2 -translate-y-1/2 text-textSubtle hover:text-textStandard ${
disabled || !value.trim() ? 'text-textSubtle cursor-not-allowed' : '' !value.trim() ? 'text-textSubtle cursor-not-allowed' : ''
}`} }`}
> >
<Send /> <Send />