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