Skip to content

Commit bb5d7dd

Browse files
liujupingJackLian
authored andcommitted
feat(context-menu): update context-menu docs, details, styles
1 parent 3e7d199 commit bb5d7dd

File tree

10 files changed

+254
-75
lines changed

10 files changed

+254
-75
lines changed

docs/docs/api/commonUI.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,70 @@ CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开
4848
| condition | 显示条件函数<br/>Function to determine display condition | (nodes: IPublicModelNode[]) => boolean (optional) | |
4949
| disabled | 禁用条件函数,可选<br/>Function to determine disabled condition, optional | (nodes: IPublicModelNode[]) => boolean (optional) | |
5050

51+
**ContextMenu 示例**
52+
53+
```typescript
54+
const App = () => {
55+
const menuItems: IPublicTypeContextMenuAction[] = [
56+
{
57+
name: 'a',
58+
title: '选项 1',
59+
action: () => console.log('选项 1 被点击'),
60+
},
61+
{
62+
name: 'b',
63+
title: '选项 2',
64+
action: () => console.log('选项 2 被点击'),
65+
},
66+
];
67+
68+
const ContextMenu = ctx.commonUI.ContextMenu;
69+
70+
return (
71+
<div>
72+
<ContextMenu menus={menuItems}>
73+
<div>右键点击这里</div>
74+
</ContextMenu>
75+
</div>
76+
);
77+
};
78+
79+
export default App;
80+
```
81+
82+
**ContextMenu.create 示例**
83+
84+
```typescript
85+
const App = () => {
86+
const menuItems: IPublicTypeContextMenuAction[] = [
87+
{
88+
name: 'a',
89+
title: '选项 1',
90+
action: () => console.log('选项 1 被点击'),
91+
},
92+
{
93+
name: 'b',
94+
title: '选项 2',
95+
action: () => console.log('选项 2 被点击'),
96+
},
97+
];
98+
99+
const ContextMenu = ctx.commonUI.ContextMenu;
100+
101+
return (
102+
<div>
103+
<div onClick={(e) => {
104+
ContextMenu.create(menuItems, e);
105+
}}>点击这里</div>
106+
</div>
107+
);
108+
};
109+
110+
export default App;
111+
```
51112

52113
### Balloon
114+
53115
详细文档: [Balloon Documentation](https://fusion.design/pc/component/balloon)
54116

55117
### Breadcrumb

docs/docs/api/material.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,33 @@ material.modifyBuiltinComponentAction('remove', (action) => {
250250
addContextMenuOption(action: IPublicTypeContextMenuAction): void;
251251
```
252252

253+
示例
254+
255+
```typescript
256+
import { IPublicEnumContextMenuType } from '@alilc/lowcode-types';
257+
258+
material.addContextMenuOption({
259+
name: 'parentItem',
260+
title: 'Parent Item',
261+
condition: (nodes) => true,
262+
items: [
263+
{
264+
name: 'childItem1',
265+
title: 'Child Item 1',
266+
action: (nodes) => console.log('Child Item 1 clicked', nodes),
267+
condition: (nodes) => true
268+
},
269+
// 分割线
270+
{
271+
type: IPublicEnumContextMenuType.SEPARATOR
272+
name: 'separator.1'
273+
}
274+
// 更多子菜单项...
275+
]
276+
});
277+
278+
```
279+
253280
#### removeContextMenuOption
254281

255282
删除特定右键菜单项
@@ -274,7 +301,26 @@ removeContextMenuOption(name: string): void;
274301
adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]): void;
275302
```
276303

304+
**示例**
305+
306+
通过 adjustContextMenuLayout 补充分割线
307+
308+
```typescript
309+
material.adjustContextMenuLayout((actions: IPublicTypeContextMenuAction) => {
310+
const names = ['a', 'b'];
311+
const newActions = [];
312+
actions.forEach(d => {
313+
newActions.push(d);
314+
if (names.include(d.name)) {
315+
newActions.push({ type: 'separator' })
316+
}
317+
});
318+
return newActions
319+
})
320+
```
321+
277322
### 物料元数据
323+
278324
#### getComponentMeta
279325
获取指定名称的物料元数据
280326

packages/designer/src/context-menu-actions.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial } from '@alilc/lowcode-types';
1+
import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial, IPublicModelPluginContext } from '@alilc/lowcode-types';
22
import { IDesigner, INode } from './designer';
33
import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties, uniqueId } from '@alilc/lowcode-utils';
44
import { Menu } from '@alifd/next';
@@ -48,6 +48,7 @@ export class GlobalContextMenuActions {
4848
event.preventDefault();
4949

5050
const actions: IPublicTypeContextMenuAction[] = [];
51+
let contextMenu: ContextMenuActions = this.contextMenuActionsMap.values().next().value;
5152
this.contextMenuActionsMap.forEach((contextMenu) => {
5253
actions.push(...contextMenu.actions);
5354
});
@@ -57,11 +58,13 @@ export class GlobalContextMenuActions {
5758
const destroy = () => {
5859
destroyFn?.();
5960
};
61+
const pluginContext: IPublicModelPluginContext = contextMenu.designer.editor.get('pluginContext') as IPublicModelPluginContext;
6062

6163
const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, {
6264
nodes: [],
6365
destroy,
6466
event,
67+
pluginContext,
6568
});
6669

6770
if (!menus.length) {
@@ -73,6 +76,7 @@ export class GlobalContextMenuActions {
7376
const menuNode = parseContextMenuAsReactNode(layoutMenu, {
7477
destroy,
7578
nodes: [],
79+
pluginContext,
7680
});
7781

7882
const target = event.target;
@@ -160,10 +164,13 @@ export class ContextMenuActions implements IContextMenuActions {
160164
destroyFn?.();
161165
};
162166

167+
const pluginContext: IPublicModelPluginContext = this.designer.editor.get('pluginContext') as IPublicModelPluginContext;
168+
163169
const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, {
164170
nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!),
165171
destroy,
166172
event,
173+
pluginContext,
167174
});
168175

169176
if (!menus.length) {
@@ -175,7 +182,7 @@ export class ContextMenuActions implements IContextMenuActions {
175182
const menuNode = parseContextMenuAsReactNode(layoutMenu, {
176183
destroy,
177184
nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!),
178-
designer,
185+
pluginContext,
179186
});
180187

181188
destroyFn = createContextMenu(menuNode, {

packages/engine/src/engine-core.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,11 @@ const innerSetters = new InnerSetters();
115115
const setters = new Setters(innerSetters);
116116

117117
const material = new Material(editor);
118-
const commonUI = new CommonUI();
118+
const commonUI = new CommonUI(editor);
119119
editor.set('project', project);
120120
editor.set('setters' as any, setters);
121121
editor.set('material', material);
122122
editor.set('innerHotkey', innerHotkey);
123-
editor.set('commonUI' as any, commonUI);
124123
const config = new Config(engineConfig);
125124
const event = new Event(commonEvent, { prefix: 'common' });
126125
const logger = new Logger({ level: 'warn', bizName: 'common' });
@@ -147,6 +146,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = {
147146
context.commonUI = commonUI;
148147
context.registerLevel = IPublicEnumPluginRegisterLevel.Default;
149148
context.isPluginRegisteredInWorkspace = false;
149+
editor.set('pluginContext', context);
150150
},
151151
};
152152

packages/engine/src/inner-plugins/default-context-menu.ts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,18 @@ import {
55
IPublicModelNode,
66
IPublicModelPluginContext,
77
IPublicTypeDragNodeDataObject,
8-
IPublicTypeI18nData,
98
IPublicTypeNodeSchema,
109
} from '@alilc/lowcode-types';
11-
import { isI18nData, isProjectSchema } from '@alilc/lowcode-utils';
10+
import { isProjectSchema } from '@alilc/lowcode-utils';
1211
import { Notification } from '@alifd/next';
13-
import { intl, getLocale } from '../locale';
12+
import { intl } from '../locale';
1413

1514
function getNodesSchema(nodes: IPublicModelNode[]) {
1615
const componentsTree = nodes.map((node) => node?.exportSchema(IPublicEnumTransformStage.Clone));
1716
const data = { type: 'nodeSchema', componentsMap: {}, componentsTree };
1817
return data;
1918
}
2019

21-
function getIntlStr(data: string | IPublicTypeI18nData) {
22-
if (!isI18nData(data)) {
23-
return data;
24-
}
25-
26-
const locale = getLocale();
27-
return data[locale] || data['zh-CN'] || data['zh_CN'] || data['en-US'] || data['en_US'] || '';
28-
}
29-
3020
async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> {
3121
return new Promise((resolve, reject) => {
3222
// 使用 Clipboard API 读取剪贴板内容
@@ -61,8 +51,9 @@ async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> {
6151
}
6252

6353
export const defaultContextMenu = (ctx: IPublicModelPluginContext) => {
64-
const { material, canvas } = ctx;
54+
const { material, canvas, common } = ctx;
6555
const { clipboard } = canvas;
56+
const { intl: utilsIntl } = common.utils;
6657

6758
return {
6859
init() {
@@ -150,7 +141,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => {
150141
});
151142
if (canAddNodes.length === 0) {
152143
Notification.open({
153-
content: `${nodeSchema.map(d => getIntlStr(d.title || d.componentName)).join(',')}等组件无法放置到${getIntlStr(parent.title || parent.componentName as any)}内`,
144+
content: `${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(parent.title || parent.componentName as any)}内`,
154145
type: 'error',
155146
});
156147
return;
@@ -198,7 +189,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => {
198189
});
199190
if (canAddNodes.length === 0) {
200191
Notification.open({
201-
content: `${nodeSchema.map(d => getIntlStr(d.title || d.componentName)).join(',')}等组件无法放置到${getIntlStr(node.title || node.componentName as any)}内`,
192+
content: `${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(node.title || node.componentName as any)}内`,
202193
type: 'error',
203194
});
204195
return;
Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
import { IPublicApiCommonUI } from '@alilc/lowcode-types';
1+
import { IPublicApiCommonUI, IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types';
22
import {
3+
IEditor,
34
Tip as InnerTip,
45
Title as InnerTitle,
56
} from '@alilc/lowcode-editor-core';
67
import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next';
78
import { ContextMenu } from '../components/context-menu';
9+
import { editorSymbol } from '../symbols';
810

911
export class CommonUI implements IPublicApiCommonUI {
12+
[editorSymbol]: IEditor;
13+
1014
Balloon = Balloon;
1115
Breadcrumb = Breadcrumb;
1216
Button = Button;
@@ -35,13 +39,29 @@ export class CommonUI implements IPublicApiCommonUI {
3539
Upload = Upload;
3640
Divider = Divider;
3741

42+
constructor(editor: IEditor) {
43+
this[editorSymbol] = editor;
44+
}
45+
3846
get Tip() {
3947
return InnerTip;
4048
}
4149
get Title() {
4250
return InnerTitle;
4351
}
52+
4453
get ContextMenu() {
45-
return ContextMenu;
54+
const editor = this[editorSymbol];
55+
const innerContextMenu = (props: any) => {
56+
const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext;
57+
return <ContextMenu {...props} pluginContext={pluginContext} />;
58+
};
59+
60+
innerContextMenu.create = (menus: IPublicTypeContextMenuAction[], event: MouseEvent) => {
61+
const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext;
62+
return ContextMenu.create(pluginContext, menus, event);
63+
};
64+
65+
return innerContextMenu;
4666
}
4767
}

packages/shell/src/components/context-menu.tsx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils';
22
import { engineConfig } from '@alilc/lowcode-editor-core';
3-
import { IPublicTypeContextMenuAction } from '@alilc/lowcode-types';
3+
import { IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types';
44
import React from 'react';
55

6-
export function ContextMenu({ children, menus }: {
6+
export function ContextMenu({ children, menus, pluginContext }: {
77
menus: IPublicTypeContextMenuAction[];
88
children: React.ReactElement[] | React.ReactElement;
9+
pluginContext: IPublicModelPluginContext;
910
}): React.ReactElement<any, string | React.JSXElementConstructor<any>> {
1011
if (!engineConfig.get('enableContextMenu')) {
1112
return (
@@ -23,7 +24,10 @@ export function ContextMenu({ children, menus }: {
2324
};
2425
const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, {
2526
destroy,
26-
}));
27+
pluginContext,
28+
}), {
29+
pluginContext,
30+
});
2731

2832
if (!children?.length) {
2933
return;
@@ -44,4 +48,20 @@ export function ContextMenu({ children, menus }: {
4448
return (
4549
<>{childrenWithContextMenu}</>
4650
);
47-
}
51+
}
52+
53+
ContextMenu.create = (pluginContext: IPublicModelPluginContext, menus: IPublicTypeContextMenuAction[], event: MouseEvent) => {
54+
const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, {
55+
pluginContext,
56+
}), {
57+
pluginContext,
58+
});
59+
60+
if (!children?.length) {
61+
return;
62+
}
63+
64+
return createContextMenu(children, {
65+
event,
66+
});
67+
};

0 commit comments

Comments
 (0)