UNPKG

phx-react

Version:

PHX REACT

142 lines • 7.23 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useCallbackRefState = void 0; exports.default = ExcalidrawModal; const tslib_1 = require("tslib"); const excalidraw_1 = require("@excalidraw/excalidraw"); const React = tslib_1.__importStar(require("react")); const react_1 = require("react"); const react_dom_1 = require("react-dom"); const Button_1 = tslib_1.__importDefault(require("../../ui/Button")); const Modal_1 = tslib_1.__importDefault(require("../../ui/Modal")); const useCallbackRefState = () => { const [refValue, setRefValue] = React.useState(null); const refCallback = React.useCallback((value) => setRefValue(value), []); return [refValue, refCallback]; }; exports.useCallbackRefState = useCallbackRefState; /** * @explorer-desc * A component which renders a modal with Excalidraw (a painting app) * which can be used to export an editable image */ function ExcalidrawModal({ closeOnClickOutside = false, initialAppState, initialElements, initialFiles, isShown = false, onClose, onDelete, onSave, }) { const excaliDrawModelRef = (0, react_1.useRef)(null); const [excalidrawAPI, excalidrawAPIRefCallback] = (0, exports.useCallbackRefState)(); const [discardModalOpen, setDiscardModalOpen] = (0, react_1.useState)(false); const [elements, setElements] = (0, react_1.useState)(initialElements); const [files, setFiles] = (0, react_1.useState)(initialFiles); (0, react_1.useEffect)(() => { if (excaliDrawModelRef.current !== null) { excaliDrawModelRef.current.focus(); } }, []); (0, react_1.useEffect)(() => { var _a; let modalOverlayElement = null; const clickOutsideHandler = (event) => { const target = event.target; if (excaliDrawModelRef.current !== null && !excaliDrawModelRef.current.contains(target) && closeOnClickOutside) { onDelete(); } }; if (excaliDrawModelRef.current !== null) { modalOverlayElement = (_a = excaliDrawModelRef.current) === null || _a === void 0 ? void 0 : _a.parentElement; if (modalOverlayElement !== null) { modalOverlayElement === null || modalOverlayElement === void 0 ? void 0 : modalOverlayElement.addEventListener('click', clickOutsideHandler); } } return () => { if (modalOverlayElement !== null) { modalOverlayElement === null || modalOverlayElement === void 0 ? void 0 : modalOverlayElement.removeEventListener('click', clickOutsideHandler); } }; }, [closeOnClickOutside, onDelete]); (0, react_1.useLayoutEffect)(() => { const currentModalRef = excaliDrawModelRef.current; const onKeyDown = (event) => { if (event.key === 'Escape') { onDelete(); } }; if (currentModalRef !== null) { currentModalRef.addEventListener('keydown', onKeyDown); } return () => { if (currentModalRef !== null) { currentModalRef.removeEventListener('keydown', onKeyDown); } }; }, [elements, files, onDelete]); const save = () => { if (elements.filter((el) => !el.isDeleted).length > 0) { const appState = excalidrawAPI === null || excalidrawAPI === void 0 ? void 0 : excalidrawAPI.getAppState(); // We only need a subset of the state const partialState = { exportBackground: appState === null || appState === void 0 ? void 0 : appState.exportBackground, exportScale: appState === null || appState === void 0 ? void 0 : appState.exportScale, exportWithDarkMode: (appState === null || appState === void 0 ? void 0 : appState.theme) === 'dark', isBindingEnabled: appState === null || appState === void 0 ? void 0 : appState.isBindingEnabled, isLoading: appState === null || appState === void 0 ? void 0 : appState.isLoading, name: appState === null || appState === void 0 ? void 0 : appState.name, theme: appState === null || appState === void 0 ? void 0 : appState.theme, viewBackgroundColor: appState === null || appState === void 0 ? void 0 : appState.viewBackgroundColor, viewModeEnabled: appState === null || appState === void 0 ? void 0 : appState.viewModeEnabled, zenModeEnabled: appState === null || appState === void 0 ? void 0 : appState.zenModeEnabled, zoom: appState === null || appState === void 0 ? void 0 : appState.zoom, }; onSave(elements, partialState, files); } else { // delete node if the scene is clear onDelete(); } }; const discard = () => { if (elements.filter((el) => !el.isDeleted).length === 0) { // delete node if the scene is clear onDelete(); } else { // Otherwise, show confirmation dialog before closing setDiscardModalOpen(true); } }; function ShowDiscardDialog() { return (React.createElement(Modal_1.default, { closeOnClickOutside: false, onClose: () => { setDiscardModalOpen(false); }, title: 'Discard' }, "Are you sure you want to discard the changes?", React.createElement("div", { className: 'ExcalidrawModal__discardModal' }, React.createElement(Button_1.default, { onClick: () => { setDiscardModalOpen(false); onClose(); } }, "Discard"), ' ', React.createElement(Button_1.default, { onClick: () => { setDiscardModalOpen(false); } }, "Cancel")))); } if (isShown === false) { return null; } const onChange = (els, _, fls) => { setElements(els); setFiles(fls); }; return (0, react_dom_1.createPortal)(React.createElement("div", { className: 'ExcalidrawModal__overlay', role: 'dialog' }, React.createElement("div", { ref: excaliDrawModelRef, className: 'ExcalidrawModal__modal', tabIndex: -1 }, React.createElement("div", { className: 'ExcalidrawModal__row' }, discardModalOpen && React.createElement(ShowDiscardDialog, null), React.createElement(excalidraw_1.Excalidraw, { excalidrawAPI: excalidrawAPIRefCallback, initialData: { appState: initialAppState || { isLoading: false }, elements: initialElements, files: initialFiles, }, onChange: onChange }), React.createElement("div", { className: 'ExcalidrawModal__actions' }, React.createElement("button", { className: 'action-button', onClick: discard, type: 'button' }, "Discard"), React.createElement("button", { className: 'action-button', onClick: save, type: 'button' }, "Save"))))), document.body); } //# sourceMappingURL=ExcalidrawModal.js.map