mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-15 18:58:11 +00:00
polyfill panes
This commit is contained in:
parent
33750b7fef
commit
89196c536c
@ -46,12 +46,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&-device-default {
|
&-device-default {
|
||||||
top: 15px;
|
top: 16px;
|
||||||
right: 15px;
|
right: 16px;
|
||||||
bottom: 15px;
|
bottom: 16px;
|
||||||
left: 15px;
|
left: 16px;
|
||||||
width: auto;
|
width: auto;
|
||||||
box-shadow: 0 2px 10px 0 rgba(31,56,88,.15);
|
box-shadow: 0 1px 4px 0 rgba(31, 50, 88, 0.125);
|
||||||
}
|
}
|
||||||
|
|
||||||
&-content {
|
&-content {
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import './designer.less';
|
|||||||
import clipboard from './clipboard';
|
import clipboard from './clipboard';
|
||||||
|
|
||||||
export class DesignerView extends Component<DesignerProps & {
|
export class DesignerView extends Component<DesignerProps & {
|
||||||
designer: Designer;
|
designer?: Designer;
|
||||||
}> {
|
}> {
|
||||||
readonly designer: Designer;
|
readonly designer: Designer;
|
||||||
|
|
||||||
|
|||||||
@ -7,18 +7,28 @@ export default class AreaManager {
|
|||||||
|
|
||||||
private config: PluginConfig[];
|
private config: PluginConfig[];
|
||||||
|
|
||||||
private editor: Editor;
|
constructor(private editor: Editor, private name: string) {
|
||||||
|
this.config = (editor && editor.config && editor.config.plugins && editor.config.plugins[name]) || [];
|
||||||
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.pluginStatus = clone(editor.pluginStatus);
|
this.pluginStatus = clone(editor.pluginStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
public isPluginStatusUpdate(pluginType?: string, notUpdateStatus?: boolean): boolean {
|
setVisible(flag: boolean) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
isEnable() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
isVisible() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmpty() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
isPluginStatusUpdate(pluginType?: string, notUpdateStatus?: boolean): boolean {
|
||||||
const { pluginStatus } = this.editor;
|
const { pluginStatus } = this.editor;
|
||||||
const list = pluginType ? this.config.filter((item): boolean => item.type === pluginType) : this.config;
|
const list = pluginType ? this.config.filter((item): boolean => item.type === pluginType) : this.config;
|
||||||
|
|
||||||
@ -31,33 +41,33 @@ export default class AreaManager {
|
|||||||
return isUpdate;
|
return isUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getVisiblePluginList(pluginType?: string): PluginConfig[] {
|
getVisiblePluginList(pluginType?: string): PluginConfig[] {
|
||||||
const res = this.config.filter((item): boolean => {
|
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): boolean => item.type === pluginType) : res;
|
return pluginType ? res.filter((item): boolean => item.type === pluginType) : res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPlugin(pluginKey: string): HOCPlugin | void {
|
getPlugin(pluginKey: string): HOCPlugin | void {
|
||||||
if (pluginKey) {
|
if (pluginKey) {
|
||||||
return this.editor && this.editor.plugins && this.editor.plugins[pluginKey];
|
return this.editor && this.editor.plugins && this.editor.plugins[pluginKey];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPluginConfig(pluginKey?: string): PluginConfig[] | PluginConfig | undefined {
|
getPluginConfig(pluginKey?: string): PluginConfig[] | PluginConfig | undefined {
|
||||||
if (pluginKey) {
|
if (pluginKey) {
|
||||||
return this.config.find(item => item.pluginKey === pluginKey);
|
return this.config.find(item => item.pluginKey === pluginKey);
|
||||||
}
|
}
|
||||||
return this.config;
|
return this.config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPluginClass(pluginKey: string): PluginClass | void {
|
getPluginClass(pluginKey: string): PluginClass | void {
|
||||||
if (pluginKey) {
|
if (pluginKey) {
|
||||||
return this.editor && this.editor.components && this.editor.components[pluginKey];
|
return this.editor && this.editor.components && this.editor.components[pluginKey];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPluginStatus(pluginKey: string): PluginStatus | void {
|
getPluginStatus(pluginKey: string): PluginStatus | void {
|
||||||
if (pluginKey) {
|
if (pluginKey) {
|
||||||
return this.editor && this.editor.pluginStatus && this.editor.pluginStatus[pluginKey];
|
return this.editor && this.editor.pluginStatus && this.editor.pluginStatus[pluginKey];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -91,7 +91,7 @@ export default class Editor extends EventEmitter {
|
|||||||
|
|
||||||
private hooksFuncs: HooksFuncs;
|
private hooksFuncs: HooksFuncs;
|
||||||
|
|
||||||
constructor(config: EditorConfig, components: PluginClassSet, utils?: Utils) {
|
constructor(config: EditorConfig = {}, components: PluginClassSet = {}, utils?: Utils) {
|
||||||
super();
|
super();
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.components = {};
|
this.components = {};
|
||||||
|
|||||||
@ -1,152 +1,12 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { Editor, PluginConfig } from '@ali/lowcode-editor-core';
|
import { Editor } from '@ali/lowcode-editor-core';
|
||||||
import { DesignerView, Designer } from '@ali/lowcode-designer';
|
import { DesignerView, Designer } from '@ali/lowcode-designer';
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
|
||||||
export interface PluginProps {
|
export interface PluginProps {
|
||||||
editor: Editor;
|
editor: Editor;
|
||||||
config: PluginConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SCHEMA = {
|
|
||||||
version: '1.0',
|
|
||||||
componentsMap: [],
|
|
||||||
componentsTree: [
|
|
||||||
{
|
|
||||||
componentName: 'Page',
|
|
||||||
fileName: 'test',
|
|
||||||
dataSource: {
|
|
||||||
list: [],
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
text: 'outter',
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
ref: 'outterView',
|
|
||||||
autoLoading: true,
|
|
||||||
style: {
|
|
||||||
padding: 20,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'Form',
|
|
||||||
props: {
|
|
||||||
labelCol: 3,
|
|
||||||
style: {},
|
|
||||||
ref: 'testForm',
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'Form.Item',
|
|
||||||
props: {
|
|
||||||
label: '姓名:',
|
|
||||||
name: 'name',
|
|
||||||
initValue: '李雷',
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'Input',
|
|
||||||
props: {
|
|
||||||
placeholder: '请输入',
|
|
||||||
size: 'medium',
|
|
||||||
style: {
|
|
||||||
width: 320,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Form.Item',
|
|
||||||
props: {
|
|
||||||
label: '年龄:',
|
|
||||||
name: 'age',
|
|
||||||
initValue: '22',
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'NumberPicker',
|
|
||||||
props: {
|
|
||||||
size: 'medium',
|
|
||||||
type: 'normal',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Form.Item',
|
|
||||||
props: {
|
|
||||||
label: '职业:',
|
|
||||||
name: 'profession',
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'Select',
|
|
||||||
props: {
|
|
||||||
dataSource: [
|
|
||||||
{
|
|
||||||
label: '教师',
|
|
||||||
value: 't',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '医生',
|
|
||||||
value: 'd',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '歌手',
|
|
||||||
value: 's',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Div',
|
|
||||||
props: {
|
|
||||||
style: {
|
|
||||||
textAlign: 'center',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'Button.Group',
|
|
||||||
props: {},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'Button',
|
|
||||||
props: {
|
|
||||||
type: 'primary',
|
|
||||||
style: {
|
|
||||||
margin: '0 5px 0 5px',
|
|
||||||
},
|
|
||||||
htmlType: 'submit',
|
|
||||||
},
|
|
||||||
children: '提交',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Button',
|
|
||||||
props: {
|
|
||||||
type: 'normal',
|
|
||||||
style: {
|
|
||||||
margin: '0 5px 0 5px',
|
|
||||||
},
|
|
||||||
htmlType: 'reset',
|
|
||||||
},
|
|
||||||
children: '重置',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
interface DesignerPluginState {
|
interface DesignerPluginState {
|
||||||
componentMetadatas?: any[] | null;
|
componentMetadatas?: any[] | null;
|
||||||
library?: any[] | null;
|
library?: any[] | null;
|
||||||
|
|||||||
@ -168,7 +168,6 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// editor.once('outlinePane.visible', setup);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,7 @@
|
|||||||
"@ali/lowcode-plugin-zh-en": "^0.8.6",
|
"@ali/lowcode-plugin-zh-en": "^0.8.6",
|
||||||
"@ali/lowcode-setters": "^0.8.6",
|
"@ali/lowcode-setters": "^0.8.6",
|
||||||
"@alifd/next": "^1.19.12",
|
"@alifd/next": "^1.19.12",
|
||||||
|
"@ali/ve-less-variables": "2.0.3",
|
||||||
"@alife/theme-lowcode-dark": "^0.1.0",
|
"@alife/theme-lowcode-dark": "^0.1.0",
|
||||||
"@alife/theme-lowcode-light": "^0.1.0",
|
"@alife/theme-lowcode-light": "^0.1.0",
|
||||||
"react": "^16.8.1",
|
"react": "^16.8.1",
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { init } from "./vision";
|
import { init } from './vision'; // VisualEngine
|
||||||
import editor from './editor';
|
import { editor } from './editor';
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
|
|||||||
@ -1,68 +1,44 @@
|
|||||||
import Editor from '@ali/lowcode-editor-core';
|
import Editor from '@ali/lowcode-editor-core';
|
||||||
import outlinePane from '@ali/lowcode-plugin-outline-pane';
|
import OutlinePane from '@ali/lowcode-plugin-outline-pane';
|
||||||
import settingsPane from '@ali/lowcode-plugin-settings-pane';
|
import SettingsPane from '@ali/lowcode-plugin-settings-pane';
|
||||||
import designer from '@ali/lowcode-plugin-designer';
|
import Designer from '@ali/lowcode-plugin-designer';
|
||||||
import { registerSetters } from '@ali/lowcode-setters';
|
import { registerSetters } from '@ali/lowcode-setters';
|
||||||
|
import { Skeleton } from './skeleton/skeleton';
|
||||||
|
|
||||||
registerSetters();
|
registerSetters();
|
||||||
|
|
||||||
export default new Editor(
|
export const editor = new Editor();
|
||||||
{
|
|
||||||
plugins: {
|
export const skeleton = new Skeleton(editor);
|
||||||
topArea: [],
|
|
||||||
leftArea: [
|
skeleton.mainArea.add({
|
||||||
{
|
name: 'designer',
|
||||||
pluginKey: 'outlinePane',
|
type: 'Widget',
|
||||||
type: 'PanelIcon',
|
content: Designer,
|
||||||
|
});
|
||||||
|
skeleton.rightArea.add({
|
||||||
|
name: 'settingsPane',
|
||||||
|
type: 'Panel',
|
||||||
|
content: SettingsPane,
|
||||||
|
});
|
||||||
|
skeleton.leftArea.add({
|
||||||
|
name: 'outlinePane',
|
||||||
|
type: 'PanelDock',
|
||||||
props: {
|
props: {
|
||||||
align: 'top',
|
align: 'top',
|
||||||
icon: 'shuxingkongjian',
|
icon: 'shuxingkongjian',
|
||||||
title: '大纲树',
|
description: '大纲树',
|
||||||
},
|
},
|
||||||
config: {
|
content: OutlinePane,
|
||||||
package: '@ali/lowcode-plugin-outline-pane',
|
panelProps: {
|
||||||
version: '^0.8.0',
|
area: 'leftFloatArea'
|
||||||
},
|
}
|
||||||
pluginProps: {},
|
});
|
||||||
},
|
|
||||||
],
|
|
||||||
rightArea: [
|
|
||||||
{
|
|
||||||
pluginKey: 'settingsPane',
|
|
||||||
type: 'Panel',
|
|
||||||
props: {},
|
|
||||||
config: {
|
|
||||||
package: '@ali/lowcode-plugin-settings-pane',
|
|
||||||
version: '^0.8.0',
|
|
||||||
},
|
|
||||||
pluginProps: {},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
centerArea: [
|
|
||||||
{
|
|
||||||
pluginKey: 'designer',
|
|
||||||
type: '',
|
|
||||||
props: {},
|
|
||||||
config: {
|
|
||||||
package: '@ali/lowcode-plugin-designer',
|
|
||||||
version: '^0.8.0',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
outlinePane,
|
|
||||||
settingsPane,
|
|
||||||
designer,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// editor-core
|
// editor-core
|
||||||
// 1. di 实现
|
// 1. di 实现
|
||||||
// 2. skeleton 区域管理
|
// 2. general bus: pub/sub
|
||||||
// 3. general bus: pub/sub
|
|
||||||
// editor-skeleton/workbench 视图实现
|
// editor-skeleton/workbench 视图实现
|
||||||
|
// 1. skeleton 区域划分 panes
|
||||||
// provide fixed left pane
|
// provide fixed left pane
|
||||||
// provide float left pane
|
// provide float left pane
|
||||||
|
|||||||
148
packages/vision-polyfill/src/flags.ts
Normal file
148
packages/vision-polyfill/src/flags.ts
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import domReady = require('domready');
|
||||||
|
import * as EventEmitter from 'events';
|
||||||
|
|
||||||
|
const Shells = ['iphone6'];
|
||||||
|
|
||||||
|
export class Flags {
|
||||||
|
|
||||||
|
public emitter: EventEmitter;
|
||||||
|
public flags: string[];
|
||||||
|
public ready: boolean;
|
||||||
|
public lastFlags: string[];
|
||||||
|
public lastShell: string;
|
||||||
|
|
||||||
|
private lastSimulatorDevice: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.emitter = new EventEmitter();
|
||||||
|
this.flags = ['design-mode'];
|
||||||
|
|
||||||
|
domReady(() => {
|
||||||
|
this.ready = true;
|
||||||
|
this.applyFlags();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public setDragMode(flag: boolean) {
|
||||||
|
if (flag) {
|
||||||
|
this.add('drag-mode');
|
||||||
|
} else {
|
||||||
|
this.remove('drag-mode');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setPreviewMode(flag: boolean) {
|
||||||
|
if (flag) {
|
||||||
|
this.add('preview-mode');
|
||||||
|
this.remove('design-mode');
|
||||||
|
} else {
|
||||||
|
this.add('design-mode');
|
||||||
|
this.remove('preview-mode');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setWithShell(shell: string) {
|
||||||
|
if (shell === this.lastShell) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.lastShell) {
|
||||||
|
this.remove(`with-${this.lastShell}shell`);
|
||||||
|
}
|
||||||
|
if (shell) {
|
||||||
|
if (Shells.indexOf(shell) < 0) {
|
||||||
|
shell = Shells[0];
|
||||||
|
}
|
||||||
|
this.add(`with-${shell}shell`);
|
||||||
|
this.lastShell = shell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setSimulator(device: string) {
|
||||||
|
if (this.lastSimulatorDevice) {
|
||||||
|
this.remove(`simulator-${this.lastSimulatorDevice}`);
|
||||||
|
}
|
||||||
|
if (device !== '' && device !== 'pc') {
|
||||||
|
this.add(`simulator-${device}`);
|
||||||
|
}
|
||||||
|
this.lastSimulatorDevice = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setHideSlate(flag: boolean) {
|
||||||
|
if (this.has('slate-fixed')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (flag) {
|
||||||
|
this.add('hide-slate');
|
||||||
|
} else {
|
||||||
|
this.remove('hide-slate');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setSlateFixedMode(flag: boolean) {
|
||||||
|
if (flag) {
|
||||||
|
this.remove('hide-slate');
|
||||||
|
this.add('slate-fixed');
|
||||||
|
} else {
|
||||||
|
this.remove('slate-fixed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setSlateFullMode(flag: boolean) {
|
||||||
|
if (flag) {
|
||||||
|
this.add('slate-full-screen');
|
||||||
|
} else {
|
||||||
|
this.remove('slate-full-screen');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFlags() {
|
||||||
|
return this.flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public applyFlags(modifiedFlag?: string) {
|
||||||
|
if (!this.ready) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const doe = document.documentElement;
|
||||||
|
if (this.lastFlags) {
|
||||||
|
this.lastFlags.filter((flag: string) => this.flags.indexOf(flag) < 0).forEach((flag) => {
|
||||||
|
doe.classList.remove(`engine-${flag}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.flags.forEach((flag) => {
|
||||||
|
doe.classList.add(`engine-${flag}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.lastFlags = this.flags.slice(0);
|
||||||
|
this.emitter.emit('flagschange', this.flags, modifiedFlag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public has(flag: string) {
|
||||||
|
return this.flags.indexOf(flag) > -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public add(flag: string) {
|
||||||
|
if (!this.has(flag)) {
|
||||||
|
this.flags.push(flag);
|
||||||
|
this.applyFlags(flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public remove(flag: string) {
|
||||||
|
const i = this.flags.indexOf(flag);
|
||||||
|
if (i > -1) {
|
||||||
|
this.flags.splice(i, 1);
|
||||||
|
this.applyFlags(flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public onFlagsChange(func: () => any) {
|
||||||
|
this.emitter.on('flagschange', func);
|
||||||
|
return () => {
|
||||||
|
this.emitter.removeListener('flagschange', func);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new Flags();
|
||||||
206
packages/vision-polyfill/src/panes.ts
Normal file
206
packages/vision-polyfill/src/panes.ts
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
import { skeleton } from './editor';
|
||||||
|
import { ReactElement } from 'react';
|
||||||
|
import { IWidgetBaseConfig } from './skeleton/types';
|
||||||
|
|
||||||
|
export interface IContentItemConfig {
|
||||||
|
title: string;
|
||||||
|
content: JSX.Element;
|
||||||
|
tip?: {
|
||||||
|
content: string;
|
||||||
|
url?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OldPaneConfig {
|
||||||
|
// 'dock' | 'action' | 'tab' | 'widget' | 'stage'
|
||||||
|
type?: string; // where
|
||||||
|
|
||||||
|
id?: string;
|
||||||
|
name: string;
|
||||||
|
title?: string;
|
||||||
|
content?: any;
|
||||||
|
|
||||||
|
place?: string; // align: left|right|top|center|bottom
|
||||||
|
description?: string; // tip?
|
||||||
|
tip?:
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
// as help tip
|
||||||
|
url?: string;
|
||||||
|
content?: string | JSX.Element;
|
||||||
|
}; // help
|
||||||
|
|
||||||
|
init?: () => any;
|
||||||
|
destroy?: () => any;
|
||||||
|
props?: any;
|
||||||
|
|
||||||
|
contents?: IContentItemConfig[];
|
||||||
|
hideTitleBar?: boolean;
|
||||||
|
width?: number;
|
||||||
|
maxWidth?: number;
|
||||||
|
height?: number;
|
||||||
|
maxHeight?: number;
|
||||||
|
position?: string | string[]; // todo
|
||||||
|
menu?: JSX.Element; // as title
|
||||||
|
index?: number; // todo
|
||||||
|
isAction?: boolean; // as normal dock
|
||||||
|
fullScreen?: boolean; // todo
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgradeConfig(config: OldPaneConfig): IWidgetBaseConfig & { area: string } {
|
||||||
|
const { type, id, name, title, content, place, description, init, destroy, props, index } = config;
|
||||||
|
|
||||||
|
const newConfig: any = {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
content,
|
||||||
|
props: {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
align: place,
|
||||||
|
onInit: init,
|
||||||
|
onDestroy: destroy,
|
||||||
|
},
|
||||||
|
contentProps: props,
|
||||||
|
index,
|
||||||
|
};
|
||||||
|
if (type === 'dock') {
|
||||||
|
newConfig.type = 'PanelDock';
|
||||||
|
newConfig.area = 'left';
|
||||||
|
const { contents, hideTitleBar, tip, width, maxWidth, height, maxHeight, position, menu, isAction } = config;
|
||||||
|
if (menu) {
|
||||||
|
newConfig.props.title = menu;
|
||||||
|
}
|
||||||
|
if (!isAction) {
|
||||||
|
newConfig.panelProps = {
|
||||||
|
hideTitleBar,
|
||||||
|
help: tip,
|
||||||
|
width,
|
||||||
|
maxWidth,
|
||||||
|
height,
|
||||||
|
maxHeight,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (contents && Array.isArray(contents)) {
|
||||||
|
newConfig.content = contents.map(({ title, content, tip }) => {
|
||||||
|
return {
|
||||||
|
type: "Panel",
|
||||||
|
content,
|
||||||
|
props: {
|
||||||
|
title,
|
||||||
|
help: tip,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (type === 'action') {
|
||||||
|
newConfig.area = 'top';
|
||||||
|
newConfig.type = 'Dock';
|
||||||
|
} else if (type === 'tab') {
|
||||||
|
newConfig.area = 'right';
|
||||||
|
newConfig.type = 'Panel';
|
||||||
|
} else if (type === 'stage') {
|
||||||
|
newConfig.area = 'stages';
|
||||||
|
newConfig.type = 'Widget';
|
||||||
|
} else {
|
||||||
|
newConfig.area = 'main';
|
||||||
|
newConfig.type = 'Widget';
|
||||||
|
}
|
||||||
|
|
||||||
|
return newConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(config: (() => OldPaneConfig) | OldPaneConfig, extraConfig?: any) {
|
||||||
|
if (typeof config === 'function') {
|
||||||
|
config = config.call(null);
|
||||||
|
}
|
||||||
|
if (!config || !config.type) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (extraConfig) {
|
||||||
|
config = { ...config, ...extraConfig };
|
||||||
|
}
|
||||||
|
|
||||||
|
skeleton.add(upgradeConfig(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionPane = Object.assign(skeleton.topArea, {
|
||||||
|
/**
|
||||||
|
* compatible *VE.actionPane.getActions*
|
||||||
|
*/
|
||||||
|
getActions(): any {
|
||||||
|
return skeleton.topArea.container.items;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* compatible *VE.actionPane.activeDock*
|
||||||
|
*/
|
||||||
|
setActions() {
|
||||||
|
// empty
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const dockPane = Object.assign(skeleton.leftArea, {
|
||||||
|
/**
|
||||||
|
* compatible *VE.dockPane.activeDock*
|
||||||
|
*/
|
||||||
|
activeDock(item: any) {
|
||||||
|
const name = item.name || item;
|
||||||
|
skeleton.getPanel(name)?.active();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compatible *VE.dockPane.onDockShow*
|
||||||
|
*/
|
||||||
|
onDockShow() {},
|
||||||
|
/**
|
||||||
|
* compatible *VE.dockPane.onDockHide*
|
||||||
|
*/
|
||||||
|
onDockHide() {},
|
||||||
|
/**
|
||||||
|
* compatible *VE.dockPane.setFixed*
|
||||||
|
*/
|
||||||
|
setFixed(flag: boolean) {
|
||||||
|
// todo:
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tabPane = Object.assign(skeleton.rightArea, {
|
||||||
|
setFloat(flag: boolean) {
|
||||||
|
// todo:
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const toolbar = Object.assign(skeleton.toolbar, {
|
||||||
|
setContents(contents: ReactElement) {
|
||||||
|
// todo:
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const widgets = skeleton.mainArea;
|
||||||
|
|
||||||
|
const stages = Object.assign(skeleton.stages, {
|
||||||
|
getStage(name: string) {
|
||||||
|
skeleton.stages.container.get(name);
|
||||||
|
},
|
||||||
|
|
||||||
|
createStage(config: any) {
|
||||||
|
config = upgradeConfig(config);
|
||||||
|
if (config.id) {
|
||||||
|
config.name = config.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stage = skeleton.stages.add(config);
|
||||||
|
return stage.getName();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
ActionPane: actionPane, // topArea
|
||||||
|
actionPane, //
|
||||||
|
DockPane: dockPane, // leftArea
|
||||||
|
dockPane,
|
||||||
|
TabPane: tabPane, // rightArea
|
||||||
|
tabPane,
|
||||||
|
add,
|
||||||
|
toolbar, // toolbar
|
||||||
|
Stages: stages,
|
||||||
|
Widgets: widgets, // centerArea
|
||||||
|
widgets,
|
||||||
|
};
|
||||||
48
packages/vision-polyfill/src/skeleton/area.ts
Normal file
48
packages/vision-polyfill/src/skeleton/area.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { obx, computed } from '@ali/lowcode-globals';
|
||||||
|
import WidgetContainer from './widget-container';
|
||||||
|
import { Skeleton } from './skeleton';
|
||||||
|
import { IWidget } from './widget';
|
||||||
|
import { IWidgetBaseConfig } from './types';
|
||||||
|
|
||||||
|
export default class Area<C extends IWidgetBaseConfig = any, T extends IWidget = IWidget> {
|
||||||
|
@obx private _visible: boolean = true;
|
||||||
|
|
||||||
|
@computed get visible() {
|
||||||
|
if (this.exclusive) {
|
||||||
|
return this.container.current != null;
|
||||||
|
}
|
||||||
|
return this._visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly container: WidgetContainer<T, C>;
|
||||||
|
constructor(readonly skeleton: Skeleton, readonly name: string, handle: (item: T | C) => T, private exclusive?: boolean, defaultSetCurrent: boolean = false) {
|
||||||
|
this.container = skeleton.createContainer(name, handle, exclusive, () => this.visible, defaultSetCurrent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed isEmpty(): boolean {
|
||||||
|
return this.container.items.length < 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
add(config: T | C): T {
|
||||||
|
return this.container.add(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private lastCurrent: T | null = null;
|
||||||
|
setVisible(flag: boolean) {
|
||||||
|
if (this.exclusive) {
|
||||||
|
const current = this.container.current;
|
||||||
|
if (flag && !current) {
|
||||||
|
this.container.active(this.lastCurrent || this.container.getAt(0))
|
||||||
|
} else if (current) {
|
||||||
|
this.lastCurrent = this.container.current;
|
||||||
|
this.container.unactive();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._visible = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
packages/vision-polyfill/src/skeleton/bottom-area.tsx
Normal file
38
packages/vision-polyfill/src/skeleton/bottom-area.tsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { Component, Fragment } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { observer } from '@ali/recore';
|
||||||
|
import Area from './area';
|
||||||
|
import Panel from './panel';
|
||||||
|
import { PanelWrapper } from './widget-views';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class BottomArea extends Component<{ area: Area<any, Panel> }> {
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
if (area.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className={classNames('lc-bottom-area', {
|
||||||
|
'lc-area-visible': area.visible,
|
||||||
|
})}>
|
||||||
|
<Contents area={area} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class Contents extends Component<{ area: Area<any, Panel> }> {
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{area.container.items.map((item) => <PanelWrapper key={item.id} panel={item} />)}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
78
packages/vision-polyfill/src/skeleton/dock.ts
Normal file
78
packages/vision-polyfill/src/skeleton/dock.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { ReactNode, createElement } from 'react';
|
||||||
|
import { uniqueId, createContent, obx } from '@ali/lowcode-globals';
|
||||||
|
import { DockConfig } from "./types";
|
||||||
|
import { Skeleton } from './skeleton';
|
||||||
|
import { DockView } from './widget-views';
|
||||||
|
import { IWidget } from './widget';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带图标(主要)/标题(次要)的扩展
|
||||||
|
*/
|
||||||
|
export default class Dock implements IWidget {
|
||||||
|
readonly isWidget = true;
|
||||||
|
readonly id = uniqueId('dock');
|
||||||
|
readonly name: string;
|
||||||
|
readonly align?: string;
|
||||||
|
|
||||||
|
@obx.ref private _visible: boolean = true;
|
||||||
|
get visible(): boolean {
|
||||||
|
return this._visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
private inited: boolean = false;
|
||||||
|
private _content: ReactNode;
|
||||||
|
get content() {
|
||||||
|
if (this.inited) {
|
||||||
|
return this._content;
|
||||||
|
}
|
||||||
|
this.inited = true;
|
||||||
|
const { props, content, contentProps } = this.config;
|
||||||
|
|
||||||
|
if (content) {
|
||||||
|
this._content = createContent(content, {
|
||||||
|
...contentProps,
|
||||||
|
editor: this.skeleton.editor,
|
||||||
|
key: this.id,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this._content = createElement(DockView, {
|
||||||
|
...props,
|
||||||
|
key: this.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._content;
|
||||||
|
}
|
||||||
|
constructor(readonly skeleton: Skeleton, private config: DockConfig) {
|
||||||
|
const { props = {}, name } = config;
|
||||||
|
this.name = name;
|
||||||
|
this.align = props.align;
|
||||||
|
}
|
||||||
|
|
||||||
|
setVisible(flag: boolean) {
|
||||||
|
if (flag === this._visible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (flag) {
|
||||||
|
this._visible = true;
|
||||||
|
} else if (this.inited) {
|
||||||
|
this._visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getContent() {
|
||||||
|
return this.content;
|
||||||
|
}
|
||||||
|
|
||||||
|
getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
this.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
41
packages/vision-polyfill/src/skeleton/left-area.tsx
Normal file
41
packages/vision-polyfill/src/skeleton/left-area.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { Component, Fragment } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { observer } from '@ali/lowcode-globals';
|
||||||
|
import Area from './area';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class LeftArea extends Component<{ area: Area }> {
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
return (
|
||||||
|
<div className={classNames("lc-left-area", {
|
||||||
|
'lc-area-visible': area.visible
|
||||||
|
})}>
|
||||||
|
<Contents area={area} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class Contents extends Component<{ area: Area }> {
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
const top: any[] = [];
|
||||||
|
const bottom: any[] = [];
|
||||||
|
area.container.items.forEach(item => {
|
||||||
|
if (item.align === 'bottom') {
|
||||||
|
bottom.push(item.content);
|
||||||
|
} else {
|
||||||
|
top.push(item.content);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<div className="lc-left-area-top">{top}</div>
|
||||||
|
<div className="lc-left-area-bottom">{bottom}</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
50
packages/vision-polyfill/src/skeleton/left-fixed-pane.tsx
Normal file
50
packages/vision-polyfill/src/skeleton/left-fixed-pane.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { Component, Fragment } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { observer } from '@ali/lowcode-globals';
|
||||||
|
import { Button } from '@alifd/next';
|
||||||
|
import Area from './area';
|
||||||
|
import { PanelConfig } from './types';
|
||||||
|
import Panel from './panel';
|
||||||
|
import { PanelWrapper } from './widget-views';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class LeftFixedPane extends Component<{ area: Area<PanelConfig, Panel> }> {
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames('lc-left-fixed-pane', {
|
||||||
|
'lc-area-visible': area.visible,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
className="lc-pane-close"
|
||||||
|
onClick={() => {
|
||||||
|
area.setVisible(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Contents area={area} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class Contents extends Component<{ area: Area<PanelConfig, Panel> }> {
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{area.container.items.map((panel) => (
|
||||||
|
<PanelWrapper key={panel.id} panel={panel} />
|
||||||
|
))}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
51
packages/vision-polyfill/src/skeleton/left-float-pane.tsx
Normal file
51
packages/vision-polyfill/src/skeleton/left-float-pane.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { Component, Fragment } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { observer } from '@ali/lowcode-globals';
|
||||||
|
import { Button } from '@alifd/next';
|
||||||
|
import Area from './area';
|
||||||
|
import Panel from './panel';
|
||||||
|
import { PanelWrapper } from './widget-views';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }> {
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
// TODO: add focusingManager
|
||||||
|
// TODO: dragstart close
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames('lc-left-float-pane', {
|
||||||
|
'lc-area-visible': area.visible,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
className="lc-pane-close"
|
||||||
|
onClick={() => {
|
||||||
|
area.setVisible(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Contents area={area} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class Contents extends Component<{ area: Area<any, Panel> }> {
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{area.container.items.map((panel) => (
|
||||||
|
<PanelWrapper key={panel.id} panel={panel} />
|
||||||
|
))}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
packages/vision-polyfill/src/skeleton/main-area.tsx
Normal file
28
packages/vision-polyfill/src/skeleton/main-area.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { Component } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { observer } from '@ali/recore';
|
||||||
|
import Area from './area';
|
||||||
|
import Panel, { isPanel } from './panel';
|
||||||
|
import { PanelWrapper } from './widget-views';
|
||||||
|
import Widget from './widget';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class MainArea extends Component<{ area: Area<any, Panel | Widget> }> {
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
return (
|
||||||
|
<div className={classNames('lc-main-area')}>
|
||||||
|
{area.container.items.map((item) => {
|
||||||
|
// todo?
|
||||||
|
if (isPanel(item)) {
|
||||||
|
return <PanelWrapper key={item.id} panel={item} />;
|
||||||
|
}
|
||||||
|
return item.content;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
79
packages/vision-polyfill/src/skeleton/panel-dock.ts
Normal file
79
packages/vision-polyfill/src/skeleton/panel-dock.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { uniqueId, obx, computed } from '@ali/lowcode-globals';
|
||||||
|
import { createElement, ReactNode } from 'react';
|
||||||
|
import { Skeleton } from './skeleton';
|
||||||
|
import { PanelDockConfig } from './types';
|
||||||
|
import Panel from './panel';
|
||||||
|
import { PanelDockView } from './widget-views';
|
||||||
|
import { IWidget } from './widget';
|
||||||
|
|
||||||
|
export default class PanelDock implements IWidget {
|
||||||
|
readonly isWidget = true;
|
||||||
|
readonly id: string;
|
||||||
|
readonly name: string;
|
||||||
|
readonly align?: string;
|
||||||
|
|
||||||
|
private inited: boolean = false;
|
||||||
|
private _content: ReactNode;
|
||||||
|
get content() {
|
||||||
|
if (this.inited) {
|
||||||
|
return this._content;
|
||||||
|
}
|
||||||
|
this.inited = true;
|
||||||
|
const { props } = this.config;
|
||||||
|
|
||||||
|
this._content = createElement(PanelDockView, {
|
||||||
|
...props,
|
||||||
|
key: this.id,
|
||||||
|
dock: this,
|
||||||
|
});
|
||||||
|
|
||||||
|
return this._content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get actived(): boolean {
|
||||||
|
return this.panel?.visible || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly panelName: string;
|
||||||
|
private _panel?: Panel;
|
||||||
|
@computed get panel() {
|
||||||
|
return this._panel || this.skeleton.getPanel(this.panelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(readonly skeleton: Skeleton, private config: PanelDockConfig) {
|
||||||
|
const { content, contentProps, panelProps, name } = config;
|
||||||
|
this.name = name;
|
||||||
|
this.id = uniqueId(`dock:${name}$`);
|
||||||
|
this.panelName = config.panelName || name;
|
||||||
|
if (content) {
|
||||||
|
this._panel = this.skeleton.add({
|
||||||
|
type: "Panel",
|
||||||
|
name: this.panelName,
|
||||||
|
props: panelProps || {},
|
||||||
|
contentProps,
|
||||||
|
content,
|
||||||
|
area: panelProps?.area || 'leftFloatArea'
|
||||||
|
}) as Panel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
this.panel?.toggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
getContent() {
|
||||||
|
return this.content;
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.panel?.setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
this.panel?.setActive(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
150
packages/vision-polyfill/src/skeleton/panel.ts
Normal file
150
packages/vision-polyfill/src/skeleton/panel.ts
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
import {createElement, ReactNode } from 'react';
|
||||||
|
import { obx, uniqueId, createContent, TitleContent } from '@ali/lowcode-globals';
|
||||||
|
import WidgetContainer from './widget-container';
|
||||||
|
import { PanelConfig, HelpTipConfig } from './types';
|
||||||
|
import { PanelView, TabsPanelView } from './widget-views';
|
||||||
|
import { Skeleton } from './skeleton';
|
||||||
|
import { composeTitle } from './utils';
|
||||||
|
import { IWidget } from './widget';
|
||||||
|
|
||||||
|
export default class Panel implements IWidget {
|
||||||
|
readonly isWidget = true;
|
||||||
|
readonly name: string;
|
||||||
|
readonly id: string;
|
||||||
|
@obx.ref inited: boolean = false;
|
||||||
|
@obx.ref private _actived: boolean = false;
|
||||||
|
get actived(): boolean {
|
||||||
|
return this._actived;
|
||||||
|
}
|
||||||
|
get visible(): boolean {
|
||||||
|
if (this.parent?.visible) {
|
||||||
|
return this._actived;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
setActive(flag: boolean) {
|
||||||
|
if (flag === this._actived) {
|
||||||
|
// TODO: 如果移动到另外一个 container,会有问题
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (flag) {
|
||||||
|
if (!this.inited) {
|
||||||
|
this.initBody();
|
||||||
|
}
|
||||||
|
this._actived = true;
|
||||||
|
this.parent?.active(this);
|
||||||
|
} else if (this.inited) {
|
||||||
|
this._actived = false;
|
||||||
|
this.parent?.unactive(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
this.setActive(!this._actived);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly isPanel = true;
|
||||||
|
|
||||||
|
private _body?: ReactNode;
|
||||||
|
get body() {
|
||||||
|
this.initBody();
|
||||||
|
return this._body;
|
||||||
|
}
|
||||||
|
|
||||||
|
get content() {
|
||||||
|
return this.plain ? this.body : createElement(PanelView, { panel: this });
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly title: TitleContent;
|
||||||
|
readonly help?: HelpTipConfig;
|
||||||
|
private plain: boolean = false;
|
||||||
|
|
||||||
|
private container?: WidgetContainer<Panel, PanelConfig>;
|
||||||
|
private parent?: WidgetContainer;
|
||||||
|
|
||||||
|
constructor(readonly skeleton: Skeleton, private config: PanelConfig) {
|
||||||
|
const { name, content, props = {} } = config;
|
||||||
|
const { hideTitleBar, title, icon, description, help, shortcut } = props;
|
||||||
|
this.name = name;
|
||||||
|
this.id = uniqueId(`pane:${name}$`);
|
||||||
|
this.title = composeTitle(title || name, icon, description);
|
||||||
|
this.plain = hideTitleBar || !title;
|
||||||
|
this.help = help;
|
||||||
|
if (Array.isArray(content)) {
|
||||||
|
this.container = this.skeleton.createContainer(name, (item) => {
|
||||||
|
if (isPanel(item)) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
return this.skeleton.createPanel(item);
|
||||||
|
}, true, () => this.visible, true);
|
||||||
|
content.forEach(item => this.add(item));
|
||||||
|
}
|
||||||
|
// todo: process shortcut
|
||||||
|
}
|
||||||
|
|
||||||
|
private initBody() {
|
||||||
|
if (this.inited) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.inited = true;
|
||||||
|
if (this.container) {
|
||||||
|
this._body = createElement(TabsPanelView, {
|
||||||
|
container: this.container,
|
||||||
|
key: this.id,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const { content, contentProps } = this.config;
|
||||||
|
this._body = createContent(content, {
|
||||||
|
...contentProps,
|
||||||
|
editor: this.skeleton.editor,
|
||||||
|
panel: this,
|
||||||
|
key: this.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setParent(parent: WidgetContainer) {
|
||||||
|
if (parent === this.parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.parent) {
|
||||||
|
this.parent.remove(this);
|
||||||
|
}
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
add(item: Panel | PanelConfig) {
|
||||||
|
return this.container?.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
getPane(name: string): Panel | null {
|
||||||
|
return this.container?.get(name) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(item: Panel | string) {
|
||||||
|
return this.container?.remove(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
active(item?: Panel | string | null) {
|
||||||
|
this.container?.active(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
getContent() {
|
||||||
|
return this.content;
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
this.setActive(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPanel(obj: any): obj is Panel {
|
||||||
|
return obj && obj.isPanel;
|
||||||
|
}
|
||||||
36
packages/vision-polyfill/src/skeleton/right-area.tsx
Normal file
36
packages/vision-polyfill/src/skeleton/right-area.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { Component, Fragment } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { observer } from '@ali/recore';
|
||||||
|
import Area from './area';
|
||||||
|
import Panel from './panel';
|
||||||
|
import { PanelWrapper } from './widget-views';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class RightArea extends Component<{ area: Area<any, Panel> }> {
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
return (
|
||||||
|
<div className={classNames('lc-right-area', {
|
||||||
|
'lc-area-visible': area.visible,
|
||||||
|
})}>
|
||||||
|
<Contents area={area} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class Contents extends Component<{ area: Area<any, Panel> }> {
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{area.container.items.map((item) => <PanelWrapper key={item.id} panel={item} />)}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
194
packages/vision-polyfill/src/skeleton/skeleton.ts
Normal file
194
packages/vision-polyfill/src/skeleton/skeleton.ts
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
import {
|
||||||
|
DockConfig,
|
||||||
|
PanelConfig,
|
||||||
|
WidgetConfig,
|
||||||
|
IWidgetBaseConfig,
|
||||||
|
PanelDockConfig,
|
||||||
|
DialogDockConfig,
|
||||||
|
isDockConfig,
|
||||||
|
isPanelDockConfig,
|
||||||
|
isPanelConfig,
|
||||||
|
} from './types';
|
||||||
|
import Editor from '@ali/lowcode-editor-core';
|
||||||
|
import Panel, { isPanel } from './panel';
|
||||||
|
import WidgetContainer from './widget-container';
|
||||||
|
import Area from './area';
|
||||||
|
import Widget, { isWidget, IWidget } from './widget';
|
||||||
|
import PanelDock from './panel-dock';
|
||||||
|
import Dock from './dock';
|
||||||
|
import { Stage, StageConfig } from './stage';
|
||||||
|
|
||||||
|
export class Skeleton {
|
||||||
|
private panels = new Map<string, Panel>();
|
||||||
|
private containers = new Map<string, WidgetContainer<any>>();
|
||||||
|
readonly leftArea: Area<DockConfig | PanelDockConfig | DialogDockConfig>;
|
||||||
|
readonly topArea: Area<DockConfig | PanelDockConfig | DialogDockConfig>;
|
||||||
|
readonly toolbar: Area<DockConfig | PanelDockConfig | DialogDockConfig>;
|
||||||
|
readonly leftFixedArea: Area<PanelConfig, Panel>;
|
||||||
|
readonly leftFloatArea: Area<PanelConfig, Panel>;
|
||||||
|
readonly rightArea: Area<PanelConfig, Panel>;
|
||||||
|
readonly mainArea: Area<WidgetConfig | PanelConfig, Widget | Panel>;
|
||||||
|
readonly bottomArea: Area<PanelConfig, Panel>;
|
||||||
|
readonly stages: Area<StageConfig, Stage>;
|
||||||
|
constructor(readonly editor: Editor) {
|
||||||
|
this.leftArea = new Area(
|
||||||
|
this,
|
||||||
|
'leftArea',
|
||||||
|
(config) => {
|
||||||
|
if (isWidget(config)) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
return this.createWidget(config);
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
this.topArea = new Area(
|
||||||
|
this,
|
||||||
|
'topArea',
|
||||||
|
(config) => {
|
||||||
|
if (isWidget(config)) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
return this.createWidget(config);
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
this.toolbar = new Area(
|
||||||
|
this,
|
||||||
|
'toolbar',
|
||||||
|
(config) => {
|
||||||
|
if (isWidget(config)) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
return this.createWidget(config);
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
this.leftFixedArea = new Area(
|
||||||
|
this,
|
||||||
|
'leftFixedArea',
|
||||||
|
(config) => {
|
||||||
|
if (isPanel(config)) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
return this.createPanel(config);
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
this.leftFloatArea = new Area(
|
||||||
|
this,
|
||||||
|
'leftFloatArea',
|
||||||
|
(config) => {
|
||||||
|
if (isPanel(config)) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
return this.createPanel(config);
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
this.rightArea = new Area(
|
||||||
|
this,
|
||||||
|
'rightArea',
|
||||||
|
(config) => {
|
||||||
|
if (isPanel(config)) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
return this.createPanel(config);
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
this.mainArea = new Area(
|
||||||
|
this,
|
||||||
|
'mainArea',
|
||||||
|
(config) => {
|
||||||
|
if (isWidget(config)) {
|
||||||
|
return config as Widget;
|
||||||
|
}
|
||||||
|
return this.createWidget(config) as Widget;
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
this.bottomArea = new Area(
|
||||||
|
this,
|
||||||
|
'bottomArea',
|
||||||
|
(config) => {
|
||||||
|
if (isPanel(config)) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
return this.createPanel(config);
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
this.stages = new Area(this, 'stages', (config) => {
|
||||||
|
if (isWidget(config)) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
return new Stage(this, config);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createWidget(config: IWidgetBaseConfig | IWidget) {
|
||||||
|
if (isWidget(config)) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
if (isDockConfig(config)) {
|
||||||
|
if (isPanelDockConfig(config)) {
|
||||||
|
return new PanelDock(this, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Dock(this, config);
|
||||||
|
}
|
||||||
|
if (isPanelConfig(config)) {
|
||||||
|
return this.createPanel(config);
|
||||||
|
}
|
||||||
|
return new Widget(this, config as WidgetConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
createPanel(config: PanelConfig) {
|
||||||
|
const panel = new Panel(this, config);
|
||||||
|
this.panels.set(panel.name, panel);
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPanel(name: string): Panel | undefined {
|
||||||
|
return this.panels.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
createContainer(
|
||||||
|
name: string,
|
||||||
|
handle: (item: any) => any,
|
||||||
|
exclusive: boolean = false,
|
||||||
|
checkVisible: () => boolean = () => true,
|
||||||
|
defaultSetCurrent: boolean = false,
|
||||||
|
) {
|
||||||
|
const container = new WidgetContainer(name, handle, exclusive, checkVisible, defaultSetCurrent);
|
||||||
|
this.containers.set(name, container);
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
add(config: IWidgetBaseConfig & { area: string }) {
|
||||||
|
const { area } = config;
|
||||||
|
switch (area) {
|
||||||
|
case 'leftArea': case 'left':
|
||||||
|
return this.leftArea.add(config as any);
|
||||||
|
case 'rightArea': case 'right':
|
||||||
|
return this.rightArea.add(config as any);
|
||||||
|
case 'topArea': case 'top':
|
||||||
|
return this.topArea.add(config as any);
|
||||||
|
case 'toolbar':
|
||||||
|
return this.toolbar.add(config as any);
|
||||||
|
case 'mainArea': case 'main': case 'center': case 'centerArea':
|
||||||
|
return this.mainArea.add(config as any);
|
||||||
|
case 'bottomArea': case 'bottom':
|
||||||
|
return this.bottomArea.add(config as any);
|
||||||
|
case 'leftFixedArea':
|
||||||
|
return this.leftFixedArea.add(config as any);
|
||||||
|
case 'leftFloatArea':
|
||||||
|
return this.leftFloatArea.add(config as any);
|
||||||
|
case 'stages':
|
||||||
|
return this.stages.add(config as any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
packages/vision-polyfill/src/skeleton/stage.ts
Normal file
51
packages/vision-polyfill/src/skeleton/stage.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import Widget from './widget';
|
||||||
|
import { Skeleton } from './skeleton';
|
||||||
|
import { WidgetConfig } from './types';
|
||||||
|
|
||||||
|
export interface StageConfig extends WidgetConfig {
|
||||||
|
isRoot?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Stage extends Widget {
|
||||||
|
readonly isRoot: boolean;
|
||||||
|
private previous?: Stage;
|
||||||
|
private refer?: {
|
||||||
|
stage?: Stage;
|
||||||
|
direction?: 'right' | 'left';
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(skeleton: Skeleton, config: StageConfig) {
|
||||||
|
super(skeleton, config);
|
||||||
|
this.isRoot = config.isRoot || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPrevious(stage: Stage) {
|
||||||
|
this.previous = stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPrevious() {
|
||||||
|
return this.previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasBack(): boolean {
|
||||||
|
return this.previous && !this.isRoot ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setRefer(stage: Stage, direction: 'right' | 'left') {
|
||||||
|
this.refer = { stage, direction };
|
||||||
|
}
|
||||||
|
|
||||||
|
setReferRight(stage: Stage) {
|
||||||
|
this.setRefer(stage, 'right');
|
||||||
|
}
|
||||||
|
|
||||||
|
setReferLeft(stage: Stage) {
|
||||||
|
this.setRefer(stage, 'left');
|
||||||
|
}
|
||||||
|
|
||||||
|
getRefer() {
|
||||||
|
const refer = this.refer;
|
||||||
|
this.refer = undefined;
|
||||||
|
return refer;
|
||||||
|
}
|
||||||
|
}
|
||||||
60
packages/vision-polyfill/src/skeleton/theme.less
Normal file
60
packages/vision-polyfill/src/skeleton/theme.less
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
@import '~@ali/ve-less-variables/index.less';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Theme Colors
|
||||||
|
*
|
||||||
|
* 乐高设计器的主要主题色变量
|
||||||
|
*/
|
||||||
|
:root {
|
||||||
|
--color-brand: @brand-color-1;
|
||||||
|
--color-brand-light: @brand-color-2;
|
||||||
|
--color-brand-dark: @brand-color-3;
|
||||||
|
|
||||||
|
--color-canvas-background: @normal-alpha-8;
|
||||||
|
|
||||||
|
--color-icon-normal: @normal-alpha-4;
|
||||||
|
--color-icon-hover: @normal-alpha-3;
|
||||||
|
--color-icon-active: @brand-color-1;
|
||||||
|
--color-icon-reverse: @white-alpha-1;
|
||||||
|
|
||||||
|
--color-line-normal: @normal-alpha-7;
|
||||||
|
--color-line-darken: darken(@normal-alpha-7, 10%);
|
||||||
|
|
||||||
|
--color-title: @dark-alpha-2;
|
||||||
|
--color-text: @dark-alpha-3;
|
||||||
|
--color-text-dark: darken(@dark-alpha-3, 10%);
|
||||||
|
--color-text-light: lighten(@dark-alpha-3, 10%);
|
||||||
|
--color-text-reverse: @white-alpha-2;
|
||||||
|
--color-text-regular: @normal-alpha-2;
|
||||||
|
|
||||||
|
--color-field-label: @dark-alpha-4;
|
||||||
|
--color-field-text: @dark-alpha-3;
|
||||||
|
--color-field-placeholder: @normal-alpha-5;
|
||||||
|
--color-field-border: @normal-alpha-5;
|
||||||
|
--color-field-border-hover: @normal-alpha-4;
|
||||||
|
--color-field-border-active: @normal-alpha-3;
|
||||||
|
--color-field-background: @white-alpha-1;
|
||||||
|
|
||||||
|
--color-function-success: @brand-success;
|
||||||
|
--color-function-success-dark: darken(@brand-success, 10%);
|
||||||
|
--color-function-success-light: lighten(@brand-success, 10%);
|
||||||
|
--color-function-warning: @brand-warning;
|
||||||
|
--color-function-warning-dark: darken(@brand-warning, 10%);
|
||||||
|
--color-function-warning-light: lighten(@brand-warning, 10%);
|
||||||
|
--color-function-information: @brand-link-hover;
|
||||||
|
--color-function-information-dark: darken(@brand-link-hover, 10%);
|
||||||
|
--color-function-information-light: lighten(@brand-link-hover, 10%);
|
||||||
|
--color-function-error: @brand-danger;
|
||||||
|
--color-function-error-dark: darken(@brand-danger, 10%);
|
||||||
|
--color-function-error-light: lighten(@brand-danger, 10%);
|
||||||
|
|
||||||
|
--color-pane-background: @white-alpha-1;
|
||||||
|
--color-block-background-normal: @white-alpha-1;
|
||||||
|
--color-block-background-light: @normal-alpha-9;
|
||||||
|
--color-block-background-shallow: @normal-alpha-8;
|
||||||
|
--color-block-background-dark: @normal-alpha-7;
|
||||||
|
--color-block-background-disabled: @normal-alpha-6;
|
||||||
|
--color-block-background-deep-dark: @normal-5;
|
||||||
|
--color-layer-mask-background: @dark-alpha-7;
|
||||||
|
--color-layer-tooltip-background: rgba(44,47,51,0.8);
|
||||||
|
}
|
||||||
49
packages/vision-polyfill/src/skeleton/toolbar.tsx
Normal file
49
packages/vision-polyfill/src/skeleton/toolbar.tsx
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { Component, Fragment } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { observer } from '@ali/lowcode-globals';
|
||||||
|
import Area from './area';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Toolbar extends Component<{ area: Area }> {
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
if (area.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames('lc-toolbar', {
|
||||||
|
'lc-area-visible': area.visible,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Contents area={area} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class Contents extends Component<{ area: Area }> {
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
const left: any[] = [];
|
||||||
|
const center: any[] = [];
|
||||||
|
const right: any[] = [];
|
||||||
|
area.container.items.forEach((item) => {
|
||||||
|
if (item.align === 'center') {
|
||||||
|
center.push(item.content);
|
||||||
|
} else if (item.align === 'right') {
|
||||||
|
right.push(item.content);
|
||||||
|
} else {
|
||||||
|
left.push(item.content);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<div className="lc-toolbar-left">{left}</div>
|
||||||
|
<div className="lc-toolbar-center">{center}</div>
|
||||||
|
<div className="lc-toolbar-right">{right}</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
44
packages/vision-polyfill/src/skeleton/top-area.tsx
Normal file
44
packages/vision-polyfill/src/skeleton/top-area.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { Component, Fragment } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { observer } from '@ali/lowcode-globals';
|
||||||
|
import Area from './area';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class TopArea extends Component<{ area: Area }> {
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
return (
|
||||||
|
<div className={classNames("lc-top-area", {
|
||||||
|
'lc-area-visible': area.visible
|
||||||
|
})}>
|
||||||
|
<Contents area={area} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class Contents extends Component<{ area: Area }> {
|
||||||
|
render() {
|
||||||
|
const { area } = this.props;
|
||||||
|
const left: any[] = [];
|
||||||
|
const center: any[] = [];
|
||||||
|
const right: any[] = [];
|
||||||
|
area.container.items.forEach(item => {
|
||||||
|
if (item.align === 'center') {
|
||||||
|
center.push(item.content);
|
||||||
|
} else if (item.align === 'left') {
|
||||||
|
right.push(item.content);
|
||||||
|
} else {
|
||||||
|
left.push(item.content);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<div className="lc-top-area-left">{left}</div>
|
||||||
|
<div className="lc-top-area-center">{center}</div>
|
||||||
|
<div className="lc-top-area-right">{right}</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
104
packages/vision-polyfill/src/skeleton/types.ts
Normal file
104
packages/vision-polyfill/src/skeleton/types.ts
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import { ReactElement, ComponentType } from 'react';
|
||||||
|
import { TitleContent, IconType, I18nData } from '@ali/lowcode-globals';
|
||||||
|
|
||||||
|
export interface IWidgetBaseConfig {
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
area?: string; // 停靠位置, 默认 float, 如果添加非固定区,
|
||||||
|
props?: object;
|
||||||
|
content?: any;
|
||||||
|
contentProps?: object;
|
||||||
|
// index?: number;
|
||||||
|
[extra: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WidgetConfig extends IWidgetBaseConfig {
|
||||||
|
type: "Widget";
|
||||||
|
name: string; // as pluginKey
|
||||||
|
props?: {
|
||||||
|
align?: "left" | "right" | "bottom" | "center" | "top";
|
||||||
|
};
|
||||||
|
content?: string | ReactElement | ComponentType<any>; // children
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isWidgetConfig(obj: any): obj is WidgetConfig {
|
||||||
|
return obj && obj.type === "Custom";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DockProps {
|
||||||
|
title?: TitleContent;
|
||||||
|
icon?: IconType;
|
||||||
|
size?: 'small' | 'medium' | 'large';
|
||||||
|
className?: string;
|
||||||
|
description?: string | I18nData;
|
||||||
|
onClick?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IDockBaseConfig extends IWidgetBaseConfig {
|
||||||
|
props?: DockProps & {
|
||||||
|
align?: "left" | "right" | "bottom" | "center" | "top";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DockConfig extends IDockBaseConfig {
|
||||||
|
type: "Dock";
|
||||||
|
content?: string | ReactElement | ComponentType<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isDockConfig(obj: any): obj is DockConfig {
|
||||||
|
return obj && /Dock$/.test(obj.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按钮弹窗扩展
|
||||||
|
export interface DialogDockConfig extends IDockBaseConfig {
|
||||||
|
type: "DialogDock";
|
||||||
|
dialogProps?: {
|
||||||
|
title?: TitleContent;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isDialogDockConfig(obj: any): obj is DialogDockConfig {
|
||||||
|
return obj && obj.type === 'DialogDock';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 窗格扩展
|
||||||
|
export interface PanelConfig extends IWidgetBaseConfig {
|
||||||
|
type: "Panel";
|
||||||
|
content?: string | ReactElement | ComponentType<any> | PanelConfig[]; // as children
|
||||||
|
props?: PanelProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPanelConfig(obj: any): obj is PanelConfig {
|
||||||
|
return obj && obj.type === 'Panel';
|
||||||
|
}
|
||||||
|
|
||||||
|
export type HelpTipConfig = string | { url?: string; content?: string | ReactElement };
|
||||||
|
|
||||||
|
export interface PanelProps {
|
||||||
|
title?: TitleContent;
|
||||||
|
icon?: any; // 冗余字段
|
||||||
|
description?: string | I18nData;
|
||||||
|
hideTitleBar?: boolean; // panel.props 兼容,不暴露
|
||||||
|
help?: HelpTipConfig; // 显示问号帮助
|
||||||
|
width?: number; // panel.props
|
||||||
|
height?: number; // panel.props
|
||||||
|
maxWidth?: number; // panel.props
|
||||||
|
maxHeight?: number; // panel.props
|
||||||
|
onInit?: () => any;
|
||||||
|
onDestroy?: () => any;
|
||||||
|
shortcut?: string; // 只有在特定位置,可触发 toggle show
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PanelDockConfig extends IDockBaseConfig {
|
||||||
|
type: "PanelDock";
|
||||||
|
panelName?: string;
|
||||||
|
panelProps?: PanelProps & {
|
||||||
|
area?: string;
|
||||||
|
};
|
||||||
|
content?: string | ReactElement | ComponentType<any> | PanelConfig[]; // content for pane
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPanelDockConfig(obj: any): obj is PanelDockConfig {
|
||||||
|
return obj && obj.type === 'PanelDock';
|
||||||
|
}
|
||||||
28
packages/vision-polyfill/src/skeleton/utils.ts
Normal file
28
packages/vision-polyfill/src/skeleton/utils.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { IconType, TitleContent, I18nData, isI18nData } from '@ali/lowcode-globals';
|
||||||
|
import { isValidElement } from 'react';
|
||||||
|
|
||||||
|
export function composeTitle(title?: TitleContent, icon?: IconType, tip?: string | I18nData) {
|
||||||
|
if (!title) {
|
||||||
|
title = {};
|
||||||
|
if (!icon) {
|
||||||
|
title.label = tip;
|
||||||
|
tip = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (icon || tip) {
|
||||||
|
if (typeof title !== 'object' || isValidElement(title) || isI18nData(title)) {
|
||||||
|
title = {
|
||||||
|
label: title,
|
||||||
|
icon,
|
||||||
|
tip,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
title = {
|
||||||
|
...title,
|
||||||
|
icon,
|
||||||
|
tip
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return title;
|
||||||
|
}
|
||||||
134
packages/vision-polyfill/src/skeleton/widget-container.ts
Normal file
134
packages/vision-polyfill/src/skeleton/widget-container.ts
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
import { obx, hasOwnProperty, computed } from '@ali/lowcode-globals';
|
||||||
|
import { isPanel } from './panel';
|
||||||
|
export interface WidgetItem {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Activeable {
|
||||||
|
setActive(flag: boolean): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isActiveable(obj: any): obj is Activeable {
|
||||||
|
return obj && obj.setActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class WidgetContainer<T extends WidgetItem = any, G extends WidgetItem = any> {
|
||||||
|
@obx.val items: T[] = [];
|
||||||
|
private maps: { [name: string]: T } = {};
|
||||||
|
@obx.ref private _current: T & Activeable | null = null;
|
||||||
|
|
||||||
|
get current() {
|
||||||
|
return this._current;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly name: string,
|
||||||
|
private handle: (item: T | G) => T,
|
||||||
|
private exclusive: boolean = false,
|
||||||
|
private checkVisible: () => boolean = () => true,
|
||||||
|
private defaultSetCurrent: boolean = false,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@computed get visible() {
|
||||||
|
return this.checkVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
active(nameOrItem?: T | string | null) {
|
||||||
|
let item: any = nameOrItem;
|
||||||
|
if (nameOrItem && typeof nameOrItem === 'string') {
|
||||||
|
item = this.get(nameOrItem);
|
||||||
|
}
|
||||||
|
if (!isActiveable(nameOrItem)) {
|
||||||
|
item = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.exclusive) {
|
||||||
|
if (this._current === item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this._current) {
|
||||||
|
this._current.setActive(false);
|
||||||
|
}
|
||||||
|
this._current = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
item.setActive(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unactive(nameOrItem?: T | string | null) {
|
||||||
|
let item: any = nameOrItem;
|
||||||
|
if (nameOrItem && typeof nameOrItem === 'string') {
|
||||||
|
item = this.get(nameOrItem);
|
||||||
|
}
|
||||||
|
if (!isActiveable(nameOrItem)) {
|
||||||
|
item = null;
|
||||||
|
}
|
||||||
|
if (this._current === item) {
|
||||||
|
this._current = null;
|
||||||
|
}
|
||||||
|
if (item) {
|
||||||
|
item.setActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add(item: T | G): T {
|
||||||
|
item = this.handle(item);
|
||||||
|
const origin = this.get(item.name);
|
||||||
|
if (origin === item) {
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
const i = origin ? this.items.indexOf(origin) : -1;
|
||||||
|
if (i > -1) {
|
||||||
|
this.items[i] = item;
|
||||||
|
} else {
|
||||||
|
this.items.push(item);
|
||||||
|
}
|
||||||
|
this.maps[item.name] = item;
|
||||||
|
if (isPanel(item)) {
|
||||||
|
item.setParent(this);
|
||||||
|
}
|
||||||
|
if (this.defaultSetCurrent) {
|
||||||
|
if (!this._current) {
|
||||||
|
this.active(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(name: string): T | null {
|
||||||
|
return this.maps[name] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAt(index: number): T | null {
|
||||||
|
return this.items[index] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
has(name: string): boolean {
|
||||||
|
return hasOwnProperty(this.maps, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
indexOf(item: T): number {
|
||||||
|
return this.items.indexOf(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return indexOf the deletion
|
||||||
|
*/
|
||||||
|
remove(item: string | T): number {
|
||||||
|
const thing = typeof item === 'string' ? this.get(item) : item;
|
||||||
|
if (!thing) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
const i = this.items.indexOf(thing);
|
||||||
|
if (i > -1) {
|
||||||
|
this.items.splice(i, 1);
|
||||||
|
}
|
||||||
|
delete this.maps[thing.name];
|
||||||
|
if (thing === this.current) {
|
||||||
|
this._current = null;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
143
packages/vision-polyfill/src/skeleton/widget-views.tsx
Normal file
143
packages/vision-polyfill/src/skeleton/widget-views.tsx
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import { Component, ReactElement } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { Title, observer } from '@ali/lowcode-globals';
|
||||||
|
import { DockProps } from './types';
|
||||||
|
import PanelDock from './panel-dock';
|
||||||
|
import { composeTitle } from './utils';
|
||||||
|
import WidgetContainer from './widget-container';
|
||||||
|
import Panel from './panel';
|
||||||
|
import Widget from './widget';
|
||||||
|
|
||||||
|
export function DockView({ title, icon, description, size, className, onClick }: DockProps) {
|
||||||
|
return (
|
||||||
|
<Title
|
||||||
|
title={composeTitle(title, icon, description)}
|
||||||
|
className={classNames('lc-dock', className, {
|
||||||
|
[`lc-dock-${size}`]: size,
|
||||||
|
})}
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class PanelDockView extends Component<DockProps & { dock: PanelDock }> {
|
||||||
|
render() {
|
||||||
|
const { dock, className, onClick, ...props } = this.props;
|
||||||
|
return DockView({
|
||||||
|
...props,
|
||||||
|
className: classNames(className, {
|
||||||
|
actived: dock.actived,
|
||||||
|
}),
|
||||||
|
onClick: () => {
|
||||||
|
onClick && onClick();
|
||||||
|
dock.toggle();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DialogDockView extends Component {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PanelView extends Component<{ panel: Panel }> {
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { panel } = this.props;
|
||||||
|
return (
|
||||||
|
<div className="lc-panel">
|
||||||
|
<PanelTitle panel={panel} />
|
||||||
|
<div className="lc-pane-body">{panel.body}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class TabsPanelView extends Component<{ container: WidgetContainer<Panel> }> {
|
||||||
|
render() {
|
||||||
|
const { container } = this.props;
|
||||||
|
const titles: ReactElement[] = [];
|
||||||
|
const contents: ReactElement[] = [];
|
||||||
|
container.items.forEach((item: any) => {
|
||||||
|
titles.push(<PanelTitle key={item.id} panel={item} className="lc-tab-title" />);
|
||||||
|
contents.push(<PanelWrapper key={item.id} panel={item} />);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="lc-tabs">
|
||||||
|
<div
|
||||||
|
className="lc-tabs-title"
|
||||||
|
onClick={(e) => {
|
||||||
|
const shell = e.currentTarget;
|
||||||
|
const t = e.target as Element;
|
||||||
|
let elt = shell.firstElementChild;
|
||||||
|
while (elt) {
|
||||||
|
if (elt.contains(t)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
elt = elt.nextElementSibling;
|
||||||
|
}
|
||||||
|
if (elt) {
|
||||||
|
container.active((elt as any).dataset.name);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{titles}
|
||||||
|
</div>
|
||||||
|
<div className="lc-tabs-content">{contents}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class PanelTitle extends Component<{ panel: Panel; className?: string }> {
|
||||||
|
render() {
|
||||||
|
const { panel, className } = this.props;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames('lc-panel-title', className, {
|
||||||
|
actived: panel.actived,
|
||||||
|
})}
|
||||||
|
data-name={panel.name}
|
||||||
|
>
|
||||||
|
<Title title={panel.title || panel.name} />
|
||||||
|
{/*pane.help ? <HelpTip tip={panel.help} /> : null*/}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class PanelWrapper extends Component<{ panel: Panel }> {
|
||||||
|
render() {
|
||||||
|
const { panel } = this.props;
|
||||||
|
if (!panel.inited) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames('lc-panel-wrapper', {
|
||||||
|
hidden: !panel.actived,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{panel.body}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class WidgetWrapper extends Component<{ widget: Widget }> {
|
||||||
|
render() {
|
||||||
|
const { widget } = this.props;
|
||||||
|
if (!widget.visible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return widget.body;
|
||||||
|
}
|
||||||
|
}
|
||||||
94
packages/vision-polyfill/src/skeleton/widget.ts
Normal file
94
packages/vision-polyfill/src/skeleton/widget.ts
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { ReactNode, createElement } from 'react';
|
||||||
|
import { createContent, uniqueId, obx } from '@ali/lowcode-globals';
|
||||||
|
import { WidgetConfig } from './types';
|
||||||
|
import { Skeleton } from './skeleton';
|
||||||
|
import { WidgetWrapper } from './widget-views';
|
||||||
|
|
||||||
|
export interface IWidget {
|
||||||
|
readonly name: string;
|
||||||
|
readonly content: any;
|
||||||
|
readonly align?: string;
|
||||||
|
readonly isWidget: true;
|
||||||
|
|
||||||
|
getName(): string;
|
||||||
|
getContent(): any;
|
||||||
|
show(): void;
|
||||||
|
hide(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Widget implements IWidget {
|
||||||
|
readonly isWidget = true;
|
||||||
|
readonly id = uniqueId('widget');
|
||||||
|
readonly name: string;
|
||||||
|
readonly align?: string;
|
||||||
|
|
||||||
|
@obx.ref private _visible: boolean = true;
|
||||||
|
get visible(): boolean {
|
||||||
|
return this._visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
@obx.ref inited: boolean = false;
|
||||||
|
private _body: ReactNode;
|
||||||
|
get body() {
|
||||||
|
if (this.inited) {
|
||||||
|
return this._body;
|
||||||
|
}
|
||||||
|
this.inited = true;
|
||||||
|
const { content, contentProps } = this.config;
|
||||||
|
this._body = createContent(content, {
|
||||||
|
...contentProps,
|
||||||
|
editor: this.skeleton.editor,
|
||||||
|
});
|
||||||
|
return this._body;
|
||||||
|
}
|
||||||
|
|
||||||
|
get content() {
|
||||||
|
return createElement(WidgetWrapper, {
|
||||||
|
widget: this,
|
||||||
|
key: this.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(readonly skeleton: Skeleton, private config: WidgetConfig) {
|
||||||
|
const { props = {}, name } = config;
|
||||||
|
this.name = name;
|
||||||
|
this.align = props.align;
|
||||||
|
}
|
||||||
|
|
||||||
|
getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
getContent() {
|
||||||
|
return this.content;
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
this.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
setVisible(flag: boolean) {
|
||||||
|
if (flag === this._visible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (flag) {
|
||||||
|
this._visible = true;
|
||||||
|
} else if (this.inited) {
|
||||||
|
this._visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
this.setVisible(!this._visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isWidget(obj: any): obj is IWidget {
|
||||||
|
return obj && obj.isWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
261
packages/vision-polyfill/src/skeleton/workbench.less
Normal file
261
packages/vision-polyfill/src/skeleton/workbench.less
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
@import "./theme.less";
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--font-family: @font-family;
|
||||||
|
--font-size-label: @fontSize-4;
|
||||||
|
--font-size-text: @fontSize-5;
|
||||||
|
--font-size-btn-large: @fontSize-3;
|
||||||
|
--font-size-btn-medium: @fontSize-4;
|
||||||
|
--font-size-btn-small: @fontSize-5;
|
||||||
|
|
||||||
|
--global-border-radius: @global-border-radius;
|
||||||
|
--input-border-radius: @input-border-radius;
|
||||||
|
--popup-border-radius: @popup-border-radius;
|
||||||
|
|
||||||
|
--left-area-width: 46px;
|
||||||
|
--right-area-width: 300px;
|
||||||
|
--top-area-height: 48px;
|
||||||
|
--toolbar-height: 32px;
|
||||||
|
--dock-pane-width: 372px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media (min-width: 1860px) {
|
||||||
|
:root {
|
||||||
|
--right-area-width: 400px;
|
||||||
|
--dock-pane-width: 452px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
position: relative;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
font-size: var(--font-size-text);
|
||||||
|
color: var(--color-text);
|
||||||
|
background-color:#EDEFF3;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.my-pane {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
.pane-title {
|
||||||
|
// height: var(--pane-title-height);
|
||||||
|
background-color: var(--pane-title-bg-color);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 15px;
|
||||||
|
.my-help-tip {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pane-body {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
overflow: auto;
|
||||||
|
.my-tabs {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
.tabs-title {
|
||||||
|
display: flex;
|
||||||
|
height: var(--pane-title-height);
|
||||||
|
> .tab-title {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
justify-content: center;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
&.actived {
|
||||||
|
cursor: default;
|
||||||
|
color: var(--color-text-avtived);
|
||||||
|
border-bottom-color: #3896ee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tabs-content {
|
||||||
|
position: absolute;
|
||||||
|
top: var(--pane-title-height);
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: calc(100% - var(--pane-title-height));
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.titled > .pane-body {
|
||||||
|
top: var(--pane-title-height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.lc-panel-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
&.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.pane-title {
|
||||||
|
height: var(--pane-title-height);
|
||||||
|
background-color: var(--pane-title-bg-color);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 15px;
|
||||||
|
.my-help-tip {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.my-tabs {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
.tabs-title {
|
||||||
|
display: flex;
|
||||||
|
height: var(--pane-title-height);
|
||||||
|
margin-right: 30px;
|
||||||
|
> .tab-title {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
justify-content: center;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
&.actived {
|
||||||
|
cursor: default;
|
||||||
|
color: var(--color-text-avtived);
|
||||||
|
border-bottom-color: #3896ee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tabs-content {
|
||||||
|
position: absolute;
|
||||||
|
top: var(--pane-title-height);
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: calc(100% - var(--pane-title-height));
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-dock {
|
||||||
|
padding: 0px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
align-self: stretch;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.my-title-label {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
&.actived, &:hover {
|
||||||
|
background-color: var(--pane-title-bg-color);
|
||||||
|
.my-title {
|
||||||
|
color: var(--color-actived);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.lc-workbench {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: #EDEFF3;
|
||||||
|
.lc-top-area {
|
||||||
|
height: var(--top-area-height);
|
||||||
|
background-color: var(--color-pane-background);
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.lc-workbench-body {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
.lc-left-float-pane {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: var(--dock-pane-width);
|
||||||
|
left: calc(var(--left-area-width) + 1px);
|
||||||
|
z-index: 20;
|
||||||
|
display: none;
|
||||||
|
&.lc-area-visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.lc-left-area {
|
||||||
|
height: 100%;
|
||||||
|
width: var(--left-area-width);
|
||||||
|
background-color: var(--color-pane-background);
|
||||||
|
display: none;
|
||||||
|
&.lc-area-visible {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.lc-left-fixed-pane {
|
||||||
|
width: var(--dock-pane-width);
|
||||||
|
background-color: var(--color-pane-background);
|
||||||
|
height: 100%;
|
||||||
|
display: none;
|
||||||
|
&.lc-area-visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.lc-left-area.lc-area-visible ~ .lc-left-fixed-pane {
|
||||||
|
margin-left: 1px;
|
||||||
|
}
|
||||||
|
.lc-left-area.lc-area-visible ~ .lc-workbench-center {
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
.lc-workbench-center {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.lc-toolbar {
|
||||||
|
height: var(--toolbar-height);
|
||||||
|
background-color: var(--color-pane-background);
|
||||||
|
}
|
||||||
|
.lc-main-area {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.lc-bottom-area {
|
||||||
|
height: var(--bottom-area-height);
|
||||||
|
background-color: var(--color-pane-background);
|
||||||
|
display: none;
|
||||||
|
&.lc-area-visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.lc-right-area {
|
||||||
|
height: 100%;
|
||||||
|
width: var(--right-area-width);
|
||||||
|
background-color: var(--color-pane-background);
|
||||||
|
display: none;
|
||||||
|
margin-left: 2px;
|
||||||
|
&.lc-area-visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
packages/vision-polyfill/src/skeleton/workbench.tsx
Normal file
40
packages/vision-polyfill/src/skeleton/workbench.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { Component } from 'react';
|
||||||
|
import { TipContainer, observer } from '@ali/lowcode-globals';
|
||||||
|
import { Skeleton } from './skeleton';
|
||||||
|
import TopArea from './top-area';
|
||||||
|
import LeftArea from './left-area';
|
||||||
|
import LeftFixedPane from './left-fixed-pane';
|
||||||
|
import LeftFloatPane from './left-float-pane';
|
||||||
|
import Toolbar from './toolbar';
|
||||||
|
import MainArea from './main-area';
|
||||||
|
import BottomArea from './bottom-area';
|
||||||
|
import RightArea from './right-area';
|
||||||
|
import './workbench.less';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class VisionWorkbench extends Component<{ skeleton: Skeleton}> {
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { skeleton } = this.props;
|
||||||
|
return (
|
||||||
|
<div className="lc-workbench">
|
||||||
|
<TopArea area={skeleton.topArea} />
|
||||||
|
<div className="lc-workbench-body">
|
||||||
|
<LeftArea area={skeleton.leftArea} />
|
||||||
|
<LeftFloatPane area={skeleton.leftFloatArea} />
|
||||||
|
<LeftFixedPane area={skeleton.leftFixedArea} />
|
||||||
|
<div className="lc-workbench-center">
|
||||||
|
<Toolbar area={skeleton.toolbar} />
|
||||||
|
<MainArea area={skeleton.mainArea} />
|
||||||
|
<BottomArea area={skeleton.bottomArea} />
|
||||||
|
</div>
|
||||||
|
<RightArea area={skeleton.rightArea} />
|
||||||
|
</div>
|
||||||
|
<TipContainer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,8 +6,9 @@ import { createElement } from 'react';
|
|||||||
import { VE_EVENTS as EVENTS, VE_HOOKS as HOOKS } from './const';
|
import { VE_EVENTS as EVENTS, VE_HOOKS as HOOKS } from './const';
|
||||||
import Bus from './bus';
|
import Bus from './bus';
|
||||||
import Symbols from './symbols';
|
import Symbols from './symbols';
|
||||||
import Skeleton from '@ali/lowcode-editor-skeleton';
|
import { editor, skeleton } from './editor';
|
||||||
import editor from './editor';
|
import { VisionWorkbench } from './skeleton/workbench';
|
||||||
|
import Panes from './panes';
|
||||||
|
|
||||||
function init(container?: Element) {
|
function init(container?: Element) {
|
||||||
if (!container) {
|
if (!container) {
|
||||||
@ -16,9 +17,12 @@ function init(container?: Element) {
|
|||||||
}
|
}
|
||||||
container.id = 'engine';
|
container.id = 'engine';
|
||||||
|
|
||||||
render(createElement(Skeleton, {
|
render(
|
||||||
editor,
|
createElement(VisionWorkbench, {
|
||||||
}), container);
|
skeleton,
|
||||||
|
}),
|
||||||
|
container,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ui = {
|
const ui = {
|
||||||
@ -51,4 +55,5 @@ export {
|
|||||||
*/
|
*/
|
||||||
init,
|
init,
|
||||||
ui,
|
ui,
|
||||||
|
Panes,
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user