aboutsummaryrefslogtreecommitdiffstats
path: root/packages/excalidraw/components/TTDDialog/MermaidToExcalidraw.tsx
diff options
context:
space:
mode:
authorkj_sh6042026-03-15 16:19:35 -0400
committerkj_sh6042026-03-15 16:19:35 -0400
commit6ec259a0e71174651bae95d4628138bf6fd68742 (patch)
tree5e33c6a5ec091ecabfcb257fdc7b6a88ed8754ac /packages/excalidraw/components/TTDDialog/MermaidToExcalidraw.tsx
parent16c8578b15c727f22921f8a80a56ee4d4e7f2272 (diff)
refactor: packages/
Diffstat (limited to 'packages/excalidraw/components/TTDDialog/MermaidToExcalidraw.tsx')
-rw-r--r--packages/excalidraw/components/TTDDialog/MermaidToExcalidraw.tsx132
1 files changed, 132 insertions, 0 deletions
diff --git a/packages/excalidraw/components/TTDDialog/MermaidToExcalidraw.tsx b/packages/excalidraw/components/TTDDialog/MermaidToExcalidraw.tsx
new file mode 100644
index 0000000..83fb91d
--- /dev/null
+++ b/packages/excalidraw/components/TTDDialog/MermaidToExcalidraw.tsx
@@ -0,0 +1,132 @@
+import { useState, useRef, useEffect, useDeferredValue } from "react";
+import type { BinaryFiles } from "../../types";
+import { useApp } from "../App";
+import type { NonDeletedExcalidrawElement } from "../../element/types";
+import { ArrowRightIcon } from "../icons";
+import "./MermaidToExcalidraw.scss";
+import { t } from "../../i18n";
+import Trans from "../Trans";
+import type { MermaidToExcalidrawLibProps } from "./common";
+import {
+ convertMermaidToExcalidraw,
+ insertToEditor,
+ saveMermaidDataToStorage,
+} from "./common";
+import { TTDDialogPanels } from "./TTDDialogPanels";
+import { TTDDialogPanel } from "./TTDDialogPanel";
+import { TTDDialogInput } from "./TTDDialogInput";
+import { TTDDialogOutput } from "./TTDDialogOutput";
+import { EditorLocalStorage } from "../../data/EditorLocalStorage";
+import { EDITOR_LS_KEYS } from "../../constants";
+import { debounce, isDevEnv } from "../../utils";
+import { TTDDialogSubmitShortcut } from "./TTDDialogSubmitShortcut";
+
+const MERMAID_EXAMPLE =
+ "flowchart TD\n A[Christmas] -->|Get money| B(Go shopping)\n B --> C{Let me think}\n C -->|One| D[Laptop]\n C -->|Two| E[iPhone]\n C -->|Three| F[Car]";
+
+const debouncedSaveMermaidDefinition = debounce(saveMermaidDataToStorage, 300);
+
+const MermaidToExcalidraw = ({
+ mermaidToExcalidrawLib,
+}: {
+ mermaidToExcalidrawLib: MermaidToExcalidrawLibProps;
+}) => {
+ const [text, setText] = useState(
+ () =>
+ EditorLocalStorage.get<string>(EDITOR_LS_KEYS.MERMAID_TO_EXCALIDRAW) ||
+ MERMAID_EXAMPLE,
+ );
+ const deferredText = useDeferredValue(text.trim());
+ const [error, setError] = useState<Error | null>(null);
+
+ const canvasRef = useRef<HTMLDivElement>(null);
+ const data = useRef<{
+ elements: readonly NonDeletedExcalidrawElement[];
+ files: BinaryFiles | null;
+ }>({ elements: [], files: null });
+
+ const app = useApp();
+
+ useEffect(() => {
+ convertMermaidToExcalidraw({
+ canvasRef,
+ data,
+ mermaidToExcalidrawLib,
+ setError,
+ mermaidDefinition: deferredText,
+ }).catch((err) => {
+ if (isDevEnv()) {
+ console.error("Failed to parse mermaid definition", err);
+ }
+ });
+
+ debouncedSaveMermaidDefinition(deferredText);
+ }, [deferredText, mermaidToExcalidrawLib]);
+
+ useEffect(
+ () => () => {
+ debouncedSaveMermaidDefinition.flush();
+ },
+ [],
+ );
+
+ const onInsertToEditor = () => {
+ insertToEditor({
+ app,
+ data,
+ text,
+ shouldSaveMermaidDataToStorage: true,
+ });
+ };
+
+ return (
+ <>
+ <div className="ttd-dialog-desc">
+ <Trans
+ i18nKey="mermaid.description"
+ flowchartLink={(el) => (
+ <a href="https://mermaid.js.org/syntax/flowchart.html">{el}</a>
+ )}
+ sequenceLink={(el) => (
+ <a href="https://mermaid.js.org/syntax/sequenceDiagram.html">
+ {el}
+ </a>
+ )}
+ classLink={(el) => (
+ <a href="https://mermaid.js.org/syntax/classDiagram.html">{el}</a>
+ )}
+ />
+ </div>
+ <TTDDialogPanels>
+ <TTDDialogPanel label={t("mermaid.syntax")}>
+ <TTDDialogInput
+ input={text}
+ placeholder={"Write Mermaid diagram defintion here..."}
+ onChange={(event) => setText(event.target.value)}
+ onKeyboardSubmit={() => {
+ onInsertToEditor();
+ }}
+ />
+ </TTDDialogPanel>
+ <TTDDialogPanel
+ label={t("mermaid.preview")}
+ panelAction={{
+ action: () => {
+ onInsertToEditor();
+ },
+ label: t("mermaid.button"),
+ icon: ArrowRightIcon,
+ }}
+ renderSubmitShortcut={() => <TTDDialogSubmitShortcut />}
+ >
+ <TTDDialogOutput
+ canvasRef={canvasRef}
+ loaded={mermaidToExcalidrawLib.loaded}
+ error={error}
+ />
+ </TTDDialogPanel>
+ </TTDDialogPanels>
+ </>
+ );
+};
+export default MermaidToExcalidraw;