{"version":3,"file":"excalidraw-component-C5Za8rqo.cjs","sources":["../src/components/editor/editor-ui/excalidraw-image.tsx","../src/components/editor/editor-ui/excalidraw-component.tsx"],"sourcesContent":["import { useEffect, useState, JSX } from \"react\";\n\nimport { exportToSvg } from \"@excalidraw/excalidraw\";\nimport type { AppState, BinaryFiles } from \"@excalidraw/excalidraw/types\";\n// @ts-ignore\nimport type { ExcalidrawElement } from \"@excalidraw/excalidraw/types/element/types\";\n\ntype NonDeleted<T> = T & { isDeleted?: false };\n\ntype ImageType = \"svg\" | \"canvas\";\n\ntype Dimension = \"inherit\" | number;\n\ntype Props = {\n  /**\n   * Configures the export setting for SVG/Canvas\n   */\n  appState: AppState;\n  /**\n   * The css class applied to image to be rendered\n   */\n  className?: string;\n  /**\n   * The Excalidraw elements to be rendered as an image\n   */\n  elements: NonDeleted<ExcalidrawElement>[];\n  /**\n   * The Excalidraw files associated with the elements\n   */\n  files: BinaryFiles;\n  /**\n   * The height of the image to be rendered\n   */\n  height?: Dimension;\n  /**\n   * The ref object to be used to render the image\n   */\n  imageContainerRef: React.MutableRefObject<HTMLDivElement | null>;\n  /**\n   * The type of image to be rendered\n   */\n  imageType?: ImageType;\n  /**\n   * The css class applied to the root element of this component\n   */\n  rootClassName?: string | null;\n  /**\n   * The width of the image to be rendered\n   */\n  width?: Dimension;\n};\n\n// exportToSvg has fonts from excalidraw.com\n// We don't want them to be used in open source\nconst removeStyleFromSvg_HACK = (svg: SVGElement) => {\n  const styleTag = svg?.firstElementChild?.firstElementChild;\n\n  // Generated SVG is getting double-sized by height and width attributes\n  // We want to match the real size of the SVG element\n  const viewBox = svg.getAttribute(\"viewBox\");\n  if (viewBox != null) {\n    const viewBoxDimensions = viewBox.split(\" \");\n    svg.setAttribute(\"width\", viewBoxDimensions[2]);\n    svg.setAttribute(\"height\", viewBoxDimensions[3]);\n  }\n\n  if (styleTag && styleTag.tagName === \"style\") {\n    styleTag.remove();\n  }\n};\n\n/**\n * @explorer-desc\n * A component for rendering Excalidraw elements as a static image\n */\nexport default function ExcalidrawImage({\n  elements,\n  files,\n  imageContainerRef,\n  appState,\n  rootClassName = null,\n  width = \"inherit\",\n  height = \"inherit\",\n}: Props): JSX.Element {\n  const [Svg, setSvg] = useState<SVGElement | null>(null);\n\n  useEffect(() => {\n    const setContent = async () => {\n      const svg: SVGElement = await exportToSvg({\n        appState,\n        elements,\n        files,\n      });\n      removeStyleFromSvg_HACK(svg);\n\n      svg.setAttribute(\"width\", \"100%\");\n      svg.setAttribute(\"height\", \"100%\");\n      svg.setAttribute(\"display\", \"block\");\n\n      setSvg(svg);\n    };\n    setContent();\n  }, [elements, files, appState]);\n\n  const containerStyle: React.CSSProperties = {};\n  if (width !== \"inherit\") {\n    containerStyle.width = `${width}px`;\n  }\n  if (height !== \"inherit\") {\n    containerStyle.height = `${height}px`;\n  }\n\n  return (\n    <div\n      ref={(node) => {\n        if (node) {\n          if (imageContainerRef) {\n            imageContainerRef.current = node;\n          }\n        }\n      }}\n      className={rootClassName ?? \"\"}\n      style={containerStyle}\n      dangerouslySetInnerHTML={{ __html: Svg?.outerHTML ?? \"\" }}\n    />\n  );\n}\n","import { useCallback, useEffect, useMemo, useRef, useState, JSX } from \"react\";\n\nimport { AppState, BinaryFiles } from \"@excalidraw/excalidraw/types\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport { useLexicalEditable } from \"@lexical/react/useLexicalEditable\";\nimport { useLexicalNodeSelection } from \"@lexical/react/useLexicalNodeSelection\";\nimport { mergeRegister } from \"@lexical/utils\";\nimport type { NodeKey } from \"lexical\";\nimport {\n  $getNodeByKey,\n  CLICK_COMMAND,\n  COMMAND_PRIORITY_LOW,\n  KEY_BACKSPACE_COMMAND,\n  KEY_DELETE_COMMAND,\n} from \"lexical\";\n\nimport { $isExcalidrawNode } from \"@/components/editor/nodes/excalidraw-node\";\nimport ExcalidrawImage from \"@/components/editor/editor-ui/excalidraw-image\";\nimport type { ExcalidrawInitialElements } from \"@/components/editor/editor-ui/excalidraw-modal\";\nimport { ExcalidrawModal } from \"@/components/editor/editor-ui/excalidraw-modal\";\nimport { ImageResizer } from \"@/components/editor/editor-ui/image-resizer\";\n\nexport default function ExcalidrawComponent({\n  nodeKey,\n  data,\n  width,\n  height,\n}: {\n  data: string;\n  nodeKey: NodeKey;\n  width: \"inherit\" | number;\n  height: \"inherit\" | number;\n}): JSX.Element {\n  const [editor] = useLexicalComposerContext();\n  const isEditable = useLexicalEditable();\n  const [isModalOpen, setModalOpen] = useState<boolean>(\n    data === \"[]\" && editor.isEditable()\n  );\n  const imageContainerRef = useRef<HTMLDivElement | null>(null);\n  const buttonRef = useRef<HTMLButtonElement | null>(null);\n  const captionButtonRef = useRef<HTMLButtonElement | null>(null);\n  const [isSelected, setSelected, clearSelection] =\n    useLexicalNodeSelection(nodeKey);\n  const [isResizing, setIsResizing] = useState<boolean>(false);\n\n  const $onDelete = useCallback(\n    (event: KeyboardEvent) => {\n      if (isSelected) {\n        event.preventDefault();\n        editor.update(() => {\n          const node = $getNodeByKey(nodeKey);\n          if (node) {\n            node.remove();\n          }\n        });\n      }\n      return false;\n    },\n    [editor, isSelected, nodeKey]\n  );\n\n  useEffect(() => {\n    if (!isEditable) {\n      if (isSelected) {\n        clearSelection();\n      }\n      return;\n    }\n    return mergeRegister(\n      editor.registerCommand(\n        CLICK_COMMAND,\n        (event: MouseEvent) => {\n          const buttonElem = buttonRef.current;\n          const eventTarget = event.target;\n\n          if (isResizing) {\n            return true;\n          }\n\n          if (buttonElem !== null && buttonElem.contains(eventTarget as Node)) {\n            if (!event.shiftKey) {\n              clearSelection();\n            }\n            setSelected(!isSelected);\n            if (event.detail > 1) {\n              setModalOpen(true);\n            }\n            return true;\n          }\n\n          return false;\n        },\n        COMMAND_PRIORITY_LOW\n      ),\n      editor.registerCommand(\n        KEY_DELETE_COMMAND,\n        $onDelete,\n        COMMAND_PRIORITY_LOW\n      ),\n      editor.registerCommand(\n        KEY_BACKSPACE_COMMAND,\n        $onDelete,\n        COMMAND_PRIORITY_LOW\n      )\n    );\n  }, [\n    clearSelection,\n    editor,\n    isSelected,\n    isResizing,\n    $onDelete,\n    setSelected,\n    isEditable,\n  ]);\n\n  const deleteNode = useCallback(() => {\n    setModalOpen(false);\n    return editor.update(() => {\n      const node = $getNodeByKey(nodeKey);\n      if (node) {\n        node.remove();\n      }\n    });\n  }, [editor, nodeKey]);\n\n  const setData = (\n    els: ExcalidrawInitialElements,\n    aps: Partial<AppState>,\n    fls: BinaryFiles\n  ) => {\n    return editor.update(() => {\n      const node = $getNodeByKey(nodeKey);\n      if ($isExcalidrawNode(node)) {\n        if ((els && els.length > 0) || Object.keys(fls).length > 0) {\n          node.setData(\n            JSON.stringify({\n              appState: aps,\n              elements: els,\n              files: fls,\n            })\n          );\n        } else {\n          node.remove();\n        }\n      }\n    });\n  };\n\n  const onResizeStart = () => {\n    setIsResizing(true);\n  };\n\n  const onResizeEnd = (\n    nextWidth: \"inherit\" | number,\n    nextHeight: \"inherit\" | number\n  ) => {\n    // Delay hiding the resize bars for click case\n    setTimeout(() => {\n      setIsResizing(false);\n    }, 200);\n\n    editor.update(() => {\n      const node = $getNodeByKey(nodeKey);\n\n      if ($isExcalidrawNode(node)) {\n        node.setWidth(nextWidth);\n        node.setHeight(nextHeight);\n      }\n    });\n  };\n\n  const openModal = useCallback(() => {\n    setModalOpen(true);\n  }, []);\n\n  const {\n    elements = [],\n    files = {},\n    appState = {},\n  } = useMemo(() => JSON.parse(data), [data]);\n\n  const closeModal = useCallback(() => {\n    setModalOpen(false);\n    if (elements.length === 0) {\n      editor.update(() => {\n        const node = $getNodeByKey(nodeKey);\n        if (node) {\n          node.remove();\n        }\n      });\n    }\n  }, [editor, nodeKey, elements.length]);\n\n  return (\n    <>\n      {isEditable && isModalOpen && (\n        <ExcalidrawModal\n          initialElements={elements}\n          initialFiles={files}\n          initialAppState={appState}\n          isShown={isModalOpen}\n          onDelete={deleteNode}\n          onClose={closeModal}\n          onSave={(els, aps, fls) => {\n            setData(els, aps, fls);\n            setModalOpen(false);\n          }}\n          closeOnClickOutside={false}\n        />\n      )}\n      {elements.length > 0 && (\n        <button\n          ref={buttonRef}\n          className={`m-0 border-0 bg-transparent p-0 ${\n            isSelected\n              ? \"user-select-none ring-2 ring-primary ring-offset-2\"\n              : \"\"\n          }`}\n        >\n          <ExcalidrawImage\n            imageContainerRef={imageContainerRef}\n            className=\"image\"\n            elements={elements}\n            files={files}\n            appState={appState}\n            width={width}\n            height={height}\n          />\n          {isSelected && isEditable && (\n            <div\n              className=\"image-edit-button\"\n              role=\"button\"\n              tabIndex={0}\n              onMouseDown={(event) => event.preventDefault()}\n              onClick={openModal}\n            />\n          )}\n          {(isSelected || isResizing) && isEditable && (\n            <ImageResizer\n              buttonRef={captionButtonRef}\n              showCaption={true}\n              setShowCaption={() => null}\n              imageRef={imageContainerRef}\n              editor={editor}\n              onResizeStart={onResizeStart}\n              onResizeEnd={onResizeEnd}\n              captionsEnabled={true}\n            />\n          )}\n        </button>\n      )}\n    </>\n  );\n}\n"],"names":["ExcalidrawImage","elements","files","imageContainerRef","appState","rootClassName","width","height","Svg","setSvg","useState","useEffect","async","svg","exportToSvg","styleTag","firstElementChild","viewBox","getAttribute","viewBoxDimensions","split","setAttribute","tagName","remove","removeStyleFromSvg_HACK","setContent","containerStyle","jsxRuntime","jsx","ref","node","current","className","style","dangerouslySetInnerHTML","__html","outerHTML","nodeKey","data","editor","useLexicalComposerContext","isEditable","useLexicalEditable","isModalOpen","setModalOpen","useRef","buttonRef","captionButtonRef","isSelected","setSelected","clearSelection","useLexicalNodeSelection","isResizing","setIsResizing","$onDelete","useCallback","event","preventDefault","update","$getNodeByKey","mergeRegister","registerCommand","CLICK_COMMAND","buttonElem","eventTarget","target","contains","shiftKey","detail","COMMAND_PRIORITY_LOW","KEY_DELETE_COMMAND","KEY_BACKSPACE_COMMAND","deleteNode","openModal","useMemo","JSON","parse","closeModal","length","jsxs","Fragment","children","ExcalidrawModal","initialElements","initialFiles","initialAppState","isShown","onDelete","onClose","onSave","els","aps","fls","$isExcalidrawNode","Object","keys","setData","stringify","closeOnClickOutside","role","tabIndex","onMouseDown","onClick","ImageResizer","showCaption","setShowCaption","imageRef","onResizeStart","onResizeEnd","nextWidth","nextHeight","setTimeout","setWidth","setHeight","captionsEnabled"],"mappings":"ySA2EA,SAAwBA,GAAgBC,SACtCA,EAAAC,MACAA,EAAAC,kBACAA,EAAAC,SACAA,EAAAC,cACAA,EAAgB,KAAAC,MAChBA,EAAQ,UAAAC,OACRA,EAAS,YAET,MAAOC,EAAKC,GAAUC,EAAAA,SAA4B,MAElDC,EAAAA,UAAU,KACWC,WACX,MAAAC,QAAwBC,cAAY,CACxCV,WACAH,WACAC,UArCwB,CAACW,IACzB,MAAAE,EAAWF,GAAKG,mBAAmBA,kBAInCC,EAAUJ,EAAIK,aAAa,WACjC,GAAe,MAAXD,EAAiB,CACb,MAAAE,EAAoBF,EAAQG,MAAM,KACxCP,EAAIQ,aAAa,QAASF,EAAkB,IAC5CN,EAAIQ,aAAa,SAAUF,EAAkB,GAAE,CAG7CJ,GAAiC,UAArBA,EAASO,SACvBP,EAASQ,UA0BPC,CAAwBX,GAEpBA,EAAAQ,aAAa,QAAS,QACtBR,EAAAQ,aAAa,SAAU,QACvBR,EAAAQ,aAAa,UAAW,SAE5BZ,EAAOI,IAEEY,IACV,CAACxB,EAAUC,EAAOE,IAErB,MAAMsB,EAAsC,CAAC,EAS3C,MARY,YAAVpB,IACaoB,EAAApB,MAAQ,GAAGA,OAEb,YAAXC,IACamB,EAAAnB,OAAS,GAAGA,OAI3BoB,EAAAC,IAAC,MAAA,CACCC,IAAMC,IACAA,GACE3B,IACFA,EAAkB4B,QAAUD,IAIlCE,UAAW3B,GAAiB,GAC5B4B,MAAOP,EACPQ,wBAAyB,CAAEC,OAAQ3B,GAAK4B,WAAa,KAG3D,iBCxGA,UAA4CC,QAC1CA,EAAAC,KACAA,EAAAhC,MACAA,EAAAC,OACAA,IAOM,MAACgC,GAAUC,MACXC,EAAaC,EAAAA,KACZC,EAAaC,GAAgBlC,EAAAA,SACzB,OAAT4B,GAAiBC,EAAOE,cAEpBtC,EAAoB0C,SAA8B,MAClDC,EAAYD,SAAiC,MAC7CE,EAAmBF,SAAiC,OACnDG,EAAYC,EAAaC,GAC9BC,EAAAA,EAAwBd,IACnBe,EAAYC,GAAiB3C,EAAAA,UAAkB,GAEhD4C,EAAYC,EAAAA,YACfC,IACKR,IACFQ,EAAMC,iBACNlB,EAAOmB,OAAO,KACN,MAAA5B,EAAO6B,gBAActB,GACvBP,GACFA,EAAKP,aAIJ,GAET,CAACgB,EAAQS,EAAYX,IAGvB1B,EAAAA,UAAU,KACR,GAAK8B,EAME,OAAAmB,EAAAA,cACLrB,EAAOsB,gBACLC,EAAAA,cACCN,IACC,MAAMO,EAAajB,EAAUf,QACvBiC,EAAcR,EAAMS,OAE1B,QAAIb,KAIe,OAAfW,IAAuBA,EAAWG,SAASF,MACxCR,EAAMW,UACMjB,IAEjBD,GAAaD,GACTQ,EAAMY,OAAS,GACjBxB,GAAa,IAER,IAKXyB,EAAAA,sBAEF9B,EAAOsB,gBACLS,EAAAA,mBACAhB,EACAe,EAAAA,sBAEF9B,EAAOsB,gBACLU,EAAAA,sBACAjB,EACAe,EAAAA,uBAvCErB,GACaE,KAyClB,CACDA,EACAX,EACAS,EACAI,EACAE,EACAL,EACAR,IAGI,MAAA+B,EAAajB,EAAAA,YAAY,KAC7BX,GAAa,GACNL,EAAOmB,OAAO,KACb,MAAA5B,EAAO6B,gBAActB,GACvBP,GACFA,EAAKP,YAGR,CAACgB,EAAQF,IAgDNoC,EAAYlB,EAAAA,YAAY,KAC5BX,GAAa,IACZ,KAEG3C,SACJA,EAAW,GAACC,MACZA,EAAQ,CAAC,EAAAE,SACTA,EAAW,CAAA,GACTsE,EAAAA,QAAQ,IAAMC,KAAKC,MAAMtC,GAAO,CAACA,IAE/BuC,EAAatB,EAAAA,YAAY,KAC7BX,GAAa,GACW,IAApB3C,EAAS6E,QACXvC,EAAOmB,OAAO,KACN,MAAA5B,EAAO6B,gBAActB,GACvBP,GACFA,EAAKP,YAIV,CAACgB,EAAQF,EAASpC,EAAS6E,SAE9B,OAEKnD,EAAAoD,KAAAC,WAAA,CAAAC,SAAA,CAAAxC,GAAcE,GACbhB,EAAAC,IAACsD,EAAAA,gBAAA,CACCC,gBAAiBlF,EACjBmF,aAAclF,EACdmF,gBAAiBjF,EACjBkF,QAAS3C,EACT4C,SAAUf,EACVgB,QAASX,EACTY,OAAQ,CAACC,EAAKC,EAAKC,KA9EX,EACdF,EACAC,EACAC,KAEOrD,EAAOmB,OAAO,KACb,MAAA5B,EAAO6B,gBAActB,GACvBwD,EAAAA,kBAAkB/D,KACf4D,GAAOA,EAAIZ,OAAS,GAAMgB,OAAOC,KAAKH,GAAKd,OAAS,EAClDhD,EAAAkE,QACHrB,KAAKsB,UAAU,CACb7F,SAAUuF,EACV1F,SAAUyF,EACVxF,MAAO0F,KAIX9D,EAAKP,aA8DKyE,CAAAN,EAAKC,EAAKC,GAClBhD,GAAa,IAEfsD,qBAAqB,IAGxBjG,EAAS6E,OAAS,GACjBnD,EAAAoD,KAAC,SAAA,CACClD,IAAKiB,EACLd,UAAW,oCACTgB,EACI,qDACA,IAGNiC,SAAA,CAAAtD,EAAAC,IAAC5B,EAAA,CACCG,oBACA6B,UAAU,QACV/B,WACAC,QACAE,WACAE,QACAC,WAEDyC,GAAcP,GACbd,EAAAC,IAAC,MAAA,CACCI,UAAU,oBACVmE,KAAK,SACLC,SAAU,EACVC,YAAc7C,GAAUA,EAAMC,iBAC9B6C,QAAS7B,KAGXzB,GAAcI,IAAeX,GAC7Bd,EAAAC,IAAC2E,EAAAA,aAAA,CACCzD,UAAWC,EACXyD,aAAa,EACbC,eAAgB,IAAM,KACtBC,SAAUvG,EACVoC,SACAoE,cAhGU,KACpBtD,GAAc,IAgGJuD,YA7FQ,CAClBC,EACAC,KAGAC,WAAW,KACT1D,GAAc,IACb,KAEHd,EAAOmB,OAAO,KACN,MAAA5B,EAAO6B,gBAActB,GAEvBwD,EAAAA,kBAAkB/D,KACpBA,EAAKkF,SAASH,GACd/E,EAAKmF,UAAUH,OAgFTI,iBAAiB,SAO/B"}