UNPKG

text-editor-studio-ts

Version:

A powerful mobile-responsive rich text editor built with Lexical and React

277 lines (276 loc) 7.36 kB
import { jsx, jsxs, Fragment } from "react/jsx-runtime"; import { useState, useEffect, useRef, useCallback, useMemo } from "react"; import { o, a, u, E as ExcalidrawModal, b as $isExcalidrawNode } from "./index-BwW17RmP.js"; import { mergeRegister } from "@lexical/utils"; import { $getNodeByKey, CLICK_COMMAND, COMMAND_PRIORITY_LOW, KEY_DELETE_COMMAND, KEY_BACKSPACE_COMMAND } from "lexical"; import { exportToSvg } from "@excalidraw/excalidraw"; import { I as ImageResizer } from "./image-resizer-CFedlLqf.js"; const removeStyleFromSvg_HACK = (svg) => { const styleTag = svg?.firstElementChild?.firstElementChild; const viewBox = svg.getAttribute("viewBox"); if (viewBox != null) { const viewBoxDimensions = viewBox.split(" "); svg.setAttribute("width", viewBoxDimensions[2]); svg.setAttribute("height", viewBoxDimensions[3]); } if (styleTag && styleTag.tagName === "style") { styleTag.remove(); } }; function ExcalidrawImage({ elements, files, imageContainerRef, appState, rootClassName = null, width = "inherit", height = "inherit" }) { const [Svg, setSvg] = useState(null); useEffect(() => { const setContent = async () => { const svg = await exportToSvg({ appState, elements, files }); removeStyleFromSvg_HACK(svg); svg.setAttribute("width", "100%"); svg.setAttribute("height", "100%"); svg.setAttribute("display", "block"); setSvg(svg); }; setContent(); }, [elements, files, appState]); const containerStyle = {}; if (width !== "inherit") { containerStyle.width = `${width}px`; } if (height !== "inherit") { containerStyle.height = `${height}px`; } return /* @__PURE__ */ jsx( "div", { ref: (node) => { if (node) { if (imageContainerRef) { imageContainerRef.current = node; } } }, className: rootClassName ?? "", style: containerStyle, dangerouslySetInnerHTML: { __html: Svg?.outerHTML ?? "" } } ); } function ExcalidrawComponent({ nodeKey, data, width, height }) { const [editor] = o(); const isEditable = a(); const [isModalOpen, setModalOpen] = useState( data === "[]" && editor.isEditable() ); const imageContainerRef = useRef(null); const buttonRef = useRef(null); const captionButtonRef = useRef(null); const [isSelected, setSelected, clearSelection] = u(nodeKey); const [isResizing, setIsResizing] = useState(false); const $onDelete = useCallback( (event) => { if (isSelected) { event.preventDefault(); editor.update(() => { const node = $getNodeByKey(nodeKey); if (node) { node.remove(); } }); } return false; }, [editor, isSelected, nodeKey] ); useEffect(() => { if (!isEditable) { if (isSelected) { clearSelection(); } return; } return mergeRegister( editor.registerCommand( CLICK_COMMAND, (event) => { const buttonElem = buttonRef.current; const eventTarget = event.target; if (isResizing) { return true; } if (buttonElem !== null && buttonElem.contains(eventTarget)) { if (!event.shiftKey) { clearSelection(); } setSelected(!isSelected); if (event.detail > 1) { setModalOpen(true); } return true; } return false; }, COMMAND_PRIORITY_LOW ), editor.registerCommand( KEY_DELETE_COMMAND, $onDelete, COMMAND_PRIORITY_LOW ), editor.registerCommand( KEY_BACKSPACE_COMMAND, $onDelete, COMMAND_PRIORITY_LOW ) ); }, [ clearSelection, editor, isSelected, isResizing, $onDelete, setSelected, isEditable ]); const deleteNode = useCallback(() => { setModalOpen(false); return editor.update(() => { const node = $getNodeByKey(nodeKey); if (node) { node.remove(); } }); }, [editor, nodeKey]); const setData = (els, aps, fls) => { return editor.update(() => { const node = $getNodeByKey(nodeKey); if ($isExcalidrawNode(node)) { if (els && els.length > 0 || Object.keys(fls).length > 0) { node.setData( JSON.stringify({ appState: aps, elements: els, files: fls }) ); } else { node.remove(); } } }); }; const onResizeStart = () => { setIsResizing(true); }; const onResizeEnd = (nextWidth, nextHeight) => { setTimeout(() => { setIsResizing(false); }, 200); editor.update(() => { const node = $getNodeByKey(nodeKey); if ($isExcalidrawNode(node)) { node.setWidth(nextWidth); node.setHeight(nextHeight); } }); }; const openModal = useCallback(() => { setModalOpen(true); }, []); const { elements = [], files = {}, appState = {} } = useMemo(() => JSON.parse(data), [data]); const closeModal = useCallback(() => { setModalOpen(false); if (elements.length === 0) { editor.update(() => { const node = $getNodeByKey(nodeKey); if (node) { node.remove(); } }); } }, [editor, nodeKey, elements.length]); return /* @__PURE__ */ jsxs(Fragment, { children: [ isEditable && isModalOpen && /* @__PURE__ */ jsx( ExcalidrawModal, { initialElements: elements, initialFiles: files, initialAppState: appState, isShown: isModalOpen, onDelete: deleteNode, onClose: closeModal, onSave: (els, aps, fls) => { setData(els, aps, fls); setModalOpen(false); }, closeOnClickOutside: false } ), elements.length > 0 && /* @__PURE__ */ jsxs( "button", { ref: buttonRef, className: `m-0 border-0 bg-transparent p-0 ${isSelected ? "user-select-none ring-2 ring-primary ring-offset-2" : ""}`, children: [ /* @__PURE__ */ jsx( ExcalidrawImage, { imageContainerRef, className: "image", elements, files, appState, width, height } ), isSelected && isEditable && /* @__PURE__ */ jsx( "div", { className: "image-edit-button", role: "button", tabIndex: 0, onMouseDown: (event) => event.preventDefault(), onClick: openModal } ), (isSelected || isResizing) && isEditable && /* @__PURE__ */ jsx( ImageResizer, { buttonRef: captionButtonRef, showCaption: true, setShowCaption: () => null, imageRef: imageContainerRef, editor, onResizeStart, onResizeEnd, captionsEnabled: true } ) ] } ) ] }); } export { ExcalidrawComponent as default }; //# sourceMappingURL=excalidraw-component-DrhkyxVZ.js.map