feat: Add toast (#2772)

Co-authored-by: Lipis <lipiridis@gmail.com>
Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
Arun 2021-01-15 20:32:46 +05:30 committed by GitHub
parent 0bf6830373
commit 543c624405
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 161 additions and 3 deletions

View File

@ -4,6 +4,7 @@ import {
redrawTextBoundingBox,
} from "../element";
import { CODES, KEYS } from "../keys";
import { t } from "../i18n";
import { register } from "./register";
import { mutateElement, newElementWith } from "../element/mutateElement";
import {
@ -23,6 +24,10 @@ export const actionCopyStyles = register({
copiedStyles = JSON.stringify(element);
}
return {
appState: {
...appState,
toastMessage: t("toast.copyStyles"),
},
commitToHistory: false,
};
},

View File

@ -67,6 +67,7 @@ export const getDefaultAppState = (): Omit<
showStats: false,
startBoundElement: null,
suggestedBindings: [],
toastMessage: null,
viewBackgroundColor: oc.white,
width: window.innerWidth,
zenModeEnabled: false,
@ -145,6 +146,7 @@ const APP_STATE_STORAGE_CONF = (<
showStats: { browser: true, export: false },
startBoundElement: { browser: false, export: false },
suggestedBindings: { browser: false, export: false },
toastMessage: { browser: false, export: false },
viewBackgroundColor: { browser: true, export: true },
width: { browser: false, export: false },
zenModeEnabled: { browser: true, export: false },

View File

@ -158,6 +158,7 @@ import {
import ContextMenu from "./ContextMenu";
import LayerUI from "./LayerUI";
import { Stats } from "./Stats";
import { Toast } from "./Toast";
const { history } = createHistory();
@ -376,6 +377,12 @@ class App extends React.Component<ExcalidrawProps, AppState> {
onClose={this.toggleStats}
/>
)}
{this.state.toastMessage !== null && (
<Toast
message={this.state.toastMessage}
clearToast={this.clearToast}
/>
)}
<main>
<canvas
id="canvas"
@ -911,6 +918,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
this.canvas!,
this.state,
);
this.setState({ toastMessage: t("toast.copyToClipboardAsPng") });
} catch (error) {
console.error(error);
this.setState({ errorMessage: error.message });
@ -1168,6 +1176,10 @@ class App extends React.Component<ExcalidrawProps, AppState> {
});
};
clearToast = () => {
this.setState({ toastMessage: null });
};
public updateScene = withBatchedUpdates((sceneData: SceneData) => {
if (sceneData.commitToHistory) {
history.resumeRecording();

32
src/components/Toast.scss Normal file
View File

@ -0,0 +1,32 @@
@import "../css/_variables";
.excalidraw {
.Toast {
animation: fade-in 0.5s;
background-color: var(--button-gray-1);
border-radius: 4px;
bottom: 10px;
box-sizing: border-box;
cursor: default;
left: 50%;
margin-left: -150px;
padding: 4px 0;
position: fixed;
text-align: center;
width: 300px;
z-index: 999999;
}
.Toast__message {
color: var(--popup-text-color);
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
}

34
src/components/Toast.tsx Normal file
View File

@ -0,0 +1,34 @@
import React, { useCallback, useEffect, useRef } from "react";
import { TOAST_TIMEOUT } from "../constants";
import "./Toast.scss";
export const Toast = ({
message,
clearToast,
}: {
message: string;
clearToast: () => void;
}) => {
const timerRef = useRef<number>(0);
const scheduleTimeout = useCallback(
() =>
(timerRef.current = window.setTimeout(() => clearToast(), TOAST_TIMEOUT)),
[clearToast],
);
useEffect(() => {
scheduleTimeout();
return () => clearTimeout(timerRef.current);
}, [scheduleTimeout, message]);
return (
<div
className="Toast"
onMouseEnter={() => clearTimeout(timerRef?.current)}
onMouseLeave={scheduleTimeout}
>
<p className="Toast__message">{message}</p>
</div>
);
};

View File

@ -89,3 +89,4 @@ export const STORAGE_KEYS = {
export const TAP_TWICE_TIMEOUT = 300;
export const TOUCH_CTX_MENU_TIMEOUT = 500;
export const TITLE_TIMEOUT = 10000;
export const TOAST_TIMEOUT = 5000;

View File

@ -36,7 +36,7 @@ export const exportCanvas = async (
},
) => {
if (elements.length === 0) {
return window.alert(t("alerts.cannotExportEmptyCanvas"));
throw new Error(t("alerts.cannotExportEmptyCanvas"));
}
if (type === "svg" || type === "clipboard-svg") {
const tempSvg = exportToSvg(elements, {

View File

@ -232,5 +232,9 @@
"title": "Stats for nerds",
"total": "Total",
"width": "Width"
},
"toast": {
"copyStyles": "Copied styles.",
"copyToClipboardAsPng": "Copied to clipboard as PNG."
}
}

View File

@ -74,6 +74,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -539,6 +540,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -986,6 +988,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -1761,6 +1764,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -1967,6 +1971,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -2417,6 +2422,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -2664,6 +2670,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -2828,6 +2835,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -3299,6 +3307,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -3607,6 +3616,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -3810,6 +3820,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -4049,6 +4060,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -4299,6 +4311,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -4699,6 +4712,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -4969,6 +4983,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -5293,6 +5308,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -5476,6 +5492,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -5637,6 +5654,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -6094,6 +6112,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -6402,6 +6421,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -8438,6 +8458,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -8798,6 +8819,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -9048,6 +9070,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -9299,6 +9322,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -9606,6 +9630,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -9767,6 +9792,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -9928,6 +9954,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -10089,6 +10116,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -10280,6 +10308,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -10471,6 +10500,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -10662,6 +10692,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -10853,6 +10884,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -11014,6 +11046,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -11175,6 +11208,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -11366,6 +11400,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -11527,6 +11562,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -11729,6 +11765,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -12435,6 +12472,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -12681,6 +12719,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -12778,6 +12817,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -12877,6 +12917,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -13038,6 +13079,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -13343,6 +13385,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -13648,6 +13691,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": "Copied styles.",
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -13744,7 +13788,7 @@ Object {
exports[`regression tests selecting 'Copy styles' in context menu copies styles: [end of test] number of elements 1`] = `1`;
exports[`regression tests selecting 'Copy styles' in context menu copies styles: [end of test] number of renders 1`] = `6`;
exports[`regression tests selecting 'Copy styles' in context menu copies styles: [end of test] number of renders 1`] = `7`;
exports[`regression tests selecting 'Delete' in context menu deletes element: [end of test] appState 1`] = `
Object {
@ -13807,6 +13851,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -14002,6 +14047,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -14254,6 +14300,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -14569,6 +14616,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": "Copied styles.",
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -15340,7 +15388,7 @@ Object {
exports[`regression tests selecting 'Paste styles' in context menu pastes styles: [end of test] number of elements 1`] = `2`;
exports[`regression tests selecting 'Paste styles' in context menu pastes styles: [end of test] number of renders 1`] = `21`;
exports[`regression tests selecting 'Paste styles' in context menu pastes styles: [end of test] number of renders 1`] = `22`;
exports[`regression tests selecting 'Send backward' in context menu sends element backward: [end of test] appState 1`] = `
Object {
@ -15405,6 +15453,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -15710,6 +15759,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -16019,6 +16069,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -16394,6 +16445,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -16564,6 +16616,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -16876,6 +16929,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -17115,6 +17169,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -17369,6 +17424,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -17683,6 +17739,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -17782,6 +17839,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -17954,6 +18012,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -18759,6 +18818,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -18860,6 +18920,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -19635,6 +19696,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -20035,6 +20097,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -20281,6 +20344,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -20380,6 +20444,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -20873,6 +20938,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,
@ -20970,6 +21036,7 @@ Object {
"showStats": false,
"startBoundElement": null,
"suggestedBindings": Array [],
"toastMessage": null,
"viewBackgroundColor": "#ffffff",
"width": 1024,
"zenModeEnabled": false,

View File

@ -82,6 +82,7 @@ export type AppState = {
previousSelectedElementIds: { [id: string]: boolean };
shouldCacheIgnoreZoom: boolean;
showShortcutsDialog: boolean;
toastMessage: string | null;
zenModeEnabled: boolean;
appearance: "light" | "dark";
gridSize: number | null;