chore: fix scroll sync in conflict resolution modal
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user