aboutsummaryrefslogtreecommitdiffstats
path: root/packages/excalidraw/components/OverwriteConfirm
diff options
context:
space:
mode:
Diffstat (limited to 'packages/excalidraw/components/OverwriteConfirm')
-rw-r--r--packages/excalidraw/components/OverwriteConfirm/OverwriteConfirm.scss126
-rw-r--r--packages/excalidraw/components/OverwriteConfirm/OverwriteConfirm.tsx74
-rw-r--r--packages/excalidraw/components/OverwriteConfirm/OverwriteConfirmActions.tsx85
-rw-r--r--packages/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.ts45
4 files changed, 330 insertions, 0 deletions
diff --git a/packages/excalidraw/components/OverwriteConfirm/OverwriteConfirm.scss b/packages/excalidraw/components/OverwriteConfirm/OverwriteConfirm.scss
new file mode 100644
index 0000000..4aad0cb
--- /dev/null
+++ b/packages/excalidraw/components/OverwriteConfirm/OverwriteConfirm.scss
@@ -0,0 +1,126 @@
+@import "../../css/variables.module.scss";
+
+.excalidraw {
+ .OverwriteConfirm {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 0.75rem;
+ isolation: isolate;
+
+ h3 {
+ margin: 0;
+
+ font-weight: 700;
+ font-size: 1.3125rem;
+ line-height: 130%;
+ align-self: flex-start;
+
+ color: var(--text-primary-color);
+ }
+
+ &__Description {
+ box-sizing: border-box;
+
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ width: 100%;
+ gap: 1rem;
+
+ @include isMobile {
+ flex-direction: column;
+ text-align: center;
+ }
+
+ padding: 2.5rem;
+
+ background: var(--color-danger-background);
+ border-radius: 0.5rem;
+
+ font-family: "Assistant";
+ font-style: normal;
+ font-weight: 400;
+ font-size: 1rem;
+ line-height: 150%;
+
+ color: var(--color-danger-color);
+
+ &__spacer {
+ flex-grow: 1;
+ }
+
+ &__icon {
+ box-sizing: border-box;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 2.5rem;
+ background: var(--color-danger-icon-background);
+ width: 3.5rem;
+ height: 3.5rem;
+
+ padding: 0.75rem;
+
+ svg {
+ color: var(--color-danger-icon-color);
+ width: 1.5rem;
+ height: 1.5rem;
+ }
+ }
+
+ &.OverwriteConfirm__Description--color-warning {
+ background: var(--color-warning-background);
+ color: var(--color-warning-color);
+
+ .OverwriteConfirm__Description__icon {
+ background: var(--color-warning-icon-background);
+ flex: 0 0 auto;
+
+ svg {
+ color: var(--color-warning-icon-color);
+ }
+ }
+ }
+ }
+
+ &__Actions {
+ display: flex;
+ flex-direction: row;
+ align-items: stretch;
+ justify-items: stretch;
+ justify-content: center;
+ gap: 1.5rem;
+
+ @include isMobile {
+ flex-direction: column;
+ }
+
+ &__Action {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 1.5rem;
+ gap: 0.75rem;
+ flex-basis: 50%;
+ flex-grow: 0;
+
+ &__content {
+ height: 100%;
+ font-size: 0.875rem;
+ text-align: center;
+ }
+
+ h4 {
+ font-weight: 700;
+ font-size: 1.125rem;
+ line-height: 130%;
+
+ margin: 0;
+
+ color: var(--text-primary-color);
+ }
+ }
+ }
+ }
+}
diff --git a/packages/excalidraw/components/OverwriteConfirm/OverwriteConfirm.tsx b/packages/excalidraw/components/OverwriteConfirm/OverwriteConfirm.tsx
new file mode 100644
index 0000000..4bf8d67
--- /dev/null
+++ b/packages/excalidraw/components/OverwriteConfirm/OverwriteConfirm.tsx
@@ -0,0 +1,74 @@
+import React from "react";
+
+import { useTunnels } from "../../context/tunnels";
+import { useAtom } from "../../editor-jotai";
+import { Dialog } from "../Dialog";
+import { withInternalFallback } from "../hoc/withInternalFallback";
+import { overwriteConfirmStateAtom } from "./OverwriteConfirmState";
+
+import { FilledButton } from "../FilledButton";
+import { alertTriangleIcon } from "../icons";
+import { Actions, Action } from "./OverwriteConfirmActions";
+import "./OverwriteConfirm.scss";
+
+export type OverwriteConfirmDialogProps = {
+ children: React.ReactNode;
+};
+
+const OverwriteConfirmDialog = Object.assign(
+ withInternalFallback(
+ "OverwriteConfirmDialog",
+ ({ children }: OverwriteConfirmDialogProps) => {
+ const { OverwriteConfirmDialogTunnel } = useTunnels();
+ const [overwriteConfirmState, setState] = useAtom(
+ overwriteConfirmStateAtom,
+ );
+
+ if (!overwriteConfirmState.active) {
+ return null;
+ }
+
+ const handleClose = () => {
+ overwriteConfirmState.onClose();
+ setState((state) => ({ ...state, active: false }));
+ };
+
+ const handleConfirm = () => {
+ overwriteConfirmState.onConfirm();
+ setState((state) => ({ ...state, active: false }));
+ };
+
+ return (
+ <OverwriteConfirmDialogTunnel.In>
+ <Dialog onCloseRequest={handleClose} title={false} size={916}>
+ <div className="OverwriteConfirm">
+ <h3>{overwriteConfirmState.title}</h3>
+ <div
+ className={`OverwriteConfirm__Description OverwriteConfirm__Description--color-${overwriteConfirmState.color}`}
+ >
+ <div className="OverwriteConfirm__Description__icon">
+ {alertTriangleIcon}
+ </div>
+ <div>{overwriteConfirmState.description}</div>
+ <div className="OverwriteConfirm__Description__spacer"></div>
+ <FilledButton
+ color={overwriteConfirmState.color}
+ size="large"
+ label={overwriteConfirmState.actionLabel}
+ onClick={handleConfirm}
+ />
+ </div>
+ <Actions>{children}</Actions>
+ </div>
+ </Dialog>
+ </OverwriteConfirmDialogTunnel.In>
+ );
+ },
+ ),
+ {
+ Actions,
+ Action,
+ },
+);
+
+export { OverwriteConfirmDialog };
diff --git a/packages/excalidraw/components/OverwriteConfirm/OverwriteConfirmActions.tsx b/packages/excalidraw/components/OverwriteConfirm/OverwriteConfirmActions.tsx
new file mode 100644
index 0000000..5da0a08
--- /dev/null
+++ b/packages/excalidraw/components/OverwriteConfirm/OverwriteConfirmActions.tsx
@@ -0,0 +1,85 @@
+import React from "react";
+import { FilledButton } from "../FilledButton";
+import { useExcalidrawActionManager, useExcalidrawSetAppState } from "../App";
+import { actionSaveFileToDisk } from "../../actions";
+import { useI18n } from "../../i18n";
+import { actionChangeExportEmbedScene } from "../../actions/actionExport";
+
+export type ActionProps = {
+ title: string;
+ children: React.ReactNode;
+ actionLabel: string;
+ onClick: () => void;
+};
+
+export const Action = ({
+ title,
+ children,
+ actionLabel,
+ onClick,
+}: ActionProps) => {
+ return (
+ <div className="OverwriteConfirm__Actions__Action">
+ <h4>{title}</h4>
+ <div className="OverwriteConfirm__Actions__Action__content">
+ {children}
+ </div>
+ <FilledButton
+ variant="outlined"
+ color="muted"
+ label={actionLabel}
+ size="large"
+ fullWidth
+ onClick={onClick}
+ />
+ </div>
+ );
+};
+
+export const ExportToImage = () => {
+ const { t } = useI18n();
+ const actionManager = useExcalidrawActionManager();
+ const setAppState = useExcalidrawSetAppState();
+
+ return (
+ <Action
+ title={t("overwriteConfirm.action.exportToImage.title")}
+ actionLabel={t("overwriteConfirm.action.exportToImage.button")}
+ onClick={() => {
+ actionManager.executeAction(actionChangeExportEmbedScene, "ui", true);
+ setAppState({ openDialog: { name: "imageExport" } });
+ }}
+ >
+ {t("overwriteConfirm.action.exportToImage.description")}
+ </Action>
+ );
+};
+
+export const SaveToDisk = () => {
+ const { t } = useI18n();
+ const actionManager = useExcalidrawActionManager();
+
+ return (
+ <Action
+ title={t("overwriteConfirm.action.saveToDisk.title")}
+ actionLabel={t("overwriteConfirm.action.saveToDisk.button")}
+ onClick={() => {
+ actionManager.executeAction(actionSaveFileToDisk, "ui");
+ }}
+ >
+ {t("overwriteConfirm.action.saveToDisk.description")}
+ </Action>
+ );
+};
+
+const Actions = Object.assign(
+ ({ children }: { children: React.ReactNode }) => {
+ return <div className="OverwriteConfirm__Actions">{children}</div>;
+ },
+ {
+ ExportToImage,
+ SaveToDisk,
+ },
+);
+
+export { Actions };
diff --git a/packages/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.ts b/packages/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.ts
new file mode 100644
index 0000000..04616aa
--- /dev/null
+++ b/packages/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.ts
@@ -0,0 +1,45 @@
+import { atom, editorJotaiStore } from "../../editor-jotai";
+import type React from "react";
+
+export type OverwriteConfirmState =
+ | {
+ active: true;
+ title: string;
+ description: React.ReactNode;
+ actionLabel: string;
+ color: "danger" | "warning";
+
+ onClose: () => void;
+ onConfirm: () => void;
+ onReject: () => void;
+ }
+ | { active: false };
+
+export const overwriteConfirmStateAtom = atom<OverwriteConfirmState>({
+ active: false,
+});
+
+export async function openConfirmModal({
+ title,
+ description,
+ actionLabel,
+ color,
+}: {
+ title: string;
+ description: React.ReactNode;
+ actionLabel: string;
+ color: "danger" | "warning";
+}) {
+ return new Promise<boolean>((resolve) => {
+ editorJotaiStore.set(overwriteConfirmStateAtom, {
+ active: true,
+ onConfirm: () => resolve(true),
+ onClose: () => resolve(false),
+ onReject: () => resolve(false),
+ title,
+ description,
+ actionLabel,
+ color,
+ });
+ });
+}