Skip to content

Commit 661cb73

Browse files
committed
chore: fix scroll sync in conflict resolution modal
1 parent 3b0e0ac commit 661cb73

File tree

3 files changed

+60
-14
lines changed

3 files changed

+60
-14
lines changed

packages/web/src/javascripts/Components/NoteView/NoteConflictResolutionModal/NoteConflictResolutionModal.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ const NoteConflictResolutionModal = ({
161161

162162
const [comparisonScrollPos, setComparisonScrollPos] = useState(0)
163163
const [shouldSyncComparisonScroll, setShouldSyncComparisonScroll] = useState(true)
164+
const onScroll = useCallback(({ target }: { target: EventTarget | null }) => {
165+
setComparisonScrollPos((target as HTMLElement).scrollTop)
166+
}, [])
164167

165168
return (
166169
<Modal
@@ -319,7 +322,7 @@ const NoteConflictResolutionModal = ({
319322
key={note.uuid}
320323
scrollPos={comparisonScrollPos}
321324
shouldSyncScroll={shouldSyncComparisonScroll}
322-
onScroll={(event) => setComparisonScrollPos((event.target as HTMLElement).scrollTop)}
325+
onScroll={onScroll}
323326
/>
324327
))}
325328
</div>

packages/web/src/javascripts/Components/NoteView/ReadonlyNoteContent.tsx

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
classNames,
99
isUIFeatureAnIframeFeature,
1010
} from '@standardnotes/snjs'
11-
import { CSSProperties, UIEventHandler, useEffect, useMemo, useRef } from 'react'
11+
import { CSSProperties, useCallback, useEffect, useMemo, useRef } from 'react'
1212
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
1313
import { useApplication } from '../ApplicationProvider'
1414
import IframeFeatureView from '../ComponentView/IframeFeatureView'
@@ -19,6 +19,7 @@ import { useLinkingController } from '@/Controllers/LinkingControllerProvider'
1919
import LinkedItemBubblesContainer from '../LinkedItems/LinkedItemBubblesContainer'
2020
import usePreference from '@/Hooks/usePreference'
2121
import { useResponsiveEditorFontSize } from '@/Utils/getPlaintextFontSize'
22+
import { getScrollParent } from '@/Utils'
2223

2324
export const ReadonlyNoteContent = ({
2425
note,
@@ -33,7 +34,7 @@ export const ReadonlyNoteContent = ({
3334
showLinkedItems?: boolean
3435
scrollPos?: number
3536
shouldSyncScroll?: boolean
36-
onScroll?: UIEventHandler
37+
onScroll?: ({ target }: { target: EventTarget | null }) => void
3738
}) => {
3839
const application = useApplication()
3940
const linkingController = useLinkingController()
@@ -64,6 +65,27 @@ export const ReadonlyNoteContent = ({
6465
}, [application, componentViewer])
6566

6667
const containerRef = useRef<HTMLDivElement>(null)
68+
const scrollerRef = useRef<HTMLElement | null>()
69+
70+
const setScroller = useCallback(() => {
71+
if (scrollerRef.current) {
72+
return
73+
}
74+
75+
scrollerRef.current = containerRef.current?.querySelector<HTMLElement>('textarea, .ContentEditable__root')
76+
77+
if (!scrollerRef.current) {
78+
return
79+
}
80+
81+
const isScrollerOverflowing = scrollerRef.current.scrollHeight > scrollerRef.current.clientHeight
82+
if (!isScrollerOverflowing) {
83+
const closestScrollParent = getScrollParent(scrollerRef.current)
84+
if (closestScrollParent) {
85+
scrollerRef.current = closestScrollParent
86+
}
87+
}
88+
}, [])
6789

6890
useEffect(() => {
6991
if (!shouldSyncScroll) {
@@ -74,16 +96,41 @@ export const ReadonlyNoteContent = ({
7496
return
7597
}
7698

77-
const scroller = containerRef.current.querySelector('textarea, .ContentEditable__root')
78-
79-
if (!scroller) {
80-
return
99+
if (!scrollerRef.current) {
100+
setScroller()
81101
}
82102

83-
scroller.scrollTo({
103+
scrollerRef.current?.scrollTo({
84104
top: scrollPos,
85105
})
86-
}, [scrollPos, shouldSyncScroll])
106+
}, [scrollPos, setScroller, shouldSyncScroll])
107+
108+
useEffect(
109+
function setupOnScrollForSuper() {
110+
if (note.noteType !== NoteType.Super) {
111+
return
112+
}
113+
114+
setScroller()
115+
116+
const scroller = scrollerRef.current
117+
118+
if (!scroller) {
119+
return
120+
}
121+
122+
const scrollHandler = (event: Event) => {
123+
onScroll?.(event)
124+
}
125+
126+
scroller.addEventListener('scroll', scrollHandler)
127+
128+
return () => {
129+
scroller.removeEventListener('scroll', scrollHandler)
130+
}
131+
},
132+
[note.noteType, onScroll, setScroller],
133+
)
87134

88135
const lineHeight = usePreference(PrefKey.EditorLineHeight)
89136
const fontSize = usePreference(PrefKey.EditorFontSize)
@@ -123,7 +170,6 @@ export const ReadonlyNoteContent = ({
123170
readonly
124171
className="blocks-editor relative h-full resize-none p-4 text-base focus:shadow-none focus:outline-none"
125172
spellcheck={content.spellcheck}
126-
onScroll={onScroll}
127173
></BlocksEditor>
128174
</BlocksEditorComposer>
129175
</div>

packages/web/src/javascripts/Components/SuperEditor/BlocksEditor.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FunctionComponent, UIEventHandler, useCallback, useState } from 'react'
1+
import { FunctionComponent, useCallback, useState } from 'react'
22
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
33
import { ContentEditable } from '@lexical/react/LexicalContentEditable'
44
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'
@@ -37,7 +37,6 @@ type BlocksEditorProps = {
3737
spellcheck?: boolean
3838
ignoreFirstChange?: boolean
3939
readonly?: boolean
40-
onScroll?: UIEventHandler
4140
}
4241

4342
export const BlocksEditor: FunctionComponent<BlocksEditorProps> = ({
@@ -48,7 +47,6 @@ export const BlocksEditor: FunctionComponent<BlocksEditorProps> = ({
4847
spellcheck,
4948
ignoreFirstChange = false,
5049
readonly,
51-
onScroll,
5250
}) => {
5351
const [didIgnoreFirstChange, setDidIgnoreFirstChange] = useState(false)
5452
const handleChange = useCallback(
@@ -87,7 +85,6 @@ export const BlocksEditor: FunctionComponent<BlocksEditorProps> = ({
8785
id={SuperEditorContentId}
8886
className={classNames('ContentEditable__root overflow-y-auto', className)}
8987
spellCheck={spellcheck}
90-
onScroll={onScroll}
9188
/>
9289
<div className="search-highlight-container pointer-events-none absolute left-0 top-0 h-full w-full" />
9390
</div>

0 commit comments

Comments
 (0)