|
@@ -3,7 +3,28 @@ import React from "react";
|
|
|
import { RoughCanvas } from "roughjs/bin/canvas";
|
|
|
import rough from "roughjs/bin/rough";
|
|
|
import "../actions";
|
|
|
-import { actionDeleteSelected, actionFinalize } from "../actions";
|
|
|
+import {
|
|
|
+ actionAddToLibrary,
|
|
|
+ actionBringForward,
|
|
|
+ actionBringToFront,
|
|
|
+ actionCopy,
|
|
|
+ actionCopyAsPng,
|
|
|
+ actionCopyAsSvg,
|
|
|
+ actionCopyStyles,
|
|
|
+ actionCut,
|
|
|
+ actionDeleteSelected,
|
|
|
+ actionDuplicateSelection,
|
|
|
+ actionFinalize,
|
|
|
+ actionGroup,
|
|
|
+ actionPasteStyles,
|
|
|
+ actionSelectAll,
|
|
|
+ actionSendBackward,
|
|
|
+ actionSendToBack,
|
|
|
+ actionToggleGridMode,
|
|
|
+ actionToggleStats,
|
|
|
+ actionToggleZenMode,
|
|
|
+ actionUngroup,
|
|
|
+} from "../actions";
|
|
|
import { createRedoAction, createUndoAction } from "../actions/actionHistory";
|
|
|
import { ActionManager } from "../actions/manager";
|
|
|
import { actions } from "../actions/register";
|
|
@@ -18,7 +39,6 @@ import {
|
|
|
} from "../clipboard";
|
|
|
import {
|
|
|
APP_NAME,
|
|
|
- CANVAS_ONLY_ACTIONS,
|
|
|
CURSOR_TYPE,
|
|
|
DEFAULT_VERTICAL_ALIGN,
|
|
|
DRAGGING_THRESHOLD,
|
|
@@ -26,7 +46,6 @@ import {
|
|
|
ELEMENT_TRANSLATE_AMOUNT,
|
|
|
ENV,
|
|
|
EVENT,
|
|
|
- GRID_SIZE,
|
|
|
LINE_CONFIRM_THRESHOLD,
|
|
|
MIME_TYPES,
|
|
|
POINTER_BUTTON,
|
|
@@ -314,6 +333,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
this.syncActionResult,
|
|
|
() => this.state,
|
|
|
() => this.scene.getElementsIncludingDeleted(),
|
|
|
+ this,
|
|
|
);
|
|
|
this.actionManager.registerAll(actions);
|
|
|
|
|
@@ -927,25 +947,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- private copyToClipboardAsSvg = async () => {
|
|
|
- const selectedElements = getSelectedElements(
|
|
|
- this.scene.getElements(),
|
|
|
- this.state,
|
|
|
- );
|
|
|
- try {
|
|
|
- await exportCanvas(
|
|
|
- "clipboard-svg",
|
|
|
- selectedElements.length ? selectedElements : this.scene.getElements(),
|
|
|
- this.state,
|
|
|
- this.canvas!,
|
|
|
- this.state,
|
|
|
- );
|
|
|
- } catch (error) {
|
|
|
- console.error(error);
|
|
|
- this.setState({ errorMessage: error.message });
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
private static resetTapTwice() {
|
|
|
didTapTwice = false;
|
|
|
}
|
|
@@ -1148,15 +1149,11 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
};
|
|
|
|
|
|
toggleZenMode = () => {
|
|
|
- this.setState({
|
|
|
- zenModeEnabled: !this.state.zenModeEnabled,
|
|
|
- });
|
|
|
+ this.actionManager.executeAction(actionToggleZenMode);
|
|
|
};
|
|
|
|
|
|
toggleGridMode = () => {
|
|
|
- this.setState({
|
|
|
- gridSize: this.state.gridSize ? null : GRID_SIZE,
|
|
|
- });
|
|
|
+ this.actionManager.executeAction(actionToggleGridMode);
|
|
|
};
|
|
|
|
|
|
toggleStats = () => {
|
|
@@ -3618,52 +3615,52 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
this.state,
|
|
|
);
|
|
|
|
|
|
+ const maybeGroupAction = actionGroup.contextItemPredicate!(
|
|
|
+ this.actionManager.getElementsIncludingDeleted(),
|
|
|
+ this.actionManager.getAppState(),
|
|
|
+ );
|
|
|
+
|
|
|
+ const maybeUngroupAction = actionUngroup.contextItemPredicate!(
|
|
|
+ this.actionManager.getElementsIncludingDeleted(),
|
|
|
+ this.actionManager.getAppState(),
|
|
|
+ );
|
|
|
+
|
|
|
+ const separator = "separator";
|
|
|
+
|
|
|
const elements = this.scene.getElements();
|
|
|
const element = this.getElementAtPosition(x, y);
|
|
|
if (!element) {
|
|
|
ContextMenu.push({
|
|
|
options: [
|
|
|
navigator.clipboard && {
|
|
|
- shortcutName: "paste",
|
|
|
- label: t("labels.paste"),
|
|
|
- action: () => this.pasteFromClipboard(null),
|
|
|
+ name: "paste",
|
|
|
+ perform: (elements, appStates) => {
|
|
|
+ this.pasteFromClipboard(null);
|
|
|
+ return {
|
|
|
+ commitToHistory: false,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ contextItemLabel: "labels.paste",
|
|
|
},
|
|
|
+ separator,
|
|
|
probablySupportsClipboardBlob &&
|
|
|
- elements.length > 0 && {
|
|
|
- shortcutName: "copyAsPng",
|
|
|
- label: t("labels.copyAsPng"),
|
|
|
- action: this.copyToClipboardAsPng,
|
|
|
- },
|
|
|
+ elements.length > 0 &&
|
|
|
+ actionCopyAsPng,
|
|
|
probablySupportsClipboardWriteText &&
|
|
|
- elements.length > 0 && {
|
|
|
- shortcutName: "copyAsSvg",
|
|
|
- label: t("labels.copyAsSvg"),
|
|
|
- action: this.copyToClipboardAsSvg,
|
|
|
- },
|
|
|
- ...this.actionManager.getContextMenuItems((action) =>
|
|
|
- CANVAS_ONLY_ACTIONS.includes(action.name),
|
|
|
- ),
|
|
|
- {
|
|
|
- checked: this.state.gridSize !== null,
|
|
|
- shortcutName: "gridMode",
|
|
|
- label: t("labels.gridMode"),
|
|
|
- action: this.toggleGridMode,
|
|
|
- },
|
|
|
- {
|
|
|
- checked: this.state.zenModeEnabled,
|
|
|
- shortcutName: "zenMode",
|
|
|
- label: t("buttons.zenMode"),
|
|
|
- action: this.toggleZenMode,
|
|
|
- },
|
|
|
- {
|
|
|
- checked: this.state.showStats,
|
|
|
- shortcutName: "stats",
|
|
|
- label: t("stats.title"),
|
|
|
- action: this.toggleStats,
|
|
|
- },
|
|
|
+ elements.length > 0 &&
|
|
|
+ actionCopyAsSvg,
|
|
|
+ ((probablySupportsClipboardBlob && elements.length > 0) ||
|
|
|
+ (probablySupportsClipboardWriteText && elements.length > 0)) &&
|
|
|
+ separator,
|
|
|
+ actionSelectAll,
|
|
|
+ separator,
|
|
|
+ actionToggleGridMode,
|
|
|
+ actionToggleZenMode,
|
|
|
+ actionToggleStats,
|
|
|
],
|
|
|
top: clientY,
|
|
|
left: clientX,
|
|
|
+ actionManager: this.actionManager,
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
@@ -3674,37 +3671,41 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
|
|
|
ContextMenu.push({
|
|
|
options: [
|
|
|
- {
|
|
|
- shortcutName: "cut",
|
|
|
- label: t("labels.cut"),
|
|
|
- action: this.cutAll,
|
|
|
- },
|
|
|
+ actionCut,
|
|
|
+ navigator.clipboard && actionCopy,
|
|
|
navigator.clipboard && {
|
|
|
- shortcutName: "copy",
|
|
|
- label: t("labels.copy"),
|
|
|
- action: this.copyAll,
|
|
|
- },
|
|
|
- navigator.clipboard && {
|
|
|
- shortcutName: "paste",
|
|
|
- label: t("labels.paste"),
|
|
|
- action: () => this.pasteFromClipboard(null),
|
|
|
- },
|
|
|
- probablySupportsClipboardBlob && {
|
|
|
- shortcutName: "copyAsPng",
|
|
|
- label: t("labels.copyAsPng"),
|
|
|
- action: this.copyToClipboardAsPng,
|
|
|
- },
|
|
|
- probablySupportsClipboardWriteText && {
|
|
|
- shortcutName: "copyAsSvg",
|
|
|
- label: t("labels.copyAsSvg"),
|
|
|
- action: this.copyToClipboardAsSvg,
|
|
|
+ name: "paste",
|
|
|
+ perform: (elements, appStates) => {
|
|
|
+ this.pasteFromClipboard(null);
|
|
|
+ return {
|
|
|
+ commitToHistory: false,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ contextItemLabel: "labels.paste",
|
|
|
},
|
|
|
- ...this.actionManager.getContextMenuItems(
|
|
|
- (action) => !CANVAS_ONLY_ACTIONS.includes(action.name),
|
|
|
- ),
|
|
|
+ separator,
|
|
|
+ probablySupportsClipboardBlob && actionCopyAsPng,
|
|
|
+ probablySupportsClipboardWriteText && actionCopyAsSvg,
|
|
|
+ separator,
|
|
|
+ actionCopyStyles,
|
|
|
+ actionPasteStyles,
|
|
|
+ separator,
|
|
|
+ maybeGroupAction && actionGroup,
|
|
|
+ maybeUngroupAction && actionUngroup,
|
|
|
+ (maybeGroupAction || maybeUngroupAction) && separator,
|
|
|
+ actionAddToLibrary,
|
|
|
+ separator,
|
|
|
+ actionSendBackward,
|
|
|
+ actionBringForward,
|
|
|
+ actionSendToBack,
|
|
|
+ actionBringToFront,
|
|
|
+ separator,
|
|
|
+ actionDuplicateSelection,
|
|
|
+ actionDeleteSelected,
|
|
|
],
|
|
|
top: clientY,
|
|
|
left: clientX,
|
|
|
+ actionManager: this.actionManager,
|
|
|
});
|
|
|
};
|
|
|
|