From e00b7f52d413e5742274dc724ffe0e6be3cda4b7 Mon Sep 17 00:00:00 2001 From: ilkin-overleaf <100852799+ilkin-overleaf@users.noreply.github.com> Date: Mon, 19 Jun 2023 17:08:13 +0300 Subject: [PATCH] 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 --- .../review-panel/current-file-container.tsx | 5 ++++ .../extensions/geometry-change-event.ts | 15 +++++++++++ .../source-editor/extensions/index.ts | 2 ++ .../hooks/use-codemirror-content-height.ts | 12 +++++++++ .../hooks/use-codemirror-measurement.ts | 27 +++++++++++++++++++ .../hooks/use-codemirror-scope.ts | 5 +++- 6 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 services/web/frontend/js/features/source-editor/extensions/geometry-change-event.ts create mode 100644 services/web/frontend/js/features/source-editor/hooks/use-codemirror-content-height.ts create mode 100644 services/web/frontend/js/features/source-editor/hooks/use-codemirror-measurement.ts diff --git a/services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx b/services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx index 78df6da40b..41ee3209d2 100644 --- a/services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx +++ b/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 (
+ reactReviewPanel + ? EditorView.updateListener.of(update => { + if (update.geometryChanged) { + window.dispatchEvent(new CustomEvent('editor:geometry-change')) + } + }) + : [] diff --git a/services/web/frontend/js/features/source-editor/extensions/index.ts b/services/web/frontend/js/features/source-editor/extensions/index.ts index eb566db96e..f2dc686713 100644 --- a/services/web/frontend/js/features/source-editor/extensions/index.ts +++ b/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): Extension[] => [ moduleExtensions.map(extension => extension()), thirdPartyExtensions(), effectListeners(), + geometryChangeEvent(options.reactReviewPanel), ] diff --git a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-content-height.ts b/services/web/frontend/js/features/source-editor/hooks/use-codemirror-content-height.ts new file mode 100644 index 0000000000..04a89f5f23 --- /dev/null +++ b/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) +} diff --git a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-measurement.ts b/services/web/frontend/js/features/source-editor/hooks/use-codemirror-measurement.ts new file mode 100644 index 0000000000..bfba8b0574 --- /dev/null +++ b/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 +} diff --git a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts b/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts index 2ab87219b4..404e9f1588 100644 --- a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts +++ b/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('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