Add NonDeleted<ExcalidrawElement> (#1068)

* add NonDeleted

* make test:all script run tests without prompt

* rename helper

* replace with helper

* make element contructors return nonDeleted elements

* cache filtered elements where appliacable for better perf

* rename manager element getter

* remove unnecessary assertion

* fix test

* make element types in resizeElement into nonDeleted

Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
Pete Hunt 2020-04-08 09:49:52 -07:00 committed by GitHub
parent c714c778ab
commit df0613d8ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 260 additions and 189 deletions

View file

@ -5,6 +5,7 @@ import React from "react";
import { trash } from "../components/icons";
import { t } from "../i18n";
import { register } from "./register";
import { getNonDeletedElements } from "../element";
export const actionDeleteSelected = register({
name: "deleteSelectedElements",
@ -20,7 +21,10 @@ export const actionDeleteSelected = register({
elementType: "selection",
multiElement: null,
},
commitToHistory: isSomeElementSelected(elements, appState),
commitToHistory: isSomeElementSelected(
getNonDeletedElements(elements),
appState,
),
};
},
contextItemLabel: "labels.delete",
@ -33,7 +37,7 @@ export const actionDeleteSelected = register({
title={t("labels.delete")}
aria-label={t("labels.delete")}
onClick={() => updateData(null)}
visible={isSomeElementSelected(elements, appState)}
visible={isSomeElementSelected(getNonDeletedElements(elements), appState)}
/>
),
});

View file

@ -2,7 +2,7 @@ import React from "react";
import { KEYS } from "../keys";
import { register } from "./register";
import { ExcalidrawElement } from "../element/types";
import { duplicateElement } from "../element";
import { duplicateElement, getNonDeletedElements } from "../element";
import { isSomeElementSelected } from "../scene";
import { ToolButton } from "../components/ToolButton";
import { clone } from "../components/icons";
@ -43,7 +43,7 @@ export const actionDuplicateSelection = register({
)}`}
aria-label={t("labels.duplicateSelection")}
onClick={() => updateData(null)}
visible={isSomeElementSelected(elements, appState)}
visible={isSomeElementSelected(getNonDeletedElements(elements), appState)}
/>
),
});

View file

@ -2,7 +2,7 @@ import React from "react";
import { menu, palette } from "../components/icons";
import { ToolButton } from "../components/ToolButton";
import { t } from "../i18n";
import { showSelectedShapeActions } from "../element";
import { showSelectedShapeActions, getNonDeletedElements } from "../element";
import { register } from "./register";
import { allowFullScreen, exitFullScreen, isFullScreen } from "../utils";
import { KEYS } from "../keys";
@ -39,7 +39,10 @@ export const actionToggleEditMenu = register({
}),
PanelComponent: ({ elements, appState, updateData }) => (
<ToolButton
visible={showSelectedShapeActions(appState, elements)}
visible={showSelectedShapeActions(
appState,
getNonDeletedElements(elements),
)}
type="button"
icon={palette}
aria-label={t("buttons.edit")}

View file

@ -5,7 +5,11 @@ import {
isSomeElementSelected,
} from "../scene";
import { ButtonSelect } from "../components/ButtonSelect";
import { isTextElement, redrawTextBoundingBox } from "../element";
import {
isTextElement,
redrawTextBoundingBox,
getNonDeletedElements,
} from "../element";
import { ColorPicker } from "../components/ColorPicker";
import { AppState } from "../../src/types";
import { t } from "../i18n";
@ -33,10 +37,15 @@ const getFormValue = function <T>(
defaultValue?: T,
): T | null {
const editingElement = appState.editingElement;
const nonDeletedElements = getNonDeletedElements(elements);
return (
(editingElement && getAttribute(editingElement)) ??
(isSomeElementSelected(elements, appState)
? getCommonAttributeOfSelectedElements(elements, appState, getAttribute)
(isSomeElementSelected(nonDeletedElements, appState)
? getCommonAttributeOfSelectedElements(
nonDeletedElements,
appState,
getAttribute,
)
: defaultValue) ??
null
);

View file

@ -9,6 +9,7 @@ import {
import { ExcalidrawElement } from "../element/types";
import { AppState } from "../types";
import { t } from "../i18n";
import { globalSceneState } from "../scene";
export class ActionManager implements ActionsManagerInterface {
actions = {} as ActionsManagerInterface["actions"];
@ -17,16 +18,18 @@ export class ActionManager implements ActionsManagerInterface {
getAppState: () => AppState;
getElements: () => readonly ExcalidrawElement[];
getElementsIncludingDeleted: () => readonly ExcalidrawElement[];
constructor(
updater: UpdaterFn,
getAppState: () => AppState,
getElements: () => readonly ExcalidrawElement[],
getElementsIncludingDeleted: () => ReturnType<
typeof globalSceneState["getElementsIncludingDeleted"]
>,
) {
this.updater = updater;
this.getAppState = getAppState;
this.getElements = getElements;
this.getElementsIncludingDeleted = getElementsIncludingDeleted;
}
registerAction(action: Action) {
@ -43,7 +46,11 @@ export class ActionManager implements ActionsManagerInterface {
.filter(
(action) =>
action.keyTest &&
action.keyTest(event, this.getAppState(), this.getElements()),
action.keyTest(
event,
this.getAppState(),
this.getElementsIncludingDeleted(),
),
);
if (data.length === 0) {
@ -51,12 +58,24 @@ export class ActionManager implements ActionsManagerInterface {
}
event.preventDefault();
this.updater(data[0].perform(this.getElements(), this.getAppState(), null));
this.updater(
data[0].perform(
this.getElementsIncludingDeleted(),
this.getAppState(),
null,
),
);
return true;
}
executeAction(action: Action) {
this.updater(action.perform(this.getElements(), this.getAppState(), null));
this.updater(
action.perform(
this.getElementsIncludingDeleted(),
this.getAppState(),
null,
),
);
}
getContextMenuItems(actionFilter: ActionFilterFn = (action) => action) {
@ -72,7 +91,11 @@ export class ActionManager implements ActionsManagerInterface {
label: action.contextItemLabel ? t(action.contextItemLabel) : "",
action: () => {
this.updater(
action.perform(this.getElements(), this.getAppState(), null),
action.perform(
this.getElementsIncludingDeleted(),
this.getAppState(),
null,
),
);
},
}));
@ -84,13 +107,17 @@ export class ActionManager implements ActionsManagerInterface {
const PanelComponent = action.PanelComponent!;
const updateData = (formState?: any) => {
this.updater(
action.perform(this.getElements(), this.getAppState(), formState),
action.perform(
this.getElementsIncludingDeleted(),
this.getAppState(),
formState,
),
);
};
return (
<PanelComponent
elements={this.getElements()}
elements={this.getElementsIncludingDeleted()}
appState={this.getAppState()}
updateData={updateData}
/>