mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
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:
parent
c714c778ab
commit
df0613d8ac
29 changed files with 260 additions and 189 deletions
|
@ -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)}
|
||||
/>
|
||||
),
|
||||
});
|
||||
|
|
|
@ -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)}
|
||||
/>
|
||||
),
|
||||
});
|
||||
|
|
|
@ -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")}
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue