mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-06-03 14:11:10 +00:00
fix: init
This commit is contained in:
parent
5abe68110e
commit
d3f8a96e72
@ -172,7 +172,8 @@ export class BoxResizingInstance extends Component<{
|
||||
metadata.configure.advanced.callbacks.onResizeEnd(e, cbNode);
|
||||
}
|
||||
|
||||
const editor = globalContext.get(Editor);
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
|
||||
@ -131,7 +131,8 @@ function createAction(content: ReactNode | ComponentType<any> | ActionContentObj
|
||||
className="lc-borders-action"
|
||||
onClick={() => {
|
||||
action && action(node);
|
||||
const editor = globalContext.get('editor');
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
|
||||
@ -22,6 +22,7 @@ export function createSimulator(
|
||||
const doc = iframe.contentDocument!;
|
||||
|
||||
win.LCSimulatorHost = host;
|
||||
win._ = window._;
|
||||
|
||||
const styles: any = {};
|
||||
const scripts: any = {};
|
||||
|
||||
@ -23,8 +23,8 @@ export class BuiltinSimulatorHostView extends Component<SimulatorHostProps> {
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
const { project, onMount } = this.props;
|
||||
this.host = (project.simulator as BuiltinSimulatorHost) || new BuiltinSimulatorHost(project);
|
||||
const { project, onMount, designer } = this.props;
|
||||
this.host = (project.simulator as BuiltinSimulatorHost) || new BuiltinSimulatorHost(project, designer);
|
||||
this.host.setProps(this.props);
|
||||
onMount?.(this.host);
|
||||
}
|
||||
@ -76,7 +76,8 @@ class Content extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
private dispose?: () => void;
|
||||
|
||||
componentDidMount() {
|
||||
const editor = globalContext.get('editor');
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
const onEnableEvents = (type: boolean) => {
|
||||
this.setState({
|
||||
disabledEvents: type,
|
||||
@ -97,7 +98,7 @@ class Content extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
render() {
|
||||
const sim = this.props.host;
|
||||
const { disabledEvents } = this.state;
|
||||
const { viewport } = sim;
|
||||
const { viewport, designer } = sim;
|
||||
const frameStyle: any = {
|
||||
transform: `scale(${viewport.scale})`,
|
||||
height: viewport.contentHeight,
|
||||
@ -107,10 +108,12 @@ class Content extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
frameStyle.pointerEvents = 'none';
|
||||
}
|
||||
|
||||
const name = designer.name;
|
||||
|
||||
return (
|
||||
<div className="lc-simulator-content">
|
||||
<iframe
|
||||
name="SimulatorRenderer"
|
||||
name={`${name}-SimulatorRenderer`}
|
||||
className="lc-simulator-content-frame"
|
||||
style={frameStyle}
|
||||
ref={(frame) => sim.mountContentFrame(frame)}
|
||||
|
||||
@ -192,10 +192,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
this.renderer?.enableAutoRepaintNode();
|
||||
}
|
||||
|
||||
constructor(project: Project) {
|
||||
constructor(project: Project, designer: Designer) {
|
||||
makeObservable(this);
|
||||
this.project = project;
|
||||
this.designer = project?.designer;
|
||||
this.designer = designer;
|
||||
this.scroller = this.designer.createScroller(this.viewport);
|
||||
this.autoRender = !engineConfig.get('disableAutoRender', false);
|
||||
this.componentsConsumer = new ResourceConsumer<Asset | undefined>(() => this.componentsAsset);
|
||||
|
||||
@ -52,7 +52,8 @@ export class LiveEditing {
|
||||
const targetElement = event.target as HTMLElement;
|
||||
const { liveTextEditing } = node.componentMeta;
|
||||
|
||||
const editor = globalContext.get(Editor);
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') || node?.componentMeta?.componentName || '';
|
||||
|
||||
@ -62,7 +62,8 @@ export default class InstanceNodeSelector extends React.Component<IProps, IState
|
||||
|
||||
if (canClick && typeof node.select === 'function') {
|
||||
node.select();
|
||||
const editor = globalContext.get(Editor);
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
|
||||
@ -5,6 +5,13 @@ import { insertChildren, TransformStage } from '../document';
|
||||
import clipboard from './clipboard';
|
||||
|
||||
export function isInLiveEditing() {
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
if (workSpace.isActive) {
|
||||
return Boolean(
|
||||
workSpace.window.editor.get('designer')?.project?.simulator?.liveEditing?.editing,
|
||||
);
|
||||
}
|
||||
|
||||
if (globalContext.has(Editor)) {
|
||||
return Boolean(
|
||||
globalContext.get(Editor).get('designer')?.project?.simulator?.liveEditing?.editing,
|
||||
|
||||
@ -10,10 +10,12 @@ export class DesignerView extends Component<DesignerProps & {
|
||||
designer?: Designer;
|
||||
}> {
|
||||
readonly designer: Designer;
|
||||
readonly name: string;
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
const { designer, ...designerProps } = props;
|
||||
this.name = designer.name;
|
||||
if (designer) {
|
||||
this.designer = designer;
|
||||
designer.setProps(designerProps);
|
||||
|
||||
@ -70,13 +70,16 @@ export class Designer {
|
||||
return this.currentDocument?.selection;
|
||||
}
|
||||
|
||||
name: string;
|
||||
|
||||
constructor(props: DesignerProps) {
|
||||
makeObservable(this);
|
||||
const { editor } = props;
|
||||
const { editor, name } = props;
|
||||
this.editor = editor;
|
||||
this.name = name;
|
||||
this.setProps(props);
|
||||
|
||||
this.project = new Project(this, props.defaultSchema);
|
||||
this.project = new Project(this, props.defaultSchema, name);
|
||||
|
||||
let startTime: any;
|
||||
let src = '';
|
||||
@ -400,7 +403,7 @@ export class Designer {
|
||||
}
|
||||
|
||||
if (components) {
|
||||
// 合并assets
|
||||
// 合并 assets
|
||||
let assets = this.editor.get('assets');
|
||||
let newAssets = megreAssets(assets, incrementalAssets);
|
||||
// 对于 assets 存在需要二次网络下载的过程,必须 await 等待结束之后,再进行事件触发
|
||||
@ -435,6 +438,21 @@ export class Designer {
|
||||
return this._simulatorProps || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供给模拟器的参数
|
||||
*/
|
||||
@computed get projectSimulatorProps(): any {
|
||||
return {
|
||||
...this.simulatorProps,
|
||||
project: this.project,
|
||||
designer: this,
|
||||
onMount: (simulator: any) => {
|
||||
this.project.mountSimulator(simulator);
|
||||
this.editor.set('simulator', simulator);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@obx.ref private _suspensed = false;
|
||||
|
||||
get suspensed(): boolean {
|
||||
|
||||
@ -171,6 +171,8 @@ function isDragEvent(e: any): e is DragEvent {
|
||||
export class Dragon {
|
||||
private sensors: ISensor[] = [];
|
||||
|
||||
key = Math.random();
|
||||
|
||||
/**
|
||||
* current active sensor, 可用于感应区高亮
|
||||
*/
|
||||
@ -188,10 +190,13 @@ export class Dragon {
|
||||
return this._dragging;
|
||||
}
|
||||
|
||||
name: string;
|
||||
|
||||
private emitter = new EventEmitter();
|
||||
|
||||
constructor(readonly designer: Designer) {
|
||||
makeObservable(this);
|
||||
this.name = designer.name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { obx, computed, makeObservable, runInAction } from '@alilc/lowcode-editor-core';
|
||||
import { obx, computed, makeObservable, runInAction, Setters } from '@alilc/lowcode-editor-core';
|
||||
import { GlobalEvent, IEditor, isJSExpression } from '@alilc/lowcode-types';
|
||||
import { uniqueId } from '@alilc/lowcode-utils';
|
||||
import { SettingPropEntry as ShellSettingPropEntry } from '@alilc/lowcode-shell';
|
||||
@ -20,6 +20,8 @@ export class SettingPropEntry implements SettingEntry {
|
||||
|
||||
readonly isSingle: boolean;
|
||||
|
||||
readonly setters: Setters;
|
||||
|
||||
readonly nodes: Node[];
|
||||
|
||||
readonly componentMeta: ComponentMeta | null;
|
||||
@ -72,6 +74,7 @@ export class SettingPropEntry implements SettingEntry {
|
||||
// copy parent static properties
|
||||
this.editor = parent.editor;
|
||||
this.nodes = parent.nodes;
|
||||
this.setters = parent.setters;
|
||||
this.componentMeta = parent.componentMeta;
|
||||
this.isSameComponent = parent.isSameComponent;
|
||||
this.isMultiple = parent.isMultiple;
|
||||
|
||||
@ -71,6 +71,8 @@ export class SettingTopEntry implements SettingEntry {
|
||||
|
||||
readonly designer: Designer;
|
||||
|
||||
readonly setters: any;
|
||||
|
||||
disposeFunctions: any[] = [];
|
||||
|
||||
constructor(readonly editor: IEditor, readonly nodes: Node[]) {
|
||||
@ -80,6 +82,7 @@ export class SettingTopEntry implements SettingEntry {
|
||||
this.id = generateSessionId(nodes);
|
||||
this.first = nodes[0];
|
||||
this.designer = this.first.document.designer;
|
||||
this.setters = editor.get('setters');
|
||||
|
||||
// setups
|
||||
this.setupComponentMeta();
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
// all this file for polyfill vision logic
|
||||
import { isValidElement } from 'react';
|
||||
import { isSetterConfig, isDynamicSetter, FieldConfig, SetterConfig } from '@alilc/lowcode-types';
|
||||
import { getSetter } from '@alilc/lowcode-editor-core';
|
||||
import { SettingField } from './setting-field';
|
||||
|
||||
function getHotterFromSetter(setter) {
|
||||
@ -63,7 +62,7 @@ export class Transducer {
|
||||
isDynamic = dynamicFlag !== false;
|
||||
}
|
||||
if (typeof setter === 'string') {
|
||||
const { component, isDynamic: dynamicFlag } = getSetter(setter) || {};
|
||||
const { component, isDynamic: dynamicFlag } = context.setters.getSetter(setter) || {};
|
||||
setter = component;
|
||||
// 如果在物料配置中声明了,在 registerSetter 没有声明,取物料配置中的声明
|
||||
isDynamic = dynamicFlag === undefined ? isDynamic : dynamicFlag !== false;
|
||||
|
||||
@ -113,7 +113,8 @@ export class History<T = NodeSchema> {
|
||||
}
|
||||
const cursor = this.session.cursor - 1;
|
||||
this.go(cursor);
|
||||
const editor = globalContext.get(Editor);
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
@ -126,7 +127,8 @@ export class History<T = NodeSchema> {
|
||||
}
|
||||
const cursor = this.session.cursor + 1;
|
||||
this.go(cursor);
|
||||
const editor = globalContext.get(Editor);
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -163,7 +163,9 @@ export class NodeChildren {
|
||||
const { document } = node;
|
||||
/* istanbul ignore next */
|
||||
if (globalContext.has('editor')) {
|
||||
globalContext.get('editor').emit('node.remove', { node, index: i });
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
editor.emit('node.remove', { node, index: i });
|
||||
}
|
||||
document.unlinkNode(node);
|
||||
document.selection.remove(node.id);
|
||||
@ -198,12 +200,14 @@ export class NodeChildren {
|
||||
const i = children.indexOf(node);
|
||||
|
||||
if (node.parent) {
|
||||
/* istanbul ignore next */
|
||||
globalContext.has('editor') &&
|
||||
globalContext.get('editor').emit('node.remove.topLevel', {
|
||||
if (globalContext.has('editor')) {
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
editor.emit('node.remove.topLevel', {
|
||||
node,
|
||||
index: node.index,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (i < 0) {
|
||||
@ -233,7 +237,9 @@ export class NodeChildren {
|
||||
this.emitter.emit('insert', node);
|
||||
/* istanbul ignore next */
|
||||
if (globalContext.has('editor')) {
|
||||
globalContext.get('editor').emit('node.add', { node });
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
editor.emit('node.add', { node });
|
||||
}
|
||||
if (useMutator) {
|
||||
this.reportModified(node, this.owner, { type: 'insert' });
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* eslint-disable no-multi-assign */
|
||||
import { Editor, EngineConfig, engineConfig } from '@alilc/lowcode-editor-core';
|
||||
import { Editor, EngineConfig, engineConfig, Setters as InnerSetters } from '@alilc/lowcode-editor-core';
|
||||
import { Designer, ILowCodePluginManager } from '@alilc/lowcode-designer';
|
||||
import { Skeleton as InnerSkeleton } from '@alilc/lowcode-editor-skeleton';
|
||||
import {
|
||||
@ -23,7 +23,7 @@ import {
|
||||
} from './plugin-types';
|
||||
import { isValidPreferenceKey } from './plugin-utils';
|
||||
|
||||
export default class PluginContext implements ILowCodePluginContext {
|
||||
export class PluginContext implements ILowCodePluginContext {
|
||||
private readonly [editorSymbol]: Editor;
|
||||
private readonly [designerSymbol]: Designer;
|
||||
private readonly [skeletonSymbol]: InnerSkeleton;
|
||||
@ -42,14 +42,18 @@ export default class PluginContext implements ILowCodePluginContext {
|
||||
const editor = this[editorSymbol] = plugins.editor;
|
||||
const designer = this[designerSymbol] = editor.get('designer')!;
|
||||
const skeleton = this[skeletonSymbol] = editor.get('skeleton')!;
|
||||
const setters = editor.get('setters')!;
|
||||
const project = editor.get('project')!;
|
||||
const material = editor.get('material')!;
|
||||
|
||||
const { pluginName = 'anonymous' } = options;
|
||||
const project = designer?.project;
|
||||
this.hotkey = new Hotkey();
|
||||
this.project = new Project(project);
|
||||
// const project = designer?.project;
|
||||
const innerSetters = new InnerSetters();
|
||||
this.hotkey = new Hotkey(editor.name, editor.workspaceMode);
|
||||
this.project = project;
|
||||
this.skeleton = new Skeleton(skeleton);
|
||||
this.setters = new Setters();
|
||||
this.material = new Material(editor);
|
||||
this.setters = setters;
|
||||
this.material = material;
|
||||
this.config = engineConfig;
|
||||
this.plugins = plugins;
|
||||
this.event = new Event(editor, { prefix: 'common' });
|
||||
|
||||
@ -15,7 +15,7 @@ import {
|
||||
} from './plugin-types';
|
||||
import { filterValidOptions } from './plugin-utils';
|
||||
import { LowCodePlugin } from './plugin';
|
||||
import LowCodePluginContext from './plugin-context';
|
||||
import { PluginContext } from './plugin-context';
|
||||
import { invariant } from '../utils';
|
||||
import sequencify from './sequencify';
|
||||
import semverSatisfies from 'semver/functions/satisfies';
|
||||
@ -34,8 +34,8 @@ export class LowCodePluginManager implements ILowCodePluginManager {
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
private _getLowCodePluginContext(options: IPluginContextOptions) {
|
||||
return new LowCodePluginContext(this, options);
|
||||
_getLowCodePluginContext(options: IPluginContextOptions) {
|
||||
return new PluginContext(this, options);
|
||||
}
|
||||
|
||||
isEngineVersionMatched(versionExp: string): boolean {
|
||||
@ -104,6 +104,7 @@ export class LowCodePluginManager implements ILowCodePluginManager {
|
||||
const plugin = new LowCodePlugin(pluginName, this, config, meta);
|
||||
// support initialization of those plugins which registered after normal initialization by plugin-manager
|
||||
if (registerOptions?.autoInit) {
|
||||
// debugger
|
||||
await plugin.init();
|
||||
}
|
||||
this.plugins.push(plugin);
|
||||
|
||||
@ -26,8 +26,7 @@ export class ProjectView extends Component<{ designer: Designer }> {
|
||||
}
|
||||
render() {
|
||||
const { designer } = this.props;
|
||||
const { project } = designer;
|
||||
const { simulatorProps } = project;
|
||||
const { project, projectSimulatorProps: simulatorProps } = designer;
|
||||
const Simulator = designer.simulatorComponent || BuiltinSimulatorHostView;
|
||||
const Loading = engineConfig.get('loadingComponent', BuiltinLoading);
|
||||
|
||||
|
||||
@ -13,6 +13,10 @@
|
||||
padding-top: 50%;
|
||||
}
|
||||
|
||||
.lc-simulator {
|
||||
background: rgb(237, 239, 243);
|
||||
}
|
||||
|
||||
.lc-simulator-shell {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { obx, computed, makeObservable, action } from '@alilc/lowcode-editor-core';
|
||||
import { obx, computed, makeObservable, action, engineConfig } from '@alilc/lowcode-editor-core';
|
||||
import { Designer } from '../designer';
|
||||
import { DocumentModel, isDocumentModel } from '../document';
|
||||
import {
|
||||
@ -33,9 +33,11 @@ export class Project {
|
||||
return this._simulator || null;
|
||||
}
|
||||
|
||||
key = Math.random();
|
||||
|
||||
// TODO: 考虑项目级别 History
|
||||
|
||||
constructor(readonly designer: Designer, schema?: ProjectSchema) {
|
||||
constructor(readonly designer: Designer, schema?: ProjectSchema, public name = 'unknown') {
|
||||
makeObservable(this);
|
||||
this.load(schema);
|
||||
}
|
||||
@ -302,25 +304,9 @@ export class Project {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供给模拟器的参数
|
||||
*/
|
||||
@computed get simulatorProps(): object {
|
||||
let { simulatorProps } = this.designer;
|
||||
if (typeof simulatorProps === 'function') {
|
||||
simulatorProps = simulatorProps(this);
|
||||
}
|
||||
return {
|
||||
...simulatorProps,
|
||||
project: this,
|
||||
onMount: this.mountSimulator.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
private mountSimulator(simulator: ISimulatorHost) {
|
||||
mountSimulator(simulator: ISimulatorHost) {
|
||||
// TODO: 多设备 simulator 支持
|
||||
this._simulator = simulator;
|
||||
this.designer.editor.set('simulator', simulator);
|
||||
this.emitter.emit('lowcode_engine_simulator_ready', simulator);
|
||||
}
|
||||
|
||||
|
||||
@ -277,6 +277,8 @@ export interface EngineOptions {
|
||||
* 配置指定节点为根组件
|
||||
*/
|
||||
focusNodeSelector?: (rootNode: Node) => Node;
|
||||
|
||||
enableWorkspaceMode?: boolean;
|
||||
}
|
||||
|
||||
const getStrictModeValue = (engineOptions: EngineOptions, defaultValue: boolean): boolean => {
|
||||
|
||||
@ -18,39 +18,6 @@ export type RegisteredSetter = {
|
||||
// 标识是否为动态setter,默认为true
|
||||
isDynamic?: boolean;
|
||||
};
|
||||
const settersMap = new Map<string, RegisteredSetter & {
|
||||
type: string;
|
||||
}>();
|
||||
export function registerSetter(
|
||||
typeOrMaps: string | { [key: string]: CustomView | RegisteredSetter },
|
||||
setter?: CustomView | RegisteredSetter,
|
||||
) {
|
||||
if (typeof typeOrMaps === 'object') {
|
||||
Object.keys(typeOrMaps).forEach(type => {
|
||||
registerSetter(type, typeOrMaps[type]);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!setter) {
|
||||
return;
|
||||
}
|
||||
if (isCustomView(setter)) {
|
||||
setter = {
|
||||
component: setter,
|
||||
// todo: intl
|
||||
title: (setter as any).displayName || (setter as any).name || 'CustomSetter',
|
||||
};
|
||||
}
|
||||
if (!setter.initialValue) {
|
||||
const initial = getInitialFromSetter(setter.component);
|
||||
if (initial) {
|
||||
setter.initialValue = (field: any) => {
|
||||
return initial.call(field, field.getValue());
|
||||
};
|
||||
}
|
||||
}
|
||||
settersMap.set(typeOrMaps, { type: typeOrMaps, ...setter });
|
||||
}
|
||||
|
||||
function getInitialFromSetter(setter: any) {
|
||||
return setter && (
|
||||
@ -59,32 +26,72 @@ function getInitialFromSetter(setter: any) {
|
||||
) || null; // eslint-disable-line
|
||||
}
|
||||
|
||||
export function getSetter(type: string): RegisteredSetter | null {
|
||||
return settersMap.get(type) || null;
|
||||
}
|
||||
export function getSettersMap() {
|
||||
return settersMap;
|
||||
}
|
||||
export class Setters {
|
||||
constructor(public name: string = 'unknown') {}
|
||||
|
||||
export function createSetterContent(setter: any, props: Record<string, any>): ReactNode {
|
||||
if (typeof setter === 'string') {
|
||||
setter = getSetter(setter);
|
||||
if (!setter) {
|
||||
return null;
|
||||
settersMap = new Map<string, RegisteredSetter & {
|
||||
type: string;
|
||||
}>();
|
||||
|
||||
getSetter = (type: string): RegisteredSetter | null => {
|
||||
return this.settersMap.get(type) || null;
|
||||
};
|
||||
|
||||
registerSetter = (
|
||||
typeOrMaps: string | { [key: string]: CustomView | RegisteredSetter },
|
||||
setter?: CustomView | RegisteredSetter,
|
||||
) => {
|
||||
if (typeof typeOrMaps === 'object') {
|
||||
Object.keys(typeOrMaps).forEach(type => {
|
||||
this.registerSetter(type, typeOrMaps[type]);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (setter.defaultProps) {
|
||||
props = {
|
||||
...setter.defaultProps,
|
||||
...props,
|
||||
if (!setter) {
|
||||
return;
|
||||
}
|
||||
if (isCustomView(setter)) {
|
||||
setter = {
|
||||
component: setter,
|
||||
// todo: intl
|
||||
title: (setter as any).displayName || (setter as any).name || 'CustomSetter',
|
||||
};
|
||||
}
|
||||
setter = setter.component;
|
||||
}
|
||||
if (!setter.initialValue) {
|
||||
const initial = getInitialFromSetter(setter.component);
|
||||
if (initial) {
|
||||
setter.initialValue = (field: any) => {
|
||||
return initial.call(field, field.getValue());
|
||||
};
|
||||
}
|
||||
}
|
||||
this.settersMap.set(typeOrMaps, { type: typeOrMaps, ...setter });
|
||||
};
|
||||
|
||||
// Fusion的表单组件都是通过 'value' in props 来判断是否使用 defaultValue
|
||||
if ('value' in props && typeof props.value === 'undefined') {
|
||||
delete props.value;
|
||||
}
|
||||
getSettersMap = () => {
|
||||
return this.settersMap;
|
||||
};
|
||||
|
||||
return createContent(setter, props);
|
||||
}
|
||||
createSetterContent = (setter: any, props: Record<string, any>): ReactNode => {
|
||||
if (typeof setter === 'string') {
|
||||
setter = this.getSetter(setter);
|
||||
if (!setter) {
|
||||
return null;
|
||||
}
|
||||
if (setter.defaultProps) {
|
||||
props = {
|
||||
...setter.defaultProps,
|
||||
...props,
|
||||
};
|
||||
}
|
||||
setter = setter.component;
|
||||
}
|
||||
|
||||
// Fusion的表单组件都是通过 'value' in props 来判断是否使用 defaultValue
|
||||
if ('value' in props && typeof props.value === 'undefined') {
|
||||
delete props.value;
|
||||
}
|
||||
|
||||
return createContent(setter, props);
|
||||
};
|
||||
}
|
||||
@ -49,6 +49,9 @@ export declare interface Editor extends StrictEventEmitter<EventEmitter, GlobalE
|
||||
|
||||
// eslint-disable-next-line no-redeclare
|
||||
export class Editor extends (EventEmitter as any) implements IEditor {
|
||||
constructor(public name: string = 'unknown', public workspaceMode: boolean = false) {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* Ioc Container
|
||||
*/
|
||||
@ -76,7 +79,7 @@ export class Editor extends (EventEmitter as any) implements IEditor {
|
||||
return this.context.has(keyOrType);
|
||||
}
|
||||
|
||||
set(key: KeyType, data: any): void | Promise<void> {
|
||||
set(key: KeyType, data: any): void | Promise<void> {
|
||||
if (key === 'assets') {
|
||||
return this.setAssets(data);
|
||||
}
|
||||
|
||||
@ -331,7 +331,8 @@ function getKeyInfo(combination: string, action?: string): KeyInfo {
|
||||
*/
|
||||
function fireCallback(callback: HotkeyCallback, e: KeyboardEvent, combo?: string, sequence?: string): void {
|
||||
try {
|
||||
const editor = globalContext.get(Editor);
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
const designer = editor.get('designer');
|
||||
const node = designer?.currentSelection?.getNodes()?.[0];
|
||||
const npm = node?.componentMeta?.npm;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Component, MouseEvent, Fragment } from 'react';
|
||||
import { shallowIntl, createSetterContent, observer, obx, engineConfig, runInAction, globalContext } from '@alilc/lowcode-editor-core';
|
||||
import { shallowIntl, observer, obx, engineConfig, runInAction, globalContext } from '@alilc/lowcode-editor-core';
|
||||
import { createContent } from '@alilc/lowcode-utils';
|
||||
import { Skeleton } from '@alilc/lowcode-editor-skeleton';
|
||||
import { isSetterConfig, CustomView, isJSSlot } from '@alilc/lowcode-types';
|
||||
@ -9,6 +9,7 @@ import PopupService, { PopupPipe } from '../popup';
|
||||
import { SkeletonContext } from '../../context';
|
||||
// import { Icon } from '@alifd/next';
|
||||
import { intl } from '../../locale';
|
||||
import { Setters } from '@alilc/lowcode-shell';
|
||||
|
||||
function isStandardComponent(componentMeta: ComponentMeta | null) {
|
||||
if (!componentMeta) return false;
|
||||
@ -39,6 +40,8 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
|
||||
|
||||
stageName: string | undefined;
|
||||
|
||||
setters: Setters;
|
||||
|
||||
constructor(props: SettingFieldViewProps) {
|
||||
super(props);
|
||||
|
||||
@ -46,8 +49,10 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
|
||||
const { extraProps } = field;
|
||||
const { display } = extraProps;
|
||||
|
||||
const editor = globalContext.get('editor');
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
const { stages } = editor.get('skeleton') as Skeleton;
|
||||
this.setters = editor.get('setters');
|
||||
let stageName;
|
||||
if (display === 'entry') {
|
||||
runInAction(() => {
|
||||
@ -216,7 +221,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
|
||||
...extraProps,
|
||||
},
|
||||
!stageName &&
|
||||
createSetterContent(setterType, {
|
||||
this.setters.createSetterContent(setterType, {
|
||||
...shallowIntl(setterProps),
|
||||
forceInline: extraProps.forceInline,
|
||||
key: field.id,
|
||||
@ -269,7 +274,8 @@ class SettingGroupView extends Component<SettingGroupViewProps> {
|
||||
const { field } = this.props;
|
||||
const { extraProps } = field;
|
||||
const { display } = extraProps;
|
||||
const editor = globalContext.get('editor');
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
const { stages } = editor.get('skeleton') as Skeleton;
|
||||
// const items = field.items;
|
||||
|
||||
|
||||
@ -14,19 +14,25 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor; config: any
|
||||
state = {
|
||||
shouldIgnoreRoot: false,
|
||||
};
|
||||
private main = new SettingsMain(globalContext.get('editor'));
|
||||
private main;
|
||||
|
||||
@obx.ref private _activeKey?: any;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
makeObservable(this);
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
this.main = new SettingsMain(editor);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setShouldIgnoreRoot();
|
||||
|
||||
globalContext.get('editor').on('designer.selection.change', () => {
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
|
||||
editor.on('designer.selection.change', () => {
|
||||
if (!engineConfig.get('stayOnTheSameSettingTab', false)) {
|
||||
this._activeKey = null;
|
||||
}
|
||||
@ -65,7 +71,8 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor; config: any
|
||||
);
|
||||
}
|
||||
|
||||
const editor = globalContext.get('editor');
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
const designer = editor.get('designer');
|
||||
const current = designer?.currentSelection?.getNodes()?.[0];
|
||||
let node: Node | null = settings.first;
|
||||
@ -128,7 +135,8 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor; config: any
|
||||
|
||||
render() {
|
||||
const { settings } = this.main;
|
||||
const editor = globalContext.get('editor');
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
if (!settings) {
|
||||
// 未选中节点,提示选中 或者 显示根节点设置
|
||||
return (
|
||||
|
||||
@ -116,12 +116,14 @@ export class DraggableLineView extends Component<{ panel: Panel }> {
|
||||
}
|
||||
|
||||
// 抛出事件,对于有些需要 panel 插件随着 度变化进行再次渲染的,由panel插件内部监听事件实现
|
||||
const editor = globalContext.get(Editor);
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
editor?.emit('dockpane.drag', width);
|
||||
}
|
||||
|
||||
onDragChange(type: 'start' | 'end') {
|
||||
const editor = globalContext.get(Editor);
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
editor?.emit('dockpane.dragchange', type);
|
||||
// builtinSimulator 屏蔽掉 鼠标事件
|
||||
editor?.emit('designer.builtinSimulator.disabledEvents', type === 'start');
|
||||
@ -185,7 +187,8 @@ export class TitledPanelView extends Component<{ panel: Panel; area?: string }>
|
||||
if (!panel.inited) {
|
||||
return null;
|
||||
}
|
||||
const editor = globalContext.get(Editor);
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
const panelName = area ? `${area}-${panel.name}` : panel.name;
|
||||
editor?.emit('skeleton.panel.toggle', {
|
||||
name: panelName || '',
|
||||
@ -247,7 +250,8 @@ export class PanelView extends Component<{
|
||||
if (!panel.inited) {
|
||||
return null;
|
||||
}
|
||||
const editor = globalContext.get(Editor);
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
const panelName = area ? `${area}-${panel.name}` : panel.name;
|
||||
editor?.emit('skeleton.panel.toggle', {
|
||||
name: panelName || '',
|
||||
|
||||
@ -65,7 +65,6 @@ export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }>
|
||||
this.props.area.setVisible(false);
|
||||
},
|
||||
onBlur: () => {
|
||||
// debugger
|
||||
this.props.area.setVisible(false);
|
||||
},
|
||||
});
|
||||
|
||||
@ -133,11 +133,38 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.lc-workbench {
|
||||
.workspace-engine-main {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #edeff3;
|
||||
|
||||
.lc-workbench {
|
||||
|
||||
}
|
||||
|
||||
.engine-editor-view {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&.active {
|
||||
z-index: 999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lc-workbench {
|
||||
&.engine-main {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #edeff3;
|
||||
}
|
||||
.lc-top-area {
|
||||
height: var(--top-area-height);
|
||||
background-color: var(--color-pane-background);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Editor, action, makeObservable } from '@alilc/lowcode-editor-core';
|
||||
import { Editor, action, makeObservable, obx } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
DockConfig,
|
||||
PanelConfig,
|
||||
@ -53,7 +53,7 @@ export class Skeleton {
|
||||
|
||||
readonly rightArea: Area<PanelConfig, Panel>;
|
||||
|
||||
readonly mainArea: Area<WidgetConfig | PanelConfig, Widget | Panel>;
|
||||
@obx readonly mainArea: Area<WidgetConfig | PanelConfig, Widget | Panel>;
|
||||
|
||||
readonly bottomArea: Area<PanelConfig, Panel>;
|
||||
|
||||
|
||||
62
packages/editor-view/package.json
Normal file
62
packages/editor-view/package.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"name": "@alilc/lowcode-editor-view",
|
||||
"version": "1.0.15",
|
||||
"description": "Shell Layer for AliLowCodeEngine",
|
||||
"main": "lib/index.js",
|
||||
"private": true,
|
||||
"module": "es/index.js",
|
||||
"files": [
|
||||
"lib",
|
||||
"es"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "build-scripts build --skip-demo",
|
||||
"test": "build-scripts test --config build.test.json",
|
||||
"test:cov": "build-scripts test --config build.test.json --jest-coverage"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alilc/lowcode-designer": "1.0.15",
|
||||
"@alilc/lowcode-editor-core": "1.0.15",
|
||||
"@alilc/lowcode-editor-skeleton": "1.0.15",
|
||||
"@alilc/lowcode-types": "1.0.15",
|
||||
"@alilc/lowcode-utils": "1.0.15",
|
||||
"classnames": "^2.2.6",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-react-16": "^1.15.5",
|
||||
"react": "^16",
|
||||
"react-dom": "^16.7.0",
|
||||
"zen-logger": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alib/build-scripts": "^0.1.29",
|
||||
"@alilc/lowcode-test-mate": "^1.0.1",
|
||||
"@testing-library/react": "^11.2.2",
|
||||
"@types/classnames": "^2.2.7",
|
||||
"@types/jest": "^26.0.16",
|
||||
"@types/lodash": "^4.14.165",
|
||||
"@types/medium-editor": "^5.0.3",
|
||||
"@types/node": "^13.7.1",
|
||||
"@types/react": "^16",
|
||||
"@types/react-dom": "^16",
|
||||
"babel-jest": "^26.5.2",
|
||||
"build-plugin-component": "^0.2.10",
|
||||
"build-scripts-config": "^0.1.8",
|
||||
"jest": "^26.6.3",
|
||||
"lodash": "^4.17.20",
|
||||
"moment": "^2.29.1",
|
||||
"typescript": "^4.0.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"resolutions": {
|
||||
"@builder/babel-preset-ice": "1.0.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "http",
|
||||
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/shell"
|
||||
},
|
||||
"gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
|
||||
}
|
||||
70
packages/editor-view/src/base-context.ts
Normal file
70
packages/editor-view/src/base-context.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { globalContext, Editor, engineConfig, Setters as InnerSetters, EngineOptions } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
Designer,
|
||||
LowCodePluginManager,
|
||||
TransformStage,
|
||||
} from '@alilc/lowcode-designer';
|
||||
import {
|
||||
Skeleton as InnerSkeleton,
|
||||
} from '@alilc/lowcode-editor-skeleton';
|
||||
import {
|
||||
WorkSpace,
|
||||
} from '@alilc/lowcode-workspace';
|
||||
|
||||
import { Hotkey, Project, Skeleton, Setters, Material, Event } from '@alilc/lowcode-shell';
|
||||
import { getLogger } from '@alilc/lowcode-utils';
|
||||
|
||||
export class BasicContext {
|
||||
skeleton;
|
||||
plugins;
|
||||
project;
|
||||
setters;
|
||||
material;
|
||||
config;
|
||||
event;
|
||||
logger;
|
||||
hotkey;
|
||||
|
||||
constructor() {
|
||||
const editor = new Editor();
|
||||
// globalContext.register(editor, Editor);
|
||||
// globalContext.register(editor, 'editor');
|
||||
|
||||
const innerSkeleton = new InnerSkeleton(editor);
|
||||
editor.set('skeleton' as any, innerSkeleton);
|
||||
|
||||
const designer = new Designer({ editor });
|
||||
editor.set('designer' as any, designer);
|
||||
|
||||
const plugins = new LowCodePluginManager(editor).toProxy();
|
||||
editor.set('plugins' as any, plugins);
|
||||
|
||||
const { project: innerProject } = designer;
|
||||
// const skeletonCabin = getSkeletonCabin(innerSkeleton);
|
||||
// const { Workbench } = skeletonCabin;
|
||||
|
||||
const hotkey = new Hotkey();
|
||||
const project = new Project(innerProject);
|
||||
const skeleton = new Skeleton(innerSkeleton);
|
||||
const innerSetters = new InnerSetters();
|
||||
const setters = new Setters(innerSetters);
|
||||
const material = new Material(editor);
|
||||
const config = engineConfig;
|
||||
const event = new Event(editor, { prefix: 'common' });
|
||||
const logger = getLogger({ level: 'warn', bizName: 'common' });
|
||||
// const designerCabin = getDesignerCabin(editor);
|
||||
const objects = {
|
||||
TransformStage,
|
||||
};
|
||||
const workSpace = new WorkSpace();
|
||||
this.skeleton = skeleton;
|
||||
this.plugins = plugins;
|
||||
this.project = project;
|
||||
this.setters = setters;
|
||||
this.material = material;
|
||||
this.config = config;
|
||||
this.event = event;
|
||||
this.logger = logger;
|
||||
this.hotkey = hotkey;
|
||||
}
|
||||
}
|
||||
24
packages/editor-view/src/context.ts
Normal file
24
packages/editor-view/src/context.ts
Normal file
@ -0,0 +1,24 @@
|
||||
// import { LowCodePluginManager } from "@alilc/lowcode-designer";
|
||||
// import { Editor, Hotkey } from "@alilc/lowcode-editor-core";
|
||||
// import { Material } from "@alilc/lowcode-shell";
|
||||
|
||||
// import {
|
||||
// Skeleton as InnerSkeleton,
|
||||
// SettingsPrimaryPane,
|
||||
// registerDefaults,
|
||||
// Workbench,
|
||||
// } from '@alilc/lowcode-editor-skeleton';
|
||||
import { EditorViewOptions } from '@alilc/lowcode-workspace';
|
||||
import { BasicContext } from './base-context';
|
||||
|
||||
export class Context extends BasicContext {
|
||||
constructor(public editorView: EditorViewOptions) {
|
||||
super();
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
await this.editorView?.init(this);
|
||||
this.plugins.init();
|
||||
}
|
||||
}
|
||||
32
packages/editor-view/src/index.tsx
Normal file
32
packages/editor-view/src/index.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import { skeletonSymbol } from '@alilc/lowcode-shell';
|
||||
import { observer } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
Workbench,
|
||||
} from '@alilc/lowcode-editor-skeleton';
|
||||
import { Component } from 'react';
|
||||
import { Context } from './context';
|
||||
|
||||
export * from './base-context';
|
||||
|
||||
@observer
|
||||
export class EditorView extends Component<any, any> {
|
||||
// 因为 document 数据在不同视图下使用的是同一份,所以这里通过 constructor 传入
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.ctx = new Context(props.editorView);
|
||||
}
|
||||
|
||||
ctx: Context;
|
||||
|
||||
render() {
|
||||
const innerSkeleton = this.ctx.skeleton[skeletonSymbol];
|
||||
// debugger;
|
||||
return (
|
||||
<Workbench
|
||||
skeleton={innerSkeleton}
|
||||
className="engine-main"
|
||||
topAreaItemClassName="engine-actionitem"
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
6
packages/editor-window/build.test.json
Normal file
6
packages/editor-window/build.test.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": [
|
||||
"build-plugin-component",
|
||||
"@alilc/lowcode-test-mate/plugin/index.ts"
|
||||
]
|
||||
}
|
||||
9
packages/editor-window/jest.config.js
Normal file
9
packages/editor-window/jest.config.js
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: [
|
||||
'src/**/*.{ts,tsx}',
|
||||
'!**/node_modules/**',
|
||||
'!**/vendor/**',
|
||||
],
|
||||
};
|
||||
62
packages/editor-window/package.json
Normal file
62
packages/editor-window/package.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"name": "@alilc/lowcode-editor-window",
|
||||
"version": "1.0.15",
|
||||
"description": "Shell Layer for AliLowCodeEngine",
|
||||
"main": "lib/index.js",
|
||||
"private": true,
|
||||
"module": "es/index.js",
|
||||
"files": [
|
||||
"lib",
|
||||
"es"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "build-scripts build --skip-demo",
|
||||
"test": "build-scripts test --config build.test.json",
|
||||
"test:cov": "build-scripts test --config build.test.json --jest-coverage"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alilc/lowcode-designer": "1.0.15",
|
||||
"@alilc/lowcode-editor-core": "1.0.15",
|
||||
"@alilc/lowcode-editor-skeleton": "1.0.15",
|
||||
"@alilc/lowcode-types": "1.0.15",
|
||||
"@alilc/lowcode-utils": "1.0.15",
|
||||
"classnames": "^2.2.6",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-react-16": "^1.15.5",
|
||||
"react": "^16",
|
||||
"react-dom": "^16.7.0",
|
||||
"zen-logger": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alib/build-scripts": "^0.1.29",
|
||||
"@alilc/lowcode-test-mate": "^1.0.1",
|
||||
"@testing-library/react": "^11.2.2",
|
||||
"@types/classnames": "^2.2.7",
|
||||
"@types/jest": "^26.0.16",
|
||||
"@types/lodash": "^4.14.165",
|
||||
"@types/medium-editor": "^5.0.3",
|
||||
"@types/node": "^13.7.1",
|
||||
"@types/react": "^16",
|
||||
"@types/react-dom": "^16",
|
||||
"babel-jest": "^26.5.2",
|
||||
"build-plugin-component": "^0.2.10",
|
||||
"build-scripts-config": "^0.1.8",
|
||||
"jest": "^26.6.3",
|
||||
"lodash": "^4.17.20",
|
||||
"moment": "^2.29.1",
|
||||
"typescript": "^4.0.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"resolutions": {
|
||||
"@builder/babel-preset-ice": "1.0.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "http",
|
||||
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/shell"
|
||||
},
|
||||
"gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
|
||||
}
|
||||
14
packages/editor-window/src/context.ts
Normal file
14
packages/editor-window/src/context.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { EditorWindow } from '@alilc/lowcode-workspace';
|
||||
import { BasicContext } from '@alilc/lowcode-editor-view';
|
||||
|
||||
export class Context extends BasicContext {
|
||||
constructor(public editorWindow: EditorWindow) {
|
||||
super();
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
await this.editorWindow.resource.init(this);
|
||||
this.plugins.init();
|
||||
}
|
||||
}
|
||||
32
packages/editor-window/src/index.tsx
Normal file
32
packages/editor-window/src/index.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import { Component } from 'react';
|
||||
import { EditorView } from '@alilc/lowcode-editor-view';
|
||||
import { Context } from './context';
|
||||
import { observer } from '@alilc/lowcode-editor-core';
|
||||
|
||||
@observer
|
||||
export class EditorWindow extends Component<{
|
||||
editorWindow: any;
|
||||
}, any> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
// if (!props.resource) {
|
||||
// throw new Error('resource is required');
|
||||
// }
|
||||
this.ctx = new Context(props.editorWindow);
|
||||
}
|
||||
|
||||
ctx;
|
||||
|
||||
render() {
|
||||
const { resource, editorView } = this.props.editorWindow;
|
||||
return (
|
||||
<EditorView
|
||||
resourceCtx={this.ctx}
|
||||
resource={resource}
|
||||
key={editorView.name}
|
||||
editorView={editorView}
|
||||
defaultViewType
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
9
packages/editor-window/tsconfig.json
Normal file
9
packages/editor-window/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": [
|
||||
"./src/"
|
||||
]
|
||||
}
|
||||
@ -1,20 +1,20 @@
|
||||
import { createElement } from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { globalContext, Editor, engineConfig, EngineOptions } from '@alilc/lowcode-editor-core';
|
||||
import { globalContext, Editor, engineConfig, EngineOptions, Setters as InnerSetters } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
Designer,
|
||||
LowCodePluginManager,
|
||||
ILowCodePluginContext,
|
||||
PluginPreference,
|
||||
} from '@alilc/lowcode-designer';
|
||||
import {
|
||||
Skeleton as InnerSkeleton,
|
||||
SettingsPrimaryPane,
|
||||
registerDefaults,
|
||||
} from '@alilc/lowcode-editor-skeleton';
|
||||
import {
|
||||
WorkSpace,
|
||||
Workbench as WorkSpaceWorkbench,
|
||||
} from '@alilc/lowcode-workspace';
|
||||
|
||||
import Outline, { OutlineBackupPane, getTreeMaster } from '@alilc/lowcode-plugin-outline-pane';
|
||||
import DesignerPlugin from '@alilc/lowcode-plugin-designer';
|
||||
import {
|
||||
Hotkey,
|
||||
Project,
|
||||
@ -29,7 +29,9 @@ import { getLogger, isPlainObject } from '@alilc/lowcode-utils';
|
||||
import './modules/live-editing';
|
||||
import classes from './modules/classes';
|
||||
import symbols from './modules/symbols';
|
||||
|
||||
import { componentMetaParser } from './inner-plugins/component-meta-parser';
|
||||
import { setterRegistry } from './inner-plugins/setter-registry';
|
||||
import { defaultPanelRegistry } from './inner-plugins/default-panel-registry';
|
||||
export * from './modules/editor-types';
|
||||
export * from './modules/skeleton-types';
|
||||
export * from './modules/designer-types';
|
||||
@ -37,9 +39,11 @@ export * from './modules/lowcode-types';
|
||||
|
||||
registerDefaults();
|
||||
|
||||
const workSpace = new WorkSpace();
|
||||
const editor = new Editor();
|
||||
globalContext.register(editor, Editor);
|
||||
globalContext.register(editor, 'editor');
|
||||
globalContext.register(workSpace, 'workSpace');
|
||||
|
||||
const innerSkeleton = new InnerSkeleton(editor);
|
||||
editor.set('skeleton' as any, innerSkeleton);
|
||||
@ -55,8 +59,13 @@ const { project: innerProject } = designer;
|
||||
const hotkey = new Hotkey();
|
||||
const project = new Project(innerProject);
|
||||
const skeleton = new Skeleton(innerSkeleton);
|
||||
const setters = new Setters();
|
||||
const innerSetters = new InnerSetters();
|
||||
const setters = new Setters(innerSetters);
|
||||
|
||||
const material = new Material(editor);
|
||||
editor.set('project', project);
|
||||
editor.set('setters' as any, setters);
|
||||
editor.set('material', material);
|
||||
const config = engineConfig;
|
||||
const event = new Event(editor, { prefix: 'common' });
|
||||
const logger = getLogger({ level: 'warn', bizName: 'common' });
|
||||
@ -75,6 +84,7 @@ export {
|
||||
common,
|
||||
// 兼容原 editor 的事件功能
|
||||
event as editor,
|
||||
workSpace,
|
||||
};
|
||||
// declare this is open-source version
|
||||
export const isOpenSource = true;
|
||||
@ -82,100 +92,7 @@ export const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {
|
||||
symbols,
|
||||
classes,
|
||||
};
|
||||
engineConfig.set('isOpenSource', isOpenSource);
|
||||
|
||||
// 注册一批内置插件
|
||||
(async function registerPlugins() {
|
||||
// 处理 editor.set('assets'),将组件元数据创建好
|
||||
const componentMetaParser = (ctx: ILowCodePluginContext) => {
|
||||
return {
|
||||
init() {
|
||||
editor.onGot('assets', (assets: any) => {
|
||||
const { components = [] } = assets;
|
||||
designer.buildComponentMetasMap(components);
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
componentMetaParser.pluginName = '___component_meta_parser___';
|
||||
await plugins.register(componentMetaParser);
|
||||
|
||||
// 注册默认的 setters
|
||||
const setterRegistry = (ctx: ILowCodePluginContext) => {
|
||||
return {
|
||||
init() {
|
||||
if (engineConfig.get('disableDefaultSetters')) return;
|
||||
const builtinSetters = require('@alilc/lowcode-engine-ext')?.setters;
|
||||
if (builtinSetters) {
|
||||
ctx.setters.registerSetter(builtinSetters);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
setterRegistry.pluginName = '___setter_registry___';
|
||||
await plugins.register(setterRegistry);
|
||||
|
||||
// 注册默认的面板
|
||||
const defaultPanelRegistry = (ctx: ILowCodePluginContext) => {
|
||||
return {
|
||||
init() {
|
||||
skeleton.add({
|
||||
area: 'mainArea',
|
||||
name: 'designer',
|
||||
type: 'Widget',
|
||||
content: DesignerPlugin,
|
||||
});
|
||||
if (!engineConfig.get('disableDefaultSettingPanel')) {
|
||||
skeleton.add({
|
||||
area: 'rightArea',
|
||||
name: 'settingsPane',
|
||||
type: 'Panel',
|
||||
content: SettingsPrimaryPane,
|
||||
props: {
|
||||
ignoreRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// by default in float area;
|
||||
let isInFloatArea = true;
|
||||
const hasPreferenceForOutline = editor
|
||||
?.getPreference()
|
||||
?.contains('outline-pane-pinned-status-isFloat', 'skeleton');
|
||||
if (hasPreferenceForOutline) {
|
||||
isInFloatArea = editor
|
||||
?.getPreference()
|
||||
?.get('outline-pane-pinned-status-isFloat', 'skeleton');
|
||||
}
|
||||
|
||||
skeleton.add({
|
||||
area: 'leftArea',
|
||||
name: 'outlinePane',
|
||||
type: 'PanelDock',
|
||||
content: Outline,
|
||||
panelProps: {
|
||||
area: isInFloatArea ? 'leftFloatArea' : 'leftFixedArea',
|
||||
keepVisibleWhileDragging: true,
|
||||
...engineConfig.get('defaultOutlinePaneProps'),
|
||||
},
|
||||
});
|
||||
skeleton.add({
|
||||
area: 'rightArea',
|
||||
name: 'backupOutline',
|
||||
type: 'Panel',
|
||||
props: {
|
||||
condition: () => {
|
||||
return designer.dragon.dragging && !getTreeMaster(designer).hasVisibleTreeBoard();
|
||||
},
|
||||
},
|
||||
content: OutlineBackupPane,
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
defaultPanelRegistry.pluginName = '___default_panel___';
|
||||
await plugins.register(defaultPanelRegistry);
|
||||
})();
|
||||
config.set('isOpenSource', isOpenSource);
|
||||
|
||||
// container which will host LowCodeEngine DOM
|
||||
let engineContainer: HTMLElement;
|
||||
@ -188,6 +105,7 @@ export async function init(
|
||||
options?: EngineOptions,
|
||||
pluginPreference?: PluginPreference,
|
||||
) {
|
||||
|
||||
await destroy();
|
||||
let engineOptions = null;
|
||||
if (isPlainObject(container)) {
|
||||
@ -206,9 +124,41 @@ export async function init(
|
||||
}
|
||||
engineConfig.setEngineOptions(engineOptions as any);
|
||||
|
||||
|
||||
if (options && options.enableWorkspaceMode) {
|
||||
render(
|
||||
createElement(WorkSpaceWorkbench, {
|
||||
workSpace,
|
||||
className: 'engine-main',
|
||||
topAreaItemClassName: 'engine-actionitem',
|
||||
}),
|
||||
engineContainer,
|
||||
);
|
||||
workSpace.setActive(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// 注册一批内置插件
|
||||
await plugins.register(componentMetaParser(designer));
|
||||
await plugins.register(setterRegistry);
|
||||
await plugins.register(defaultPanelRegistry(editor, designer));
|
||||
|
||||
await plugins.init(pluginPreference as any);
|
||||
|
||||
const { Workbench } = common.skeletonCabin;
|
||||
if (options && options.enableWorkspaceMode) {
|
||||
render(
|
||||
createElement(WorkSpaceWorkbench, {
|
||||
workSpace,
|
||||
// skeleton: workSpace.skeleton,
|
||||
className: 'engine-main',
|
||||
topAreaItemClassName: 'engine-actionitem',
|
||||
}),
|
||||
engineContainer,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
render(
|
||||
createElement(Workbench, {
|
||||
skeleton: innerSkeleton,
|
||||
|
||||
20
packages/engine/src/inner-plugins/component-meta-parser.ts
Normal file
20
packages/engine/src/inner-plugins/component-meta-parser.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { ILowCodePluginContext } from '@alilc/lowcode-designer';
|
||||
|
||||
export const componentMetaParser = (designer: any) => {
|
||||
const fun = (ctx: ILowCodePluginContext) => {
|
||||
return {
|
||||
init() {
|
||||
const { material } = ctx;
|
||||
material.onChangeAssets(() => {
|
||||
const assets = material.getAssets();
|
||||
const { components = [] } = assets;
|
||||
designer.buildComponentMetasMap(components);
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
fun.pluginName = '___component_meta_parser___';
|
||||
|
||||
return fun;
|
||||
};
|
||||
93
packages/engine/src/inner-plugins/default-panel-registry.tsx
Normal file
93
packages/engine/src/inner-plugins/default-panel-registry.tsx
Normal file
@ -0,0 +1,93 @@
|
||||
import { ILowCodePluginContext } from '@alilc/lowcode-designer';
|
||||
import { SettingsPrimaryPane } from '@alilc/lowcode-editor-skeleton';
|
||||
import DesignerPlugin from '@alilc/lowcode-plugin-designer';
|
||||
import Outline, { getTreeMaster, OutlineBackupPane } from '@alilc/lowcode-plugin-outline-pane';
|
||||
|
||||
// 注册默认的面板
|
||||
export const defaultPanelRegistry = (editor: any, designer: any) => {
|
||||
const fun = (ctx: ILowCodePluginContext) => {
|
||||
return {
|
||||
init() {
|
||||
const { skeleton, config } = ctx;
|
||||
skeleton.add({
|
||||
area: 'mainArea',
|
||||
name: 'designer',
|
||||
type: 'Widget',
|
||||
content: <DesignerPlugin
|
||||
engineConfig={config}
|
||||
engineEditor={editor}
|
||||
/>,
|
||||
});
|
||||
if (!config.get('disableDefaultSettingPanel')) {
|
||||
skeleton.add({
|
||||
area: 'rightArea',
|
||||
name: 'settingsPane',
|
||||
type: 'Panel',
|
||||
content: SettingsPrimaryPane,
|
||||
props: {
|
||||
ignoreRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// by default in float area;
|
||||
let isInFloatArea = true;
|
||||
const hasPreferenceForOutline = editor
|
||||
?.getPreference()
|
||||
?.contains('outline-pane-pinned-status-isFloat', 'skeleton');
|
||||
if (hasPreferenceForOutline) {
|
||||
isInFloatArea = editor
|
||||
?.getPreference()
|
||||
?.get('outline-pane-pinned-status-isFloat', 'skeleton');
|
||||
}
|
||||
|
||||
skeleton.add({
|
||||
area: 'leftArea',
|
||||
name: 'outlinePane',
|
||||
type: 'PanelDock',
|
||||
content: {
|
||||
...Outline,
|
||||
content: (props: any) => {
|
||||
const Content = Outline.content;
|
||||
return (
|
||||
<Content
|
||||
engineConfig={config}
|
||||
engineEditor={editor}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
panelProps: {
|
||||
area: isInFloatArea ? 'leftFloatArea' : 'leftFixedArea',
|
||||
keepVisibleWhileDragging: true,
|
||||
...config.get('defaultOutlinePaneProps'),
|
||||
},
|
||||
});
|
||||
skeleton.add({
|
||||
area: 'rightArea',
|
||||
name: 'backupOutline',
|
||||
type: 'Panel',
|
||||
props: {
|
||||
condition: () => {
|
||||
return designer.dragon.dragging && !getTreeMaster(designer).hasVisibleTreeBoard();
|
||||
},
|
||||
},
|
||||
content: () => (
|
||||
<OutlineBackupPane
|
||||
engineConfig={config}
|
||||
engineEditor={editor}
|
||||
/>
|
||||
),
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
fun.pluginName = '___default_panel___';
|
||||
|
||||
return fun;
|
||||
};
|
||||
|
||||
|
||||
export default defaultPanelRegistry;
|
||||
17
packages/engine/src/inner-plugins/setter-registry.ts
Normal file
17
packages/engine/src/inner-plugins/setter-registry.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { ILowCodePluginContext } from '@alilc/lowcode-designer';
|
||||
|
||||
// 注册默认的 setters
|
||||
export const setterRegistry = (ctx: ILowCodePluginContext) => {
|
||||
return {
|
||||
init() {
|
||||
const { config } = ctx;
|
||||
if (config.get('disableDefaultSetters')) return;
|
||||
const builtinSetters = require('@alilc/lowcode-engine-ext')?.setters;
|
||||
if (builtinSetters) {
|
||||
ctx.setters.registerSetter(builtinSetters);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
setterRegistry.pluginName = '___setter_registry___';
|
||||
@ -5,7 +5,9 @@ import { Asset } from '@alilc/lowcode-utils';
|
||||
import './index.scss';
|
||||
|
||||
export interface PluginProps {
|
||||
editor: Editor;
|
||||
// editor?: Editor;
|
||||
// engineConfig?: any;
|
||||
engineEditor?: any;
|
||||
}
|
||||
|
||||
interface DesignerPluginState {
|
||||
@ -46,7 +48,7 @@ export default class DesignerPlugin extends PureComponent<PluginProps, DesignerP
|
||||
}
|
||||
|
||||
private async setupAssets() {
|
||||
const editor = globalContext.get('editor');
|
||||
const editor = this.props.engineEditor;
|
||||
try {
|
||||
const assets = await editor.onceGot('assets');
|
||||
const renderEnv = engineConfig.get('renderEnv') || editor.get('renderEnv');
|
||||
@ -85,7 +87,7 @@ export default class DesignerPlugin extends PureComponent<PluginProps, DesignerP
|
||||
}
|
||||
|
||||
private handleDesignerMount = (designer: Designer): void => {
|
||||
const editor = globalContext.get('editor');
|
||||
const editor = this.props.engineEditor;
|
||||
editor.set('designer', designer);
|
||||
editor.emit('designer.ready', designer);
|
||||
editor.onGot('schema', (schema) => {
|
||||
@ -94,7 +96,7 @@ export default class DesignerPlugin extends PureComponent<PluginProps, DesignerP
|
||||
};
|
||||
|
||||
render(): React.ReactNode {
|
||||
const editor = globalContext.get('editor');
|
||||
const editor = this.props.engineEditor;
|
||||
const {
|
||||
componentMetadatas,
|
||||
utilsMetadata,
|
||||
@ -119,6 +121,7 @@ export default class DesignerPlugin extends PureComponent<PluginProps, DesignerP
|
||||
onMount={this.handleDesignerMount}
|
||||
className="lowcode-plugin-designer"
|
||||
editor={editor}
|
||||
name={editor.name}
|
||||
designer={editor.get('designer')}
|
||||
componentMetadatas={componentMetadatas}
|
||||
simulatorProps={{
|
||||
|
||||
@ -5,11 +5,12 @@ import { OutlinePane } from './pane';
|
||||
|
||||
export const Backup = Symbol.for('backup-outline');
|
||||
|
||||
export class OutlineBackupPane extends PureComponent<PluginProps> {
|
||||
export class OutlineBackupPane extends PureComponent<any> {
|
||||
render() {
|
||||
return (
|
||||
<OutlinePane
|
||||
editor={globalContext.get('editor')}
|
||||
editor={this.props.engineEditor}
|
||||
engineEditor={this.props.engineEditor}
|
||||
config={{
|
||||
name: Backup,
|
||||
}}
|
||||
|
||||
@ -7,9 +7,15 @@ import './style.less';
|
||||
import { IEditor } from '@alilc/lowcode-types';
|
||||
import Filter from './filter';
|
||||
|
||||
interface Props { config: any; editor: IEditor }
|
||||
@observer
|
||||
export class OutlinePane extends Component<{ config: any; editor: IEditor }> {
|
||||
private main = new OutlineMain(globalContext.get('editor'), this.props.config.name || this.props.config.pluginKey);
|
||||
export class OutlinePane extends Component<any> {
|
||||
private main;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.main = new OutlineMain(this.props.engineEditor, this.props.config.name || this.props.config.pluginKey);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.main.purge();
|
||||
|
||||
@ -16,7 +16,8 @@ import { IconLock, IconUnlock } from '../icons';
|
||||
|
||||
|
||||
function emitOutlineEvent(type: string, treeNode: TreeNode, rest?: Record<string, unknown>) {
|
||||
const editor = globalContext.get(Editor);
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
const node = treeNode?.node;
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
|
||||
@ -66,7 +66,8 @@ export default class TreeView extends Component<{ tree: Tree }> {
|
||||
}
|
||||
} else {
|
||||
selection.select(id);
|
||||
const editor = globalContext.get(Editor);
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
const editor = workSpace.isActive ? workSpace.window.editor : globalContext.get('editor');
|
||||
const selectedNode = designer.currentSelection?.getNodes()?.[0];
|
||||
const npm = selectedNode?.componentMeta?.npm;
|
||||
const selected =
|
||||
|
||||
@ -245,7 +245,6 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
constructor() {
|
||||
this.dispose = host.connect(this, () => {
|
||||
// sync layout config
|
||||
// debugger;
|
||||
this._layout = host.project.get('config').layout;
|
||||
// todo: split with others, not all should recompute
|
||||
if (this._libraryMap !== host.libraryMap || this._componentsMap !== host.designer.componentsMap) {
|
||||
|
||||
@ -171,6 +171,7 @@ class Renderer extends Component<{
|
||||
this.schemaChangedSymbol = false;
|
||||
|
||||
if (!container.autoRender || isRendererDetached()) return null;
|
||||
|
||||
return (
|
||||
<LowCodeRenderer
|
||||
locale={locale}
|
||||
|
||||
@ -3,7 +3,6 @@ import {
|
||||
isFormEvent as innerIsFormEvent,
|
||||
compatibleLegaoSchema as innerCompatibleLegaoSchema,
|
||||
getNodeSchemaById as innerGetNodeSchemaById,
|
||||
transactionManager,
|
||||
} from '@alilc/lowcode-utils';
|
||||
import {
|
||||
isNodeSchema as innerIsNodeSchema,
|
||||
@ -44,7 +43,7 @@ import {
|
||||
shallowIntl,
|
||||
createIntl as innerCreateIntl,
|
||||
intl,
|
||||
createSetterContent,
|
||||
// createSetterContent,
|
||||
obx,
|
||||
observable,
|
||||
makeObservable,
|
||||
@ -54,7 +53,7 @@ import {
|
||||
globalLocale,
|
||||
} from '@alilc/lowcode-editor-core';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { transactionManager } from 'utils/src/transaction-manager';
|
||||
|
||||
const getDesignerCabin = (editor: Editor) => {
|
||||
const designer = editor.get('designer') as Designer;
|
||||
@ -97,6 +96,12 @@ const getSkeletonCabin = (skeleton: InnerSkeleton) => {
|
||||
};
|
||||
|
||||
class Utils {
|
||||
readonly [editorSymbol]: Editor;
|
||||
|
||||
constructor(editor: Editor) {
|
||||
this[editorSymbol] = editor;
|
||||
}
|
||||
|
||||
isNodeSchema(data: any): data is NodeSchema {
|
||||
return innerIsNodeSchema(data);
|
||||
}
|
||||
@ -148,21 +153,26 @@ export default class Common {
|
||||
this[skeletonSymbol] = skeleton;
|
||||
this.__designerCabin = getDesignerCabin(this[editorSymbol]);
|
||||
this.__skeletonCabin = getSkeletonCabin(this[skeletonSymbol]);
|
||||
this.__utils = new Utils();
|
||||
this.__utils = new Utils(this[editorSymbol]);
|
||||
}
|
||||
|
||||
objects = {
|
||||
TransformStage,
|
||||
};
|
||||
|
||||
get utils(): any {
|
||||
return this.__utils;
|
||||
}
|
||||
|
||||
get editorCabin(): any {
|
||||
const Setters = this[editorSymbol].get('setters');
|
||||
return {
|
||||
Title: InnerTitle,
|
||||
Tip: InnerTip,
|
||||
shallowIntl,
|
||||
createIntl: innerCreateIntl,
|
||||
intl,
|
||||
createSetterContent,
|
||||
createSetterContent: Setters.createSetterContent,
|
||||
obx,
|
||||
observable,
|
||||
makeObservable,
|
||||
|
||||
@ -7,12 +7,27 @@ import {
|
||||
import { dragonSymbol } from './symbols';
|
||||
import LocateEvent from './locate-event';
|
||||
import DragObject from './drag-object';
|
||||
import { globalContext } from '@alilc/lowcode-editor-core';
|
||||
|
||||
export const innerDragonSymbol = Symbol('innerDragonSymbol');
|
||||
|
||||
export default class Dragon {
|
||||
private readonly [dragonSymbol]: InnerDragon;
|
||||
private readonly [innerDragonSymbol]: InnerDragon;
|
||||
|
||||
get [dragonSymbol](): any {
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
let editor = globalContext.get('editor');
|
||||
|
||||
if (workSpace.isActive) {
|
||||
editor = workSpace.window.editor;
|
||||
}
|
||||
|
||||
const designer = editor.get('designer');
|
||||
return designer.dragon;
|
||||
}
|
||||
|
||||
constructor(dragon: InnerDragon) {
|
||||
this[dragonSymbol] = dragon;
|
||||
this[innerDragonSymbol] = dragon;
|
||||
}
|
||||
|
||||
static create(dragon: InnerDragon | null) {
|
||||
|
||||
@ -8,8 +8,10 @@ type EventOptions = {
|
||||
prefix: string;
|
||||
};
|
||||
|
||||
const innerEditorSymbol = Symbol('editor');
|
||||
|
||||
export default class Event {
|
||||
private readonly [editorSymbol]: InnerEditor;
|
||||
private readonly [innerEditorSymbol]: InnerEditor;
|
||||
private readonly options: EventOptions;
|
||||
|
||||
// TODO:
|
||||
@ -18,8 +20,20 @@ export default class Event {
|
||||
*/
|
||||
readonly names = [];
|
||||
|
||||
constructor(editor: InnerEditor, options: EventOptions) {
|
||||
this[editorSymbol] = editor;
|
||||
get [editorSymbol](): InnerEditor {
|
||||
if (this.workspaceMode) {
|
||||
return this[innerEditorSymbol];
|
||||
}
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
if (workSpace.isActive) {
|
||||
return workSpace.window.editor;
|
||||
}
|
||||
|
||||
return this[innerEditorSymbol];
|
||||
}
|
||||
|
||||
constructor(editor: InnerEditor, options: EventOptions, public workspaceMode = false) {
|
||||
this[innerEditorSymbol] = editor;
|
||||
this.options = options;
|
||||
if (!this.options.prefix) {
|
||||
logger.warn('prefix is required while initializing Event');
|
||||
|
||||
@ -2,6 +2,9 @@ import { hotkey, HotkeyCallback } from '@alilc/lowcode-editor-core';
|
||||
import { Disposable } from '@alilc/lowcode-types';
|
||||
|
||||
export default class Hotkey {
|
||||
constructor(public name: string = 'unknown', public workspaceMode: boolean = false) {
|
||||
}
|
||||
|
||||
get callbacks() {
|
||||
return hotkey.callBacks;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Editor } from '@alilc/lowcode-editor-core';
|
||||
import { Editor, globalContext } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
Designer,
|
||||
registerMetadataTransducer,
|
||||
@ -14,13 +14,32 @@ import { ComponentAction, ComponentMetadata } from '@alilc/lowcode-types';
|
||||
import { editorSymbol, designerSymbol } from './symbols';
|
||||
import ComponentMeta from './component-meta';
|
||||
|
||||
export default class Material {
|
||||
private readonly [editorSymbol]: Editor;
|
||||
private readonly [designerSymbol]: Designer;
|
||||
const innerEditorSymbol = Symbol('editor');
|
||||
|
||||
constructor(editor: Editor) {
|
||||
this[editorSymbol] = editor;
|
||||
this[designerSymbol] = editor.get('designer')!;
|
||||
export default class Material {
|
||||
// private readonly [editorSymbol]: Editor;
|
||||
private readonly [innerEditorSymbol]: Editor;
|
||||
// private readonly [designerSymbol]: Designer;
|
||||
|
||||
get [editorSymbol]() {
|
||||
if (this.workspaceMode) {
|
||||
return this[innerEditorSymbol];
|
||||
}
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
if (workSpace.isActive) {
|
||||
return workSpace.window.editor;
|
||||
}
|
||||
|
||||
return this[innerEditorSymbol];
|
||||
}
|
||||
|
||||
get [designerSymbol]() {
|
||||
return this[editorSymbol].get('designer')!;
|
||||
}
|
||||
|
||||
constructor(editor: Editor, public workspaceMode: boolean = false, public name: string = 'unknown') {
|
||||
this[innerEditorSymbol] = editor;
|
||||
// this[designerSymbol] = editor.get('designer')!;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -5,18 +5,32 @@ import {
|
||||
TransformStage,
|
||||
} from '@alilc/lowcode-designer';
|
||||
import { RootSchema, ProjectSchema, IEditor } from '@alilc/lowcode-types';
|
||||
import { globalContext } from '@alilc/lowcode-editor-core';
|
||||
import DocumentModel from './document-model';
|
||||
import SimulatorHost from './simulator-host';
|
||||
import { editorSymbol, projectSymbol, simulatorHostSymbol, simulatorRendererSymbol, documentSymbol } from './symbols';
|
||||
|
||||
const innerProjectSymbol = Symbol('project');
|
||||
|
||||
export default class Project {
|
||||
private readonly [projectSymbol]: InnerProject;
|
||||
private readonly [editorSymbol]: IEditor;
|
||||
private readonly [innerProjectSymbol]: InnerProject;
|
||||
private [simulatorHostSymbol]: BuiltinSimulatorHost;
|
||||
private [simulatorRendererSymbol]: any;
|
||||
get [projectSymbol]() {
|
||||
if (this.workspaceMode) {
|
||||
return this[innerProjectSymbol];
|
||||
}
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
if (workSpace.isActive) {
|
||||
return workSpace.window.innerProject;
|
||||
}
|
||||
|
||||
constructor(project: InnerProject) {
|
||||
this[projectSymbol] = project;
|
||||
return this[innerProjectSymbol];
|
||||
}
|
||||
|
||||
constructor(project: InnerProject, public workspaceMode: boolean = false) {
|
||||
this[innerProjectSymbol] = project;
|
||||
this[editorSymbol] = project?.designer.editor;
|
||||
}
|
||||
|
||||
|
||||
@ -1,23 +1,46 @@
|
||||
import { getSetter, registerSetter, getSettersMap, RegisteredSetter } from '@alilc/lowcode-editor-core';
|
||||
import { Setters as InnerSetters, RegisteredSetter, globalContext } from '@alilc/lowcode-editor-core';
|
||||
import { CustomView } from '@alilc/lowcode-types';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
const innerSettersSymbol = Symbol('setters');
|
||||
const settersSymbol = Symbol('setters');
|
||||
|
||||
export default class Setters {
|
||||
readonly [innerSettersSymbol]: InnerSetters;
|
||||
|
||||
get [settersSymbol](): InnerSetters {
|
||||
if (this.workspaceMode) {
|
||||
return this[innerSettersSymbol];
|
||||
}
|
||||
|
||||
const workSpace = globalContext.get('workSpace');
|
||||
if (workSpace.isActive) {
|
||||
return workSpace.window.innerSetters;
|
||||
}
|
||||
|
||||
return this[innerSettersSymbol];
|
||||
}
|
||||
|
||||
constructor(innerSetters: InnerSetters, readonly workspaceMode = false) {
|
||||
this[innerSettersSymbol] = innerSetters;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定 setter
|
||||
* @param type
|
||||
* @returns
|
||||
*/
|
||||
getSetter(type: string) {
|
||||
return getSetter(type);
|
||||
}
|
||||
getSetter = (type: string) => {
|
||||
return this[settersSymbol].getSetter(type);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取已注册的所有 settersMap
|
||||
* @returns
|
||||
*/
|
||||
getSettersMap() {
|
||||
return getSettersMap();
|
||||
}
|
||||
getSettersMap = () => {
|
||||
return this[settersSymbol].getSettersMap();
|
||||
};
|
||||
|
||||
/**
|
||||
* 注册一个 setter
|
||||
@ -25,10 +48,14 @@ export default class Setters {
|
||||
* @param setter
|
||||
* @returns
|
||||
*/
|
||||
registerSetter(
|
||||
registerSetter = (
|
||||
typeOrMaps: string | { [key: string]: CustomView | RegisteredSetter },
|
||||
setter?: CustomView | RegisteredSetter | undefined,
|
||||
) {
|
||||
return registerSetter(typeOrMaps, setter);
|
||||
}
|
||||
) => {
|
||||
return this[settersSymbol].registerSetter(typeOrMaps, setter);
|
||||
};
|
||||
|
||||
createSetterContent = (setter: any, props: Record<string, any>): ReactNode => {
|
||||
return this[settersSymbol].createSetterContent(setter, props);
|
||||
};
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ export default class SettingPropEntry {
|
||||
* 获取设置属性的 setter
|
||||
*/
|
||||
get setter() {
|
||||
return this[settingPropEntrySymbol].setter;
|
||||
return this[settingPropEntrySymbol].innerSetters;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -21,6 +21,8 @@ export interface SettingTarget {
|
||||
*/
|
||||
readonly editor: IEditor;
|
||||
|
||||
readonly setters: any;
|
||||
|
||||
/**
|
||||
* 访问路径
|
||||
*/
|
||||
|
||||
5
packages/workspace/build.json
Normal file
5
packages/workspace/build.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"plugins": [
|
||||
"build-plugin-component"
|
||||
]
|
||||
}
|
||||
6
packages/workspace/build.test.json
Normal file
6
packages/workspace/build.test.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": [
|
||||
"build-plugin-component",
|
||||
"@alilc/lowcode-test-mate/plugin/index.ts"
|
||||
]
|
||||
}
|
||||
9
packages/workspace/jest.config.js
Normal file
9
packages/workspace/jest.config.js
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: [
|
||||
'src/**/*.{ts,tsx}',
|
||||
'!**/node_modules/**',
|
||||
'!**/vendor/**',
|
||||
],
|
||||
};
|
||||
62
packages/workspace/package.json
Normal file
62
packages/workspace/package.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"name": "@alilc/lowcode-workspace",
|
||||
"version": "1.0.15",
|
||||
"description": "Shell Layer for AliLowCodeEngine",
|
||||
"main": "lib/index.js",
|
||||
"private": true,
|
||||
"module": "es/index.js",
|
||||
"files": [
|
||||
"lib",
|
||||
"es"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "build-scripts build --skip-demo",
|
||||
"test": "build-scripts test --config build.test.json",
|
||||
"test:cov": "build-scripts test --config build.test.json --jest-coverage"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alilc/lowcode-designer": "1.0.15",
|
||||
"@alilc/lowcode-editor-core": "1.0.15",
|
||||
"@alilc/lowcode-editor-skeleton": "1.0.15",
|
||||
"@alilc/lowcode-types": "1.0.15",
|
||||
"@alilc/lowcode-utils": "1.0.15",
|
||||
"classnames": "^2.2.6",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-react-16": "^1.15.5",
|
||||
"react": "^16",
|
||||
"react-dom": "^16.7.0",
|
||||
"zen-logger": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alib/build-scripts": "^0.1.29",
|
||||
"@alilc/lowcode-test-mate": "^1.0.1",
|
||||
"@testing-library/react": "^11.2.2",
|
||||
"@types/classnames": "^2.2.7",
|
||||
"@types/jest": "^26.0.16",
|
||||
"@types/lodash": "^4.14.165",
|
||||
"@types/medium-editor": "^5.0.3",
|
||||
"@types/node": "^13.7.1",
|
||||
"@types/react": "^16",
|
||||
"@types/react-dom": "^16",
|
||||
"babel-jest": "^26.5.2",
|
||||
"build-plugin-component": "^0.2.10",
|
||||
"build-scripts-config": "^0.1.8",
|
||||
"jest": "^26.6.3",
|
||||
"lodash": "^4.17.20",
|
||||
"moment": "^2.29.1",
|
||||
"typescript": "^4.0.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"resolutions": {
|
||||
"@builder/babel-preset-ice": "1.0.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "http",
|
||||
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/shell"
|
||||
},
|
||||
"gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
|
||||
}
|
||||
99
packages/workspace/src/base-context.ts
Normal file
99
packages/workspace/src/base-context.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import { Editor, engineConfig, Setters as InnerSetters } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
Designer,
|
||||
LowCodePluginManager,
|
||||
TransformStage,
|
||||
} from '@alilc/lowcode-designer';
|
||||
import {
|
||||
Skeleton as InnerSkeleton,
|
||||
} from '@alilc/lowcode-editor-skeleton';
|
||||
import {
|
||||
// EditorWindow,
|
||||
WorkSpace,
|
||||
} from '@alilc/lowcode-workspace';
|
||||
|
||||
import { Hotkey, Project, Skeleton, Setters, Material, Event } from '@alilc/lowcode-shell';
|
||||
import { getLogger } from '@alilc/lowcode-utils';
|
||||
import { setterRegistry } from 'engine/src/inner-plugins/setter-registry';
|
||||
import { componentMetaParser } from 'engine/src/inner-plugins/component-meta-parser';
|
||||
import defaultPanelRegistry from 'engine/src/inner-plugins/default-panel-registry';
|
||||
import { EditorWindow } from './editor-window/context';
|
||||
|
||||
export class BasicContext {
|
||||
skeleton;
|
||||
plugins;
|
||||
project;
|
||||
setters;
|
||||
material;
|
||||
config;
|
||||
event;
|
||||
logger;
|
||||
hotkey;
|
||||
innerProject;
|
||||
editor: Editor;
|
||||
designer;
|
||||
registerInnerPlugins: any;
|
||||
innerSetters: any;
|
||||
|
||||
constructor(workSpace: WorkSpace, name: string, public editorWindow?: EditorWindow) {
|
||||
const editor = new Editor(name, true);
|
||||
|
||||
// globalContext.register(editor, Editor);
|
||||
// globalContext.register(editor, 'editor');
|
||||
// if (editorWindow) {
|
||||
// }
|
||||
// const project = editorWindow ? editorWindow.project : new Project(innerProject);
|
||||
// if (editorWindow) {
|
||||
// }
|
||||
|
||||
const innerSkeleton = new InnerSkeleton(editor);
|
||||
editor.set('skeleton' as any, innerSkeleton);
|
||||
|
||||
const designer: Designer = new Designer({
|
||||
editor,
|
||||
name,
|
||||
});
|
||||
editor.set('designer' as any, designer);
|
||||
|
||||
const plugins = new LowCodePluginManager(editor).toProxy();
|
||||
editor.set('plugins' as any, plugins);
|
||||
|
||||
const { project: innerProject } = designer;
|
||||
const hotkey = new Hotkey(name);
|
||||
const innerSetters = new InnerSetters(name);
|
||||
const setters = new Setters(innerSetters, true);
|
||||
const material = new Material(editor, true);
|
||||
const project = new Project(innerProject, true);
|
||||
const config = engineConfig;
|
||||
const event = new Event(editor, { prefix: 'common' });
|
||||
const logger = getLogger({ level: 'warn', bizName: 'common' });
|
||||
editor.set('setters', setters);
|
||||
editor.set('project', project);
|
||||
editor.set('material', material);
|
||||
this.innerSetters = innerSetters;
|
||||
this.skeleton = innerSkeleton;
|
||||
this.plugins = plugins;
|
||||
this.innerProject = innerProject;
|
||||
this.project = project;
|
||||
this.setters = setters;
|
||||
this.material = material;
|
||||
this.config = config;
|
||||
this.event = event;
|
||||
this.logger = logger;
|
||||
this.hotkey = hotkey;
|
||||
this.editor = editor;
|
||||
this.designer = designer;
|
||||
|
||||
// 注册一批内置插件
|
||||
this.registerInnerPlugins = async function registerPlugins() {
|
||||
// console.log('ctx', ctx);
|
||||
await plugins.register(componentMetaParser(designer));
|
||||
await plugins.register(setterRegistry);
|
||||
await plugins.register(defaultPanelRegistry(editor, designer));
|
||||
};
|
||||
}
|
||||
|
||||
// get project() {
|
||||
// return this.editorWindow ? this.editorWindow.project : this._project;
|
||||
// }
|
||||
}
|
||||
4
packages/workspace/src/context.ts
Normal file
4
packages/workspace/src/context.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { createContext } from 'react';
|
||||
import { Skeleton } from './skeleton';
|
||||
|
||||
export const SkeletonContext = createContext<Skeleton>({} as any);
|
||||
35
packages/workspace/src/editor-view/context.ts
Normal file
35
packages/workspace/src/editor-view/context.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { makeObservable, obx, runInAction } from '@alilc/lowcode-editor-core';
|
||||
import { EditorViewOptions, EditorWindow } from '@alilc/lowcode-workspace';
|
||||
import { flow } from 'mobx';
|
||||
import { BasicContext } from '../base-context';
|
||||
|
||||
export class Context extends BasicContext {
|
||||
name = 'editor-view';
|
||||
|
||||
constructor(public workspace: any, public editorWindow: EditorWindow, public editorView: EditorViewOptions) {
|
||||
super(workspace, editorView.name, editorWindow);
|
||||
this.name = editorView.name;
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
@obx _activate = false;
|
||||
|
||||
setActivate = (_activate: boolean) => {
|
||||
this._activate = _activate;
|
||||
};
|
||||
|
||||
get active() {
|
||||
return this._activate;
|
||||
}
|
||||
|
||||
@obx isInit: boolean = false;
|
||||
|
||||
init = flow(function* (this: any) {
|
||||
yield this.registerInnerPlugins();
|
||||
yield this.editorView?.init(this.plugins._getLowCodePluginContext({
|
||||
pluginName: 'any',
|
||||
}));
|
||||
yield this.plugins.init();
|
||||
this.isInit = true;
|
||||
});
|
||||
}
|
||||
39
packages/workspace/src/editor-view/view.tsx
Normal file
39
packages/workspace/src/editor-view/view.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import { skeletonSymbol } from '@alilc/lowcode-shell';
|
||||
import { observer } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
Workbench,
|
||||
} from '@alilc/lowcode-editor-skeleton';
|
||||
import { Component } from 'react';
|
||||
import { Context } from './context';
|
||||
|
||||
export * from '../base-context';
|
||||
|
||||
@observer
|
||||
export class EditorView extends Component<any, any> {
|
||||
// 因为 document 数据在不同视图下使用的是同一份,所以这里通过 constructor 传入
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
// this.ctx = new Context(props.editorView);
|
||||
}
|
||||
|
||||
// ctx: Context;
|
||||
|
||||
render() {
|
||||
const { active } = this.props;
|
||||
const editorView = this.props.editorView;
|
||||
const skeleton = editorView.skeleton;
|
||||
if (!editorView.isInit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Workbench
|
||||
skeleton={skeleton}
|
||||
className={active ? 'active engine-editor-view' : 'engine-editor-view'}
|
||||
topAreaItemClassName="engine-actionitem"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
16
packages/workspace/src/editor-window.ts
Normal file
16
packages/workspace/src/editor-window.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { makeObservable, obx } from '@alilc/lowcode-editor-core';
|
||||
import { Resource } from './resource';
|
||||
|
||||
export class EditorWindow {
|
||||
constructor(public resource: Resource) {
|
||||
// debugger
|
||||
makeObservable(this);
|
||||
this.editorView = resource.getEditorView(this.resource.defaultViewType);
|
||||
}
|
||||
|
||||
@obx editorView;
|
||||
|
||||
changeViewType(name: string) {
|
||||
this.editorView = this.resource.getEditorView(name);
|
||||
}
|
||||
}
|
||||
82
packages/workspace/src/editor-window/context.ts
Normal file
82
packages/workspace/src/editor-window/context.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import { computed, makeObservable, obx } from '@alilc/lowcode-editor-core';
|
||||
import { Context } from '../editor-view/context';
|
||||
import { WorkSpace } from '..';
|
||||
import { Resource } from '../resource';
|
||||
|
||||
export class EditorWindow {
|
||||
constructor(public resource: Resource, public workspace: WorkSpace) {
|
||||
makeObservable(this);
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
await this.initViewTypes();
|
||||
await this.execViewTypesInit();
|
||||
this.setDefaultViewType();
|
||||
}
|
||||
|
||||
initViewTypes = async () => {
|
||||
const editorViews = this.resource.editorViews;
|
||||
for (let i = 0; i < editorViews.length; i++) {
|
||||
const name = editorViews[i].name;
|
||||
await this.initViewType(name);
|
||||
if (!this.editorView) {
|
||||
this.changeViewType(name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
execViewTypesInit = async () => {
|
||||
const editorViews = this.resource.editorViews;
|
||||
for (let i = 0; i < editorViews.length; i++) {
|
||||
const name = editorViews[i].name;
|
||||
this.changeViewType(name);
|
||||
await this.editorViews.get(name)?.init();
|
||||
}
|
||||
};
|
||||
|
||||
setDefaultViewType = () => {
|
||||
this.changeViewType(this.resource.defaultViewType);
|
||||
};
|
||||
|
||||
@obx.ref editorView: Context;
|
||||
|
||||
@obx editorViews: Map<string, Context> = new Map<string, Context>();
|
||||
|
||||
initViewType = async (name: string) => {
|
||||
const viewInfo = this.resource.getEditorView(name);
|
||||
if (this.editorViews.get(name)) {
|
||||
return;
|
||||
}
|
||||
const editorView = new Context(this.workspace, this, viewInfo as any);
|
||||
// await editorView.init();
|
||||
this.editorViews.set(name, editorView);
|
||||
};
|
||||
|
||||
changeViewType = (name: string) => {
|
||||
this.editorView?.setActivate(false);
|
||||
this.editorView = this.editorViews.get(name)!;
|
||||
|
||||
this.editorView.setActivate(true);
|
||||
};
|
||||
|
||||
get project() {
|
||||
return this.editorView?.project;
|
||||
}
|
||||
|
||||
get innerProject() {
|
||||
return this.editorView?.innerProject;
|
||||
}
|
||||
|
||||
get innerSetters() {
|
||||
return this.editorView?.innerSetters;
|
||||
}
|
||||
|
||||
get editor() {
|
||||
return this.editorView?.editor;
|
||||
}
|
||||
|
||||
get designer() {
|
||||
return this.editorView?.designer;
|
||||
}
|
||||
}
|
||||
45
packages/workspace/src/editor-window/view.tsx
Normal file
45
packages/workspace/src/editor-window/view.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
import { Component } from 'react';
|
||||
import { EditorView } from '../editor-view/view';
|
||||
import { observer } from '@alilc/lowcode-editor-core';
|
||||
import { EditorWindow } from './context';
|
||||
|
||||
@observer
|
||||
export class EditorWindowView extends Component<{
|
||||
editorWindow: EditorWindow;
|
||||
}, any> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { resource, editorView, editorViews } = this.props.editorWindow;
|
||||
// const editorViews = Array.from(editorViews.values())
|
||||
if (!editorView) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className="workspace-engine-main">
|
||||
{/* <EditorView
|
||||
resource={resource}
|
||||
key={editorView.name}
|
||||
active={editorView.active}
|
||||
editorView={editorView}
|
||||
defaultViewType
|
||||
/> */}
|
||||
{
|
||||
Array.from(editorViews.values()).map((editorView: any) => {
|
||||
return (
|
||||
<EditorView
|
||||
resource={resource}
|
||||
key={editorView.name}
|
||||
active={editorView.active}
|
||||
editorView={editorView}
|
||||
defaultViewType
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
76
packages/workspace/src/index.ts
Normal file
76
packages/workspace/src/index.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import { Editor } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
Skeleton as InnerSkeleton,
|
||||
} from '@alilc/lowcode-editor-skeleton';
|
||||
import { EditorWindow } from './editor-window/context';
|
||||
import { Resource } from './resource';
|
||||
export { Resource } from './resource';
|
||||
export * from './editor-window/context';
|
||||
export * from './layouts/workbench';
|
||||
|
||||
export class WorkSpace {
|
||||
constructor() {
|
||||
this.editor = new Editor();
|
||||
this.skeleton = new InnerSkeleton(this.editor);
|
||||
if (this.defaultResource) {
|
||||
this.window = new EditorWindow(this.defaultResource, this);
|
||||
}
|
||||
}
|
||||
|
||||
private _isActive = false;
|
||||
|
||||
get isActive() {
|
||||
return this._isActive;
|
||||
}
|
||||
|
||||
setActive(value: boolean) {
|
||||
this._isActive = value;
|
||||
}
|
||||
|
||||
editorWindows: [];
|
||||
|
||||
window: EditorWindow;
|
||||
|
||||
private resources: Map<string, Resource> = new Map();
|
||||
|
||||
registerResourceType(resourceName: string, resourceType: 'editor' | 'webview', options: ResourceOptions): void {
|
||||
if (resourceType === 'editor') {
|
||||
const resource = new Resource(options);
|
||||
this.resources.set(resourceName, resource);
|
||||
|
||||
if (!this.window) {
|
||||
this.window = new EditorWindow(this.defaultResource, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get defaultResource() {
|
||||
if (this.resources.size === 1) {
|
||||
return this.resources.values().next().value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
removeResourceType(resourceName: string) {
|
||||
if (this.resources.has(resourceName)) {
|
||||
this.resources.delete(resourceName);
|
||||
}
|
||||
}
|
||||
|
||||
openEditorWindow() {}
|
||||
}
|
||||
|
||||
export interface ResourceOptions {
|
||||
description: string;
|
||||
defaultViewType?: string;
|
||||
editorViews?: EditorViewOptions[];
|
||||
init: (ctx: any) => Promise<void>;
|
||||
dispose: (ctx: any) => Promise<void>;
|
||||
}
|
||||
|
||||
export interface EditorViewOptions {
|
||||
name: string;
|
||||
init: (ctx: any) => Promise<void>;
|
||||
save: (ctx: any) => Promise<void>;
|
||||
}
|
||||
35
packages/workspace/src/layouts/bottom-area.tsx
Normal file
35
packages/workspace/src/layouts/bottom-area.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import { Component, Fragment } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { observer } from '@alilc/lowcode-editor-core';
|
||||
import Area from '../area';
|
||||
import Panel from '../widget/panel';
|
||||
|
||||
@observer
|
||||
export default class BottomArea extends Component<{ area: Area<any, Panel> }> {
|
||||
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) => item.content)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
47
packages/workspace/src/layouts/left-area.tsx
Normal file
47
packages/workspace/src/layouts/left-area.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { Component, Fragment } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { observer } from '@alilc/lowcode-editor-core';
|
||||
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.slice().sort((a, b) => {
|
||||
const index1 = a.config?.index || 0;
|
||||
const index2 = b.config?.index || 0;
|
||||
return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1);
|
||||
}).forEach((item) => {
|
||||
const content = <div key={`left-area-${item.name}`}>{item.content}</div>;
|
||||
if (item.align === 'bottom') {
|
||||
bottom.push(content);
|
||||
} else {
|
||||
top.push(content);
|
||||
}
|
||||
});
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="lc-left-area-top">{top}</div>
|
||||
<div className="lc-left-area-bottom">{bottom}</div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
44
packages/workspace/src/layouts/left-fixed-pane.tsx
Normal file
44
packages/workspace/src/layouts/left-fixed-pane.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import { Component, Fragment } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { observer } from '@alilc/lowcode-editor-core';
|
||||
import Area from '../area';
|
||||
import { PanelConfig } from '../types';
|
||||
import Panel from '../widget/panel';
|
||||
|
||||
@observer
|
||||
export default class LeftFixedPane extends Component<{ area: Area<PanelConfig, Panel> }> {
|
||||
componentDidUpdate() {
|
||||
// FIXME: dirty fix, need deep think
|
||||
this.props.area.skeleton.editor.get('designer')?.touchOffsetObserver();
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const { area } = this.props;
|
||||
const width = area.current?.config.props?.width;
|
||||
const style = width
|
||||
? {
|
||||
width,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames('lc-left-fixed-pane', {
|
||||
'lc-area-visible': area.visible,
|
||||
})}
|
||||
style={style}
|
||||
>
|
||||
<Contents area={area} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@observer
|
||||
class Contents extends Component<{ area: Area<PanelConfig, Panel> }> {
|
||||
render() {
|
||||
const { area } = this.props;
|
||||
return <Fragment>{area.container.items.map((panel) => panel.content)}</Fragment>;
|
||||
}
|
||||
}
|
||||
131
packages/workspace/src/layouts/left-float-pane.tsx
Normal file
131
packages/workspace/src/layouts/left-float-pane.tsx
Normal file
@ -0,0 +1,131 @@
|
||||
import { Component, Fragment } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { observer, Focusable, focusTracker } from '@alilc/lowcode-editor-core';
|
||||
import Area from '../area';
|
||||
import Panel from '../widget/panel';
|
||||
|
||||
@observer
|
||||
export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }> {
|
||||
private dispose?: () => void;
|
||||
|
||||
private focusing?: Focusable;
|
||||
|
||||
private shell: HTMLElement | null = null;
|
||||
|
||||
componentDidMount() {
|
||||
const { area } = this.props;
|
||||
const triggerClose = (e: any) => {
|
||||
if (!area.visible) return;
|
||||
// 当 MouseEvent 的 target 为「插入占位符」时,不关闭当前 panel
|
||||
if (e.originalEvent?.target?.classList.contains('insertion')) return;
|
||||
// 假如当前操作 target 祖先节点中有属性 data-keep-visible-while-dragging="true" 代表该 target 所属 panel
|
||||
// 不希望 target 在 panel 范围内拖拽时关闭 panel
|
||||
const panelElem = e.originalEvent?.target.closest('div[data-keep-visible-while-dragging="true"]');
|
||||
if (panelElem) return;
|
||||
area.setVisible(false);
|
||||
};
|
||||
area.skeleton.editor.on('designer.drag', triggerClose);
|
||||
|
||||
this.dispose = () => {
|
||||
area.skeleton.editor.removeListener('designer.drag', triggerClose);
|
||||
};
|
||||
|
||||
this.focusing = focusTracker.create({
|
||||
range: (e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
if (!target) {
|
||||
return false;
|
||||
}
|
||||
if (this.shell?.contains(target)) {
|
||||
return true;
|
||||
}
|
||||
// 点击了 iframe 内容,算失焦
|
||||
if ((document.querySelector('.lc-simulator-content-frame') as HTMLIFrameElement)?.contentWindow?.document.documentElement.contains(target)) {
|
||||
return false;
|
||||
}
|
||||
// 点击设置区
|
||||
if (document.querySelector('.lc-right-area')?.contains(target)) {
|
||||
return false;
|
||||
}
|
||||
// 点击非编辑区域的popup/dialog,插件栏左侧等不触发失焦
|
||||
if (!document.querySelector('.lc-workbench')?.contains(target)) {
|
||||
return true;
|
||||
}
|
||||
// 排除设置区,iframe 之后,都不算失焦
|
||||
if (document.querySelector('.lc-workbench-body')?.contains(target)) {
|
||||
return true;
|
||||
}
|
||||
const docks = area.current?.getAssocDocks();
|
||||
if (docks && docks?.length) {
|
||||
return docks.some(dock => dock.getDOMNode()?.contains(target));
|
||||
}
|
||||
return false;
|
||||
},
|
||||
onEsc: () => {
|
||||
this.props.area.setVisible(false);
|
||||
},
|
||||
onBlur: () => {
|
||||
this.props.area.setVisible(false);
|
||||
},
|
||||
});
|
||||
|
||||
this.onEffect();
|
||||
}
|
||||
|
||||
onEffect() {
|
||||
const { area } = this.props;
|
||||
if (area.visible) {
|
||||
this.focusing?.active();
|
||||
// 关闭当前fixed区域的面板
|
||||
// TODO: 看看有没有更合适的地方
|
||||
const fixedContainer = area?.skeleton?.leftFixedArea?.container;
|
||||
const currentFixed = fixedContainer?.current;
|
||||
if (currentFixed) {
|
||||
fixedContainer.unactive(currentFixed);
|
||||
}
|
||||
} else {
|
||||
this.focusing?.suspense();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.onEffect();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.focusing?.purge();
|
||||
this.dispose?.();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { area } = this.props;
|
||||
const width = area.current?.config.props?.width;
|
||||
|
||||
const style = width ? {
|
||||
width,
|
||||
} : undefined;
|
||||
return (
|
||||
<div
|
||||
ref={(ref) => { this.shell = ref; }}
|
||||
className={classNames('lc-left-float-pane', {
|
||||
'lc-area-visible': area.visible,
|
||||
})}
|
||||
style={style}
|
||||
>
|
||||
<Contents area={area} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@observer
|
||||
class Contents extends Component<{ area: Area<any, Panel> }> {
|
||||
render() {
|
||||
const { area } = this.props;
|
||||
return (
|
||||
<Fragment>
|
||||
{area.container.items.map((panel) => panel.content)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
18
packages/workspace/src/layouts/main-area.tsx
Normal file
18
packages/workspace/src/layouts/main-area.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { Component } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { observer } from '@alilc/lowcode-editor-core';
|
||||
import Area from '../area';
|
||||
import Panel from '../widget/panel';
|
||||
import Widget from '../widget/widget';
|
||||
|
||||
@observer
|
||||
export default class MainArea extends Component<{ area: Area<any, Panel | Widget> }> {
|
||||
render() {
|
||||
const { area } = this.props;
|
||||
return (
|
||||
<div className={classNames('lc-main-area engine-workspacepane')}>
|
||||
{area.container.items.map((item) => item.content)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
62
packages/workspace/src/layouts/theme.less
Normal file
62
packages/workspace/src/layouts/theme.less
Normal file
@ -0,0 +1,62 @@
|
||||
@import '../less-variables.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);
|
||||
|
||||
--pane-title-bg-color: rgba(31,56,88,.04);
|
||||
}
|
||||
62
packages/workspace/src/layouts/top-area.tsx
Normal file
62
packages/workspace/src/layouts/top-area.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import { Component, Fragment } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { observer } from '@alilc/lowcode-editor-core';
|
||||
import Area from '../area';
|
||||
|
||||
@observer
|
||||
export default class TopArea extends Component<{ area: Area; itemClassName?: string }> {
|
||||
render() {
|
||||
const { area, itemClassName } = this.props;
|
||||
|
||||
if (!area?.container?.items?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames('lc-top-area engine-actionpane', {
|
||||
'lc-area-visible': area.visible,
|
||||
})}
|
||||
>
|
||||
<Contents area={area} itemClassName={itemClassName} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@observer
|
||||
class Contents extends Component<{ area: Area; itemClassName?: string }> {
|
||||
render() {
|
||||
const { area, itemClassName } = this.props;
|
||||
const left: any[] = [];
|
||||
const center: any[] = [];
|
||||
const right: any[] = [];
|
||||
area.container.items.slice().sort((a, b) => {
|
||||
const index1 = a.config?.index || 0;
|
||||
const index2 = b.config?.index || 0;
|
||||
return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1);
|
||||
}).forEach(item => {
|
||||
const content = (
|
||||
<div className={itemClassName || ''} key={`top-area-${item.name}`}>
|
||||
{item.content}
|
||||
</div>
|
||||
);
|
||||
if (item.align === 'center') {
|
||||
center.push(content);
|
||||
} else if (item.align === 'left') {
|
||||
left.push(content);
|
||||
} else {
|
||||
right.push(content);
|
||||
}
|
||||
});
|
||||
if (!center || !center.length) {
|
||||
return null;
|
||||
}
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
398
packages/workspace/src/layouts/workbench.less
Normal file
398
packages/workspace/src/layouts/workbench.less
Normal file
@ -0,0 +1,398 @@
|
||||
@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: 48px;
|
||||
--right-area-width: 300px;
|
||||
--top-area-height: 48px;
|
||||
--toolbar-height: 36px;
|
||||
--dock-pane-width: 300px;
|
||||
--dock-fixed-pane-width: 300px;
|
||||
}
|
||||
|
||||
@media (min-width: 1860px) {
|
||||
:root {
|
||||
--right-area-width: 400px;
|
||||
--dock-pane-width: 452px;
|
||||
--dock-fixed-pane-width: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
.lc-titled-panel {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
background-color: var(--color-pane-background);
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
.lc-panel-title {
|
||||
// background-color: var(--pane-title-bg-color,rgba(31,56,88,.04));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 0 15px;
|
||||
|
||||
.lc-help-tip {
|
||||
margin-left: 4px;
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
> .lc-panel-title {
|
||||
height: 48px;
|
||||
font-size: 16px;
|
||||
padding: 0 15px;
|
||||
// border-bottom: 1px solid var(--color-line-normal,rgba(31,56,88,.1));
|
||||
color: #0f1726;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.lc-panel-body {
|
||||
position: absolute;
|
||||
top: 48px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow: visible;
|
||||
/*
|
||||
.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;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
.lc-outline-tree-container {
|
||||
border-top: 1px solid var(--color-line-normal, rgba(31, 56, 88, 0.1));
|
||||
}
|
||||
}
|
||||
.lc-panel {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
background-color: var(--color-pane-background);
|
||||
// overflow: auto;
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.lc-workspace-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: none;
|
||||
margin-bottom: 2px;
|
||||
padding: 8px 12px 8px 16px;
|
||||
|
||||
&.lc-area-visible {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.lc-top-area-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.lc-top-area-center {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 0 8px;
|
||||
}
|
||||
.lc-top-area-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
> * {
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.ve-quick-search-trigger {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
.lc-workspace-workbench-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
position: relative;
|
||||
|
||||
.lc-tabs-title {
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
position: relative;
|
||||
display: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
// background: rgba(31,56,88,0.04);
|
||||
border-bottom: 1px solid #edeff3;
|
||||
.lc-tab-title {
|
||||
flex: 1;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-bottom: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
&.actived {
|
||||
color: #0079f2;
|
||||
border-bottom-color: #0079f2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lc-tabs-content {
|
||||
position: absolute;
|
||||
top: 32px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.lc-pane-icon-close {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 14px;
|
||||
height: auto;
|
||||
z-index: 2;
|
||||
.next-icon {
|
||||
line-height: 1;
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.lc-pane-icon-fix,
|
||||
.lc-pane-icon-float {
|
||||
position: absolute;
|
||||
right: 38px;
|
||||
top: 14px;
|
||||
height: auto;
|
||||
z-index: 2;
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.lc-left-float-pane {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: var(--dock-pane-width);
|
||||
// min-width: var(--dock-fixed-pane-width);
|
||||
left: calc(var(--left-area-width) + 1px);
|
||||
background-color: var(--color-pane-background);
|
||||
box-shadow: 4px 6px 6px 0 rgba(31, 50, 88, 0.08);
|
||||
z-index: 820;
|
||||
display: none;
|
||||
// padding-top: 36px;
|
||||
&.lc-area-visible {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.lc-left-area {
|
||||
height: 100%;
|
||||
width: var(--left-area-width);
|
||||
background-color: var(--color-pane-background);
|
||||
display: none;
|
||||
flex-shrink: 0;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
overflow: hidden;
|
||||
&.lc-area-visible {
|
||||
display: flex;
|
||||
}
|
||||
.lc-left-area-top,
|
||||
.lc-left-area-bottom {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
.lc-title {
|
||||
flex-direction: column;
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.has-tip {
|
||||
cursor: pointer;
|
||||
}
|
||||
&.actived {
|
||||
color: #0079f2;
|
||||
}
|
||||
&.disabled {
|
||||
opacity: 0.4;
|
||||
}
|
||||
.lc-title-icon {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
margin: 0;
|
||||
.next-icon:before {
|
||||
line-height: 1 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.lc-left-area-top {
|
||||
padding-top: 12px;
|
||||
}
|
||||
.lc-left-area-bottom {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
}
|
||||
.lc-left-fixed-pane {
|
||||
width: var(--dock-fixed-pane-width);
|
||||
background-color: var(--color-pane-background);
|
||||
height: 100%;
|
||||
display: none;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 820;
|
||||
&.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-workspace-workbench-center {
|
||||
margin-left: 2px;
|
||||
}
|
||||
.lc-outline-pane {
|
||||
.lc-outline-tree .tree-node .tree-node-title {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
.lc-workspace-workbench-center {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 10;
|
||||
.lc-toolbar {
|
||||
display: flex;
|
||||
height: var(--toolbar-height);
|
||||
background-color: var(--color-pane-background);
|
||||
padding: 8px 16px;
|
||||
.lc-toolbar-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.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;
|
||||
flex-shrink: 0;
|
||||
margin-left: 2px;
|
||||
position: relative;
|
||||
> .lc-panel {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
&.lc-area-visible {
|
||||
display: block;
|
||||
}
|
||||
.lc-settings-tabs {
|
||||
> .next-tabs-nav-extra {
|
||||
top: 36px !important;
|
||||
}
|
||||
.lc-settings-tab-item {
|
||||
.next-tabs-tab-inner {
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
}
|
||||
}
|
||||
.lc-title {
|
||||
color: inherit;
|
||||
line-height: inherit !important;
|
||||
}
|
||||
}
|
||||
.lc-settings-tabs-content {
|
||||
top: 66px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
packages/workspace/src/layouts/workbench.tsx
Normal file
56
packages/workspace/src/layouts/workbench.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import { Component } from 'react';
|
||||
import { TipContainer, observer } from '@alilc/lowcode-editor-core';
|
||||
import { EditorWindowView } from '../editor-window/view';
|
||||
import classNames from 'classnames';
|
||||
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';
|
||||
import { SkeletonContext } from '../context';
|
||||
import { EditorConfig, PluginClassSet } from '@alilc/lowcode-types';
|
||||
import { WorkSpace } from '..';
|
||||
|
||||
@observer
|
||||
export class Workbench extends Component<{ workSpace: WorkSpace; config?: EditorConfig; components?: PluginClassSet; className?: string; topAreaItemClassName?: string }> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
const { config, components, workSpace } = this.props;
|
||||
const { skeleton } = workSpace;
|
||||
skeleton.buildFromConfig(config, components);
|
||||
}
|
||||
|
||||
// componentDidCatch(error: any) {
|
||||
// globalContext.get(Editor).emit('editor.skeleton.workbench.error', error);
|
||||
// }
|
||||
|
||||
render() {
|
||||
const { workSpace, className, topAreaItemClassName } = this.props;
|
||||
const { skeleton } = workSpace;
|
||||
return (
|
||||
<div className={classNames('lc-workspace-workbench', className)}>
|
||||
<SkeletonContext.Provider value={skeleton}>
|
||||
<TopArea area={skeleton.topArea} itemClassName={topAreaItemClassName} />
|
||||
<div className="lc-workspace-workbench-body">
|
||||
<LeftArea area={skeleton.leftArea} />
|
||||
<LeftFloatPane area={skeleton.leftFloatArea} />
|
||||
<LeftFixedPane area={skeleton.leftFixedArea} />
|
||||
<div className="lc-workspace-workbench-center">
|
||||
{/* <Toolbar area={skeleton.toolbar} /> */}
|
||||
<EditorWindowView editorWindow={workSpace.window} />
|
||||
<MainArea area={skeleton.mainArea} />
|
||||
<BottomArea area={skeleton.bottomArea} />
|
||||
</div>
|
||||
{/* <RightArea area={skeleton.rightArea} /> */}
|
||||
</div>
|
||||
<TipContainer />
|
||||
</SkeletonContext.Provider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
215
packages/workspace/src/less-variables.less
Normal file
215
packages/workspace/src/less-variables.less
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* 基础的 DPL 定义使用了 kuma base 的定义,参考:
|
||||
* https://github.com/uxcore/kuma-base/tree/master/variables
|
||||
*/
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* ==================== Font Family ==========================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* @font-family: "STHeiti", "Microsoft Yahei", "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;
|
||||
*/
|
||||
|
||||
@font-family: 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Helvetica, Arial, sans-serif;
|
||||
@font-family-code: Monaco, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Helvetica, Arial,
|
||||
sans-serif;
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* ===================== Color DPL ===========================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
@brand-color-1: rgba(0, 108, 255, 1);
|
||||
@brand-color-2: rgba(25, 122, 255, 1);
|
||||
@brand-color-3: rgba(0, 96, 229, 1);
|
||||
|
||||
@brand-color-1-3: rgba(0, 108, 255, 0.6);
|
||||
@brand-color-1-4: rgba(0, 108, 255, 0.4);
|
||||
@brand-color-1-5: rgba(0, 108, 255, 0.3);
|
||||
@brand-color-1-6: rgba(0, 108, 255, 0.2);
|
||||
@brand-color-1-7: rgba(0, 108, 255, 0.1);
|
||||
|
||||
@brand-color: @brand-color-1;
|
||||
|
||||
@white-alpha-1: rgb(255, 255, 255); // W-1
|
||||
@white-alpha-2: rgba(255, 255, 255, 0.8); // W-2 A80
|
||||
@white-alpha-3: rgba(255, 255, 255, 0.6); // W-3 A60
|
||||
@white-alpha-4: rgba(255, 255, 255, 0.4); // W-4 A40
|
||||
@white-alpha-5: rgba(255, 255, 255, 0.3); // W-5 A30
|
||||
@white-alpha-6: rgba(255, 255, 255, 0.2); // W-6 A20
|
||||
@white-alpha-7: rgba(255, 255, 255, 0.1); // W-7 A10
|
||||
@white-alpha-8: rgba(255, 255, 255, 0.06); // W-8 A6
|
||||
|
||||
@dark-alpha-1: rgba(0, 0, 0, 1); // D-1 A100
|
||||
@dark-alpha-2: rgba(0, 0, 0, 0.8); // D-2 A80
|
||||
@dark-alpha-3: rgba(0, 0, 0, 0.6); // D-3 A60
|
||||
@dark-alpha-4: rgba(0, 0, 0, 0.4); // D-4 A40
|
||||
@dark-alpha-5: rgba(0, 0, 0, 0.3); // D-5 A30
|
||||
@dark-alpha-6: rgba(0, 0, 0, 0.2); // D-6 A20
|
||||
@dark-alpha-7: rgba(0, 0, 0, 0.1); // D-7 A10
|
||||
@dark-alpha-8: rgba(0, 0, 0, 0.06); // D-8 A6
|
||||
@dark-alpha-9: rgba(0, 0, 0, 0.04); // D-9 A4
|
||||
|
||||
@normal-alpha-1: rgba(31, 56, 88, 1); // N-1 A100
|
||||
@normal-alpha-2: rgba(31, 56, 88, 0.8); // N-2 A80
|
||||
@normal-alpha-3: rgba(31, 56, 88, 0.6); // N-3 A60
|
||||
@normal-alpha-4: rgba(31, 56, 88, 0.4); // N-4 A40
|
||||
@normal-alpha-5: rgba(31, 56, 88, 0.3); // N-5 A30
|
||||
@normal-alpha-6: rgba(31, 56, 88, 0.2); // N-6 A20
|
||||
@normal-alpha-7: rgba(31, 56, 88, 0.1); // N-7 A10
|
||||
@normal-alpha-8: rgba(31, 56, 88, 0.06); // N-8 A6
|
||||
@normal-alpha-9: rgba(31, 56, 88, 0.04); // N-9 A4
|
||||
|
||||
@normal-3: #77879c;
|
||||
@normal-4: #a3aebd;
|
||||
@normal-5: #bac3cc;
|
||||
@normal-6: #d1d7de;
|
||||
|
||||
@gray-dark: #333; // N2_4
|
||||
@gray: #666; // N2_3
|
||||
@gray-light: #999; // N2_2
|
||||
@gray-lighter: #ccc; // N2_1
|
||||
|
||||
@brand-secondary: #2c2f33; // B2_3
|
||||
// 补色
|
||||
@brand-complement: #00b3e8; // B3_1
|
||||
// 复合
|
||||
@brand-comosite: #00c587; // B3_2
|
||||
// 浓度
|
||||
@brand-deep: #73461d; // B3_3
|
||||
|
||||
// F1-1
|
||||
@brand-danger: rgb(240, 70, 49);
|
||||
// F1-2 (10% white)
|
||||
@brand-danger-hover: rgba(240, 70, 49, 0.9);
|
||||
// F1-3 (5% black)
|
||||
@brand-danger-focus: rgba(240, 70, 49, 0.95);
|
||||
|
||||
// F2-1
|
||||
@brand-warning: rgb(250, 189, 14);
|
||||
// F3-1
|
||||
@brand-success: rgb(102, 188, 92);
|
||||
// F4-1
|
||||
@brand-link: rgb(102, 188, 92);
|
||||
// F4-2
|
||||
@brand-link-hover: #2e76a6;
|
||||
|
||||
// F1-1-7 A10
|
||||
@brand-danger-alpha-7: rgba(240, 70, 49, 0.9);
|
||||
// F1-1-8 A6
|
||||
@brand-danger-alpha-8: rgba(240, 70, 49, 0.8);
|
||||
// F2-1-2 A80
|
||||
@brand-warning-alpha-2: rgba(250, 189, 14, 0.8);
|
||||
// F2-1-7 A10
|
||||
@brand-warning-alpha-7: rgba(250, 189, 14, 0.9);
|
||||
// F3-1-2 A80
|
||||
@brand-success-alpha-2: rgba(102, 188, 92, 0.8);
|
||||
// F3-1-7 A10
|
||||
@brand-success-alpha-7: rgba(102, 188, 92, 0.9);
|
||||
// F4-1-7 A10
|
||||
@brand-link-alpha-7: rgba(102, 188, 92, 0.9);
|
||||
|
||||
// 文本色
|
||||
@text-primary-color: @dark-alpha-3;
|
||||
@text-secondary-color: @normal-alpha-3;
|
||||
@text-thirdary-color: @dark-alpha-4;
|
||||
@text-disabled-color: @normal-alpha-5;
|
||||
@text-helper-color: @dark-alpha-4;
|
||||
@text-danger-color: @brand-danger;
|
||||
@text-ali-color: #ec6c00;
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* =================== Shadow Box ============================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
@box-shadow-1: 0 1px 4px 0 rgba(31, 56, 88, 0.15); // 1 级阴影,物体由原来存在于底面的物体展开,物体和底面关联紧密
|
||||
@box-shadow-2: 0 2px 10px 0 rgba(31, 56, 88, 0.15); // 2 级阴影,hover状态,物体层级较高
|
||||
@box-shadow-3: 0 4px 15px 0 rgba(31, 56, 88, 0.15); // 3 级阴影,当物体层级高于所有界面元素,弹窗用
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* ================= FontSize of Level =======================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
@fontSize-1: 26px;
|
||||
@fontSize-2: 20px;
|
||||
@fontSize-3: 16px;
|
||||
@fontSize-4: 14px;
|
||||
@fontSize-5: 12px;
|
||||
|
||||
@fontLineHeight-1: 38px;
|
||||
@fontLineHeight-2: 30px;
|
||||
@fontLineHeight-3: 26px;
|
||||
@fontLineHeight-4: 24px;
|
||||
@fontLineHeight-5: 20px;
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* ================= FontSize of Level =======================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
@global-border-radius: 3px;
|
||||
@input-border-radius: 3px;
|
||||
@popup-border-radius: 6px;
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* ===================== Transistion =========================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
@transition-duration: 0.3s;
|
||||
@transition-ease: cubic-bezier(0.23, 1, 0.32, 1);
|
||||
@transition-delay: 0s;
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* ================ Global Configruations ====================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
@topPaneHeight: 48px;
|
||||
@actionpane-height: 48px;
|
||||
@tabPaneWidth: 260px;
|
||||
@input-standard-height: 32px;
|
||||
@dockpane-width: 48px;
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* =================== Deprecated Items ======================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
@head-bgcolor: @white-alpha-1;
|
||||
@pane-bgcolor: @white-alpha-1;
|
||||
@pane-dark-bgcolor: @white-alpha-1;
|
||||
@pane-bdcolor: @normal-4;
|
||||
@blank-bgcolor: @normal-5;
|
||||
@title-bgcolor: @white-alpha-1;
|
||||
@title-bdcolor: transparent;
|
||||
@section-bgcolor: transparent;
|
||||
@section-bdcolor: @white-alpha-1;
|
||||
@button-bgcolor: @white-alpha-1;
|
||||
@button-bdcolor: transparent;
|
||||
@button-blue-color: @brand-color;
|
||||
@button-blue-hover-color: @brand-color;
|
||||
@sub-title-bgcolor: @white-alpha-1;
|
||||
@sub-title-bdcolor: transparent;
|
||||
@text-color: @text-primary-color;
|
||||
@icon-color: @gray;
|
||||
@icon-color-active: @gray-light;
|
||||
@ghost-bgcolor: @dark-alpha-3;
|
||||
@input-bgcolor: transparent;
|
||||
@input-bdcolor: @normal-alpha-5;
|
||||
@hover-color: #5a99cc;
|
||||
@active-color: #5a99cc;
|
||||
@disabled-color: #666;
|
||||
@setter-popup-bg: rgb(80, 86, 109);
|
||||
33
packages/workspace/src/resource.ts
Normal file
33
packages/workspace/src/resource.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { EditorViewOptions, ResourceOptions } from '.';
|
||||
|
||||
export class Resource {
|
||||
constructor(options: ResourceOptions) {
|
||||
if (options.editorViews) {
|
||||
options.editorViews.forEach((d: any) => {
|
||||
this.editorViewMap.set(d.name, d);
|
||||
});
|
||||
}
|
||||
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
options: ResourceOptions;
|
||||
|
||||
editorViewMap: Map<string, EditorViewOptions> = new Map<string, EditorViewOptions>();
|
||||
|
||||
init(ctx: any) {
|
||||
this.options.init(ctx);
|
||||
}
|
||||
|
||||
getEditorView(name: string) {
|
||||
return this.editorViewMap.get(name);
|
||||
}
|
||||
|
||||
get defaultViewType() {
|
||||
return this.options.defaultViewType || this.editorViewMap.keys().next().value;
|
||||
}
|
||||
|
||||
get editorViews() {
|
||||
return Array.from(this.editorViewMap.values());
|
||||
}
|
||||
}
|
||||
406
packages/workspace/src/skeleton.ts
Normal file
406
packages/workspace/src/skeleton.ts
Normal file
@ -0,0 +1,406 @@
|
||||
import { Editor, action, makeObservable } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
DockConfig,
|
||||
PanelConfig,
|
||||
WidgetConfig,
|
||||
IWidgetBaseConfig,
|
||||
PanelDockConfig,
|
||||
DialogDockConfig,
|
||||
isDockConfig,
|
||||
isPanelDockConfig,
|
||||
isPanelConfig,
|
||||
DividerConfig,
|
||||
isDividerConfig,
|
||||
IWidgetConfigArea,
|
||||
} from './types';
|
||||
import Panel, { isPanel } from './widget/panel';
|
||||
import WidgetContainer from './widget/widget-container';
|
||||
import Area from './area';
|
||||
import Widget, { isWidget, IWidget } from './widget/widget';
|
||||
import PanelDock from './widget/panel-dock';
|
||||
import Dock from './widget/dock';
|
||||
import { Stage, StageConfig } from './widget/stage';
|
||||
import { isValidElement } from 'react';
|
||||
import { isPlainObject, uniqueId } from '@alilc/lowcode-utils';
|
||||
import { Divider } from '@alifd/next';
|
||||
import { EditorConfig, PluginClassSet } from '@alilc/lowcode-types';
|
||||
|
||||
export enum SkeletonEvents {
|
||||
PANEL_DOCK_ACTIVE = 'skeleton.panel-dock.active',
|
||||
PANEL_DOCK_UNACTIVE = 'skeleton.panel-dock.unactive',
|
||||
PANEL_SHOW = 'skeleton.panel.show',
|
||||
PANEL_HIDE = 'skeleton.panel.hide',
|
||||
WIDGET_SHOW = 'skeleton.widget.show',
|
||||
WIDGET_HIDE = 'skeleton.widget.hide',
|
||||
WIDGET_DISABLE = 'skeleton.widget.disable',
|
||||
WIDGET_ENABLE = 'skeleton.widget.enable',
|
||||
}
|
||||
|
||||
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 | DividerConfig | PanelDockConfig | DialogDockConfig>;
|
||||
|
||||
readonly toolbar: Area<DockConfig | DividerConfig | 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) {
|
||||
makeObservable(this);
|
||||
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);
|
||||
},
|
||||
false,
|
||||
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);
|
||||
});
|
||||
|
||||
this.setupPlugins();
|
||||
this.setupEvents();
|
||||
}
|
||||
/**
|
||||
* setup events
|
||||
*
|
||||
* @memberof Skeleton
|
||||
*/
|
||||
setupEvents() {
|
||||
// adjust pinned status when panel shown
|
||||
this.editor.on('skeleton.panel.show', (panelName, panel) => {
|
||||
const panelNameKey = `${panelName}-pinned-status-isFloat`;
|
||||
const isInFloatAreaPreferenceExists = this.editor?.getPreference()?.contains(panelNameKey, 'skeleton');
|
||||
if (isInFloatAreaPreferenceExists) {
|
||||
const isInFloatAreaFromPreference = this.editor?.getPreference()?.get(panelNameKey, 'skeleton');
|
||||
const isCurrentInFloatArea = panel?.isChildOfFloatArea();
|
||||
if (isInFloatAreaFromPreference !== isCurrentInFloatArea) {
|
||||
this.toggleFloatStatus(panel);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* set isFloat status for panel
|
||||
*
|
||||
* @param {*} panel
|
||||
* @memberof Skeleton
|
||||
*/
|
||||
@action
|
||||
toggleFloatStatus(panel: Panel) {
|
||||
const isFloat = panel?.parent?.name === 'leftFloatArea';
|
||||
if (isFloat) {
|
||||
this.leftFloatArea.remove(panel);
|
||||
this.leftFixedArea.add(panel);
|
||||
this.leftFixedArea.container.active(panel);
|
||||
} else {
|
||||
this.leftFixedArea.remove(panel);
|
||||
this.leftFloatArea.add(panel);
|
||||
this.leftFloatArea.container.active(panel);
|
||||
}
|
||||
this.editor?.getPreference()?.set(`${panel.name}-pinned-status-isFloat`, !isFloat, 'skeleton');
|
||||
}
|
||||
|
||||
buildFromConfig(config?: EditorConfig, components: PluginClassSet = {}) {
|
||||
if (config) {
|
||||
this.editor.init(config, components);
|
||||
}
|
||||
this.setupPlugins();
|
||||
}
|
||||
|
||||
private setupPlugins() {
|
||||
const { config, components = {} } = this.editor;
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { plugins } = config;
|
||||
if (!plugins) {
|
||||
return;
|
||||
}
|
||||
Object.keys(plugins).forEach((area) => {
|
||||
plugins[area].forEach((item) => {
|
||||
const { pluginKey, type, props = {}, pluginProps } = item;
|
||||
const config: Partial<IWidgetBaseConfig> = {
|
||||
area: area as IWidgetConfigArea,
|
||||
type: 'Widget',
|
||||
name: pluginKey,
|
||||
contentProps: pluginProps,
|
||||
};
|
||||
const { dialogProps, balloonProps, panelProps, linkProps, ...restProps } = props;
|
||||
config.props = restProps;
|
||||
if (dialogProps) {
|
||||
config.dialogProps = dialogProps;
|
||||
}
|
||||
if (balloonProps) {
|
||||
config.balloonProps = balloonProps;
|
||||
}
|
||||
if (panelProps) {
|
||||
config.panelProps = panelProps;
|
||||
}
|
||||
if (linkProps) {
|
||||
config.linkProps = linkProps;
|
||||
}
|
||||
if (type === 'TabPanel') {
|
||||
config.type = 'Panel';
|
||||
} else if (/Icon$/.test(type)) {
|
||||
config.type = type.replace('Icon', 'Dock');
|
||||
}
|
||||
if (pluginKey in components) {
|
||||
config.content = components[pluginKey];
|
||||
}
|
||||
this.add(config as IWidgetBaseConfig);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
postEvent(event: SkeletonEvents, ...args: any[]) {
|
||||
this.editor.emit(event, ...args);
|
||||
}
|
||||
|
||||
readonly widgets: IWidget[] = [];
|
||||
|
||||
createWidget(config: IWidgetBaseConfig | IWidget) {
|
||||
if (isWidget(config)) {
|
||||
return config;
|
||||
}
|
||||
|
||||
config = this.parseConfig(config);
|
||||
let widget: IWidget;
|
||||
if (isDockConfig(config)) {
|
||||
if (isPanelDockConfig(config)) {
|
||||
widget = new PanelDock(this, config);
|
||||
} else if (false) {
|
||||
// DialogDock
|
||||
// others...
|
||||
} else {
|
||||
widget = new Dock(this, config);
|
||||
}
|
||||
} else if (isDividerConfig(config)) {
|
||||
widget = new Widget(this, {
|
||||
...config,
|
||||
type: 'Widget',
|
||||
content: Divider,
|
||||
});
|
||||
} else if (isPanelConfig(config)) {
|
||||
widget = this.createPanel(config);
|
||||
} else {
|
||||
widget = new Widget(this, config as WidgetConfig);
|
||||
}
|
||||
this.widgets.push(widget);
|
||||
return widget;
|
||||
}
|
||||
|
||||
getWidget(name: string): IWidget | undefined {
|
||||
return this.widgets.find(widget => widget.name === name);
|
||||
}
|
||||
|
||||
createPanel(config: PanelConfig) {
|
||||
const parsedConfig = this.parseConfig(config);
|
||||
const panel = new Panel(this, parsedConfig as PanelConfig);
|
||||
this.panels.set(panel.name, panel);
|
||||
return panel;
|
||||
}
|
||||
|
||||
getPanel(name: string): Panel | undefined {
|
||||
return this.panels.get(name);
|
||||
}
|
||||
|
||||
getStage(name: string) {
|
||||
return this.stages.container.get(name);
|
||||
}
|
||||
|
||||
createStage(config: any) {
|
||||
const stage = this.add({
|
||||
name: uniqueId('stage'),
|
||||
area: 'stages',
|
||||
...config,
|
||||
});
|
||||
return stage?.getName?.();
|
||||
}
|
||||
|
||||
createContainer(
|
||||
name: string,
|
||||
handle: (item: any) => any,
|
||||
exclusive = false,
|
||||
checkVisible: () => boolean = () => true,
|
||||
defaultSetCurrent = false,
|
||||
) {
|
||||
const container = new WidgetContainer(name, handle, exclusive, checkVisible, defaultSetCurrent);
|
||||
this.containers.set(name, container);
|
||||
return container;
|
||||
}
|
||||
|
||||
private parseConfig(config: IWidgetBaseConfig) {
|
||||
if (config.parsed) {
|
||||
return config;
|
||||
}
|
||||
const { content, ...restConfig } = config;
|
||||
if (content) {
|
||||
if (isPlainObject(content) && !isValidElement(content)) {
|
||||
Object.keys(content).forEach((key) => {
|
||||
if (/props$/i.test(key) && restConfig[key]) {
|
||||
restConfig[key] = {
|
||||
...restConfig[key],
|
||||
...content[key],
|
||||
};
|
||||
} else {
|
||||
restConfig[key] = content[key];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
restConfig.content = content;
|
||||
}
|
||||
}
|
||||
restConfig.pluginKey = restConfig.name;
|
||||
restConfig.parsed = true;
|
||||
return restConfig;
|
||||
}
|
||||
|
||||
add(config: IWidgetBaseConfig, extraConfig?: Record<string, any>) {
|
||||
const parsedConfig = {
|
||||
...this.parseConfig(config),
|
||||
...extraConfig,
|
||||
};
|
||||
let { area } = parsedConfig;
|
||||
if (!area) {
|
||||
if (parsedConfig.type === 'Panel') {
|
||||
area = 'leftFloatArea';
|
||||
} else if (parsedConfig.type === 'Widget') {
|
||||
area = 'mainArea';
|
||||
} else {
|
||||
area = 'leftArea';
|
||||
}
|
||||
}
|
||||
switch (area) {
|
||||
case 'leftArea':
|
||||
case 'left':
|
||||
return this.leftArea.add(parsedConfig as PanelDockConfig);
|
||||
case 'rightArea':
|
||||
case 'right':
|
||||
return this.rightArea.add(parsedConfig as PanelConfig);
|
||||
case 'topArea':
|
||||
case 'top':
|
||||
return this.topArea.add(parsedConfig as PanelDockConfig);
|
||||
case 'toolbar':
|
||||
return this.toolbar.add(parsedConfig as PanelDockConfig);
|
||||
case 'mainArea':
|
||||
case 'main':
|
||||
case 'center':
|
||||
case 'centerArea':
|
||||
return this.mainArea.add(parsedConfig as PanelConfig);
|
||||
case 'bottomArea':
|
||||
case 'bottom':
|
||||
return this.bottomArea.add(parsedConfig as PanelConfig);
|
||||
case 'leftFixedArea':
|
||||
return this.leftFixedArea.add(parsedConfig as PanelConfig);
|
||||
case 'leftFloatArea':
|
||||
return this.leftFloatArea.add(parsedConfig as PanelConfig);
|
||||
case 'stages':
|
||||
return this.stages.add(parsedConfig as StageConfig);
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
9
packages/workspace/tsconfig.json
Normal file
9
packages/workspace/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": [
|
||||
"./src/"
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user