Merge pull request #35182 from overleaf/ii-use-event-listener

[web] Replace useScopeEventEmitter and useScopeEventListener with useEventListener

GitOrigin-RevId: 8348c8c980b01e172fee3371980176d2b58ceec6
This commit is contained in:
ilkin-overleaf
2026-09-17 11:22:34 +00:00
committed by Copybot
parent df4e336399
commit 6f8ecc7678
14 changed files with 45 additions and 188 deletions
@@ -24,7 +24,6 @@ import {
findDocEntityById,
findFileRefEntityById,
} from '@/features/ide-react/util/find-doc-entity-by-id'
import useScopeEventEmitter from '@/shared/hooks/use-scope-event-emitter'
import { useModalsContext } from '@/features/ide-react/context/modals-context'
import { useTranslation } from 'react-i18next'
import customLocalStorage from '@/infrastructure/local-storage'
@@ -111,8 +110,6 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
wantTrackChangesRef.current = wantTrackChanges
}, [wantTrackChanges])
const goToLineEmitter = useScopeEventEmitter('editor:gotoLine')
const { fileTreeData } = useFileTreeData()
const [ignoringExternalUpdates, setIgnoringExternalUpdates] = useState(false)
@@ -197,12 +194,11 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
[currentDocumentId]
)
const jumpToLine = useCallback(
(options: GotoLineOptions) => {
goToLineEmitter(options)
},
[goToLineEmitter]
)
const jumpToLine = useCallback((options: GotoLineOptions) => {
window.dispatchEvent(
new CustomEvent('editor:gotoLine', { detail: options })
)
}, [])
const attachErrorHandlerToDocument = useCallback(
(doc: Doc, document: DocumentContainer) => {
@@ -417,7 +413,9 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
}
} else if (hasGotoOffset(options)) {
const jump = () => {
eventEmitter.emit('editor:gotoOffset', options)
window.dispatchEvent(
new CustomEvent('editor:gotoOffset', { detail: options })
)
}
if (isNewDoc) {
@@ -16,7 +16,6 @@ import {
import { JoinProjectPayload } from '@/features/ide-react/connection/join-project-payload'
import { useConnectionContext } from '@/features/ide-react/context/connection-context'
import { postJSON } from '@/infrastructure/fetch-json'
import { ReactScopeEventEmitter } from '@/features/ide-react/scope-event-emitter/react-scope-event-emitter'
import getMeta from '@/utils/meta'
import { type PermissionsLevel } from '@/features/ide-react/types/permissions'
import { useProjectContext } from '@/shared/context/project-context'
@@ -48,9 +47,6 @@ export const IdeReactProvider: FC<React.PropsWithChildren> = ({ children }) => {
const [permissionsLevel, setPermissionsLevel] =
useState<PermissionsLevel>('readOnly')
const [outOfSync, setOutOfSync] = useState(false)
const [scopeEventEmitter] = useState(
() => new ReactScopeEventEmitter(eventEmitter)
)
const [unstableStore] = useState(() => {
const store = new ReactScopeValueStore()
// Add dummy editor.ready key for Writefull, that relies on this calling
@@ -165,11 +161,7 @@ export const IdeReactProvider: FC<React.PropsWithChildren> = ({ children }) => {
return (
<IdeReactContext.Provider value={value}>
<IdeProvider
ide={ide}
scopeEventEmitter={scopeEventEmitter}
unstableStore={unstableStore}
>
<IdeProvider ide={ide} unstableStore={unstableStore}>
{children}
</IdeProvider>
</IdeReactContext.Provider>
@@ -15,8 +15,8 @@ import { Doc } from '../../../../../types/doc'
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
import { findDocEntityById } from '@/features/ide-react/util/find-doc-entity-by-id'
import useSocketListener from '@/features/ide-react/hooks/use-socket-listener'
import useEventListener from '@/shared/hooks/use-event-listener'
import { debugConsole } from '@/utils/debugging'
import { IdeEvents } from '@/features/ide-react/create-ide-event-emitter'
import { getHueForUserId } from '@/shared/utils/colors'
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
@@ -199,21 +199,15 @@ export const OnlineUsersProvider: FC<React.PropsWithChildren> = ({
}, [eventEmitter, setAllValues, setOnlineUsers, socket])
// Track the position of the main cursor
useEffect(() => {
const handleCursorUpdate = ({
detail: [position],
}: CustomEvent<IdeEvents['cursor:editor:update']>) => {
useEventListener(
'cursor:editor:update',
useCallback((event: CustomEvent<CursorPosition>) => {
const position = event.detail
if (position) {
setCurrentPosition(position)
}
}
eventEmitter.on('cursor:editor:update', handleCursorUpdate)
return () => {
eventEmitter.off('cursor:editor:update', handleCursorUpdate)
}
}, [cursorUpdateInterval, eventEmitter])
}, [])
)
// Send the latest position to other clients when currentPosition changes
useEffect(() => {
@@ -8,7 +8,6 @@ import {
useMemo,
useState,
} from 'react'
import useScopeEventEmitter from '@/shared/hooks/use-scope-event-emitter'
import useEventListener from '@/shared/hooks/use-event-listener'
import { isValidTeXFile } from '@/main/is-valid-tex-file'
import localStorage from '@/infrastructure/local-storage'
@@ -55,8 +54,6 @@ export const OutlineProvider: FC<React.PropsWithChildren> = ({ children }) => {
const [ignoreNextScroll, setIgnoreNextScroll] = useState<boolean>(false)
const { sendEvent } = useEditorAnalytics()
const goToLineEmitter = useScopeEventEmitter('editor:gotoLine', true)
useEventListener(
'file-view:file-opened',
useCallback(() => {
@@ -106,14 +103,18 @@ export const OutlineProvider: FC<React.PropsWithChildren> = ({ children }) => {
const jumpToLine = useCallback(
(lineNumber: number, syncToPdf: boolean) => {
setIgnoreNextScroll(true)
goToLineEmitter({
gotoLine: lineNumber,
gotoColumn: 0,
syncToPdf,
})
window.dispatchEvent(
new CustomEvent('editor:gotoLine', {
detail: {
gotoLine: lineNumber,
gotoColumn: 0,
syncToPdf,
},
})
)
sendEvent('outline-jump-to-line')
},
[goToLineEmitter, sendEvent]
[sendEvent]
)
const highlightedLine = useMemo(
@@ -1,37 +0,0 @@
import {
ScopeEventEmitter,
ScopeEventName,
} from '../../../../../types/ide/scope-event-emitter'
import { IdeEvents } from '@/features/ide-react/create-ide-event-emitter'
export class ReactScopeEventEmitter implements ScopeEventEmitter {
// eslint-disable-next-line no-useless-constructor
constructor(private readonly eventEmitter: EventTarget) {}
emit<T extends ScopeEventName>(
eventName: T,
broadcast: boolean,
...detail: IdeEvents[T]
) {
this.eventEmitter.dispatchEvent(new CustomEvent(eventName, { detail }))
}
on<T extends ScopeEventName>(
eventName: T,
listener: (event: Event, ...args: IdeEvents[T]) => void
) {
const wrappedListener = (event: CustomEvent<IdeEvents[T]>) => {
listener(event, ...event.detail)
}
this.eventEmitter.addEventListener(
eventName,
wrappedListener as EventListener
)
return () => {
this.eventEmitter.removeEventListener(
eventName,
wrappedListener as EventListener
)
}
}
}