mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-25 11:16:31 -05:00
wip
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
4d70ccafbc
commit
5f27996ed0
5 changed files with 79 additions and 30 deletions
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
import { EditorView } from '@codemirror/view'
|
||||||
|
import { setNoteContent } from '../../../../redux/note-details/methods'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs the CodeMirror content to the redux store.
|
||||||
|
*
|
||||||
|
* @return the codemirror extension that updates the redux state
|
||||||
|
*/
|
||||||
|
export const useSyncToReduxExtension = () => {
|
||||||
|
return useMemo(
|
||||||
|
() =>
|
||||||
|
EditorView.updateListener.of((update) => {
|
||||||
|
if (!update.docChanged) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setNoteContent(update.state.sliceDoc())
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
}
|
|
@ -24,7 +24,6 @@ import { useApplyScrollState } from './hooks/use-apply-scroll-state'
|
||||||
import { useCursorActivityCallback } from './hooks/use-cursor-activity-callback'
|
import { useCursorActivityCallback } from './hooks/use-cursor-activity-callback'
|
||||||
import { useDisconnectOnUserLoginStatusChange } from './hooks/use-disconnect-on-user-login-status-change'
|
import { useDisconnectOnUserLoginStatusChange } from './hooks/use-disconnect-on-user-login-status-change'
|
||||||
import { useUpdateCodeMirrorReference } from './hooks/use-update-code-mirror-reference'
|
import { useUpdateCodeMirrorReference } from './hooks/use-update-code-mirror-reference'
|
||||||
import { useBindYTextToRedux } from './hooks/yjs/use-bind-y-text-to-redux'
|
|
||||||
import { useCodeMirrorYjsExtension } from './hooks/yjs/use-code-mirror-yjs-extension'
|
import { useCodeMirrorYjsExtension } from './hooks/yjs/use-code-mirror-yjs-extension'
|
||||||
import { useOnMetadataUpdated } from './hooks/yjs/use-on-metadata-updated'
|
import { useOnMetadataUpdated } from './hooks/yjs/use-on-metadata-updated'
|
||||||
import { useOnNoteDeleted } from './hooks/yjs/use-on-note-deleted'
|
import { useOnNoteDeleted } from './hooks/yjs/use-on-note-deleted'
|
||||||
|
@ -43,6 +42,7 @@ import { lintGutter } from '@codemirror/lint'
|
||||||
import { oneDark } from '@codemirror/theme-one-dark'
|
import { oneDark } from '@codemirror/theme-one-dark'
|
||||||
import ReactCodeMirror from '@uiw/react-codemirror'
|
import ReactCodeMirror from '@uiw/react-codemirror'
|
||||||
import React, { useEffect, useMemo } from 'react'
|
import React, { useEffect, useMemo } from 'react'
|
||||||
|
import { useSyncToReduxExtension } from './codemirror-extensions/use-sync-to-redux-extension'
|
||||||
|
|
||||||
export type EditorPaneProps = ScrollProps
|
export type EditorPaneProps = ScrollProps
|
||||||
|
|
||||||
|
@ -83,12 +83,14 @@ export const EditorPane: React.FC<EditorPaneProps> = ({ scrollState, onScroll, o
|
||||||
useOnMetadataUpdated(messageTransporter)
|
useOnMetadataUpdated(messageTransporter)
|
||||||
useOnNoteDeleted(messageTransporter)
|
useOnNoteDeleted(messageTransporter)
|
||||||
|
|
||||||
useBindYTextToRedux(realtimeDoc)
|
|
||||||
useReceiveRealtimeUsers(messageTransporter)
|
useReceiveRealtimeUsers(messageTransporter)
|
||||||
useSendRealtimeActivity(messageTransporter)
|
useSendRealtimeActivity(messageTransporter)
|
||||||
|
|
||||||
|
const syncToReduxExtension = useSyncToReduxExtension()
|
||||||
|
|
||||||
const extensions = useMemo(
|
const extensions = useMemo(
|
||||||
() => [
|
() => [
|
||||||
|
syncToReduxExtension,
|
||||||
linterExtension,
|
linterExtension,
|
||||||
lintGutter(),
|
lintGutter(),
|
||||||
markdown({
|
markdown({
|
||||||
|
@ -107,17 +109,18 @@ export const EditorPane: React.FC<EditorPaneProps> = ({ scrollState, onScroll, o
|
||||||
spellCheckExtension
|
spellCheckExtension
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
syncToReduxExtension,
|
||||||
linterExtension,
|
linterExtension,
|
||||||
remoteCursorsExtension,
|
remoteCursorsExtension,
|
||||||
autoCompletionExtension,
|
lineWrappingExtension,
|
||||||
editorScrollExtension,
|
editorScrollExtension,
|
||||||
tablePasteExtensions,
|
tablePasteExtensions,
|
||||||
fileInsertExtension,
|
fileInsertExtension,
|
||||||
|
autoCompletionExtension,
|
||||||
cursorActivityExtension,
|
cursorActivityExtension,
|
||||||
updateViewContextExtension,
|
updateViewContextExtension,
|
||||||
yjsExtension,
|
yjsExtension,
|
||||||
spellCheckExtension,
|
spellCheckExtension
|
||||||
lineWrappingExtension
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
import { setNoteContent } from '../../../../../redux/note-details/methods'
|
|
||||||
import type { RealtimeDoc } from '@hedgedoc/commons'
|
|
||||||
import { useEffect } from 'react'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* One-Way-synchronizes the text of the markdown content channel from the given {@link RealtimeDoc realtime doc} into the global application state.
|
|
||||||
*
|
|
||||||
* @param realtimeDoc The {@link RealtimeDoc realtime doc} that contains the markdown content
|
|
||||||
*/
|
|
||||||
export const useBindYTextToRedux = (realtimeDoc: RealtimeDoc): void => {
|
|
||||||
useEffect(() => {
|
|
||||||
const yText = realtimeDoc.getMarkdownContentChannel()
|
|
||||||
const yTextCallback = () => setNoteContent(yText.toString())
|
|
||||||
yText.observe(yTextCallback)
|
|
||||||
return () => yText.unobserve(yTextCallback)
|
|
||||||
}, [realtimeDoc])
|
|
||||||
}
|
|
39
frontend/src/hooks/common/use-deferred-state.ts
Normal file
39
frontend/src/hooks/common/use-deferred-state.ts
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
|
import { useInterval } from 'react-use'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a value that changes often and outputs the last value that hasn't been changed in the last interval.
|
||||||
|
*
|
||||||
|
* @param value The value to defer
|
||||||
|
* @param initialValue The initial value that is used until the first update
|
||||||
|
* @param checkInterval The interval in ms that is used to check for updates. Default is 200ms.
|
||||||
|
* @return The slowed down value
|
||||||
|
*/
|
||||||
|
export const useDeferredState = <T>(value: T, initialValue: T, checkInterval = 200): T => {
|
||||||
|
const valueRef = useRef<T>(initialValue)
|
||||||
|
const lastTimestamp = useRef<number>(0)
|
||||||
|
const [deferredValue, setDeferredValue] = useState<T>(initialValue)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
valueRef.current = value
|
||||||
|
lastTimestamp.current = new Date().getTime()
|
||||||
|
}, [value])
|
||||||
|
|
||||||
|
useInterval(
|
||||||
|
useCallback(() => {
|
||||||
|
const currentTimeStamp = new Date().getTime()
|
||||||
|
if (currentTimeStamp - lastTimestamp.current >= checkInterval) {
|
||||||
|
setDeferredValue(valueRef.current)
|
||||||
|
}
|
||||||
|
}, [checkInterval]),
|
||||||
|
checkInterval
|
||||||
|
)
|
||||||
|
|
||||||
|
return deferredValue
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
import { useFrontendConfig } from '../../components/common/frontend-config-context/use-frontend-config'
|
import { useFrontendConfig } from '../../components/common/frontend-config-context/use-frontend-config'
|
||||||
import { useApplicationState } from './use-application-state'
|
import { useApplicationState } from './use-application-state'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
import { useDeferredState } from './use-deferred-state'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the markdown content from the global application state trimmed to the maximal note length and without the frontmatter lines.
|
* Returns the markdown content from the global application state trimmed to the maximal note length and without the frontmatter lines.
|
||||||
|
@ -28,7 +29,8 @@ export const useTrimmedNoteMarkdownContentWithoutFrontmatter = (): string[] => {
|
||||||
}
|
}
|
||||||
}, [markdownContent, maxLength])
|
}, [markdownContent, maxLength])
|
||||||
|
|
||||||
return useMemo(() => {
|
return useDeferredState(
|
||||||
return trimmedLines.slice(lineOffset)
|
useMemo(() => trimmedLines.slice(lineOffset), [lineOffset, trimmedLines]),
|
||||||
}, [lineOffset, trimmedLines])
|
[]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue