Fix issue where a page reload would cause the content of text notes to be missing
All checks were successful
/ Push Docker image to local registry (push) Successful in 2m58s

I hate libraries that do weird things and expect weird stuff... Lexical
talking about you here...
This commit is contained in:
kalle 2025-04-15 22:15:13 +02:00
parent aa0fa074a1
commit bf2519b45a
3 changed files with 45 additions and 30 deletions

View file

@ -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<string, Y.Doc>): 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<string, Y.Doc>): Provider => {
// Just overwrite it, because we have the doc managed externally
yjsDocMap.set(id, doc);
return provider as any as Provider;
}, [provider, doc]);
return (
<LexicalComposer initialConfig={initialEditorConfig}>

View file

@ -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;
}

View file

@ -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 (
<NoteProvider id={id}>
<Content id={id} />
</NoteProvider>
);
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 <>
<NoteHeader id={id} />
<div className="flex-shrink-0 min-h-full max-w-3xl mx-auto w-full">
<Editor noteId={id} />
</div>
</>
}
return <NoteProvider id={id}>
<Content id={id} type={type} />
</NoteProvider>;
}
function Content(props: { id: string }) {
const metadata = useNoteMetadata(props.id);
switch (metadata?.get("type")) {
case "text": return <>
<NoteHeader id={props.id} />
<div className="flex-shrink-0 min-h-full max-w-3xl mx-auto w-full">
<Editor noteId={props.id} />
</div>
</>;
function Content(props: { id: string, type?: NoteType }) {
switch (props.type) {
case "canvas": return <>
<NoteCanvas noteId={props.id} />
</>;