diff --git a/viewer/src/client/components/chat/ChatInput.jsx b/viewer/src/client/components/chat/ChatInput.jsx index a808030..2ab9a77 100644 --- a/viewer/src/client/components/chat/ChatInput.jsx +++ b/viewer/src/client/components/chat/ChatInput.jsx @@ -19,6 +19,8 @@ import { blobToAttachment, imageFilesFromDataTransfer, MAX_ATTACHMENTS } from ". export { buildSendValue }; +const MAX_TEXTAREA_HEIGHT = 192; // tailwind max-h-48 + function ChatInput({ className }, ref) { const [value, setValue] = useState(""); const turnInProgress = useChatStore((state) => state.turnInProgress); @@ -165,6 +167,15 @@ function ChatInput({ className }, ref) { window.requestAnimationFrame?.(() => textareaRef.current?.focus()); }, []); + const adjustTextareaHeight = useCallback(() => { + const textarea = textareaRef.current; + if (!textarea) return; + textarea.style.height = "0px"; + const nextHeight = Math.min(textarea.scrollHeight, MAX_TEXTAREA_HEIGHT); + textarea.style.height = `${nextHeight}px`; + textarea.style.overflowY = textarea.scrollHeight > MAX_TEXTAREA_HEIGHT ? "auto" : "hidden"; + }, []); + useImperativeHandle(ref, () => ({ focus(options) { textareaRef.current?.focus(options); @@ -186,6 +197,10 @@ function ChatInput({ className }, ref) { const hasStrip = pendingTokens.length > 0 || pendingAttachments.length > 0; + useEffect(() => { + adjustTextareaHeight(); + }, [value, hasStrip, adjustTextareaHeight]); + return (
diff --git a/viewer/src/client/components/chat/Markdown.jsx b/viewer/src/client/components/chat/Markdown.jsx index c4c811b..82b6597 100644 --- a/viewer/src/client/components/chat/Markdown.jsx +++ b/viewer/src/client/components/chat/Markdown.jsx @@ -26,6 +26,39 @@ const COMPONENTS = { {children} ), + table: ({ children }) => ( +