Преглед изворни кода

Merge pull request #13492 from overleaf/td-review-panel-sync-height

Add hook for synchronizing review panel height with editor content height

GitOrigin-RevId: ef0a96ef4e77e7858b28f6f65254a4b0c1e778ea
ilkin-overleaf пре 3 година
родитељ
комит
15db0ce4e3

+ 5 - 0
services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx

@@ -1,6 +1,11 @@
 import Container from './container'
+import useCodeMirrorContentHeight from '../../hooks/use-codemirror-content-height'
 
 function CurrentFileContainer() {
+  const contentHeight = useCodeMirrorContentHeight()
+
+  console.log('Review panel got content height', contentHeight)
+
   return (
     <Container>
       <div

+ 15 - 0
services/web/frontend/js/features/source-editor/extensions/geometry-change-event.ts

@@ -0,0 +1,15 @@
+import { EditorView } from '@codemirror/view'
+
+/**
+ * An extension that triggers a custom DOM event whenever the editor geometry
+ * changes. This is used to synchronize the editor content and review panel
+ * height in "Current file" mode.
+ */
+export const geometryChangeEvent = (reactReviewPanel: boolean) =>
+  reactReviewPanel
+    ? EditorView.updateListener.of(update => {
+        if (update.geometryChanged) {
+          window.dispatchEvent(new CustomEvent('editor:geometry-change'))
+        }
+      })
+    : []

+ 2 - 0
services/web/frontend/js/features/source-editor/extensions/index.ts

@@ -45,6 +45,7 @@ import { keymaps } from './keymaps'
 import { shortcuts } from './shortcuts'
 import { effectListeners } from './effect-listeners'
 import { highlightSpecialChars } from './highlight-special-chars'
+import { geometryChangeEvent } from './geometry-change-event'
 
 const moduleExtensions: Array<() => Extension> = importOverleafModules(
   'sourceEditorExtensions'
@@ -130,4 +131,5 @@ export const createExtensions = (options: Record<string, any>): Extension[] => [
   moduleExtensions.map(extension => extension()),
   thirdPartyExtensions(),
   effectListeners(),
+  geometryChangeEvent(options.reactReviewPanel),
 ]

+ 12 - 0
services/web/frontend/js/features/source-editor/hooks/use-codemirror-content-height.ts

@@ -0,0 +1,12 @@
+import { EditorView } from '@codemirror/view'
+import useCodeMirrorMeasurement from './use-codemirror-measurement'
+
+// view.contentHeight, which is measured for us by CodeMirror and is what the
+// gutters use, is sometimes a pixel or so short of the full height of the
+// editor content, which leaves a small gap at the bottom, so use the DOM
+// scrollHeight property instead.
+const measureContentHeight = (view: EditorView) => view.contentDOM.scrollHeight
+
+export default function useCodeMirrorContentHeight() {
+  return useCodeMirrorMeasurement('content-height', measureContentHeight)
+}

+ 27 - 0
services/web/frontend/js/features/source-editor/hooks/use-codemirror-measurement.ts

@@ -0,0 +1,27 @@
+import { useCallback, useState } from 'react'
+import { useCodeMirrorViewContext } from '../components/codemirror-editor'
+import { EditorView } from '@codemirror/view'
+import useEventListener from '../../../shared/hooks/use-event-listener'
+
+export default function useCodeMirrorMeasurement(
+  key: string,
+  measure: (view: EditorView) => number
+) {
+  const view = useCodeMirrorViewContext()
+  const [measurement, setMeasurement] = useState(measure(view))
+
+  useEventListener(
+    'editor:geometry-change',
+    useCallback(() => {
+      view.requestMeasure({
+        key,
+        read: () => measure(view),
+        write(value) {
+          setMeasurement(value)
+        },
+      })
+    }, [view, measure, key])
+  )
+
+  return measurement
+}

+ 4 - 1
services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts

@@ -47,6 +47,7 @@ import { EditorView } from '@codemirror/view'
 import { CurrentDoc } from '../../../../../types/current-doc'
 import { useErrorHandler } from 'react-error-boundary'
 import { setVisual } from '../extensions/visual/visual'
+import getMeta from '../../../utils/meta'
 
 function useCodeMirrorScope(view: EditorView) {
   const ide = useIdeContext()
@@ -86,6 +87,7 @@ function useCodeMirrorScope(view: EditorView) {
   )
 
   const [visual] = useScopeValue<boolean>('editor.showVisual')
+  const reactReviewPanel: boolean = getMeta('ol-isReviewPanelReact')
 
   // build the translation phrases
   const phrases = usePhrases()
@@ -266,6 +268,7 @@ function useCodeMirrorScope(view: EditorView) {
           visual: visualRef.current,
           changeManager: createChangeManager(view, currentDoc),
           handleError,
+          reactReviewPanel,
         }),
       })
       view.setState(state)
@@ -295,7 +298,7 @@ function useCodeMirrorScope(view: EditorView) {
     }
     // IMPORTANT: This effect must not depend on anything variable apart from currentDoc,
     // as the editor state is recreated when the effect runs.
-  }, [view, currentDoc, handleError])
+  }, [view, currentDoc, handleError, reactReviewPanel])
 
   useEffect(() => {
     visualRef.current.visual = visual