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', 'error',
{ default: ['signature', 'field', 'constructor', 'method'] } { 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** **@since v1.0.16**
### isDetectingNode ### isDetectingNode
检查拖拽放置的目标节点是否可以放置该拖拽对象 判断是否当前节点处于被探测状态
```typescript ```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 { createIcon, isReactComponent, isActionContentObject } from '@alilc/lowcode-utils';
import { IPublicTypeActionContentObject } from '@alilc/lowcode-types'; import { IPublicTypeActionContentObject } from '@alilc/lowcode-types';
import { BuiltinSimulatorHost } from '../host'; import { BuiltinSimulatorHost } from '../host';
import { OffsetObserver } from '../../designer'; import { INode, OffsetObserver } from '../../designer';
import { Node } from '../../document';
import NodeSelector from '../node-selector'; import NodeSelector from '../node-selector';
import { ISimulatorHost } from '../../simulator';
@observer @observer
export class BorderSelectingInstance extends Component<{ 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) { function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActionContentObject, key: string, node: INode) {
if (isValidElement(content)) { if (isValidElement<{ key: string; node: INode }>(content)) {
return cloneElement(content, { key, node }); return cloneElement(content, { key, node });
} }
if (isReactComponent(content)) { if (isReactComponent(content)) {
@ -130,7 +130,7 @@ function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActio
key={key} key={key}
className="lc-borders-action" className="lc-borders-action"
onClick={() => { onClick={() => {
action && action(node); action && action(node.internalToShellNode()!);
const workspace = globalContext.get('workspace'); const workspace = globalContext.get('workspace');
const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor');
const npm = node?.componentMeta?.npm; const npm = node?.componentMeta?.npm;
@ -153,8 +153,8 @@ function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActio
} }
@observer @observer
export class BorderSelectingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> { export class BorderSelectingForNode extends Component<{ host: ISimulatorHost; node: INode }> {
get host(): BuiltinSimulatorHost { get host(): ISimulatorHost {
return this.props.host; return this.props.host;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@ import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core';
import { Logger } from '@alilc/lowcode-utils'; import { Logger } from '@alilc/lowcode-utils';
import { IPublicTypeWidgetBaseConfig } from '@alilc/lowcode-types'; import { IPublicTypeWidgetBaseConfig } from '@alilc/lowcode-types';
import { WidgetContainer } from './widget/widget-container'; import { WidgetContainer } from './widget/widget-container';
import { Skeleton } from './skeleton'; import { ISkeleton } from './skeleton';
import { IWidget } from './widget/widget'; import { IWidget } from './widget/widget';
const logger = new Logger({ level: 'warn', bizName: 'skeleton:area' }); 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>; 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); makeObservable(this);
this.container = skeleton.createContainer(name, handle, exclusive, () => this.visible, defaultSetCurrent); 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); return this.container.remove(config);
} }
private lastCurrent: T | null = null;
setVisible(flag: boolean) { setVisible(flag: boolean) {
if (this.exclusive) { if (this.exclusive) {
const { current } = this.container; const { current } = this.container;

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
import { createContext } from 'react'; 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 { observer, Focusable, focusTracker } from '@alilc/lowcode-editor-core';
import { Area } from '../area'; import { Area } from '../area';
import { Panel } from '../widget/panel'; import { Panel } from '../widget/panel';
import { PanelConfig } from '../types';
@observer @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 dispose?: () => void;
private focusing?: Focusable; private focusing?: Focusable;

View File

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

View File

@ -1,7 +1,7 @@
import { Component } from 'react'; import { Component } from 'react';
import { TipContainer, observer } from '@alilc/lowcode-editor-core'; import { TipContainer, observer } from '@alilc/lowcode-editor-core';
import classNames from 'classnames'; import classNames from 'classnames';
import { Skeleton } from '../skeleton'; import { ISkeleton } from '../skeleton';
import TopArea from './top-area'; import TopArea from './top-area';
import LeftArea from './left-area'; import LeftArea from './left-area';
import LeftFixedPane from './left-fixed-pane'; import LeftFixedPane from './left-fixed-pane';
@ -16,7 +16,7 @@ import { EditorConfig, PluginClassSet } from '@alilc/lowcode-types';
@observer @observer
export class Workbench extends Component<{ export class Workbench extends Component<{
skeleton: Skeleton; skeleton: ISkeleton;
config?: EditorConfig; config?: EditorConfig;
components?: PluginClassSet; components?: PluginClassSet;
className?: string; 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 { import {
DockConfig, DockConfig,
PanelConfig, PanelConfig,
@ -27,6 +27,7 @@ import {
IPublicTypeWidgetBaseConfig, IPublicTypeWidgetBaseConfig,
IPublicTypeWidgetConfigArea, IPublicTypeWidgetConfigArea,
IPublicTypeSkeletonConfig, IPublicTypeSkeletonConfig,
IPublicApiSkeleton,
} from '@alilc/lowcode-types'; } from '@alilc/lowcode-types';
const logger = new Logger({ level: 'warn', bizName: 'skeleton' }); const logger = new Logger({ level: 'warn', bizName: 'skeleton' });
@ -42,6 +43,66 @@ export enum SkeletonEvents {
WIDGET_ENABLE = 'skeleton.widget.enable', 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 { export class Skeleton {
private panels = new Map<string, Panel>(); private panels = new Map<string, Panel>();
@ -69,7 +130,7 @@ export class Skeleton {
readonly widgets: IWidget[] = []; readonly widgets: IWidget[] = [];
constructor(readonly editor: Editor, readonly viewName: string = 'global') { constructor(readonly editor: IEditor, readonly viewName: string = 'global') {
makeObservable(this); makeObservable(this);
this.leftArea = new Area( this.leftArea = new Area(
this, this,
@ -244,7 +305,7 @@ export class Skeleton {
Object.keys(plugins).forEach((area) => { Object.keys(plugins).forEach((area) => {
plugins[area].forEach((item) => { plugins[area].forEach((item) => {
const { pluginKey, type, props = {}, pluginProps } = item; const { pluginKey, type, props = {}, pluginProps } = item;
const config: Partial<IPublicTypeWidgetBaseConfig> = { const config: IPublicTypeWidgetBaseConfig = {
area: area as IPublicTypeWidgetConfigArea, area: area as IPublicTypeWidgetConfigArea,
type: 'Widget', type: 'Widget',
name: pluginKey, name: pluginKey,
@ -272,7 +333,7 @@ export class Skeleton {
if (pluginKey in components) { if (pluginKey in components) {
config.content = components[pluginKey]; 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 leadingFnRe = /^function/;
const leadingFnNameRe = /^\w+\s*\(/; const leadingFnNameRe = /^\w+\s*\(/;
const logger = getLogger({ level: 'warn', bizName: 'skeleton:transducers' }); const logger = getLogger({ level: 'warn', bizName: 'skeleton:transducers' });
/** /**
* *
* () => {} / val => {} * () => {} / val => {}

View File

@ -1,12 +1,11 @@
import { ReactElement, ComponentType } from 'react'; import { ReactElement, ComponentType } from 'react';
import { import {
IPublicTypeTitleContent, IPublicTypeTitleContent,
IPublicTypeIconType,
IPublicTypeI18nData, IPublicTypeI18nData,
TipContent,
IPublicTypeWidgetConfigArea, IPublicTypeWidgetConfigArea,
IPublicTypeWidgetBaseConfig, IPublicTypeWidgetBaseConfig,
IPublicTypePanelDockPanelProps, IPublicTypePanelDockPanelProps,
IPublicTypePanelDockProps,
} from '@alilc/lowcode-types'; } from '@alilc/lowcode-types';
import { IWidget } from './widget/widget'; import { IWidget } from './widget/widget';
@ -24,13 +23,7 @@ export function isWidgetConfig(obj: any): obj is WidgetConfig {
return obj && obj.type === 'Widget'; return obj && obj.type === 'Widget';
} }
export interface DockProps { export interface DockProps extends IPublicTypePanelDockProps {
title?: IPublicTypeTitleContent;
icon?: IPublicTypeIconType;
size?: 'small' | 'medium' | 'large';
className?: string;
description?: TipContent;
onClick?: () => void;
} }
export interface DividerConfig extends IPublicTypeWidgetBaseConfig { 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 { uniqueId, createContent } from '@alilc/lowcode-utils';
import { getEvent } from '@alilc/lowcode-shell'; import { getEvent } from '@alilc/lowcode-shell';
import { DockConfig } from '../types'; import { DockConfig } from '../types';
import { Skeleton } from '../skeleton'; import { ISkeleton } from '../skeleton';
import { DockView, WidgetView } from '../components/widget-views'; import { DockView, WidgetView } from '../components/widget-views';
import { IWidget } from './widget'; import { IWidget } from './widget';
@ -59,7 +59,7 @@ export class Dock implements IWidget {
return this._body; return this._body;
} }
constructor(readonly skeleton: Skeleton, readonly config: DockConfig) { constructor(readonly skeleton: ISkeleton, readonly config: DockConfig) {
makeObservable(this); makeObservable(this);
const { props = {}, name } = config; const { props = {}, name } = config;
this.name = name; this.name = name;

View File

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

View File

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

View File

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

View File

@ -3,45 +3,51 @@ import { isI18nData, isTitleConfig } from '@alilc/lowcode-utils';
import { isValidElement } from 'react'; import { isValidElement } from 'react';
export function composeTitle(title?: IPublicTypeTitleContent, icon?: IPublicTypeIconType, tip?: TipContent, tipAsTitle?: boolean, noIcon?: boolean) { export function composeTitle(title?: IPublicTypeTitleContent, icon?: IPublicTypeIconType, tip?: TipContent, tipAsTitle?: boolean, noIcon?: boolean) {
let _title: IPublicTypeTitleContent | undefined;
if (!title) { if (!title) {
title = {}; _title = {};
if (!icon || tipAsTitle) { if (!icon || tipAsTitle) {
title.label = tip; _title = {
label: tip,
};
tip = undefined; tip = undefined;
} }
} else {
_title = title;
} }
if (icon || tip) { if (icon || tip) {
if (typeof title !== 'object' || isValidElement(title) || isI18nData(title)) { if (typeof _title !== 'object' || isValidElement(_title) || isI18nData(_title)) {
if (isValidElement(title)) { if (isValidElement(_title)) {
if (title.type === 'svg' || (title.type as any).getIcon) { if (_title.type === 'svg' || _title.type.getIcon) {
if (!icon) { if (!icon) {
icon = title as any; icon = _title;
} }
if (tipAsTitle) { if (tipAsTitle) {
title = tip as any; _title = tip;
tip = null; tip = null;
} else { } else {
title = undefined; _title = undefined;
} }
} }
} }
title = { _title = {
label: title, label: _title,
icon, icon,
tip, tip,
}; };
} else { } else {
title = { _title = {
...title, ..._title,
icon, icon,
tip, tip,
}; };
} }
} }
if (isTitleConfig(title) && noIcon) { if (isTitleConfig(_title) && noIcon) {
if (!isValidElement(title)) { 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 { createContent, uniqueId } from '@alilc/lowcode-utils';
import { getEvent } from '@alilc/lowcode-shell'; import { getEvent } from '@alilc/lowcode-shell';
import { WidgetConfig } from '../types'; import { WidgetConfig } from '../types';
import { Skeleton } from '../skeleton'; import { ISkeleton } from '../skeleton';
import { WidgetView } from '../components/widget-views'; import { WidgetView } from '../components/widget-views';
import { IPublicTypeTitleContent, IPublicTypeWidgetBaseConfig } from '@alilc/lowcode-types'; import { IPublicTypeTitleContent, IPublicTypeWidgetBaseConfig } from '@alilc/lowcode-types';
@ -15,7 +15,7 @@ export interface IWidget {
readonly visible: boolean; readonly visible: boolean;
readonly disabled?: boolean; readonly disabled?: boolean;
readonly body: ReactNode; readonly body: ReactNode;
readonly skeleton: Skeleton; readonly skeleton: ISkeleton;
readonly config: IPublicTypeWidgetBaseConfig; readonly config: IPublicTypeWidgetBaseConfig;
getName(): string; getName(): string;
@ -71,7 +71,7 @@ export class Widget implements IWidget {
readonly title: IPublicTypeTitleContent; readonly title: IPublicTypeTitleContent;
constructor(readonly skeleton: Skeleton, readonly config: WidgetConfig) { constructor(readonly skeleton: ISkeleton, readonly config: WidgetConfig) {
makeObservable(this); makeObservable(this);
const { props = {}, name } = config; const { props = {}, name } = config;
this.name = name; this.name = name;

View File

@ -461,6 +461,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
locale: renderer.locale, locale: renderer.locale,
messages: _schema.i18n || {}, messages: _schema.i18n || {},
device: renderer.device, device: renderer.device,
locale: renderer.locale,
appHelper: renderer.context, appHelper: renderer.context,
rendererName: 'LowCodeRenderer', rendererName: 'LowCodeRenderer',
thisRequiredInJSE: host.thisRequiredInJSE, thisRequiredInJSE: host.thisRequiredInJSE,
@ -632,4 +633,4 @@ function getLowCodeComponentProps(props: any) {
return newProps; 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 { getLogger, isPluginEventName } from '@alilc/lowcode-utils';
import { IPublicApiEvent, IPublicTypeDisposable } from '@alilc/lowcode-types'; import { IPublicApiEvent, IPublicTypeDisposable } from '@alilc/lowcode-types';
@ -11,10 +11,10 @@ type EventOptions = {
const eventBusSymbol = Symbol('eventBus'); const eventBusSymbol = Symbol('eventBus');
export class Event implements IPublicApiEvent { export class Event implements IPublicApiEvent {
private readonly [eventBusSymbol]: EventBus; private readonly [eventBusSymbol]: IEventBus;
private readonly options: EventOptions; private readonly options: EventOptions;
constructor(eventBus: EventBus, options: EventOptions, public workspaceMode = false) { constructor(eventBus: IEventBus, options: EventOptions, public workspaceMode = false) {
this[eventBusSymbol] = eventBus; this[eventBusSymbol] = eventBus;
this.options = options; this.options = options;
if (!this.options.prefix) { 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); return new Event(editor.eventBus, options);
} }

View File

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

View File

@ -1,17 +1,18 @@
import { globalContext } from '@alilc/lowcode-editor-core'; import { globalContext } from '@alilc/lowcode-editor-core';
import { import {
Skeleton as InnerSkeleton, ISkeleton,
SkeletonEvents, SkeletonEvents,
} from '@alilc/lowcode-editor-skeleton'; } from '@alilc/lowcode-editor-skeleton';
import { skeletonSymbol } from '../symbols'; import { skeletonSymbol } from '../symbols';
import { IPublicApiSkeleton, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; import { IPublicApiSkeleton, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types';
const innerSkeletonSymbol = Symbol('skeleton'); const innerSkeletonSymbol = Symbol('skeleton');
export class Skeleton implements IPublicApiSkeleton { export class Skeleton implements IPublicApiSkeleton {
private readonly [innerSkeletonSymbol]: InnerSkeleton; private readonly [innerSkeletonSymbol]: ISkeleton;
private readonly pluginName: string; private readonly pluginName: string;
get [skeletonSymbol](): InnerSkeleton { get [skeletonSymbol](): ISkeleton {
if (this.workspaceMode) { if (this.workspaceMode) {
return this[innerSkeletonSymbol]; return this[innerSkeletonSymbol];
} }
@ -24,7 +25,7 @@ export class Skeleton implements IPublicApiSkeleton {
} }
constructor( constructor(
skeleton: InnerSkeleton, skeleton: ISkeleton,
pluginName: string, pluginName: string,
readonly workspaceMode: boolean = false, readonly workspaceMode: boolean = false,
) { ) {
@ -57,7 +58,7 @@ export class Skeleton implements IPublicApiSkeleton {
if (!normalizeArea(area)) { if (!normalizeArea(area)) {
return; 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) { switch (area) {
case 'leftArea': case 'leftArea':
case 'left': case 'left':

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,8 @@
import { ReactElement } from 'react'; import { ReactElement } from 'react';
export interface IPublicModelResource { export interface IBaseModelResource<
Resource
> {
get title(): string | undefined; get title(): string | undefined;
get icon(): ReactElement | undefined; get icon(): ReactElement | undefined;
@ -13,7 +15,9 @@ export interface IPublicModelResource {
get category(): string | undefined; get category(): string | undefined;
get children(): IPublicModelResource[]; get children(): Resource[];
get viewName(): string | undefined; 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 { IPublicTypeDisposable, IPublicTypeNodeSchema } from '../type';
import { IPublicModelResource } from './resource'; import { IPublicModelResource } from './resource';
export interface IPublicModelWindow { export interface IPublicModelWindow<
Resource = IPublicModelResource
> {
/** 窗口 id */ /** 窗口 id */
id: string; id: string;
@ -14,7 +16,7 @@ export interface IPublicModelWindow {
icon?: ReactElement; icon?: ReactElement;
/** 窗口资源类型 */ /** 窗口资源类型 */
resource?: IPublicModelResource; resource?: Resource;
/** 当前窗口导入 schema */ /** 当前窗口导入 schema */
importSchema(schema: IPublicTypeNodeSchema): void; importSchema(schema: IPublicTypeNodeSchema): void;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
// 仅使用类型 // 仅使用类型
import { IPublicModelNode } from '@alilc/lowcode-types'; import { IPublicModelNode } from '@alilc/lowcode-types';
import { MouseEvent } from 'react';
export const getClosestNode = <Node extends IPublicModelNode = IPublicModelNode>( export const getClosestNode = <Node extends IPublicModelNode = IPublicModelNode>(
node: Node, node: Node,
@ -12,7 +13,7 @@ export const getClosestNode = <Node extends IPublicModelNode = IPublicModelNode>
return node; return node;
} else { } else {
// @ts-ignore // @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 * @param {unknown} e
* @returns {boolean} true表示可点击 * @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 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; return canClick;
}; }

View File

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

View File

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

View File

@ -1,4 +1,4 @@
export { Workspace } from './workspace'; export { Workspace, IWorkspace } from './workspace';
export * from './window'; export * from './window';
export * from './layouts/workbench'; 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'; 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) { 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 { Logger } from '@alilc/lowcode-utils';
import { BasicContext } from './context/base-context'; import { BasicContext, IBasicContext } from './context/base-context';
import { ResourceType } from './resource-type'; import { ResourceType, IResourceType } from './resource-type';
import { Workspace as InnerWorkSpace } from './workspace'; import { IWorkspace } from './workspace';
const logger = new Logger({ level: 'warn', bizName: 'workspace:resource' }); const logger = new Logger({ level: 'warn', bizName: 'workspace:resource' });
export class Resource implements IPublicModelResource { export interface IBaseResource<T> extends IBaseModelResource<T> {
private context: BasicContext; 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; resourceTypeInstance: IPublicResourceTypeConfig;
@ -49,13 +67,15 @@ export class Resource implements IPublicModelResource {
return this.context.innerSkeleton; return this.context.innerSkeleton;
} }
get children(): Resource[] { get children(): IResource[] {
return this.resourceData?.children?.map(d => new Resource(d, this.resourceType, this.workspace)) || []; 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.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(); this.init();
if (this.resourceTypeInstance.editorViews) { if (this.resourceTypeInstance.editorViews) {
this.resourceTypeInstance.editorViews.forEach((d: any) => { this.resourceTypeInstance.editorViews.forEach((d: any) => {

View File

@ -1,9 +1,10 @@
import { uniqueId } from '@alilc/lowcode-utils'; import { uniqueId } from '@alilc/lowcode-utils';
import { createModuleEventBus, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; import { createModuleEventBus, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core';
import { Context } from './context/view-context'; import { Context } from './context/view-context';
import { Workspace } from './workspace'; import { IWorkspace } from './workspace';
import { Resource } from './resource'; import { IResource } from './resource';
import { IPublicTypeDisposable } from '../../types/es/shell/type/disposable'; import { IPublicTypeDisposable } from '../../types/es/shell/type/disposable';
import { IPublicModelWindow } from '@alilc/lowcode-types';
interface IWindowCOnfig { interface IWindowCOnfig {
title: string | undefined; title: string | undefined;
@ -11,7 +12,13 @@ interface IWindowCOnfig {
viewType?: string | undefined; 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'); id: string = uniqueId('window');
icon: React.ReactElement | undefined; icon: React.ReactElement | undefined;
@ -27,7 +34,7 @@ export class EditorWindow {
@obx initReady = false; @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); makeObservable(this);
this.init(); this.init();
this.title = config.title; 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 { createModuleEventBus, Editor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core';
import { Plugins } from '@alilc/lowcode-shell'; import { IPublicApiPlugins, IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType, IShellModelFactory } from '@alilc/lowcode-types';
import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types';
import { BasicContext } from './context/base-context'; import { BasicContext } from './context/base-context';
import { EditorWindow } from './window'; import { EditorWindow, IEditorWindow } from './window';
import { Resource } from './resource'; import { IResource, Resource } from './resource';
import { ResourceType } from './resource-type'; import { IResourceType, ResourceType } from './resource-type';
enum event { enum EVENT {
ChangeWindow = 'change_window', CHANGE_WINDOW = 'change_window',
ChangeActiveWindow = 'change_active_window', CHANGE_ACTIVE_WINDOW = 'change_active_window',
} }
const CHANGE_EVENT = 'resource.list.change'; const CHANGE_EVENT = 'resource.list.change';
interface IWorkspace extends Omit<IPublicApiWorkspace< export interface IWorkspace extends Omit<IPublicApiWorkspace<
LowCodePluginManager LowCodePluginManager,
>, 'resourceList'> {} 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 { export class Workspace implements IWorkspace {
context: BasicContext; context: BasicContext;
@ -28,7 +38,7 @@ export class Workspace implements IWorkspace {
private resourceTypeMap: Map<string, ResourceType> = new Map(); private resourceTypeMap: Map<string, ResourceType> = new Map();
private resourceList: Resource[] = []; private resourceList: IResource[] = [];
get skeleton() { get skeleton() {
return this.context.innerSkeleton; return this.context.innerSkeleton;
@ -50,14 +60,14 @@ export class Workspace implements IWorkspace {
return null; 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( constructor(
readonly registryInnerPlugin: (designer: Designer, editor: Editor, plugins: Plugins) => Promise<void>, readonly registryInnerPlugin: (designer: IDesigner, editor: Editor, plugins: IPublicApiPlugins) => Promise<void>,
readonly shellModelFactory: any, readonly shellModelFactory: any,
) { ) {
this.init(); this.init();
@ -74,7 +84,10 @@ export class Workspace implements IWorkspace {
return; return;
} }
const title = this.defaultResourceType.name; 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, { this.window = new EditorWindow(resource, this, {
title, title,
}); });
@ -113,7 +126,7 @@ export class Workspace implements IWorkspace {
}; };
} }
getResourceType(resourceName: string): ResourceType { getResourceType(resourceName: string): IResourceType {
return this.resourceTypeMap.get(resourceName)!; return this.resourceTypeMap.get(resourceName)!;
} }
@ -139,7 +152,7 @@ export class Workspace implements IWorkspace {
} }
removeEditorWindow(resourceName: string) { 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); this.remove(index);
} }
@ -157,7 +170,7 @@ export class Workspace implements IWorkspace {
console.error(`${name} resourceType is not available`); console.error(`${name} resourceType is not available`);
return; 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) { if (filterWindows && filterWindows.length) {
this.window = filterWindows[0]; this.window = filterWindows[0];
this.emitChangeActiveWindow(); this.emitChangeActiveWindow();
@ -180,24 +193,24 @@ export class Workspace implements IWorkspace {
} }
onChangeWindows(fn: () => void) { onChangeWindows(fn: () => void) {
this.emitter.on(event.ChangeWindow, fn); this.emitter.on(EVENT.CHANGE_WINDOW, fn);
return () => { return () => {
this.emitter.removeListener(event.ChangeWindow, fn); this.emitter.removeListener(EVENT.CHANGE_WINDOW, fn);
}; };
} }
emitChangeWindow() { emitChangeWindow() {
this.emitter.emit(event.ChangeWindow); this.emitter.emit(EVENT.CHANGE_WINDOW);
} }
emitChangeActiveWindow() { emitChangeActiveWindow() {
this.emitter.emit(event.ChangeActiveWindow); this.emitter.emit(EVENT.CHANGE_ACTIVE_WINDOW);
} }
onChangeActiveWindow(fn: () => void) { onChangeActiveWindow(fn: () => void) {
this.emitter.on(event.ChangeActiveWindow, fn); this.emitter.on(EVENT.CHANGE_ACTIVE_WINDOW, fn);
return () => { return () => {
this.emitter.removeListener(event.ChangeActiveWindow, fn); this.emitter.removeListener(EVENT.CHANGE_ACTIVE_WINDOW, fn);
}; };
} }
} }