chore(react/type_widget): persist data

This commit is contained in:
Elian Doran
2025-09-20 22:22:20 +03:00
parent 02259c55f3
commit 143e6a556c
3 changed files with 52 additions and 16 deletions

View File

@@ -107,7 +107,10 @@ export function useEditorSpacedUpdate({ note, getData, onContentChange, dataSave
}, [ blob ]); }, [ blob ]);
// React to update interval changes. // React to update interval changes.
useEffect(() => spacedUpdate.setUpdateInterval(updateInterval), [ updateInterval ]); useEffect(() => {
if (!updateInterval) return;
spacedUpdate.setUpdateInterval(updateInterval);
}, [ updateInterval ]);
return spacedUpdate; return spacedUpdate;
} }

View File

@@ -1,12 +1,13 @@
import { useCallback, useEffect, useRef } from "preact/hooks"; import { useCallback, useEffect, useRef } from "preact/hooks";
import { TypeWidgetProps } from "./type_widget"; import { TypeWidgetProps } from "./type_widget";
import { MindElixirData, default as VanillaMindElixir } from "mind-elixir"; import { MindElixirData, MindElixirInstance, Operation, default as VanillaMindElixir } from "mind-elixir";
import { HTMLAttributes } from "preact"; import { HTMLAttributes, RefObject } from "preact";
// allow node-menu plugin css to be bundled by webpack // allow node-menu plugin css to be bundled by webpack
import nodeMenu from "@mind-elixir/node-menu"; import nodeMenu from "@mind-elixir/node-menu";
import "mind-elixir/style"; import "mind-elixir/style";
import "@mind-elixir/node-menu/dist/style.css"; import "@mind-elixir/node-menu/dist/style.css";
import "./MindMap.css"; import "./MindMap.css";
import { useEditorSpacedUpdate } from "../react/hooks";
const NEW_TOPIC_NAME = ""; const NEW_TOPIC_NAME = "";
@@ -15,13 +16,34 @@ interface MindmapModel extends MindElixirData {
} }
interface MindElixirProps { interface MindElixirProps {
apiRef?: RefObject<MindElixirInstance>;
direction: number; direction: number;
containerProps?: Omit<HTMLAttributes<HTMLDivElement>, "ref">; containerProps?: Omit<HTMLAttributes<HTMLDivElement>, "ref">;
content: MindElixirData; content: MindElixirData;
onChange?: () => void;
} }
export default function MindMap({ }: TypeWidgetProps) { export default function MindMap({ note }: TypeWidgetProps) {
const content = VanillaMindElixir.new(NEW_TOPIC_NAME); const content = VanillaMindElixir.new(NEW_TOPIC_NAME);
const apiRef = useRef<MindElixirInstance>(null);
const spacedUpdate = useEditorSpacedUpdate({
note,
getData: () => ({ content: apiRef.current?.getDataString() }),
onContentChange: (content) => {
let newContent: MindElixirData;
if (content) {
try {
newContent = JSON.parse(content) as MindmapModel;
} catch (e) {
console.warn(e);
console.debug("Wrong JSON content: ", content);
}
} else {
newContent = VanillaMindElixir.new(NEW_TOPIC_NAME)
}
apiRef.current?.init(newContent!);
}
});
const onKeyDown = useCallback((e: KeyboardEvent) => { const onKeyDown = useCallback((e: KeyboardEvent) => {
/* /*
@@ -42,7 +64,9 @@ export default function MindMap({ }: TypeWidgetProps) {
return ( return (
<div className="note-detail-mind-map note-detail-printable"> <div className="note-detail-mind-map note-detail-printable">
<MindElixir <MindElixir
apiRef={apiRef}
content={content} content={content}
onChange={() => spacedUpdate.scheduleUpdate()}
containerProps={{ containerProps={{
className: "mind-map-container", className: "mind-map-container",
onKeyDown onKeyDown
@@ -52,8 +76,9 @@ export default function MindMap({ }: TypeWidgetProps) {
) )
} }
function MindElixir({ content, containerProps, direction }: MindElixirProps) { function MindElixir({ content, containerProps, direction, apiRef: externalApiRef, onChange }: MindElixirProps) {
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const apiRef = useRef<MindElixirInstance>(null);
useEffect(() => { useEffect(() => {
if (!containerRef.current) return; if (!containerRef.current) return;
@@ -66,12 +91,28 @@ function MindElixir({ content, containerProps, direction }: MindElixirProps) {
mind.install(nodeMenu); mind.install(nodeMenu);
mind.init(content); mind.init(content);
apiRef.current = mind;
if (externalApiRef) {
externalApiRef.current = mind;
}
return () => mind.destroy(); return () => mind.destroy();
}, []); }, []);
return ( // On change listener.
<div ref={containerRef} {...containerProps}> useEffect(() => {
if (!onChange) return;
</div> const listener = (operation: Operation) => {
if (operation.name !== "beginEdit") {
onChange();
}
}
apiRef.current?.bus.addListener("operation", listener);
return () => apiRef.current?.bus?.removeListener("operation", listener);
}, [ onChange ]);
return (
<div ref={containerRef} {...containerProps} />
) )
} }

View File

@@ -55,14 +55,6 @@ export default class MindMapWidget extends TypeWidget {
}); });
this.mind = mind; this.mind = mind;
mind.init(this.MindElixir.new(NEW_TOPIC_NAME));
// TODO: See why the typeof mindmap is not correct.
mind.bus.addListener("operation", (operation: { name: string }) => {
this.triggeredByUserOperation = true;
if (operation.name !== "beginEdit") {
this.spacedUpdate.scheduleUpdate();
}
});
} }
async getData() { async getData() {