From bf2519b45a8f7adb2d75a431e7f0f64d5643d9cb Mon Sep 17 00:00:00 2001 From: Kalle Struik Date: Tue, 15 Apr 2025 22:15:13 +0200 Subject: [PATCH] Fix issue where a page reload would cause the content of text notes to be missing I hate libraries that do weird things and expect weird stuff... Lexical talking about you here... --- frontend/src/editor/Editor.tsx | 23 ++++++++++--------- frontend/src/hooks/use-ydoc.ts | 18 +++++++++++---- frontend/src/routes/app/note.$id.tsx | 34 ++++++++++++++++------------ 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/frontend/src/editor/Editor.tsx b/frontend/src/editor/Editor.tsx index daa2e8c..c0932ff 100644 --- a/frontend/src/editor/Editor.tsx +++ b/frontend/src/editor/Editor.tsx @@ -16,22 +16,23 @@ import { LinkIconNode, LinkMarkerNode, LinkNode, LinkUrlNode } from "./nodes/lin import { LinkPlugin } from "./plugins/link_plugin"; import { TermIconNode, TermMarkerNode, TermNode } from "./nodes/term_node"; import { TermPlugin } from "./plugins/term_plugin"; -import { useCallback } from "react"; import type { Provider } from "@lexical/yjs"; import type { NoteId } from "~/lib/metadata"; import type { Klass, LexicalNode } from "lexical"; -import { useNoteDoc, useNoteProviders } from "~/hooks/use-note"; +import { createProviders } from "~/hooks/use-ydoc"; + +function providerFactory(id: string, yjsDocMap: Map): Provider { + let doc = yjsDocMap.get(id) + if (!doc) { + doc = new Y.Doc(); + yjsDocMap.set(id, doc); + } + const [_, websocketProvider] = createProviders(id, doc); + + return websocketProvider as any as Provider; +} export function Editor(props: { noteId: NoteId }) { - const provider = useNoteProviders().websocket; - const doc = useNoteDoc(); - - const providerFactory = useCallback((id: string, yjsDocMap: Map): Provider => { - // Just overwrite it, because we have the doc managed externally - yjsDocMap.set(id, doc); - - return provider as any as Provider; - }, [provider, doc]); return ( diff --git a/frontend/src/hooks/use-ydoc.ts b/frontend/src/hooks/use-ydoc.ts index 4680f38..aa5f985 100644 --- a/frontend/src/hooks/use-ydoc.ts +++ b/frontend/src/hooks/use-ydoc.ts @@ -13,12 +13,10 @@ export function useYDoc(name: string) { return } - const indexeddbProvider = new IndexeddbPersistence(name, ydoc); + const [indexeddbProvider, websocketProvider] = createProviders(name, ydoc); + // Connect the websocket provider. This is not done by default because of lexical. + websocketProvider.connect(); setIndexeddbProvider(indexeddbProvider); - - const websocketProvider = new WebsocketProvider(`/sync`, name, ydoc, { - connect: true, - }); setWebsocketProvider(websocketProvider); return () => { @@ -30,3 +28,13 @@ export function useYDoc(name: string) { return { ydoc, indexeddbProvider, websocketProvider }; } + +export function createProviders(name: string, doc: Y.Doc) { + const indexeddbProvider = new IndexeddbPersistence(name, doc); + const websocketProvider = new WebsocketProvider(`/sync`, name, doc, { + connect: false, + }); + + + return [indexeddbProvider, websocketProvider] as const; +} diff --git a/frontend/src/routes/app/note.$id.tsx b/frontend/src/routes/app/note.$id.tsx index e137d12..b7c8fd0 100644 --- a/frontend/src/routes/app/note.$id.tsx +++ b/frontend/src/routes/app/note.$id.tsx @@ -4,6 +4,7 @@ import { NoteHeader } from "~/components/note/note_header"; import { Editor } from "~/editor/Editor"; import { useNoteMetadata } from "~/hooks/use-metadata"; import { NoteProvider } from "~/hooks/use-note"; +import type { NoteType } from "~/lib/metadata"; export const Route = createFileRoute("/app/note/$id")({ component: RouteComponent, @@ -11,23 +12,28 @@ export const Route = createFileRoute("/app/note/$id")({ function RouteComponent() { const { id } = Route.useParams(); - return ( - - - - ); + const metadata = useNoteMetadata(id); + const type = metadata?.get("type"); + + // Lexical is special and needs to be created before any provider, otherwise + // it won't load the doc correctly... + if (type == "text") { + return <> + +
+ +
+ + } + + return + + ; } -function Content(props: { id: string }) { - const metadata = useNoteMetadata(props.id); - switch (metadata?.get("type")) { - case "text": return <> - -
- -
- ; +function Content(props: { id: string, type?: NoteType }) { + switch (props.type) { case "canvas": return <> ;