chore: fix scroll sync in conflict resolution modal

This commit is contained in:
Aman Harwara
2023-12-18 13:23:39 +05:30
parent 3b0e0ac013
commit 661cb73749
3 changed files with 60 additions and 14 deletions

View File

@@ -161,6 +161,9 @@ const NoteConflictResolutionModal = ({
const [comparisonScrollPos, setComparisonScrollPos] = useState(0)
const [shouldSyncComparisonScroll, setShouldSyncComparisonScroll] = useState(true)
const onScroll = useCallback(({ target }: { target: EventTarget | null }) => {
setComparisonScrollPos((target as HTMLElement).scrollTop)
}, [])
return (
<Modal
@@ -319,7 +322,7 @@ const NoteConflictResolutionModal = ({
key={note.uuid}
scrollPos={comparisonScrollPos}
shouldSyncScroll={shouldSyncComparisonScroll}
onScroll={(event) => setComparisonScrollPos((event.target as HTMLElement).scrollTop)}
onScroll={onScroll}
/>
))}
</div>

View File

@@ -8,7 +8,7 @@ import {
classNames,
isUIFeatureAnIframeFeature,
} from '@standardnotes/snjs'
import { CSSProperties, UIEventHandler, useEffect, useMemo, useRef } from 'react'
import { CSSProperties, useCallback, useEffect, useMemo, useRef } from 'react'
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
import { useApplication } from '../ApplicationProvider'
import IframeFeatureView from '../ComponentView/IframeFeatureView'
@@ -19,6 +19,7 @@ import { useLinkingController } from '@/Controllers/LinkingControllerProvider'
import LinkedItemBubblesContainer from '../LinkedItems/LinkedItemBubblesContainer'
import usePreference from '@/Hooks/usePreference'
import { useResponsiveEditorFontSize } from '@/Utils/getPlaintextFontSize'
import { getScrollParent } from '@/Utils'
export const ReadonlyNoteContent = ({
note,
@@ -33,7 +34,7 @@ export const ReadonlyNoteContent = ({
showLinkedItems?: boolean
scrollPos?: number
shouldSyncScroll?: boolean
onScroll?: UIEventHandler
onScroll?: ({ target }: { target: EventTarget | null }) => void
}) => {
const application = useApplication()
const linkingController = useLinkingController()
@@ -64,6 +65,27 @@ export const ReadonlyNoteContent = ({
}, [application, componentViewer])
const containerRef = useRef<HTMLDivElement>(null)
const scrollerRef = useRef<HTMLElement | null>()
const setScroller = useCallback(() => {
if (scrollerRef.current) {
return
}
scrollerRef.current = containerRef.current?.querySelector<HTMLElement>('textarea, .ContentEditable__root')
if (!scrollerRef.current) {
return
}
const isScrollerOverflowing = scrollerRef.current.scrollHeight > scrollerRef.current.clientHeight
if (!isScrollerOverflowing) {
const closestScrollParent = getScrollParent(scrollerRef.current)
if (closestScrollParent) {
scrollerRef.current = closestScrollParent
}
}
}, [])
useEffect(() => {
if (!shouldSyncScroll) {
@@ -74,16 +96,41 @@ export const ReadonlyNoteContent = ({
return
}
const scroller = containerRef.current.querySelector('textarea, .ContentEditable__root')
if (!scroller) {
return
if (!scrollerRef.current) {
setScroller()
}
scroller.scrollTo({
scrollerRef.current?.scrollTo({
top: scrollPos,
})
}, [scrollPos, shouldSyncScroll])
}, [scrollPos, setScroller, shouldSyncScroll])
useEffect(
function setupOnScrollForSuper() {
if (note.noteType !== NoteType.Super) {
return
}
setScroller()
const scroller = scrollerRef.current
if (!scroller) {
return
}
const scrollHandler = (event: Event) => {
onScroll?.(event)
}
scroller.addEventListener('scroll', scrollHandler)
return () => {
scroller.removeEventListener('scroll', scrollHandler)
}
},
[note.noteType, onScroll, setScroller],
)
const lineHeight = usePreference(PrefKey.EditorLineHeight)
const fontSize = usePreference(PrefKey.EditorFontSize)
@@ -123,7 +170,6 @@ export const ReadonlyNoteContent = ({
readonly
className="blocks-editor relative h-full resize-none p-4 text-base focus:shadow-none focus:outline-none"
spellcheck={content.spellcheck}
onScroll={onScroll}
></BlocksEditor>
</BlocksEditorComposer>
</div>

View File

@@ -1,4 +1,4 @@
import { FunctionComponent, UIEventHandler, useCallback, useState } from 'react'
import { FunctionComponent, useCallback, useState } from 'react'
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
import { ContentEditable } from '@lexical/react/LexicalContentEditable'
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'
@@ -37,7 +37,6 @@ type BlocksEditorProps = {
spellcheck?: boolean
ignoreFirstChange?: boolean
readonly?: boolean
onScroll?: UIEventHandler
}
export const BlocksEditor: FunctionComponent<BlocksEditorProps> = ({
@@ -48,7 +47,6 @@ export const BlocksEditor: FunctionComponent<BlocksEditorProps> = ({
spellcheck,
ignoreFirstChange = false,
readonly,
onScroll,
}) => {
const [didIgnoreFirstChange, setDidIgnoreFirstChange] = useState(false)
const handleChange = useCallback(
@@ -87,7 +85,6 @@ export const BlocksEditor: FunctionComponent<BlocksEditorProps> = ({
id={SuperEditorContentId}
className={classNames('ContentEditable__root overflow-y-auto', className)}
spellCheck={spellcheck}
onScroll={onScroll}
/>
<div className="search-highlight-container pointer-events-none absolute left-0 top-0 h-full w-full" />
</div>