-
-
-
-
+ {actionManager.renderAction(
+ "bringForward",
+ elements,
+ appState,
+ syncActionResult
+ )}
+ {actionManager.renderAction(
+ "bringToFront",
+ elements,
+ appState,
+ syncActionResult
+ )}
+ {actionManager.renderAction(
+ "sendBackward",
+ elements,
+ appState,
+ syncActionResult
+ )}
+ {actionManager.renderAction(
+ "sendToBack",
+ elements,
+ appState,
+ syncActionResult
+ )}
);
diff --git a/src/index.tsx b/src/index.tsx
index 53b48cd4..0a2fbdbf 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -4,19 +4,16 @@ import ReactDOM from "react-dom";
import rough from "roughjs/bin/wrappers/rough";
import { RoughCanvas } from "roughjs/bin/canvas";
-import { moveOneLeft, moveAllLeft, moveOneRight, moveAllRight } from "./zindex";
import {
newElement,
duplicateElement,
resizeTest,
isTextElement,
textWysiwyg,
- getElementAbsoluteCoords,
- redrawTextBoundingBox
+ getElementAbsoluteCoords
} from "./element";
import {
clearSelection,
- getSelectedIndices,
deleteSelectedElements,
setSelection,
isOverScrollBars,
@@ -41,7 +38,33 @@ import ContextMenu from "./components/ContextMenu";
import "./styles.scss";
import { getElementWithResizeHandler } from "./element/resizeTest";
+import {
+ ActionManager,
+ actionDeleteSelected,
+ actionSendBackward,
+ actionBringForward,
+ actionSendToBack,
+ actionBringToFront,
+ actionSelectAll,
+ actionChangeStrokeColor,
+ actionChangeBackgroundColor,
+ actionChangeOpacity,
+ actionChangeStrokeWidth,
+ actionChangeFillStyle,
+ actionChangeSloppiness,
+ actionChangeFontSize,
+ actionChangeFontFamily,
+ actionChangeViewBackgroundColor,
+ actionClearCanvas,
+ actionChangeProjectName,
+ actionChangeExportBackground,
+ actionLoadScene,
+ actionSaveScene,
+ actionCopyStyles,
+ actionPasteStyles
+} from "./actions";
import { SidePanel } from "./components/SidePanel";
+import { ActionResult } from "./actions/types";
let { elements } = createScene();
const { history } = createHistory();
@@ -50,8 +73,6 @@ const DEFAULT_PROJECT_NAME = `excalidraw-${getDateTime()}`;
const CANVAS_WINDOW_OFFSET_LEFT = 250;
const CANVAS_WINDOW_OFFSET_TOP = 0;
-let copiedStyles: string = "{}";
-
function resetCursor() {
document.documentElement.style.cursor = "";
}
@@ -101,6 +122,48 @@ export class App extends React.Component<{}, AppState> {
canvas: HTMLCanvasElement | null = null;
rc: RoughCanvas | null = null;
+ actionManager: ActionManager = new ActionManager();
+ constructor(props: any) {
+ super(props);
+ this.actionManager.registerAction(actionDeleteSelected);
+ this.actionManager.registerAction(actionSendToBack);
+ this.actionManager.registerAction(actionBringToFront);
+ this.actionManager.registerAction(actionSendBackward);
+ this.actionManager.registerAction(actionBringForward);
+ this.actionManager.registerAction(actionSelectAll);
+
+ this.actionManager.registerAction(actionChangeStrokeColor);
+ this.actionManager.registerAction(actionChangeBackgroundColor);
+ this.actionManager.registerAction(actionChangeFillStyle);
+ this.actionManager.registerAction(actionChangeStrokeWidth);
+ this.actionManager.registerAction(actionChangeOpacity);
+ this.actionManager.registerAction(actionChangeSloppiness);
+ this.actionManager.registerAction(actionChangeFontSize);
+ this.actionManager.registerAction(actionChangeFontFamily);
+
+ this.actionManager.registerAction(actionChangeViewBackgroundColor);
+ this.actionManager.registerAction(actionClearCanvas);
+
+ this.actionManager.registerAction(actionChangeProjectName);
+ this.actionManager.registerAction(actionChangeExportBackground);
+ this.actionManager.registerAction(actionSaveScene);
+ this.actionManager.registerAction(actionLoadScene);
+
+ this.actionManager.registerAction(actionCopyStyles);
+ this.actionManager.registerAction(actionPasteStyles);
+ }
+
+ private syncActionResult = (res: ActionResult) => {
+ if (res.elements !== undefined) {
+ elements = res.elements;
+ this.forceUpdate();
+ }
+
+ if (res.appState !== undefined) {
+ this.setState({ ...res.appState });
+ }
+ };
+
public componentDidMount() {
document.addEventListener("keydown", this.onKeyDown, false);
document.addEventListener("mousemove", this.getCurrentCursorPosition);
@@ -166,10 +229,14 @@ export class App extends React.Component<{}, AppState> {
}
if (isInputLike(event.target)) return;
- if (event.key === KEYS.BACKSPACE || event.key === KEYS.DELETE) {
- this.deleteSelectedElements();
- event.preventDefault();
- } else if (isArrowKey(event.key)) {
+ const data = this.actionManager.handleKeyDown(event, elements, this.state);
+ this.syncActionResult(data);
+
+ if (data.elements !== undefined && data.appState !== undefined) {
+ return;
+ }
+
+ if (isArrowKey(event.key)) {
const step = event.shiftKey
? ELEMENT_SHIFT_TRANSLATE_AMOUNT
: ELEMENT_TRANSLATE_AMOUNT;
@@ -186,46 +253,6 @@ export class App extends React.Component<{}, AppState> {
});
this.forceUpdate();
event.preventDefault();
-
- // Send backward: Cmd-Shift-Alt-B
- } else if (
- event[META_KEY] &&
- event.shiftKey &&
- event.altKey &&
- event.code === "KeyB"
- ) {
- this.moveOneLeft();
- event.preventDefault();
-
- // Send to back: Cmd-Shift-B
- } else if (event[META_KEY] && event.shiftKey && event.code === "KeyB") {
- this.moveAllLeft();
- event.preventDefault();
-
- // Bring forward: Cmd-Shift-Alt-F
- } else if (
- event[META_KEY] &&
- event.shiftKey &&
- event.altKey &&
- event.code === "KeyF"
- ) {
- this.moveOneRight();
- event.preventDefault();
-
- // Bring to front: Cmd-Shift-F
- } else if (event[META_KEY] && event.shiftKey && event.code === "KeyF") {
- this.moveAllRight();
- event.preventDefault();
- // Select all: Cmd-A
- } else if (event[META_KEY] && event.code === "KeyA") {
- let newElements = [...elements];
- newElements.forEach(element => {
- element.isSelected = true;
- });
-
- elements = newElements;
- this.forceUpdate();
- event.preventDefault();
} else if (shapesShortcutKeys.includes(event.key.toLowerCase())) {
this.setState({ elementType: findShapeByKey(event.key) });
} else if (event[META_KEY] && event.code === "KeyZ") {
@@ -244,99 +271,11 @@ export class App extends React.Component<{}, AppState> {
}
this.forceUpdate();
event.preventDefault();
- // Copy Styles: Cmd-Shift-C
- } else if (event.metaKey && event.shiftKey && event.code === "KeyC") {
- this.copyStyles();
- // Paste Styles: Cmd-Shift-V
- } else if (event.metaKey && event.shiftKey && event.code === "KeyV") {
- this.pasteStyles();
- event.preventDefault();
}
};
- private deleteSelectedElements = () => {
- elements = deleteSelectedElements(elements);
- this.forceUpdate();
- };
-
- private clearCanvas = () => {
- if (window.confirm("This will clear the whole canvas. Are you sure?")) {
- elements = [];
- this.setState({
- viewBackgroundColor: "#ffffff",
- scrollX: 0,
- scrollY: 0
- });
- this.forceUpdate();
- }
- };
-
- private copyStyles = () => {
- const element = elements.find(el => el.isSelected);
- if (element) {
- copiedStyles = JSON.stringify(element);
- }
- };
-
- private pasteStyles = () => {
- const pastedElement = JSON.parse(copiedStyles);
- elements = elements.map(element => {
- if (element.isSelected) {
- const newElement = {
- ...element,
- backgroundColor: pastedElement?.backgroundColor,
- strokeWidth: pastedElement?.strokeWidth,
- strokeColor: pastedElement?.strokeColor,
- fillStyle: pastedElement?.fillStyle,
- opacity: pastedElement?.opacity,
- roughness: pastedElement?.roughness
- };
- if (isTextElement(newElement)) {
- newElement.font = pastedElement?.font;
- redrawTextBoundingBox(newElement);
- }
- return newElement;
- }
- return element;
- });
- this.forceUpdate();
- };
-
- private moveAllLeft = () => {
- elements = moveAllLeft([...elements], getSelectedIndices(elements));
- this.forceUpdate();
- };
-
- private moveOneLeft = () => {
- elements = moveOneLeft([...elements], getSelectedIndices(elements));
- this.forceUpdate();
- };
-
- private moveAllRight = () => {
- elements = moveAllRight([...elements], getSelectedIndices(elements));
- this.forceUpdate();
- };
-
- private moveOneRight = () => {
- elements = moveOneRight([...elements], getSelectedIndices(elements));
- this.forceUpdate();
- };
-
private removeWheelEventListener: (() => void) | undefined;
- private changeProperty = (
- callback: (element: ExcalidrawElement) => ExcalidrawElement
- ) => {
- elements = elements.map(element => {
- if (element.isSelected) {
- return callback(element);
- }
- return element;
- });
-
- this.forceUpdate();
- };
-
private copyToClipboard = () => {
if (navigator.clipboard) {
const text = JSON.stringify(
@@ -384,6 +323,9 @@ export class App extends React.Component<{}, AppState> {
}}
>