Filter context menu items through isActionEnabled
.
This commit is contained in:
parent
01432813a6
commit
a5bd54b86d
@ -75,7 +75,7 @@ export class ActionManager {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public registerActionGuards() {
|
||||
registerActionGuards() {
|
||||
const disablers = getActionDisablers();
|
||||
for (const d in disablers) {
|
||||
const dName = d as ActionName;
|
||||
@ -90,7 +90,7 @@ export class ActionManager {
|
||||
}
|
||||
}
|
||||
|
||||
public registerDisableFn(name: ActionName, disabler: DisableFn) {
|
||||
registerDisableFn(name: ActionName, disabler: DisableFn) {
|
||||
if (!(name in this.disablers)) {
|
||||
this.disablers[name] = [] as DisableFn[];
|
||||
}
|
||||
@ -99,7 +99,7 @@ export class ActionManager {
|
||||
}
|
||||
}
|
||||
|
||||
public registerEnableFn(name: Action["name"], enabler: EnableFn) {
|
||||
registerEnableFn(name: Action["name"], enabler: EnableFn) {
|
||||
if (!(name in this.enablers)) {
|
||||
this.enablers[name] = [] as EnableFn[];
|
||||
}
|
||||
@ -108,18 +108,25 @@ export class ActionManager {
|
||||
}
|
||||
}
|
||||
|
||||
public getCustomActions(opts?: {
|
||||
getCustomActions(opts?: {
|
||||
elements?: readonly ExcalidrawElement[];
|
||||
data?: Record<string, any>;
|
||||
guardsOnly?: boolean;
|
||||
}): Action[] {
|
||||
// For testing
|
||||
if (this === undefined) {
|
||||
return [];
|
||||
}
|
||||
const filter =
|
||||
opts !== undefined &&
|
||||
("elements" in opts || "data" in opts || "guardsOnly" in opts);
|
||||
const customActions: Action[] = [];
|
||||
for (const key in this.actions) {
|
||||
const action = this.actions[key];
|
||||
if (!isActionName(action.name) && this.isActionEnabled(action, opts)) {
|
||||
if (
|
||||
!isActionName(action.name) &&
|
||||
(!filter || this.isActionEnabled(action, opts))
|
||||
) {
|
||||
customActions.push(action);
|
||||
}
|
||||
}
|
||||
@ -142,7 +149,7 @@ export class ActionManager {
|
||||
(action) =>
|
||||
(action.name in canvasActions
|
||||
? canvasActions[action.name as keyof typeof canvasActions]
|
||||
: this.isActionEnabled(action)) &&
|
||||
: this.isActionEnabled(action, { guardsOnly: true })) &&
|
||||
action.keyTest &&
|
||||
action.keyTest(
|
||||
event,
|
||||
@ -200,7 +207,7 @@ export class ActionManager {
|
||||
"PanelComponent" in this.actions[name] &&
|
||||
(name in canvasActions
|
||||
? canvasActions[name as keyof typeof canvasActions]
|
||||
: this.isActionEnabled(this.actions[name]))
|
||||
: this.isActionEnabled(this.actions[name], { guardsOnly: true }))
|
||||
) {
|
||||
const action = this.actions[name];
|
||||
const PanelComponent = action.PanelComponent!;
|
||||
@ -236,35 +243,39 @@ export class ActionManager {
|
||||
};
|
||||
|
||||
isActionEnabled = (
|
||||
action: Action,
|
||||
action: Action | ActionName,
|
||||
opts?: {
|
||||
elements?: readonly ExcalidrawElement[];
|
||||
data?: Record<string, any>;
|
||||
guardsOnly?: boolean;
|
||||
},
|
||||
): boolean => {
|
||||
const elements = opts?.elements ?? this.getElementsIncludingDeleted();
|
||||
const appState = this.getAppState();
|
||||
const data = opts?.data;
|
||||
|
||||
const _action = isActionName(action) ? this.actions[action] : action;
|
||||
|
||||
if (
|
||||
action.predicate &&
|
||||
!action.predicate(elements, appState, this.app.props, this.app, data)
|
||||
!opts?.guardsOnly &&
|
||||
_action.predicate &&
|
||||
!_action.predicate(elements, appState, this.app.props, this.app, data)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isActionName(action.name)) {
|
||||
if (isActionName(_action.name)) {
|
||||
return !(
|
||||
action.name in this.disablers &&
|
||||
this.disablers[action.name].some((fn) =>
|
||||
fn(elements, appState, action.name as ActionName),
|
||||
_action.name in this.disablers &&
|
||||
this.disablers[_action.name].some((fn) =>
|
||||
fn(elements, appState, _action.name as ActionName),
|
||||
)
|
||||
);
|
||||
}
|
||||
return (
|
||||
action.name in this.enablers &&
|
||||
this.enablers[action.name].some((fn) =>
|
||||
fn(elements, appState, action.name),
|
||||
_action.name in this.enablers &&
|
||||
this.enablers[_action.name].some((fn) =>
|
||||
fn(elements, appState, _action.name),
|
||||
)
|
||||
);
|
||||
};
|
||||
|
@ -3,7 +3,7 @@ import { ActionManager } from "../actions/manager";
|
||||
import { getNonDeletedElements } from "../element";
|
||||
import { ExcalidrawElement, PointerType } from "../element/types";
|
||||
import { t } from "../i18n";
|
||||
import { useDevice } from "../components/App";
|
||||
import { useDevice, useExcalidrawActionManager } from "../components/App";
|
||||
import {
|
||||
canChangeRoundness,
|
||||
canHaveArrowheads,
|
||||
@ -36,12 +36,10 @@ export const SelectedShapeActions = ({
|
||||
appState,
|
||||
elements,
|
||||
renderAction,
|
||||
getCustomActions,
|
||||
}: {
|
||||
appState: AppState;
|
||||
elements: readonly ExcalidrawElement[];
|
||||
renderAction: ActionManager["renderAction"];
|
||||
getCustomActions: ActionManager["getCustomActions"];
|
||||
}) => {
|
||||
const targetElements = getTargetElements(
|
||||
getNonDeletedElements(elements),
|
||||
@ -94,9 +92,9 @@ export const SelectedShapeActions = ({
|
||||
{showChangeBackgroundIcons && (
|
||||
<div>{renderAction("changeBackgroundColor")}</div>
|
||||
)}
|
||||
{getCustomActions({ elements: targetElements }).map((action) =>
|
||||
renderAction(action.name),
|
||||
)}
|
||||
{useExcalidrawActionManager()
|
||||
.getCustomActions({ elements: targetElements })
|
||||
.map((action) => renderAction(action.name))}
|
||||
{showFillIcons && renderAction("changeFillStyle")}
|
||||
|
||||
{(hasStrokeWidth(appState.activeTool.type) ||
|
||||
|
@ -6167,20 +6167,29 @@ class App extends React.Component<AppProps, AppState> {
|
||||
type: "canvas" | "element" | "custom",
|
||||
source?: string,
|
||||
): ContextMenuItems => {
|
||||
const options: ContextMenuItems = [];
|
||||
let addedCustom = false;
|
||||
const custom: ContextMenuItems = [];
|
||||
this.actionManager
|
||||
.getCustomActions({ data: { source } })
|
||||
.forEach((action) => {
|
||||
addedCustom = true;
|
||||
options.push(action);
|
||||
});
|
||||
.getCustomActions({ data: { source: source ?? "" } })
|
||||
.forEach((action) => custom.push(action));
|
||||
if (type === "custom") {
|
||||
return options;
|
||||
return custom;
|
||||
}
|
||||
if (addedCustom) {
|
||||
options.push(CONTEXT_MENU_SEPARATOR);
|
||||
if (custom.length > 0) {
|
||||
custom.push(CONTEXT_MENU_SEPARATOR);
|
||||
}
|
||||
const standard: ContextMenuItems = this._getContextMenuItems(type).filter(
|
||||
(item) =>
|
||||
!item ||
|
||||
item === CONTEXT_MENU_SEPARATOR ||
|
||||
this.actionManager.isActionEnabled(item, { guardsOnly: true }),
|
||||
);
|
||||
return [...custom, ...standard];
|
||||
};
|
||||
|
||||
private _getContextMenuItems = (
|
||||
type: "canvas" | "element",
|
||||
): ContextMenuItems => {
|
||||
const options: ContextMenuItems = [];
|
||||
|
||||
options.push(actionCopyAsPng, actionCopyAsSvg);
|
||||
|
||||
|
@ -244,7 +244,6 @@ const LayerUI = ({
|
||||
appState={appState}
|
||||
elements={elements}
|
||||
renderAction={actionManager.renderAction}
|
||||
getCustomActions={actionManager.getCustomActions}
|
||||
/>
|
||||
</Island>
|
||||
</Section>
|
||||
|
@ -193,7 +193,6 @@ export const MobileMenu = ({
|
||||
appState={appState}
|
||||
elements={elements}
|
||||
renderAction={actionManager.renderAction}
|
||||
getCustomActions={actionManager.getCustomActions}
|
||||
/>
|
||||
</Section>
|
||||
) : null}
|
||||
|
Loading…
x
Reference in New Issue
Block a user