feat: add undo/redo buttons & tweak footer (#3832)

Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
This commit is contained in:
David Luzar 2021-07-15 18:48:03 +02:00 committed by GitHub
parent 685abac81a
commit 99623334d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 152 additions and 125 deletions

View file

@ -1,7 +1,7 @@
import React from "react";
import { getDefaultAppState } from "../appState";
import { ColorPicker } from "../components/ColorPicker";
import { resetZoom, trash, zoomIn, zoomOut } from "../components/icons";
import { trash, zoomIn, zoomOut } from "../components/icons";
import { ToolButton } from "../components/ToolButton";
import { DarkModeToggle } from "../components/DarkModeToggle";
import { ZOOM_STEP } from "../constants";
@ -17,6 +17,7 @@ import { getNewZoom } from "../scene/zoom";
import { AppState, NormalizedZoomValue } from "../types";
import { getShortcutKey } from "../utils";
import { register } from "./register";
import { Tooltip } from "../components/Tooltip";
export const actionChangeViewBackgroundColor = register({
name: "changeViewBackgroundColor",
@ -108,6 +109,7 @@ export const actionZoomIn = register({
onClick={() => {
updateData(null);
}}
size="small"
/>
),
keyTest: (event) =>
@ -142,6 +144,7 @@ export const actionZoomOut = register({
onClick={() => {
updateData(null);
}}
size="small"
/>
),
keyTest: (event) =>
@ -168,16 +171,21 @@ export const actionResetZoom = register({
commitToHistory: false,
};
},
PanelComponent: ({ updateData }) => (
<ToolButton
type="button"
icon={resetZoom}
title={t("buttons.resetZoom")}
aria-label={t("buttons.resetZoom")}
onClick={() => {
updateData(null);
}}
/>
PanelComponent: ({ updateData, appState }) => (
<Tooltip label={t("buttons.resetZoom")}>
<ToolButton
type="button"
className="reset-zoom-button"
title={t("buttons.resetZoom")}
aria-label={t("buttons.resetZoom")}
onClick={() => {
updateData(null);
}}
size="small"
>
{(appState.zoom.value * 100).toFixed(0)}%
</ToolButton>
</Tooltip>
),
keyTest: (event) =>
(event.code === CODES.ZERO || event.code === CODES.NUM_ZERO) &&

View file

@ -70,7 +70,7 @@ export const actionChangeExportScale = register({
return (
<ToolButton
key={s}
size="s"
size="small"
type="radio"
icon={`${s}x`}
name="export-canvas-scale"
@ -120,7 +120,7 @@ export const actionChangeExportEmbedScene = register({
>
{t("labels.exportEmbedScene")}
<Tooltip label={t("labels.exportEmbedScene_details")} long={true}>
<div className="Tooltip-icon">{questionCircle}</div>
<div className="excalidraw-tooltip-icon">{questionCircle}</div>
</Tooltip>
</CheckboxItem>
),

View file

@ -69,12 +69,13 @@ export const createUndoAction: ActionCreator = (history) => ({
event[KEYS.CTRL_OR_CMD] &&
event.key.toLowerCase() === KEYS.Z &&
!event.shiftKey,
PanelComponent: ({ updateData }) => (
PanelComponent: ({ updateData, data }) => (
<ToolButton
type="button"
icon={undo}
aria-label={t("buttons.undo")}
onClick={updateData}
size={data?.size || "medium"}
/>
),
commitToHistory: () => false,
@ -89,12 +90,13 @@ export const createRedoAction: ActionCreator = (history) => ({
event.shiftKey &&
event.key.toLowerCase() === KEYS.Z) ||
(isWindows && event.ctrlKey && !event.shiftKey && event.key === KEYS.Y),
PanelComponent: ({ updateData }) => (
PanelComponent: ({ updateData, data }) => (
<ToolButton
type="button"
icon={redo}
aria-label={t("buttons.redo")}
onClick={updateData}
size={data?.size || "medium"}
/>
),
commitToHistory: () => false,

View file

@ -30,8 +30,8 @@ export const actionGoToCollaborator = register({
commitToHistory: false,
};
},
PanelComponent: ({ appState, updateData, id }) => {
const clientId = id;
PanelComponent: ({ appState, updateData, data }) => {
const clientId: string | undefined = data?.id;
if (!clientId) {
return null;
}

View file

@ -5,6 +5,7 @@ import {
UpdaterFn,
ActionName,
ActionResult,
PanelComponentProps,
} from "./types";
import { ExcalidrawElement } from "../element/types";
import { AppProps, AppState } from "../types";
@ -107,11 +108,10 @@ export class ActionManager implements ActionsManagerInterface {
);
}
// Id is an attribute that we can use to pass in data like keys.
// This is needed for dynamically generated action components
// like the user list. We can use this key to extract more
// data from app state. This is an alternative to generic prop hell!
renderAction = (name: ActionName, id?: string) => {
/**
* @param data additional data sent to the PanelComponent
*/
renderAction = (name: ActionName, data?: PanelComponentProps["data"]) => {
const canvasActions = this.app.props.UIOptions.canvasActions;
if (
@ -139,8 +139,8 @@ export class ActionManager implements ActionsManagerInterface {
elements={this.getElementsIncludingDeleted()}
appState={this.getAppState()}
updateData={updateData}
id={id}
appProps={this.app.props}
data={data}
/>
);
}

View file

@ -2,6 +2,7 @@ import React from "react";
import { ExcalidrawElement } from "../element/types";
import { AppState, ExcalidrawProps } from "../types";
import Library from "../data/library";
import { ToolButtonSize } from "../components/ToolButton";
/** if false, the action should be prevented */
export type ActionResult =
@ -102,15 +103,17 @@ export type ActionName =
| "exportWithDarkMode"
| "toggleTheme";
export type PanelComponentProps = {
elements: readonly ExcalidrawElement[];
appState: AppState;
updateData: (formData?: any) => void;
appProps: ExcalidrawProps;
data?: Partial<{ id: string; size: ToolButtonSize }>;
};
export interface Action {
name: ActionName;
PanelComponent?: React.FC<{
elements: readonly ExcalidrawElement[];
appState: AppState;
updateData: (formData?: any) => void;
appProps: ExcalidrawProps;
id?: string;
}>;
PanelComponent?: React.FC<PanelComponentProps>;
perform: ActionFn;
keyPriority?: number;
keyTest?: (