mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-02-07 22:39:24 +00:00
Merge branch 'feat/joint-editor' of gitlab.alibaba-inc.com:ali-lowcode/ali-lowcode-engine into feat/joint-editor
This commit is contained in:
commit
4a673068ee
@ -1,8 +1,16 @@
|
|||||||
const { eslint, deepmerge } = require('@ice/spec');
|
const { tslint, deepmerge } = require('@ice/spec');
|
||||||
|
|
||||||
module.exports = deepmerge(eslint, {
|
module.exports = deepmerge(tslint, {
|
||||||
rules: {
|
rules: {
|
||||||
"global-require": 0,
|
"global-require": 0,
|
||||||
"interface-name" : [true, "never-prefix"]
|
"comma-dangle": 0,
|
||||||
|
"no-unused-expressions": 0,
|
||||||
|
"object-shorthand": 0,
|
||||||
|
"jsx-a11y/anchor-has-content": 0,
|
||||||
|
"react/sort-comp": 0,
|
||||||
|
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx", ".tsx", "ts"] }],
|
||||||
|
"@typescript-eslint/interface-name-prefix": 0,
|
||||||
|
"@typescript-eslint/no-explicit-any": 0,
|
||||||
|
"@typescript-eslint/explicit-member-accessibility": 0
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -12,7 +12,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
['ice-plugin-fusion', {
|
['ice-plugin-fusion', {
|
||||||
themePackage: '@alife/dpl-iceluna',
|
themePackage: '@alife/theme-lowcode-light',
|
||||||
}],
|
}],
|
||||||
['ice-plugin-moment-locales', {
|
['ice-plugin-moment-locales', {
|
||||||
locales: ['zh-cn'],
|
locales: ['zh-cn'],
|
||||||
|
|||||||
@ -4,9 +4,12 @@
|
|||||||
"description": "低代码编辑器",
|
"description": "低代码编辑器",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ali/iceluna-addon-2": "^1.0.3",
|
"@ali/iceluna-addon-2": "^1.0.3",
|
||||||
|
"@ali/iceluna-addon-component-list": "^1.0.10",
|
||||||
"@ali/iceluna-sdk": "^1.0.5-beta.26",
|
"@ali/iceluna-sdk": "^1.0.5-beta.26",
|
||||||
"@alifd/next": "^1.x",
|
"@alifd/next": "^1.x",
|
||||||
"@alife/dpl-iceluna": "^2.3.2",
|
"@alife/dpl-iceluna": "^2.3.2",
|
||||||
|
"@alife/theme-lowcode-dark": "^0.1.0",
|
||||||
|
"@alife/theme-lowcode-light": "^0.1.0",
|
||||||
"@icedesign/theme": "^1.x",
|
"@icedesign/theme": "^1.x",
|
||||||
"events": "^3.1.0",
|
"events": "^3.1.0",
|
||||||
"intl-messageformat": "^8.2.1",
|
"intl-messageformat": "^8.2.1",
|
||||||
@ -21,13 +24,14 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ice/spec": "^0.1.1",
|
"@ice/spec": "^0.1.1",
|
||||||
"@types/react": "^16.8.3",
|
|
||||||
"@types/react-dom": "^16.8.2",
|
|
||||||
"@types/debug": "^4.1.5",
|
"@types/debug": "^4.1.5",
|
||||||
"@types/events": "^3.0.0",
|
"@types/events": "^3.0.0",
|
||||||
|
"@types/react": "^16.8.3",
|
||||||
|
"@types/react-dom": "^16.8.2",
|
||||||
"@types/store": "^2.0.2",
|
"@types/store": "^2.0.2",
|
||||||
"css-modules-typescript-loader": "^2.0.4",
|
"css-modules-typescript-loader": "^2.0.4",
|
||||||
"eslint": "^6.0.1",
|
"eslint": "^6.0.1",
|
||||||
|
"husky": "^4.2.3",
|
||||||
"ice-plugin-fusion": "^0.1.4",
|
"ice-plugin-fusion": "^0.1.4",
|
||||||
"ice-plugin-moment-locales": "^0.1.0",
|
"ice-plugin-moment-locales": "^0.1.0",
|
||||||
"ice-scripts": "^2.0.0",
|
"ice-scripts": "^2.0.0",
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
<script src="https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js"></script>
|
<script src="https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body class="dark">
|
||||||
<div id="ice-container"></div>
|
<div id="ice-container"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
152
packages/editor/src/config/assets.js
Normal file
152
packages/editor/src/config/assets.js
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
export default {
|
||||||
|
version: '1.0.0',
|
||||||
|
packages: {
|
||||||
|
'@alifd/next': {
|
||||||
|
title: 'fusion组件库',
|
||||||
|
package: '@alifd/next',
|
||||||
|
version: '1.19.18',
|
||||||
|
urls: [
|
||||||
|
'https://unpkg.antfin-inc.com/@alife/next@1.19.18/dist/next.js',
|
||||||
|
'https://unpkg.antfin-inc.com/@alife/next@1.19.18/dist/next.css'
|
||||||
|
],
|
||||||
|
library: 'Next'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Button: {
|
||||||
|
componentName: 'Button',
|
||||||
|
title: '按钮',
|
||||||
|
devMode: 'proCode',
|
||||||
|
npm: {
|
||||||
|
package: '@alifd/next',
|
||||||
|
version: '1.19.18',
|
||||||
|
destructuring: true,
|
||||||
|
exportName: 'Button'
|
||||||
|
},
|
||||||
|
props: [
|
||||||
|
{
|
||||||
|
name: 'type',
|
||||||
|
propType: 'string'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'children',
|
||||||
|
propType: 'string'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
configure: {
|
||||||
|
props: [
|
||||||
|
{
|
||||||
|
name: 'type',
|
||||||
|
setter: {
|
||||||
|
componentName: 'Input'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'children',
|
||||||
|
setter: {
|
||||||
|
componentName: 'Input'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Input: {
|
||||||
|
componentName: 'Input',
|
||||||
|
title: '输入框',
|
||||||
|
devMode: 'proCode',
|
||||||
|
npm: {
|
||||||
|
package: '@alifd/next',
|
||||||
|
version: '1.19.18',
|
||||||
|
destructuring: true,
|
||||||
|
exportName: 'Input'
|
||||||
|
},
|
||||||
|
props: [
|
||||||
|
{
|
||||||
|
name: 'placeholder',
|
||||||
|
propType: 'string'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
configure: {
|
||||||
|
props: [
|
||||||
|
{
|
||||||
|
name: 'placeholder',
|
||||||
|
setter: {
|
||||||
|
componentName: 'Input'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
componentList: [
|
||||||
|
{
|
||||||
|
title: '基础',
|
||||||
|
icon: '',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Button',
|
||||||
|
title: '按钮',
|
||||||
|
icon: '',
|
||||||
|
package: '@alife/next',
|
||||||
|
snippets: [
|
||||||
|
{
|
||||||
|
title: 'private',
|
||||||
|
screenshort: '',
|
||||||
|
schema: {
|
||||||
|
componentName: 'Button',
|
||||||
|
props: {
|
||||||
|
type: 'primary'
|
||||||
|
},
|
||||||
|
children: 'Primary'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'secondary',
|
||||||
|
screenshort: '',
|
||||||
|
schema: {
|
||||||
|
componentName: 'Button',
|
||||||
|
props: {
|
||||||
|
type: 'secondary'
|
||||||
|
},
|
||||||
|
children: 'secondary'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'normal',
|
||||||
|
screenshort: '',
|
||||||
|
schema: {
|
||||||
|
componentName: 'Button',
|
||||||
|
props: {
|
||||||
|
type: 'normal'
|
||||||
|
},
|
||||||
|
children: 'normal'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '表单',
|
||||||
|
icon: '',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Input',
|
||||||
|
title: '输入框',
|
||||||
|
icon: '',
|
||||||
|
package: '@alife/next',
|
||||||
|
snippets: [
|
||||||
|
{
|
||||||
|
title: '普通',
|
||||||
|
screenshort: '',
|
||||||
|
schema: {
|
||||||
|
componentName: 'Input',
|
||||||
|
props: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
@ -1,7 +1,3 @@
|
|||||||
import logo from '../plugins/logo';
|
|
||||||
import Designer from '../plugins/designer';
|
|
||||||
import undoRedo from '../plugins/undoRedo';
|
|
||||||
import Settings from '../../../plugin-settings';
|
|
||||||
import topBalloonIcon from '@ali/iceluna-addon-2';
|
import topBalloonIcon from '@ali/iceluna-addon-2';
|
||||||
import topDialogIcon from '@ali/iceluna-addon-2';
|
import topDialogIcon from '@ali/iceluna-addon-2';
|
||||||
import leftPanelIcon from '@ali/iceluna-addon-2';
|
import leftPanelIcon from '@ali/iceluna-addon-2';
|
||||||
@ -12,6 +8,11 @@ import rightPanel1 from '@ali/iceluna-addon-2';
|
|||||||
import rightPanel2 from '@ali/iceluna-addon-2';
|
import rightPanel2 from '@ali/iceluna-addon-2';
|
||||||
import rightPanel3 from '@ali/iceluna-addon-2';
|
import rightPanel3 from '@ali/iceluna-addon-2';
|
||||||
import rightPanel4 from '@ali/iceluna-addon-2';
|
import rightPanel4 from '@ali/iceluna-addon-2';
|
||||||
|
import componentList from '@ali/iceluna-addon-component-list';
|
||||||
|
import Settings from '../../../plugin-settings';
|
||||||
|
import undoRedo from '../plugins/undoRedo';
|
||||||
|
import Designer from '../plugins/designer';
|
||||||
|
import logo from '../plugins/logo';
|
||||||
|
|
||||||
import PluginFactory from '../framework/pluginFactory';
|
import PluginFactory from '../framework/pluginFactory';
|
||||||
|
|
||||||
@ -29,5 +30,6 @@ export default {
|
|||||||
rightPanel1: PluginFactory(rightPanel1),
|
rightPanel1: PluginFactory(rightPanel1),
|
||||||
rightPanel2: PluginFactory(rightPanel2),
|
rightPanel2: PluginFactory(rightPanel2),
|
||||||
rightPanel3: PluginFactory(rightPanel3),
|
rightPanel3: PluginFactory(rightPanel3),
|
||||||
rightPanel4: PluginFactory(rightPanel4)
|
rightPanel4: PluginFactory(rightPanel4),
|
||||||
|
componentList: PluginFactory(componentList)
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,13 +4,17 @@ import { registerSetter } from '../../../plugin-settings/src';
|
|||||||
import { createElement } from 'react';
|
import { createElement } from 'react';
|
||||||
|
|
||||||
registerSetter('ClassNameSetter', () => {
|
registerSetter('ClassNameSetter', () => {
|
||||||
return createElement('div', {
|
return createElement(
|
||||||
|
'div',
|
||||||
|
{
|
||||||
className: 'lc-block-setter'
|
className: 'lc-block-setter'
|
||||||
}, '这里是类名绑定');
|
},
|
||||||
|
'这里是类名绑定'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
registerSetter('EventsSetter', Input);
|
registerSetter('EventsSetter', Input);
|
||||||
|
|
||||||
registerSetter('StringSetter', { component: Input, props: { placeholder: "请输入" } });
|
registerSetter('StringSetter', { component: Input, props: { placeholder: '请输入' } });
|
||||||
|
|
||||||
registerSetter('NumberSetter', NumberSetter as any);
|
registerSetter('NumberSetter', NumberSetter as any);
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import assets from './assets';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
version: '^1.0.2',
|
version: '^1.0.2',
|
||||||
theme: {
|
theme: {
|
||||||
@ -25,7 +27,8 @@ export default {
|
|||||||
version: '1.0.0'
|
version: '1.0.0'
|
||||||
},
|
},
|
||||||
pluginProps: {
|
pluginProps: {
|
||||||
logo: 'https://img.alicdn.com/tfs/TB1mHYDxQP2gK0jSZPxXXacQpXa-112-64.png'
|
logo: 'https://img.alicdn.com/tfs/TB1hoI9x1H2gK0jSZFEXXcqMpXa-146-40.png',
|
||||||
|
href: '/'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -71,7 +74,7 @@ export default {
|
|||||||
type: 'Custom',
|
type: 'Custom',
|
||||||
props: {
|
props: {
|
||||||
align: 'right',
|
align: 'right',
|
||||||
width: 90
|
width: 88
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
package: '@ali/lowcode-plugin-undo-redo',
|
package: '@ali/lowcode-plugin-undo-redo',
|
||||||
@ -107,8 +110,8 @@ export default {
|
|||||||
align: 'right',
|
align: 'right',
|
||||||
title: 'icon',
|
title: 'icon',
|
||||||
icon: 'dengpao',
|
icon: 'dengpao',
|
||||||
onClick: function(editor) {
|
onClick(editor) {
|
||||||
alert('icon addon invoke, current activeKey: ' + editor.activeKey);
|
alert(`icon addon invoke, current activeKey: ${editor.activeKey}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
config: {},
|
config: {},
|
||||||
@ -116,6 +119,22 @@ export default {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
leftArea: [
|
leftArea: [
|
||||||
|
{
|
||||||
|
pluginKey: 'componentList',
|
||||||
|
type: 'PanelIcon',
|
||||||
|
props: {
|
||||||
|
align: 'top',
|
||||||
|
icon: 'zujianku',
|
||||||
|
title: '组件库'
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
package: '@ali/iceluna-addon-component-list',
|
||||||
|
version: '^1.0.4'
|
||||||
|
},
|
||||||
|
pluginProps: {
|
||||||
|
disableAppComponent: true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
pluginKey: 'leftPanelIcon',
|
pluginKey: 'leftPanelIcon',
|
||||||
type: 'PanelIcon',
|
type: 'PanelIcon',
|
||||||
@ -150,7 +169,11 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
align: 'top',
|
align: 'top',
|
||||||
title: 'panel2',
|
title: 'panel2',
|
||||||
icon: 'dengpao'
|
icon: 'dengpao',
|
||||||
|
panelProps: {
|
||||||
|
defaultWidth: 400,
|
||||||
|
floatable: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
package: '@ali/iceluna-addon-2',
|
package: '@ali/iceluna-addon-2',
|
||||||
@ -194,8 +217,8 @@ export default {
|
|||||||
align: 'bottom',
|
align: 'bottom',
|
||||||
title: 'icon',
|
title: 'icon',
|
||||||
icon: 'dengpao',
|
icon: 'dengpao',
|
||||||
onClick: function(editor) {
|
onClick(editor) {
|
||||||
alert('icon addon invoke, current activeKey: ' + editor.activeKey);
|
alert(`icon addon invoke, current activeKey: ${editor.activeKey}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
config: {},
|
config: {},
|
||||||
@ -211,7 +234,52 @@ export default {
|
|||||||
version: '^1.0.0'
|
version: '^1.0.0'
|
||||||
},
|
},
|
||||||
pluginProps: {}
|
pluginProps: {}
|
||||||
},
|
}
|
||||||
|
// {
|
||||||
|
// pluginKey: 'rightPanel1',
|
||||||
|
// type: 'TabPanel',
|
||||||
|
// props: {
|
||||||
|
// title: '样式'
|
||||||
|
// },
|
||||||
|
// config: {
|
||||||
|
// version: '^1.0.0'
|
||||||
|
// },
|
||||||
|
// pluginProps: {}
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// pluginKey: 'rightPanel2',
|
||||||
|
// type: 'TabPanel',
|
||||||
|
// props: {
|
||||||
|
// title: '属性',
|
||||||
|
// icon: 'dengpao'
|
||||||
|
// },
|
||||||
|
// config: {
|
||||||
|
// version: '^1.0.0'
|
||||||
|
// },
|
||||||
|
// pluginProps: {}
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// pluginKey: 'rightPanel3',
|
||||||
|
// type: 'TabPanel',
|
||||||
|
// props: {
|
||||||
|
// title: '事件'
|
||||||
|
// },
|
||||||
|
// config: {
|
||||||
|
// version: '^1.0.0'
|
||||||
|
// },
|
||||||
|
// pluginProps: {}
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// pluginKey: 'rightPanel4',
|
||||||
|
// type: 'TabPanel',
|
||||||
|
// props: {
|
||||||
|
// title: '数据'
|
||||||
|
// },
|
||||||
|
// config: {
|
||||||
|
// version: '^1.0.0'
|
||||||
|
// },
|
||||||
|
// pluginProps: {}
|
||||||
|
// }
|
||||||
],
|
],
|
||||||
centerArea: [
|
centerArea: [
|
||||||
{
|
{
|
||||||
@ -224,5 +292,51 @@ export default {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
hooks: [],
|
hooks: [],
|
||||||
shortCuts: []
|
shortCuts: [],
|
||||||
|
lifeCycles: {
|
||||||
|
init: function init(editor) {
|
||||||
|
const transformMaterial = componentList => {
|
||||||
|
return componentList.map(category => {
|
||||||
|
return {
|
||||||
|
name: category.title,
|
||||||
|
items: category.children.map(comp => {
|
||||||
|
return {
|
||||||
|
...comp,
|
||||||
|
name: comp.componentName,
|
||||||
|
libraryId: 1,
|
||||||
|
snippets: comp.snippets.map(snippet => {
|
||||||
|
return {
|
||||||
|
name: snippet.title,
|
||||||
|
screenshort: snippet.screenshort,
|
||||||
|
code: JSON.stringify(snippet.schema)
|
||||||
|
};
|
||||||
|
})
|
||||||
|
};
|
||||||
|
})
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const list = transformMaterial(assets.componentList);
|
||||||
|
editor.set({
|
||||||
|
componentsMap: assets.components,
|
||||||
|
componentMaterial: {
|
||||||
|
library: [
|
||||||
|
{
|
||||||
|
name: 'Fusion组件库',
|
||||||
|
id: 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
list
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.set('dndHelper', {
|
||||||
|
handleResourceDragStart: function(ev, tagName, schema) {
|
||||||
|
// 物料面板中组件snippet的dragStart回调
|
||||||
|
// ev: 原始的domEvent;tagName: 组件的描述文案;schema: snippet的schema
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,26 +4,36 @@ import { clone, deepEqual } from './utils';
|
|||||||
|
|
||||||
export default class AreaManager {
|
export default class AreaManager {
|
||||||
private pluginStatus: PluginStatus;
|
private pluginStatus: PluginStatus;
|
||||||
|
|
||||||
private config: PluginConfig[];
|
private config: PluginConfig[];
|
||||||
constructor(private editor: Editor, private area: string) {
|
|
||||||
|
private editor: Editor;
|
||||||
|
|
||||||
|
private area: string;
|
||||||
|
|
||||||
|
constructor(editor: Editor, area: string) {
|
||||||
|
this.editor = editor;
|
||||||
|
this.area = area;
|
||||||
this.config = (editor && editor.config && editor.config.plugins && editor.config.plugins[this.area]) || [];
|
this.config = (editor && editor.config && editor.config.plugins && editor.config.plugins[this.area]) || [];
|
||||||
this.pluginStatus = clone(editor.pluginStatus);
|
this.pluginStatus = clone(editor.pluginStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
public isPluginStatusUpdate(pluginType?: string): boolean {
|
public isPluginStatusUpdate(pluginType?: string): boolean {
|
||||||
const { pluginStatus } = this.editor;
|
const { pluginStatus } = this.editor;
|
||||||
const list = pluginType ? this.config.filter(item => item.type === pluginType) : this.config;
|
const list = pluginType ? this.config.filter((item): boolean => item.type === pluginType) : this.config;
|
||||||
|
|
||||||
const isUpdate = list.some(item => !deepEqual(pluginStatus[item.pluginKey], this.pluginStatus[item.pluginKey]));
|
const isUpdate = list.some(
|
||||||
|
(item): boolean => !deepEqual(pluginStatus[item.pluginKey], this.pluginStatus[item.pluginKey])
|
||||||
|
);
|
||||||
this.pluginStatus = clone(pluginStatus);
|
this.pluginStatus = clone(pluginStatus);
|
||||||
return isUpdate;
|
return isUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getVisiblePluginList(pluginType?: string): PluginConfig[] {
|
public getVisiblePluginList(pluginType?: string): PluginConfig[] {
|
||||||
const res = this.config.filter(item => {
|
const res = this.config.filter((item): boolean => {
|
||||||
return !this.pluginStatus[item.pluginKey] || this.pluginStatus[item.pluginKey].visible;
|
return !!(!this.pluginStatus[item.pluginKey] || this.pluginStatus[item.pluginKey].visible);
|
||||||
});
|
});
|
||||||
return pluginType ? res.filter(item => item.type === pluginType) : res;
|
return pluginType ? res.filter((item): boolean => item.type === pluginType) : res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPluginConfig(): PluginConfig[] {
|
public getPluginConfig(): PluginConfig[] {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
import { createContext } from 'react';
|
import { createContext } from 'react';
|
||||||
|
|
||||||
const context = createContext({});
|
const context = createContext({});
|
||||||
export default context;
|
export default context;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export interface EditorConfig {
|
|||||||
shortCuts?: ShortCutsConfig;
|
shortCuts?: ShortCutsConfig;
|
||||||
utils?: UtilsConfig;
|
utils?: UtilsConfig;
|
||||||
constants?: ConstantsConfig;
|
constants?: ConstantsConfig;
|
||||||
lifeCycles?: lifeCyclesConfig;
|
lifeCycles?: LifeCyclesConfig;
|
||||||
i18n?: I18nConfig;
|
i18n?: I18nConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ export interface ThemeConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface PluginsConfig {
|
export interface PluginsConfig {
|
||||||
[propName: string]: Array<PluginConfig>;
|
[propName: string]: PluginConfig[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PluginConfig {
|
export interface PluginConfig {
|
||||||
@ -63,7 +63,7 @@ export interface PluginConfig {
|
|||||||
pluginProps?: object;
|
pluginProps?: object;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HooksConfig = Array<HookConfig>;
|
export type HooksConfig = HookConfig[];
|
||||||
|
|
||||||
export interface HookConfig {
|
export interface HookConfig {
|
||||||
message: string;
|
message: string;
|
||||||
@ -71,14 +71,14 @@ export interface HookConfig {
|
|||||||
handler: (editor: Editor, ...args) => void;
|
handler: (editor: Editor, ...args) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ShortCutsConfig = Array<ShortCutConfig>;
|
export type ShortCutsConfig = ShortCutConfig[];
|
||||||
|
|
||||||
export interface ShortCutConfig {
|
export interface ShortCutConfig {
|
||||||
keyboard: string;
|
keyboard: string;
|
||||||
handler: (editor: Editor, ev: React.KeyboardEventHandler<HTMLElement>, keymaster: any) => void;
|
handler: (editor: Editor, ev: Event, keymaster: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UtilsConfig = Array<UtilConfig>;
|
export type UtilsConfig = UtilConfig[];
|
||||||
|
|
||||||
export interface UtilConfig {
|
export interface UtilConfig {
|
||||||
name: string;
|
name: string;
|
||||||
@ -88,7 +88,7 @@ export interface UtilConfig {
|
|||||||
|
|
||||||
export type ConstantsConfig = object;
|
export type ConstantsConfig = object;
|
||||||
|
|
||||||
export interface lifeCyclesConfig {
|
export interface LifeCyclesConfig {
|
||||||
init?: (editor: Editor) => any;
|
init?: (editor: Editor) => any;
|
||||||
destroy?: (editor: Editor) => any;
|
destroy?: (editor: Editor) => any;
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ export interface lifeCyclesConfig {
|
|||||||
export type LocaleType = 'zh-CN' | 'zh-TW' | 'en-US' | 'ja-JP';
|
export type LocaleType = 'zh-CN' | 'zh-TW' | 'en-US' | 'ja-JP';
|
||||||
|
|
||||||
export interface I18nMessages {
|
export interface I18nMessages {
|
||||||
[propName: string]: string;
|
[key: string]: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface I18nConfig {
|
export interface I18nConfig {
|
||||||
@ -109,27 +109,46 @@ export interface I18nConfig {
|
|||||||
export type I18nFunction = (key: string, params: any) => string;
|
export type I18nFunction = (key: string, params: any) => string;
|
||||||
|
|
||||||
export interface Utils {
|
export interface Utils {
|
||||||
[propName: string]: (...args) => any;
|
[key: string]: (...args) => any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PluginClass extends React.ComponentClass<{
|
export interface PluginProps {
|
||||||
editor: Editor;
|
editor: Editor;
|
||||||
[key: string]: any
|
config: PluginConfig;
|
||||||
}> {
|
i18n?: I18nFunction;
|
||||||
init?: (editor: Editor) => void;
|
ref?: React.RefObject<React.ReactElement>;
|
||||||
open?: () => any;
|
[key: string]: any;
|
||||||
close?: () => any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PluginComponents {
|
export type Plugin = React.ReactNode & {
|
||||||
[propName: string]: PluginClass;
|
open?: () => boolean | void | Promise<any>;
|
||||||
|
close?: () => boolean | void | Promise<any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HOCPlugin = React.ReactNode & {
|
||||||
|
open: () => Promise<any>;
|
||||||
|
close: () => Promise<any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface PluginSet {
|
||||||
|
[key: string]: HOCPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PluginClass = React.ComponentType<PluginProps> & {
|
||||||
|
init?: (editor: Editor) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface PluginClassSet {
|
||||||
|
[key: string]: PluginClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PluginStatus {
|
export interface PluginStatus {
|
||||||
[propName: string]: {
|
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
visible?: boolean;
|
visible?: boolean;
|
||||||
marked?: boolean;
|
marked?: boolean;
|
||||||
locked?: boolean;
|
locked?: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
export interface PluginStatusSet {
|
||||||
|
[key: string]: PluginStatus;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,35 +1,56 @@
|
|||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
import { EditorConfig, HooksConfig, LocaleType, PluginComponents, PluginStatus, Utils } from './definitions';
|
import {
|
||||||
|
EditorConfig,
|
||||||
|
HooksConfig,
|
||||||
|
LocaleType,
|
||||||
|
PluginStatusSet,
|
||||||
|
Utils,
|
||||||
|
PluginClassSet,
|
||||||
|
PluginSet
|
||||||
|
} from './definitions';
|
||||||
|
|
||||||
import { registShortCuts, transformToPromise, unRegistShortCuts } from './utils';
|
import * as editorUtils from './utils';
|
||||||
|
|
||||||
|
const { registShortCuts, transformToPromise, unRegistShortCuts } = editorUtils;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
__isDebug?: boolean;
|
||||||
|
__newFunc?: (funcStr: string) => (...args: any[]) => any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 根据url参数设置debug选项
|
// 根据url参数设置debug选项
|
||||||
const res = /_?debug=(.*?)(&|$)/.exec(location.search);
|
const debugRegRes = /_?debug=(.*?)(&|$)/.exec(location.search);
|
||||||
if (res && res[1]) {
|
if (debugRegRes && debugRegRes[1]) {
|
||||||
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
window.__isDebug = true;
|
window.__isDebug = true;
|
||||||
store.storage.write('debug', res[1] === 'true' ? '*' : res[1]);
|
store.storage.write('debug', debugRegRes[1] === 'true' ? '*' : debugRegRes[1]);
|
||||||
} else {
|
} else {
|
||||||
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
window.__isDebug = false;
|
window.__isDebug = false;
|
||||||
store.remove('debug');
|
store.remove('debug');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重要,用于矫正画布执行new Function的window对象上下文
|
// 重要,用于矫正画布执行new Function的window对象上下文
|
||||||
window.__newFunc = funContext => {
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
return new Function(funContext);
|
window.__newFunc = (funContext: string): ((...args: any[]) => any) => {
|
||||||
|
// eslint-disable-next-line no-new-func
|
||||||
|
return new Function(funContext) as (...args: any[]) => any;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 关闭浏览器前提醒,只有产生过交互才会生效
|
// 关闭浏览器前提醒,只有产生过交互才会生效
|
||||||
window.onbeforeunload = function(e) {
|
window.onbeforeunload = function(e: Event): string | void {
|
||||||
e = e || window.event;
|
const ev = e || window.event;
|
||||||
// 本地调试不生效
|
// 本地调试不生效
|
||||||
if (location.href.indexOf('localhost') > 0) {
|
if (location.href.indexOf('localhost') > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const msg = '您确定要离开此页面吗?';
|
const msg = '您确定要离开此页面吗?';
|
||||||
e.cancelBubble = true;
|
ev.cancelBubble = true;
|
||||||
e.returnValue = msg;
|
ev.returnValue = true;
|
||||||
if (e.stopPropagation) {
|
if (e.stopPropagation) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -47,26 +68,40 @@ export interface HooksFuncs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class Editor extends EventEmitter {
|
export default class Editor extends EventEmitter {
|
||||||
public static getInstance = (config: EditorConfig, components: PluginComponents, utils?: Utils): Editor => {
|
public static getInstance = (config: EditorConfig, components: PluginClassSet, utils?: Utils): Editor => {
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
instance = new Editor(config, components, utils);
|
instance = new Editor(config, components, utils);
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
};
|
};
|
||||||
|
|
||||||
public pluginStatus: PluginStatus;
|
public config: EditorConfig;
|
||||||
public plugins: PluginComponents;
|
|
||||||
|
public components: PluginClassSet;
|
||||||
|
|
||||||
|
public utils: Utils;
|
||||||
|
|
||||||
|
public pluginStatus: PluginStatusSet;
|
||||||
|
|
||||||
|
public plugins: PluginSet;
|
||||||
|
|
||||||
public locale: LocaleType;
|
public locale: LocaleType;
|
||||||
|
|
||||||
public emit: (msg: string, ...args) => void;
|
public emit: (msg: string, ...args) => void;
|
||||||
|
|
||||||
public on: (msg: string, handler: (...args) => void) => void;
|
public on: (msg: string, handler: (...args) => void) => void;
|
||||||
|
|
||||||
public once: (msg: string, handler: (...args) => void) => void;
|
public once: (msg: string, handler: (...args) => void) => void;
|
||||||
|
|
||||||
public off: (msg: string, handler: (...args) => void) => void;
|
public off: (msg: string, handler: (...args) => void) => void;
|
||||||
|
|
||||||
private hooksFuncs: HooksFuncs;
|
private hooksFuncs: HooksFuncs;
|
||||||
|
|
||||||
constructor(public config: EditorConfig, public components: PluginComponents, public utils?: Utils) {
|
constructor(config: EditorConfig, components: PluginClassSet, utils?: Utils) {
|
||||||
super();
|
super();
|
||||||
|
this.config = config;
|
||||||
|
this.components = components;
|
||||||
|
this.utils = { ...editorUtils, ...utils };
|
||||||
instance = this;
|
instance = this;
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
@ -80,21 +115,21 @@ export default class Editor extends EventEmitter {
|
|||||||
this.initHooks(hooks || []);
|
this.initHooks(hooks || []);
|
||||||
|
|
||||||
this.emit('editor.beforeInit');
|
this.emit('editor.beforeInit');
|
||||||
const init = (lifeCycles && lifeCycles.init) || (() => {});
|
const init = (lifeCycles && lifeCycles.init) || ((): void => {});
|
||||||
// 用户可以通过设置extensions.init自定义初始化流程;
|
// 用户可以通过设置extensions.init自定义初始化流程;
|
||||||
return transformToPromise(init(this))
|
return transformToPromise(init(this))
|
||||||
.then(() => {
|
.then((): boolean => {
|
||||||
// 注册快捷键
|
// 注册快捷键
|
||||||
registShortCuts(shortCuts, this);
|
registShortCuts(shortCuts, this);
|
||||||
this.emit('editor.afterInit');
|
this.emit('editor.afterInit');
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch((err): void => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy(): void {
|
||||||
debug('destroy');
|
debug('destroy');
|
||||||
try {
|
try {
|
||||||
const { hooks = [], shortCuts = [], lifeCycles = {} } = this.config;
|
const { hooks = [], shortCuts = [], lifeCycles = {} } = this.config;
|
||||||
@ -105,7 +140,6 @@ export default class Editor extends EventEmitter {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn(err);
|
console.warn(err);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +155,7 @@ export default class Editor extends EventEmitter {
|
|||||||
}
|
}
|
||||||
this[key] = val;
|
this[key] = val;
|
||||||
} else if (typeof key === 'object') {
|
} else if (typeof key === 'object') {
|
||||||
Object.keys(key).forEach(item => {
|
Object.keys(key).forEach((item): void => {
|
||||||
this[item] = key[item];
|
this[item] = key[item];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -131,26 +165,26 @@ export default class Editor extends EventEmitter {
|
|||||||
if (!Array.isArray(events)) {
|
if (!Array.isArray(events)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
events.forEach(event => this.on(event, lisenter));
|
events.forEach((event): void => this.on(event, lisenter));
|
||||||
}
|
}
|
||||||
|
|
||||||
public batchOnce(events: string[], lisenter: (...args) => void): void {
|
public batchOnce(events: string[], lisenter: (...args) => void): void {
|
||||||
if (!Array.isArray(events)) {
|
if (!Array.isArray(events)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
events.forEach(event => this.once(event, lisenter));
|
events.forEach((event): void => this.once(event, lisenter));
|
||||||
}
|
}
|
||||||
|
|
||||||
public batchOff(events: string[], lisenter: (...args) => void): void {
|
public batchOff(events: string[], lisenter: (...args) => void): void {
|
||||||
if (!Array.isArray(events)) {
|
if (!Array.isArray(events)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
events.forEach(event => this.off(event, lisenter));
|
events.forEach((event): void => this.off(event, lisenter));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 销毁hooks中的消息监听
|
// 销毁hooks中的消息监听
|
||||||
private destroyHooks(hooks: HooksConfig = []) {
|
private destroyHooks(hooks: HooksConfig = []): void {
|
||||||
hooks.forEach((item, idx) => {
|
hooks.forEach((item, idx): void => {
|
||||||
if (typeof this.hooksFuncs[idx] === 'function') {
|
if (typeof this.hooksFuncs[idx] === 'function') {
|
||||||
this.off(item.message, this.hooksFuncs[idx]);
|
this.off(item.message, this.hooksFuncs[idx]);
|
||||||
}
|
}
|
||||||
@ -160,8 +194,8 @@ export default class Editor extends EventEmitter {
|
|||||||
|
|
||||||
// 初始化hooks中的消息监听
|
// 初始化hooks中的消息监听
|
||||||
private initHooks(hooks: HooksConfig = []): void {
|
private initHooks(hooks: HooksConfig = []): void {
|
||||||
this.hooksFuncs = hooks.map(item => {
|
this.hooksFuncs = hooks.map((item): ((...arg) => void) => {
|
||||||
const func = (...args) => {
|
const func = (...args): void => {
|
||||||
item.handler(this, ...args);
|
item.handler(this, ...args);
|
||||||
};
|
};
|
||||||
this[item.type](item.message, func);
|
this[item.type](item.message, func);
|
||||||
@ -169,12 +203,12 @@ export default class Editor extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private initPluginStatus() {
|
private initPluginStatus(): PluginStatusSet {
|
||||||
const { plugins = {} } = this.config;
|
const { plugins = {} } = this.config;
|
||||||
const pluginAreas = Object.keys(plugins);
|
const pluginAreas = Object.keys(plugins);
|
||||||
const res: PluginStatus = {};
|
const res: PluginStatusSet = {};
|
||||||
pluginAreas.forEach(area => {
|
pluginAreas.forEach((area): void => {
|
||||||
(plugins[area] || []).forEach(plugin => {
|
(plugins[area] || []).forEach((plugin): void => {
|
||||||
if (plugin.type === 'Divider') {
|
if (plugin.type === 'Divider') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import Editor from './editor';
|
import Editor from './editor';
|
||||||
export { default as PluginFactory } from './pluginFactory';
|
|
||||||
export { default as EditorContext } from './context';
|
|
||||||
|
|
||||||
import * as editorUtils from './utils';
|
import * as editorUtils from './utils';
|
||||||
import * as editorDefinitions from './definitions';
|
import * as editorDefinitions from './definitions';
|
||||||
|
|
||||||
|
export { default as PluginFactory } from './pluginFactory';
|
||||||
|
export { default as EditorContext } from './context';
|
||||||
|
|
||||||
export default Editor;
|
export default Editor;
|
||||||
|
|
||||||
export const utils = editorUtils;
|
export const utils = editorUtils;
|
||||||
|
|||||||
@ -1,32 +1,24 @@
|
|||||||
import React, { createRef, PureComponent } from 'react';
|
import React, { createRef, PureComponent } from 'react';
|
||||||
|
|
||||||
import EditorContext from './context';
|
import EditorContext from './context';
|
||||||
import { I18nFunction, PluginConfig } from './definitions';
|
import { I18nFunction, PluginProps, PluginClass, Plugin } from './definitions';
|
||||||
import Editor from './editor';
|
import Editor from './editor';
|
||||||
import { acceptsRef, generateI18n, isEmpty, transformToPromise } from './utils';
|
import { acceptsRef, generateI18n, isEmpty, transformToPromise } from './utils';
|
||||||
|
|
||||||
export interface PluginProps {
|
export default function pluginFactory(Comp: PluginClass): React.ComponentType<PluginProps> {
|
||||||
editor: Editor;
|
|
||||||
config: PluginConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InjectedPluginProps {
|
|
||||||
i18n?: I18nFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function pluginFactory(
|
|
||||||
Comp: React.ComponentType<PluginProps & InjectedPluginProps>
|
|
||||||
): React.ComponentType<PluginProps> {
|
|
||||||
class LowcodePlugin extends PureComponent<PluginProps> {
|
class LowcodePlugin extends PureComponent<PluginProps> {
|
||||||
public static displayName = 'LowcodeEditorPlugin';
|
public static displayName = 'LowcodeEditorPlugin';
|
||||||
public static defaultProps = {
|
|
||||||
config: {}
|
|
||||||
};
|
|
||||||
public static contextType = EditorContext;
|
public static contextType = EditorContext;
|
||||||
|
|
||||||
public static init = Comp.init;
|
public static init = Comp.init;
|
||||||
public ref = createRef<React.Component>();
|
|
||||||
|
public ref: React.RefObject<React.ReactElement> & Plugin;
|
||||||
|
|
||||||
private editor: Editor;
|
private editor: Editor;
|
||||||
|
|
||||||
private pluginKey: string;
|
private pluginKey: string;
|
||||||
|
|
||||||
private i18n: I18nFunction;
|
private i18n: I18nFunction;
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
@ -36,6 +28,7 @@ export default function pluginFactory(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { locale, messages, editor } = props;
|
const { locale, messages, editor } = props;
|
||||||
|
this.ref = createRef<React.ReactElement>();
|
||||||
// 注册插件
|
// 注册插件
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
this.i18n = generateI18n(locale, messages);
|
this.i18n = generateI18n(locale, messages);
|
||||||
@ -46,7 +39,7 @@ export default function pluginFactory(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount(): void {
|
||||||
// 销毁插件
|
// 销毁插件
|
||||||
if (this.editor && this.editor.plugins) {
|
if (this.editor && this.editor.plugins) {
|
||||||
delete this.editor.plugins[this.pluginKey];
|
delete this.editor.plugins[this.pluginKey];
|
||||||
@ -60,14 +53,14 @@ export default function pluginFactory(
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
public close = () => {
|
public close = (): Promise<any> => {
|
||||||
if (this.ref && this.ref.close && typeof this.ref.close === 'function') {
|
if (this.ref && this.ref.close && typeof this.ref.close === 'function') {
|
||||||
return transformToPromise(this.ref.close());
|
return transformToPromise(this.ref.close());
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
public render() {
|
public render(): React.ReactNode {
|
||||||
const { config } = this.props;
|
const { config } = this.props;
|
||||||
const props = {
|
const props = {
|
||||||
i18n: this.i18n,
|
i18n: this.i18n,
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
import IntlMessageFormat from 'intl-messageformat';
|
import IntlMessageFormat from 'intl-messageformat';
|
||||||
import keymaster from 'keymaster';
|
import keymaster from 'keymaster';
|
||||||
import { EditorConfig, I18nFunction, I18nMessages, LocaleType, ShortCutsConfig } from './definitions';
|
|
||||||
import Editor from './editor';
|
|
||||||
|
|
||||||
import _clone from 'lodash/cloneDeep';
|
import _clone from 'lodash/cloneDeep';
|
||||||
import _debounce from 'lodash/debounce';
|
import _debounce from 'lodash/debounce';
|
||||||
@ -10,6 +8,10 @@ import _deepEqual from 'lodash/isEqualWith';
|
|||||||
import _pick from 'lodash/pick';
|
import _pick from 'lodash/pick';
|
||||||
import _throttle from 'lodash/throttle';
|
import _throttle from 'lodash/throttle';
|
||||||
|
|
||||||
|
import _serialize from 'serialize-javascript';
|
||||||
|
import Editor from './editor';
|
||||||
|
import { EditorConfig, I18nFunction, I18nMessages, LocaleType, ShortCutsConfig } from './definitions';
|
||||||
|
|
||||||
export const pick = _pick;
|
export const pick = _pick;
|
||||||
export const deepEqual = _deepEqual;
|
export const deepEqual = _deepEqual;
|
||||||
export const clone = _clone;
|
export const clone = _clone;
|
||||||
@ -17,7 +19,6 @@ export const isEmpty = _isEmpty;
|
|||||||
export const throttle = _throttle;
|
export const throttle = _throttle;
|
||||||
export const debounce = _debounce;
|
export const debounce = _debounce;
|
||||||
|
|
||||||
import _serialize from 'serialize-javascript';
|
|
||||||
export const serialize = _serialize;
|
export const serialize = _serialize;
|
||||||
|
|
||||||
const ENV = {
|
const ENV = {
|
||||||
@ -27,6 +28,17 @@ const ENV = {
|
|||||||
WEB: 'WEB'
|
WEB: 'WEB'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
sendIDEMessage?: (params: IDEMessageParams) => void;
|
||||||
|
goldlog?: {
|
||||||
|
record: (logKey: string, gmKey: string, goKey: string, method: 'POST' | 'GET') => (...args: any[]) => any;
|
||||||
|
};
|
||||||
|
is_theia?: boolean;
|
||||||
|
vscode?: boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface IDEMessageParams {
|
export interface IDEMessageParams {
|
||||||
action: string;
|
action: string;
|
||||||
data: {
|
data: {
|
||||||
@ -57,7 +69,7 @@ export function serializeParams(obj: object): string {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
const res: string[] = [];
|
const res: string[] = [];
|
||||||
Object.entries(obj).forEach(([key, val]) => {
|
Object.entries(obj).forEach(([key, val]): void => {
|
||||||
if (val === null || val === undefined || val === '') {
|
if (val === null || val === undefined || val === '') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -115,8 +127,8 @@ export function getEnv(): string {
|
|||||||
|
|
||||||
// 注册快捷键
|
// 注册快捷键
|
||||||
export function registShortCuts(config: ShortCutsConfig, editor: Editor): void {
|
export function registShortCuts(config: ShortCutsConfig, editor: Editor): void {
|
||||||
(config || []).forEach(item => {
|
(config || []).forEach((item): void => {
|
||||||
keymaster(item.keyboard, ev => {
|
keymaster(item.keyboard, (ev: Event): void => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
item.handler(editor, ev, keymaster);
|
item.handler(editor, ev, keymaster);
|
||||||
});
|
});
|
||||||
@ -125,7 +137,7 @@ export function registShortCuts(config: ShortCutsConfig, editor: Editor): void {
|
|||||||
|
|
||||||
// 取消注册快捷
|
// 取消注册快捷
|
||||||
export function unRegistShortCuts(config: ShortCutsConfig): void {
|
export function unRegistShortCuts(config: ShortCutsConfig): void {
|
||||||
(config || []).forEach(item => {
|
(config || []).forEach((item): void => {
|
||||||
keymaster.unbind(item.keyboard);
|
keymaster.unbind(item.keyboard);
|
||||||
});
|
});
|
||||||
if (window.parent.vscode) {
|
if (window.parent.vscode) {
|
||||||
@ -141,7 +153,7 @@ export function transformToPromise(input: any): Promise<{}> {
|
|||||||
if (input instanceof Promise) {
|
if (input instanceof Promise) {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject): void => {
|
||||||
if (input || input === undefined) {
|
if (input || input === undefined) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
@ -161,7 +173,7 @@ export function transformArrayToMap<T>(arr: T[], key: string, overwrite: boolean
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const res = {};
|
const res = {};
|
||||||
arr.forEach(item => {
|
arr.forEach((item): void => {
|
||||||
const curKey = item[key];
|
const curKey = item[key];
|
||||||
if (item[key] === undefined) {
|
if (item[key] === undefined) {
|
||||||
return;
|
return;
|
||||||
@ -187,7 +199,7 @@ export function parseSearch(search: string): Query {
|
|||||||
const str = search.replace(/^\?/, '');
|
const str = search.replace(/^\?/, '');
|
||||||
const paramStr = str.split('&');
|
const paramStr = str.split('&');
|
||||||
const res = {};
|
const res = {};
|
||||||
paramStr.forEach(item => {
|
paramStr.forEach((item): void => {
|
||||||
const regRes = item.split('=');
|
const regRes = item.split('=');
|
||||||
if (regRes[0] && regRes[1]) {
|
if (regRes[0] && regRes[1]) {
|
||||||
res[regRes[0]] = decodeURIComponent(regRes[1]);
|
res[regRes[0]] = decodeURIComponent(regRes[1]);
|
||||||
@ -210,7 +222,7 @@ export function comboEditorConfig(defaultConfig: EditorConfig = {}, customConfig
|
|||||||
const customShortCuts = transformArrayToMap(shortCuts || [], 'keyboard');
|
const customShortCuts = transformArrayToMap(shortCuts || [], 'keyboard');
|
||||||
const localeList = ['zh-CN', 'zh-TW', 'en-US', 'ja-JP'];
|
const localeList = ['zh-CN', 'zh-TW', 'en-US', 'ja-JP'];
|
||||||
const i18nConfig = {};
|
const i18nConfig = {};
|
||||||
localeList.forEach(key => {
|
localeList.forEach((key): void => {
|
||||||
i18nConfig[key] = {
|
i18nConfig[key] = {
|
||||||
...(defaultConfig.i18n && defaultConfig.i18n[key]),
|
...(defaultConfig.i18n && defaultConfig.i18n[key]),
|
||||||
...(i18n && i18n[key])
|
...(i18n && i18n[key])
|
||||||
@ -248,9 +260,12 @@ export function comboEditorConfig(defaultConfig: EditorConfig = {}, customConfig
|
|||||||
* 判断当前组件是否能够设置ref
|
* 判断当前组件是否能够设置ref
|
||||||
* @param {*} Comp 需要判断的组件
|
* @param {*} Comp 需要判断的组件
|
||||||
*/
|
*/
|
||||||
export function acceptsRef(Comp: React.ComponentType) {
|
export function acceptsRef(Comp: React.ReactNode): boolean {
|
||||||
const hasSymbol = typeof Symbol === 'function' && Symbol.for;
|
const hasSymbol = typeof Symbol === 'function' && Symbol.for;
|
||||||
const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
|
const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
|
||||||
|
if (!Comp || typeof Comp !== 'object' || isEmpty(Comp)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
(Comp.$$typeof && Comp.$$typeof === REACT_FORWARD_REF_TYPE) || (Comp.prototype && Comp.prototype.isReactComponent)
|
(Comp.$$typeof && Comp.$$typeof === REACT_FORWARD_REF_TYPE) || (Comp.prototype && Comp.prototype.isReactComponent)
|
||||||
);
|
);
|
||||||
|
|||||||
@ -10,12 +10,9 @@ import constants from './config/constants';
|
|||||||
import './config/locale';
|
import './config/locale';
|
||||||
import './config/setters';
|
import './config/setters';
|
||||||
|
|
||||||
import pkg from '../package.json';
|
|
||||||
import './global.scss';
|
import './global.scss';
|
||||||
import './config/theme.scss';
|
import './config/theme.scss';
|
||||||
|
|
||||||
(window as any).__pkg = pkg;
|
|
||||||
|
|
||||||
const ICE_CONTAINER = document.getElementById('ice-container');
|
const ICE_CONTAINER = document.getElementById('ice-container');
|
||||||
|
|
||||||
if (!ICE_CONTAINER) {
|
if (!ICE_CONTAINER) {
|
||||||
@ -26,7 +23,7 @@ ReactDOM.render(
|
|||||||
<Router>
|
<Router>
|
||||||
<Route
|
<Route
|
||||||
path="/*"
|
path="/*"
|
||||||
component={props => (
|
component={(props): React.ReactNode => (
|
||||||
<Skeleton
|
<Skeleton
|
||||||
{...props}
|
{...props}
|
||||||
{...(config.skeleton && config.skeleton.props)}
|
{...(config.skeleton && config.skeleton.props)}
|
||||||
|
|||||||
@ -163,16 +163,19 @@ const SCHEMA = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default class DesignerPlugin extends PureComponent<PluginProps> {
|
export default class DesignerPlugin extends PureComponent<PluginProps> {
|
||||||
static displayName: 'LowcodePluginDesigner';
|
displayName: 'LowcodePluginDesigner';
|
||||||
|
|
||||||
constructor(props) {
|
handleDesignerMount = (designer): void => {
|
||||||
super(props);
|
const { editor } = this.props;
|
||||||
}
|
editor.set('designer', designer);
|
||||||
|
editor.emit('designer.ready', designer);
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render(): React.ReactNode {
|
||||||
const { editor } = this.props;
|
const { editor } = this.props;
|
||||||
return (
|
return (
|
||||||
<Designer
|
<Designer
|
||||||
|
onMount={this.handleDesignerMount}
|
||||||
className="lowcode-plugin-designer"
|
className="lowcode-plugin-designer"
|
||||||
defaultSchema={SCHEMA as any}
|
defaultSchema={SCHEMA as any}
|
||||||
eventPipe={editor as any}
|
eventPipe={editor as any}
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
.lowcode-plugin-logo {
|
.lowcode-plugin-logo {
|
||||||
padding: 8px 16px;
|
padding: 14px 8px;
|
||||||
|
padding-left: 8px;
|
||||||
.logo {
|
.logo {
|
||||||
|
display: block;
|
||||||
width: 56px;
|
width: 56px;
|
||||||
height: 32px;
|
height: 20px;
|
||||||
|
cursor: pointer;
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
import Editor from '../../framework/index';
|
import { PluginProps } from '../../framework/definitions';
|
||||||
import { PluginConfig } from '../../framework/definitions';
|
|
||||||
|
|
||||||
export interface PluginProps {
|
export interface IProps {
|
||||||
editor: Editor;
|
|
||||||
config: PluginConfig;
|
|
||||||
logo?: string;
|
logo?: string;
|
||||||
|
href?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function(props: PluginProps) {
|
const Logo: React.FC<IProps & PluginProps> = (props): React.ReactElement => {
|
||||||
return (
|
return (
|
||||||
<div className="lowcode-plugin-logo">
|
<div className="lowcode-plugin-logo">
|
||||||
<div className="logo" style={{ backgroundImage: `url(${props.logo})` }} />
|
<a className="logo" target="blank" href={props.href || '/'} style={{ backgroundImage: `url(${props.logo})` }} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default Logo;
|
||||||
|
|||||||
@ -1,22 +1,75 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
import Editor from '../../framework/index';
|
import { PluginProps } from '../../framework/definitions';
|
||||||
import { PluginConfig } from '../../framework/definitions';
|
|
||||||
import TopIcon from '../../skeleton/components/TopIcon/index';
|
import TopIcon from '../../skeleton/components/TopIcon/index';
|
||||||
|
|
||||||
export interface PluginProps {
|
export interface IProps {
|
||||||
editor: Editor;
|
|
||||||
config: PluginConfig;
|
|
||||||
logo?: string;
|
logo?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function(props: PluginProps) {
|
export interface IState {
|
||||||
const [backEnable, setBackEnable] = useState(true);
|
undoEnable: boolean;
|
||||||
const [forwardEnable, setForwardEnable] = useState(true);
|
redoEnable: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class UndoRedo extends PureComponent<IProps & PluginProps, IState> {
|
||||||
|
public static display = 'LowcodeUndoRedo';
|
||||||
|
|
||||||
|
private history: any;
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
undoEnable: false,
|
||||||
|
redoEnable: false
|
||||||
|
};
|
||||||
|
if (props.editor.designer) {
|
||||||
|
this.init();
|
||||||
|
} else {
|
||||||
|
props.editor.on('designer.ready', (): void => {
|
||||||
|
this.init();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init = (): void => {
|
||||||
|
const { editor } = this.props;
|
||||||
|
this.history = editor.designer.currentHistory;
|
||||||
|
this.updateState(this.history.getState());
|
||||||
|
editor.on('designer.history-change', (history): void => {
|
||||||
|
this.history = history;
|
||||||
|
this.history.onStateChange(this.updateState);
|
||||||
|
});
|
||||||
|
this.history.onStateChange(this.updateState);
|
||||||
|
};
|
||||||
|
|
||||||
|
updateState = (state: number): void => {
|
||||||
|
console.log('++++', !!(state & 1), !!(state & 2));
|
||||||
|
this.setState({
|
||||||
|
undoEnable: !!(state & 1),
|
||||||
|
redoEnable: !!(state & 2)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleUndoClick = (): void => {
|
||||||
|
if (this.history) {
|
||||||
|
this.history.back();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleRedoClick = (): void => {
|
||||||
|
if (this.history) {
|
||||||
|
this.history.forward();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render(): React.ReactNode {
|
||||||
|
const { undoEnable, redoEnable } = this.state;
|
||||||
return (
|
return (
|
||||||
<div className="lowcode-plugin-undo-redo">
|
<div className="lowcode-plugin-undo-redo">
|
||||||
<TopIcon icon="houtui" title="后退" disabled={!backEnable} />
|
<TopIcon icon="houtui" title="后退" disabled={!undoEnable} onClick={this.handleUndoClick} />
|
||||||
<TopIcon icon="qianjin" title="前进" disabled={!forwardEnable} />
|
<TopIcon icon="qianjin" title="前进" disabled={!redoEnable} onClick={this.handleRedoClick} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,34 +1,16 @@
|
|||||||
.lowcode-left-plugin {
|
.lowcode-left-plugin {
|
||||||
font-size: 16px;
|
font-size: 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 36px;
|
line-height: 44px;
|
||||||
height: 36px;
|
height: 44px;
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
color: #777;
|
color: $color-text1-3;
|
||||||
&.collapse {
|
|
||||||
height: 40px;
|
|
||||||
color: #8c8c8c;
|
|
||||||
border-bottom: 1px solid #bfbfbf;
|
|
||||||
}
|
|
||||||
&.locked {
|
&.locked {
|
||||||
color: red !important;
|
color: red !important;
|
||||||
}
|
}
|
||||||
&.active {
|
|
||||||
color: #fff !important;
|
|
||||||
background-color: $color-brand1-9 !important;
|
|
||||||
&.disabled {
|
|
||||||
color: #fff;
|
|
||||||
background-color: $color-fill1-7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.disabled {
|
|
||||||
cursor: not-allowed;
|
|
||||||
color: $color-text1-1;
|
|
||||||
}
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $color-brand1-1;
|
|
||||||
color: $color-brand1-6;
|
color: $color-brand1-6;
|
||||||
&:before {
|
&:before {
|
||||||
content: attr(data-tooltip);
|
content: attr(data-tooltip);
|
||||||
@ -41,8 +23,8 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
padding: 6px 8px;
|
padding: 6px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: rgba(0, 0, 0, 0.75);
|
background: $balloon-tooltip-color-bg;
|
||||||
color: #fff;
|
color: $color-text1-3;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
&:after {
|
&:after {
|
||||||
@ -52,8 +34,21 @@
|
|||||||
left: 40px;
|
left: 40px;
|
||||||
top: 15px;
|
top: 15px;
|
||||||
border: 5px solid transparent;
|
border: 5px solid transparent;
|
||||||
border-right-color: rgba(0, 0, 0, 0.75);
|
border-right: 5px solid $balloon-tooltip-color-bg;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.active {
|
||||||
|
color: $color-brand1-9;
|
||||||
|
&.disabled {
|
||||||
|
color: $color-text1-1;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
color: $color-brand1-6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
color: $color-text1-1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ export default class LeftPlugin extends PureComponent<LeftPluginProps, LeftPlugi
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
marked: false,
|
marked: false,
|
||||||
locked: false,
|
locked: false,
|
||||||
onClick: () => {}
|
onClick: (): void => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
@ -40,7 +40,7 @@ export default class LeftPlugin extends PureComponent<LeftPluginProps, LeftPlugi
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount(): void {
|
||||||
const { config, editor } = this.props;
|
const { config, editor } = this.props;
|
||||||
const pluginKey = config && config.pluginKey;
|
const pluginKey = config && config.pluginKey;
|
||||||
if (editor && pluginKey) {
|
if (editor && pluginKey) {
|
||||||
@ -49,7 +49,7 @@ export default class LeftPlugin extends PureComponent<LeftPluginProps, LeftPlugi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount(): void {
|
||||||
const { config, editor } = this.props;
|
const { config, editor } = this.props;
|
||||||
const pluginKey = config && config.pluginKey;
|
const pluginKey = config && config.pluginKey;
|
||||||
if (editor && pluginKey) {
|
if (editor && pluginKey) {
|
||||||
@ -58,12 +58,12 @@ export default class LeftPlugin extends PureComponent<LeftPluginProps, LeftPlugi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClose = () => {
|
handleClose = (): void => {
|
||||||
const { config, editor } = this.props;
|
const { config, editor } = this.props;
|
||||||
const pluginKey = config && config.pluginKey;
|
const pluginKey = config && config.pluginKey;
|
||||||
const plugin = editor.plugins && editor.plugins[pluginKey];
|
const plugin = editor.plugins && editor.plugins[pluginKey];
|
||||||
if (plugin) {
|
if (plugin && plugin.close) {
|
||||||
plugin.close().then(() => {
|
plugin.close().then((): void => {
|
||||||
this.setState({
|
this.setState({
|
||||||
dialogVisible: false
|
dialogVisible: false
|
||||||
});
|
});
|
||||||
@ -71,24 +71,26 @@ export default class LeftPlugin extends PureComponent<LeftPluginProps, LeftPlugi
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleOpen = () => {
|
handleOpen = (): void => {
|
||||||
// todo 对话框类型的插件初始时拿不到插件实例
|
// todo 对话框类型的插件初始时拿不到插件实例
|
||||||
this.setState({
|
this.setState({
|
||||||
dialogVisible: true
|
dialogVisible: true
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleShow = () => {
|
handleShow = (): void => {
|
||||||
const { disabled, config, onClick, editor } = this.props;
|
const { disabled, config, onClick, editor } = this.props;
|
||||||
const pluginKey = config && config.pluginKey;
|
const pluginKey = config && config.pluginKey;
|
||||||
if (disabled || !pluginKey) return;
|
if (disabled || !pluginKey) return;
|
||||||
//考虑到弹窗情况,延时发送消息
|
// 考虑到弹窗情况,延时发送消息
|
||||||
setTimeout(() => editor.emit(`${pluginKey}.addon.activate`), 0);
|
setTimeout((): void => editor.emit(`${pluginKey}.plugin.activate`), 0);
|
||||||
this.handleOpen();
|
this.handleOpen();
|
||||||
onClick && onClick();
|
if (onClick) {
|
||||||
|
onClick();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
renderIcon = clickCallback => {
|
renderIcon = (clickCallback): React.ReactNode => {
|
||||||
const { active, disabled, marked, locked, onClick, config } = this.props;
|
const { active, disabled, marked, locked, onClick, config } = this.props;
|
||||||
const { pluginKey, props } = config || {};
|
const { pluginKey, props } = config || {};
|
||||||
const { icon, title } = props || {};
|
const { icon, title } = props || {};
|
||||||
@ -100,10 +102,11 @@ export default class LeftPlugin extends PureComponent<LeftPluginProps, LeftPlugi
|
|||||||
locked
|
locked
|
||||||
})}
|
})}
|
||||||
data-tooltip={title}
|
data-tooltip={title}
|
||||||
onClick={() => {
|
onClick={(): void => {
|
||||||
if (disabled) return;
|
if (disabled) return;
|
||||||
//考虑到弹窗情况,延时发送消息
|
// 考虑到弹窗情况,延时发送消息
|
||||||
clickCallback && clickCallback();
|
clickCallback && clickCallback();
|
||||||
|
|
||||||
onClick && onClick();
|
onClick && onClick();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -118,7 +121,7 @@ export default class LeftPlugin extends PureComponent<LeftPluginProps, LeftPlugi
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render(): React.ReactNode {
|
||||||
const { marked, locked, active, disabled, config, editor, pluginClass: Comp } = this.props;
|
const { marked, locked, active, disabled, config, editor, pluginClass: Comp } = this.props;
|
||||||
const { pluginKey, props, type, pluginProps } = config || {};
|
const { pluginKey, props, type, pluginProps } = config || {};
|
||||||
const { onClick, title } = props || {};
|
const { onClick, title } = props || {};
|
||||||
@ -133,7 +136,7 @@ export default class LeftPlugin extends PureComponent<LeftPluginProps, LeftPlugi
|
|||||||
locked={locked}
|
locked={locked}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
config={config}
|
config={config}
|
||||||
onClick={() => {
|
onClick={(): void => {
|
||||||
onClick && onClick.call(null, editor);
|
onClick && onClick.call(null, editor);
|
||||||
}}
|
}}
|
||||||
{...pluginProps}
|
{...pluginProps}
|
||||||
@ -145,30 +148,34 @@ export default class LeftPlugin extends PureComponent<LeftPluginProps, LeftPlugi
|
|||||||
case 'LinkIcon':
|
case 'LinkIcon':
|
||||||
return (
|
return (
|
||||||
<a {...(props.linkProps || {})}>
|
<a {...(props.linkProps || {})}>
|
||||||
{this.renderIcon(() => {
|
{this.renderIcon((): void => {
|
||||||
onClick && onClick.call(null, editor);
|
onClick && onClick.call(null, editor);
|
||||||
})}
|
})}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
case 'Icon':
|
case 'Icon':
|
||||||
return this.renderIcon(() => {
|
return this.renderIcon((): void => {
|
||||||
onClick && onClick.call(null, editor);
|
onClick && onClick.call(null, editor);
|
||||||
});
|
});
|
||||||
case 'DialogIcon':
|
case 'DialogIcon':
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{this.renderIcon(() => {
|
{this.renderIcon((): void => {
|
||||||
onClick && onClick.call(null, editor);
|
onClick && onClick.call(null, editor);
|
||||||
this.handleOpen();
|
this.handleOpen();
|
||||||
})}
|
})}
|
||||||
<Dialog
|
<Dialog
|
||||||
onOk={() => {
|
onOk={(): void => {
|
||||||
editor.emit(`${pluginKey}.dialog.onOk`);
|
editor.emit(`${pluginKey}.dialog.onOk`);
|
||||||
this.handleClose();
|
this.handleClose();
|
||||||
}}
|
}}
|
||||||
onCancel={this.handleClose}
|
onCancel={this.handleClose}
|
||||||
onClose={this.handleClose}
|
onClose={this.handleClose}
|
||||||
title={title}
|
title={title}
|
||||||
|
style={{
|
||||||
|
width: 500,
|
||||||
|
...(props.dialogProps && props.dialogProps.style)
|
||||||
|
}}
|
||||||
{...(props.dialogProps || {})}
|
{...(props.dialogProps || {})}
|
||||||
visible={dialogVisible}
|
visible={dialogVisible}
|
||||||
>
|
>
|
||||||
@ -179,7 +186,7 @@ export default class LeftPlugin extends PureComponent<LeftPluginProps, LeftPlugi
|
|||||||
case 'BalloonIcon':
|
case 'BalloonIcon':
|
||||||
return (
|
return (
|
||||||
<Balloon
|
<Balloon
|
||||||
trigger={this.renderIcon(() => {
|
trigger={this.renderIcon((): void => {
|
||||||
onClick && onClick.call(null, editor);
|
onClick && onClick.call(null, editor);
|
||||||
})}
|
})}
|
||||||
align="r"
|
align="r"
|
||||||
@ -190,7 +197,7 @@ export default class LeftPlugin extends PureComponent<LeftPluginProps, LeftPlugi
|
|||||||
</Balloon>
|
</Balloon>
|
||||||
);
|
);
|
||||||
case 'PanelIcon':
|
case 'PanelIcon':
|
||||||
return this.renderIcon(() => {
|
return this.renderIcon((): void => {
|
||||||
onClick && onClick.call(null, editor);
|
onClick && onClick.call(null, editor);
|
||||||
this.handleOpen();
|
this.handleOpen();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,12 +2,12 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
background: #ffffff;
|
background: $card-background;
|
||||||
transition: width 0.3s ease;
|
transition: width 0.3s ease;
|
||||||
transform: translate3d(0, 0, 0);
|
transform: translate3d(0, 0, 0);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
&.visible {
|
&.visible {
|
||||||
border-right: 1px solid #bfbfbf;
|
border-right: 1px solid $color-line1-1;
|
||||||
}
|
}
|
||||||
.drag-area {
|
.drag-area {
|
||||||
display: none;
|
display: none;
|
||||||
@ -16,7 +16,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: 999;
|
z-index: 99;
|
||||||
}
|
}
|
||||||
&.draggable {
|
&.draggable {
|
||||||
.drag-area {
|
.drag-area {
|
||||||
@ -41,12 +41,12 @@
|
|||||||
}
|
}
|
||||||
&.left {
|
&.left {
|
||||||
&.floatable {
|
&.floatable {
|
||||||
left: 44px;
|
left: 48px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.right {
|
&.right {
|
||||||
&.floatable {
|
&.floatable {
|
||||||
right: 44px;
|
right: 48px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,7 +37,7 @@ export default class Panel extends PureComponent<PanelProps, PanelState> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render(): React.ReactNode {
|
||||||
const { align, draggable, floatable, visible } = this.props;
|
const { align, draggable, floatable, visible } = this.props;
|
||||||
const { width } = this.state;
|
const { width } = this.state;
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,21 +1,27 @@
|
|||||||
.next-btn.next-large.lowcode-top-btn {
|
.lowcode-top-icon {
|
||||||
|
display: inline-block;
|
||||||
width: 44px;
|
width: 44px;
|
||||||
height: 44px;
|
font-size: 20px;
|
||||||
padding: 0;
|
line-height: 48px;
|
||||||
margin: 2px -2px;
|
color: $color-text1-3;
|
||||||
text-align: center;
|
position: relative;
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
color: #777;
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
color: $color-text1-1;
|
color: $color-text1-1;
|
||||||
|
&:hover {
|
||||||
|
color: $color-text1-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
color: $color-brand1-9;
|
||||||
|
&:hover {
|
||||||
|
color: $color-brand1-6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&.locked {
|
&.locked {
|
||||||
color: red !important;
|
color: red !important;
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $color-brand1-1;
|
|
||||||
color: $color-brand1-6;
|
color: $color-brand1-6;
|
||||||
&:before {
|
&:before {
|
||||||
content: attr(data-tooltip);
|
content: attr(data-tooltip);
|
||||||
@ -31,8 +37,8 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
padding: 6px 8px;
|
padding: 6px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: rgba(0, 0, 0, 0.75);
|
background: $balloon-tooltip-color-bg;
|
||||||
color: #fff;
|
color: $color-text1-3;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
&:after {
|
&:after {
|
||||||
@ -43,7 +49,7 @@
|
|||||||
transform: translate(-50%, 0);
|
transform: translate(-50%, 0);
|
||||||
bottom: -5px;
|
bottom: -5px;
|
||||||
border: 5px solid transparent;
|
border: 5px solid transparent;
|
||||||
border-bottom-color: rgba(0, 0, 0, 0.75);
|
border-bottom-color: $balloon-tooltip-color-bg;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
@ -51,7 +57,7 @@
|
|||||||
}
|
}
|
||||||
i.next-icon {
|
i.next-icon {
|
||||||
&:before {
|
&:before {
|
||||||
font-size: 17px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Icon, Button } from '@alifd/next';
|
import { Icon } from '@alifd/next';
|
||||||
|
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
|
||||||
@ -13,13 +13,13 @@ export interface TopIconProps {
|
|||||||
locked?: boolean;
|
locked?: boolean;
|
||||||
marked?: boolean;
|
marked?: boolean;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
showTitle?: boolean;
|
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
title?: string;
|
title?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class TopIcon extends PureComponent<TopIconProps> {
|
export default class TopIcon extends PureComponent<TopIconProps> {
|
||||||
static displayName = 'LowcodeTopIcon';
|
static displayName = 'LowcodeTopIcon';
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
active: false,
|
active: false,
|
||||||
className: '',
|
className: '',
|
||||||
@ -27,20 +27,16 @@ export default class TopIcon extends PureComponent<TopIconProps> {
|
|||||||
icon: '',
|
icon: '',
|
||||||
id: '',
|
id: '',
|
||||||
locked: false,
|
locked: false,
|
||||||
onClick: () => {},
|
onClick: (): void => {},
|
||||||
showTitle: false,
|
|
||||||
style: {},
|
style: {},
|
||||||
title: ''
|
title: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render(): React.ReactNode {
|
||||||
const { active, disabled, icon, locked, title, className, id, style, showTitle, onClick } = this.props;
|
const { active, disabled, icon, locked, title, className, id, style, onClick } = this.props;
|
||||||
return (
|
return (
|
||||||
<Button
|
<div
|
||||||
type="normal"
|
className={classNames('lowcode-top-icon', className, {
|
||||||
size="large"
|
|
||||||
text={true}
|
|
||||||
className={classNames('lowcode-top-btn', className, {
|
|
||||||
active,
|
active,
|
||||||
disabled,
|
disabled,
|
||||||
locked
|
locked
|
||||||
@ -50,11 +46,8 @@ export default class TopIcon extends PureComponent<TopIconProps> {
|
|||||||
style={style}
|
style={style}
|
||||||
onClick={disabled ? undefined : onClick}
|
onClick={disabled ? undefined : onClick}
|
||||||
>
|
>
|
||||||
<div>
|
<Icon type={icon} />
|
||||||
<Icon size="large" type={icon} />
|
|
||||||
{showTitle && <span>{title}</span>}
|
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { PureComponent, Fragment } from 'react';
|
import React, { PureComponent, Fragment, CSSProperties } from 'react';
|
||||||
|
|
||||||
import TopIcon from '../TopIcon';
|
|
||||||
import { Balloon, Badge, Dialog } from '@alifd/next';
|
import { Balloon, Badge, Dialog } from '@alifd/next';
|
||||||
|
import TopIcon from '../TopIcon';
|
||||||
|
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
import { PluginConfig, PluginClass } from '../../../framework/definitions';
|
import { PluginConfig, PluginClass } from '../../../framework/definitions';
|
||||||
@ -31,7 +31,7 @@ export default class TopPlugin extends PureComponent<TopPluginProps, TopPluginSt
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
marked: false,
|
marked: false,
|
||||||
locked: false,
|
locked: false,
|
||||||
onClick: () => {}
|
onClick: (): void => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
@ -41,7 +41,7 @@ export default class TopPlugin extends PureComponent<TopPluginProps, TopPluginSt
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount(): void {
|
||||||
const { config, editor } = this.props;
|
const { config, editor } = this.props;
|
||||||
const pluginKey = config && config.pluginKey;
|
const pluginKey = config && config.pluginKey;
|
||||||
if (editor && pluginKey) {
|
if (editor && pluginKey) {
|
||||||
@ -50,7 +50,7 @@ export default class TopPlugin extends PureComponent<TopPluginProps, TopPluginSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount(): void {
|
||||||
const { config, editor } = this.props;
|
const { config, editor } = this.props;
|
||||||
const pluginKey = config && config.pluginKey;
|
const pluginKey = config && config.pluginKey;
|
||||||
if (editor && pluginKey) {
|
if (editor && pluginKey) {
|
||||||
@ -59,22 +59,22 @@ export default class TopPlugin extends PureComponent<TopPluginProps, TopPluginSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleShow = () => {
|
handleShow = (): void => {
|
||||||
const { disabled, config, onClick, editor } = this.props;
|
const { disabled, config, onClick, editor } = this.props;
|
||||||
const pluginKey = config && config.pluginKey;
|
const pluginKey = config && config.pluginKey;
|
||||||
if (disabled || !pluginKey) return;
|
if (disabled || !pluginKey) return;
|
||||||
//考虑到弹窗情况,延时发送消息
|
// 考虑到弹窗情况,延时发送消息
|
||||||
setTimeout(() => editor.emit(`${pluginKey}.addon.activate`), 0);
|
setTimeout((): void => editor.emit(`${pluginKey}.plugin.activate`), 0);
|
||||||
this.handleOpen();
|
this.handleOpen();
|
||||||
onClick && onClick();
|
onClick && onClick();
|
||||||
};
|
};
|
||||||
|
|
||||||
handleClose = () => {
|
handleClose = (): void => {
|
||||||
const { config, editor } = this.props;
|
const { config, editor } = this.props;
|
||||||
const pluginKey = config && config.pluginKey;
|
const pluginKey = config && config.pluginKey;
|
||||||
const plugin = editor.plugins && editor.plugins[pluginKey];
|
const plugin = editor.plugins && editor.plugins[pluginKey];
|
||||||
if (plugin) {
|
if (plugin && plugin.close) {
|
||||||
plugin.close().then(() => {
|
plugin.close().then((): void => {
|
||||||
this.setState({
|
this.setState({
|
||||||
dialogVisible: false
|
dialogVisible: false
|
||||||
});
|
});
|
||||||
@ -82,29 +82,29 @@ export default class TopPlugin extends PureComponent<TopPluginProps, TopPluginSt
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleOpen = () => {
|
handleOpen = (): void => {
|
||||||
// todo dialog类型的插件初始时拿不动插件实例
|
// todo dialog类型的插件初始时拿不动插件实例
|
||||||
this.setState({
|
this.setState({
|
||||||
dialogVisible: true
|
dialogVisible: true
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
renderIcon = clickCallback => {
|
renderIcon = (clickCallback): React.ReactNode => {
|
||||||
const { active, disabled, marked, locked, config, onClick, editor } = this.props;
|
const { active, disabled, marked, locked, config, onClick, editor } = this.props;
|
||||||
const { pluginKey, props } = config || {};
|
const { pluginKey, props } = config || {};
|
||||||
const { icon, title } = props || {};
|
const { icon, title } = props || {};
|
||||||
const node = (
|
const node = (
|
||||||
<TopIcon
|
<TopIcon
|
||||||
className={`lowcode-top-addon ${pluginKey}`}
|
className={`lowcode-top-plugin ${pluginKey}`}
|
||||||
active={active}
|
active={active}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
locked={locked}
|
locked={locked}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
title={title}
|
title={title}
|
||||||
onClick={() => {
|
onClick={(): void => {
|
||||||
if (disabled) return;
|
if (disabled) return;
|
||||||
//考虑到弹窗情况,延时发送消息
|
// 考虑到弹窗情况,延时发送消息
|
||||||
setTimeout(() => editor.emit(`${pluginKey}.addon.activate`), 0);
|
setTimeout((): void => editor.emit(`${pluginKey}.plugin.activate`), 0);
|
||||||
clickCallback && clickCallback();
|
clickCallback && clickCallback();
|
||||||
onClick && onClick();
|
onClick && onClick();
|
||||||
}}
|
}}
|
||||||
@ -113,8 +113,8 @@ export default class TopPlugin extends PureComponent<TopPluginProps, TopPluginSt
|
|||||||
return marked ? <Badge dot>{node}</Badge> : node;
|
return marked ? <Badge dot>{node}</Badge> : node;
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render(): React.ReactNode {
|
||||||
const { active, marked, locked, disabled, config, editor, pluginClass: Comp } = this.props;
|
const { active, marked, locked, disabled, config, editor, pluginClass: Comp, style } = this.props;
|
||||||
const { pluginKey, pluginProps, props, type } = config || {};
|
const { pluginKey, pluginProps, props, type } = config || {};
|
||||||
const { onClick, title } = props || {};
|
const { onClick, title } = props || {};
|
||||||
const { dialogVisible } = this.state;
|
const { dialogVisible } = this.state;
|
||||||
@ -127,7 +127,7 @@ export default class TopPlugin extends PureComponent<TopPluginProps, TopPluginSt
|
|||||||
locked={locked}
|
locked={locked}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
config={config}
|
config={config}
|
||||||
onClick={() => {
|
onClick={(): void => {
|
||||||
onClick && onClick.call(null, editor);
|
onClick && onClick.call(null, editor);
|
||||||
}}
|
}}
|
||||||
{...pluginProps}
|
{...pluginProps}
|
||||||
@ -139,30 +139,34 @@ export default class TopPlugin extends PureComponent<TopPluginProps, TopPluginSt
|
|||||||
case 'LinkIcon':
|
case 'LinkIcon':
|
||||||
return (
|
return (
|
||||||
<a {...props.linkProps}>
|
<a {...props.linkProps}>
|
||||||
{this.renderIcon(() => {
|
{this.renderIcon((): void => {
|
||||||
onClick && onClick.call(null, editor);
|
onClick && onClick.call(null, editor);
|
||||||
})}
|
})}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
case 'Icon':
|
case 'Icon':
|
||||||
return this.renderIcon(() => {
|
return this.renderIcon((): void => {
|
||||||
onClick && onClick.call(null, editor);
|
onClick && onClick.call(null, editor);
|
||||||
});
|
});
|
||||||
case 'DialogIcon':
|
case 'DialogIcon':
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{this.renderIcon(() => {
|
{this.renderIcon((): void => {
|
||||||
onClick && onClick.call(null, editor);
|
onClick && onClick.call(null, editor);
|
||||||
this.handleOpen();
|
this.handleOpen();
|
||||||
})}
|
})}
|
||||||
<Dialog
|
<Dialog
|
||||||
onOk={() => {
|
onOk={(): void => {
|
||||||
editor.emit(`${pluginKey}.dialog.onOk`);
|
editor.emit(`${pluginKey}.dialog.onOk`);
|
||||||
this.handleClose();
|
this.handleClose();
|
||||||
}}
|
}}
|
||||||
onCancel={this.handleClose}
|
onCancel={this.handleClose}
|
||||||
onClose={this.handleClose}
|
onClose={this.handleClose}
|
||||||
title={title}
|
title={title}
|
||||||
|
style={{
|
||||||
|
width: 500,
|
||||||
|
...(props.dialogProps && props.dialogProps.style)
|
||||||
|
}}
|
||||||
{...props.dialogProps}
|
{...props.dialogProps}
|
||||||
visible={dialogVisible}
|
visible={dialogVisible}
|
||||||
>
|
>
|
||||||
@ -173,7 +177,7 @@ export default class TopPlugin extends PureComponent<TopPluginProps, TopPluginSt
|
|||||||
case 'BalloonIcon':
|
case 'BalloonIcon':
|
||||||
return (
|
return (
|
||||||
<Balloon
|
<Balloon
|
||||||
trigger={this.renderIcon(() => {
|
trigger={this.renderIcon((): void => {
|
||||||
onClick && onClick.call(null, editor);
|
onClick && onClick.call(null, editor);
|
||||||
})}
|
})}
|
||||||
triggerType={['click', 'hover']}
|
triggerType={['click', 'hover']}
|
||||||
|
|||||||
@ -6,7 +6,9 @@ body {
|
|||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
color: $color-text1-3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.next-loading {
|
.next-loading {
|
||||||
.next-loading-wrap {
|
.next-loading-wrap {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -15,7 +17,7 @@ body {
|
|||||||
.lowcode-editor {
|
.lowcode-editor {
|
||||||
.lowcode-main-content {
|
.lowcode-main-content {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 48px;
|
top: 50px;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
|
|
||||||
import { HashRouter as Router, Route } from 'react-router-dom';
|
|
||||||
import { Loading, ConfigProvider } from '@alifd/next';
|
import { Loading, ConfigProvider } from '@alifd/next';
|
||||||
|
|
||||||
import Editor from '../framework/editor';
|
import Editor from '../framework/editor';
|
||||||
import { EditorConfig, Utils, PluginComponents } from '../framework/definitions';
|
import { EditorConfig, Utils, PluginClassSet } from '../framework/definitions';
|
||||||
import { comboEditorConfig, parseSearch } from '../framework/utils';
|
import { comboEditorConfig, parseSearch } from '../framework/utils';
|
||||||
|
|
||||||
import defaultConfig from './config/skeleton';
|
import defaultConfig from './config/skeleton';
|
||||||
@ -19,8 +18,17 @@ import './global.scss';
|
|||||||
|
|
||||||
let renderIdx = 0;
|
let renderIdx = 0;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
__ctx: {
|
||||||
|
editor: Editor;
|
||||||
|
appHelper: Editor;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface SkeletonProps {
|
export interface SkeletonProps {
|
||||||
components: PluginComponents;
|
components: PluginClassSet;
|
||||||
config: EditorConfig;
|
config: EditorConfig;
|
||||||
history: object;
|
history: object;
|
||||||
location: object;
|
location: object;
|
||||||
@ -29,15 +37,15 @@ export interface SkeletonProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SkeletonState {
|
export interface SkeletonState {
|
||||||
initReady: boolean;
|
initReady?: boolean;
|
||||||
skeletonKey: string;
|
skeletonKey?: string;
|
||||||
__hasError?: boolean;
|
__hasError?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Skeleton extends PureComponent<SkeletonProps, SkeletonState> {
|
export default class Skeleton extends PureComponent<SkeletonProps, SkeletonState> {
|
||||||
static displayName = 'LowcodeEditorSkeleton';
|
static displayName = 'LowcodeEditorSkeleton';
|
||||||
|
|
||||||
static getDerivedStateFromError() {
|
static getDerivedStateFromError(): SkeletonState {
|
||||||
return {
|
return {
|
||||||
__hasError: true
|
__hasError: true
|
||||||
};
|
};
|
||||||
@ -56,11 +64,11 @@ export default class Skeleton extends PureComponent<SkeletonProps, SkeletonState
|
|||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount(): void {
|
||||||
this.editor && this.editor.destroy();
|
this.editor && this.editor.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidCatch(err) {
|
componentDidCatch(err): void {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,15 +77,17 @@ export default class Skeleton extends PureComponent<SkeletonProps, SkeletonState
|
|||||||
this.editor.destroy();
|
this.editor.destroy();
|
||||||
}
|
}
|
||||||
const { utils, config, components } = this.props;
|
const { utils, config, components } = this.props;
|
||||||
const editor = (this.editor = new Editor(comboEditorConfig(defaultConfig, config), components, {
|
const editor = new Editor(comboEditorConfig(defaultConfig, config), components, {
|
||||||
...skeletonUtils,
|
...skeletonUtils,
|
||||||
...utils
|
...utils
|
||||||
}));
|
});
|
||||||
|
this.editor = editor;
|
||||||
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
window.__ctx = {
|
window.__ctx = {
|
||||||
editor,
|
editor,
|
||||||
appHelper: editor
|
appHelper: editor
|
||||||
};
|
};
|
||||||
editor.once('editor.reset', () => {
|
editor.once('editor.reset', (): void => {
|
||||||
this.setState({
|
this.setState({
|
||||||
initReady: false
|
initReady: false
|
||||||
});
|
});
|
||||||
@ -85,22 +95,23 @@ export default class Skeleton extends PureComponent<SkeletonProps, SkeletonState
|
|||||||
this.init(true);
|
this.init(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.editor.init().then(() => {
|
this.editor.init().then((): void => {
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
initReady: true,
|
initReady: true,
|
||||||
//刷新IDE时生成新的skeletonKey保证插件生命周期重新执行
|
// 刷新IDE时生成新的skeletonKey保证插件生命周期重新执行
|
||||||
skeletonKey: isReset ? `skeleton${++renderIdx}` : this.state.skeletonKey
|
skeletonKey: isReset ? `skeleton${++renderIdx}` : this.state.skeletonKey
|
||||||
},
|
},
|
||||||
() => {
|
(): void => {
|
||||||
editor.emit('editor.ready');
|
editor.emit('editor.ready');
|
||||||
|
editor.emit('ide.ready');
|
||||||
isReset && editor.emit('ide.afterReset');
|
isReset && editor.emit('ide.afterReset');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render(): React.ReactNode {
|
||||||
const { initReady, skeletonKey, __hasError } = this.state;
|
const { initReady, skeletonKey, __hasError } = this.state;
|
||||||
const { location, history, match } = this.props;
|
const { location, history, match } = this.props;
|
||||||
if (__hasError || !this.editor) {
|
if (__hasError || !this.editor) {
|
||||||
|
|||||||
@ -12,6 +12,7 @@ export default class CenterArea extends PureComponent<CenterAreaProps> {
|
|||||||
static displayName = 'LowcodeCenterArea';
|
static displayName = 'LowcodeCenterArea';
|
||||||
|
|
||||||
private editor: Editor;
|
private editor: Editor;
|
||||||
|
|
||||||
private areaManager: AreaManager;
|
private areaManager: AreaManager;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -20,10 +21,11 @@ export default class CenterArea extends PureComponent<CenterAreaProps> {
|
|||||||
this.areaManager = new AreaManager(this.editor, 'centerArea');
|
this.areaManager = new AreaManager(this.editor, 'centerArea');
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount(): void {
|
||||||
this.editor.on('skeleton.update', this.handleSkeletonUpdate);
|
this.editor.on('skeleton.update', this.handleSkeletonUpdate);
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
|
||||||
|
componentWillUnmount(): void {
|
||||||
this.editor.off('skeleton.update', this.handleSkeletonUpdate);
|
this.editor.off('skeleton.update', this.handleSkeletonUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,14 +36,16 @@ export default class CenterArea extends PureComponent<CenterAreaProps> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render(): React.ReactNode {
|
||||||
const visiblePluginList = this.areaManager.getVisiblePluginList();
|
const visiblePluginList = this.areaManager.getVisiblePluginList();
|
||||||
return (
|
return (
|
||||||
<div className="lowcode-center-area">
|
<div className="lowcode-center-area">
|
||||||
{visiblePluginList.map(item => {
|
{visiblePluginList.map(
|
||||||
|
(item): React.ReactNode => {
|
||||||
const Comp = this.editor.components[item.pluginKey];
|
const Comp = this.editor.components[item.pluginKey];
|
||||||
return <Comp key={item.pluginKey} editor={this.editor} config={item} {...item.pluginProps} />;
|
return <Comp key={item.pluginKey} editor={this.editor} config={item} {...item.pluginProps} />;
|
||||||
})}
|
}
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,23 @@
|
|||||||
.lowcode-left-area-nav {
|
.lowcode-left-area-nav {
|
||||||
width: 48px;
|
width: 50px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: #ffffff;
|
background-color: $card-background;
|
||||||
border-right: 1px solid #e8ebee;
|
border-right: 2px solid $color-line1-1;
|
||||||
position: relative;
|
position: relative;
|
||||||
.top-area {
|
.top-area {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: #ffffff;
|
padding: 12px 0;
|
||||||
|
background-color: $card-background;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
.bottom-area {
|
.bottom-area {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 20px;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: #ffffff;
|
padding: 12px 0;
|
||||||
|
background-color: $card-background;
|
||||||
max-height: calc(100% - 20px);
|
max-height: calc(100% - 20px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import './index.scss';
|
|||||||
import Editor from '../../../framework/editor';
|
import Editor from '../../../framework/editor';
|
||||||
import { PluginConfig } from '../../../framework/definitions';
|
import { PluginConfig } from '../../../framework/definitions';
|
||||||
import AreaManager from '../../../framework/areaManager';
|
import AreaManager from '../../../framework/areaManager';
|
||||||
|
import { isEmpty } from '../../../framework/utils';
|
||||||
|
|
||||||
export interface LeftAreaNavProps {
|
export interface LeftAreaNavProps {
|
||||||
editor: Editor;
|
editor: Editor;
|
||||||
@ -17,8 +18,10 @@ export default class LeftAreaNav extends PureComponent<LeftAreaNavProps, LeftAre
|
|||||||
static displayName = 'LowcodeLeftAreaNav';
|
static displayName = 'LowcodeLeftAreaNav';
|
||||||
|
|
||||||
private editor: Editor;
|
private editor: Editor;
|
||||||
|
|
||||||
private areaManager: AreaManager;
|
private areaManager: AreaManager;
|
||||||
private cacheActiveKey: string;
|
|
||||||
|
// private cacheActiveKey: string;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -28,17 +31,18 @@ export default class LeftAreaNav extends PureComponent<LeftAreaNavProps, LeftAre
|
|||||||
this.state = {
|
this.state = {
|
||||||
activeKey: 'none'
|
activeKey: 'none'
|
||||||
};
|
};
|
||||||
this.cacheActiveKey = 'none';
|
// this.cacheActiveKey = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount(): void {
|
||||||
this.editor.on('skeleton.update', this.handleSkeletonUpdate);
|
this.editor.on('skeleton.update', this.handleSkeletonUpdate);
|
||||||
this.editor.on('leftNav.change', this.handlePluginChange);
|
this.editor.on('leftNav.change', this.handlePluginChange);
|
||||||
const visiblePanelPluginList = this.areaManager.getVisiblePluginList().filter(item => item.type === 'IconPanel');
|
const visiblePanelPluginList = this.areaManager.getVisiblePluginList().filter(item => item.type === 'IconPanel');
|
||||||
const defaultKey = (visiblePanelPluginList[0] && visiblePanelPluginList[0].pluginKey) || 'componentAttr';
|
const defaultKey = (visiblePanelPluginList[0] && visiblePanelPluginList[0].pluginKey) || 'componentAttr';
|
||||||
this.handlePluginChange(defaultKey);
|
this.handlePluginChange(defaultKey);
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
|
||||||
|
componentWillUnmount(): void {
|
||||||
this.editor.off('skeleton.update', this.handleSkeletonUpdate);
|
this.editor.off('skeleton.update', this.handleSkeletonUpdate);
|
||||||
this.editor.off('leftNav.change', this.handlePluginChange);
|
this.editor.off('leftNav.change', this.handlePluginChange);
|
||||||
}
|
}
|
||||||
@ -57,48 +61,46 @@ export default class LeftAreaNav extends PureComponent<LeftAreaNavProps, LeftAre
|
|||||||
const nextPlugin = plugins[key];
|
const nextPlugin = plugins[key];
|
||||||
if (activeKey === 'none') {
|
if (activeKey === 'none') {
|
||||||
if (nextPlugin) {
|
if (nextPlugin) {
|
||||||
nextPlugin.open().then(() => {
|
nextPlugin.open().then((): void => {
|
||||||
this.updateActiveKey(key);
|
this.updateActiveKey(key);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (activeKey === key) {
|
} else if (activeKey === key) {
|
||||||
if (prePlugin) {
|
if (prePlugin) {
|
||||||
prePlugin.close().then(() => {
|
prePlugin.close().then((): void => {
|
||||||
this.updateActiveKey('none');
|
this.updateActiveKey('none');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else if (prePlugin) {
|
||||||
// 先关后开
|
// 先关后开
|
||||||
if (prePlugin) {
|
prePlugin.close().then((): void => {
|
||||||
prePlugin.close().then(() => {
|
|
||||||
if (nextPlugin) {
|
if (nextPlugin) {
|
||||||
nextPlugin.open().then(() => {
|
nextPlugin.open().then((): void => {
|
||||||
this.updateActiveKey(key);
|
this.updateActiveKey(key);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
handleCollapseClick = (): void => {
|
// handleCollapseClick = (): void => {
|
||||||
const { activeKey } = this.state;
|
// const { activeKey } = this.state;
|
||||||
if (activeKey === 'none') {
|
// if (activeKey === 'none') {
|
||||||
const plugin = this.editor.plugins[this.cacheActiveKey];
|
// const plugin = this.editor.plugins[this.cacheActiveKey];
|
||||||
if (plugin) {
|
// if (plugin) {
|
||||||
plugin.open().then(() => {
|
// plugin.open().then(() => {
|
||||||
this.updateActiveKey(this.cacheActiveKey);
|
// this.updateActiveKey(this.cacheActiveKey);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
const plugin = this.editor.plugins[activeKey];
|
// const plugin = this.editor.plugins[activeKey];
|
||||||
if (plugin) {
|
// if (plugin) {
|
||||||
plugin.close().then(() => {
|
// plugin.close().then(() => {
|
||||||
this.updateActiveKey('none');
|
// this.updateActiveKey('none');
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
handlePluginClick = (item: PluginConfig): void => {
|
handlePluginClick = (item: PluginConfig): void => {
|
||||||
if (item.type === 'PanelIcon') {
|
if (item.type === 'PanelIcon') {
|
||||||
@ -107,17 +109,18 @@ export default class LeftAreaNav extends PureComponent<LeftAreaNavProps, LeftAre
|
|||||||
};
|
};
|
||||||
|
|
||||||
updateActiveKey = (key: string): void => {
|
updateActiveKey = (key: string): void => {
|
||||||
if (key === 'none') {
|
// if (key === 'none') {
|
||||||
this.cacheActiveKey = this.state.activeKey;
|
// this.cacheActiveKey = this.state.activeKey;
|
||||||
}
|
// }
|
||||||
this.editor.set('leftNav', key);
|
this.editor.set('leftNav', key);
|
||||||
this.setState({ activeKey: key });
|
this.setState({ activeKey: key });
|
||||||
this.editor.emit('leftPanel.show', key);
|
this.editor.emit('leftPanel.show', key);
|
||||||
};
|
};
|
||||||
|
|
||||||
renderPluginList = (list: Array<PluginConfig> = []): Array<React.ReactElement> => {
|
renderPluginList = (list: PluginConfig[] = []): React.ReactElement[] => {
|
||||||
const { activeKey } = this.state;
|
const { activeKey } = this.state;
|
||||||
return list.map((item, idx) => {
|
return list.map(
|
||||||
|
(item): React.ReactElement => {
|
||||||
const pluginStatus = this.editor.pluginStatus[item.pluginKey];
|
const pluginStatus = this.editor.pluginStatus[item.pluginKey];
|
||||||
return (
|
return (
|
||||||
<LeftPlugin
|
<LeftPlugin
|
||||||
@ -125,20 +128,23 @@ export default class LeftAreaNav extends PureComponent<LeftAreaNavProps, LeftAre
|
|||||||
config={item}
|
config={item}
|
||||||
editor={this.editor}
|
editor={this.editor}
|
||||||
pluginClass={this.editor.components[item.pluginKey]}
|
pluginClass={this.editor.components[item.pluginKey]}
|
||||||
onClick={() => this.handlePluginClick(item)}
|
onClick={(): void => this.handlePluginClick(item)}
|
||||||
active={activeKey === item.pluginKey}
|
active={activeKey === item.pluginKey}
|
||||||
{...pluginStatus}
|
{...pluginStatus}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render(): React.ReactNode {
|
||||||
const { activeKey } = this.state;
|
const topList: PluginConfig[] = [];
|
||||||
const topList: Array<PluginConfig> = [];
|
const bottomList: PluginConfig[] = [];
|
||||||
const bottomList: Array<PluginConfig> = [];
|
|
||||||
const visiblePluginList = this.areaManager.getVisiblePluginList();
|
const visiblePluginList = this.areaManager.getVisiblePluginList();
|
||||||
visiblePluginList.forEach(item => {
|
if (isEmpty(visiblePluginList)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
visiblePluginList.forEach((item): void => {
|
||||||
const align = item.props && item.props.align === 'bottom' ? 'bottom' : 'top';
|
const align = item.props && item.props.align === 'bottom' ? 'bottom' : 'top';
|
||||||
if (align === 'bottom') {
|
if (align === 'bottom') {
|
||||||
bottomList.push(item);
|
bottomList.push(item);
|
||||||
@ -151,7 +157,7 @@ export default class LeftAreaNav extends PureComponent<LeftAreaNavProps, LeftAre
|
|||||||
<div className="lowcode-left-area-nav">
|
<div className="lowcode-left-area-nav">
|
||||||
<div className="bottom-area">{this.renderPluginList(bottomList)}</div>
|
<div className="bottom-area">{this.renderPluginList(bottomList)}</div>
|
||||||
<div className="top-area">
|
<div className="top-area">
|
||||||
<LeftPlugin
|
{/* <LeftPlugin
|
||||||
editor={this.editor}
|
editor={this.editor}
|
||||||
key="collapse"
|
key="collapse"
|
||||||
config={{
|
config={{
|
||||||
@ -163,7 +169,7 @@ export default class LeftAreaNav extends PureComponent<LeftAreaNavProps, LeftAre
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onClick={this.handleCollapseClick}
|
onClick={this.handleCollapseClick}
|
||||||
/>
|
/> */}
|
||||||
{this.renderPluginList(topList)}
|
{this.renderPluginList(topList)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -16,6 +16,7 @@ export default class LeftAreaPanel extends PureComponent<LeftAreaPanelProps, Lef
|
|||||||
static displayName = 'LowcodeLeftAreaPanel';
|
static displayName = 'LowcodeLeftAreaPanel';
|
||||||
|
|
||||||
private editor: Editor;
|
private editor: Editor;
|
||||||
|
|
||||||
private areaManager: AreaManager;
|
private areaManager: AreaManager;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -28,11 +29,12 @@ export default class LeftAreaPanel extends PureComponent<LeftAreaPanelProps, Lef
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount(): void {
|
||||||
this.editor.on('skeleton.update', this.handleSkeletonUpdate);
|
this.editor.on('skeleton.update', this.handleSkeletonUpdate);
|
||||||
this.editor.on('leftPanel.show', this.handlePluginChange);
|
this.editor.on('leftPanel.show', this.handlePluginChange);
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
|
||||||
|
componentWillUnmount(): void {
|
||||||
this.editor.off('skeleton.update', this.handleSkeletonUpdate);
|
this.editor.off('skeleton.update', this.handleSkeletonUpdate);
|
||||||
this.editor.off('leftPanel.show', this.handlePluginChange);
|
this.editor.off('leftPanel.show', this.handlePluginChange);
|
||||||
}
|
}
|
||||||
@ -50,20 +52,26 @@ export default class LeftAreaPanel extends PureComponent<LeftAreaPanelProps, Lef
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render(): React.ReactNode {
|
||||||
const { activeKey } = this.state;
|
const { activeKey } = this.state;
|
||||||
const list = this.areaManager.getVisiblePluginList('PanelIcon');
|
const list = this.areaManager.getVisiblePluginList('PanelIcon');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{list.map((item, idx) => {
|
{list.map(
|
||||||
|
(item): React.ReactElement => {
|
||||||
const Comp = this.editor.components[item.pluginKey];
|
const Comp = this.editor.components[item.pluginKey];
|
||||||
return (
|
return (
|
||||||
<Panel key={item.pluginKey} visible={item.pluginKey === activeKey}>
|
<Panel
|
||||||
|
key={item.pluginKey}
|
||||||
|
visible={item.pluginKey === activeKey}
|
||||||
|
{...(item.props && item.props.panelProps)}
|
||||||
|
>
|
||||||
<Comp editor={this.editor} config={item} {...item.pluginProps} />
|
<Comp editor={this.editor} config={item} {...item.pluginProps} />
|
||||||
</Panel>
|
</Panel>
|
||||||
);
|
);
|
||||||
})}
|
}
|
||||||
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,24 @@
|
|||||||
.lowcode-right-area {
|
.lowcode-right-area {
|
||||||
width: 300px;
|
width: 262px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #ffffff;
|
background-color: $card-background;
|
||||||
border-left: 1px solid #e8ebee;
|
border-left: 2px solid $color-line1-1;
|
||||||
|
|
||||||
|
.right-panel {
|
||||||
|
overflow: auto;
|
||||||
|
// border-top: 2px solid $color-line1-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//tab定义
|
||||||
|
.right-tabs.next-tabs {
|
||||||
|
.next-tabs-nav {
|
||||||
|
width: 100%;
|
||||||
|
.next-tabs-tab-inner {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
.right-plugin-title {
|
.right-plugin-title {
|
||||||
|
text-align: center;
|
||||||
&.locked {
|
&.locked {
|
||||||
color: red !important;
|
color: red !important;
|
||||||
}
|
}
|
||||||
@ -14,39 +29,11 @@
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
color: $color-text1-1;
|
color: $color-text1-1;
|
||||||
}
|
}
|
||||||
}
|
.next-icon {
|
||||||
|
line-height: 15px;
|
||||||
//tab定义
|
margin-right: 2px;
|
||||||
.next-tabs-wrapped.right-tabs {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-top: -1px;
|
|
||||||
.next-tabs-bar {
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.next-tabs-nav {
|
|
||||||
display: block;
|
|
||||||
.next-tabs-tab {
|
|
||||||
&:first-child {
|
|
||||||
border-left: none;
|
|
||||||
}
|
|
||||||
font-size: 14px;
|
|
||||||
text-align: center;
|
|
||||||
border-right: none !important;
|
|
||||||
margin-right: 0 !important;
|
|
||||||
width: 25%;
|
|
||||||
&.active {
|
|
||||||
background: none;
|
|
||||||
border-bottom-color: #f7f7f7 !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.next-tabs-content {
|
|
||||||
flex: 1;
|
|
||||||
.next-tabs-tabpane.active {
|
|
||||||
height: 100%;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import './index.scss';
|
|||||||
import Editor from '../../../framework/editor';
|
import Editor from '../../../framework/editor';
|
||||||
import AreaManager from '../../../framework/areaManager';
|
import AreaManager from '../../../framework/areaManager';
|
||||||
import { PluginConfig } from '../../../framework/definitions';
|
import { PluginConfig } from '../../../framework/definitions';
|
||||||
|
import { isEmpty } from '../../../framework/utils';
|
||||||
|
|
||||||
export interface RightAreaProps {
|
export interface RightAreaProps {
|
||||||
editor: Editor;
|
editor: Editor;
|
||||||
@ -17,6 +18,7 @@ export default class RightArea extends PureComponent<RightAreaProps, RightAreaSt
|
|||||||
static displayName = 'LowcodeRightArea';
|
static displayName = 'LowcodeRightArea';
|
||||||
|
|
||||||
private editor: Editor;
|
private editor: Editor;
|
||||||
|
|
||||||
private areaManager: AreaManager;
|
private areaManager: AreaManager;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -28,14 +30,15 @@ export default class RightArea extends PureComponent<RightAreaProps, RightAreaSt
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount(): void {
|
||||||
this.editor.on('skeleton.update', this.handleSkeletonUpdate);
|
this.editor.on('skeleton.update', this.handleSkeletonUpdate);
|
||||||
this.editor.on('rightNav.change', this.handlePluginChange);
|
this.editor.on('rightNav.change', this.handlePluginChange);
|
||||||
const visiblePluginList = this.areaManager.getVisiblePluginList();
|
const visiblePluginList = this.areaManager.getVisiblePluginList('TabPanel');
|
||||||
const defaultKey = (visiblePluginList[0] && visiblePluginList[0].pluginKey) || 'componentAttr';
|
const defaultKey = (visiblePluginList[0] && visiblePluginList[0].pluginKey) || 'componentAttr';
|
||||||
this.handlePluginChange(defaultKey, true);
|
this.handlePluginChange(defaultKey, true);
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
|
||||||
|
componentWillUnmount(): void {
|
||||||
this.editor.off('skeleton.update', this.handleSkeletonUpdate);
|
this.editor.off('skeleton.update', this.handleSkeletonUpdate);
|
||||||
this.editor.off('rightNav.change', this.handlePluginChange);
|
this.editor.off('rightNav.change', this.handlePluginChange);
|
||||||
}
|
}
|
||||||
@ -50,12 +53,12 @@ export default class RightArea extends PureComponent<RightAreaProps, RightAreaSt
|
|||||||
} else {
|
} else {
|
||||||
const currentPlugin = this.editor.plugins[activeKey];
|
const currentPlugin = this.editor.plugins[activeKey];
|
||||||
if (currentPlugin) {
|
if (currentPlugin) {
|
||||||
currentPlugin.close().then(() => {
|
currentPlugin.close().then((): void => {
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
activeKey: ''
|
activeKey: ''
|
||||||
},
|
},
|
||||||
() => {
|
(): void => {
|
||||||
const visiblePluginList = this.areaManager.getVisiblePluginList();
|
const visiblePluginList = this.areaManager.getVisiblePluginList();
|
||||||
const firstPlugin = visiblePluginList && visiblePluginList[0];
|
const firstPlugin = visiblePluginList && visiblePluginList[0];
|
||||||
if (firstPlugin) {
|
if (firstPlugin) {
|
||||||
@ -72,12 +75,12 @@ export default class RightArea extends PureComponent<RightAreaProps, RightAreaSt
|
|||||||
handlePluginChange = (key: string, isinit?: boolean): void => {
|
handlePluginChange = (key: string, isinit?: boolean): void => {
|
||||||
const activeKey = this.state.activeKey;
|
const activeKey = this.state.activeKey;
|
||||||
const plugins = this.editor.plugins || {};
|
const plugins = this.editor.plugins || {};
|
||||||
const openPlugin = () => {
|
const openPlugin = (): void => {
|
||||||
if (!plugins[key]) {
|
if (!plugins[key]) {
|
||||||
console.error(`plugin ${key} has not regist in the editor`);
|
console.error(`plugin ${key} has not regist in the editor`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
plugins[key].open().then(() => {
|
plugins[key].open().then((): void => {
|
||||||
this.editor.set('rightNav', key);
|
this.editor.set('rightNav', key);
|
||||||
this.setState({
|
this.setState({
|
||||||
activeKey: key
|
activeKey: key
|
||||||
@ -86,7 +89,7 @@ export default class RightArea extends PureComponent<RightAreaProps, RightAreaSt
|
|||||||
};
|
};
|
||||||
if (key === activeKey && !isinit) return;
|
if (key === activeKey && !isinit) return;
|
||||||
if (activeKey && plugins[activeKey]) {
|
if (activeKey && plugins[activeKey]) {
|
||||||
plugins[activeKey].close().then(() => {
|
plugins[activeKey].close().then((): void => {
|
||||||
openPlugin();
|
openPlugin();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -102,21 +105,11 @@ export default class RightArea extends PureComponent<RightAreaProps, RightAreaSt
|
|||||||
|
|
||||||
const renderTitle = (): React.ReactElement => (
|
const renderTitle = (): React.ReactElement => (
|
||||||
<div
|
<div
|
||||||
className={`right-addon-title ${active ? 'active' : ''} ${locked ? 'locked' : ''} ${
|
className={`right-plugin-title ${active ? 'active' : ''} ${locked ? 'locked' : ''} ${
|
||||||
disabled ? 'disabled' : ''
|
disabled ? 'disabled' : ''
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{!!icon && (
|
{!!icon && <Icon size="xs" type={icon} />}
|
||||||
<Icon
|
|
||||||
type={icon}
|
|
||||||
style={{
|
|
||||||
marginRight: 2,
|
|
||||||
fontSize: '14px',
|
|
||||||
lineHeight: '14px',
|
|
||||||
verticalAlign: 'top'
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{title}
|
{title}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -126,45 +119,68 @@ export default class RightArea extends PureComponent<RightAreaProps, RightAreaSt
|
|||||||
return renderTitle();
|
return renderTitle();
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
renderTabPanels = (list: PluginConfig[], height: string): React.ReactNode => {
|
||||||
const visiblePluginList = this.areaManager.getVisiblePluginList();
|
if (isEmpty(list)) {
|
||||||
if (visiblePluginList.length < 2) {
|
return null;
|
||||||
const pane = visiblePluginList[0];
|
|
||||||
if (!pane) {
|
|
||||||
return <div className="lowcode-right-area"></div>;
|
|
||||||
}
|
|
||||||
const Comp = this.editor.components[pane.pluginKey];
|
|
||||||
return (
|
|
||||||
<div className="lowcode-right-area">
|
|
||||||
<Comp editor={this.editor} config={pane} {...pane.pluginProps} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="lowcode-right-area">
|
|
||||||
<Tab
|
<Tab
|
||||||
shape="wrapped"
|
|
||||||
className="right-tabs"
|
className="right-tabs"
|
||||||
style={{
|
style={{
|
||||||
height: '100%'
|
height
|
||||||
}}
|
}}
|
||||||
activeKey={this.state.activeKey}
|
activeKey={this.state.activeKey}
|
||||||
lazyLoad={false}
|
lazyLoad={false}
|
||||||
onChange={this.handlePluginChange}
|
onChange={this.handlePluginChange}
|
||||||
>
|
>
|
||||||
{visiblePluginList.map((item, idx) => {
|
{list.map(
|
||||||
|
(item): React.ReactElement => {
|
||||||
const Comp = this.editor.components[item.pluginKey];
|
const Comp = this.editor.components[item.pluginKey];
|
||||||
return (
|
return (
|
||||||
<Tab.Item
|
<Tab.Item
|
||||||
key={item.pluginKey}
|
key={item.pluginKey}
|
||||||
title={this.renderTabTitle(item)}
|
title={this.renderTabTitle(item)}
|
||||||
disabled={this.editor.pluginStatus[item.pluginKey].disabled}
|
disabled={this.editor.pluginStatus[item.pluginKey].disabled}
|
||||||
|
style={{
|
||||||
|
width: `${100 / list.length}%`
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Comp editor={this.editor} config={item} {...item.pluginProps} />
|
<Comp editor={this.editor} config={item} {...item.pluginProps} />
|
||||||
</Tab.Item>
|
</Tab.Item>
|
||||||
);
|
);
|
||||||
})}
|
}
|
||||||
|
)}
|
||||||
</Tab>
|
</Tab>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
renderPanels = (list: PluginConfig[], height: string): React.ReactNode => {
|
||||||
|
return list.map(
|
||||||
|
(item): React.ReactElement => {
|
||||||
|
const Comp = this.editor.components[item.pluginKey];
|
||||||
|
return (
|
||||||
|
<div className="right-panel" style={{ height }} key={item.pluginKey}>
|
||||||
|
<Comp editor={this.editor} config={item} {...item.pluginProps} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
render(): React.ReactNode {
|
||||||
|
const tabList = this.areaManager.getVisiblePluginList('TabPanel');
|
||||||
|
const panelList = this.areaManager.getVisiblePluginList('Panel');
|
||||||
|
if (isEmpty(panelList) && isEmpty(tabList)) {
|
||||||
|
return null;
|
||||||
|
} else if (tabList.length === 1) {
|
||||||
|
panelList.unshift(tabList[0]);
|
||||||
|
tabList.splice(0, 1);
|
||||||
|
}
|
||||||
|
const height = `${Math.floor(100 / (panelList.length + (tabList.length > 0 ? 1 : 0)))}%`;
|
||||||
|
return (
|
||||||
|
<div className="lowcode-right-area">
|
||||||
|
{this.renderTabPanels(tabList, height)}
|
||||||
|
{this.renderPanels(panelList, height)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,24 +3,28 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 48px;
|
height: 50px;
|
||||||
background-color: #ffffff;
|
background-color: $card-background;
|
||||||
border-bottom: 1px solid #e8ebee;
|
border-bottom: 2px solid $color-line1-1;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
.divider {
|
.divider {
|
||||||
max-width: 0;
|
max-width: 0;
|
||||||
margin: 8px 12px;
|
margin: 12px 16px;
|
||||||
height: 30px;
|
height: 24px;
|
||||||
border-right: 1px solid rgba(191, 191, 191, 0.3);
|
border-right: 1px solid $color-line1-2;
|
||||||
}
|
}
|
||||||
.next-col {
|
.next-col {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
.left-area {
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
.right-area {
|
.right-area {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 12px;
|
right: 12px;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
padding: 0 16px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: #ffffff;
|
background: $card-background;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ export default class TopArea extends PureComponent<TopAreaProps> {
|
|||||||
static displayName = 'LowcodeTopArea';
|
static displayName = 'LowcodeTopArea';
|
||||||
|
|
||||||
private areaManager: AreaManager;
|
private areaManager: AreaManager;
|
||||||
|
|
||||||
private editor: Editor;
|
private editor: Editor;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -24,10 +25,11 @@ export default class TopArea extends PureComponent<TopAreaProps> {
|
|||||||
this.areaManager = new AreaManager(props.editor, 'topArea');
|
this.areaManager = new AreaManager(props.editor, 'topArea');
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount(): void {
|
||||||
this.editor.on('skeleton.update', this.handleSkeletonUpdate);
|
this.editor.on('skeleton.update', this.handleSkeletonUpdate);
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
|
||||||
|
componentWillUnmount(): void {
|
||||||
this.editor.off('skeleton.update', this.handleSkeletonUpdate);
|
this.editor.off('skeleton.update', this.handleSkeletonUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,15 +40,16 @@ export default class TopArea extends PureComponent<TopAreaProps> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
renderPluginList = (list: Array<PluginConfig> = []): Array<React.ReactElement> => {
|
renderPluginList = (list: PluginConfig[] = []): React.ReactElement[] => {
|
||||||
return list.map((item, idx) => {
|
return list.map(
|
||||||
|
(item, idx): React.ReactElement => {
|
||||||
const isDivider = item.type === 'Divider';
|
const isDivider = item.type === 'Divider';
|
||||||
return (
|
return (
|
||||||
<Col
|
<Col
|
||||||
className={isDivider ? 'divider' : ''}
|
className={isDivider ? 'divider' : ''}
|
||||||
key={isDivider ? idx : item.pluginKey}
|
key={isDivider ? idx : item.pluginKey}
|
||||||
style={{
|
style={{
|
||||||
width: (item.props && item.props.width) || 40,
|
width: (item.props && item.props.width) || 36,
|
||||||
flex: 'none'
|
flex: 'none'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -55,14 +58,15 @@ export default class TopArea extends PureComponent<TopAreaProps> {
|
|||||||
)}
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render(): React.ReactNode {
|
||||||
const leftList: Array<PluginConfig> = [];
|
const leftList: PluginConfig[] = [];
|
||||||
const rightList: Array<PluginConfig> = [];
|
const rightList: PluginConfig[] = [];
|
||||||
const visiblePluginList = this.areaManager.getVisiblePluginList();
|
const visiblePluginList = this.areaManager.getVisiblePluginList();
|
||||||
visiblePluginList.forEach(item => {
|
visiblePluginList.forEach((item): void => {
|
||||||
const align = item.props && item.props.align === 'right' ? 'right' : 'left';
|
const align = item.props && item.props.align === 'right' ? 'right' : 'left';
|
||||||
// 分隔符不允许相邻
|
// 分隔符不允许相邻
|
||||||
if (item.type === 'Divider') {
|
if (item.type === 'Divider') {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user