import React from "react"; import { resetCursor } from "../utils"; import { t } from "../i18n"; interface TopErrorBoundaryState { unresolvedError: Error[] | null; hasError: boolean; stack: string; localStorage: string; } export class TopErrorBoundary extends React.Component< any, TopErrorBoundaryState > { state: TopErrorBoundaryState = { unresolvedError: null, hasError: false, stack: "", localStorage: "", }; componentDidCatch(error: Error) { resetCursor(); const _localStorage: any = {}; for (const [key, value] of Object.entries({ ...localStorage })) { try { _localStorage[key] = JSON.parse(value); } catch (error) { _localStorage[key] = value; } } this.setState(state => ({ hasError: true, unresolvedError: state.unresolvedError ? state.unresolvedError.concat(error) : [error], localStorage: JSON.stringify(_localStorage), })); } async componentDidUpdate() { if (this.state.unresolvedError !== null) { let stack = ""; for (const error of this.state.unresolvedError) { if (stack) { stack += `\n\n================\n\n`; } stack += `${error.message}:\n\n`; try { const StackTrace = await import("stacktrace-js"); stack += (await StackTrace.fromError(error)).join("\n"); } catch (error) { console.error(error); stack += error.stack || ""; } } this.setState(state => ({ unresolvedError: null, stack: `${ state.stack ? `${state.stack}\n\n================\n\n${stack}` : stack }`, })); } } private selectTextArea(event: React.MouseEvent) { if (event.target !== document.activeElement) { event.preventDefault(); (event.target as HTMLTextAreaElement).select(); } } private async createGithubIssue() { let body = ""; try { const templateStr = (await import("../bug-issue-template")).default; if (typeof templateStr === "string") { body = encodeURIComponent(templateStr); } } catch (error) { console.error(error); } window.open( `https://github.com/excalidraw/excalidraw/issues/new?body=${body}`, ); } render() { if (this.state.hasError) { return (
{t("errorSplash.headingMain_pre")}
{t("errorSplash.clearCanvasMessage")}
⚠️ {t("errorSplash.clearCanvasCaveat")}
{t("errorSplash.openIssueMessage_pre")} {t("errorSplash.openIssueMessage_post")}