diff options
| author | kj_sh604 | 2026-03-15 16:19:35 -0400 |
|---|---|---|
| committer | kj_sh604 | 2026-03-15 16:19:35 -0400 |
| commit | 6ec259a0e71174651bae95d4628138bf6fd68742 (patch) | |
| tree | 5e33c6a5ec091ecabfcb257fdc7b6a88ed8754ac /packages/excalidraw/components/TTDDialog/MermaidToExcalidraw.tsx | |
| parent | 16c8578b15c727f22921f8a80a56ee4d4e7f2272 (diff) | |
refactor: packages/
Diffstat (limited to 'packages/excalidraw/components/TTDDialog/MermaidToExcalidraw.tsx')
| -rw-r--r-- | packages/excalidraw/components/TTDDialog/MermaidToExcalidraw.tsx | 132 |
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; |
