diff --git a/web/chat/chat-input-text-area.react.js b/web/chat/chat-input-text-area.react.js index 7b7857f9f..5fc3ee7fe 100644 --- a/web/chat/chat-input-text-area.react.js +++ b/web/chat/chat-input-text-area.react.js @@ -1,107 +1,114 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import css from './chat-input-bar.css'; type Props = { +send?: () => mixed, +escape?: () => void, +focus: boolean, +currentText: string, +setCurrentText: (text: string) => void, +onChangePosition: () => void, }; const ChatInputTextArea: React.ComponentType = React.memo( function ChatInputTextArea(props: Props) { const { currentText, focus, escape, send, setCurrentText, onChangePosition, } = props; const textareaRef = React.useRef(null); const focusAndUpdateText = React.useCallback(() => { if (!focus) { return; } // We need to call focus() first on Safari, otherwise the cursor // ends up at the start instead of the end for some reason const textarea = textareaRef.current; invariant(textarea, 'textarea should be set'); textarea.focus(); // We reset the textarea to an empty string at the start so that // the cursor always ends up at the end, even if the text doesn't // actually change textarea.value = ''; if (currentText) { textarea.value = currentText; } // The above strategies make sure the cursor is at the end, // but we also need to make sure that we're scrolled to the bottom textarea.scrollTop = textarea.scrollHeight; }, [currentText, focus]); const updateHeight = React.useCallback(() => { const textarea = textareaRef.current; if (textarea) { textarea.style.height = 'auto'; const newHeight = Math.min(textarea.scrollHeight, 150); textarea.style.height = `${newHeight}px`; } onChangePosition(); }, [onChangePosition]); React.useEffect(() => { - updateHeight(); focusAndUpdateText(); // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + React.useEffect(() => { + updateHeight(); + // We want to update the height when the text changes. We can't include + // updateHeight in the dep list because it causes a stack overflow... see + // comments on D8035 for more details + // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentText]); const onKeyDown = (event: SyntheticKeyboardEvent) => { if (event.key === 'Escape') { event.preventDefault(); if (!escape) { return; } escape(); } else if (event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); if (!send) { return; } send(); } }; const onChangeMessageText = ( event: SyntheticEvent, ) => { setCurrentText(event.currentTarget.value); updateHeight(); }; return (