feat: Support customising canvas actions 🎉 (#3364)

* feat: Support hiding save, save as, clear & export

* Remove canvasActions from state & minor changes

* Rename prop to UIOptions & pass default value

* Make requested changes

* better type checking so that optional check not needed at every point

* remove optional checks

* Add few tests

* Add describe block for canvasActions & use snapshot tests

* Add support for hiding canvas background picker

* Take snapshot of canvasActions instead of the whole app

* Add support for hiding dark mode toggle

* Update README.md

* Rename table heading

* Update changelog

* Make requested changes

* Update test name

* tweaks

Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
This commit is contained in:
Arun 2021-04-04 15:57:14 +05:30 committed by GitHub
parent c54a099010
commit 233576628c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 637 additions and 15 deletions

View file

@ -33,6 +33,7 @@ export const actionChangeViewBackgroundColor = register({
type="canvasBackground"
color={appState.viewBackgroundColor}
onChange={(color) => updateData(color)}
data-testid="canvas-background-picker"
/>
</div>
);
@ -72,6 +73,7 @@ export const actionClearCanvas = register({
updateData(null);
}
}}
data-testid="clear-canvas-button"
/>
),
});

View file

@ -136,6 +136,7 @@ export const actionSaveScene = register({
aria-label={t("buttons.save")}
showAriaLabel={useIsMobile()}
onClick={() => updateData(null)}
data-testid="save-button"
/>
),
});
@ -167,6 +168,7 @@ export const actionSaveAsScene = register({
showAriaLabel={useIsMobile()}
hidden={!supported}
onClick={() => updateData(null)}
data-testid="save-as-button"
/>
),
});
@ -204,6 +206,7 @@ export const actionLoadScene = register({
aria-label={t("buttons.load")}
showAriaLabel={useIsMobile()}
onClick={updateData}
data-testid="load-button"
/>
),
});

View file

@ -7,12 +7,12 @@ import {
ActionResult,
} from "./types";
import { ExcalidrawElement } from "../element/types";
import { AppState, ExcalidrawProps } from "../types";
import { AppProps, AppState } from "../types";
import { MODES } from "../constants";
// This is the <App> component, but for now we don't care about anything but its
// `canvas` state.
type App = { canvas: HTMLCanvasElement | null; props: ExcalidrawProps };
type App = { canvas: HTMLCanvasElement | null; props: AppProps };
export class ActionManager implements ActionsManagerInterface {
actions = {} as ActionsManagerInterface["actions"];
@ -52,10 +52,14 @@ export class ActionManager implements ActionsManagerInterface {
}
handleKeyDown(event: KeyboardEvent) {
const canvasActions = this.app.props.UIOptions.canvasActions;
const data = Object.values(this.actions)
.sort((a, b) => (b.keyPriority || 0) - (a.keyPriority || 0))
.filter(
(action) =>
(action.name in canvasActions
? canvasActions[action.name as keyof typeof canvasActions]
: true) &&
action.keyTest &&
action.keyTest(
event,
@ -102,7 +106,15 @@ export class ActionManager implements ActionsManagerInterface {
// 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) => {
if (this.actions[name] && "PanelComponent" in this.actions[name]) {
const canvasActions = this.app.props.UIOptions.canvasActions;
if (
this.actions[name] &&
"PanelComponent" in this.actions[name] &&
(name in canvasActions
? canvasActions[name as keyof typeof canvasActions]
: true)
) {
const action = this.actions[name];
const PanelComponent = action.PanelComponent!;
const updateData = (formState?: any) => {