Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions ui/desktop/src/components/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,7 @@ export default function ChatView({ setView }: { setView: (view: View) => void })

<div className="relative">
{isLoading && <LoadingGoose />}
<Input
handleSubmit={handleSubmit}
disabled={isLoading}
isLoading={isLoading}
onStop={onStopGoose}
/>
<Input handleSubmit={handleSubmit} isLoading={isLoading} onStop={onStopGoose} />
<BottomMenu hasMessages={hasMessages} setView={setView} />
</div>
</Card>
Expand Down
49 changes: 25 additions & 24 deletions ui/desktop/src/components/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,21 @@ import { Attach, Send } from './icons';

interface InputProps {
handleSubmit: (e: React.FormEvent) => void;
disabled?: boolean;
isLoading?: boolean;
onStop?: () => void;
}

export default function Input({
handleSubmit,
disabled = false,
isLoading = false,
onStop,
}: InputProps) {
export default function Input({ handleSubmit, isLoading = false, onStop }: InputProps) {
const [value, setValue] = useState('');
// State to track if the IME is composing (i.e., in the middle of Japanese IME input)
const [isComposing, setIsComposing] = useState(false);
const textAreaRef = useRef<HTMLTextAreaElement>(null);

useEffect(() => {
if (textAreaRef.current && !disabled) {
if (textAreaRef.current) {
textAreaRef.current.focus();
}
}, [disabled, value]);
}, [value]);

const useAutosizeTextArea = (textAreaRef: HTMLTextAreaElement | null, value: string) => {
useEffect(() => {
Expand Down Expand Up @@ -57,10 +51,19 @@ export default function Input({
};

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' && !evt.shiftKey && !isComposing) {
if (evt.key === 'Enter') {
// 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();
if (value.trim()) {

// Only submit if not loading and has content
if (!isLoading && value.trim()) {
handleSubmit(new CustomEvent('submit', { detail: { value } }));
setValue('');
}
Expand All @@ -69,7 +72,7 @@ export default function Input({

const onFormSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (value.trim()) {
if (value.trim() && !isLoading) {
handleSubmit(new CustomEvent('submit', { detail: { value } }));
setValue('');
}
Expand Down Expand Up @@ -97,27 +100,21 @@ export default function Input({
onCompositionStart={handleCompositionStart}
onCompositionEnd={handleCompositionEnd}
onKeyDown={handleKeyDown}
disabled={disabled}
ref={textAreaRef}
rows={1}
style={{
minHeight: `${minHeight}px`,
maxHeight: `${maxHeight}px`,
overflowY: 'auto',
}}
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' : ''
}`}
className="w-full outline-none border-none focus:ring-0 bg-transparent p-0 text-base resize-none text-textStandard"
/>
<Button
type="button"
size="icon"
variant="ghost"
onClick={handleFileSelect}
disabled={disabled}
className={`absolute right-[40px] top-1/2 -translate-y-1/2 text-textSubtle hover:text-textStandard ${
disabled ? 'text-textSubtle cursor-not-allowed' : ''
}`}
className="absolute right-[40px] top-1/2 -translate-y-1/2 text-textSubtle hover:text-textStandard"
>
<Attach />
</Button>
Expand All @@ -126,7 +123,11 @@ export default function Input({
type="button"
size="icon"
variant="ghost"
onClick={onStop}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add preventDefault and stopPropagation here, otherwise it triggers a bug when Goose is generating, and there is text in the input box, and you click on the stop button, the text is submitted.
I guess it's because when we clicks on the stop button, the isLoading changes from true to false, and it renders the submit button. When the click event bubble up, its parent element is the form, so it triggers the form submit.

onStop();
}}
className="absolute right-2 top-1/2 -translate-y-1/2 [&_svg]:size-5 text-textSubtle hover:text-textStandard"
>
<Stop size={24} />
Expand All @@ -136,9 +137,9 @@ export default function Input({
type="submit"
size="icon"
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 ${
disabled || !value.trim() ? 'text-textSubtle cursor-not-allowed' : ''
!value.trim() ? 'text-textSubtle cursor-not-allowed' : ''
}`}
>
<Send />
Expand Down
Loading