Merge branch 'develop' into release/1.1.4-beta

This commit is contained in:
JackLian 2023-03-21 10:00:07 +08:00
commit bd6f83da6a
64 changed files with 597 additions and 361 deletions

View File

@ -52,6 +52,6 @@ module.exports = {
'error',
{ default: ['signature', 'field', 'constructor', 'method'] }
],
'no-unused-vars': ['error', { "destructuredArrayIgnorePattern": "^_" }]
'@typescript-eslint/no-unused-vars': ['error']
},
};

View File

@ -220,7 +220,7 @@ checkNesting(
**@since v1.0.16**
### isDetectingNode
检查拖拽放置的目标节点是否可以放置该拖拽对象
判断是否当前节点处于被探测状态
```typescript
/**

View File

@ -13,9 +13,9 @@ import { observer, computed, Tip, globalContext } from '@alilc/lowcode-editor-co
import { createIcon, isReactComponent, isActionContentObject } from '@alilc/lowcode-utils';
import { IPublicTypeActionContentObject } from '@alilc/lowcode-types';
import { BuiltinSimulatorHost } from '../host';
import { OffsetObserver } from '../../designer';
import { Node } from '../../document';
import { INode, OffsetObserver } from '../../designer';
import NodeSelector from '../node-selector';
import { ISimulatorHost } from '../../simulator';
@observer
export class BorderSelectingInstance extends Component<{
@ -116,8 +116,8 @@ class Toolbar extends Component<{ observed: OffsetObserver }> {
}
}
function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActionContentObject, key: string, node: Node) {
if (isValidElement(content)) {
function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActionContentObject, key: string, node: INode) {
if (isValidElement<{ key: string; node: INode }>(content)) {
return cloneElement(content, { key, node });
}
if (isReactComponent(content)) {
@ -130,7 +130,7 @@ function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActio
key={key}
className="lc-borders-action"
onClick={() => {
action && action(node);
action && action(node.internalToShellNode()!);
const workspace = globalContext.get('workspace');
const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor');
const npm = node?.componentMeta?.npm;
@ -153,8 +153,8 @@ function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActio
}
@observer
export class BorderSelectingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> {
get host(): BuiltinSimulatorHost {
export class BorderSelectingForNode extends Component<{ host: ISimulatorHost; node: INode }> {
get host(): ISimulatorHost {
return this.props.host;
}

View File

@ -6,6 +6,7 @@ import {
getPublicPath,
focusTracker,
engineConfig,
globalLocale,
IReactionPublic,
IReactionOptions,
IReactionDisposer,
@ -47,26 +48,26 @@ import {
getRectTarget,
CanvasPoint,
Designer,
IDesigner,
} from '../designer';
import { parseMetadata } from './utils/parse-metadata';
import { getClosestClickableNode } from './utils/clickable';
import {
IPublicTypeComponentMetadata,
IPublicTypeComponentSchema,
IPublicTypePackage,
IPublicEnumTransitionType,
IPublicEnumDragObjectType,
IPublicTypeDragNodeObject,
IPublicTypeNodeInstance,
IPublicTypeComponentInstance,
IPublicTypeLocationChildrenDetail,
IPublicTypeLocationDetailType,
IPublicTypeRect,
IPublicModelNode,
} from '@alilc/lowcode-types';
import { BuiltinSimulatorRenderer } from './renderer';
import { clipboard } from '../designer/clipboard';
import { LiveEditing } from './live-editing/live-editing';
import { Project } from '../project';
import { IProject, Project } from '../project';
import { IScroller } from '../designer/scroller';
import { isElementNode, isDOMNodeVisible } from '../utils/misc';
import { debounce } from 'lodash';
@ -164,9 +165,9 @@ const defaultRaxEnvironment = [
export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProps> {
readonly isSimulator = true;
readonly project: Project;
readonly project: IProject;
readonly designer: Designer;
readonly designer: IDesigner;
readonly viewport = new Viewport();
@ -198,7 +199,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
}
@computed get locale(): string {
return this.get('locale');
return this.get('locale') || globalLocale.getLocale();
}
@computed get deviceClassName(): string | undefined {
@ -217,7 +218,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
return this.get('requestHandlersMap') || null;
}
get thisRequiredInJSE(): any {
get thisRequiredInJSE(): boolean {
return engineConfig.get('thisRequiredInJSE') ?? true;
}
@ -559,8 +560,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
return;
}
// FIXME: dirty fix remove label-for fro liveEditing
(downEvent.target as HTMLElement).removeAttribute('for');
const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element);
downEvent.target?.removeAttribute('for');
const nodeInst = this.getNodeInstanceFromElement(downEvent.target);
const { focusNode } = documentModel;
const node = getClosestClickableNode(nodeInst?.node || focusNode, downEvent);
// 如果找不到可点击的节点,直接返回
@ -675,11 +676,11 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
const x = new Event('click');
x.initEvent('click', true);
this._iframe?.dispatchEvent(x);
const target = e.target as HTMLElement;
const target = e.target;
const customizeIgnoreSelectors = engineConfig.get('customizeIgnoreSelectors');
// TODO: need more elegant solution to ignore click events of components in designer
const defaultIgnoreSelectors: any = [
const defaultIgnoreSelectors: string[] = [
'.next-input-group',
'.next-checkbox-group',
'.next-checkbox-wrapper',
@ -741,7 +742,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
}
};
const leave = () => {
this.project.currentDocument && detecting.leave(this.project.currentDocument)
this.project.currentDocument && detecting.leave(this.project.currentDocument);
};
doc.addEventListener('mouseover', hover, true);
@ -812,7 +813,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
/**
* @see ISimulator
*/
setSuspense(suspended: boolean) {
setSuspense(/** _suspended: boolean */) {
return false;
// if (suspended) {
// /*
@ -897,7 +898,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
return this.renderer?.getComponent(componentName) || null;
}
createComponent(schema: IPublicTypeComponentSchema): Component | null {
createComponent(/** _schema: IPublicTypeComponentSchema */): Component | null {
return null;
// return this.renderer?.createComponent(schema) || null;
}
@ -1018,7 +1019,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
}
if (last) {
const r: any = new DOMRect(last.x, last.y, last.r - last.x, last.b - last.y);
const r: IPublicTypeRect = new DOMRect(last.x, last.y, last.r - last.x, last.b - last.y);
r.elements = elements;
r.computed = _computed;
return r;
@ -1186,13 +1187,14 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
*/
locate(e: ILocateEvent): any {
const { dragObject } = e;
const { nodes } = dragObject as IPublicTypeDragNodeObject;
const nodes = dragObject?.nodes;
const operationalNodes = nodes?.filter((node) => {
const onMoveHook = node.componentMeta?.advanced.callbacks?.onMoveHook;
const canMove = onMoveHook && typeof onMoveHook === 'function' ? onMoveHook(node.internalToShellNode()) : true;
let parentContainerNode: Node | null = null;
let parentContainerNode: INode | null = null;
let parentNode = node.parent;
while (parentNode) {
@ -1254,7 +1256,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
};
const locationData = {
target: container as INode,
target: container,
detail,
source: `simulator${document.id}`,
event: e,
@ -1279,12 +1281,12 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
return this.designer.createLocation(locationData);
}
let nearRect = null;
let nearIndex = 0;
let nearNode = null;
let nearDistance = null;
let minTop = null;
let maxBottom = null;
let nearRect: IPublicTypeRect | null = null;
let nearIndex: number = 0;
let nearNode: INode | null = null;
let nearDistance: number | null = null;
let minTop: number | null = null;
let maxBottom: number | null = null;
for (let i = 0, l = children.size; i < l; i++) {
const node = children.get(i)!;
@ -1341,8 +1343,13 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
const vertical = inline || row;
// TODO: fix type
const near: any = {
node: nearNode,
const near: {
node: IPublicModelNode;
pos: 'before' | 'after' | 'replace';
rect?: IPublicTypeRect;
align?: 'V' | 'H';
} = {
node: nearNode.internalToShellNode()!,
pos: 'before',
align: vertical ? 'V' : 'H',
};
@ -1465,7 +1472,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
container = container.parent;
instance = this.getClosestNodeInstance(dropContainer.instance, container.id)?.instance;
dropContainer = {
container: container,
container,
instance,
};
} else {
@ -1483,12 +1490,12 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
/**
*
*/
handleAccept({ container, instance }: DropContainer, e: ILocateEvent): boolean {
handleAccept({ container }: DropContainer, e: ILocateEvent): boolean {
const { dragObject } = e;
const document = this.currentDocument!;
const focusNode = document.focusNode;
if (isRootNode(container) || container.contains(focusNode)) {
return document.checkNesting(focusNode, dragObject as any);
return document.checkNesting(focusNode!, dragObject as any);
}
const meta = (container as Node).componentMeta;
@ -1509,15 +1516,12 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
getNearByContainer(
{ container, instance }: DropContainer,
drillDownExcludes: Set<INode>,
e: ILocateEvent,
) {
const { children } = container;
const document = this.project.currentDocument!;
if (!children || children.isEmpty()) {
return null;
}
const nearDistance: any = null;
const nearBy: any = null;
for (let i = 0, l = children.size; i < l; i++) {
let child = children.get(i);

View File

@ -1,19 +1,19 @@
import { Overlay } from '@alifd/next';
import React from 'react';
import React, { MouseEvent } from 'react';
import { Title, globalContext } from '@alilc/lowcode-editor-core';
import { canClickNode } from '@alilc/lowcode-utils';
import './index.less';
import { Node, INode } from '@alilc/lowcode-designer';
import { INode } from '@alilc/lowcode-designer';
const { Popup } = Overlay;
export interface IProps {
node: Node;
node: INode;
}
export interface IState {
parentNodes: Node[];
parentNodes: INode[];
}
type UnionNode = INode | null;
@ -26,14 +26,18 @@ export default class InstanceNodeSelector extends React.Component<IProps, IState
componentDidMount() {
const parentNodes = this.getParentNodes(this.props.node);
this.setState({
parentNodes,
parentNodes: parentNodes ?? [],
});
}
// 获取节点的父级节点(最多获取 5 层)
getParentNodes = (node: Node) => {
getParentNodes = (node: INode) => {
const parentNodes: any[] = [];
const { focusNode } = node.document;
const focusNode = node.document?.focusNode;
if (!focusNode) {
return null;
}
if (node.contains(focusNode) || !focusNode.contains(node)) {
return parentNodes;
@ -53,12 +57,12 @@ export default class InstanceNodeSelector extends React.Component<IProps, IState
return parentNodes;
};
onSelect = (node: Node) => (e: unknown) => {
onSelect = (node: INode) => (event: MouseEvent) => {
if (!node) {
return;
}
const canClick = canClickNode(node, e as MouseEvent);
const canClick = canClickNode(node.internalToShellNode()!, event);
if (canClick && typeof node.select === 'function') {
node.select();
@ -76,19 +80,19 @@ export default class InstanceNodeSelector extends React.Component<IProps, IState
}
};
onMouseOver = (node: Node) => (_: any, flag = true) => {
onMouseOver = (node: INode) => (_: any, flag = true) => {
if (node && typeof node.hover === 'function') {
node.hover(flag);
}
};
onMouseOut = (node: Node) => (_: any, flag = false) => {
onMouseOut = (node: INode) => (_: any, flag = false) => {
if (node && typeof node.hover === 'function') {
node.hover(flag);
}
};
renderNodes = (/* node: Node */) => {
renderNodes = () => {
const nodes = this.state.parentNodes;
if (!nodes || nodes.length < 1) {
return null;
@ -136,7 +140,7 @@ export default class InstanceNodeSelector extends React.Component<IProps, IState
triggerType="hover"
offset={[0, 0]}
>
<div className="instance-node-selector">{this.renderNodes(node)}</div>
<div className="instance-node-selector">{this.renderNodes()}</div>
</Popup>
</div>
);

View File

@ -16,17 +16,15 @@ import {
IPublicModelScroller,
IPublicTypeLocationData,
IPublicEnumTransformStage,
IPublicModelDragon,
IPublicModelDropLocation,
IPublicModelLocateEvent,
} from '@alilc/lowcode-types';
import { megreAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils';
import { Project } from '../project';
import { IProject, Project } from '../project';
import { Node, DocumentModel, insertChildren, INode } from '../document';
import { ComponentMeta, IComponentMeta } from '../component-meta';
import { INodeSelector, Component } from '../simulator';
import { Scroller } from './scroller';
import { Dragon, IDragon, ILocateEvent } from './dragon';
import { Dragon, IDragon } from './dragon';
import { ActiveTracker, IActiveTracker } from './active-tracker';
import { Detecting } from './detecting';
import { DropLocation } from './location';
@ -64,7 +62,11 @@ export interface DesignerProps {
export interface IDesigner {
readonly shellModelFactory: IShellModelFactory;
get dragon(): IPublicModelDragon;
viewName: string | undefined;
readonly project: IProject;
get dragon(): IDragon;
get activeTracker(): IActiveTracker;
@ -78,6 +80,10 @@ export interface IDesigner {
createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller;
refreshComponentMetasMap(): void;
createOffsetObserver(nodeInstance: INodeSelector): OffsetObserver | null;
/**
* dragon
*/
@ -92,6 +98,8 @@ export interface IDesigner {
generateMetadata?: () => IPublicTypeComponentMetadata | null,
): IComponentMeta;
clearLocation(): void;
createComponentMeta(data: IPublicTypeComponentMetadata): IComponentMeta | null;
getComponentMetasMap(): Map<string, IComponentMeta>;
@ -118,7 +126,7 @@ export class Designer implements IDesigner {
readonly detecting = new Detecting();
readonly project: Project;
readonly project: IProject;
readonly editor: IPublicModelEditor;
@ -140,7 +148,7 @@ export class Designer implements IDesigner {
@obx.ref private _simulatorComponent?: ComponentType<any>;
@obx.ref private _simulatorProps?: Record<string, any> | ((project: Project) => object);
@obx.ref private _simulatorProps?: Record<string, any> | ((project: IProject) => object);
@obx.ref private _suspensed = false;

View File

@ -11,9 +11,9 @@ import {
IPublicModelSensor,
} from '@alilc/lowcode-types';
import { setNativeSelection, cursor } from '@alilc/lowcode-utils';
import { Node } from '../document';
import { INode, Node } from '../document';
import { ISimulatorHost, isSimulatorHost } from '../simulator';
import { Designer } from './designer';
import { IDesigner } from './designer';
import { makeEventsHandler } from '../utils/misc';
export interface ILocateEvent extends IPublicModelLocateEvent {
@ -88,14 +88,17 @@ function getSourceSensor(dragObject: IPublicModelDragObject): ISimulatorHost | n
if (!isDragNodeObject(dragObject)) {
return null;
}
return dragObject.nodes[0]?.document.simulator || null;
return dragObject.nodes[0]?.document?.simulator || null;
}
function isDragEvent(e: any): e is DragEvent {
return e?.type?.startsWith('drag');
}
export interface IDragon extends IPublicModelDragon {
export interface IDragon extends IPublicModelDragon<
INode,
ILocateEvent
> {
emitter: IEventBus;
}
@ -130,7 +133,7 @@ export class Dragon implements IDragon {
emitter: IEventBus = createModuleEventBus('Dragon');
constructor(readonly designer: Designer) {
constructor(readonly designer: IDesigner) {
makeObservable(this);
this.viewName = designer.viewName;
}
@ -167,7 +170,7 @@ export class Dragon implements IDragon {
* @param dragObject
* @param boostEvent
*/
boost(dragObject: IPublicModelDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node | IPublicModelNode) {
boost(dragObject: IPublicModelDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: INode | IPublicModelNode) {
const { designer } = this;
const masterSensors = this.getMasterSensors();
const handleEvents = makeEventsHandler(boostEvent, masterSensors);
@ -264,7 +267,7 @@ export class Dragon implements IDragon {
this.emitter.emit('rgl.add.placeholder', {
rglNode,
fromRglNode,
node: locateEvent.dragObject.nodes[0],
node: locateEvent.dragObject?.nodes[0],
event: e,
});
designer.clearLocation();

View File

@ -2,7 +2,7 @@ import requestIdleCallback, { cancelIdleCallback } from 'ric-shim';
import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core';
import { uniqueId } from '@alilc/lowcode-utils';
import { INodeSelector, IViewport } from '../simulator';
import { Node } from '../document';
import { INode } from '../document';
export class OffsetObserver {
readonly id = uniqueId('oobx');
@ -93,11 +93,11 @@ export class OffsetObserver {
private pid: number | undefined;
readonly viewport: IViewport;
readonly viewport: IViewport | undefined;
private isRoot: boolean;
readonly node: Node;
readonly node: INode;
readonly compute: () => void;
@ -105,10 +105,10 @@ export class OffsetObserver {
const { node, instance } = nodeInstance;
this.node = node;
const doc = node.document;
const host = doc.simulator!;
const focusNode = doc.focusNode;
const host = doc?.simulator;
const focusNode = doc?.focusNode;
this.isRoot = node.contains(focusNode!);
this.viewport = host.viewport;
this.viewport = host?.viewport;
makeObservable(this);
if (this.isRoot) {
this.hasOffset = true;
@ -118,7 +118,7 @@ export class OffsetObserver {
return;
}
let pid: number;
let pid: number | undefined;
const compute = () => {
if (pid !== this.pid) {
return;

View File

@ -35,7 +35,7 @@ import {
isDragNodeDataObject,
isNode,
} from '@alilc/lowcode-utils';
import { IProject, Project } from '../project';
import { IProject } from '../project';
import { ISimulatorHost } from '../simulator';
import { IComponentMeta } from '../component-meta';
import { IDesigner, IHistory } from '../designer';
@ -56,7 +56,7 @@ export type GetDataType<T, NodeType> = T extends undefined
export interface IDocumentModel extends Omit< IPublicModelDocumentModel<
ISelection,
IHistory,
INode | IRootNode,
INode,
IDropLocation,
IModalNodesManager,
IProject
@ -81,6 +81,8 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel<
readonly designer: IDesigner;
selection: ISelection;
get rootNode(): INode | null;
get simulator(): ISimulatorHost | null;
@ -98,8 +100,6 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel<
get currentRoot(): INode | null;
selection: ISelection;
isBlank(): boolean;
/**

View File

@ -6,7 +6,6 @@ import {
IPublicApiMaterial,
IPublicApiEvent,
IPublicApiCommon,
IPublicTypeCompositeObject,
IPublicApiPlugins,
IPublicTypePluginConfig,
IPublicApiLogger,
@ -16,7 +15,9 @@ import {
IPublicApiCanvas,
IPublicApiWorkspace,
IPublicTypePluginMeta,
IPublicTypePluginRegisterOptions,
} from '@alilc/lowcode-types';
import PluginContext from './plugin-context';
export type PluginPreference = Map<string, Record<string, IPublicTypePreferenceValueType>>;
@ -72,7 +73,7 @@ export interface ILowCodePluginManagerCore {
register(
pluginModel: IPublicTypePlugin,
pluginOptions?: any,
options?: IPublicTypeCompositeObject,
options?: IPublicTypePluginRegisterOptions,
): Promise<void>;
init(pluginPreference?: Map<string, Record<string, IPublicTypePreferenceValueType>>): Promise<void>;
get(pluginName: string): ILowCodePluginRuntime | undefined;
@ -81,6 +82,7 @@ export interface ILowCodePluginManagerCore {
delete(pluginName: string): any;
setDisabled(pluginName: string, flag: boolean): void;
dispose(): void;
_getLowCodePluginContext (options: IPluginContextOptions): PluginContext;
}
export type ILowCodePluginManager = ILowCodePluginManagerCore & ILowCodePluginManagerPluginAccessor;

View File

@ -41,6 +41,14 @@ export interface IProject extends Omit< IBaseApiProject<
get documents(): IDocumentModel[];
get i18n(): {
[local: string]: {
[key: string]: any;
};
};
mountSimulator(simulator: ISimulatorHost): void;
open(doc?: string | IDocumentModel | IPublicTypeRootSchema): IDocumentModel | null;
getDocumentByFileName(fileName: string): IDocumentModel | null;

View File

@ -1,8 +1,9 @@
import { ComponentType } from 'react';
import { IPublicTypeComponentMetadata, IPublicTypeNodeSchema, IPublicTypeScrollable, IPublicTypeComponentInstance, IPublicModelSensor, IPublicTypeNodeInstance, IPublicTypePackage } from '@alilc/lowcode-types';
import { Point, ScrollTarget, ILocateEvent } from './designer';
import { Point, ScrollTarget, ILocateEvent, IDesigner } from './designer';
import { BuiltinSimulatorRenderer } from './builtin-simulator/renderer';
import { INode } from './document';
import { IProject } from './project';
export type AutoFit = '100%';
// eslint-disable-next-line no-redeclare
@ -89,6 +90,10 @@ export interface ISimulatorHost<P = object> extends IPublicModelSensor<INode> {
readonly contentDocument?: Document;
readonly renderer?: BuiltinSimulatorRenderer;
readonly project: IProject;
readonly designer: IDesigner;
// dependsAsset // like react jQuery lodash
// themesAsset
// componentsAsset

View File

@ -2,7 +2,7 @@
/* eslint-disable max-len */
import { StrictEventEmitter } from 'strict-event-emitter-types';
import { EventEmitter } from 'events';
import { EventBus } from './event-bus';
import { EventBus, IEventBus } from './event-bus';
import {
IPublicModelEditor,
EditorConfig,
@ -52,15 +52,18 @@ export declare interface Editor extends StrictEventEmitter<EventEmitter, GlobalE
eventNames(): Array<string | symbol>;
}
export interface IEditor extends IPublicModelEditor {
config?: EditorConfig;
components?: PluginClassSet;
eventBus: IEventBus;
init(config?: EditorConfig, components?: PluginClassSet): Promise<any>;
}
// eslint-disable-next-line no-redeclare
export class Editor extends (EventEmitter as any) implements IPublicModelEditor {
constructor(readonly viewName: string = 'global', readonly workspaceMode: boolean = false) {
// eslint-disable-next-line constructor-super
super();
// set global emitter maxListeners
this.setMaxListeners(200);
this.eventBus = new EventBus(this);
}
export class Editor extends EventEmitter implements IEditor {
/**
* Ioc Container
@ -71,10 +74,32 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor
return globalLocale.getLocale();
}
config?: EditorConfig;
eventBus: EventBus;
components?: PluginClassSet;
// readonly utils = utils;
private hooks: HookConfig[] = [];
private waits = new Map<
IPublicTypeEditorValueKey,
Array<{
once?: boolean;
resolve: (data: any) => void;
}>
>();
constructor(readonly viewName: string = 'global', readonly workspaceMode: boolean = false) {
// eslint-disable-next-line constructor-super
super();
// set global emitter maxListeners
this.setMaxListeners(200);
this.eventBus = new EventBus(this);
}
get<T = undefined, KeyOrType = any>(
keyOrType: KeyOrType,
): IPublicTypeEditorGetResult<T, KeyOrType> | undefined {
@ -202,12 +227,6 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor
this.notifyGot(key || data);
}
config?: EditorConfig;
eventBus: EventBus;
components?: PluginClassSet;
async init(config?: EditorConfig, components?: PluginClassSet): Promise<any> {
this.config = config || {};
this.components = components || {};
@ -270,16 +289,6 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor
});
};
/* eslint-disable */
private waits = new Map<
IPublicTypeEditorValueKey,
Array<{
once?: boolean;
resolve: (data: any) => void;
}>
>();
/* eslint-enable */
private notifyGot(key: IPublicTypeEditorValueKey) {
let waits = this.waits.get(key);
if (!waits) {

View File

@ -339,8 +339,8 @@ function fireCallback(callback: IPublicTypeHotkeyCallback, e: KeyboardEvent, com
}
}
export interface IHotKey extends IPublicApiHotkey {
export interface IHotKey extends Omit<IPublicApiHotkey, 'bind' | 'callbacks'> {
activate(activate: boolean): void;
}
export class Hotkey implements IHotKey {

View File

@ -1,4 +1,5 @@
import { Component } from 'react';
import ReactDOM from 'react-dom';
import { TipItem } from './tip-item';
import { tipHandler } from './tip-handler';
@ -25,7 +26,7 @@ export class TipContainer extends Component {
}
render() {
return window.ReactDOM.createPortal(
return ReactDOM.createPortal(
<div className="lc-tips-container">
<TipItem />
</div>,

View File

@ -1,7 +1,7 @@
import { Component, isValidElement, ReactNode } from 'react';
import classNames from 'classnames';
import { createIcon, isI18nData } from '@alilc/lowcode-utils';
import { IPublicTypeTitleContent, IPublicTypeI18nData } from '@alilc/lowcode-types';
import { createIcon, isI18nData, isTitleConfig } from '@alilc/lowcode-utils';
import { IPublicTypeTitleContent, IPublicTypeI18nData, IPublicTypeTitleConfig } from '@alilc/lowcode-types';
import { intl } from '../../intl';
import { Tip } from '../tip';
import './title.less';
@ -88,7 +88,8 @@ export class Title extends Component<{
render() {
// eslint-disable-next-line prefer-const
let { title, className } = this.props;
const { title, className } = this.props;
let _title: IPublicTypeTitleConfig;
if (title == null) {
return null;
}
@ -96,34 +97,40 @@ export class Title extends Component<{
return title;
}
if (typeof title === 'string' || isI18nData(title)) {
title = { label: title };
_title = { label: title };
} else if (isTitleConfig(title)) {
_title = title;
} else {
_title = {
label: title,
};
}
const icon = title.icon ? createIcon(title.icon, { size: 20 }) : null;
const icon = _title.icon ? createIcon(_title.icon, { size: 20 }) : null;
let tip: any = null;
if (title.tip) {
if (isValidElement(title.tip) && title.tip.type === Tip) {
tip = title.tip;
if (_title.tip) {
if (isValidElement(_title.tip) && _title.tip.type === Tip) {
tip = _title.tip;
} else {
const tipProps =
typeof title.tip === 'object' && !(isValidElement(title.tip) || isI18nData(title.tip))
? title.tip
: { children: title.tip };
typeof _title.tip === 'object' && !(isValidElement(_title.tip) || isI18nData(_title.tip))
? _title.tip
: { children: _title.tip };
tip = <Tip {...tipProps} />;
}
}
return (
<span
className={classNames('lc-title', className, title.className, {
className={classNames('lc-title', className, _title.className, {
'has-tip': !!tip,
'only-icon': !title.label,
'only-icon': !_title.label,
})}
onClick={this.handleClick}
>
{icon ? <b className="lc-title-icon">{icon}</b> : null}
{this.renderLabel(title.label)}
{this.renderLabel(_title.label)}
{tip}
</span>
);

View File

@ -3,7 +3,7 @@ import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core';
import { Logger } from '@alilc/lowcode-utils';
import { IPublicTypeWidgetBaseConfig } from '@alilc/lowcode-types';
import { WidgetContainer } from './widget/widget-container';
import { Skeleton } from './skeleton';
import { ISkeleton } from './skeleton';
import { IWidget } from './widget/widget';
const logger = new Logger({ level: 'warn', bizName: 'skeleton:area' });
@ -35,7 +35,9 @@ export class Area<C extends IPublicTypeWidgetBaseConfig = any, T extends IWidget
readonly container: WidgetContainer<T, C>;
constructor(readonly skeleton: Skeleton, readonly name: string, handle: (item: T | C) => T, private exclusive?: boolean, defaultSetCurrent = false) {
private lastCurrent: T | null = null;
constructor(readonly skeleton: ISkeleton, readonly name: string, handle: (item: T | C) => T, private exclusive?: boolean, defaultSetCurrent = false) {
makeObservable(this);
this.container = skeleton.createContainer(name, handle, exclusive, () => this.visible, defaultSetCurrent);
}
@ -57,8 +59,6 @@ export class Area<C extends IPublicTypeWidgetBaseConfig = any, T extends IWidget
return this.container.remove(config);
}
private lastCurrent: T | null = null;
setVisible(flag: boolean) {
if (this.exclusive) {
const { current } = this.container;

View File

@ -92,7 +92,10 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
const { extraProps } = this.field;
const { ignoreDefaultValue } = extraProps;
try {
return typeof ignoreDefaultValue === 'function' ? ignoreDefaultValue(this.field.internalToShell()) : false;
if (typeof ignoreDefaultValue === 'function') {
return ignoreDefaultValue(this.field.internalToShellField());
}
return false;
} catch (error) {
console.error('exception when ignoreDefaultValue is excuted', error);
}

View File

@ -1,10 +1,9 @@
import React, { Component } from 'react';
import classNames from 'classnames';
import { observer } from '@alilc/lowcode-editor-core';
import { SettingTopEntry, SettingField } from '@alilc/lowcode-designer';
import StageChain from './stage-chain';
import Stage from './stage';
import { Skeleton } from '../../skeleton';
import { ISkeleton } from '../../skeleton';
import PopupService, { PopupPipe } from '../popup';
import { Stage as StageWidget } from '../../widget/stage';
@ -14,9 +13,7 @@ export type StageBoxProps = typeof StageBoxDefaultProps & {
stageChain?: StageChain;
className?: string;
children: React.ReactNode;
skeleton: Skeleton;
// @todo to remove
target?: SettingTopEntry | SettingField;
skeleton: ISkeleton;
};
type WillDetachMember = () => void;

View File

@ -47,6 +47,8 @@ function HelpTip({ tip }: any) {
@observer
export class PanelDockView extends Component<DockProps & { dock: PanelDock }> {
private lastActived = false;
componentDidMount() {
this.checkActived();
}
@ -55,8 +57,6 @@ export class PanelDockView extends Component<DockProps & { dock: PanelDock }> {
this.checkActived();
}
private lastActived = false;
checkActived() {
const { dock } = this.props;
if (dock.actived !== this.lastActived) {
@ -134,7 +134,7 @@ export class DraggableLineView extends Component<{ panel: Panel }> {
// 默认 关闭,通过配置开启
const enableDrag = this.props.panel.config.props?.enableDrag;
const isRightArea = this.props.panel.config?.area === 'rightArea';
if (isRightArea || !enableDrag || this.props.panel?.parent.name === 'leftFixedArea') {
if (isRightArea || !enableDrag || this.props.panel?.parent?.name === 'leftFixedArea') {
return null;
}
return (
@ -159,6 +159,8 @@ export class DraggableLineView extends Component<{ panel: Panel }> {
@observer
export class TitledPanelView extends Component<{ panel: Panel; area?: string }> {
private lastVisible = false;
componentDidMount() {
this.checkVisible();
}
@ -167,8 +169,6 @@ export class TitledPanelView extends Component<{ panel: Panel; area?: string }>
this.checkVisible();
}
private lastVisible = false;
checkVisible() {
const { panel } = this.props;
const currentVisible = panel.inited && panel.visible;
@ -218,6 +218,8 @@ export class PanelView extends Component<{
hideOperationRow?: boolean;
hideDragLine?: boolean;
}> {
private lastVisible = false;
componentDidMount() {
this.checkVisible();
}
@ -226,8 +228,6 @@ export class PanelView extends Component<{
this.checkVisible();
}
private lastVisible = false;
checkVisible() {
const { panel } = this.props;
const currentVisible = panel.inited && panel.visible;
@ -331,6 +331,9 @@ class PanelTitle extends Component<{ panel: Panel; className?: string }> {
@observer
export class WidgetView extends Component<{ widget: IWidget }> {
private lastVisible = false;
private lastDisabled: boolean | undefined = false;
componentDidMount() {
this.checkVisible();
this.checkDisabled();
@ -341,9 +344,6 @@ export class WidgetView extends Component<{ widget: IWidget }> {
this.checkDisabled();
}
private lastVisible = false;
private lastDisabled = false;
checkVisible() {
const { widget } = this.props;
const currentVisible = widget.visible;

View File

@ -1,4 +1,4 @@
import { createContext } from 'react';
import { Skeleton } from './skeleton';
import { ISkeleton } from './skeleton';
export const SkeletonContext = createContext<Skeleton>({} as any);
export const SkeletonContext = createContext<ISkeleton>({} as any);

View File

@ -3,9 +3,10 @@ import classNames from 'classnames';
import { observer, Focusable, focusTracker } from '@alilc/lowcode-editor-core';
import { Area } from '../area';
import { Panel } from '../widget/panel';
import { PanelConfig } from '../types';
@observer
export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }> {
export default class LeftFloatPane extends Component<{ area: Area<PanelConfig, Panel> }> {
private dispose?: () => void;
private focusing?: Focusable;

View File

@ -323,10 +323,8 @@ body {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
&.has-tip {
cursor: pointer;
}
&.actived {
color: #0079f2;
}

View File

@ -1,7 +1,7 @@
import { Component } from 'react';
import { TipContainer, observer } from '@alilc/lowcode-editor-core';
import classNames from 'classnames';
import { Skeleton } from '../skeleton';
import { ISkeleton } from '../skeleton';
import TopArea from './top-area';
import LeftArea from './left-area';
import LeftFixedPane from './left-fixed-pane';
@ -16,7 +16,7 @@ import { EditorConfig, PluginClassSet } from '@alilc/lowcode-types';
@observer
export class Workbench extends Component<{
skeleton: Skeleton;
skeleton: ISkeleton;
config?: EditorConfig;
components?: PluginClassSet;
className?: string;

View File

@ -1,4 +1,4 @@
import { Editor, action, makeObservable, obx, engineConfig } from '@alilc/lowcode-editor-core';
import { action, makeObservable, obx, engineConfig, IEditor } from '@alilc/lowcode-editor-core';
import {
DockConfig,
PanelConfig,
@ -27,6 +27,7 @@ import {
IPublicTypeWidgetBaseConfig,
IPublicTypeWidgetConfigArea,
IPublicTypeSkeletonConfig,
IPublicApiSkeleton,
} from '@alilc/lowcode-types';
const logger = new Logger({ level: 'warn', bizName: 'skeleton' });
@ -42,6 +43,66 @@ export enum SkeletonEvents {
WIDGET_ENABLE = 'skeleton.widget.enable',
}
export interface ISkeleton extends Omit<IPublicApiSkeleton,
'showPanel' |
'hidePanel' |
'showWidget' |
'enableWidget' |
'hideWidget' |
'disableWidget' |
'showArea' |
'onShowPanel' |
'onHidePanel' |
'onShowWidget' |
'onHideWidget' |
'remove' |
'hideArea'
> {
editor: IEditor;
readonly leftArea: Area<DockConfig | PanelDockConfig | DialogDockConfig>;
readonly topArea: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>;
readonly subTopArea: 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>;
readonly widgets: IWidget[];
getPanel(name: string): Panel | undefined;
getWidget(name: string): IWidget | undefined;
buildFromConfig(config?: EditorConfig, components?: PluginClassSet): void;
createStage(config: any): string | undefined;
getStage(name: string): Stage | null;
createContainer(
name: string,
handle: (item: any) => any,
exclusive?: boolean,
checkVisible?: () => boolean,
defaultSetCurrent?: boolean,
): WidgetContainer;
createPanel(config: PanelConfig): Panel;
}
export class Skeleton {
private panels = new Map<string, Panel>();
@ -69,7 +130,7 @@ export class Skeleton {
readonly widgets: IWidget[] = [];
constructor(readonly editor: Editor, readonly viewName: string = 'global') {
constructor(readonly editor: IEditor, readonly viewName: string = 'global') {
makeObservable(this);
this.leftArea = new Area(
this,
@ -244,7 +305,7 @@ export class Skeleton {
Object.keys(plugins).forEach((area) => {
plugins[area].forEach((item) => {
const { pluginKey, type, props = {}, pluginProps } = item;
const config: Partial<IPublicTypeWidgetBaseConfig> = {
const config: IPublicTypeWidgetBaseConfig = {
area: area as IPublicTypeWidgetConfigArea,
type: 'Widget',
name: pluginKey,
@ -272,7 +333,7 @@ export class Skeleton {
if (pluginKey in components) {
config.content = components[pluginKey];
}
this.add(config as IPublicTypeWidgetBaseConfig);
this.add(config);
});
});
}

View File

@ -4,6 +4,7 @@ import { isPlainObject, isJSFunction, getLogger } from '@alilc/lowcode-utils';
const leadingFnRe = /^function/;
const leadingFnNameRe = /^\w+\s*\(/;
const logger = getLogger({ level: 'warn', bizName: 'skeleton:transducers' });
/**
*
* () => {} / val => {}

View File

@ -1,12 +1,11 @@
import { ReactElement, ComponentType } from 'react';
import {
IPublicTypeTitleContent,
IPublicTypeIconType,
IPublicTypeI18nData,
TipContent,
IPublicTypeWidgetConfigArea,
IPublicTypeWidgetBaseConfig,
IPublicTypePanelDockPanelProps,
IPublicTypePanelDockProps,
} from '@alilc/lowcode-types';
import { IWidget } from './widget/widget';
@ -24,13 +23,7 @@ export function isWidgetConfig(obj: any): obj is WidgetConfig {
return obj && obj.type === 'Widget';
}
export interface DockProps {
title?: IPublicTypeTitleContent;
icon?: IPublicTypeIconType;
size?: 'small' | 'medium' | 'large';
className?: string;
description?: TipContent;
onClick?: () => void;
export interface DockProps extends IPublicTypePanelDockProps {
}
export interface DividerConfig extends IPublicTypeWidgetBaseConfig {

View File

@ -3,7 +3,7 @@ import { makeObservable, obx } from '@alilc/lowcode-editor-core';
import { uniqueId, createContent } from '@alilc/lowcode-utils';
import { getEvent } from '@alilc/lowcode-shell';
import { DockConfig } from '../types';
import { Skeleton } from '../skeleton';
import { ISkeleton } from '../skeleton';
import { DockView, WidgetView } from '../components/widget-views';
import { IWidget } from './widget';
@ -59,7 +59,7 @@ export class Dock implements IWidget {
return this._body;
}
constructor(readonly skeleton: Skeleton, readonly config: DockConfig) {
constructor(readonly skeleton: ISkeleton, readonly config: DockConfig) {
makeObservable(this);
const { props = {}, name } = config;
this.name = name;

View File

@ -1,7 +1,7 @@
import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core';
import { uniqueId } from '@alilc/lowcode-utils';
import { createElement, ReactNode, ReactInstance } from 'react';
import { Skeleton } from '../skeleton';
import { ISkeleton } from '../skeleton';
import { PanelDockConfig } from '../types';
import { Panel } from './panel';
import { PanelDockView, WidgetView } from '../components/widget-views';
@ -18,7 +18,7 @@ export class PanelDock implements IWidget {
readonly name: string;
readonly align?: string;
readonly align?: 'left' | 'right' | 'bottom' | 'center' | 'top' | undefined;
private inited = false;
@ -51,11 +51,6 @@ export class PanelDock implements IWidget {
});
}
getDOMNode() {
// eslint-disable-next-line react/no-find-dom-node
return this._shell ? findDOMNode(this._shell) : null;
}
@obx.ref private _visible = true;
get visible() {
@ -76,7 +71,7 @@ export class PanelDock implements IWidget {
return this._panel || this.skeleton.getPanel(this.panelName);
}
constructor(readonly skeleton: Skeleton, readonly config: PanelDockConfig) {
constructor(readonly skeleton: ISkeleton, readonly config: PanelDockConfig) {
makeObservable(this);
const { content, contentProps, panelProps, name, props } = config;
this.name = name;
@ -84,7 +79,7 @@ export class PanelDock implements IWidget {
this.panelName = config.panelName || name;
this.align = props?.align;
if (content) {
const _panelProps: any = { ...panelProps };
const _panelProps = { ...panelProps };
if (_panelProps.title == null && props) {
_panelProps.title = composeTitle(props.title, undefined, props.description, true, true);
}
@ -102,6 +97,11 @@ export class PanelDock implements IWidget {
}
}
getDOMNode() {
// eslint-disable-next-line react/no-find-dom-node
return this._shell ? findDOMNode(this._shell) : null;
}
setVisible(flag: boolean) {
if (flag === this._visible) {
return;
@ -170,7 +170,6 @@ export class PanelDock implements IWidget {
}
}
export function isPanelDock(obj: any): obj is PanelDock {
return obj && obj.isPanelDock;
}

View File

@ -6,7 +6,7 @@ import { WidgetContainer } from './widget-container';
import { getEvent } from '@alilc/lowcode-shell';
import { PanelConfig, HelpTipConfig } from '../types';
import { TitledPanelView, TabsPanelView, PanelView } from '../components/widget-views';
import { Skeleton } from '../skeleton';
import { ISkeleton } from '../skeleton';
import { composeTitle } from './utils';
import { IWidget } from './widget';
import { isPanelDock, PanelDock } from './panel-dock';
@ -80,7 +80,7 @@ export class Panel implements IWidget {
@obx.ref public parent?: WidgetContainer;
constructor(readonly skeleton: Skeleton, readonly config: PanelConfig) {
constructor(readonly skeleton: ISkeleton, readonly config: PanelConfig) {
makeObservable(this);
const { name, content, props = {} } = config;
const { hideTitleBar, title, icon, description, help } = props;
@ -111,7 +111,7 @@ export class Panel implements IWidget {
props.onInit.call(this, this);
}
if (content.onInit) {
if (typeof content !== 'string' && content && content.onInit) {
content.onInit.call(this, this);
}
// todo: process shortcut

View File

@ -1,6 +1,6 @@
// import { uniqueId } from '@alilc/lowcode-utils';
import { Widget } from './widget';
import { Skeleton } from '../skeleton';
import { ISkeleton } from '../skeleton';
import { WidgetConfig } from '../types';
export interface StageConfig extends WidgetConfig {
@ -17,7 +17,7 @@ export class Stage extends Widget {
direction?: 'right' | 'left';
};
constructor(skeleton: Skeleton, config: StageConfig) {
constructor(skeleton: ISkeleton, config: StageConfig) {
super(skeleton, config);
this.isRoot = config.isRoot || false;
}

View File

@ -3,45 +3,51 @@ import { isI18nData, isTitleConfig } from '@alilc/lowcode-utils';
import { isValidElement } from 'react';
export function composeTitle(title?: IPublicTypeTitleContent, icon?: IPublicTypeIconType, tip?: TipContent, tipAsTitle?: boolean, noIcon?: boolean) {
let _title: IPublicTypeTitleContent | undefined;
if (!title) {
title = {};
_title = {};
if (!icon || tipAsTitle) {
title.label = tip;
_title = {
label: tip,
};
tip = undefined;
}
} else {
_title = title;
}
if (icon || tip) {
if (typeof title !== 'object' || isValidElement(title) || isI18nData(title)) {
if (isValidElement(title)) {
if (title.type === 'svg' || (title.type as any).getIcon) {
if (typeof _title !== 'object' || isValidElement(_title) || isI18nData(_title)) {
if (isValidElement(_title)) {
if (_title.type === 'svg' || _title.type.getIcon) {
if (!icon) {
icon = title as any;
icon = _title;
}
if (tipAsTitle) {
title = tip as any;
_title = tip;
tip = null;
} else {
title = undefined;
_title = undefined;
}
}
}
title = {
label: title,
_title = {
label: _title,
icon,
tip,
};
} else {
title = {
...title,
_title = {
..._title,
icon,
tip,
};
}
}
if (isTitleConfig(title) && noIcon) {
if (isTitleConfig(_title) && noIcon) {
if (!isValidElement(title)) {
title.icon = undefined;
_title.icon = undefined;
}
}
return title;
return _title;
}

View File

@ -3,7 +3,7 @@ import { makeObservable, obx } from '@alilc/lowcode-editor-core';
import { createContent, uniqueId } from '@alilc/lowcode-utils';
import { getEvent } from '@alilc/lowcode-shell';
import { WidgetConfig } from '../types';
import { Skeleton } from '../skeleton';
import { ISkeleton } from '../skeleton';
import { WidgetView } from '../components/widget-views';
import { IPublicTypeTitleContent, IPublicTypeWidgetBaseConfig } from '@alilc/lowcode-types';
@ -15,7 +15,7 @@ export interface IWidget {
readonly visible: boolean;
readonly disabled?: boolean;
readonly body: ReactNode;
readonly skeleton: Skeleton;
readonly skeleton: ISkeleton;
readonly config: IPublicTypeWidgetBaseConfig;
getName(): string;
@ -71,7 +71,7 @@ export class Widget implements IWidget {
readonly title: IPublicTypeTitleContent;
constructor(readonly skeleton: Skeleton, readonly config: WidgetConfig) {
constructor(readonly skeleton: ISkeleton, readonly config: WidgetConfig) {
makeObservable(this);
const { props = {}, name } = config;
this.name = name;

View File

@ -461,6 +461,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
locale: renderer.locale,
messages: _schema.i18n || {},
device: renderer.device,
locale: renderer.locale,
appHelper: renderer.context,
rendererName: 'LowCodeRenderer',
thisRequiredInJSE: host.thisRequiredInJSE,
@ -632,4 +633,4 @@ function getLowCodeComponentProps(props: any) {
return newProps;
}
export default new SimulatorRendererContainer();
export default new SimulatorRendererContainer();

View File

@ -1,4 +1,4 @@
import { Editor as InnerEditor, EventBus } from '@alilc/lowcode-editor-core';
import { IEditor, IEventBus } from '@alilc/lowcode-editor-core';
import { getLogger, isPluginEventName } from '@alilc/lowcode-utils';
import { IPublicApiEvent, IPublicTypeDisposable } from '@alilc/lowcode-types';
@ -11,10 +11,10 @@ type EventOptions = {
const eventBusSymbol = Symbol('eventBus');
export class Event implements IPublicApiEvent {
private readonly [eventBusSymbol]: EventBus;
private readonly [eventBusSymbol]: IEventBus;
private readonly options: EventOptions;
constructor(eventBus: EventBus, options: EventOptions, public workspaceMode = false) {
constructor(eventBus: IEventBus, options: EventOptions, public workspaceMode = false) {
this[eventBusSymbol] = eventBus;
this.options = options;
if (!this.options.prefix) {
@ -69,6 +69,6 @@ export class Event implements IPublicApiEvent {
}
}
export function getEvent(editor: InnerEditor, options: any = { prefix: 'common' }) {
export function getEvent(editor: IEditor, options: any = { prefix: 'common' }) {
return new Event(editor.eventBus, options);
}

View File

@ -1,5 +1,5 @@
import {
LowCodePluginManager,
ILowCodePluginManager,
} from '@alilc/lowcode-designer';
import { globalContext } from '@alilc/lowcode-editor-core';
import {
@ -14,8 +14,8 @@ import { pluginsSymbol } from '../symbols';
const innerPluginsSymbol = Symbol('plugin');
export class Plugins implements IPublicApiPlugins {
private readonly [innerPluginsSymbol]: LowCodePluginManager;
get [pluginsSymbol](): LowCodePluginManager {
private readonly [innerPluginsSymbol]: ILowCodePluginManager;
get [pluginsSymbol](): ILowCodePluginManager {
if (this.workspaceMode) {
return this[innerPluginsSymbol];
}
@ -27,7 +27,7 @@ export class Plugins implements IPublicApiPlugins {
return this[innerPluginsSymbol];
}
constructor(plugins: LowCodePluginManager, public workspaceMode: boolean = false) {
constructor(plugins: ILowCodePluginManager, public workspaceMode: boolean = false) {
this[innerPluginsSymbol] = plugins;
}

View File

@ -1,17 +1,18 @@
import { globalContext } from '@alilc/lowcode-editor-core';
import {
Skeleton as InnerSkeleton,
ISkeleton,
SkeletonEvents,
} from '@alilc/lowcode-editor-skeleton';
import { skeletonSymbol } from '../symbols';
import { IPublicApiSkeleton, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types';
const innerSkeletonSymbol = Symbol('skeleton');
export class Skeleton implements IPublicApiSkeleton {
private readonly [innerSkeletonSymbol]: InnerSkeleton;
private readonly [innerSkeletonSymbol]: ISkeleton;
private readonly pluginName: string;
get [skeletonSymbol](): InnerSkeleton {
get [skeletonSymbol](): ISkeleton {
if (this.workspaceMode) {
return this[innerSkeletonSymbol];
}
@ -24,7 +25,7 @@ export class Skeleton implements IPublicApiSkeleton {
}
constructor(
skeleton: InnerSkeleton,
skeleton: ISkeleton,
pluginName: string,
readonly workspaceMode: boolean = false,
) {
@ -57,7 +58,7 @@ export class Skeleton implements IPublicApiSkeleton {
if (!normalizeArea(area)) {
return;
}
skeleton[normalizeArea(area)!].container?.remove(name);
skeleton[normalizeArea(area)].container?.remove(name);
}
/**
@ -185,7 +186,7 @@ export class Skeleton implements IPublicApiSkeleton {
}
}
function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined) {
function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea' | 'rightArea' | 'topArea' | 'toolbar' | 'mainArea' | 'bottomArea' | 'leftFixedArea' | 'leftFloatArea' | 'stages' {
switch (area) {
case 'leftArea':
case 'left':

View File

@ -1,13 +1,13 @@
import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types';
import { Workspace as InnerWorkSpace } from '@alilc/lowcode-workspace';
import { IWorkspace } from '@alilc/lowcode-workspace';
import { Plugins } from '@alilc/lowcode-shell';
import { workspaceSymbol } from '../symbols';
import { Resource as ShellResource, Window as ShellWindow } from '../model';
export class Workspace implements IPublicApiWorkspace {
readonly [workspaceSymbol]: InnerWorkSpace;
readonly [workspaceSymbol]: IWorkspace;
constructor(innerWorkspace: InnerWorkSpace) {
constructor(innerWorkspace: IWorkspace) {
this[workspaceSymbol] = innerWorkspace;
}

View File

@ -1,5 +1,7 @@
import {
IDragon,
ILocateEvent as InnerLocateEvent,
INode,
} from '@alilc/lowcode-designer';
import { dragonSymbol, nodeSymbol } from '../symbols';
import LocateEvent from './locate-event';
@ -11,18 +13,19 @@ import {
IPublicModelDragObject,
IPublicTypeDragNodeDataObject,
IPublicModelNode,
IPublicTypeDragObject,
} from '@alilc/lowcode-types';
export const innerDragonSymbol = Symbol('innerDragonSymbol');
export class Dragon implements IPublicModelDragon {
private readonly [innerDragonSymbol]: IPublicModelDragon;
private readonly [innerDragonSymbol]: IDragon;
constructor(innerDragon: IPublicModelDragon, readonly workspaceMode: boolean) {
constructor(innerDragon: IDragon, readonly workspaceMode: boolean) {
this[innerDragonSymbol] = innerDragon;
}
get [dragonSymbol](): any {
get [dragonSymbol](): IDragon {
if (this.workspaceMode) {
return this[innerDragonSymbol];
}
@ -38,7 +41,7 @@ export class Dragon implements IPublicModelDragon {
}
static create(
dragon: IPublicModelDragon | null,
dragon: IDragon | null,
workspaceMode: boolean,
): IPublicModelDragon | null {
if (!dragon) {
@ -102,11 +105,13 @@ export class Dragon implements IPublicModelDragon {
* @param dragObject
* @param boostEvent
*/
boost(dragObject: DragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node | IPublicModelNode): void {
boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: IPublicModelNode & {
[nodeSymbol]: INode;
}): void {
return this[dragonSymbol].boost({
...dragObject,
nodes: dragObject.nodes.map((node: any) => node[nodeSymbol]),
}, boostEvent, fromRglNode);
}, boostEvent, fromRglNode?.[nodeSymbol]);
}
/**

View File

@ -1,16 +1,16 @@
import { ILocateEvent as InnerLocateEvent } from '@alilc/lowcode-designer';
import { ILocateEvent } from '@alilc/lowcode-designer';
import { locateEventSymbol } from '../symbols';
import { DragObject } from './drag-object';
import { IPublicModelLocateEvent, IPublicModelDragObject } from '@alilc/lowcode-types';
export default class LocateEvent implements IPublicModelLocateEvent {
private readonly [locateEventSymbol]: InnerLocateEvent;
private readonly [locateEventSymbol]: ILocateEvent;
constructor(locateEvent: InnerLocateEvent) {
constructor(locateEvent: ILocateEvent) {
this[locateEventSymbol] = locateEvent;
}
static create(locateEvent: InnerLocateEvent): IPublicModelLocateEvent | null {
static create(locateEvent: ILocateEvent): IPublicModelLocateEvent | null {
if (!locateEvent) {
return null;
}

View File

@ -1,11 +1,11 @@
import { IPublicModelResource } from '@alilc/lowcode-types';
import { Resource as InnerResource } from '@alilc/lowcode-workspace';
import { IResource } from '@alilc/lowcode-workspace';
import { resourceSymbol } from '../symbols';
export class Resource implements IPublicModelResource {
readonly [resourceSymbol]: InnerResource;
readonly [resourceSymbol]: IResource;
constructor(resource: InnerResource) {
constructor(resource: IResource) {
this[resourceSymbol] = resource;
}

View File

@ -1,10 +1,10 @@
import { windowSymbol } from '../symbols';
import { IPublicModelResource, IPublicModelWindow, IPublicTypeDisposable } from '@alilc/lowcode-types';
import { EditorWindow } from '@alilc/lowcode-workspace';
import { IEditorWindow } from '@alilc/lowcode-workspace';
import { Resource as ShellResource } from './resource';
export class Window implements IPublicModelWindow {
private readonly [windowSymbol]: EditorWindow;
private readonly [windowSymbol]: IEditorWindow;
get id() {
return this[windowSymbol]?.id;
@ -22,7 +22,7 @@ export class Window implements IPublicModelWindow {
return new ShellResource(this[windowSymbol].resource);
}
constructor(editorWindow: EditorWindow) {
constructor(editorWindow: IEditorWindow) {
this[windowSymbol] = editorWindow;
}

View File

@ -2,19 +2,20 @@ import { IPublicModelWindow } from '../model';
import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types';
export interface IPublicApiWorkspace<
Plugins = IPublicApiPlugins
Plugins = IPublicApiPlugins,
ModelWindow = IPublicModelWindow
> {
/** 是否启用 workspace 模式 */
isActive: boolean;
/** 当前设计器窗口 */
window: IPublicModelWindow;
window: ModelWindow;
plugins: Plugins;
/** 当前设计器的编辑窗口 */
windows: IPublicModelWindow[];
windows: ModelWindow[];
/** 获取资源树列表 */
get resourceList(): IPublicModelResource[];

View File

@ -1,8 +1,3 @@
export interface IPublicModelDragObject {
import { IPublicTypeDragNodeDataObject, IPublicTypeDragNodeObject } from '../type';
get type(): any;
get nodes(): any;
get data(): any;
}
export type IPublicModelDragObject = Readonly<IPublicTypeDragNodeObject> | Readonly<IPublicTypeDragNodeDataObject>;

View File

@ -3,7 +3,8 @@ import { IPublicTypeDragNodeDataObject, IPublicTypeDragObject } from '../type';
import { IPublicModelDragObject, IPublicModelLocateEvent, IPublicModelNode } from './';
export interface IPublicModelDragon<
Node = IPublicModelNode
Node = IPublicModelNode,
LocateEvent = IPublicModelLocateEvent
> {
/**
@ -18,7 +19,7 @@ export interface IPublicModelDragon<
* @param func
* @returns
*/
onDragstart(func: (e: IPublicModelLocateEvent) => any): () => void;
onDragstart(func: (e: LocateEvent) => any): () => void;
/**
* drag
@ -26,7 +27,7 @@ export interface IPublicModelDragon<
* @param func
* @returns
*/
onDrag(func: (e: IPublicModelLocateEvent) => any): () => void;
onDrag(func: (e: LocateEvent) => any): () => void;
/**
* dragend

View File

@ -1,6 +1,8 @@
import { ReactElement } from 'react';
export interface IPublicModelResource {
export interface IBaseModelResource<
Resource
> {
get title(): string | undefined;
get icon(): ReactElement | undefined;
@ -13,7 +15,9 @@ export interface IPublicModelResource {
get category(): string | undefined;
get children(): IPublicModelResource[];
get children(): Resource[];
get viewName(): string | undefined;
}
}
export type IPublicModelResource = IBaseModelResource<IPublicModelResource>;

View File

@ -2,7 +2,9 @@ import { ReactElement } from 'react';
import { IPublicTypeDisposable, IPublicTypeNodeSchema } from '../type';
import { IPublicModelResource } from './resource';
export interface IPublicModelWindow {
export interface IPublicModelWindow<
Resource = IPublicModelResource
> {
/** 窗口 id */
id: string;
@ -14,7 +16,7 @@ export interface IPublicModelWindow {
icon?: ReactElement;
/** 窗口资源类型 */
resource?: IPublicModelResource;
resource?: Resource;
/** 当前窗口导入 schema */
importSchema(schema: IPublicTypeNodeSchema): void;

View File

@ -1,19 +1,23 @@
import { IPublicModelNode } from '../model';
import { IPublicTypeIconType, TipContent } from './';
/**
*
*/
export interface IPublicTypeActionContentObject {
/**
*
*/
icon?: IPublicTypeIconType;
/**
*
*/
title?: TipContent;
/**
*
*/
action?: (currentNode: any) => void;
action?: (currentNode: IPublicModelNode) => void;
}

View File

@ -15,13 +15,14 @@ export enum LocationDetailType {
}
export type IPublicTypeRect = DOMRect & {
elements: Array<Element | Text>;
elements?: Array<Element | Text>;
computed?: boolean;
};
export interface IPublicTypeLocationChildrenDetail {
type: IPublicTypeLocationDetailType.Children;
index?: number | null;
/**
*
*/
@ -43,8 +44,7 @@ export interface IPublicTypeLocationPropDetail {
domNode?: HTMLElement;
}
// eslint-disable-next-line max-len
export type IPublicTypeLocationDetail = IPublicTypeLocationChildrenDetail | IPublicTypeLocationPropDetail | { type: string; [key: string]: any };
export type IPublicTypeLocationDetail = IPublicTypeLocationChildrenDetail | IPublicTypeLocationPropDetail | { [key: string]: any; type: string };
export interface IPublicTypeLocationData<
Node = IPublicModelNode

View File

@ -1,3 +1,4 @@
import { MouseEvent } from 'react';
import { IPublicTypePropType, IPublicTypeComponentAction } from './';
import { IPublicModelNode, IPublicModelProp, IPublicModelSettingField } from '../model';

View File

@ -1,20 +1,27 @@
import { ReactElement } from 'react';
export interface IPublicResourceData {
/** 资源名字 */
resourceName: string;
/** 资源标题 */
title: string;
title?: string;
/** 分类 */
category?: string;
/** 资源视图 */
viewName?: string;
/** 资源 icon */
icon?: ReactElement;
/** 资源其他配置 */
options: {
[key: string]: any;
};
/** 资源子元素 */
children?: IPublicResourceData[];
}

View File

@ -1,4 +1,4 @@
import { IPublicTypeWidgetConfigArea } from './';
import { IPublicTypeIconType, IPublicTypeTitleContent, IPublicTypeWidgetConfigArea, TipContent } from './';
export interface IPublicTypeWidgetBaseConfig {
[extra: string]: any;
@ -21,6 +21,24 @@ export interface IPublicTypePanelDockConfig extends IPublicTypeWidgetBaseConfig
type: 'PanelDock';
panelProps?: IPublicTypePanelDockPanelProps;
props?: IPublicTypePanelDockProps;
}
export interface IPublicTypePanelDockProps {
[key: string]: any;
size?: 'small' | 'medium' | 'large';
className?: string;
description?: TipContent;
onClick?: () => void;
icon?: IPublicTypeIconType;
title?: IPublicTypeTitleContent;
}
export interface IPublicTypePanelDockPanelProps {

View File

@ -1,4 +1,5 @@
import { IPublicTypeActionContentObject } from '@alilc/lowcode-types';
export function isActionContentObject(obj: any): boolean {
export function isActionContentObject(obj: any): obj is IPublicTypeActionContentObject {
return obj && typeof obj === 'object';
}

View File

@ -1,4 +1,5 @@
import { IPublicTypeLocationData } from '@alilc/lowcode-types';
export function isLocationData(obj: any): boolean {
export function isLocationData(obj: any): obj is IPublicTypeLocationData {
return obj && obj.target && obj.detail;
}

View File

@ -10,14 +10,13 @@ const pseudoMap = ['hover', 'focus', 'active', 'visited'];
const RE_CAMEL = /[A-Z]/g;
const RE_HYPHEN = /[-\s]+(.)?/g;
const CSS_REG = /:root(.*)\{.*/i;
const PROPS_REG = /([^:]*):\s?(.*)/i;
// 给 css 分组
function groupingCss(css) {
function groupingCss(css: string) {
let stackLength = 0;
let startIndex = 0;
const group = [];
const group: string[] = [];
css.split('').forEach((char, index) => {
if (char === '{') {
stackLength++;
@ -33,38 +32,38 @@ function groupingCss(css) {
return group;
}
function isString(str) {
function isString(str: any): str is string {
return {}.toString.call(str) === '[object String]';
}
function hyphenate(str) {
function hyphenate(str: string): string {
return str.replace(RE_CAMEL, w => `-${w}`).toLowerCase();
}
function camelize(str) {
function camelize(str: string): string {
return str.replace(RE_HYPHEN, (m, w) => (w ? w.toUpperCase() : ''));
}
/**
* convert
* {background-color: "red"}
* to
* background-color: red;
*/
function runtimeToCss(runtime) {
const css = [];
function runtimeToCss(runtime: Record<string, string>) {
const css: string[] = [];
Object.keys(runtime).forEach((key) => {
css.push(` ${key}: ${runtime[key]};`);
});
return css.join('\n');
}
function toNativeStyle(runtime) {
function toNativeStyle(runtime: Record<string, string> | undefined) {
if (!runtime) {
return {};
}
if (runtime.default) {
const normalized = {};
const normalized: Record<string, string> = {};
Object.keys(runtime).forEach((pseudo) => {
if (pseudo === 'extra') {
normalized[pseudo] = runtime[pseudo];
@ -98,14 +97,13 @@ function normalizeStyle(style) {
return normalized;
}
const normalized = {};
const normalized: Record<string, string | Record<string, string>> = {};
Object.keys(style).forEach((key) => {
normalized[hyphenate(key)] = style[key];
});
return normalized;
}
function toCss(runtime) {
if (!runtime) {
return (
@ -115,7 +113,7 @@ function toCss(runtime) {
}
if (runtime.default) {
const css = [];
const css: string[] = [];
Object.keys(runtime).forEach((pseudo) => {
if (pseudo === 'extra') {
Array.isArray(runtime.extra) && css.push(runtime.extra.join('\n'));
@ -140,11 +138,14 @@ ${runtimeToCss(normalizeStyle(runtime))}
);
}
function cssToRuntime(css) {
function cssToRuntime(css: string) {
if (!css) {
return {};
}
const runtime = {};
const runtime: {
extra?: string[];
default?: Record<string, string>;
} = {};
const groups = groupingCss(css);
groups.forEach((cssItem) => {
if (!cssItem.startsWith(':root')) {
@ -153,7 +154,7 @@ function cssToRuntime(css) {
} else {
const res = /:root:?(.*)?{(.*)/ig.exec(cssItem.replace(/[\r\n]+/ig, '').trim());
if (res) {
let pseudo;
let pseudo: string | undefined;
if (res[1] && res[1].trim() && some(pseudoMap, pse => res[1].indexOf(pse) === 0)) {
pseudo = res[1].trim();
@ -161,8 +162,8 @@ function cssToRuntime(css) {
pseudo = res[1];
}
const s = {};
res[2].split(';').reduce((prev, next) => {
const s: Record<string, string> = {};
res[2].split(';').reduce<string[]>((prev, next) => {
if (next.indexOf('base64') > -1) {
prev[prev.length - 1] += `;${next}`;
} else {
@ -173,8 +174,8 @@ function cssToRuntime(css) {
if (item) {
if (PROPS_REG.test(item)) {
const props = item.match(PROPS_REG);
const key = props[1];
const value = props[2];
const key = props?.[1];
const value = props?.[2];
if (key && value) {
s[key.trim()] = value.trim();
}
@ -182,10 +183,7 @@ function cssToRuntime(css) {
}
});
if (!pseudo) {
pseudo = 'default';
}
runtime[pseudo] = s;
runtime[pseudo || 'default'] = s;
}
}
});

View File

@ -23,7 +23,8 @@ export function isReactComponent(obj: any): obj is ComponentType<any> {
export function wrapReactClass(view: FunctionComponent) {
let ViewComponentClass = class extends Component {
render() {
return createElement(view, this.props);
const { children, ...other } = this.props;
return createElement(view, other, children);
}
} as any;
ViewComponentClass = cloneEnumerableProperty(ViewComponentClass, view);

View File

@ -1,5 +1,6 @@
// 仅使用类型
import { IPublicModelNode } from '@alilc/lowcode-types';
import { MouseEvent } from 'react';
export const getClosestNode = <Node extends IPublicModelNode = IPublicModelNode>(
node: Node,
@ -12,7 +13,7 @@ export const getClosestNode = <Node extends IPublicModelNode = IPublicModelNode>
return node;
} else {
// @ts-ignore
return getClosestNode(node.getParent(), until);
return getClosestNode(node.parent, until);
}
};
@ -22,8 +23,8 @@ export const getClosestNode = <Node extends IPublicModelNode = IPublicModelNode>
* @param {unknown} e
* @returns {boolean} true表示可点击
*/
export function canClickNode<Node extends IPublicModelNode = IPublicModelNode>(node: Node, e: unknown): boolean {
export function canClickNode<Node extends IPublicModelNode = IPublicModelNode>(node: Node, e: MouseEvent): boolean {
const onClickHook = node.componentMeta?.advanced?.callbacks?.onClickHook;
const canClick = typeof onClickHook === 'function' ? onClickHook(e as MouseEvent, node) : true;
const canClick = typeof onClickHook === 'function' ? onClickHook(e, node) : true;
return canClick;
};
}

View File

@ -3,13 +3,17 @@ import {
engineConfig, Setters as InnerSetters,
Hotkey as InnerHotkey,
commonEvent,
IEngineConfig,
IHotKey,
} from '@alilc/lowcode-editor-core';
import {
Designer,
ILowCodePluginContextApiAssembler,
LowCodePluginManager,
ILowCodePluginContextPrivate,
Project as InnerProject,
IProject,
IDesigner,
ILowCodePluginManager,
} from '@alilc/lowcode-designer';
import {
Skeleton as InnerSkeleton,
@ -29,40 +33,72 @@ import {
} from '@alilc/lowcode-shell';
import {
IPluginPreferenceMananger,
IPublicApiCanvas,
IPublicApiCommon,
IPublicApiEvent,
IPublicApiWorkspace,
IPublicApiHotkey,
IPublicApiMaterial,
IPublicApiPlugins,
IPublicApiProject,
IPublicApiSetters,
IPublicApiSkeleton,
IPublicModelPluginContext,
IPublicTypePluginMeta,
} from '@alilc/lowcode-types';
import { getLogger } from '@alilc/lowcode-utils';
import { Workspace as InnerWorkspace } from '../workspace';
import { EditorWindow } from '../window';
import { getLogger, Logger as InnerLogger } from '@alilc/lowcode-utils';
import { IWorkspace } from '../workspace';
import { IEditorWindow } from '../window';
export class BasicContext implements IPublicModelPluginContext {
skeleton: Skeleton;
plugins: Plugins;
project: Project;
setters: Setters;
material: Material;
common: Common;
config;
event;
logger;
hotkey: Hotkey;
innerProject: InnerProject;
export interface IBasicContext extends Omit<IPublicModelPluginContext, 'workspace'> {
skeleton: IPublicApiSkeleton;
plugins: IPublicApiPlugins;
project: IPublicApiProject;
setters: IPublicApiSetters;
material: IPublicApiMaterial;
common: IPublicApiCommon;
config: IEngineConfig;
event: IPublicApiEvent;
logger: InnerLogger;
hotkey: IPublicApiHotkey;
innerProject: IProject;
editor: Editor;
designer: Designer;
designer: IDesigner;
registerInnerPlugins: () => Promise<void>;
innerSetters: InnerSetters;
innerSkeleton: InnerSkeleton;
innerHotkey: InnerHotkey;
innerPlugins: LowCodePluginManager;
canvas: Canvas;
innerHotkey: IHotKey;
innerPlugins: ILowCodePluginManager;
canvas: IPublicApiCanvas;
pluginEvent: IPublicApiEvent;
preference: IPluginPreferenceMananger;
workspace: IPublicApiWorkspace;
workspace: IWorkspace;
}
constructor(innerWorkspace: InnerWorkspace, viewName: string, public editorWindow?: EditorWindow) {
export class BasicContext implements IBasicContext {
skeleton: IPublicApiSkeleton;
plugins: IPublicApiPlugins;
project: IPublicApiProject;
setters: IPublicApiSetters;
material: IPublicApiMaterial;
common: IPublicApiCommon;
config: IEngineConfig;
event: IPublicApiEvent;
logger: InnerLogger;
hotkey: IPublicApiHotkey;
innerProject: IProject;
editor: Editor;
designer: IDesigner;
registerInnerPlugins: () => Promise<void>;
innerSetters: InnerSetters;
innerSkeleton: InnerSkeleton;
innerHotkey: IHotKey;
innerPlugins: ILowCodePluginManager;
canvas: IPublicApiCanvas;
pluginEvent: IPublicApiEvent;
preference: IPluginPreferenceMananger;
workspace: IWorkspace;
constructor(innerWorkspace: IWorkspace, viewName: string, public editorWindow?: IEditorWindow) {
const editor = new Editor(viewName, true);
const innerSkeleton = new InnerSkeleton(editor, viewName);
@ -110,7 +146,7 @@ export class BasicContext implements IPublicModelPluginContext {
this.canvas = canvas;
const common = new Common(editor, innerSkeleton);
this.common = common;
let plugins: any;
let plugins: IPublicApiPlugins;
const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = {
assembleApis: (context: ILowCodePluginContextPrivate, pluginName: string, meta: IPublicTypePluginMeta) => {

View File

@ -1,9 +1,9 @@
import { computed, makeObservable, obx } from '@alilc/lowcode-editor-core';
import { IPublicEditorViewConfig, IPublicTypeEditorView } from '@alilc/lowcode-types';
import { flow } from 'mobx';
import { Workspace as InnerWorkspace } from '../workspace';
import { IWorkspace } from '../workspace';
import { BasicContext } from './base-context';
import { EditorWindow } from '../window';
import { IEditorWindow } from '../window';
import { getWebviewPlugin } from '../inner-plugins/webview';
export class Context extends BasicContext {
@ -21,7 +21,7 @@ export class Context extends BasicContext {
return this._activate;
}
init = flow(function* (this: any) {
init = flow(function* (this: Context) {
if (this.viewType === 'webview') {
const url = yield this.instance?.url?.();
yield this.plugins.register(getWebviewPlugin(url, this.viewName));
@ -33,7 +33,7 @@ export class Context extends BasicContext {
this.isInit = true;
});
constructor(public workspace: InnerWorkspace, public editorWindow: EditorWindow, public editorView: IPublicTypeEditorView, options: Object | undefined) {
constructor(public workspace: IWorkspace, public editorWindow: IEditorWindow, public editorView: IPublicTypeEditorView, options: Object | undefined) {
super(workspace, editorView.viewName, editorWindow);
this.viewType = editorView.viewType || 'editor';
this.viewName = editorView.viewName;

View File

@ -1,4 +1,4 @@
export { Workspace } from './workspace';
export { Workspace, IWorkspace } from './workspace';
export * from './window';
export * from './layouts/workbench';
export { Resource } from './resource';
export { Resource, IResource } from './resource';

View File

@ -1,6 +1,14 @@
import { IPublicTypeResourceType } from '@alilc/lowcode-types';
export class ResourceType {
export interface IResourceType extends Omit<IPublicTypeResourceType, 'resourceName' | 'resourceType'> {
name: string;
type: 'editor' | 'webview';
resourceTypeModel: IPublicTypeResourceType;
}
export class ResourceType implements IResourceType {
constructor(readonly resourceTypeModel: IPublicTypeResourceType) {
}

View File

@ -1,13 +1,31 @@
import { IPublicTypeEditorView, IPublicModelResource, IPublicResourceData, IPublicResourceTypeConfig } from '@alilc/lowcode-types';
import { IPublicTypeEditorView, IPublicResourceData, IPublicResourceTypeConfig, IBaseModelResource } from '@alilc/lowcode-types';
import { Logger } from '@alilc/lowcode-utils';
import { BasicContext } from './context/base-context';
import { ResourceType } from './resource-type';
import { Workspace as InnerWorkSpace } from './workspace';
import { BasicContext, IBasicContext } from './context/base-context';
import { ResourceType, IResourceType } from './resource-type';
import { IWorkspace } from './workspace';
const logger = new Logger({ level: 'warn', bizName: 'workspace:resource' });
export class Resource implements IPublicModelResource {
private context: BasicContext;
export interface IBaseResource<T> extends IBaseModelResource<T> {
readonly resourceType: ResourceType;
get editorViews(): IPublicTypeEditorView[];
get defaultViewType(): string;
getEditorView(name: string): IPublicTypeEditorView | undefined;
import(schema: any): Promise<any>;
save(value: any): Promise<any>;
url(): Promise<string | undefined>;
}
export type IResource = IBaseResource<IResource>;
export class Resource implements IResource {
private context: IBasicContext;
resourceTypeInstance: IPublicResourceTypeConfig;
@ -49,13 +67,15 @@ export class Resource implements IPublicModelResource {
return this.context.innerSkeleton;
}
get children(): Resource[] {
get children(): IResource[] {
return this.resourceData?.children?.map(d => new Resource(d, this.resourceType, this.workspace)) || [];
}
constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType, readonly workspace: InnerWorkSpace) {
constructor(readonly resourceData: IPublicResourceData, readonly resourceType: IResourceType, readonly workspace: IWorkspace) {
this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`);
this.resourceTypeInstance = resourceType.resourceTypeModel(this.context, this.options);
this.resourceTypeInstance = resourceType.resourceTypeModel(this.context.innerPlugins._getLowCodePluginContext({
pluginName: '',
}), this.options);
this.init();
if (this.resourceTypeInstance.editorViews) {
this.resourceTypeInstance.editorViews.forEach((d: any) => {

View File

@ -1,9 +1,10 @@
import { uniqueId } from '@alilc/lowcode-utils';
import { createModuleEventBus, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core';
import { Context } from './context/view-context';
import { Workspace } from './workspace';
import { Resource } from './resource';
import { IWorkspace } from './workspace';
import { IResource } from './resource';
import { IPublicTypeDisposable } from '../../types/es/shell/type/disposable';
import { IPublicModelWindow } from '@alilc/lowcode-types';
interface IWindowCOnfig {
title: string | undefined;
@ -11,7 +12,13 @@ interface IWindowCOnfig {
viewType?: string | undefined;
}
export class EditorWindow {
export interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'changeViewType'> {
readonly resource: IResource;
changeViewType: (name: string, ignoreEmit?: boolean) => void;
}
export class EditorWindow implements IEditorWindow {
id: string = uniqueId('window');
icon: React.ReactElement | undefined;
@ -27,7 +34,7 @@ export class EditorWindow {
@obx initReady = false;
constructor(readonly resource: Resource, readonly workspace: Workspace, private config: IWindowCOnfig) {
constructor(readonly resource: IResource, readonly workspace: IWorkspace, private config: IWindowCOnfig) {
makeObservable(this);
this.init();
this.title = config.title;

View File

@ -1,23 +1,33 @@
import { Designer, LowCodePluginManager } from '@alilc/lowcode-designer';
import { IDesigner, ILowCodePluginManager, LowCodePluginManager } from '@alilc/lowcode-designer';
import { createModuleEventBus, Editor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core';
import { Plugins } from '@alilc/lowcode-shell';
import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types';
import { IPublicApiPlugins, IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType, IShellModelFactory } from '@alilc/lowcode-types';
import { BasicContext } from './context/base-context';
import { EditorWindow } from './window';
import { Resource } from './resource';
import { ResourceType } from './resource-type';
import { EditorWindow, IEditorWindow } from './window';
import { IResource, Resource } from './resource';
import { IResourceType, ResourceType } from './resource-type';
enum event {
ChangeWindow = 'change_window',
enum EVENT {
CHANGE_WINDOW = 'change_window',
ChangeActiveWindow = 'change_active_window',
CHANGE_ACTIVE_WINDOW = 'change_active_window',
}
const CHANGE_EVENT = 'resource.list.change';
interface IWorkspace extends Omit<IPublicApiWorkspace<
LowCodePluginManager
>, 'resourceList'> {}
export interface IWorkspace extends Omit<IPublicApiWorkspace<
LowCodePluginManager,
IEditorWindow
>, 'resourceList' | 'plugins'> {
readonly registryInnerPlugin: (designer: IDesigner, editor: Editor, plugins: IPublicApiPlugins) => Promise<void>;
readonly shellModelFactory: IShellModelFactory;
window: IEditorWindow;
plugins: ILowCodePluginManager;
getResourceList(): IResource[];
}
export class Workspace implements IWorkspace {
context: BasicContext;
@ -28,7 +38,7 @@ export class Workspace implements IWorkspace {
private resourceTypeMap: Map<string, ResourceType> = new Map();
private resourceList: Resource[] = [];
private resourceList: IResource[] = [];
get skeleton() {
return this.context.innerSkeleton;
@ -50,14 +60,14 @@ export class Workspace implements IWorkspace {
return null;
}
@obx.ref windows: EditorWindow[] = [];
@obx.ref windows: IEditorWindow[] = [];
editorWindowMap: Map<string, EditorWindow> = new Map<string, EditorWindow>();
editorWindowMap: Map<string, IEditorWindow> = new Map<string, IEditorWindow>();
@obx.ref window: EditorWindow;
@obx.ref window: IEditorWindow;
constructor(
readonly registryInnerPlugin: (designer: Designer, editor: Editor, plugins: Plugins) => Promise<void>,
readonly registryInnerPlugin: (designer: IDesigner, editor: Editor, plugins: IPublicApiPlugins) => Promise<void>,
readonly shellModelFactory: any,
) {
this.init();
@ -74,7 +84,10 @@ export class Workspace implements IWorkspace {
return;
}
const title = this.defaultResourceType.name;
const resource = new Resource({}, this.defaultResourceType, this);
const resource = new Resource({
resourceName: title,
options: {},
}, this.defaultResourceType, this);
this.window = new EditorWindow(resource, this, {
title,
});
@ -113,7 +126,7 @@ export class Workspace implements IWorkspace {
};
}
getResourceType(resourceName: string): ResourceType {
getResourceType(resourceName: string): IResourceType {
return this.resourceTypeMap.get(resourceName)!;
}
@ -139,7 +152,7 @@ export class Workspace implements IWorkspace {
}
removeEditorWindow(resourceName: string) {
const index = this.windows.findIndex(d => (d.resource.name === resourceName && d.title));
const index = this.windows.findIndex(d => (d.resource?.name === resourceName && d.title));
this.remove(index);
}
@ -157,7 +170,7 @@ export class Workspace implements IWorkspace {
console.error(`${name} resourceType is not available`);
return;
}
const filterWindows = this.windows.filter(d => (d.resource.name === name && d.resource.title == title));
const filterWindows = this.windows.filter(d => (d.resource?.name === name && d.resource.title == title));
if (filterWindows && filterWindows.length) {
this.window = filterWindows[0];
this.emitChangeActiveWindow();
@ -180,24 +193,24 @@ export class Workspace implements IWorkspace {
}
onChangeWindows(fn: () => void) {
this.emitter.on(event.ChangeWindow, fn);
this.emitter.on(EVENT.CHANGE_WINDOW, fn);
return () => {
this.emitter.removeListener(event.ChangeWindow, fn);
this.emitter.removeListener(EVENT.CHANGE_WINDOW, fn);
};
}
emitChangeWindow() {
this.emitter.emit(event.ChangeWindow);
this.emitter.emit(EVENT.CHANGE_WINDOW);
}
emitChangeActiveWindow() {
this.emitter.emit(event.ChangeActiveWindow);
this.emitter.emit(EVENT.CHANGE_ACTIVE_WINDOW);
}
onChangeActiveWindow(fn: () => void) {
this.emitter.on(event.ChangeActiveWindow, fn);
this.emitter.on(EVENT.CHANGE_ACTIVE_WINDOW, fn);
return () => {
this.emitter.removeListener(event.ChangeActiveWindow, fn);
this.emitter.removeListener(EVENT.CHANGE_ACTIVE_WINDOW, fn);
};
}
}