From 3a88a60e23b0402159189b4c700dae4c2c7f4a57 Mon Sep 17 00:00:00 2001 From: Tim Down <158919+timdown@users.noreply.github.com> Date: Fri, 2 Feb 2024 11:54:26 +0000 Subject: [PATCH] Merge pull request #16700 from overleaf/td-scroll-comment-input-into-view Scroll comment textarea into view after autofocus GitOrigin-RevId: c8542f40d25772a14e7511702c0e47b7001be275 --- .../review-panel/entries/add-comment-entry.tsx | 17 +++++++++++++++++ .../components/auto-expanding-text-area.tsx | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/services/web/frontend/js/features/source-editor/components/review-panel/entries/add-comment-entry.tsx b/services/web/frontend/js/features/source-editor/components/review-panel/entries/add-comment-entry.tsx index 50cb258809..b1224ddd64 100644 --- a/services/web/frontend/js/features/source-editor/components/review-panel/entries/add-comment-entry.tsx +++ b/services/web/frontend/js/features/source-editor/components/review-panel/entries/add-comment-entry.tsx @@ -88,6 +88,22 @@ function AddCommentEntry() { } } + const handleCommentAutoFocus = (textarea: HTMLTextAreaElement) => { + // Sometimes the comment textarea is scrolled out of view once focussed, + // so this checks for that and scrolls it into view if necessary. It + // seems we sometimes need to allow time for the dust to settle after + // focussing the textarea before scrolling. + window.setTimeout(() => { + const observer = new IntersectionObserver(([entry]) => { + if (entry.intersectionRatio < 1) { + textarea.scrollIntoView({ block: 'center' }) + } + observer.disconnect() + }) + observer.observe(textarea) + }, 500) + } + return ( @@ -109,6 +125,7 @@ function AddCommentEntry() { onChange={e => setContent(e.target.value)} onKeyPress={handleCommentKeyPress} onResize={handleLayoutChange} + onAutoFocus={handleCommentAutoFocus} placeholder={t('add_your_comment_here')} value={content} autoFocus // eslint-disable-line jsx-a11y/no-autofocus diff --git a/services/web/frontend/js/shared/components/auto-expanding-text-area.tsx b/services/web/frontend/js/shared/components/auto-expanding-text-area.tsx index e1e945084e..8f56f5c0ae 100644 --- a/services/web/frontend/js/shared/components/auto-expanding-text-area.tsx +++ b/services/web/frontend/js/shared/components/auto-expanding-text-area.tsx @@ -6,6 +6,7 @@ type AutoExpandingTextAreaProps = MergeAndOverride< React.ComponentProps<'textarea'>, { onResize?: () => void + onAutoFocus?: (textarea: HTMLTextAreaElement) => void } > @@ -13,6 +14,7 @@ function AutoExpandingTextArea({ onChange, onResize, autoFocus, + onAutoFocus, ...rest }: AutoExpandingTextAreaProps) { const ref = useRef(null) @@ -102,6 +104,13 @@ function AutoExpandingTextArea({ } }, [onResize]) + // Maintain a copy onAutoFocus in a ref for use in the autofocus effect + // below so that the effect doesn't run when onAutoFocus changes + const onAutoFocusRef = useRef(onAutoFocus) + useEffect(() => { + onAutoFocusRef.current = onAutoFocus + }, [onAutoFocus]) + // Implement autofocus manually so that the cursor is placed at the end of // the textarea content useEffect(() => { @@ -113,10 +122,17 @@ function AutoExpandingTextArea({ resetHeight() if (autoFocus) { const cursorPos = el.value.length - window.setTimeout(() => { + const timer = window.setTimeout(() => { el.focus() el.setSelectionRange(cursorPos, cursorPos) + if (onAutoFocusRef.current) { + onAutoFocusRef.current(el) + } }, 100) + + return () => { + window.clearTimeout(timer) + } } }, [autoFocus, resetHeight])