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 [comparisonScrollPos, setComparisonScrollPos] = useState(0)
|
||||||
const [shouldSyncComparisonScroll, setShouldSyncComparisonScroll] = useState(true)
|
const [shouldSyncComparisonScroll, setShouldSyncComparisonScroll] = useState(true)
|
||||||
|
const onScroll = useCallback(({ target }: { target: EventTarget | null }) => {
|
||||||
|
setComparisonScrollPos((target as HTMLElement).scrollTop)
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@@ -319,7 +322,7 @@ const NoteConflictResolutionModal = ({
|
|||||||
key={note.uuid}
|
key={note.uuid}
|
||||||
scrollPos={comparisonScrollPos}
|
scrollPos={comparisonScrollPos}
|
||||||
shouldSyncScroll={shouldSyncComparisonScroll}
|
shouldSyncScroll={shouldSyncComparisonScroll}
|
||||||
onScroll={(event) => setComparisonScrollPos((event.target as HTMLElement).scrollTop)}
|
onScroll={onScroll}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
classNames,
|
classNames,
|
||||||
isUIFeatureAnIframeFeature,
|
isUIFeatureAnIframeFeature,
|
||||||
} from '@standardnotes/snjs'
|
} 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 { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
|
||||||
import { useApplication } from '../ApplicationProvider'
|
import { useApplication } from '../ApplicationProvider'
|
||||||
import IframeFeatureView from '../ComponentView/IframeFeatureView'
|
import IframeFeatureView from '../ComponentView/IframeFeatureView'
|
||||||
@@ -19,6 +19,7 @@ import { useLinkingController } from '@/Controllers/LinkingControllerProvider'
|
|||||||
import LinkedItemBubblesContainer from '../LinkedItems/LinkedItemBubblesContainer'
|
import LinkedItemBubblesContainer from '../LinkedItems/LinkedItemBubblesContainer'
|
||||||
import usePreference from '@/Hooks/usePreference'
|
import usePreference from '@/Hooks/usePreference'
|
||||||
import { useResponsiveEditorFontSize } from '@/Utils/getPlaintextFontSize'
|
import { useResponsiveEditorFontSize } from '@/Utils/getPlaintextFontSize'
|
||||||
|
import { getScrollParent } from '@/Utils'
|
||||||
|
|
||||||
export const ReadonlyNoteContent = ({
|
export const ReadonlyNoteContent = ({
|
||||||
note,
|
note,
|
||||||
@@ -33,7 +34,7 @@ export const ReadonlyNoteContent = ({
|
|||||||
showLinkedItems?: boolean
|
showLinkedItems?: boolean
|
||||||
scrollPos?: number
|
scrollPos?: number
|
||||||
shouldSyncScroll?: boolean
|
shouldSyncScroll?: boolean
|
||||||
onScroll?: UIEventHandler
|
onScroll?: ({ target }: { target: EventTarget | null }) => void
|
||||||
}) => {
|
}) => {
|
||||||
const application = useApplication()
|
const application = useApplication()
|
||||||
const linkingController = useLinkingController()
|
const linkingController = useLinkingController()
|
||||||
@@ -64,6 +65,27 @@ export const ReadonlyNoteContent = ({
|
|||||||
}, [application, componentViewer])
|
}, [application, componentViewer])
|
||||||
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null)
|
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(() => {
|
useEffect(() => {
|
||||||
if (!shouldSyncScroll) {
|
if (!shouldSyncScroll) {
|
||||||
@@ -74,16 +96,41 @@ export const ReadonlyNoteContent = ({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const scroller = containerRef.current.querySelector('textarea, .ContentEditable__root')
|
if (!scrollerRef.current) {
|
||||||
|
setScroller()
|
||||||
if (!scroller) {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scroller.scrollTo({
|
scrollerRef.current?.scrollTo({
|
||||||
top: scrollPos,
|
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 lineHeight = usePreference(PrefKey.EditorLineHeight)
|
||||||
const fontSize = usePreference(PrefKey.EditorFontSize)
|
const fontSize = usePreference(PrefKey.EditorFontSize)
|
||||||
@@ -123,7 +170,6 @@ export const ReadonlyNoteContent = ({
|
|||||||
readonly
|
readonly
|
||||||
className="blocks-editor relative h-full resize-none p-4 text-base focus:shadow-none focus:outline-none"
|
className="blocks-editor relative h-full resize-none p-4 text-base focus:shadow-none focus:outline-none"
|
||||||
spellcheck={content.spellcheck}
|
spellcheck={content.spellcheck}
|
||||||
onScroll={onScroll}
|
|
||||||
></BlocksEditor>
|
></BlocksEditor>
|
||||||
</BlocksEditorComposer>
|
</BlocksEditorComposer>
|
||||||
</div>
|
</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 { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
|
||||||
import { ContentEditable } from '@lexical/react/LexicalContentEditable'
|
import { ContentEditable } from '@lexical/react/LexicalContentEditable'
|
||||||
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'
|
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'
|
||||||
@@ -37,7 +37,6 @@ type BlocksEditorProps = {
|
|||||||
spellcheck?: boolean
|
spellcheck?: boolean
|
||||||
ignoreFirstChange?: boolean
|
ignoreFirstChange?: boolean
|
||||||
readonly?: boolean
|
readonly?: boolean
|
||||||
onScroll?: UIEventHandler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BlocksEditor: FunctionComponent<BlocksEditorProps> = ({
|
export const BlocksEditor: FunctionComponent<BlocksEditorProps> = ({
|
||||||
@@ -48,7 +47,6 @@ export const BlocksEditor: FunctionComponent<BlocksEditorProps> = ({
|
|||||||
spellcheck,
|
spellcheck,
|
||||||
ignoreFirstChange = false,
|
ignoreFirstChange = false,
|
||||||
readonly,
|
readonly,
|
||||||
onScroll,
|
|
||||||
}) => {
|
}) => {
|
||||||
const [didIgnoreFirstChange, setDidIgnoreFirstChange] = useState(false)
|
const [didIgnoreFirstChange, setDidIgnoreFirstChange] = useState(false)
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
@@ -87,7 +85,6 @@ export const BlocksEditor: FunctionComponent<BlocksEditorProps> = ({
|
|||||||
id={SuperEditorContentId}
|
id={SuperEditorContentId}
|
||||||
className={classNames('ContentEditable__root overflow-y-auto', className)}
|
className={classNames('ContentEditable__root overflow-y-auto', className)}
|
||||||
spellCheck={spellcheck}
|
spellCheck={spellcheck}
|
||||||
onScroll={onScroll}
|
|
||||||
/>
|
/>
|
||||||
<div className="search-highlight-container pointer-events-none absolute left-0 top-0 h-full w-full" />
|
<div className="search-highlight-container pointer-events-none absolute left-0 top-0 h-full w-full" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user