Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support customType in activeTool #5144

Merged
merged 5 commits into from May 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 18 additions & 11 deletions src/actions/actionCanvas.tsx
Expand Up @@ -11,7 +11,7 @@ import { getNormalizedZoom, getSelectedElements } from "../scene";
import { centerScrollOn } from "../scene/scroll";
import { getStateForZoom } from "../scene/zoom";
import { AppState, NormalizedZoomValue } from "../types";
import { getShortcutKey } from "../utils";
import { getShortcutKey, updateActiveTool } from "../utils";
import { register } from "./register";
import { Tooltip } from "../components/Tooltip";
import { newElementWith } from "../element/mutateElement";
Expand Down Expand Up @@ -304,21 +304,28 @@ export const actionErase = register({
name: "eraser",
trackEvent: { category: "toolbar" },
perform: (elements, appState) => {
let activeTool: AppState["activeTool"];

if (isEraserActive(appState)) {
activeTool = updateActiveTool(appState, {
...(appState.activeTool.lastActiveToolBeforeEraser || {
type: "selection",
}),
lastActiveToolBeforeEraser: null,
});
} else {
activeTool = updateActiveTool(appState, {
type: "eraser",
lastActiveToolBeforeEraser: appState.activeTool,
});
}

return {
appState: {
...appState,
selectedElementIds: {},
selectedGroupIds: {},
activeTool: {
...appState.activeTool,
type: isEraserActive(appState)
? appState.activeTool.lastActiveToolBeforeEraser ?? "selection"
: "eraser",
lastActiveToolBeforeEraser:
appState.activeTool.type === "eraser" //node throws incorrect type error when using isEraserActive()
? null
: appState.activeTool.type,
},
activeTool,
},
commitToHistory: true,
};
Expand Down
3 changes: 2 additions & 1 deletion src/actions/actionDeleteSelected.tsx
Expand Up @@ -12,6 +12,7 @@ import { getElementsInGroup } from "../groups";
import { LinearElementEditor } from "../element/linearElementEditor";
import { fixBindingsAfterDeletion } from "../element/binding";
import { isBoundToContainer } from "../element/typeChecks";
import { updateActiveTool } from "../utils";

const deleteSelectedElements = (
elements: readonly ExcalidrawElement[],
Expand Down Expand Up @@ -134,7 +135,7 @@ export const actionDeleteSelected = register({
elements: nextElements,
appState: {
...nextAppState,
activeTool: { ...appState.activeTool, type: "selection" },
activeTool: updateActiveTool(appState, { type: "selection" }),
multiElement: null,
},
commitToHistory: isSomeElementSelected(
Expand Down
26 changes: 17 additions & 9 deletions src/actions/actionFinalize.tsx
@@ -1,6 +1,6 @@
import { KEYS } from "../keys";
import { isInvisiblySmallElement } from "../element";
import { resetCursor } from "../utils";
import { updateActiveTool, resetCursor } from "../utils";
import { ToolButton } from "../components/ToolButton";
import { done } from "../components/icons";
import { t } from "../i18n";
Expand All @@ -14,6 +14,7 @@ import {
bindOrUnbindLinearElement,
} from "../element/binding";
import { isBindingElement } from "../element/typeChecks";
import { AppState } from "../types";

export const actionFinalize = register({
name: "finalize",
Expand Down Expand Up @@ -137,6 +138,20 @@ export const actionFinalize = register({
resetCursor(canvas);
}

let activeTool: AppState["activeTool"];
if (appState.activeTool.type === "eraser") {
activeTool = updateActiveTool(appState, {
...(appState.activeTool.lastActiveToolBeforeEraser || {
type: "selection",
}),
lastActiveToolBeforeEraser: null,
});
} else {
activeTool = updateActiveTool(appState, {
type: "selection",
});
}

return {
elements: newElements,
appState: {
Expand All @@ -147,14 +162,7 @@ export const actionFinalize = register({
appState.activeTool.type === "freedraw") &&
multiPointElement
? appState.activeTool
: {
...appState.activeTool,
type:
appState.activeTool.type === "eraser" &&
appState.activeTool.lastActiveToolBeforeEraser
? appState.activeTool.lastActiveToolBeforeEraser
: "selection",
},
: activeTool,
draggingElement: null,
multiElement: null,
editingElement: null,
Expand Down
1 change: 1 addition & 0 deletions src/appState.ts
Expand Up @@ -43,6 +43,7 @@ export const getDefaultAppState = (): Omit<
editingLinearElement: null,
activeTool: {
type: "selection",
customType: null,
locked: false,
lastActiveToolBeforeEraser: null,
},
Expand Down
11 changes: 9 additions & 2 deletions src/components/Actions.tsx
Expand Up @@ -15,7 +15,12 @@ import {
} from "../scene";
import { SHAPES } from "../shapes";
import { AppState, Zoom } from "../types";
import { capitalizeString, isTransparent, setCursorForShape } from "../utils";
import {
capitalizeString,
isTransparent,
updateActiveTool,
setCursorForShape,
} from "../utils";
import Stack from "./Stack";
import { ToolButton } from "./ToolButton";
import { hasStrokeColor } from "../scene/comparisons";
Expand Down Expand Up @@ -229,7 +234,9 @@ export const ShapesSwitcher = ({
if (appState.activeTool.type !== value) {
trackEvent("toolbar", value, "ui");
}
const nextActiveTool = { ...activeTool, type: value };
const nextActiveTool = updateActiveTool(appState, {
type: value,
});
setAppState({
activeTool: nextActiveTool,
multiElement: null,
Expand Down
49 changes: 31 additions & 18 deletions src/components/App.tsx
Expand Up @@ -183,7 +183,7 @@ import {
import Scene from "../scene/Scene";
import { RenderConfig, ScrollBars } from "../scene/types";
import { getStateForZoom } from "../scene/zoom";
import { findShapeByKey } from "../shapes";
import { findShapeByKey, SHAPES } from "../shapes";
import {
AppClassProperties,
AppProps,
Expand Down Expand Up @@ -219,6 +219,7 @@ import {
withBatchedUpdatesThrottled,
updateObject,
setEraserCursor,
updateActiveTool,
} from "../utils";
import ContextMenu, { ContextMenuOption } from "./ContextMenu";
import LayerUI from "./LayerUI";
Expand Down Expand Up @@ -1074,7 +1075,7 @@ class App extends React.Component<AppProps, AppState> {
isEraserActive(this.state)
) {
this.setState({
activeTool: { ...this.state.activeTool, type: "selection" },
activeTool: updateActiveTool(this.state, { type: "selection" }),
});
}
if (
Expand Down Expand Up @@ -1444,7 +1445,7 @@ class App extends React.Component<AppProps, AppState> {
} else if (data.text) {
this.addTextFromPaste(data.text);
}
this.setActiveTool({ ...this.state.activeTool, type: "selection" });
this.setActiveTool({ type: "selection" });
event?.preventDefault();
},
);
Expand Down Expand Up @@ -1532,7 +1533,7 @@ class App extends React.Component<AppProps, AppState> {
}
},
);
this.setActiveTool({ ...this.state.activeTool, type: "selection" });
this.setActiveTool({ type: "selection" });
};

private addTextFromPaste(text: any) {
Expand Down Expand Up @@ -1594,10 +1595,13 @@ class App extends React.Component<AppProps, AppState> {
return {
activeTool: {
...prevState.activeTool,
...updateActiveTool(
this.state,
prevState.activeTool.locked
? { type: "selection" }
: prevState.activeTool,
),
locked: !prevState.activeTool.locked,
type: prevState.activeTool.locked
? "selection"
: prevState.activeTool.type,
},
};
});
Expand Down Expand Up @@ -1895,7 +1899,7 @@ class App extends React.Component<AppProps, AppState> {
`keyboard (${this.deviceType.isMobile ? "mobile" : "desktop"})`,
);
}
this.setActiveTool({ ...this.state.activeTool, type: shape });
this.setActiveTool({ type: shape });
event.stopPropagation();
} else if (event.key === KEYS.Q) {
this.toggleLock("keyboard");
Expand Down Expand Up @@ -1971,28 +1975,33 @@ class App extends React.Component<AppProps, AppState> {
}
});

private setActiveTool(tool: AppState["activeTool"]) {
private setActiveTool(
tool:
| { type: typeof SHAPES[number]["value"] | "eraser" }
| { type: "custom"; customType: string },
) {
const nextActiveTool = updateActiveTool(this.state, tool);
if (!isHoldingSpace) {
setCursorForShape(this.canvas, this.state);
}
if (isToolIcon(document.activeElement)) {
this.focusContainer();
}
if (!isLinearElementType(tool.type)) {
if (!isLinearElementType(nextActiveTool.type)) {
this.setState({ suggestedBindings: [] });
}
if (tool.type === "image") {
if (nextActiveTool.type === "image") {
this.onImageAction();
}
if (tool.type !== "selection") {
if (nextActiveTool.type !== "selection") {
this.setState({
activeTool: tool,
activeTool: nextActiveTool,
selectedElementIds: {},
selectedGroupIds: {},
editingGroupId: null,
});
} else {
this.setState({ activeTool: tool });
this.setState({ activeTool: nextActiveTool });
}
}

Expand Down Expand Up @@ -3057,6 +3066,8 @@ class App extends React.Component<AppProps, AppState> {
this.state.activeTool.type,
pointerDownState,
);
} else if (this.state.activeTool.type === "custom") {
setCursor(this.canvas, CURSOR_TYPE.CROSSHAIR);
} else if (this.state.activeTool.type !== "eraser") {
this.createGenericElementOnPointerDown(
this.state.activeTool.type,
Expand Down Expand Up @@ -3638,7 +3649,7 @@ class App extends React.Component<AppProps, AppState> {
resetCursor(this.canvas);
if (!this.state.activeTool.locked) {
this.setState({
activeTool: { ...this.state.activeTool, type: "selection" },
activeTool: updateActiveTool(this.state, { type: "selection" }),
});
}
};
Expand Down Expand Up @@ -4457,7 +4468,9 @@ class App extends React.Component<AppProps, AppState> {
resetCursor(this.canvas);
this.setState((prevState) => ({
draggingElement: null,
activeTool: { ...prevState.activeTool, type: "selection" },
activeTool: updateActiveTool(this.state, {
type: "selection",
}),
selectedElementIds: {
...prevState.selectedElementIds,
[this.state.draggingElement!.id]: true,
Expand Down Expand Up @@ -4679,7 +4692,7 @@ class App extends React.Component<AppProps, AppState> {
this.setState({
draggingElement: null,
suggestedBindings: [],
activeTool: { ...activeTool, type: "selection" },
activeTool: updateActiveTool(this.state, { type: "selection" }),
});
} else {
this.setState({
Expand Down Expand Up @@ -4985,7 +4998,7 @@ class App extends React.Component<AppProps, AppState> {
{
pendingImageElement: null,
editingElement: null,
activeTool: { ...this.state.activeTool, type: "selection" },
activeTool: updateActiveTool(this.state, { type: "selection" }),
},
() => {
this.actionManager.executeAction(actionFinalize);
Expand Down
15 changes: 11 additions & 4 deletions src/data/restore.ts
Expand Up @@ -26,7 +26,7 @@ import {
import { getDefaultAppState } from "../appState";
import { LinearElementEditor } from "../element/linearElementEditor";
import { bumpVersion } from "../element/mutateElement";
import { getUpdatedTimestamp } from "../utils";
import { getUpdatedTimestamp, updateActiveTool } from "../utils";
import { arrayToMap } from "../utils";

type RestoredAppState = Omit<
Expand All @@ -48,6 +48,7 @@ export const AllowedExcalidrawActiveTools: Record<
arrow: true,
freedraw: true,
eraser: false,
custom: true,
};

export type RestoredDataState = {
Expand Down Expand Up @@ -198,6 +199,7 @@ const restoreElement = (
y,
});
}

// generic elements
case "ellipse":
return restoreElementWithProperties(element, {});
Expand Down Expand Up @@ -255,6 +257,7 @@ export const restoreAppState = (
? localValue
: defaultValue;
}

return {
...nextAppState,
cursorButton: localAppState?.cursorButton || "up",
Expand All @@ -263,11 +266,15 @@ export const restoreAppState = (
localAppState?.penDetected ??
(appState.penMode ? appState.penDetected ?? false : false),
activeTool: {
...updateActiveTool(
defaultAppState,
nextAppState.activeTool.type &&
AllowedExcalidrawActiveTools[nextAppState.activeTool.type]
? nextAppState.activeTool
: { type: "selection" },
),
lastActiveToolBeforeEraser: null,
locked: nextAppState.activeTool.locked ?? false,
type: AllowedExcalidrawActiveTools[nextAppState.activeTool.type]
? nextAppState.activeTool.type ?? "selection"
: "selection",
},
// Migrates from previous version where appState.zoom was a number
zoom:
Expand Down