From 706922f8b14f8790db159fbafe9c23eb9fa26feb Mon Sep 17 00:00:00 2001 From: paulclindo Date: Wed, 30 Oct 2024 17:30:05 -0500 Subject: [PATCH 1/5] fix: textarea input --- .../components/chat/conversation-footer.tsx | 13 ++- .../src/components/chat/chat-input-area.tsx | 83 +++++++++++-------- .../src/components/chat/chat-input.tsx | 6 +- .../shinkai-ui/src/hooks/use-combined-refs.ts | 22 +++++ 4 files changed, 82 insertions(+), 42 deletions(-) create mode 100644 libs/shinkai-ui/src/hooks/use-combined-refs.ts diff --git a/apps/shinkai-desktop/src/components/chat/conversation-footer.tsx b/apps/shinkai-desktop/src/components/chat/conversation-footer.tsx index b6ae2fe25..6ca0d2fee 100644 --- a/apps/shinkai-desktop/src/components/chat/conversation-footer.tsx +++ b/apps/shinkai-desktop/src/components/chat/conversation-footer.tsx @@ -56,7 +56,7 @@ import { cn } from '@shinkai_network/shinkai-ui/utils'; import { partial } from 'filesize'; import { AnimatePresence, motion } from 'framer-motion'; import { Paperclip, X, XIcon } from 'lucide-react'; -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { useDropzone } from 'react-dropzone'; import { useForm, useWatch } from 'react-hook-form'; import { useLocation, useNavigate, useParams } from 'react-router-dom'; @@ -571,6 +571,7 @@ function ConversationChatFooter({ inboxId }: { inboxId: string }) { (state) => state.setWorkflowSelected, ); + const textareaRef = useRef(null); const auth = useAuth((state) => state.auth); const { captureAnalyticEvent } = useAnalytics(); @@ -732,6 +733,11 @@ function ConversationChatFooter({ inboxId }: { inboxId: string }) { useEffect(() => { if (promptSelected) { chatForm.setValue('message', promptSelected.prompt); + setTimeout(() => { + if (!textareaRef.current) return; + textareaRef.current.scrollTop = textareaRef.current.scrollHeight; + textareaRef.current.focus(); + }, 10); } }, [chatForm, promptSelected]); @@ -744,9 +750,7 @@ function ConversationChatFooter({ inboxId }: { inboxId: string }) {
{workflowSelected && ( diff --git a/libs/shinkai-ui/src/components/chat/chat-input-area.tsx b/libs/shinkai-ui/src/components/chat/chat-input-area.tsx index 572060342..69f55e3a4 100644 --- a/libs/shinkai-ui/src/components/chat/chat-input-area.tsx +++ b/libs/shinkai-ui/src/components/chat/chat-input-area.tsx @@ -1,19 +1,9 @@ import * as React from 'react'; -import { useRef } from 'react'; +import { useCombinedRefs } from '../../hooks/use-combined-refs'; import { ChatInput } from './chat-input'; -export const ChatInputArea = ({ - value, - onChange, - autoFocus, - onSubmit, - disabled, - isLoading, - placeholder, - topAddons, - bottomAddons, -}: { +type ChatInputAreaProps = { value: string; onChange: (value: string) => void; onSubmit: () => void; @@ -23,27 +13,50 @@ export const ChatInputArea = ({ placeholder?: string; topAddons?: React.ReactNode; bottomAddons?: React.ReactNode; -}) => { - const chatInputAreaRef = useRef(null); - return ( -
- {topAddons} -
chatInputAreaRef?.current?.focus()} - > - onChange(e.target.value)} - onSend={onSubmit} - placeholder={placeholder ?? 'Send a message'} - ref={chatInputAreaRef} - value={value} - /> - {bottomAddons} -
-
- ); }; + +export const ChatInputArea = React.forwardRef< + HTMLTextAreaElement, + ChatInputAreaProps +>( + ( + { + value, + onChange, + autoFocus, + onSubmit, + disabled, + isLoading, + placeholder, + topAddons, + bottomAddons, + }, + ref, + ) => { + const textareaRef = useCombinedRefs(ref); + + return ( +
+ {topAddons} +
textareaRef?.current?.focus()} + > + onChange(e.target.value)} + onSend={onSubmit} + placeholder={placeholder ?? 'Send a message'} + ref={textareaRef} + value={value} + /> + {bottomAddons} +
+
+ ); + }, +); + +ChatInputArea.displayName = 'ChatInputArea'; diff --git a/libs/shinkai-ui/src/components/chat/chat-input.tsx b/libs/shinkai-ui/src/components/chat/chat-input.tsx index 637d10919..fcda16cf1 100644 --- a/libs/shinkai-ui/src/components/chat/chat-input.tsx +++ b/libs/shinkai-ui/src/components/chat/chat-input.tsx @@ -9,6 +9,7 @@ export interface ChatInputProps export const useAutoResizeTextarea = ( ref: React.ForwardedRef, + value: string | number | readonly string[] | undefined, autoResize = true, //later to unify ) => { const textAreaRef = React.useRef(null); @@ -30,16 +31,15 @@ export const useAutoResizeTextarea = ( ref?.addEventListener('input', updateTextareaHeight); return () => ref?.removeEventListener('input', updateTextareaHeight); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [value]); return { textAreaRef }; }; const ChatInputBase = React.forwardRef( ({ className, onSend, ...props }, ref) => { - const { textAreaRef } = useAutoResizeTextarea(ref); + const { textAreaRef } = useAutoResizeTextarea(ref, props.value); return (