Просмотр исходного кода

Prevent scrolling when reply input is focused (#22968)

* Prevent scrolling when reply textarea is focused

* remove focusIsOnTextarea check as it is handled above

* remove unnecessery setSelected

GitOrigin-RevId: 5ce3fc6691a19fe2566875785607bb4faa3e9f52
Domagoj Kriskovic 1 год назад
Родитель
Сommit
e5a4a8606f

+ 22 - 5
services/web/frontend/js/features/review-panel-new/components/review-panel-entry.tsx

@@ -1,4 +1,4 @@
-import { FC, useCallback, useEffect, useState } from 'react'
+import { FC, useCallback, useEffect, useRef, useState } from 'react'
 import { AnyOperation } from '../../../../../types/change'
 import {
   useCodeMirrorStateContext,
@@ -15,6 +15,7 @@ import { useLayoutContext } from '@/shared/context/layout-context'
 import { EditorSelection } from '@codemirror/state'
 import { EditorView } from '@codemirror/view'
 import MaterialIcon from '@/shared/components/material-icon'
+import { OFFSET_FOR_ENTRIES_ABOVE } from '../utils/position-items'
 
 export const ReviewPanelEntry: FC<{
   position: number
@@ -47,8 +48,10 @@ export const ReviewPanelEntry: FC<{
   const { openDocId, getCurrentDocId } = useEditorManagerContext()
   const [selected, setSelected] = useState(false)
   const [focused, setFocused] = useState(false)
+  const [textareaFocused, setTextareaFocused] = useState(false)
   const { setReviewPanelOpen, reviewPanelOpen } = useLayoutContext()
   const highlighted = isSelectionWithinOp(op, state.selection.main)
+  const entryRef = useRef<HTMLDivElement>(null)
 
   const openReviewPanel = useCallback(() => {
     setReviewPanelOpen(true)
@@ -69,6 +72,17 @@ export const ReviewPanelEntry: FC<{
         return
       }
 
+      if (event.target instanceof HTMLTextAreaElement) {
+        const entryBottom =
+          (entryRef.current?.offsetTop || 0) +
+          (entryRef.current?.offsetHeight || 0)
+
+        if (entryBottom > OFFSET_FOR_ENTRIES_ABOVE) {
+          setTextareaFocused(true)
+          return
+        }
+      }
+
       setSelected(true)
 
       if (!selectLineOnFocus) {
@@ -76,10 +90,7 @@ export const ReviewPanelEntry: FC<{
       }
 
       if (getCurrentDocId() !== docId) {
-        const focusIsOnTextarea = event.target instanceof HTMLTextAreaElement
-        if (focusIsOnTextarea === false) {
-          openDocId(docId, { gotoOffset: position, keepCurrentView: true })
-        }
+        openDocId(docId, { gotoOffset: position, keepCurrentView: true })
       } else {
         setTimeout(() =>
           view.dispatch({
@@ -113,10 +124,12 @@ export const ReviewPanelEntry: FC<{
 
   return (
     <div
+      ref={entryRef}
       onFocus={focusHandler}
       onBlur={() => {
         setSelected(false)
         setFocused(false)
+        setTextareaFocused(false)
       }}
       onMouseEnter={() => {
         if (hoverRanges) {
@@ -143,6 +156,10 @@ export const ReviewPanelEntry: FC<{
           // 'highlighted' is set if the selection is within op but that doesn't necessarily mean it should be selected
           // multiple entries can be highlighted at the same time
           'review-panel-entry-highlighted': highlighted,
+          // 'textarea-focused' only changes entry styling (border, shadow etc)
+          // it doesnt change selected entry because that moves the cursor
+          // and repositions entries which can cause textarea to be scrolled out of view
+          'review-panel-entry-textarea-focused': textareaFocused,
           'review-panel-entry-disabled': disabled,
         },
         className

+ 1 - 1
services/web/frontend/js/features/review-panel-new/utils/position-items.ts

@@ -1,8 +1,8 @@
 import getMeta from '@/utils/meta'
 import { debounce } from 'lodash'
 
+export const OFFSET_FOR_ENTRIES_ABOVE = 70
 const COLLAPSED_HEADER_HEIGHT = getMeta('ol-isReviewerRoleEnabled') ? 42 : 75
-const OFFSET_FOR_ENTRIES_ABOVE = 70
 const GAP_BETWEEN_ENTRIES = 4
 
 export const positionItems = debounce(

+ 2 - 1
services/web/frontend/stylesheets/app/editor/review-panel-new.less

@@ -50,7 +50,8 @@
   }
 
   .review-panel-entry.review-panel-entry-selected,
-  .review-panel-entry.review-panel-entry-highlighted {
+  .review-panel-entry.review-panel-entry-highlighted,
+  .review-panel-entry.review-panel-entry-textarea-focused {
     margin-left: @spacing-01;
     border: 1px solid @blue-50;
     // shadow-md

+ 2 - 1
services/web/frontend/stylesheets/bootstrap-5/pages/editor/review-panel-new.scss

@@ -57,7 +57,8 @@
   }
 
   .review-panel-entry.review-panel-entry-selected,
-  .review-panel-entry.review-panel-entry-highlighted {
+  .review-panel-entry.review-panel-entry-highlighted,
+  .review-panel-entry.review-panel-entry-textarea-focused {
     margin-left: var(--spacing-01);
     border: 1px solid var(--border-active);