phx-react
Version:
PHX REACT
142 lines • 7.23 kB
JavaScript
"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