fix: remove legacy React.render() from the editor (#5893)

This commit is contained in:
David Luzar 2022-11-19 18:27:54 +01:00 committed by GitHub
parent 96a5d6548b
commit 8ed0fc2c87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 48 deletions

View File

@ -5917,6 +5917,7 @@ class App extends React.Component<AppProps, AppState> {
},
type: "canvas" | "element",
) => {
trackEvent("contextMenu", "openContextMenu", type);
if (this.state.showHyperlinkPopup) {
this.setState({ showHyperlinkPopup: false });
}

View File

@ -1,4 +1,4 @@
import { render, unmountComponentAtNode } from "react-dom";
import { createRoot, Root } from "react-dom/client";
import clsx from "clsx";
import { Popover } from "./Popover";
import { t } from "../i18n";
@ -89,42 +89,38 @@ const ContextMenu = ({
);
};
const contextMenuNodeByContainer = new WeakMap<HTMLElement, HTMLDivElement>();
const contextMenuRoots = new WeakMap<HTMLElement, Root>();
const getContextMenuNode = (container: HTMLElement): HTMLDivElement => {
let contextMenuNode = contextMenuNodeByContainer.get(container);
if (contextMenuNode) {
return contextMenuNode;
const getContextMenuRoot = (container: HTMLElement): Root => {
let contextMenuRoot = contextMenuRoots.get(container);
if (contextMenuRoot) {
return contextMenuRoot;
}
contextMenuNode = document.createElement("div");
container
.querySelector(".excalidraw-contextMenuContainer")!
.appendChild(contextMenuNode);
contextMenuNodeByContainer.set(container, contextMenuNode);
return contextMenuNode;
};
type ContextMenuParams = {
options: (ContextMenuOption | false | null | undefined)[];
top: ContextMenuProps["top"];
left: ContextMenuProps["left"];
actionManager: ContextMenuProps["actionManager"];
appState: Readonly<AppState>;
container: HTMLElement;
elements: readonly NonDeletedExcalidrawElement[];
contextMenuRoot = createRoot(
container.querySelector(".excalidraw-contextMenuContainer")!,
);
contextMenuRoots.set(container, contextMenuRoot);
return contextMenuRoot;
};
const handleClose = (container: HTMLElement) => {
const contextMenuNode = contextMenuNodeByContainer.get(container);
if (contextMenuNode) {
unmountComponentAtNode(contextMenuNode);
contextMenuNode.remove();
contextMenuNodeByContainer.delete(container);
const contextMenuRoot = contextMenuRoots.get(container);
if (contextMenuRoot) {
contextMenuRoot.unmount();
contextMenuRoots.delete(container);
}
};
export default {
push(params: ContextMenuParams) {
push(params: {
options: (ContextMenuOption | false | null | undefined)[];
top: ContextMenuProps["top"];
left: ContextMenuProps["left"];
actionManager: ContextMenuProps["actionManager"];
appState: Readonly<AppState>;
container: HTMLElement;
elements: readonly NonDeletedExcalidrawElement[];
}) {
const options = Array.of<ContextMenuOption>();
params.options.forEach((option) => {
if (option) {
@ -132,7 +128,7 @@ export default {
}
});
if (options.length) {
render(
getContextMenuRoot(params.container).render(
<ContextMenu
top={params.top}
left={params.left}
@ -142,7 +138,6 @@ export default {
appState={params.appState}
elements={params.elements}
/>,
getContextMenuNode(params.container),
);
}
},

View File

@ -1,9 +1,7 @@
import React, { useEffect, useRef, useState } from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { probablySupportsClipboardBlob } from "../clipboard";
import { canvasToBlob } from "../data/blob";
import { NonDeletedExcalidrawElement } from "../element/types";
import { CanvasError } from "../errors";
import { t } from "../i18n";
import { getSelectedElements, isSomeElementSelected } from "../scene";
import { exportToCanvas } from "../scene/export";
@ -33,19 +31,6 @@ export const ErrorCanvasPreview = () => {
);
};
const renderPreview = (
content: HTMLCanvasElement | Error,
previewNode: HTMLDivElement,
) => {
unmountComponentAtNode(previewNode);
previewNode.innerHTML = "";
if (content instanceof HTMLCanvasElement) {
previewNode.appendChild(content);
} else {
render(<ErrorCanvasPreview />, previewNode);
}
};
export type ExportCB = (
elements: readonly NonDeletedExcalidrawElement[],
scale?: number,
@ -99,6 +84,7 @@ const ImageExportModal = ({
const [exportSelected, setExportSelected] = useState(someElementIsSelected);
const previewRef = useRef<HTMLDivElement>(null);
const { exportBackground, viewBackgroundColor } = appState;
const [renderError, setRenderError] = useState<Error | null>(null);
const exportedElements = exportSelected
? getSelectedElements(elements, appState, true)
@ -119,15 +105,16 @@ const ImageExportModal = ({
exportPadding,
})
.then((canvas) => {
setRenderError(null);
// if converting to blob fails, there's some problem that will
// likely prevent preview and export (e.g. canvas too big)
return canvasToBlob(canvas).then(() => {
renderPreview(canvas, previewNode);
previewNode.replaceChildren(canvas);
});
})
.catch((error) => {
console.error(error);
renderPreview(new CanvasError(), previewNode);
setRenderError(error);
});
}, [
appState,
@ -140,7 +127,9 @@ const ImageExportModal = ({
return (
<div className="ExportDialog">
<div className="ExportDialog__preview" ref={previewRef} />
<div className="ExportDialog__preview" ref={previewRef}>
{renderError && <ErrorCanvasPreview />}
</div>
{supportsContextFilters &&
actionManager.renderAction("exportWithDarkMode")}
<div style={{ display: "grid", gridTemplateColumns: "1fr" }}>